/*********************************************************************** * plug_vol2surf.c - plugin interface to vol2surf computation * * Provide an interface to the global v2s_plugin_opts structure. * * - R. Reynolds *********************************************************************** */ #include "afni.h" #include "vol2surf.h" #ifndef ALLOW_PLUGINS # error "Plugins not properly set up -- see machdep.h" #endif static char * PV2S_main( PLUGIN_interface * ); static char g_help[] = " This plugin provides an interface to the vol2surf options used by afni\n" " for the display of the Overlay dataset values on the surfaces in suma.\n" " \n" " For each Local Domain Parent that afni has received from suma, vol2surf\n" " computes a node color overlay and sends it to suma. This is computed\n" " by mapping afni's Overlay data across the 1 or 2 surfaces of each given\n" " LDP (Local Domain Parent).\n" " \n" " By default, each LDP gets a color list based on:\n" " \n" " o if only 1 surface for this LDP : intersection of the surface\n" " and afni's Overlay sub-brick, subject to afni's color bar and\n" " thresholding (afni voxels that do not survive the threshold take\n" " no part in the mapping)\n" " \n" " o if 2 or more surfaces for this LDP : intersection of the midpoint\n" " of the first 2 surfaces received from suma (for this LDP) and the\n" " Overlay sub-brick in afni, again subject to afni's color bar and\n" " thresholding\n" " \n" " These defaults are for surfaces that have _not_ been chosen via the\n" " plugin interface. Surfaces chosen via the plugin are, of course,\n" " mapped as the user specifies. Note that to recreate the defaults, use\n" " the 'mask' function for 1 surface, and the midpoint function for more\n" " than 1. The 'num steps' and 'seg index' will not be applicable.\n" " \n" " As of May, 2018, there is a 'map_all' option under 'use vol2surf'. In\n" " that case, all mappable surfaces will be processed using the plugin\n" " options, rather than the simple defaults.\n" " \n" " ---\n" " \n" " The minimum choices that must be made are on the 'function' line:\n" " 'use vol2surf?' (should be 'yes' :), and 'map func' (should be valid).\n" " \n" " ** Note that as a plugin, surfaces will be unknown at initialization\n" " time. Therefore the interface is via afni's surface index list.\n" " To see the surface index list, set the debug level to 2, and then\n" " press 'Set+Keep'. Part of the text output to the _terminal window_\n" " will be '+d valid surface indices and labels: ...'.\n" " \n" " ** For detailed information, please try : '3dVol2Surf -help'.\n" " \n" " ----------------------------- options --------------------------------\n" " function:\n" " \n" " use vol2surf? : choose 'yes' to make the plugin options active\n" " choose 'map_all' to apply options to all surfaces,\n" " not simply those in pair 0 and/or 1\n" " map func : choose a function to apply to values along node pair\n" " segments, embedded in the AFNI volume\n" " seg index : apply all values along a each segment, or only those\n" " from unique voxels\n" " num steps : the number of evenly spaced points each segment will\n" " be divided into\n" " \n" " surf pair 0:\n" " \n" " apply? : if no, skip this surface (pair)\n" " surf_A : choose the afni surface index for surface A\n" " use B? : form segments by joining nodes from surface A with\n" " nodes on surface B (an alternate choice is to use\n" " only surface A, along with its normals)\n" " surf_B : choose the afni surface index for surface B\n" " \n" " surf pair 1:\n" " \n" " apply? : if no, skip this surface (pair)\n" " surf_A : choose the afni surface index for surface A\n" " use B? : form segments by joining nodes from surface A with\n" " nodes on surface B (an alternate choice is to use\n" " only surface A, along with its normals)\n" " surf_B : choose the afni surface index for surface B\n" " \n" " normals:\n" " \n" " use normals? : segments are formed from each node from surface A\n" " along its normal, and of length 'norm len'\n" " norm len : this will be the length of each segment\n" " norm dir : choose what to do with the normal directions:\n" " check : let vol2surf try to decide\n" " keep : keep the default directions\n" " reverse : reverse the default directions\n" " \n" " offsets:\n" " \n" " NOTE - segments are considered directed from the node on surface A\n" " in the direction of surface B (or the normal), so if f_p1 is\n" " positive each segment gets shorter (going toward surface B),\n" " but if f_pn is positive each segment gets longer (still moving\n" " in the direction from surface A to surface B)\n" " \n" " f_p1_mm : move each segment starting point this number of\n" " millimeters toward surface B\n" " f_pn_mm : move each segment ending point this number of\n" " millimeters farther from surface A\n" " f_p1_fr : move each segment starting point this fraction of the\n" " distance toward surface B\n" " f_pn_fr : move each segment ending point this fraction of the\n" " distance farther from surface A\n" " \n" " out of range:\n" " \n" " oob nodes? : whether to still output results for those nodes which\n" " are out-of-bounds (i.e. outside the bounding box of\n" " the AFNI overlay dataset)\n" " oob value : if out-of-bounds nodes are output, this value will be\n" " given to them\n" " oom nodes? : whether to still output results for those nodes which\n" " are out-of-mask (i.e. masked by the threshold brick)\n" " oob value : if out-of-mask nodes are output, this value will be\n" " given to them\n" " output:\n" " \n" " first node : starting index for nodes to output\n" " last node : ending index for nodes to output (0 means 'nodes-1')\n" " (sorry, that means you cannot output from 0 to 0)\n" " outfile.1D : also send the results to this file (in 1D format)\n" " outfile.niml : also send the results to this file (in niml format)\n" " \n" " debug level:\n" " \n" " level : provide this level of debug output (0-5)\n" " node : provide additional debug output for this node\n" " \n" " \n" " Author: R Reynolds\n" " \n" " ----------------------------------------------------------------------\n" " History:\n" " \n" " 1.0 9 September 2004 [rickr] - initial version\n" " \n" " 1.1 16 September 2004 [rickr]\n" " - init gp_index to -1 (set it in afni)\n" " - allow the user to keep or reverse normal directions\n" " \n" " 1.2 29 September 2004 [rickr]\n" " - now set global ready if all is well\n" " - clear norms if not in use\n" " - name all local functions PV2S_*\n" " - if debug > 0, display chosen surfaces in terminal\n" " - if debug > 1, display all possible surfaces in terminal\n" " \n" " 1.3 08 October 2004 [rickr]\n" " - Global changes for new LDP processing:\n" " - added second surface pair to GUI\n" " - made small help and hint changes\n" " - fixed receive order of fr and mm offsets (mm was fr)\n" " - verify that surface pairs have matching LDPs\n" " - added PV2S_disp_afni_surfaces() to list all surfaces w/indices\n" " \n" " 1.4 25 October 2004 [rickr]\n" " - make sure the surface pairs are actually different\n" " - make sure surfaces have the same number of nodes\n" " - process all parameters, but only complain if 'ready'\n" " - always pass along debug/dnode\n" " \n" " 1.5 11 Dec 2004 [rickr] - describe default behavior here\n" " 1.5a 22 Mar 2005 [rickr] - removed all tabs\n" " 1.6 28 Mar 2006 [rickr] - fixed mode computation\n" " 1.7 09 Aug 2006 [rickr] - store surface labels for history note\n" ; #define P_MAP_NAMES_NVALS 16 /* should match enum for global maps */ #define P_NY_NVALS 2 #define P_NYA_NVALS 3 #define P_KEEP_NVALS 3 #define P_STEP_NVALS 2 static char * gp_ny_list[] = { "no", "yes" }; static char * gp_nyA_list[] = { "no", "yes", "map_all" }; static char * gp_keep_list[] = { "no check yet", "keep", "reverse" }; static char * gp_step_list[] = { "voxel", "node" }; typedef struct { v2s_plugin_opts * vpo; char * hist; char ** maps; } pv2s_globals; static pv2s_globals globs; /* these are just pointers to afni globals */ /* local functions */ static int PV2S_check_surfaces(PLUGIN_interface * plint, int sa, int sb, char *mesg, int debug); static int PV2S_disp_afni_surfaces(PLUGIN_interface * plint); static int PV2S_init_plugin_opts(pv2s_globals * g); static int PV2S_process_args(PLUGIN_interface * plint,pv2s_globals * g, char *mesg); /* for ease of error reporting */ #define PV2S_BAIL_VALUE(buf,str,val) \ do { sprintf((buf), "-------------------------------------\n" \ "%s\n" \ "bad value = %d\n" \ "-------------------------------------", \ (str), (val) ); } while (0) DEFINE_PLUGIN_PROTOTYPE /* for C++ compilation */ PLUGIN_interface * PLUGIN_init( int ncall ) { PLUGIN_interface * plint; void * void_vpo; int ival; ENTRY("vol2surf: PLUGIN_init"); if ( ncall > 0 ) RETURN(NULL); /* only one interface */ /* might be temporary */ if ( PLUTO_set_v2s_addrs(&void_vpo, &globs.maps, &globs.hist) ) { fprintf(stderr,"** plug_v2s: failed to init globals\n"); RETURN(NULL); } /* using a void pointer so we don't have to put vol2surf.h in afni.h */ globs.vpo = (v2s_plugin_opts *)void_vpo; PV2S_init_plugin_opts(&globs); plint = PLUTO_new_interface("Vol2Surf", "configure afni's volume to surface options", g_help, PLUGIN_CALL_VIA_MENU, PV2S_main); PLUTO_add_hint (plint, "configure vol2surf options"); PLUTO_set_sequence (plint, "A:afnicontrol:surf"); PLUTO_set_runlabels(plint, "Set+Keep", "Set+Close"); /* first input : do we use vol2surf? */ PLUTO_add_option( plint, "function", "op_st", TRUE ); PLUTO_add_hint ( plint, "decide whether to use vol2surf" ); PLUTO_add_string( plint, "use vol2surf? ", P_NYA_NVALS, gp_nyA_list, 0 ); PLUTO_add_hint ( plint, "use vol2surf (or basic intersection)" ); PLUTO_add_string( plint, "map func",P_MAP_NAMES_NVALS,globs.maps,0); PLUTO_add_hint ( plint, "choose a filter to apply to segment values" ); PLUTO_add_string( plint, "seg index",P_STEP_NVALS,gp_step_list,0); PLUTO_add_hint ( plint, "along segments, count only distinct voxels?"); PLUTO_add_number( plint, "num steps", 0, 100, 0, 2, 1 ); PLUTO_add_hint ( plint, "number of steps to divide each segment into" ); /* choose surface indices for surf pair 0 */ /* - note that we do not yet have surfaces to choose from */ PLUTO_add_option( plint, "surf pair 0", "surf pair 0", TRUE ); PLUTO_add_hint ( plint, "choose first surface index(es)" ); PLUTO_add_string( plint, "apply? ", P_NY_NVALS, gp_ny_list, 1 ); PLUTO_add_hint ( plint, "decide whether to apply surface(s)" ); PLUTO_add_number( plint, "surf_A", 0, 50, 0, 0, 1 ); PLUTO_add_hint ( plint, "choose surface A index" ); PLUTO_add_string( plint, "use B? ", P_NY_NVALS, gp_ny_list, 0 ); PLUTO_add_hint ( plint, "decide whether to use surface B" ); PLUTO_add_number( plint, "surf_B", 0, 50, 0, 1, 1 ); PLUTO_add_hint ( plint, "choose surface B index" ); /* choose surface indices for surf pair 1 */ /* - note that we do not yet have surfaces to choose from */ PLUTO_add_option( plint, "surf pair 1", "surf pair 1", TRUE ); PLUTO_add_hint ( plint, "choose second surface index(es)" ); PLUTO_add_string( plint, "apply? ", P_NY_NVALS, gp_ny_list, 0 ); PLUTO_add_hint ( plint, "decide whether to apply surface(s)" ); PLUTO_add_number( plint, "surf_A", 0, 50, 0, 2, 1 ); PLUTO_add_hint ( plint, "choose surface A index" ); PLUTO_add_string( plint, "use B? ", P_NY_NVALS, gp_ny_list, 0 ); PLUTO_add_hint ( plint, "decide whether to use surface B" ); PLUTO_add_number( plint, "surf_B", 0, 50, 0, 3, 1 ); PLUTO_add_hint ( plint, "choose surface B index" ); /* menu for using normals */ PLUTO_add_option( plint, "normals", "normals", FALSE ); PLUTO_add_hint ( plint, "control use of normals (instead of surf_B)" ); PLUTO_add_string( plint, "use normals? ", P_NY_NVALS, gp_ny_list, 0 ); PLUTO_add_hint ( plint, "should normals be used to simulate surf_B?" ); PLUTO_add_number( plint, "norm len", -100, 100, 1, 10, 1 ); PLUTO_add_hint ( plint, "what (signed) length should the normals be?" ); PLUTO_add_string( plint, "norm dir", P_KEEP_NVALS, gp_keep_list, 1 ); PLUTO_add_hint ( plint, "check normal direction, or keep or reverse it" ); /* segment offsets */ PLUTO_add_option( plint, "offsets", "offsets", FALSE ); PLUTO_add_hint ( plint,"offset segment endpoints, directed from p1 to pn"); PLUTO_add_number( plint, "f_p1_mm", -100, 100, 1, 0, 1 ); PLUTO_add_hint ( plint, "move p1 towards pn, in millimeters" ); PLUTO_add_number( plint, "f_pn_mm", -100, 100, 1, 0, 1 ); PLUTO_add_hint ( plint, "move pn farther from p1, in millimeters" ); PLUTO_add_number( plint, "f_p1_fr", -100, 100, 1, 0, 1 ); PLUTO_add_hint ( plint, "move p1 towards pn, by this segment fraction" ); PLUTO_add_number( plint, "f_pn_fr", -100, 100, 1, 0, 1 ); PLUTO_add_hint ( plint, "move pn farther from p1, by this fraction" ); /* out of bounds or mask */ PLUTO_add_option( plint, "out of range", "oor", FALSE ); PLUTO_add_hint ( plint, "what to do when out of bounds or mask" ); PLUTO_add_string( plint, "oob nodes?", P_NY_NVALS, gp_ny_list, 0 ); PLUTO_add_hint ( plint, "keep out-of-bounds nodes? (outside the dataset)"); PLUTO_add_number( plint, "oob value", 0, 0, 0, -2, 1 ); PLUTO_add_hint ( plint, "value to apply when out of dataset bounds" ); PLUTO_add_string( plint, "oom nodes?", P_NY_NVALS, gp_ny_list, 0 ); PLUTO_add_hint ( plint, "keep out-of-mask nodes? (below threshold)"); PLUTO_add_number( plint, "oom value", 0, 0, 0, -1, 1 ); PLUTO_add_hint ( plint, "value for masked out nodes" ); /* choose node processing range */ PLUTO_add_option( plint, "output", "output", FALSE ); PLUTO_add_hint ( plint, "select node range and output files" ); PLUTO_add_number( plint, "first node", 0, 0, 0, 0, 1 ); PLUTO_add_hint ( plint, "starting node to process (zero based)" ); PLUTO_add_number( plint, "last node", 0, 0, 0, 0, 1 ); PLUTO_add_hint ( plint, "end node to process (zero based)" ); PLUTO_add_string( plint, "outfile.1D", 0, NULL, 14 ); PLUTO_add_hint ( plint, "name for 1D output file - will overwrite!" ); PLUTO_add_string( plint, "outfile.niml", 0, NULL, 14 ); PLUTO_add_hint ( plint, "name for niml output file - will overwrite!" ); /* debugging level (0 if not set) */ PLUTO_add_option( plint, "debug level", "debug level", FALSE ); PLUTO_add_hint ( plint, "choose debug level (and debug node)" ); PLUTO_add_number( plint, "level", 0, 5, 0, globs.vpo->sopt.debug, 1 ); PLUTO_add_hint ( plint, "debug level - how much to print to terminal" ); PLUTO_add_number( plint, "node", 0, 0, 0, -1, 1 ); PLUTO_add_hint ( plint, "particular node to print debug information for" ); RETURN(plint); } char * PV2S_main ( PLUGIN_interface * plint ) { pv2s_globals * g; static char message[2048]; /* use this to output failures */ ENTRY("PV2S_main"); g = &globs; /* to have only one global access */ message[0] = '\0'; /* init to empty string */ g->vpo->ready = 0; if ( (PV2S_process_args(plint, g, message) != 0) && message[0] ) RETURN(message); RETURN(NULL); } /* base defaults to local and duplicate to global */ static int PV2S_init_plugin_opts(pv2s_globals * g) { int ival; ENTRY("PV2S_init_plugin_opts"); memset(g->vpo, 0, sizeof(*g->vpo)); g->vpo->ready = 0; /* flag as "not ready to go" */ g->vpo->use0 = 0; g->vpo->use1 = 0; g->vpo->s0A = -1; g->vpo->s0B = -1; g->vpo->s1A = -1; g->vpo->s1B = -1; g->vpo->label[0] = gv2s_no_label; /* init surface labels as undefined */ g->vpo->label[0] = gv2s_no_label; /* 7 Aug 2006 [rickr] */ g->vpo->label[0] = gv2s_no_label; g->vpo->label[0] = gv2s_no_label; g->vpo->sopt.gp_index = -1; /* maybe init debug from env 16 Sep 2009 [rickr] */ ival = (int)AFNI_numenv("AFNI_DEBUG_PLUG_VOL2SURF") ; if( ival < 0 ) ival = 0; if( ival > 5 ) ival = 5; /* limit to plugin range */ g->vpo->sopt.debug = ival; g->vpo->sopt.dnode = -1; g->vpo->sopt.outfile_1D = NULL; g->vpo->sopt.outfile_niml = NULL; g->vpo->sopt.segc_file = NULL; /* 30 Jun 2006 */ RETURN(0); } static int PV2S_process_args(PLUGIN_interface * plint, pv2s_globals * g, char * mesg) { THD_session * ss; v2s_plugin_opts lvpo; v2s_opts_t * sopt; float fval; char * tag, * str; int val, ready = 0; ENTRY("PV2S_process_args"); /* do we have a valid 3D view and session? */ if ( !IM3D_OPEN(plint->im3d) || !plint->im3d->ss_now ) { sprintf(mesg, "----------------------------------------------\n" "strange failure: invalid 3D view or session???\n" "----------------------------------------------"); RETURN(-1); } /* to a quick check to be sure we are talking with suma */ ss = plint->im3d->ss_now; if (ss && ss->su_num < 1) { sprintf(mesg, "-----------------------------------------\n" "no surfaces: is afni 'talking' with suma?\n" "-----------------------------------------"); RETURN(1); } /* copy current values, and make local changes while checking */ lvpo = *g->vpo; sopt = &lvpo.sopt; /* just for typing */ while ( (tag = PLUTO_get_optiontag(plint)) != NULL ) { if ( sopt->debug > 2 ) fprintf(stderr,"+d received option tag: %s\n", tag); if ( ! strcmp(tag, "op_st") ) { str = PLUTO_get_string(plint); val = PLUTO_string_index(str, P_NYA_NVALS, gp_nyA_list); if ( (val < 0) || (val >= P_NYA_NVALS) ) { PV2S_BAIL_VALUE(mesg,"bad NYA vals", val); RETURN(1); } /* option to process v2s on all surfaces 16 May 2018 [rickr] */ if ( val == 2 ) lvpo.map_all = 1; ready = (val>0); /* this is the interface to "ready" */ /* now get map */ str = PLUTO_get_string(plint); val = PLUTO_string_index(str, P_MAP_NAMES_NVALS, g->maps); if ( ready && val == E_SMAP_INVALID ) { sprintf( mesg, "--------------------------------\n" "please choose a mapping function\n" "--------------------------------" ); RETURN(1); } else if (ready && ((val < E_SMAP_INVALID) || (val >= E_SMAP_FINAL))) { PV2S_BAIL_VALUE(mesg, "illegal 'map func'", val); RETURN(1); } sopt->map = val; /* now get step index */ str = PLUTO_get_string(plint); val = PLUTO_string_index(str, P_STEP_NVALS, gp_step_list); sopt->f_index = val > 0 ? 1 : 0; /* be sure */ val = (int)PLUTO_get_number(plint); /* num steps */ if (ready && ((val <= 0) || (val >= V2S_STEPS_TOOOOO_BIG))) { PV2S_BAIL_VALUE(mesg, "steps too big", val); RETURN(1); } sopt->f_steps = val; } else if ( ! strcmp(tag, "surf pair 0") ) { lvpo.use0 = 0; str = PLUTO_get_string(plint); if ( PLUTO_string_index(str, P_NY_NVALS, gp_ny_list) != 0 ) { lvpo.use0 = 1; lvpo.s0A = (int)PLUTO_get_number(plint); lvpo.s0B = -1; /* first assume to not use surf_B */ str = PLUTO_get_string(plint); if ( PLUTO_string_index(str, P_NY_NVALS, gp_ny_list) != 0 ) lvpo.s0B = (int)PLUTO_get_number(plint); } } else if ( ! strcmp(tag, "surf pair 1") ) { lvpo.use1 = 0; str = PLUTO_get_string(plint); if ( PLUTO_string_index(str, P_NY_NVALS, gp_ny_list) != 0 ) { lvpo.use1 = 1; lvpo.s1A = (int)PLUTO_get_number(plint); lvpo.s1B = -1; /* first assume to not use surf_B */ str = PLUTO_get_string(plint); if ( PLUTO_string_index(str, P_NY_NVALS, gp_ny_list) != 0 ) lvpo.s1B = (int)PLUTO_get_number(plint); } } else if ( ! strcmp(tag, "normals") ) { str = PLUTO_get_string(plint); if ( PLUTO_string_index(str, P_NY_NVALS, gp_ny_list) != 0 ) { sopt->use_norms = 1; sopt->norm_len = PLUTO_get_number(plint); str = PLUTO_get_string(plint); val = PLUTO_string_index(str, P_KEEP_NVALS, gp_keep_list); if ( val == 1 ) sopt->norm_dir = V2S_NORM_KEEP; else if ( val == 2 ) sopt->norm_dir = V2S_NORM_REVERSE; else sopt->norm_dir = V2S_NORM_DEFAULT; } else sopt->use_norms = 0; } else if ( ! strcmp(tag, "offsets") ) { int test = 0; sopt->f_p1_mm = PLUTO_get_number(plint); sopt->f_pn_mm = PLUTO_get_number(plint); sopt->f_p1_fr = PLUTO_get_number(plint); sopt->f_pn_fr = PLUTO_get_number(plint); /* check for consistency */ if ( sopt->f_p1_fr != 0 || sopt->f_pn_fr != 0 ) test |= 1; if ( sopt->f_p1_mm != 0 || sopt->f_pn_mm != 0 ) test |= 2; if ( ready && test > 2 ) /* i.e. == 3 */ { sprintf( mesg, "---------------------------------\n" "use only one pair of f*_mm, f*_fr\n" "to change normal lengths \n" "---------------------------------" ); RETURN(1); } } else if ( ! strcmp(tag, "oor") ) { /* out of bounds ... */ str = PLUTO_get_string(plint); val = PLUTO_string_index(str, P_NY_NVALS, gp_ny_list); fval = PLUTO_get_number(plint); if ( val != 0 ) { sopt->oob.show = 1; sopt->oob.value = fval; } else sopt->oob.show = 0; /* out of mask ... */ str = PLUTO_get_string(plint); val = PLUTO_string_index(str, P_NY_NVALS, gp_ny_list); fval = PLUTO_get_number(plint); if ( val != 0 ) { sopt->oom.show = 1; sopt->oom.value = fval; } else sopt->oom.show = 0; } else if ( ! strcmp(tag, "output") ) { sopt->first_node = (int)PLUTO_get_number(plint); sopt->last_node = (int)PLUTO_get_number(plint); if ( ready && sopt->first_node > sopt->last_node ) { sprintf( mesg, "-----------------------------\n" "illegal node range values: \n" "first (%d) > last (%d) \n" "-----------------------------", sopt->first_node, sopt->last_node ); RETURN(1); } /* get output filenames */ if ( sopt->outfile_1D ) free(sopt->outfile_1D); if ( sopt->outfile_niml ) free(sopt->outfile_niml); sopt->outfile_1D = sopt->outfile_niml = NULL; str = PLUTO_get_string(plint); if ( strlen(str) > 0 ) { sopt->outfile_1D = (char *)calloc(strlen(str)+1,sizeof(char)); strcpy(sopt->outfile_1D, str); } str = PLUTO_get_string(plint); /* make sure the string looks like *.niml.dset 4 Nov 2008 */ val = strlen(str); if ( val > 0 && (val < 11 || strcmp(str+val-10,".niml.dset")) ) { sprintf( mesg, "-----------------------------------\n" "NIML dataset must end in .niml.dset\n" "have: %s\n" "-----------------------------------", str ); RETURN(1); } if ( strlen(str) > 0 ) { sopt->outfile_niml = (char *)calloc(strlen(str)+1,sizeof(char)); strcpy(sopt->outfile_niml, str); } } else if ( ! strcmp(tag, "debug level") ) { sopt->debug = (int)PLUTO_get_number(plint); sopt->dnode = (int)PLUTO_get_number(plint); } else { sprintf( mesg, "---------------------------\n" "Unknown option tag : %s\n" "---------------------------", tag ); RETURN(1); } } if ( sopt->debug > 1 ) { disp_v2s_plugin_opts( "plug_vol2surf options done : ", &lvpo ); disp_v2s_opts_t( " surface options : ", sopt ); } /* should we just run away? always adjust debugging first... */ g->vpo->sopt.debug = lvpo.sopt.debug; g->vpo->sopt.dnode = lvpo.sopt.dnode; if ( lvpo.use0 == 0 && lvpo.use1 == 0 ) ready = 0; if ( ! ready ) { if ( sopt->debug > 0 ) PV2S_disp_afni_surfaces(plint); RETURN(1); } if ( ! v2s_is_good_map(sopt->map, 1) ) { sprintf( mesg, "-------------------------------------------\n" "mapping function is invalid in this context\n" "index %d, name '%s'\n" "-------------------------------------------", sopt->map, (sopt->map < E_SMAP_INVALID || sopt->map >= E_SMAP_FINAL) ? "out-of-range" : g->maps[sopt->map] ); RETURN(1); } /* verify surface consistency */ if ( lvpo.use0 ) { if ( PV2S_check_surfaces(plint, lvpo.s0A, lvpo.s0B, mesg, sopt->debug) ) RETURN(1); if ( lvpo.s0A == lvpo.s0B ) { sprintf( mesg, "--------------------------------\n" "error: for pair 0, surfA = surfB\n" "--------------------------------" ); RETURN(1); } lvpo.label[0] = ss->su_surf[lvpo.s0A]->label_ldp; if(lvpo.s0B >= 0) lvpo.label[1] = ss->su_surf[lvpo.s0B]->label_ldp; } else lvpo.label[0] = lvpo.label[1] = gv2s_no_label; /* no labels */ if ( lvpo.use1 ) { if ( PV2S_check_surfaces(plint, lvpo.s1A, lvpo.s1B, mesg, sopt->debug) ) RETURN(1); if ( lvpo.s1A == lvpo.s1B ) { sprintf( mesg, "--------------------------------\n" "error: for pair 1, surfA = surfB\n" "--------------------------------" ); RETURN(1); } lvpo.label[2] = ss->su_surf[lvpo.s1A]->label_ldp; if(lvpo.s1B >= 0) lvpo.label[3] = ss->su_surf[lvpo.s1B]->label_ldp; } else lvpo.label[2] = lvpo.label[3] = gv2s_no_label; /* no labels */ /* if the user wants normals, they can only supply one surface per pair */ if ( sopt->use_norms && ((lvpo.use0 && lvpo.s0B >= 0) || (lvpo.use1 && lvpo.s1B >= 0)) ) { sprintf( mesg, "----------------------------------------\n" "cannot use normals while using surface B\n" "----------------------------------------" ); RETURN(1); } if ( sopt->debug > 0 ) PV2S_disp_afni_surfaces(plint); /* for now, only output nodes and a single data column */ sopt->skip_cols = V2S_SKIP_ALL ^ V2S_SKIP_NODES; if ( ready ) /* then copy changes over old values */ { *g->vpo = lvpo; g->vpo->ready = 1; } RETURN(0); } static int PV2S_check_surfaces(PLUGIN_interface * plint, int sa, int sb, char * mesg, int debug) { THD_session * ss; ENTRY("PV2S_check_surfaces"); ss = plint->im3d->ss_now; if ( ss->su_num < 1 ) { PV2S_BAIL_VALUE(mesg, "Not enough surfaces in session.\n", ss->su_num); RETURN(1); } /* verify that the surface indices are valid */ if ( sa < 0 ) { PV2S_BAIL_VALUE(mesg, "surf_A has invalid index", sa); RETURN(1); } if ( sa >= ss->su_num ) { PV2S_BAIL_VALUE(mesg, "surf_A beyond valid index", ss->su_num - 1); RETURN(1); } if ( sb >= ss->su_num ) { PV2S_BAIL_VALUE(mesg, "surf_B beyond valid index", ss->su_num - 1); RETURN(1); } if ( sb >= 0 ) { /* then check that surf_A and surf_B share LDP */ if (strncmp(ss->su_surf[sa]->idcode_ldp,ss->su_surf[sb]->idcode_ldp,32)) { char * la = ss->su_surf[sa]->label_ldp; char * lb = ss->su_surf[sb]->label_ldp; if ( ! *la ) la = "undefined"; if ( ! *lb ) lb = "undefined"; sprintf(mesg, "---------------------------------------\n" "Error: Surf_A and Surf_B have different\n" " local domain parents\n" "LDP #%d = '%s', LDP #%d = '%s'\n" "---------------------------------------", sa, la, sb, lb); RETURN(1); } /* and that they have the same number of nodes */ if ( ss->su_surf[sa]->num_ixyz != ss->su_surf[sb]->num_ixyz ) { sprintf(mesg, "------------------------------------------------\n" "Big problem: Surf_A and Surf_B have different\n" " numbers of nodes! They cannot share an LDP.\n" " SurfA: '%s', %d nodes\n" " SurfB: '%s', %d nodes\n" "------------------------------------------------", ss->su_surf[sa]->label, ss->su_surf[sa]->num_ixyz, ss->su_surf[sb]->label, ss->su_surf[sb]->num_ixyz); RETURN(1); } } if ( debug > 0 && ss->su_surf ) { if ( ss->su_surf[sa] ) /* we have checked sa >= 0, above */ fprintf(stderr,"+d surf_A label: '%s'\n", *ss->su_surf[sa]->label ? ss->su_surf[sa]->label : "not set"); else fprintf(stderr,"** surf_A (#%d) pointer not set??\n", sa); if ( sb < 0 ) fprintf(stderr,"-d surf_B not in use\n"); else if ( ss->su_surf[sb] ) fprintf(stderr,"+d surf_B label: '%s'\n", *ss->su_surf[sb]->label ? ss->su_surf[sb]->label : "not set"); else fprintf(stderr,"** surf_B (#%d) pointer not set??\n", sb); } RETURN(0); } static int PV2S_disp_afni_surfaces(PLUGIN_interface * plint) { THD_session * ss; char * ldp, * label; int c; ENTRY("disp_afni_surfaces"); ss = plint->im3d->ss_now; if ( ss->su_surf <= 0 ) RETURN(0); fprintf(stderr,"-d --------------------------------------\n"); fprintf(stderr," afni surface indices, labels and LDPs:\n"); for ( c = 0; c < ss->su_num; c++ ) { label = ss->su_surf[c]->label; ldp = ss->su_surf[c]->label_ldp; if ( ! *label ) label = "undefined"; if ( ! *ldp ) ldp = "undefined"; fprintf(stderr," index %2d, label '%s', LDP '%s'\n", c, label, ldp ); } RETURN(0); }