1 /***********************************************************************
2 * plug_vol2surf.c - plugin interface to vol2surf computation
3 *
4 * Provide an interface to the global v2s_plugin_opts structure.
5 *
6 * - R. Reynolds
7 ***********************************************************************
8 */
9
10 #include "afni.h"
11 #include "vol2surf.h"
12
13 #ifndef ALLOW_PLUGINS
14 # error "Plugins not properly set up -- see machdep.h"
15 #endif
16
17 static char * PV2S_main( PLUGIN_interface * );
18
19 static char g_help[] =
20 " This plugin provides an interface to the vol2surf options used by afni\n"
21 " for the display of the Overlay dataset values on the surfaces in suma.\n"
22 " \n"
23 " For each Local Domain Parent that afni has received from suma, vol2surf\n"
24 " computes a node color overlay and sends it to suma. This is computed\n"
25 " by mapping afni's Overlay data across the 1 or 2 surfaces of each given\n"
26 " LDP (Local Domain Parent).\n"
27 " \n"
28 " By default, each LDP gets a color list based on:\n"
29 " \n"
30 " o if only 1 surface for this LDP : intersection of the surface\n"
31 " and afni's Overlay sub-brick, subject to afni's color bar and\n"
32 " thresholding (afni voxels that do not survive the threshold take\n"
33 " no part in the mapping)\n"
34 " \n"
35 " o if 2 or more surfaces for this LDP : intersection of the midpoint\n"
36 " of the first 2 surfaces received from suma (for this LDP) and the\n"
37 " Overlay sub-brick in afni, again subject to afni's color bar and\n"
38 " thresholding\n"
39 " \n"
40 " These defaults are for surfaces that have _not_ been chosen via the\n"
41 " plugin interface. Surfaces chosen via the plugin are, of course,\n"
42 " mapped as the user specifies. Note that to recreate the defaults, use\n"
43 " the 'mask' function for 1 surface, and the midpoint function for more\n"
44 " than 1. The 'num steps' and 'seg index' will not be applicable.\n"
45 " \n"
46 " As of May, 2018, there is a 'map_all' option under 'use vol2surf'. In\n"
47 " that case, all mappable surfaces will be processed using the plugin\n"
48 " options, rather than the simple defaults.\n"
49 " \n"
50 " ---\n"
51 " \n"
52 " The minimum choices that must be made are on the 'function' line:\n"
53 " 'use vol2surf?' (should be 'yes' :), and 'map func' (should be valid).\n"
54 " \n"
55 " ** Note that as a plugin, surfaces will be unknown at initialization\n"
56 " time. Therefore the interface is via afni's surface index list.\n"
57 " To see the surface index list, set the debug level to 2, and then\n"
58 " press 'Set+Keep'. Part of the text output to the _terminal window_\n"
59 " will be '+d valid surface indices and labels: ...'.\n"
60 " \n"
61 " ** For detailed infomation, please try the command: '3dVol2Surf -help'.\n"
62 " \n"
63 " ----------------------------- options --------------------------------\n"
64 " function:\n"
65 " \n"
66 " use vol2surf? : choose 'yes' to make the plugin options active\n"
67 " choose 'map_all' to apply options to all surfaces,\n"
68 " not simply those in pair 0 and/or 1\n"
69 " map func : choose a function to apply to values along node pair\n"
70 " segments, embedded in the AFNI volume\n"
71 " seg index : apply all values along a each segment, or only those\n"
72 " from unique voxels\n"
73 " num steps : the number of evenly spaced points each segment will\n"
74 " be divided into\n"
75 " \n"
76 " surf pair 0:\n"
77 " \n"
78 " apply? : if no, skip this surface (pair)\n"
79 " surf_A : choose the afni surface index for surface A\n"
80 " use B? : form segments by joining nodes from surface A with\n"
81 " nodes on surface B (an alternate choice is to use\n"
82 " only surface A, along with its normals)\n"
83 " surf_B : choose the afni surface index for surface B\n"
84 " \n"
85 " surf pair 1:\n"
86 " \n"
87 " apply? : if no, skip this surface (pair)\n"
88 " surf_A : choose the afni surface index for surface A\n"
89 " use B? : form segments by joining nodes from surface A with\n"
90 " nodes on surface B (an alternate choice is to use\n"
91 " only surface A, along with its normals)\n"
92 " surf_B : choose the afni surface index for surface B\n"
93 " \n"
94 " normals:\n"
95 " \n"
96 " use normals? : segments are formed from each node from surface A\n"
97 " along its normal, and of length 'norm len'\n"
98 " norm len : this will be the length of each segment\n"
99 " norm dir : choose what to do with the normal directions:\n"
100 " check : let vol2surf try to decide\n"
101 " keep : keep the default directions\n"
102 " reverse : reverse the default directions\n"
103 " \n"
104 " offsets:\n"
105 " \n"
106 " NOTE - segments are considered directed from the node on surface A\n"
107 " in the direction of surface B (or the normal), so if f_p1 is\n"
108 " positive each segment gets shorter (going toward surface B),\n"
109 " but if f_pn is positive each segment gets longer (still moving\n"
110 " in the direction from surface A to surface B)\n"
111 " \n"
112 " f_p1_mm : move each segment starting point this number of\n"
113 " millimeters toward surface B\n"
114 " f_pn_mm : move each segment ending point this number of\n"
115 " millimeters farther from surface A\n"
116 " f_p1_fr : move each segment starting point this fraction of the\n"
117 " distance toward surface B\n"
118 " f_pn_fr : move each segment ending point this fraction of the\n"
119 " distance farther from surface A\n"
120 " \n"
121 " out of range:\n"
122 " \n"
123 " oob nodes? : whether to still output results for those nodes which\n"
124 " are out-of-bounds (i.e. outside the bounding box of\n"
125 " the AFNI overlay dataset)\n"
126 " oob value : if out-of-bounds nodes are output, this value will be\n"
127 " given to them\n"
128 " oom nodes? : whether to still output results for those nodes which\n"
129 " are out-of-mask (i.e. masked by the threshold brick)\n"
130 " oob value : if out-of-mask nodes are output, this value will be\n"
131 " given to them\n"
132 " output:\n"
133 " \n"
134 " first node : starting index for nodes to output\n"
135 " last node : ending index for nodes to output (0 means 'nodes-1')\n"
136 " (sorry, that means you cannot output from 0 to 0)\n"
137 " outfile.1D : also send the results to this file (in 1D format)\n"
138 " outfile.niml : also send the results to this file (in niml format)\n"
139 " \n"
140 " debug level:\n"
141 " \n"
142 " level : provide this level of debug output (0-5)\n"
143 " node : provide additional debug output for this node\n"
144 " \n"
145 " \n"
146 " Author: R Reynolds\n"
147 " \n"
148 " ----------------------------------------------------------------------\n"
149 " History:\n"
150 " \n"
151 " 1.0 9 September 2004 [rickr] - initial version\n"
152 " \n"
153 " 1.1 16 September 2004 [rickr]\n"
154 " - init gp_index to -1 (set it in afni)\n"
155 " - allow the user to keep or reverse normal directions\n"
156 " \n"
157 " 1.2 29 September 2004 [rickr]\n"
158 " - now set global ready if all is well\n"
159 " - clear norms if not in use\n"
160 " - name all local functions PV2S_*\n"
161 " - if debug > 0, display chosen surfaces in terminal\n"
162 " - if debug > 1, display all possible surfaces in terminal\n"
163 " \n"
164 " 1.3 08 October 2004 [rickr]\n"
165 " - Global changes for new LDP processing:\n"
166 " - added second surface pair to GUI\n"
167 " - made small help and hint changes\n"
168 " - fixed receive order of fr and mm offsets (mm was fr)\n"
169 " - verify that surface pairs have matching LDPs\n"
170 " - added PV2S_disp_afni_surfaces() to list all surfaces w/indices\n"
171 " \n"
172 " 1.4 25 October 2004 [rickr]\n"
173 " - make sure the surface pairs are actually different\n"
174 " - make sure surfaces have the same number of nodes\n"
175 " - process all parameters, but only complain if 'ready'\n"
176 " - always pass along debug/dnode\n"
177 " \n"
178 " 1.5 11 Dec 2004 [rickr] - describe default behavior here\n"
179 " 1.5a 22 Mar 2005 [rickr] - removed all tabs\n"
180 " 1.6 28 Mar 2006 [rickr] - fixed mode computation\n"
181 " 1.7 09 Aug 2006 [rickr] - store surface labels for history note\n"
182 ;
183
184 #define P_MAP_NAMES_NVALS 16 /* should match enum for global maps */
185 #define P_NY_NVALS 2
186 #define P_NYA_NVALS 3
187 #define P_KEEP_NVALS 3
188 #define P_STEP_NVALS 2
189
190 static char * gp_ny_list[] = { "no", "yes" };
191 static char * gp_nyA_list[] = { "no", "yes", "map_all" };
192 static char * gp_keep_list[] = { "no check yet", "keep", "reverse" };
193 static char * gp_step_list[] = { "voxel", "node" };
194
195 typedef struct
196 {
197 v2s_plugin_opts * vpo;
198 char * hist;
199 char ** maps;
200 } pv2s_globals;
201
202 static pv2s_globals globs; /* these are just pointers to afni globals */
203
204 /* local functions */
205 static int PV2S_check_surfaces(PLUGIN_interface * plint, int sa, int sb,
206 char *mesg, int debug);
207 static int PV2S_disp_afni_surfaces(PLUGIN_interface * plint);
208 static int PV2S_init_plugin_opts(pv2s_globals * g);
209 static int PV2S_process_args(PLUGIN_interface * plint,pv2s_globals * g,
210 char *mesg);
211
212 /* for ease of error reporting */
213 #define PV2S_BAIL_VALUE(buf,str,val) \
214 do { sprintf((buf), "-------------------------------------\n" \
215 "%s\n" \
216 "bad value = %d\n" \
217 "-------------------------------------", \
218 (str), (val) ); } while (0)
219
220 DEFINE_PLUGIN_PROTOTYPE /* for C++ compilation */
221
PLUGIN_init(int ncall)222 PLUGIN_interface * PLUGIN_init( int ncall )
223 {
224 PLUGIN_interface * plint;
225 void * void_vpo;
226 int ival;
227
228 ENTRY("vol2surf: PLUGIN_init");
229
230 if ( ncall > 0 ) RETURN(NULL); /* only one interface */
231
232 /* might be temporary */
233 if ( PLUTO_set_v2s_addrs(&void_vpo, &globs.maps, &globs.hist) )
234 {
235 fprintf(stderr,"** plug_v2s: failed to init globals\n");
236 RETURN(NULL);
237 }
238
239 /* using a void pointer so we don't have to put vol2surf.h in afni.h */
240 globs.vpo = (v2s_plugin_opts *)void_vpo;
241
242 PV2S_init_plugin_opts(&globs);
243
244 plint = PLUTO_new_interface("Vol2Surf",
245 "configure afni's volume to surface options",
246 g_help, PLUGIN_CALL_VIA_MENU, PV2S_main);
247
248 PLUTO_add_hint (plint, "configure vol2surf options");
249 PLUTO_set_sequence (plint, "A:afnicontrol:surf");
250 PLUTO_set_runlabels(plint, "Set+Keep", "Set+Close");
251
252 /* first input : do we use vol2surf? */
253 PLUTO_add_option( plint, "function", "op_st", TRUE );
254 PLUTO_add_hint ( plint, "decide whether to use vol2surf" );
255 PLUTO_add_string( plint, "use vol2surf? ", P_NYA_NVALS, gp_nyA_list, 0 );
256 PLUTO_add_hint ( plint, "use vol2surf (or basic intersection)" );
257 PLUTO_add_string( plint, "map func",P_MAP_NAMES_NVALS,globs.maps,0);
258 PLUTO_add_hint ( plint, "choose a filter to apply to segment values" );
259 PLUTO_add_string( plint, "seg index",P_STEP_NVALS,gp_step_list,0);
260 PLUTO_add_hint ( plint, "along segments, count only distinct voxels?");
261 PLUTO_add_number( plint, "num steps", 0, 100, 0, 2, 1 );
262 PLUTO_add_hint ( plint, "number of steps to divide each segment into" );
263
264 /* choose surface indices for surf pair 0 */
265 /* - note that we do not yet have surfaces to choose from */
266 PLUTO_add_option( plint, "surf pair 0", "surf pair 0", TRUE );
267 PLUTO_add_hint ( plint, "choose first surface index(es)" );
268 PLUTO_add_string( plint, "apply? ", P_NY_NVALS, gp_ny_list, 1 );
269 PLUTO_add_hint ( plint, "decide whether to apply surface(s)" );
270 PLUTO_add_number( plint, "surf_A", 0, 50, 0, 0, 1 );
271 PLUTO_add_hint ( plint, "choose surface A index" );
272 PLUTO_add_string( plint, "use B? ", P_NY_NVALS, gp_ny_list, 0 );
273 PLUTO_add_hint ( plint, "decide whether to use surface B" );
274 PLUTO_add_number( plint, "surf_B", 0, 50, 0, 1, 1 );
275 PLUTO_add_hint ( plint, "choose surface B index" );
276
277 /* choose surface indices for surf pair 1 */
278 /* - note that we do not yet have surfaces to choose from */
279 PLUTO_add_option( plint, "surf pair 1", "surf pair 1", TRUE );
280 PLUTO_add_hint ( plint, "choose second surface index(es)" );
281 PLUTO_add_string( plint, "apply? ", P_NY_NVALS, gp_ny_list, 0 );
282 PLUTO_add_hint ( plint, "decide whether to apply surface(s)" );
283 PLUTO_add_number( plint, "surf_A", 0, 50, 0, 2, 1 );
284 PLUTO_add_hint ( plint, "choose surface A index" );
285 PLUTO_add_string( plint, "use B? ", P_NY_NVALS, gp_ny_list, 0 );
286 PLUTO_add_hint ( plint, "decide whether to use surface B" );
287 PLUTO_add_number( plint, "surf_B", 0, 50, 0, 3, 1 );
288 PLUTO_add_hint ( plint, "choose surface B index" );
289
290 /* menu for using normals */
291 PLUTO_add_option( plint, "normals", "normals", FALSE );
292 PLUTO_add_hint ( plint, "control use of normals (instead of surf_B)" );
293 PLUTO_add_string( plint, "use normals? ", P_NY_NVALS, gp_ny_list, 0 );
294 PLUTO_add_hint ( plint, "should normals be used to simulate surf_B?" );
295 PLUTO_add_number( plint, "norm len", -100, 100, 1, 10, 1 );
296 PLUTO_add_hint ( plint, "what (signed) length should the normals be?" );
297 PLUTO_add_string( plint, "norm dir", P_KEEP_NVALS, gp_keep_list, 1 );
298 PLUTO_add_hint ( plint, "check normal direction, or keep or reverse it" );
299
300 /* segment offsets */
301 PLUTO_add_option( plint, "offsets", "offsets", FALSE );
302 PLUTO_add_hint ( plint,"offset segment endpoints, directed from p1 to pn");
303 PLUTO_add_number( plint, "f_p1_mm", -100, 100, 1, 0, 1 );
304 PLUTO_add_hint ( plint, "move p1 towards pn, in millimeters" );
305 PLUTO_add_number( plint, "f_pn_mm", -100, 100, 1, 0, 1 );
306 PLUTO_add_hint ( plint, "move pn farther from p1, in millimeters" );
307 PLUTO_add_number( plint, "f_p1_fr", -100, 100, 1, 0, 1 );
308 PLUTO_add_hint ( plint, "move p1 towards pn, by this segment fraction" );
309 PLUTO_add_number( plint, "f_pn_fr", -100, 100, 1, 0, 1 );
310 PLUTO_add_hint ( plint, "move pn farther from p1, by this fraction" );
311
312 /* out of bounds or mask */
313 PLUTO_add_option( plint, "out of range", "oor", FALSE );
314 PLUTO_add_hint ( plint, "what to do when out of bounds or mask" );
315 PLUTO_add_string( plint, "oob nodes?", P_NY_NVALS, gp_ny_list, 0 );
316 PLUTO_add_hint ( plint, "keep out-of-bounds nodes? (outside the dataset)");
317 PLUTO_add_number( plint, "oob value", 0, 0, 0, -2, 1 );
318 PLUTO_add_hint ( plint, "value to apply when out of dataset bounds" );
319 PLUTO_add_string( plint, "oom nodes?", P_NY_NVALS, gp_ny_list, 0 );
320 PLUTO_add_hint ( plint, "keep out-of-mask nodes? (below threshold)");
321 PLUTO_add_number( plint, "oom value", 0, 0, 0, -1, 1 );
322 PLUTO_add_hint ( plint, "value for masked out nodes" );
323
324 /* choose node processing range */
325 PLUTO_add_option( plint, "output", "output", FALSE );
326 PLUTO_add_hint ( plint, "select node range and output files" );
327 PLUTO_add_number( plint, "first node", 0, 0, 0, 0, 1 );
328 PLUTO_add_hint ( plint, "starting node to process (zero based)" );
329 PLUTO_add_number( plint, "last node", 0, 0, 0, 0, 1 );
330 PLUTO_add_hint ( plint, "end node to process (zero based)" );
331 PLUTO_add_string( plint, "outfile.1D", 0, NULL, 14 );
332 PLUTO_add_hint ( plint, "name for 1D output file - will overwrite!" );
333 PLUTO_add_string( plint, "outfile.niml", 0, NULL, 14 );
334 PLUTO_add_hint ( plint, "name for niml output file - will overwrite!" );
335
336 /* debugging level (0 if not set) */
337 PLUTO_add_option( plint, "debug level", "debug level", FALSE );
338 PLUTO_add_hint ( plint, "choose debug level (and debug node)" );
339 PLUTO_add_number( plint, "level", 0, 5, 0, globs.vpo->sopt.debug, 1 );
340 PLUTO_add_hint ( plint, "debug level - how much to print to terminal" );
341 PLUTO_add_number( plint, "node", 0, 0, 0, -1, 1 );
342 PLUTO_add_hint ( plint, "particular node to print debug infomation for" );
343
344 RETURN(plint);
345 }
346
PV2S_main(PLUGIN_interface * plint)347 char * PV2S_main ( PLUGIN_interface * plint )
348 {
349 pv2s_globals * g;
350 static char message[2048]; /* use this to output failures */
351
352 ENTRY("PV2S_main");
353
354 g = &globs; /* to have only one global access */
355 message[0] = '\0'; /* init to empty string */
356
357 g->vpo->ready = 0;
358
359 if ( (PV2S_process_args(plint, g, message) != 0) && message[0] )
360 RETURN(message);
361
362 RETURN(NULL);
363 }
364
365 /* base defaults to local and duplicate to global */
PV2S_init_plugin_opts(pv2s_globals * g)366 static int PV2S_init_plugin_opts(pv2s_globals * g)
367 {
368 int ival;
369 ENTRY("PV2S_init_plugin_opts");
370 memset(g->vpo, 0, sizeof(*g->vpo));
371
372 g->vpo->ready = 0; /* flag as "not ready to go" */
373 g->vpo->use0 = 0;
374 g->vpo->use1 = 0;
375 g->vpo->s0A = -1;
376 g->vpo->s0B = -1;
377 g->vpo->s1A = -1;
378 g->vpo->s1B = -1;
379 g->vpo->label[0] = gv2s_no_label; /* init surface labels as undefined */
380 g->vpo->label[0] = gv2s_no_label; /* 7 Aug 2006 [rickr] */
381 g->vpo->label[0] = gv2s_no_label;
382 g->vpo->label[0] = gv2s_no_label;
383
384 g->vpo->sopt.gp_index = -1;
385
386 /* maybe init debug from env 16 Sep 2009 [rickr] */
387 ival = (int)AFNI_numenv("AFNI_DEBUG_PLUG_VOL2SURF") ;
388 if( ival < 0 ) ival = 0;
389 if( ival > 5 ) ival = 5; /* limit to plugin range */
390 g->vpo->sopt.debug = ival;
391
392 g->vpo->sopt.dnode = -1;
393 g->vpo->sopt.outfile_1D = NULL;
394 g->vpo->sopt.outfile_niml = NULL;
395 g->vpo->sopt.segc_file = NULL; /* 30 Jun 2006 */
396
397 RETURN(0);
398 }
399
400
401
PV2S_process_args(PLUGIN_interface * plint,pv2s_globals * g,char * mesg)402 static int PV2S_process_args(PLUGIN_interface * plint, pv2s_globals * g,
403 char * mesg)
404 {
405 THD_session * ss;
406 v2s_plugin_opts lvpo;
407 v2s_opts_t * sopt;
408 float fval;
409 char * tag, * str;
410 int val, ready = 0;
411
412 ENTRY("PV2S_process_args");
413
414 /* do we have a valid 3D view and session? */
415 if ( !IM3D_OPEN(plint->im3d) || !plint->im3d->ss_now )
416 {
417 sprintf(mesg, "----------------------------------------------\n"
418 "strange failure: invalid 3D view or session???\n"
419 "----------------------------------------------");
420 RETURN(-1);
421 }
422
423 /* to a quick check to be sure we are talking with suma */
424 ss = plint->im3d->ss_now;
425 if (ss && ss->su_num < 1)
426 {
427 sprintf(mesg, "-----------------------------------------\n"
428 "no surfaces: is afni 'talking' with suma?\n"
429 "-----------------------------------------");
430 RETURN(1);
431 }
432
433 /* copy current values, and make local changes while checking */
434 lvpo = *g->vpo;
435 sopt = &lvpo.sopt; /* just for typing */
436
437 while ( (tag = PLUTO_get_optiontag(plint)) != NULL )
438 {
439 if ( sopt->debug > 2 )
440 fprintf(stderr,"+d received option tag: %s\n", tag);
441
442 if ( ! strcmp(tag, "op_st") )
443 {
444 str = PLUTO_get_string(plint);
445 val = PLUTO_string_index(str, P_NYA_NVALS, gp_nyA_list);
446
447 if ( (val < 0) || (val >= P_NYA_NVALS) )
448 {
449 PV2S_BAIL_VALUE(mesg,"bad NYA vals", val);
450 RETURN(1);
451 }
452 /* option to process v2s on all surfaces 16 May 2018 [rickr] */
453 if ( val == 2 ) lvpo.map_all = 1;
454
455 ready = (val>0); /* this is the interface to "ready" */
456
457 /* now get map */
458 str = PLUTO_get_string(plint);
459 val = PLUTO_string_index(str, P_MAP_NAMES_NVALS, g->maps);
460 if ( ready && val == E_SMAP_INVALID )
461 {
462 sprintf( mesg, "--------------------------------\n"
463 "please choose a mapping function\n"
464 "--------------------------------" );
465 RETURN(1);
466 }
467 else if (ready && ((val < E_SMAP_INVALID) || (val >= E_SMAP_FINAL)))
468 {
469 PV2S_BAIL_VALUE(mesg, "illegal 'map func'", val);
470 RETURN(1);
471 }
472 sopt->map = val;
473
474 /* now get step index */
475 str = PLUTO_get_string(plint);
476 val = PLUTO_string_index(str, P_STEP_NVALS, gp_step_list);
477 sopt->f_index = val > 0 ? 1 : 0; /* be sure */
478
479 val = (int)PLUTO_get_number(plint); /* num steps */
480 if (ready && ((val <= 0) || (val >= V2S_STEPS_TOOOOO_BIG)))
481 {
482 PV2S_BAIL_VALUE(mesg, "steps too big", val);
483 RETURN(1);
484 }
485 sopt->f_steps = val;
486 }
487 else if ( ! strcmp(tag, "surf pair 0") )
488 {
489 lvpo.use0 = 0;
490 str = PLUTO_get_string(plint);
491 if ( PLUTO_string_index(str, P_NY_NVALS, gp_ny_list) != 0 )
492 {
493 lvpo.use0 = 1;
494 lvpo.s0A = (int)PLUTO_get_number(plint);
495 lvpo.s0B = -1; /* first assume to not use surf_B */
496 str = PLUTO_get_string(plint);
497 if ( PLUTO_string_index(str, P_NY_NVALS, gp_ny_list) != 0 )
498 lvpo.s0B = (int)PLUTO_get_number(plint);
499 }
500 }
501 else if ( ! strcmp(tag, "surf pair 1") )
502 {
503 lvpo.use1 = 0;
504 str = PLUTO_get_string(plint);
505 if ( PLUTO_string_index(str, P_NY_NVALS, gp_ny_list) != 0 )
506 {
507 lvpo.use1 = 1;
508 lvpo.s1A = (int)PLUTO_get_number(plint);
509 lvpo.s1B = -1; /* first assume to not use surf_B */
510 str = PLUTO_get_string(plint);
511 if ( PLUTO_string_index(str, P_NY_NVALS, gp_ny_list) != 0 )
512 lvpo.s1B = (int)PLUTO_get_number(plint);
513 }
514 }
515 else if ( ! strcmp(tag, "normals") )
516 {
517 str = PLUTO_get_string(plint);
518 if ( PLUTO_string_index(str, P_NY_NVALS, gp_ny_list) != 0 )
519 {
520 sopt->use_norms = 1;
521 sopt->norm_len = PLUTO_get_number(plint);
522
523 str = PLUTO_get_string(plint);
524 val = PLUTO_string_index(str, P_KEEP_NVALS, gp_keep_list);
525 if ( val == 1 ) sopt->norm_dir = V2S_NORM_KEEP;
526 else if ( val == 2 ) sopt->norm_dir = V2S_NORM_REVERSE;
527 else sopt->norm_dir = V2S_NORM_DEFAULT;
528 }
529 else
530 sopt->use_norms = 0;
531 }
532 else if ( ! strcmp(tag, "offsets") )
533 {
534 int test = 0;
535
536 sopt->f_p1_mm = PLUTO_get_number(plint);
537 sopt->f_pn_mm = PLUTO_get_number(plint);
538 sopt->f_p1_fr = PLUTO_get_number(plint);
539 sopt->f_pn_fr = PLUTO_get_number(plint);
540
541 /* check for consistency */
542 if ( sopt->f_p1_fr != 0 || sopt->f_pn_fr != 0 ) test |= 1;
543 if ( sopt->f_p1_mm != 0 || sopt->f_pn_mm != 0 ) test |= 2;
544 if ( ready && test > 2 ) /* i.e. == 3 */
545 {
546 sprintf( mesg, "---------------------------------\n"
547 "use only one pair of f*_mm, f*_fr\n"
548 "to change normal lengths \n"
549 "---------------------------------" );
550 RETURN(1);
551 }
552 }
553 else if ( ! strcmp(tag, "oor") )
554 {
555 /* out of bounds ... */
556 str = PLUTO_get_string(plint);
557 val = PLUTO_string_index(str, P_NY_NVALS, gp_ny_list);
558 fval = PLUTO_get_number(plint);
559 if ( val != 0 )
560 {
561 sopt->oob.show = 1;
562 sopt->oob.value = fval;
563 }
564 else
565 sopt->oob.show = 0;
566
567 /* out of mask ... */
568 str = PLUTO_get_string(plint);
569 val = PLUTO_string_index(str, P_NY_NVALS, gp_ny_list);
570 fval = PLUTO_get_number(plint);
571 if ( val != 0 )
572 {
573 sopt->oom.show = 1;
574 sopt->oom.value = fval;
575 }
576 else
577 sopt->oom.show = 0;
578 }
579 else if ( ! strcmp(tag, "output") )
580 {
581 sopt->first_node = (int)PLUTO_get_number(plint);
582 sopt->last_node = (int)PLUTO_get_number(plint);
583 if ( ready && sopt->first_node > sopt->last_node )
584 {
585 sprintf( mesg, "-----------------------------\n"
586 "illegal node range values: \n"
587 "first (%d) > last (%d) \n"
588 "-----------------------------",
589 sopt->first_node, sopt->last_node );
590 RETURN(1);
591 }
592
593 /* get output filenames */
594 if ( sopt->outfile_1D ) free(sopt->outfile_1D);
595 if ( sopt->outfile_niml ) free(sopt->outfile_niml);
596 sopt->outfile_1D = sopt->outfile_niml = NULL;
597
598 str = PLUTO_get_string(plint);
599 if ( strlen(str) > 0 )
600 {
601 sopt->outfile_1D = (char *)calloc(strlen(str)+1,sizeof(char));
602 strcpy(sopt->outfile_1D, str);
603 }
604
605 str = PLUTO_get_string(plint);
606
607 /* make sure the string looks like *.niml.dset 4 Nov 2008 */
608 val = strlen(str);
609 if ( val > 0 && (val < 11 || strcmp(str+val-10,".niml.dset")) )
610 {
611 sprintf( mesg, "-----------------------------------\n"
612 "NIML dataset must end in .niml.dset\n"
613 "have: %s\n"
614 "-----------------------------------", str );
615 RETURN(1);
616 }
617
618 if ( strlen(str) > 0 )
619 {
620 sopt->outfile_niml = (char *)calloc(strlen(str)+1,sizeof(char));
621 strcpy(sopt->outfile_niml, str);
622 }
623 }
624 else if ( ! strcmp(tag, "debug level") )
625 {
626 sopt->debug = (int)PLUTO_get_number(plint);
627 sopt->dnode = (int)PLUTO_get_number(plint);
628 }
629 else
630 {
631 sprintf( mesg, "---------------------------\n"
632 "Unknown option tag : %s\n"
633 "---------------------------", tag );
634 RETURN(1);
635 }
636 }
637
638 if ( sopt->debug > 1 )
639 {
640 disp_v2s_plugin_opts( "plug_vol2surf options done : ", &lvpo );
641 disp_v2s_opts_t( " surface options : ", sopt );
642 }
643
644 /* should we just run away? always adjust debugging first... */
645 g->vpo->sopt.debug = lvpo.sopt.debug;
646 g->vpo->sopt.dnode = lvpo.sopt.dnode;
647
648 if ( lvpo.use0 == 0 && lvpo.use1 == 0 ) ready = 0;
649
650 if ( ! ready )
651 {
652 if ( sopt->debug > 0 )
653 PV2S_disp_afni_surfaces(plint);
654 RETURN(1);
655 }
656
657 if ( ! v2s_is_good_map(sopt->map, 1) )
658 {
659 sprintf( mesg, "-------------------------------------------\n"
660 "mapping function is invalid in this context\n"
661 "index %d, name '%s'\n"
662 "-------------------------------------------",
663 sopt->map,
664 (sopt->map < E_SMAP_INVALID || sopt->map >= E_SMAP_FINAL) ?
665 "out-of-range" : g->maps[sopt->map] );
666 RETURN(1);
667 }
668
669 /* verify surface consistency */
670 if ( lvpo.use0 )
671 {
672 if ( PV2S_check_surfaces(plint, lvpo.s0A, lvpo.s0B, mesg, sopt->debug) )
673 RETURN(1);
674 if ( lvpo.s0A == lvpo.s0B )
675 {
676 sprintf( mesg, "--------------------------------\n"
677 "error: for pair 0, surfA = surfB\n"
678 "--------------------------------" );
679 RETURN(1);
680 }
681 lvpo.label[0] = ss->su_surf[lvpo.s0A]->label_ldp;
682 if(lvpo.s0B >= 0) lvpo.label[1] = ss->su_surf[lvpo.s0B]->label_ldp;
683 }
684 else
685 lvpo.label[0] = lvpo.label[1] = gv2s_no_label; /* no labels */
686
687 if ( lvpo.use1 )
688 {
689 if ( PV2S_check_surfaces(plint, lvpo.s1A, lvpo.s1B, mesg, sopt->debug) )
690 RETURN(1);
691 if ( lvpo.s1A == lvpo.s1B )
692 {
693 sprintf( mesg, "--------------------------------\n"
694 "error: for pair 1, surfA = surfB\n"
695 "--------------------------------" );
696 RETURN(1);
697 }
698 lvpo.label[2] = ss->su_surf[lvpo.s1A]->label_ldp;
699 if(lvpo.s1B >= 0) lvpo.label[3] = ss->su_surf[lvpo.s1B]->label_ldp;
700 }
701 else
702 lvpo.label[2] = lvpo.label[3] = gv2s_no_label; /* no labels */
703
704 /* if the user wan't normals, they can only supply one surface per pair */
705 if ( sopt->use_norms && ((lvpo.use0 && lvpo.s0B >= 0) ||
706 (lvpo.use1 && lvpo.s1B >= 0)) )
707 {
708 sprintf( mesg, "----------------------------------------\n"
709 "cannot use normals while using surface B\n"
710 "----------------------------------------" );
711 RETURN(1);
712 }
713
714 if ( sopt->debug > 0 )
715 PV2S_disp_afni_surfaces(plint);
716
717 /* for now, only output nodes and a single data column */
718 sopt->skip_cols = V2S_SKIP_ALL ^ V2S_SKIP_NODES;
719
720 if ( ready ) /* then copy changes over old values */
721 {
722 *g->vpo = lvpo;
723 g->vpo->ready = 1;
724 }
725
726 RETURN(0);
727 }
728
PV2S_check_surfaces(PLUGIN_interface * plint,int sa,int sb,char * mesg,int debug)729 static int PV2S_check_surfaces(PLUGIN_interface * plint, int sa, int sb,
730 char * mesg, int debug)
731 {
732 THD_session * ss;
733
734 ENTRY("PV2S_check_surfaces");
735
736 ss = plint->im3d->ss_now;
737
738 if ( ss->su_num < 1 )
739 {
740 PV2S_BAIL_VALUE(mesg, "Not enough surfaces in session.\n", ss->su_num);
741 RETURN(1);
742 }
743
744 /* verify that the surface indices are valid */
745 if ( sa < 0 )
746 {
747 PV2S_BAIL_VALUE(mesg, "surf_A has invalid index", sa);
748 RETURN(1);
749 }
750
751 if ( sa >= ss->su_num )
752 {
753 PV2S_BAIL_VALUE(mesg, "surf_A beyond valid index", ss->su_num - 1);
754 RETURN(1);
755 }
756
757 if ( sb >= ss->su_num )
758 {
759 PV2S_BAIL_VALUE(mesg, "surf_B beyond valid index", ss->su_num - 1);
760 RETURN(1);
761 }
762
763 if ( sb >= 0 )
764 {
765 /* then check that surf_A and surf_B share LDP */
766 if (strncmp(ss->su_surf[sa]->idcode_ldp,ss->su_surf[sb]->idcode_ldp,32))
767 {
768 char * la = ss->su_surf[sa]->label_ldp;
769 char * lb = ss->su_surf[sb]->label_ldp;
770 if ( ! *la ) la = "undefined";
771 if ( ! *lb ) lb = "undefined";
772 sprintf(mesg, "---------------------------------------\n"
773 "Error: Surf_A and Surf_B have different\n"
774 " local domain parents\n"
775 "LDP #%d = '%s', LDP #%d = '%s'\n"
776 "---------------------------------------",
777 sa, la, sb, lb);
778 RETURN(1);
779 }
780
781 /* and that they have the same number of nodes */
782 if ( ss->su_surf[sa]->num_ixyz != ss->su_surf[sb]->num_ixyz )
783 {
784 sprintf(mesg, "------------------------------------------------\n"
785 "Big problem: Surf_A and Surf_B have different\n"
786 " numbers of nodes! They cannot share an LDP.\n"
787 " SurfA: '%s', %d nodes\n"
788 " SurfB: '%s', %d nodes\n"
789 "------------------------------------------------",
790 ss->su_surf[sa]->label, ss->su_surf[sa]->num_ixyz,
791 ss->su_surf[sb]->label, ss->su_surf[sb]->num_ixyz);
792 RETURN(1);
793 }
794 }
795
796 if ( debug > 0 && ss->su_surf )
797 {
798 if ( ss->su_surf[sa] ) /* we have checked sa >= 0, above */
799 fprintf(stderr,"+d surf_A label: '%s'\n",
800 *ss->su_surf[sa]->label ? ss->su_surf[sa]->label : "not set");
801 else
802 fprintf(stderr,"** surf_A (#%d) pointer not set??\n", sa);
803
804 if ( sb < 0 )
805 fprintf(stderr,"-d surf_B not in use\n");
806 else if ( ss->su_surf[sb] )
807 fprintf(stderr,"+d surf_B label: '%s'\n",
808 *ss->su_surf[sb]->label ? ss->su_surf[sb]->label : "not set");
809 else
810 fprintf(stderr,"** surf_B (#%d) pointer not set??\n", sb);
811 }
812
813 RETURN(0);
814 }
815
PV2S_disp_afni_surfaces(PLUGIN_interface * plint)816 static int PV2S_disp_afni_surfaces(PLUGIN_interface * plint)
817 {
818 THD_session * ss;
819 char * ldp, * label;
820 int c;
821
822 ENTRY("disp_afni_surfaces");
823
824 ss = plint->im3d->ss_now;
825
826 if ( ss->su_surf <= 0 )
827 RETURN(0);
828
829 fprintf(stderr,"-d --------------------------------------\n");
830 fprintf(stderr," afni surface indices, labels and LDPs:\n");
831 for ( c = 0; c < ss->su_num; c++ )
832 {
833 label = ss->su_surf[c]->label;
834 ldp = ss->su_surf[c]->label_ldp;
835 if ( ! *label ) label = "undefined";
836 if ( ! *ldp ) ldp = "undefined";
837
838 fprintf(stderr," index %2d, label '%s', LDP '%s'\n",
839 c, label, ldp );
840 }
841
842 RETURN(0);
843 }
844