1 /*****************************************************************************
2 Major portions of this software are copyrighted by the Medical College
3 of Wisconsin, 1994-2000, and are released under the Gnu General Public
4 License, Version 2. See the file README.Copyright for details.
5 ******************************************************************************/
6
7 /***********************************************************************
8 *
9 * plug_roiedit.c - a region of interest editor (afni plugin)
10 *
11 * Rick Reynolds
12 * Medical College of WI
13 *
14 *************
15 * history:
16 *
17 * October 7, 2003 [rickr]
18 * - renamed old and new fields of r_alg_s to Bold and Bnew
19 * June 10, 2005 [rickr]
20 * - added lots of ENTRY/RETURN pairs
21 * - continue on 'set fill point' with no data
22 * - use DSET_load in case use has not opened afni windows yet
23 ***********************************************************************
24 */
25
26 #include <Xm/FileSB.h>
27
28 #include "afni.h"
29
30 #ifndef ALLOW_PLUGINS
31 # error "Plugins not properly set up -- see machdep.h"
32 #endif
33
34 #include "plug_roiedit.h" /* RCR stuff */
35
36 /***********************************************************************
37 Plugin to draw values into a dataset.
38 Makes a custom interface.
39 ************************************************************************/
40
41 /*---------- prototypes for internal routines ----------*/
42
43 static char * DRAW_main( PLUGIN_interface * ) ;
44
45 static void DRAW_make_widgets(void) ;
46
47 static void DRAW_done_CB ( Widget , XtPointer , XtPointer ) ;
48 static void DRAW_undo_CB ( Widget , XtPointer , XtPointer ) ;
49 static void DRAW_help_CB ( Widget , XtPointer , XtPointer ) ;
50 static void DRAW_quit_CB ( Widget , XtPointer , XtPointer ) ;
51 static void DRAW_save_CB ( Widget , XtPointer , XtPointer ) ;
52 static void DRAW_choose_CB( Widget , XtPointer , XtPointer ) ;
53 static void DRAW_color_CB ( MCW_arrowval * , XtPointer ) ;
54 static void DRAW_mode_CB ( MCW_arrowval * , XtPointer ) ;
55 static void DRAW_value_CB ( MCW_arrowval * , XtPointer ) ;
56
57 static void DRAW_receiver( int , int , void * , void * ) ;
58 static void DRAW_into_dataset( int , int * , int * , int * , void * ) ;
59 static void DRAW_finalize_dset_CB( Widget , XtPointer , MCW_choose_cbs * ) ;
60 static void DRAW_2dfiller( int nx , int ny , int ix , int jy , byte * ar ) ;
61
62 static PLUGIN_interface * plint = NULL ;
63
64 /***********************************************************************
65 Set up the interface to the user. Note that we bypass the
66 normal interface creation, and simply have the menu selection
67 directly call the main function, which will create a custom
68 set of interface widgets.
69 ************************************************************************/
70
71
72 DEFINE_PLUGIN_PROTOTYPE
73
PLUGIN_init(int ncall)74 PLUGIN_interface * PLUGIN_init( int ncall )
75 {
76 if( ncall > 0 ) return NULL ; /* only one interface */
77
78 CHECK_IF_ALLOWED("GYRUSFINDER","Gyrus Finder") ; /* 30 Sep 2016 */
79
80 plint = PLUTO_new_interface( "Gyrus Finder" , NULL , NULL ,
81 PLUGIN_CALL_IMMEDIATELY , DRAW_main ) ;
82
83 PLUTO_add_hint( plint , "Interactive Region of Interest Editor" ) ;
84
85 PLUTO_set_sequence( plint , "z:Reynolds" ) ;
86
87 return plint ;
88 }
89
90 /***************************************************************************
91 Will be called from AFNI when user selects from Plugins menu.
92 ****************************************************************************/
93
94 /* Interface widgets */
95
96 static Widget shell=NULL , rowcol , info_lab , choose_pb ;
97 static Widget done_pb , undo_pb , help_pb , quit_pb , save_pb ;
98 static MCW_arrowval * value_av , * color_av , * mode_av ;
99
100 /* Other data */
101
102 #define MODE_CURVE 0
103 #define MODE_CLOSED 1
104 #define MODE_POINTS 2
105 #define MODE_FLOOD_VAL 3
106 #define MODE_FLOOD_NZ 4
107 #define MODE_VOL_FILL 5
108 #define MODE_CONN_PTS 6
109
110 static char * mode_strings[] = {
111 "Open Curve" , "Closed Curve" , "Points" , "Flood->Value",
112 "Flood->Nonzero", "Set Fill Point", "Connect Points" };
113
114 static int mode_ints[] = {
115 DRAWING_LINES , DRAWING_FILL , DRAWING_POINTS , DRAWING_POINTS ,
116 DRAWING_POINTS, DRAWING_POINTS, DRAWING_POINTS };
117
118 #define NUM_modes (sizeof(mode_ints)/sizeof(int))
119
120 static MCW_DC * dc ; /* display context */
121 static Three_D_View * im3d ; /* AFNI controller */
122 static THD_3dim_dataset * dset ; /* The dataset! */
123
124 static int color_index = 1 ; /* from color_av */
125 static int mode_ival = MODE_CURVE ;
126 static int mode_index = DRAWING_LINES ; /* from mode_av */
127 static int value_int = 1 ; /* from value_av */
128 static float value_float = 1.0 ; /* ditto */
129
130 static int editor_open = 0 ;
131 static int dset_changed = 0 ;
132 static int recv_open = 0 ;
133 static int recv_key = -1 ; /* 15 Jun 1999 by RWCox */
134
135 static int undo_bufsiz = 0 ; /* size of undo_buf in bytes */
136 static int undo_bufnum = 0 ; /* size of undo_xyz in ints */
137 static int undo_bufuse = 0 ; /* number of entries in undo buffer */
138 static void * undo_buf = NULL ; /* stores data to be copied back to dataset */
139 static int * undo_xyz = NULL ; /* stores voxel indices for copying */
140
141 static THD_dataxes dax_save ; /* save this for later referenc */
142
DRAW_main(PLUGIN_interface * plint)143 char * DRAW_main( PLUGIN_interface * plint )
144 {
145 XmString xstr ;
146
147 ENTRY("DRAW_main");
148
149 #if 0
150 /* RCR - this plugin is not authorized outside of the mcw domain */
151 if ( ! r_check_host( ) )
152 return NULL;
153 #endif
154
155 /*-- sanity checks --*/
156
157 if( ! IM3D_OPEN(plint->im3d) ) RETURN( "AFNI Controller\nnot opened?!") ;
158
159 if( editor_open )
160 {
161 XMapRaised( XtDisplay(shell) , XtWindow(shell) ) ; NI_sleep(1);
162
163 if ( gRX.main_is_open )
164 {
165 XMapRaised( XtDisplay( gRX.main ) , XtWindow( gRX.main ) ) ; NI_sleep(1);
166 }
167 else
168 {
169 XtMapWidget( gRX.main ); NI_sleep(1) ;
170 gRX.main_is_open = 1;
171 }
172
173 RETURN(NULL);
174 }
175
176 im3d = plint->im3d ; /* save for local use */
177
178 /*-- create widgets, first time through --*/
179
180 if( shell == NULL ){
181 dc = im3d->dc ; /* save this too */
182 DRAW_make_widgets() ;
183 PLUTO_set_topshell( plint , shell ) ; /* 22 Sep 2000 */
184 RWC_visibilize_widget( shell ) ; /* 27 Sep 2000 */
185 }
186
187 /*-- set titlebar --*/
188
189 { static char clabel[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ; /* see afni_func.c */
190 char ttl[PLUGIN_STRING_SIZE] ; int ic ;
191
192 ic = AFNI_controller_index(im3d) ; /* find out which controller */
193
194 if( ic >=0 && ic < 26 ){
195 sprintf( ttl , "'AFNI' GyrusFinder [%c]" , clabel[ic] ) ;
196 XtVaSetValues( shell , XmNtitle , ttl , NULL ) ;
197 }
198 }
199
200 /*-- set the info label --*/
201
202 xstr = XmStringCreateLtoR( "[No dataset]" ,
203 XmFONTLIST_DEFAULT_TAG ) ;
204 XtVaSetValues( info_lab , XmNlabelString , xstr , NULL ) ;
205 XmStringFree(xstr) ;
206
207 /*-- pop the widget up --*/
208
209 XtMapWidget(shell) ; NI_sleep(1) ;
210
211 if ( gRX.main_is_open )
212 {
213 XMapRaised( XtDisplay( gRX.main ) , XtWindow( gRX.main ) ) ; NI_sleep(1);
214 }
215 else
216 {
217 XtMapWidget( gRX.main ); NI_sleep(1) ;
218 gRX.main_is_open = 1;
219 }
220
221
222 /*-- misc initialization --*/
223
224 dset = NULL ; /* not editing anything */
225 dset_changed = 0 ; /* not yet changed */
226 editor_open = 1 ; /* editor is now open for business */
227 recv_open = 0 ; /* receiver is not yet open */
228 recv_key = -1;
229
230 SENSITIZE(undo_pb,0) ; undo_bufuse = 0 ;
231 SENSITIZE(save_pb,0) ;
232 SENSITIZE(choose_pb,1) ;
233
234 RETURN(NULL) ;
235 }
236
237 /*------------------------------------------------------------------------
238 Make the control popup for this thing
239 --------------------------------------------------------------------------*/
240
241 /*-- structures defining action buttons (at bottom of popup) --*/
242
243 #define NACT 5 /* number of action buttons */
244
245 static MCW_action_item DRAW_actor[NACT] = {
246 {"Undo",DRAW_undo_CB,NULL,
247 "Undoes previous draw\naction, if possible","Undo last change",0} ,
248
249 {"Help",DRAW_help_CB,NULL,
250 "Displays more help" , "Displays more help",0} ,
251
252 {"Quit",DRAW_quit_CB,NULL,
253 "Discard edits since last Save\nand close Editor" ,
254 "Discard edits and close",0} ,
255
256 {"Save",DRAW_save_CB,NULL,
257 "Save edits to disk\nand continue" , "Save to disk and continue",0} ,
258
259 {"Done",DRAW_done_CB,NULL,
260 "Save edits to disk\nand close Editor" , "Save and close",1}
261 } ;
262
DRAW_make_widgets(void)263 static void DRAW_make_widgets(void)
264 {
265 XmString xstr ;
266
267 ENTRY("DRAW_make_widgets");
268
269 /*** top level shell for window manager ***/
270
271 shell =
272 XtVaAppCreateShell(
273 "AFNI" , "AFNI" , topLevelShellWidgetClass , dc->display ,
274 XmNtitle , "GFinder Editor", /* top of window */
275 XmNiconName , "GFinder" , /* label on icon */
276 XmNdeleteResponse , XmDO_NOTHING , /* deletion handled below */
277 XmNallowShellResize , True , /* let code resize shell? */
278 XmNmappedWhenManaged , False , /* must map it manually */
279 XmNinitialResourcesPersistent , False ,
280 NULL ) ;
281
282 if( afni48_good ) /* set icon pixmap */
283 XtVaSetValues( shell ,
284 XmNiconPixmap , afni48_pixmap ,
285 NULL ) ;
286
287 if( MCW_isitmwm(shell) ) /* remove some MWM functions */
288 XtVaSetValues( shell ,
289 XmNmwmFunctions ,
290 MWM_FUNC_MOVE | MWM_FUNC_CLOSE | MWM_FUNC_MINIMIZE ,
291 NULL ) ;
292
293 XmAddWMProtocolCallback( /* make "Close" window menu work */
294 shell ,
295 XmInternAtom( dc->display , "WM_DELETE_WINDOW" , False ) ,
296 DRAW_quit_CB , (XtPointer) plint ) ;
297
298 /*** rowcolumn widget to hold all user interface stuff ***/
299
300 rowcol = XtVaCreateWidget(
301 "AFNI" , xmRowColumnWidgetClass , shell ,
302 XmNpacking , XmPACK_TIGHT ,
303 XmNorientation , XmVERTICAL ,
304 XmNtraversalOn , True ,
305 XmNinitialResourcesPersistent , False ,
306 NULL ) ;
307
308 /*** label at top to let user know who we are ***/
309
310 xstr = XmStringCreateLtoR( "[No dataset]" ,
311 XmFONTLIST_DEFAULT_TAG ) ;
312 info_lab = XtVaCreateManagedWidget(
313 "AFNI" , xmLabelWidgetClass , rowcol ,
314 XmNlabelString , xstr ,
315 XmNinitialResourcesPersistent , False ,
316 NULL ) ;
317 XmStringFree(xstr) ;
318 MCW_register_help( info_lab , "Shows dataset being edited" ) ;
319 MCW_register_hint( info_lab , "Shows dataset being edited" ) ;
320
321 /*** separator for visual neatness ***/
322
323 (void) XtVaCreateManagedWidget(
324 "AFNI" , xmSeparatorWidgetClass , rowcol ,
325 XmNseparatorType , XmSINGLE_LINE ,
326 XmNinitialResourcesPersistent , False ,
327 NULL ) ;
328
329 /*** button to let user choose dataset to edit ***/
330
331 xstr = XmStringCreateLtoR( "Choose Dataset" , XmFONTLIST_DEFAULT_TAG ) ;
332 choose_pb = XtVaCreateManagedWidget(
333 "AFNI" , xmPushButtonWidgetClass , rowcol ,
334 XmNlabelString , xstr ,
335 XmNtraversalOn , True ,
336 XmNinitialResourcesPersistent , False ,
337 NULL ) ;
338 XmStringFree(xstr) ;
339 XtAddCallback( choose_pb, XmNactivateCallback, DRAW_choose_CB, NULL ) ;
340 MCW_register_help( choose_pb ,
341 "Use this to popup a\n"
342 "'chooser' that lets\n"
343 "you select which\n"
344 "dataset to edit."
345 ) ;
346 MCW_register_hint( choose_pb , "Popup a dataset chooser" ) ;
347
348 /*** arrowval to choose value that is drawn into dataset voxels ***/
349
350 value_av = new_MCW_arrowval( rowcol , "Drawing Value " ,
351 MCW_AV_downup , -32767,32767,value_int ,
352 MCW_AV_editext , 0 ,
353 DRAW_value_CB , NULL , NULL,NULL ) ;
354
355 MCW_reghelp_children( value_av->wrowcol ,
356 "Use this to set the value that\n"
357 "will be drawn into the dataset\n"
358 "using mouse button 2."
359 ) ;
360 MCW_reghint_children( value_av->wrowcol , "Goes into dataset voxels" ) ;
361
362 /*** option menu to choose drawing color ***/
363
364 color_av = new_MCW_colormenu( rowcol , "Drawing Color " , dc ,
365 1 , dc->ovc->ncol_ov - 1 , color_index ,
366 DRAW_color_CB , NULL ) ;
367
368 MCW_reghelp_children( color_av->wrowcol ,
369 "Use this to set the color that is\n"
370 "shown during mouse button 2 drawing.\n"
371 "N.B.: After drawing is completed,\n"
372 " the dataset will be displayed\n"
373 " with the chosen value replacing\n"
374 " the drawing color. This color\n"
375 " is used ONLY while button 2 is\n"
376 " actually pressed down."
377 ) ;
378 MCW_reghint_children( color_av->wrowcol , "Used when button 2 is drawing" ) ;
379
380 /*** arrowval to choose drawing mode ***/
381
382 mode_av = new_MCW_optmenu( rowcol , "Drawing Mode " ,
383 0 , NUM_modes-1 , 0,0 ,
384 DRAW_mode_CB , NULL ,
385 MCW_av_substring_CB , mode_strings ) ;
386
387 MCW_reghelp_children( mode_av->wrowcol ,
388 "Use this to set the way in which\n"
389 "drawing pixels on the screen is\n"
390 "used to select dataset voxels:\n"
391 "Open Curve = voxels picked along lines drawn;\n"
392 "Closed Curve = voxels forming a closed curve\n"
393 "Points = only voxels at X11 notify pixels;\n"
394 "Flood->Value = flood fill from the chosen point\n"
395 " out to points = Drawing Value\n"
396 "Flood->Nonzero = flood fill from chosen point out\n"
397 " to any nonzero point"
398 ) ;
399 MCW_reghint_children( mode_av->wrowcol , "How voxels are chosen") ;
400
401 /*** separator for visual neatness ***/
402
403 (void) XtVaCreateManagedWidget(
404 "AFNI" , xmSeparatorWidgetClass , rowcol ,
405 XmNseparatorType , XmSINGLE_LINE ,
406 XmNinitialResourcesPersistent , False ,
407 NULL ) ;
408
409 /*** a set of action buttons below the line ***/
410
411 (void) MCW_action_area( rowcol , DRAW_actor , NACT ) ;
412
413 undo_pb = (Widget) DRAW_actor[0].data ;
414 help_pb = (Widget) DRAW_actor[1].data ;
415 quit_pb = (Widget) DRAW_actor[2].data ;
416 save_pb = (Widget) DRAW_actor[3].data ;
417 done_pb = (Widget) DRAW_actor[4].data ;
418
419 /*** that's all (for Bob) ***/
420
421 XtManageChild(rowcol) ;
422 XtRealizeWidget(shell) ; NI_sleep(1) ; /* will not be mapped */
423
424 r_main_mk_main_shell( );
425
426 EXRETURN;
427 }
428
429
430 /*----------------------------------------------------------------------
431 **
432 ** Check the hostname of the computer. If the name is not part of the
433 ** mcw.edu domain, then the machine is not authorized to use this plugin.
434 **
435 **----------------------------------------------------------------------
436 */
437 #if 0
438 static int
439 r_check_host( void )
440 {
441 long hostid = 0;
442
443 hostid = gethostid( );
444
445 if ( ( hostid & R_HOSTID_MASK ) != R_HOSTID_VAL )
446 {
447 rERROR( "Your machine is not currently authorized to use this plugin.");
448
449 system( "echo GF usage :`whoami`@`hostname`|mail rickr@mcw.edu" );
450
451 return 0;
452 }
453
454 return 1;
455 }
456 #endif
457
458 /*----------------------------------------------------------------------
459 **
460 ** Create main GyrusFinder shell.
461 **
462 **----------------------------------------------------------------------
463 */
464 static void
r_main_mk_main_shell(void)465 r_main_mk_main_shell( void )
466 {
467 ENTRY("r_main_mk_main_shell");
468 #ifdef R_LOG_INFO_D
469 if ( ! r_open_log_file( ) ) EXRETURN ;
470 #endif
471
472 r_wtgr_mk_main_shell ( &gRX );
473 r_INT_mk_main_shell ( &gRI ); /* interpolation shell */
474 r_HL_mk_main_shell ( &gRH ); /* hole filler shell */
475 r_main_mk_show_buttons( );
476
477 EXRETURN;
478 }
479
480
481 #ifdef R_LOG_INFO_D
482 /*----------------------------------------------------------------------
483 **
484 ** Open R_LOG_FILE to log messages to.
485 **
486 **----------------------------------------------------------------------
487 */
488 static int
r_open_log_file(void)489 r_open_log_file( void )
490 {
491 if ( ( gr_logfile = fopen( R_LOG_FILE, "a" ) ) == NULL )
492 {
493 sprintf( gRmessage, "Failed to open '%s' for append.", R_LOG_FILE );
494 rERROR( gRmessage );
495
496 return 0;
497 }
498
499 return 1;
500 }
501 #endif
502
503
504 /*----------------------------------------------------------------------
505 **
506 ** Main window for buttons to show other windows.
507 **
508 **----------------------------------------------------------------------
509 */
510 static void
r_main_mk_show_buttons(void)511 r_main_mk_show_buttons( void )
512 {
513 int ac;
514 Arg al[ 10 ];
515 Widget button, tmpb, tmpb2;
516 XmString xstr;
517
518 ENTRY("r_main_mk_show_buttons");
519
520 gRX.main_is_open = 1;
521
522 ac = 0;
523 XtSetArg( al[ac], XmNinitialResourcesPersistent, False ); ac++;
524 XtSetArg( al[ac], XmNdeleteResponse, XmDO_NOTHING ); ac++;
525 gRX.main = XtAppCreateShell( "GyrusFinder", "rshell",
526 topLevelShellWidgetClass, gRX.display, al, ac );
527
528 XmAddWMProtocolCallback( gRX.main,
529 XmInternAtom( gRX.display, "WM_DELETE_WINDOW", False ),
530 ( XtCallbackProc )r_main_cb_quit, ( XtPointer )NULL );
531
532 ac = 0;
533 gRX.mainForm = XmCreateForm( gRX.main, "form", al, ac );
534
535
536 /* raise interpolator button */
537 ac = 0;
538 XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER ); ac++;
539 XtSetArg( al[ac], XmNwidth, 220 ); ac++;
540 xstr = XmStringCreateLtoR( "Interpolator", gRX.charset );
541 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
542 button = XmCreatePushButton( gRX.mainForm, "INT", al, ac );
543 XtManageChild( button );
544 XtAddCallback( button, XmNactivateCallback,
545 ( XtCallbackProc )r_any_cb_raise, "INT" );
546 XtSetSensitive( button, True );
547 XmStringFree(xstr) ;
548 tmpb = button;
549
550 /* raise wtgr button */
551 ac = 0;
552 XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER ); ac++;
553 XtSetArg( al[ac], XmNtopAttachment, XmATTACH_WIDGET ); ac++;
554 XtSetArg( al[ac], XmNtopWidget, tmpb ); ac++;
555 XtSetArg( al[ac], XmNwidth, 220 ); ac++;
556 xstr = XmStringCreateLtoR( "White/Gray Finder", gRX.charset );
557 XtSetArg( al[ ac ], XmNlabelString, xstr ); ac++;
558 button = XmCreatePushButton( gRX.mainForm, "WhiteGray", al, ac );
559 XtManageChild( button );
560 XtAddCallback( button, XmNactivateCallback,
561 ( XtCallbackProc )r_any_cb_raise, "wtgr" );
562 XtSetSensitive( button, True );
563 XmStringFree( xstr );
564 tmpb = button;
565
566
567 /* raise holes button */
568 ac = 0;
569 XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER ); ac++;
570 XtSetArg( al[ac], XmNtopAttachment, XmATTACH_WIDGET ); ac++;
571 XtSetArg( al[ac], XmNtopWidget, tmpb ); ac++;
572 XtSetArg( al[ac], XmNwidth, 220 ); ac++;
573 xstr = XmStringCreateLtoR( "Hole Filler", gRX.charset );
574 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
575 button = XmCreatePushButton( gRX.mainForm, "fillholes", al, ac );
576 XtManageChild( button );
577 XtAddCallback( button, XmNactivateCallback,
578 ( XtCallbackProc )r_any_cb_raise, "HL" );
579 XtSetSensitive( button, True );
580 XmStringFree( xstr );
581 tmpb = button;
582
583
584 /* UNDO button */
585
586 ac = 0;
587 XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER ); ac++;
588 XtSetArg( al[ac], XmNtopAttachment, XmATTACH_WIDGET ); ac++;
589 XtSetArg( al[ac], XmNtopWidget, tmpb ); ac++;
590 XtSetArg( al[ac], XmNwidth, 110 ); ac++;
591 xstr = XmStringCreateLtoR( "UNDO", gRX.charset );
592 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
593 button = XmCreatePushButton( gRX.mainForm, "saveas", al, ac );
594 XtManageChild( button );
595 XtAddCallback( button, XmNactivateCallback,
596 ( XtCallbackProc )r_any_cb_undo, NULL );
597 XtSetSensitive( button, True );
598 XmStringFree( xstr );
599 tmpb2 = button;
600
601
602 /* save as button */
603
604 ac = 0;
605 XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER ); ac++;
606 XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET ); ac++;
607 XtSetArg( al[ac], XmNleftWidget, button ); ac++;
608 XtSetArg( al[ac], XmNtopAttachment, XmATTACH_WIDGET ); ac++;
609 XtSetArg( al[ac], XmNtopWidget, tmpb ); ac++;
610 XtSetArg( al[ac], XmNwidth, 110 ); ac++;
611 xstr = XmStringCreateLtoR( "Save As", gRX.charset );
612 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
613 button = XmCreatePushButton( gRX.mainForm, "saveas", al, ac );
614 XtManageChild( button );
615 XtAddCallback( button, XmNactivateCallback,
616 ( XtCallbackProc )r_any_cb_raise, "saveas" );
617 XtSetSensitive( button, True );
618 XmStringFree( xstr );
619 tmpb = button;
620
621 /*
622 ** We're going to cheat a little here. The "save as" widget will
623 ** be implemented as a child of the main RC. So we need to create
624 ** the widget now, so the main "save as" button can raise/manage it.
625 */
626
627 r_main_mk_save_as_fr( gRX.mainForm );
628
629
630 /* help button */
631 ac = 0;
632 XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER ); ac++;
633 XtSetArg( al[ac], XmNtopAttachment, XmATTACH_WIDGET ); ac++;
634 XtSetArg( al[ac], XmNtopWidget, tmpb2 ); ac++;
635 XtSetArg( al[ac], XmNwidth, 110 ); ac++;
636 xstr = XmStringCreateLtoR( "Help", gRX.charset );
637 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
638 button = XmCreatePushButton( gRX.mainForm, "help", al, ac );
639 XtManageChild( button );
640 XtAddCallback( button, XmNactivateCallback,
641 ( XtCallbackProc )r_main_cb_help, NULL );
642 XtSetSensitive( button, True );
643 XmStringFree( xstr );
644
645
646 /* show data structures button */
647 ac = 0;
648 XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER ); ac++;
649 XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET ); ac++;
650 XtSetArg( al[ac], XmNleftWidget, button ); ac++;
651 XtSetArg( al[ac], XmNtopAttachment, XmATTACH_WIDGET ); ac++;
652 XtSetArg( al[ac], XmNtopWidget, tmpb ); ac++;
653 XtSetArg( al[ac], XmNwidth, 110 ); ac++;
654 xstr = XmStringCreateLtoR( "structs", gRX.charset );
655 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
656 button = XmCreatePushButton( gRX.mainForm, "structs", al, ac );
657 XtManageChild( button );
658 XtAddCallback( button, XmNactivateCallback,
659 ( XtCallbackProc )r_main_cb_show_structs, NULL );
660 XtSetSensitive( button, True );
661 XmStringFree( xstr );
662
663
664 XtManageChild( gRX.mainForm );
665 XtRealizeWidget( gRX.main ); NI_sleep(1) ;
666
667 EXRETURN;
668 }
669
670
671 /*----------------------------------------------------------------------
672 **
673 ** Create the save as widget under the main RC.
674 **
675 **----------------------------------------------------------------------
676 */
677 static void
r_main_mk_save_as_fr(Widget parent)678 r_main_mk_save_as_fr( Widget parent )
679 {
680 Widget button, junk, hrc, vrc, frame;
681 Arg al[ 10 ];
682 int ac;
683 char string[ 25 ];
684
685 ENTRY("r_main_mk_save_as_fr");
686
687 XtVaSetValues( shell ,
688 XmNmwmFunctions ,
689 MWM_FUNC_MOVE | MWM_FUNC_CLOSE | MWM_FUNC_MINIMIZE ,
690 NULL ) ;
691 ac = 0;
692 XtSetArg( al[ ac ], XmNdialogTitle,
693 XmStringCreateLtoR( "Save As", gRX.charset ) ); ac++;
694 XtSetArg( al[ ac ], XmNtextString,
695 XmStringCreateLtoR( gRA.save_as_name, gRX.charset ) ); ac++;
696 XtSetArg( al[ ac ], XmNselectionLabelString,
697 XmStringCreateLtoR( "AFNI prefix : ", gRX.charset ) ); ac++;
698 XtSetArg( al[ ac ], XmNokLabelString,
699 XmStringCreateLtoR( "save", gRX.charset ) ); ac++;
700 XtSetArg( al[ ac ], XmNapplyLabelString,
701 XmStringCreateLtoR( "overwrite", gRX.charset ) ); ac++;
702 XtSetArg( al[ ac ], XmNcancelLabelString,
703 XmStringCreateLtoR( "hide", gRX.charset ) ); ac++;
704 XtSetArg( al[ ac ], XmNminimizeButtons, True ); ac++;
705 XtSetArg( al[ac], XmNinitialResourcesPersistent, False ); ac++;
706 XtSetArg( al[ac], XmNmappedWhenManaged, False ); ac++;
707 XtSetArg( al[ac], XmNdeleteResponse, XmDO_NOTHING ); ac++;
708 gRX.save_as_file_d = XmCreatePromptDialog( parent, "dialog", al, ac );
709
710 XmAddWMProtocolCallback( gRX.save_as_file_d,
711 XmInternAtom( gRX.display, "WM_DELETE_WINDOW", False ),
712 ( XtCallbackProc )r_any_cb_hide, "saveas" );
713
714 XtAddCallback( gRX.save_as_file_d, XmNokCallback,
715 ( XtCallbackProc )r_main_cb_saveas, ( XtPointer )0 );
716 XtAddCallback( gRX.save_as_file_d, XmNapplyCallback,
717 ( XtCallbackProc )r_main_cb_saveas, ( XtPointer )1 );
718 XtAddCallback( gRX.save_as_file_d, XmNcancelCallback,
719 ( XtCallbackProc )r_any_cb_hide, "saveas" );
720
721 XtManageChild( XmSelectionBoxGetChild( gRX.save_as_file_d,
722 XmDIALOG_APPLY_BUTTON ) );
723 XtUnmanageChild( XmSelectionBoxGetChild( gRX.save_as_file_d,
724 XmDIALOG_HELP_BUTTON ) );
725
726 XtManageChild( gRX.save_as_file_d );
727
728 VISIBILIZE_WHEN_MAPPED(gRX.save_as_file_d) ; /* 27 Sep 2000 */
729
730 /*
731 ** Once we prevent it from popping up immediately, set it to display
732 ** anytime it's managed.
733 */
734 ac = 0;
735 XtSetArg( al[ac], XmNmappedWhenManaged, True ); ac++;
736 XtSetValues( gRX.save_as_file_d, al, ac );
737
738 EXRETURN;
739 }
740
741
742 /*----------------------------------------------------------------------
743 **
744 ** Create main shell and gray and white matter function frames.
745 **
746 **----------------------------------------------------------------------
747 */
748 static void
r_wtgr_mk_main_shell(r_X_s * X)749 r_wtgr_mk_main_shell( r_X_s * X )
750 {
751 Widget junk, frame, rc;
752 XmString xstring;
753 Arg al[ 20 ];
754 int ac;
755
756 ENTRY("r_wtgr_mk_main_shell");
757
758 /* create a main RC widget with four frame children */
759
760 if ( ! r_init_Alg_values( &gRA ) )
761 EXRETURN;
762
763 if ( ! r_init_pt_conn_s( &gRCP ) )
764 EXRETURN;
765
766 X->display = dc->display;
767 X->charset = XmSTRING_DEFAULT_CHARSET;
768
769 ac = 0;
770 XtSetArg( al[ac], XmNinitialResourcesPersistent, False ); ac++;
771 XtSetArg( al[ac], XmNdeleteResponse, XmDO_NOTHING ); ac++;
772 XtSetArg( al[ac], XmNmappedWhenManaged, False ); ac++;
773 X->wtgr_main = XtAppCreateShell( "White/Gray Finder", "rshell",
774 topLevelShellWidgetClass, X->display, al, ac );
775
776 XmAddWMProtocolCallback( gRX.wtgr_main,
777 XmInternAtom( gRX.display, "WM_DELETE_WINDOW", False ),
778 ( XtCallbackProc )r_any_cb_hide, "wtgr" );
779
780 ac = 0;
781 XtSetArg( al[ac], XmNspacing, 15 ); ac++;
782 XtSetArg( al[ac], XmNmarginWidth, 10 ); ac++;
783 XtSetArg( al[ac], XmNmarginHeight, 10 ); ac++;
784 X->wtgr_mainRC = XmCreateRowColumn( X->wtgr_main, "rowcolumn", al, ac );
785
786 /* create the main white and gray selection frames */
787 ( void )r_wt_mk_main_frame( X, X->wtgr_mainRC );
788 ( void )r_gr_mk_main_frame( X, X->wtgr_mainRC );
789
790
791 XtManageChild( X->wtgr_mainRC );
792 XtRealizeWidget( X->wtgr_main );
793
794 EXRETURN ;
795 }
796
797
798 /*----------------------------------------------------------------------
799 **
800 ** Create the Hole Filler shell.
801 **
802 **----------------------------------------------------------------------
803 */
804 static void
r_HL_mk_main_shell(holes_s * H)805 r_HL_mk_main_shell( holes_s * H )
806 {
807 Widget junk, frame, rc;
808 XmString xstring;
809 Arg al[ 20 ];
810 int ac;
811
812 ENTRY("r_HL_mk_main_shell");
813
814 if ( ! r_init_holes_vals( H ) )
815 EXRETURN;
816
817 ac = 0;
818 XtSetArg( al[ac], XmNinitialResourcesPersistent, False ); ac++;
819 XtSetArg( al[ac], XmNdeleteResponse, XmDO_NOTHING ); ac++;
820 XtSetArg( al[ac], XmNmappedWhenManaged, False ); ac++;
821 H->main = XtAppCreateShell( "Hole Filler", "rshell",
822 topLevelShellWidgetClass, gRX.display, al, ac );
823
824 XmAddWMProtocolCallback( gRH.main,
825 XmInternAtom( gRX.display, "WM_DELETE_WINDOW", False ),
826 ( XtCallbackProc )r_any_cb_hide, "HL" );
827
828 ac = 0;
829 XtSetArg( al[ac], XmNspacing, 15 ); ac++;
830 XtSetArg( al[ac], XmNmarginWidth, 10 ); ac++;
831 XtSetArg( al[ac], XmNmarginHeight, 10 ); ac++;
832 H->mainRC = XmCreateRowColumn( H->main, "rowcolumn", al, ac );
833
834 ( void )r_HL_mk_fillval_fr( H, H->mainRC );
835 ( void )r_HL_mk_maxsize_fr( H, H->mainRC );
836 ( void )r_HL_mk_buttons ( H, H->mainRC );
837
838 XtManageChild ( H->mainRC );
839 XtRealizeWidget( H->main ); NI_sleep(1) ;
840
841 EXRETURN;
842 }
843
844
845 /*----------------------------------------------------------------------
846 **
847 ** Create buttons for the "hole filling" app.
848 **
849 **----------------------------------------------------------------------
850 */
851 static Widget
r_HL_mk_buttons(holes_s * H,Widget parent)852 r_HL_mk_buttons( holes_s * H, Widget parent )
853 {
854 int ac;
855 Arg al[ 10 ];
856 Widget form, frame, button1, button2;
857 XmString xstr;
858
859 ENTRY("r_HL_mk_buttons");
860
861 /* create frame to hold form and buttons */
862 ac = 0;
863 frame = XmCreateFrame( parent, "frame", al, ac );
864
865 /* create form to hold push buttons */
866 ac = 0;
867 XtSetArg( al[ac], XmNhorizontalSpacing, R_BUTTON_SPACE ); ac++;
868 form = XmCreateForm( frame, "form", al, ac );
869
870
871 /* region fill button */
872 ac = 0;
873 xstr = XmStringCreateLtoR( "FILL", gRX.charset );
874 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
875 button1 = XmCreatePushButton( form, "fill", al, ac );
876 XtManageChild( button1 );
877 XtAddCallback( button1, XmNactivateCallback,
878 ( XtCallbackProc )r_HL_cb_fill, H );
879 XtSetSensitive( button1, True );
880 XmStringFree( xstr );
881
882 /* unfill button */
883 ac = 0;
884 XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET ); ac++;
885 XtSetArg( al[ac], XmNleftWidget, button1 ); ac++;
886 xstr = XmStringCreateLtoR( "unfill", gRX.charset );
887 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
888 button2 = XmCreatePushButton( form, "unfill", al, ac );
889 XtManageChild( button2 );
890 XtAddCallback( button2, XmNactivateCallback,
891 ( XtCallbackProc )r_any_cb_unfill, &H->fill_val );
892 XtSetSensitive( button2, True );
893 XmStringFree( xstr );
894
895
896 /* stats button */
897 ac = 0;
898 XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET ); ac++;
899 XtSetArg( al[ac], XmNleftWidget, button2 ); ac++;
900 xstr = XmStringCreateLtoR( "stats", gRX.charset );
901 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
902 button1 = XmCreatePushButton( form, "stats", al, ac );
903 XtManageChild( button1 );
904 XtAddCallback( button1, XmNactivateCallback,
905 ( XtCallbackProc )r_any_cb_fill_stats, &gRH.fill_val );
906 XtSetSensitive( button1, True );
907 XmStringFree( xstr );
908
909 /* hide button */
910 ac = 0;
911 XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET ); ac++;
912 XtSetArg( al[ac], XmNleftWidget, button1 ); ac++;
913 xstr = XmStringCreateLtoR( "hide", gRX.charset );
914 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
915 button2 = XmCreatePushButton( form, "hide", al, ac );
916 XtManageChild( button2 );
917 XtAddCallback( button2, XmNactivateCallback,
918 ( XtCallbackProc )r_any_cb_hide, "HL" );
919 XtSetSensitive( button2, True );
920 XmStringFree( xstr );
921
922
923 XtManageChild( form );
924 XtManageChild( frame );
925
926 RETURN( frame );
927 }
928
929
930 /*----------------------------------------------------------------------
931 **
932 ** Create the "max hole size" widget for hole filler window.
933 **
934 **----------------------------------------------------------------------
935 */
936 static Widget
r_HL_mk_maxsize_fr(holes_s * H,Widget parent)937 r_HL_mk_maxsize_fr( holes_s * H, Widget parent )
938 {
939 Widget junk, rc, frame;
940 XmString xstr;
941 Arg al[ 10 ];
942 int ac;
943 char string[ 15 ];
944
945 ENTRY("r_HL_mk_maxsize_fr");
946
947 ac = 0;
948 frame = XmCreateFrame( parent, "frame", al, ac );
949
950 ac = 0;
951 XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT ); ac++;
952 XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL ); ac++;
953 rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
954
955
956 sprintf( string, "%d", H->max_size );
957
958 ac = 0;
959 xstr = XmStringCreateLtoR( "max size : ", gRX.charset );
960 XtSetArg( al[ ac ], XmNlabelString, xstr ); ac++;
961 junk = XmCreateLabel( rc, "label", al, ac );
962 XtManageChild( junk );
963 XmStringFree( xstr );
964
965 ac = 0;
966 XtSetArg( al[ ac ], XmNvalue, string ); ac++;
967 XtSetArg( al[ ac ], XmNwidth, 80 ); ac++;
968 H->maxsize_w = XmCreateText( rc, "text", al, ac );
969 XtManageChild( H->maxsize_w );
970 XtAddCallback( H->maxsize_w, XmNactivateCallback,
971 ( XtCallbackProc )r_HL_cb_set_maxsize, NULL );
972 XtAddCallback( H->maxsize_w, XmNlosingFocusCallback,
973 ( XtCallbackProc )r_HL_cb_set_maxsize, NULL );
974
975
976 XtManageChild( rc );
977 XtManageChild( frame );
978
979 RETURN( frame );
980 }
981
982
983 /*----------------------------------------------------------------------
984 **
985 ** Create the "fill value" widget for hole filler window.
986 **
987 **----------------------------------------------------------------------
988 */
989 static Widget
r_HL_mk_fillval_fr(holes_s * H,Widget parent)990 r_HL_mk_fillval_fr( holes_s * H, Widget parent )
991 {
992 Widget junk, rc, frame;
993 XmString xstr;
994 Arg al[ 10 ];
995 int ac;
996 char string[ 15 ];
997
998 ENTRY("r_HL_mk_fillval_fr");
999
1000 ac = 0;
1001 frame = XmCreateFrame( parent, "frame", al, ac );
1002
1003 ac = 0;
1004 XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT ); ac++;
1005 XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL ); ac++;
1006 rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
1007
1008
1009 sprintf( string, "%d", H->fill_val );
1010
1011 ac = 0;
1012 xstr = XmStringCreateLtoR( "fill value : ", gRX.charset );
1013 XtSetArg( al[ ac ], XmNlabelString, xstr ); ac++;
1014 junk = XmCreateLabel( rc, "label", al, ac );
1015 XtManageChild( junk );
1016 XmStringFree( xstr );
1017
1018 ac = 0;
1019 XtSetArg( al[ ac ], XmNvalue, string ); ac++;
1020 XtSetArg( al[ ac ], XmNwidth, 80 ); ac++;
1021 H->fillval_w = XmCreateText( rc, "text", al, ac );
1022 XtManageChild( H->fillval_w );
1023 XtAddCallback( H->fillval_w, XmNactivateCallback,
1024 ( XtCallbackProc )r_HL_cb_set_fill_val, NULL );
1025 XtAddCallback( H->fillval_w, XmNlosingFocusCallback,
1026 ( XtCallbackProc )r_HL_cb_set_fill_val, NULL );
1027
1028
1029 XtManageChild( rc );
1030 XtManageChild( frame );
1031
1032 RETURN( frame );
1033 }
1034
1035
1036 /*----------------------------------------------------------------------
1037 **
1038 ** Initialize the holes_s structure.
1039 **
1040 **----------------------------------------------------------------------
1041 */
1042 static int
r_init_holes_vals(holes_s * H)1043 r_init_holes_vals( holes_s * H )
1044 {
1045 ENTRY("r_init_holes_vals");
1046
1047 H->max_size = 6;
1048 H->fill_val = 3;
1049
1050 H->filled.points = NULL;
1051 H->filled.used = 0;
1052 H->filled.M = 0;
1053
1054 RETURN(1);
1055 }
1056
1057
1058 /*----------------------------------------------------------------------
1059 **
1060 ** Fill all interior holes, subject to a size restriction.
1061 **
1062 **----------------------------------------------------------------------
1063 */
1064 static void
r_HL_cb_fill(Widget w,XtPointer client_data,XtPointer call_data)1065 r_HL_cb_fill(
1066 Widget w,
1067 XtPointer client_data,
1068 XtPointer call_data
1069 )
1070 {
1071 points_t Marked, Search;
1072 holes_s * H = (holes_s *)client_data;
1073 short * fdata = gRA.fdata;
1074 short * fptr, * uptr;
1075 int * wgpts, *tmpp;
1076 int count, fill_size, coord, status, pcount;
1077
1078 ENTRY("r_HL_cb_fill");
1079
1080 /* first store fdata to undo_data */
1081 fptr = gRA.fdata; uptr = gRA.undo_data;
1082 for ( count = 0; count < gRA.nvox; count++ )
1083 *uptr++ = *fptr++;
1084
1085
1086 Search.points = Marked.points = NULL;
1087
1088 /* add gRA.border and gr_edge to wtgr_edge */
1089 H->wtgr_edge.used = 0;
1090 for ( count = 0, wgpts = H->gr_edge.points;
1091 count < H->gr_edge.used;
1092 count++, wgpts++ )
1093 if ( ! r_add_to_boundary( &H->wtgr_edge, *wgpts ) )
1094 EXRETURN;
1095
1096 for ( count = 0, wgpts = gRA.border.points;
1097 count < gRA.border.used;
1098 count++, wgpts++ )
1099 if ( ! r_add_to_boundary( &H->wtgr_edge, *wgpts ) )
1100 EXRETURN;
1101
1102 /* for each point in white/gray boundary - try to grow */
1103 /* (watch for 3-D brick edges) */
1104 for ( count = 0, wgpts = H->wtgr_edge.points;
1105 count < H->wtgr_edge.used;
1106 count++, wgpts++ )
1107 {
1108
1109 fill_size = 0; /* init for current fill region */
1110
1111 fptr = fdata + *wgpts; /* addr + coordinate (offset) */
1112 if ( *fptr )
1113 continue;
1114
1115 if ( ! r_add_to_boundary( &Search, *wgpts ) )
1116 EXRETURN;
1117
1118 while ( Search.used > 0 )
1119 {
1120 coord = Search.points[Search.used - 1];
1121 Search.used--;
1122
1123 *(fdata + coord) = H->fill_val; /* mark as found */
1124 if ( ! r_add_to_boundary( &Marked, coord ) )
1125 EXRETURN;
1126
1127 fill_size++;
1128
1129 /* 1 = OK, 0 = BAD point found, -1 = memory error */
1130 if ( ( status = r_HL_check_neighbors( &Search, coord ) ) == -1 )
1131 EXRETURN;
1132
1133 if ( ( fill_size > H->max_size ) || ( status == 0 ) )
1134 {
1135 status = 0; /* if we enter through fill_size */
1136
1137 for ( pcount = 0, tmpp = Search.points;
1138 pcount < Search.used;
1139 pcount++, tmpp++ )
1140 *(fdata + *tmpp) = R_HL_BAD_VAL;
1141
1142 Search.used = 0; /* will terminate search loop */
1143
1144 for ( pcount = 0, tmpp = Marked.points;
1145 pcount < Marked.used;
1146 pcount++, tmpp++ )
1147 *(fdata + *tmpp) = R_HL_BAD_VAL;
1148
1149 Marked.used = 0;
1150 }
1151 }
1152
1153 Marked.used = 0;
1154 }
1155
1156 /* reset all BAD_VAL points - we haven't saved them */
1157 for ( count = 0, fptr = fdata; count < gRA.nvox; count++, fptr++ )
1158 if ( *fptr == R_HL_BAD_VAL )
1159 *fptr = 0;
1160
1161
1162 THD_load_statistics( gRA.func ) ;
1163 PLUTO_dset_redisplay( gRA.func ) ;
1164
1165 dset_changed = 1;
1166
1167 EXRETURN;
1168 }
1169
1170
1171 /*----------------------------------------------------------------------
1172 **
1173 ** Check neighbors for insertion into searchlist, or for BAD values.
1174 **
1175 ** Make sure we don't "leave" the 3-D image.
1176 **
1177 ** return 1 - normal
1178 ** 0 - BAD point found
1179 ** -1 - memory error ( r_add_to_boundary() )
1180 **
1181 **----------------------------------------------------------------------
1182 */
1183 static int
r_HL_check_neighbors(points_t * P,int coord)1184 r_HL_check_neighbors( points_t * P, int coord )
1185 {
1186 short * nptr = gRA.neighbors;
1187 short * fvalp = NULL;
1188 int nx, nxy, value;
1189
1190 ENTRY("r_HL_check_neighbors");
1191
1192 nx = gRA.nx;
1193 nxy = gRA.nxy;
1194
1195 if ( nptr[ coord ] == -1 ) /* do not accept edge points */
1196 RETURN(1); /* normal return */
1197
1198 fvalp = gRA.fdata + coord;
1199
1200 value = *(fvalp - 1);
1201 if ( value == R_HL_BAD_VAL )
1202 RETURN(0);
1203 else if ( ! value )
1204 if ( ! r_add_to_boundary( P, coord - 1 ) )
1205 RETURN(-1);
1206
1207 value = *(fvalp + 1);
1208 if ( value == R_HL_BAD_VAL )
1209 RETURN(0);
1210 else if ( ! value )
1211 if ( ! r_add_to_boundary( P, coord + 1 ) )
1212 RETURN(-1);
1213
1214 value = *(fvalp - nx);
1215 if ( value == R_HL_BAD_VAL )
1216 RETURN(0);
1217 else if ( ! value )
1218 if ( ! r_add_to_boundary( P, coord - nx ) )
1219 RETURN(-1);
1220
1221 value = *(fvalp + nx);
1222 if ( value == R_HL_BAD_VAL )
1223 RETURN(0);
1224 else if ( ! value )
1225 if ( ! r_add_to_boundary( P, coord + nx ) )
1226 RETURN(-1);
1227
1228 value = *(fvalp - nxy);
1229 if ( value == R_HL_BAD_VAL )
1230 RETURN(0);
1231 else if ( ! value )
1232 if ( ! r_add_to_boundary( P, coord - nxy ) )
1233 RETURN(-1);
1234
1235 value = *(fvalp + nxy);
1236 if ( value == R_HL_BAD_VAL )
1237 RETURN(0);
1238 else if ( ! value )
1239 if ( ! r_add_to_boundary( P, coord + nxy ) )
1240 RETURN(-1);
1241
1242 RETURN(0);
1243 }
1244
1245
1246 /*----------------------------------------------------------------------
1247 **
1248 ** Create interpolation shell.
1249 **
1250 **----------------------------------------------------------------------
1251 */
1252 static void
r_INT_mk_main_shell(interp_s * I)1253 r_INT_mk_main_shell( interp_s * I )
1254 {
1255 Widget junk, frame, rc;
1256 XmString xstring;
1257 Arg al[ 20 ];
1258 int ac;
1259
1260 ENTRY("r_INT_mk_main_shell");
1261
1262 if ( ! r_init_interp_vals( I ) )
1263 EXRETURN;
1264
1265 ac = 0;
1266 XtSetArg( al[ac], XmNinitialResourcesPersistent, False ); ac++;
1267 XtSetArg( al[ac], XmNdeleteResponse, XmDO_NOTHING ); ac++;
1268 XtSetArg( al[ac], XmNmappedWhenManaged, False ); ac++;
1269 I->main = XtAppCreateShell( "The Interpolator",
1270 "rshell", topLevelShellWidgetClass, gRX.display, al, ac );
1271
1272 XmAddWMProtocolCallback( I->main,
1273 XmInternAtom( gRX.display, "WM_DELETE_WINDOW", False ),
1274 ( XtCallbackProc )r_any_cb_hide, "INT" );
1275
1276 ac = 0;
1277 XtSetArg( al[ac], XmNspacing, 15 ); ac++;
1278 XtSetArg( al[ac], XmNmarginWidth, 10 ); ac++;
1279 XtSetArg( al[ac], XmNmarginHeight, 10 ); ac++;
1280 I->mainRC = XmCreateRowColumn( I->main, "rowcolumn", al, ac );
1281
1282 /* create the main white and gray selection frames */
1283 ( void )r_INT_mk_fillval_fr ( I, I->mainRC );
1284 ( void )r_INT_mk_app_buttons( I, I->mainRC );
1285
1286 XtManageChild( I->mainRC );
1287 XtRealizeWidget( I->main ); NI_sleep(1) ;
1288
1289 EXRETURN ;
1290 }
1291
1292
1293 /*----------------------------------------------------------------------
1294 **
1295 ** Create boundary (gray matter) buttons.
1296 **
1297 **----------------------------------------------------------------------
1298 */
1299 static Widget
r_INT_mk_app_buttons(interp_s * I,Widget parent)1300 r_INT_mk_app_buttons( interp_s * I, Widget parent )
1301 {
1302 int ac;
1303 Arg al[ 10 ];
1304 Widget form, frame, button1, button2;
1305 XmString xstr;
1306
1307 ENTRY("r_INT_mk_app_buttons");
1308
1309 /* create frame to hold form and buttons */
1310 ac = 0;
1311 frame = XmCreateFrame( parent, "frame", al, ac );
1312
1313 /* create form to hold push buttons */
1314 ac = 0;
1315 XtSetArg( al[ac], XmNhorizontalSpacing, R_BUTTON_SPACE ); ac++;
1316 form = XmCreateForm( frame, "form", al, ac );
1317
1318
1319 /* region fill button */
1320 ac = 0;
1321 xstr = XmStringCreateLtoR( "FILL", gRX.charset );
1322 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
1323 button1 = XmCreatePushButton( form, "fill", al, ac );
1324 XtManageChild( button1 );
1325 XtAddCallback( button1, XmNactivateCallback,
1326 ( XtCallbackProc )r_INT_cb_fill, I );
1327 XtSetSensitive( button1, True );
1328 XmStringFree( xstr );
1329 MCW_register_hint( button1 , "interpolate between the last two lines" );
1330
1331 /* unfill button */
1332 ac = 0;
1333 XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET ); ac++;
1334 XtSetArg( al[ac], XmNleftWidget, button1 ); ac++;
1335 xstr = XmStringCreateLtoR( "unfill", gRX.charset );
1336 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
1337 button2 = XmCreatePushButton( form, "unfill", al, ac );
1338 XtManageChild( button2 );
1339 XtAddCallback( button2, XmNactivateCallback,
1340 ( XtCallbackProc )r_any_cb_unfill, &gRI.fill_val );
1341 XtSetSensitive( button2, True );
1342 XmStringFree( xstr );
1343 MCW_register_hint( button2 , "unfill at interpolation \"fill value\"" );
1344
1345 /* apply button - set interpolation values to draw values */
1346 ac = 0;
1347 XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET ); ac++;
1348 XtSetArg( al[ac], XmNleftWidget, button2 ); ac++;
1349 xstr = XmStringCreateLtoR( "apply", gRX.charset );
1350 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
1351 button1 = XmCreatePushButton( form, "apply", al, ac );
1352 XtManageChild( button1 );
1353 XtAddCallback( button1, XmNactivateCallback,
1354 ( XtCallbackProc )r_any_cb_apply, &gRI.fill_val );
1355 XtSetSensitive( button1, True );
1356 XmStringFree( xstr );
1357 MCW_register_hint( button1 , "sets fill values to main draw values" );
1358
1359
1360 /* stats button */
1361 ac = 0;
1362 XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET ); ac++;
1363 XtSetArg( al[ac], XmNleftWidget, button1 ); ac++;
1364 xstr = XmStringCreateLtoR( "stats", gRX.charset );
1365 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
1366 button2 = XmCreatePushButton( form, "stats", al, ac );
1367 XtManageChild( button2 );
1368 XtAddCallback( button2, XmNactivateCallback,
1369 ( XtCallbackProc )r_any_cb_fill_stats, &gRI.fill_val );
1370 XtSetSensitive( button2, True );
1371 XmStringFree( xstr );
1372
1373 /* hide button */
1374 ac = 0;
1375 XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET ); ac++;
1376 XtSetArg( al[ac], XmNleftWidget, button2 ); ac++;
1377 xstr = XmStringCreateLtoR( "hide", gRX.charset );
1378 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
1379 button1 = XmCreatePushButton( form, "hide", al, ac );
1380 XtManageChild( button1 );
1381 XtAddCallback( button1, XmNactivateCallback,
1382 ( XtCallbackProc )r_any_cb_hide, "INT" );
1383 XtSetSensitive( button1, True );
1384 XmStringFree( xstr );
1385
1386
1387 XtManageChild( form );
1388 XtManageChild( frame );
1389
1390 RETURN( frame );
1391 }
1392
1393
1394 /*----------------------------------------------------------------------
1395 **
1396 ** Create the "fill value" widget for interpolation window.
1397 **
1398 **----------------------------------------------------------------------
1399 */
1400 static Widget
r_INT_mk_fillval_fr(interp_s * I,Widget parent)1401 r_INT_mk_fillval_fr( interp_s * I, Widget parent )
1402 {
1403 Widget junk, rc, frame;
1404 XmString xstr;
1405 Arg al[ 10 ];
1406 int ac;
1407 char string[ 15 ];
1408
1409 ENTRY("r_INT_mk_fillval_fr");
1410
1411 ac = 0;
1412 frame = XmCreateFrame( parent, "frame", al, ac );
1413
1414 ac = 0;
1415 XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT ); ac++;
1416 XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL ); ac++;
1417 rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
1418
1419
1420 sprintf( string, "%d", I->fill_val );
1421
1422 ac = 0;
1423 xstr = XmStringCreateLtoR( "fill value : ", gRX.charset );
1424 XtSetArg( al[ ac ], XmNlabelString, xstr ); ac++;
1425 junk = XmCreateLabel( rc, "label", al, ac );
1426 XtManageChild( junk );
1427 XmStringFree( xstr );
1428
1429 ac = 0;
1430 XtSetArg( al[ ac ], XmNvalue, string ); ac++;
1431 XtSetArg( al[ ac ], XmNwidth, 80 ); ac++;
1432 I->fillval_w = XmCreateText( rc, "text", al, ac );
1433 XtManageChild( I->fillval_w );
1434 XtAddCallback( I->fillval_w, XmNactivateCallback,
1435 ( XtCallbackProc )r_INT_cb_set_fill_val, NULL );
1436 XtAddCallback( I->fillval_w, XmNlosingFocusCallback,
1437 ( XtCallbackProc )r_INT_cb_set_fill_val, NULL );
1438
1439
1440 XtManageChild( rc );
1441 XtManageChild( frame );
1442
1443 RETURN( frame );
1444 }
1445
1446
1447 /*----------------------------------------------------------------------
1448 **
1449 ** Callback to apply the interpolation values (change them to
1450 ** drawn values).
1451 **
1452 **----------------------------------------------------------------------
1453 */
1454 static void
r_any_cb_apply(Widget w,XtPointer client_data,XtPointer call_data)1455 r_any_cb_apply(
1456 Widget w,
1457 XtPointer client_data,
1458 XtPointer call_data
1459 )
1460 {
1461 short * fptr, * uptr;
1462 int clear_val = *( (int *)client_data );
1463 int count;
1464
1465 ENTRY("r_any_cb_apply");
1466
1467 if ( ! gRA.fdata ) /* error beep */
1468 {
1469 fprintf( stderr, "%c", 7 );
1470 EXRETURN;
1471 }
1472
1473 /* first store to undo_data */
1474 fptr = gRA.fdata; uptr = gRA.undo_data;
1475 for ( count = 0; count < gRA.nvox; count++ )
1476 *uptr++ = *fptr++;
1477
1478 for ( count = 0, fptr = gRA.fdata; count < gRA.nvox; count++, fptr++ )
1479 if ( *fptr == clear_val )
1480 *fptr = value_int;
1481
1482 THD_load_statistics( gRA.func ) ;
1483 PLUTO_dset_redisplay( gRA.func ) ;
1484
1485 EXRETURN;
1486 }
1487
1488
1489 /*----------------------------------------------------------------------
1490 **
1491 ** Callback to hide windows.
1492 **
1493 **----------------------------------------------------------------------
1494 */
1495 static void
r_any_cb_hide(Widget w,char * client_data,XtPointer call_data)1496 r_any_cb_hide(
1497 Widget w,
1498 char * client_data,
1499 XtPointer call_data
1500 )
1501 {
1502 ENTRY("r_any_cb_hide");
1503
1504 if ( ! strcmp( client_data, "INT" ) )
1505 XtUnmapWidget( gRI.main );
1506 else if ( ! strcmp( client_data, "HL" ) )
1507 XtUnmapWidget( gRH.main );
1508 else if ( ! strcmp( client_data, "wtgr" ) )
1509 XtUnmapWidget( gRX.wtgr_main );
1510 else if ( ! strcmp( client_data, "saveas" ) )
1511 XtUnmanageChild( gRX.save_as_file_d );
1512 else if ( ! strcmp( client_data, "all" ) )
1513 {
1514 XtUnmapWidget( gRI.main );
1515 XtUnmapWidget( gRH.main );
1516 XtUnmapWidget( gRX.wtgr_main );
1517 XtUnmanageChild( gRX.save_as_file_d );
1518 }
1519 else
1520 {
1521 sprintf( gRmessage, "rach_10 : client_data is '%s'\n", client_data );
1522 rERROR( gRmessage );
1523 }
1524
1525 EXRETURN;
1526 }
1527
1528
1529 /*----------------------------------------------------------------------
1530 **
1531 ** Callback to raise windows.
1532 **
1533 **----------------------------------------------------------------------
1534 */
1535 static void
r_any_cb_raise(Widget w,char * client_data,XtPointer call_data)1536 r_any_cb_raise(
1537 Widget w,
1538 char * client_data,
1539 XtPointer call_data
1540 )
1541 {
1542 ENTRY("r_any_cb_raise");
1543
1544 if ( ! strcmp( client_data, "INT" ) )
1545 {
1546 XMapRaised( XtDisplay( gRI.main ) , XtWindow( gRI.main ) ); NI_sleep(1);
1547 }
1548 else if ( ! strcmp( client_data, "HL" ) )
1549 {
1550 XMapRaised( XtDisplay( gRH.main ) , XtWindow( gRH.main ) ); NI_sleep(1);
1551 }
1552 else if ( ! strcmp( client_data, "wtgr" ) )
1553 {
1554 XMapRaised( XtDisplay( gRX.wtgr_main ) , XtWindow( gRX.wtgr_main ) ); NI_sleep(1);
1555 }
1556 else if ( ! strcmp( client_data, "saveas" ) )
1557 {
1558 XtManageChild( gRX.save_as_file_d );
1559 XtPopup( XtParent( gRX.save_as_file_d ), XtGrabNone ); NI_sleep(1);
1560 }
1561 else if ( ! strcmp( client_data, "all" ) )
1562 {
1563 XMapRaised( XtDisplay( gRI.main ) , XtWindow( gRI.main ) ); NI_sleep(1);
1564 XMapRaised( XtDisplay( gRH.main ) , XtWindow( gRH.main ) ); NI_sleep(1);
1565 XMapRaised( XtDisplay( gRX.wtgr_main ) , XtWindow( gRX.wtgr_main ) ); NI_sleep(1);
1566 XtManageChild( gRX.save_as_file_d );
1567 XtPopup( XtParent( gRX.save_as_file_d ), XtGrabNone ); NI_sleep(1);
1568 }
1569 else
1570 {
1571 sprintf( gRmessage, "racr_10 : client_data is '%s'\n", client_data );
1572 rERROR( gRmessage );
1573 }
1574
1575 EXRETURN;
1576 }
1577
1578
1579 /*----------------------------------------------------------------------
1580 **
1581 ** Callback to undo previous action (restore fdata from undo_data).
1582 **
1583 **----------------------------------------------------------------------
1584 */
1585 static void
r_any_cb_undo(Widget w,XtPointer client_data,XtPointer call_data)1586 r_any_cb_undo(
1587 Widget w,
1588 XtPointer client_data,
1589 XtPointer call_data
1590 )
1591 {
1592 short * fptr, * uptr;
1593 int count;
1594
1595 ENTRY("r_any_cb_undo");
1596
1597 fptr = gRA.fdata; uptr = gRA.undo_data;
1598 if ( !fptr || !uptr )
1599 {
1600 fprintf(stderr,"** undo without pointers: (%p,%p)\n",fptr,uptr);
1601 EXRETURN;
1602 }
1603
1604 for ( count = 0; count < gRA.nvox; count++ )
1605 *fptr++ = *uptr++;
1606
1607 THD_load_statistics( gRA.func ) ;
1608 PLUTO_dset_redisplay( gRA.func ) ;
1609
1610 EXRETURN;
1611 }
1612
1613
1614 /*----------------------------------------------------------------------
1615 **
1616 ** Callback to interpolate between user drawn lines.
1617 **
1618 **----------------------------------------------------------------------
1619 */
1620 static void
r_INT_cb_fill(Widget w,XtPointer client_data,XtPointer call_data)1621 r_INT_cb_fill(
1622 Widget w,
1623 XtPointer client_data,
1624 XtPointer call_data
1625 )
1626 {
1627 r_ipt_t sourcep, destp;
1628 interp_s * I = (interp_s *)client_data;
1629 points_t * lb, * sb;
1630 double index_ratio, tot_dist;
1631 double dx, dy, dz, dcurr;
1632 double fx, fy, fz;
1633 short * fnptr = gRA.fdata, * sptr;
1634 short * fptr, * uptr;
1635 int * ip1;
1636 int count, dest_index, coord;
1637 int nx = gRA.nx, ny = gRA.ny, nz = gRA.nz;
1638
1639 ENTRY("r_INT_cb_fill");
1640
1641 if ( ! gRA.fdata )
1642 {
1643 fprintf( stderr, "%c", 7 );
1644 EXRETURN;
1645 }
1646
1647 if ( ! I )
1648 {
1649 rERROR( "Error : entered r_INT_cb_fill() without client_data." );
1650 EXRETURN;
1651 }
1652
1653 /* check that neither border is empty */
1654 if ( I->A.used <= 0 || I->B.used <= 0 )
1655 {
1656 fprintf( stderr, "%c", 7 );
1657 rWARNING( "Missing bounding curve for interpolation." );
1658 EXRETURN;
1659 }
1660
1661 /* first store to undo_data */
1662 fptr = gRA.fdata; uptr = gRA.undo_data;
1663 for ( count = 0; count < gRA.nvox; count++ )
1664 *uptr++ = *fptr++;
1665
1666 if ( I->A.used >= I->B.used )
1667 {
1668 lb = &I->A;
1669 sb = &I->B;
1670 index_ratio = I->B.used / (double)I->A.used;
1671 }
1672 else
1673 {
1674 lb = &I->B;
1675 sb = &I->A;
1676 index_ratio = I->A.used / (double)I->B.used;
1677 }
1678
1679 for ( count = 0, ip1 = lb->points; count < lb->used; count++, ip1++ )
1680 {
1681 sourcep = r_index2pt( *ip1, nx, ny, nz );
1682 dest_index = count * index_ratio + 0.0001;
1683 destp = r_index2pt( sb->points[dest_index], nx, ny, nz );
1684
1685 tot_dist = r_p_distance( sourcep, destp );
1686 dx = R_DIST_STEP * ( destp.x - sourcep.x ) / tot_dist;
1687 dy = R_DIST_STEP * ( destp.y - sourcep.y ) / tot_dist;
1688 dz = R_DIST_STEP * ( destp.z - sourcep.z ) / tot_dist;
1689 fx = sourcep.x + dx;
1690 fy = sourcep.y + dy;
1691 fz = sourcep.z + dz;
1692
1693 for ( dcurr = R_DIST_STEP; dcurr < tot_dist; dcurr += R_DIST_STEP )
1694 {
1695 coord = (int)fx + nx * ( (int)fy + ny * (int)fz );
1696
1697 sptr = fnptr + coord;
1698
1699 /* if ( ! *sptr ) - draw through anything? */
1700 *sptr = I->fill_val;
1701
1702 fx += dx;
1703 fy += dy;
1704 fz += dz;
1705 }
1706 }
1707
1708 THD_load_statistics( gRA.func );
1709 PLUTO_dset_redisplay( gRA.func );
1710 dset_changed = 1;
1711
1712 EXRETURN;
1713 }
1714
1715
1716 /*----------------------------------------------------------------------
1717 **
1718 ** Compute the distance between two points.
1719 **
1720 **----------------------------------------------------------------------
1721 */
1722 static double
r_p_distance(r_ipt_t p1,r_ipt_t p2)1723 r_p_distance( r_ipt_t p1, r_ipt_t p2 )
1724 {
1725 return( sqrt( ( p1.x - p2.x ) * ( p1.x - p2.x ) +
1726 ( p1.y - p2.y ) * ( p1.y - p2.y ) +
1727 ( p1.z - p2.z ) * ( p1.z - p2.z ) )
1728 );
1729 }
1730
1731
1732 /*----------------------------------------------------------------------
1733 **
1734 ** Convert the coordinate to a point.
1735 **
1736 ** We assume coord is of the form coord = X + nx * ( Y + ny * Z ).
1737 ** The resulting point is P = { X, Y, Z }.
1738 **
1739 **----------------------------------------------------------------------
1740 */
1741 static r_ipt_t
r_index2pt(int coord,int nx,int ny,int nz)1742 r_index2pt( int coord, int nx, int ny, int nz )
1743 {
1744 r_ipt_t p = { 0, 0, 0 };
1745 int tmp;
1746
1747 ENTRY("r_index2pt");
1748
1749 if ( coord < 0 )
1750 {
1751 sprintf( gRmessage, "Coordinate %d is out of range!\n", coord );
1752 rERROR( gRmessage );
1753 RETURN(p);
1754 }
1755
1756 p.x = coord % nx;
1757 tmp = coord / nx;
1758 p.y = tmp % ny;
1759 p.z = tmp / ny;
1760
1761 if ( p.z >= nz )
1762 {
1763 sprintf( gRmessage, "Coordinate %d is out of range!\n"
1764 "Associated point is (%d,%d,%d).\n",
1765 coord, p.x, p.y, p.z );
1766 rERROR( gRmessage );
1767 }
1768
1769 RETURN(p);
1770 }
1771
1772
1773 /*----------------------------------------------------------------------
1774 **
1775 ** Initialize the point connection structure.
1776 **
1777 ** structure :
1778 **
1779 ** typedef struct
1780 ** {
1781 ** r_ipt_t source;
1782 ** r_ipt_t dest;
1783 **
1784 ** int cur_pt; * flag denoting first or second point *
1785 ** } r_pt_conn_s;
1786 **
1787 **----------------------------------------------------------------------
1788 */
1789 static int
r_init_pt_conn_s(r_pt_conn_s * P)1790 r_init_pt_conn_s( r_pt_conn_s * P )
1791 {
1792 r_ipt_t p = { 0, 0, 0 };
1793
1794 P->cur_pt = 1; /* may be either 1 or 2 */
1795 P->source = p; /* just to initialize to SOMEthing */
1796 P->dest = p;
1797
1798 P->plist.points = NULL; /* init border structure */
1799 P->plist.used = 0;
1800 P->plist.M = 0;
1801
1802 return 1;
1803 }
1804
1805
1806 /*----------------------------------------------------------------------
1807 **
1808 ** Initialize the Algorithm values.
1809 **
1810 ** structure :
1811 **
1812 ** typedef struct
1813 ** {
1814 ** Widget main; * main application widget *
1815 ** Widget mainRC; * main rowcolumn widget *
1816 **
1817 ** int fill_val;
1818 ** int afni_undo;
1819 **
1820 ** points_t A, B; * two point structures for interpolation *
1821 ** } interp_s;
1822 **
1823 **----------------------------------------------------------------------
1824 */
1825 static int
r_init_interp_vals(interp_s * I)1826 r_init_interp_vals( interp_s * I )
1827 {
1828 ENTRY("r_init_interp_vals");
1829
1830 I->fill_val = 2;
1831 I->afni_undo = 0;
1832
1833 I->A.used = 0;
1834 I->A.M = 100;
1835 I->A.points = (int *)malloc( I->A.M * sizeof( int ) );
1836
1837 if ( I->A.points == NULL )
1838 {
1839 fprintf( stderr, "\nError: riiv10\n"
1840 "Failed to allocate %d ints for interpolation struct.\n\n",
1841 I->A.M );
1842 RETURN(0);
1843 }
1844
1845 I->B.used = 0;
1846 I->B.M = 100;
1847 I->B.points = (int *)malloc( I->B.M * sizeof( int ) );
1848
1849 if ( I->B.points == NULL )
1850 {
1851 fprintf( stderr, "\nError: riiv20\n"
1852 "Failed to allocate %d ints for interpolation struct.\n\n",
1853 I->B.M );
1854 RETURN(0);
1855 }
1856
1857 RETURN(1);
1858 }
1859
1860
1861 /*----------------------------------------------------------------------
1862 **
1863 ** Create main filling widgets.
1864 **
1865 **----------------------------------------------------------------------
1866 */
1867 static Widget
r_wt_mk_main_frame(r_X_s * X,Widget parent)1868 r_wt_mk_main_frame( r_X_s * X, Widget parent )
1869 {
1870 Widget frame, rc, label;
1871 XmString xstring;
1872 Arg al[ 20 ];
1873 int ac;
1874
1875 ENTRY("r_wt_mk_main_frame");
1876
1877 ac = 0;
1878 XtSetArg( al[ ac ], XmNmarginHeight, 3 ); ac++;
1879 frame = XmCreateFrame( parent, "frame", al, ac );
1880
1881 ac = 0;
1882 XtSetArg( al[ ac ], XmNlabelString,
1883 XmStringCreate( "White Matter Fill :", X->charset ) ); ac++;
1884 XtSetArg( al[ ac ], XmNchildType, XmFRAME_TITLE_CHILD ); ac++;
1885 XtSetArg( al[ ac ], XmNchildVerticalAlignment,
1886 XmALIGNMENT_BASELINE_BOTTOM); ac++;
1887 label = XmCreateLabel( frame, "label", al, ac );
1888 XtManageChild( label );
1889
1890 ac = 0;
1891 rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
1892
1893 ( void )r_wt_mk_range_fr ( X, rc );
1894 ( void )r_wt_mk_fillval_fr ( X, rc );
1895 ( void )r_wt_mk_nbrs_fr ( X, rc );
1896 ( void )r_wt_mk_diag_conn_fr ( X, rc );
1897 ( void )r_wt_mk_strong_bord_fr( X, rc );
1898
1899 r_wt_mk_fill_buttons( X, rc );
1900
1901
1902 XtManageChild( rc );
1903 XtManageChild( frame );
1904
1905 RETURN(frame);
1906 }
1907
1908
1909 /*----------------------------------------------------------------------
1910 **
1911 ** Create the main gray matter function frame.
1912 **
1913 **----------------------------------------------------------------------
1914 */
1915 static Widget
r_gr_mk_main_frame(r_X_s * X,Widget parent)1916 r_gr_mk_main_frame( r_X_s * X, Widget parent )
1917 {
1918 Widget frame, rc, label;
1919 XmString xstring;
1920 Arg al[ 20 ];
1921 int ac;
1922
1923 ENTRY("r_gr_mk_main_frame");
1924
1925 ac = 0;
1926 XtSetArg( al[ ac ], XmNmarginHeight, 3 ); ac++;
1927 frame = XmCreateFrame( parent, "frame", al, ac );
1928
1929 ac = 0;
1930 XtSetArg( al[ ac ], XmNlabelString,
1931 XmStringCreate( "Gray Matter Fill :", X->charset ) ); ac++;
1932 XtSetArg( al[ ac ], XmNchildType, XmFRAME_TITLE_CHILD ); ac++;
1933 XtSetArg( al[ ac ], XmNchildVerticalAlignment,
1934 XmALIGNMENT_BASELINE_BOTTOM); ac++;
1935 label = XmCreateLabel( frame, "label", al, ac );
1936 XtManageChild( label );
1937
1938 ac = 0;
1939 rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
1940
1941
1942 ( void )r_gr_mk_range_fr ( X, rc );
1943 ( void )r_gr_mk_fillval_fr ( X, rc );
1944 ( void )r_gr_mk_max_dist_w ( X, rc );
1945 ( void )r_gr_mk_fill_buttons( X, rc );
1946
1947
1948
1949 XtManageChild( rc );
1950 XtManageChild( frame );
1951
1952 RETURN(frame);
1953 }
1954
1955
1956 /*----------------------------------------------------------------------
1957 **
1958 ** Initialize the Algorithm values.
1959 **
1960 **----------------------------------------------------------------------
1961 */
1962 static int
r_init_Alg_values(r_alg_s * A)1963 r_init_Alg_values( r_alg_s * A )
1964 {
1965 ENTRY("r_init_Alg_values");
1966
1967 A->point_value = 75;
1968 A->point_coord = -1; /* means user has not yet selected a point */
1969 A->adjust_point = 0;
1970
1971 strcpy( A->save_as_name, "default" );
1972
1973 A->wt_fill_val = 5;
1974 A->wt_range_min = r_wtgr_calc_min_frm_val( A->point_value );
1975 A->wt_range_max = r_wtgr_calc_max_frm_val( A->point_value );
1976 A->wt_diag_connect = 0; /* any connection */
1977
1978 A->gr_fill_val = 10;
1979 A->gr_range_min = r_wtgr_calc_min_frm_val( 42 );
1980 A->gr_range_max = r_wtgr_calc_max_frm_val( 42 );
1981 A->gr_max_dist = 4;
1982
1983 A->anat = plint->im3d->anat_now;
1984
1985 fprintf(stderr,"r_init_Alg_values(): A->anat = %p\n",A->anat);
1986 if ( A->anat )
1987 {
1988 if ( ! DSET_LOADED(A->anat) )
1989 {
1990 DSET_load( A->anat );
1991 fprintf(stderr,"-d loading anat...\n");
1992 }
1993 A->adata = (short *)DSET_BRICK_ARRAY( A->anat, 0 );
1994 /*fprintf(stderr,"Set A->adata to %p\n",A->adata);*/
1995 }
1996
1997 /*
1998 ** Create boundary memory and check for malloc success.
1999 */
2000 A->Bold.used = 0;
2001 A->Bold.M = 1000;
2002 A->Bold.points = (int *)malloc( A->Bold.M * sizeof( int ) );
2003
2004 if ( A->Bold.points == NULL )
2005 {
2006 fprintf( stderr, "Error: riAv10\n"
2007 "Failed to allocate %d ints for boundary.\n", A->Bold.M );
2008 RETURN(0);
2009 }
2010
2011 A->Bnew.used = 0;
2012 A->Bnew.M = 1000;
2013 A->Bnew.points = (int *)malloc( A->Bnew.M * sizeof( int ) );
2014
2015 if ( A->Bnew.points == NULL )
2016 {
2017 fprintf( stderr, "\nError: riAv20\n"
2018 "Failed to allocate %d ints for boundary.\n\n", A->Bnew.M );
2019 RETURN(0);
2020 }
2021
2022 A->border.used = 0;
2023 A->border.M = 1000;
2024 A->border.points = (int *)malloc( A->border.M * sizeof( int ) );
2025
2026 if ( A->border.points == NULL )
2027 {
2028 fprintf( stderr, "\nError: riAv30\n"
2029 "Failed to allocate %d ints for boundary.\n\n",
2030 A->border.M );
2031 RETURN(0);
2032 }
2033
2034 /* we will initialize this after we know we have data */
2035 A->neighbors = NULL; /* - will be nvox */
2036 A->undo_data = NULL; /* - will be nvox */
2037
2038 A->min_nbrs = 0;
2039 A->strong_borders = 1;
2040
2041
2042 RETURN(1);
2043 }
2044
2045
2046 /*----------------------------------------------------------------------
2047 **
2048 ** Initialize the afni values.
2049 **
2050 **----------------------------------------------------------------------
2051 */
2052 static void
r_init_afni_vars(r_alg_s * A,THD_3dim_dataset * func)2053 r_init_afni_vars( r_alg_s * A, THD_3dim_dataset * func )
2054 {
2055 ENTRY("r_init_afni_vars");
2056
2057 A->anat = plint->im3d->anat_now;
2058
2059 if ( func )
2060 {
2061 if ( DSET_BRICK_TYPE( func, 0 ) != MRI_short )
2062 {
2063 ( void )MCW_popup_message( gRX.main,
2064 "Serious error.\n"
2065 "\n"
2066 "Functional data is not of\n"
2067 "type short. Please choose\n"
2068 "another dataset.\n",
2069 MCW_USER_KILL | MCW_TIMER_KILL );
2070 EXRETURN;
2071 }
2072
2073 A->func = func;
2074
2075 A->factor = DSET_BRICK_FACTOR( A->func, 0 );
2076 A->factor = ( A->factor == 0.0 ) ? 1.0 : A->factor;
2077 A->fdata = (short *)DSET_BRICK_ARRAY( A->func, 0 );
2078
2079 A->nx = DSET_NX( A->func );
2080 A->ny = DSET_NY( A->func );
2081 A->nz = DSET_NZ( A->func );
2082 A->nxy = A->nx * A->ny;
2083 A->nvox = A->nx * A->ny * A->nz;
2084
2085 if ( A->neighbors == NULL )
2086 {
2087 A->neighbors = malloc( A->nvox * sizeof( short ) );
2088 if ( A->neighbors == NULL )
2089 {
2090 fprintf( stderr, "\nError: riav10\n"
2091 "Failed to allocate %d ints for neighbors.\n\n", A->nvox );
2092 }
2093
2094 A->undo_data = calloc( A->nvox, sizeof( short ) );
2095 if ( A->undo_data == NULL )
2096 {
2097 fprintf( stderr, "\nError: riav20\n"
2098 "Failed to allocate %d ints for undo_data.\n\n", A->nvox );
2099 }
2100 }
2101 }
2102 else
2103 ( void )MCW_popup_message( gRX.main,
2104 "Serious error.\n"
2105 "\n"
2106 "Missing functional dataset.\n"
2107 "Please choose another dataset.\n",
2108 MCW_USER_KILL | MCW_TIMER_KILL );
2109
2110 fprintf(stderr,"r_init_afni_vars(): A->anat = %p\n",A->anat);
2111 if ( A->anat )
2112 {
2113 if ( DSET_BRICK_TYPE( A->anat, 0 ) != MRI_short )
2114 {
2115 ( void )MCW_popup_message( gRX.main,
2116 "Serious error.\n"
2117 "\n"
2118 "Anatomical data is not of\n"
2119 "type short. Please choose\n"
2120 "another dataset.\n",
2121 MCW_USER_KILL | MCW_TIMER_KILL );
2122 EXRETURN;
2123 }
2124
2125 if ( ! DSET_LOADED(A->anat) )
2126 {
2127 fprintf(stderr,"-d loading anat...\n");
2128 DSET_load( A->anat );
2129 }
2130
2131 A->adata = (short *)DSET_BRICK_ARRAY( A->anat, 0 );
2132 /*fprintf(stderr,"Set A->adata to %p\n",A->adata);*/
2133 }
2134 else
2135 ( void )MCW_popup_message( gRX.main,
2136 "Serious error.\n"
2137 "\n"
2138 "Missing anatomical dataset.\n"
2139 "Please choose another dataset.\n",
2140 MCW_USER_KILL | MCW_TIMER_KILL );
2141
2142 EXRETURN;
2143 }
2144
2145
2146 /*----------------------------------------------------------------------
2147 **
2148 ** Callback to output statistics on selected matter.
2149 **
2150 **----------------------------------------------------------------------
2151 */
2152 static void
r_any_cb_fill_stats(Widget w,XtPointer client_data,XtPointer call_data)2153 r_any_cb_fill_stats(
2154 Widget w,
2155 XtPointer client_data,
2156 XtPointer call_data
2157 )
2158 {
2159 short * fptr = gRA.fdata;
2160 short * aptr = gRA.adata;
2161 int fillval = *(int *)client_data;
2162 int count, min = 30000, max = -30000, size = 0;
2163
2164 ENTRY("r_any_cb_fill_stats");
2165
2166 if ( ! gRA.fdata )
2167 {
2168 fputc( 7, stderr ); /* hard-code a beep */
2169 EXRETURN;
2170 }
2171
2172 for ( count = 0; count < gRA.nvox; count++ )
2173 {
2174 if ( *fptr == fillval )
2175 {
2176 if ( *aptr > max )
2177 max = *aptr;
2178 if ( *aptr < min )
2179 min = *aptr;
2180 size++;
2181 }
2182
2183 aptr++;
2184 fptr++;
2185 }
2186
2187 printf( "------------------------------------------------------------\n" );
2188
2189 if ( size > 0 )
2190 {
2191 printf( "fill region min = %d\n", min );
2192 printf( "fill region max = %d\n", max );
2193 printf( "fill region size = %d\n", size );
2194 printf( "\n" );
2195
2196 r_histogram( &gRA, min, max, fillval );
2197 }
2198 else
2199 rWARNING( "Fill region is empty." );
2200
2201 printf( "------------------------------------------------------------\n" );
2202
2203 EXRETURN;
2204 }
2205
2206
2207 /*----------------------------------------------------------------------
2208 **
2209 ** Make a histogram from the selected data.
2210 **
2211 **----------------------------------------------------------------------
2212 */
2213 static void
r_histogram(r_alg_s * A,int min,int max,int check_val)2214 r_histogram( r_alg_s * A, int min, int max, int check_val )
2215 {
2216 int * hist;
2217
2218 short * fptr = gRA.fdata;
2219 short * aptr = gRA.adata;
2220 int count, size = max - min + 1, total = 0;
2221
2222 ENTRY("r_histogram");
2223
2224 if ( ( hist = (int *)malloc( size * sizeof( int ) ) ) == NULL )
2225 {
2226 sprintf( gRmessage, "Error: pr_rh_10\n"
2227 "Failed alloca for %d ints.", size );
2228 rWARNING( gRmessage );
2229 EXRETURN;
2230 }
2231
2232 for ( count = 0; count < size; count++ )
2233 hist[count] = 0;
2234
2235 for ( count = 0; count < A->nvox; count++ )
2236 {
2237 if ( *fptr == check_val )
2238 {
2239 hist[*aptr - min]++;
2240 total++;
2241 }
2242
2243 aptr++;
2244 fptr++;
2245 }
2246
2247 printf( " value \t nvox \t %%\n" );
2248 printf( "--------- \t --------- \t --------- \n" );
2249
2250 for ( count = 0; count < size; count++)
2251 printf( " %6d \t %7d \t %7.3f\n",
2252 min + count, hist[ count ], 100.0 * hist[ count ] / total );
2253 free(hist);
2254 EXRETURN;
2255 }
2256
2257
2258 /*----------------------------------------------------------------------
2259 **
2260 ** Callback to toggle the strong borders flag.
2261 **
2262 **----------------------------------------------------------------------
2263 */
2264 static void
r_wt_cb_SB_toggle(Widget w,XtPointer client_data,XtPointer call_data)2265 r_wt_cb_SB_toggle(
2266 Widget w,
2267 XtPointer client_data,
2268 XtPointer call_data
2269 )
2270 {
2271 RwcBoolean set;
2272 Arg al[ 10 ];
2273 int ac;
2274
2275 ac = 0;
2276 XtSetArg( al[ ac ], XmNset, &set ); ac++;
2277 XtGetValues( w, al, ac );
2278
2279 if ( set )
2280 gRA.strong_borders = 1;
2281 else
2282 gRA.strong_borders = 0;
2283
2284 return;
2285 }
2286
2287
2288 /*----------------------------------------------------------------------
2289 **
2290 ** Given an integer value, return the suggested minimum search value.
2291 **
2292 **----------------------------------------------------------------------
2293 */
2294 static int
r_wtgr_calc_min_frm_val(int value)2295 r_wtgr_calc_min_frm_val( int value )
2296 {
2297 return( (int)(0.94 * value - 5) );
2298 }
2299
2300
2301 /*----------------------------------------------------------------------
2302 **
2303 ** Given an integer value, return the suggested minimum search value.
2304 **
2305 **----------------------------------------------------------------------
2306 */
2307 static int
r_wtgr_calc_max_frm_val(int value)2308 r_wtgr_calc_max_frm_val( int value )
2309 {
2310 return( (int)(1.06 * value + 5) );
2311 }
2312
2313
2314 /*----------------------------------------------------------------------
2315 **
2316 ** Hide the main white/gray matter finder.
2317 **
2318 **----------------------------------------------------------------------
2319 */
2320 static void
r_wtgr_cb_hide(void)2321 r_wtgr_cb_hide( void )
2322 {
2323 XtUnmapWidget( gRX.wtgr_main );
2324 }
2325
2326
2327 /*----------------------------------------------------------------------
2328 **
2329 ** Callback to suggest range limits for white AND gray matter search.
2330 **
2331 ** Values will be set in the wt_range_min_w and wt_range_max_w widgets.
2332 **
2333 **----------------------------------------------------------------------
2334 */
2335 static void
r_wtgr_cb_suggest_limits(Widget w,XtPointer client_data,XtPointer call_data)2336 r_wtgr_cb_suggest_limits(
2337 Widget w,
2338 XtPointer client_data,
2339 XtPointer call_data
2340 )
2341 {
2342 Widget minw, maxw;
2343 char * cdptr = (char *)client_data;
2344 char string[ 10 ] = "";
2345 Arg al[ 10 ];
2346 int ac, min, max;
2347
2348 ENTRY("r_wtgr_cb_suggest_limits");
2349
2350 if ( ! cdptr )
2351 {
2352 fprintf( stderr,
2353 "Entered r_wtgr_cb_suggest_limits() without a type.\n" );
2354 EXRETURN;
2355 }
2356
2357 min = r_wtgr_calc_min_frm_val( gRA.point_value );
2358 max = r_wtgr_calc_max_frm_val( gRA.point_value );
2359
2360 if ( ! strcmp( cdptr, "white" ) )
2361 {
2362 gRA.wt_range_min = min; /* apply the new values */
2363 gRA.wt_range_max = max;
2364
2365 minw = gRX.wt_range_min_w; /* set the widgets to be updated */
2366 maxw = gRX.wt_range_max_w;
2367 }
2368 else /* then gray */
2369 {
2370 max = min - 1; /* assume the gray starts below white */
2371 min = 0.60 * min;
2372
2373 gRA.gr_range_max = max;
2374 gRA.gr_range_min = min;
2375
2376 minw = gRX.gr_range_min_w;
2377 maxw = gRX.gr_range_max_w;
2378 }
2379
2380 /* set the values into the range widgets */
2381
2382 sprintf( string, "%d", min );
2383
2384 ac = 0;
2385 XtSetArg( al[ ac ], XmNvalue, string ); ac++;
2386 XtSetValues( minw, al, ac );
2387
2388
2389 sprintf( string, "%d", max );
2390
2391 ac = 0;
2392 XtSetArg( al[ ac ], XmNvalue, string ); ac++;
2393 XtSetValues( maxw, al, ac );
2394
2395 EXRETURN;
2396 }
2397
2398
2399 /*----------------------------------------------------------------------
2400 **
2401 ** Create boundary (gray matter) buttons.
2402 **
2403 **----------------------------------------------------------------------
2404 */
2405 static Widget
r_gr_mk_fill_buttons(r_X_s * X,Widget parent)2406 r_gr_mk_fill_buttons( r_X_s * X, Widget parent )
2407 {
2408 int ac;
2409 Arg al[ 10 ];
2410 Widget form, frame, button;
2411 XmString xstr;
2412
2413 ENTRY("r_gr_mk_fill_buttons");
2414
2415 /* create frame to hold form and buttons */
2416 ac = 0;
2417 frame = XmCreateFrame( parent, "frame", al, ac );
2418
2419 /* create form to hold push buttons */
2420 ac = 0;
2421 XtSetArg( al[ac], XmNhorizontalSpacing, R_BUTTON_SPACE ); ac++;
2422 form = XmCreateForm( frame, "form", al, ac );
2423
2424
2425 /* region fill button */
2426 ac = 0;
2427 xstr = XmStringCreateLtoR( "FILL", gRX.charset );
2428 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
2429 button = XmCreatePushButton( form, "fill", al, ac );
2430 XtManageChild( button );
2431 XtAddCallback( button, XmNactivateCallback,
2432 ( XtCallbackProc )r_gr_cb_fill, NULL );
2433 XtSetSensitive( button, True );
2434 XmStringFree( xstr );
2435 MCW_register_hint( button , "fill the gray matter region" );
2436
2437 /* unfill button */
2438 ac = 0;
2439 XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET ); ac++;
2440 XtSetArg( al[ac], XmNleftWidget, button ); ac++;
2441 xstr = XmStringCreateLtoR( "unfill", gRX.charset );
2442 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
2443 button = XmCreatePushButton( form, "unfill", al, ac );
2444 XtManageChild( button );
2445 XtAddCallback( button, XmNactivateCallback,
2446 ( XtCallbackProc )r_any_cb_unfill, &gRA.gr_fill_val );
2447 XtSetSensitive( button, True );
2448 XmStringFree( xstr );
2449 MCW_register_hint( button , "unfill the \"fill value\" region" );
2450
2451
2452 /* suggest range button */
2453 ac = 0;
2454 XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET ); ac++;
2455 XtSetArg( al[ac], XmNleftWidget, button ); ac++;
2456 xstr = XmStringCreateLtoR( "suggest range", gRX.charset );
2457 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
2458 button = XmCreatePushButton( form, "suggest_range", al, ac );
2459 XtManageChild( button );
2460 XtAddCallback( button, XmNactivateCallback,
2461 ( XtCallbackProc )r_wtgr_cb_suggest_limits, "gray" );
2462 XtSetSensitive( button, True );
2463 XmStringFree( xstr );
2464 MCW_register_hint( button , "suggest a range for gray matter values" );
2465
2466
2467 /* stats button */
2468 ac = 0;
2469 XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET ); ac++;
2470 XtSetArg( al[ac], XmNleftWidget, button ); ac++;
2471 xstr = XmStringCreateLtoR( "stats", gRX.charset );
2472 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
2473 button = XmCreatePushButton( form, "stats", al, ac );
2474 XtManageChild( button );
2475 XtAddCallback( button, XmNactivateCallback,
2476 ( XtCallbackProc )r_any_cb_fill_stats, &gRA.gr_fill_val );
2477 XtSetSensitive( button, True );
2478 XmStringFree( xstr );
2479 MCW_register_hint( button , "get stats for this \"fill value\"" );
2480
2481
2482 /* hide window button */
2483 ac = 0;
2484 XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET ); ac++;
2485 XtSetArg( al[ac], XmNleftWidget, button ); ac++;
2486 xstr = XmStringCreateLtoR( "hide", gRX.charset );
2487 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
2488 button = XmCreatePushButton( form, "hide", al, ac );
2489 XtManageChild( button );
2490 XtAddCallback( button, XmNactivateCallback,
2491 ( XtCallbackProc )r_any_cb_hide, "wtgr" );
2492 XtSetSensitive( button, True );
2493 XmStringFree( xstr );
2494 MCW_register_hint( button , "temporarily close this window" );
2495
2496
2497 XtManageChild( form );
2498 XtManageChild( frame );
2499
2500 RETURN( frame );
2501 }
2502
2503
2504 /*----------------------------------------------------------------------
2505 **
2506 ** Create FILL type buttons for the white matter search.
2507 **
2508 **----------------------------------------------------------------------
2509 */
2510 static void
r_wt_mk_fill_buttons(r_X_s * X,Widget parent)2511 r_wt_mk_fill_buttons( r_X_s * X, Widget parent )
2512 {
2513 int ac;
2514 Arg al[ 10 ];
2515 Widget form, frame, button1, button2, button3;
2516 XmString xstr;
2517
2518 ENTRY("r_wt_mk_fill_buttons");
2519
2520 /* create frame to hold form and buttons */
2521 ac = 0;
2522 frame = XmCreateFrame( parent, "frame", al, ac );
2523
2524 /* create form to hold push buttons */
2525 ac = 0;
2526 XtSetArg( al[ac], XmNhorizontalSpacing, R_BUTTON_SPACE ); ac++;
2527 form = XmCreateForm( frame, "form", al, ac );
2528
2529
2530 /* region fill button */
2531 ac = 0;
2532 xstr = XmStringCreateLtoR( "FILL", gRX.charset );
2533 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
2534 button1 = XmCreatePushButton( form, "fill", al, ac );
2535 XtManageChild( button1 );
2536 XtAddCallback( button1, XmNactivateCallback,
2537 ( XtCallbackProc )r_wt_cb_fill, NULL );
2538 XtSetSensitive( button1, True );
2539 XmStringFree( xstr );
2540 MCW_register_hint( button1 , "fill the white matter region" );
2541
2542
2543 /* MORE region fill button */
2544 ac = 0;
2545 XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET ); ac++;
2546 XtSetArg( al[ac], XmNleftWidget, button1 ); ac++;
2547 xstr = XmStringCreateLtoR( "MORE", gRX.charset );
2548 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
2549 button3 = XmCreatePushButton( form, "more", al, ac );
2550 XtManageChild( button3 );
2551 XtAddCallback( button3, XmNactivateCallback,
2552 ( XtCallbackProc )r_wt_cb_fill, "0" );
2553 XtSetSensitive( button3, True );
2554 XmStringFree( xstr );
2555 MCW_register_hint( button3 , "fill more white matter (no unfill)" );
2556
2557
2558 /* unfill button */
2559 ac = 0;
2560 XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET ); ac++;
2561 XtSetArg( al[ac], XmNleftWidget, button3 ); ac++;
2562 xstr = XmStringCreateLtoR( "unfill", gRX.charset );
2563 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
2564 button2 = XmCreatePushButton( form, "unfill", al, ac );
2565 XtManageChild( button2 );
2566 XtAddCallback( button2, XmNactivateCallback,
2567 ( XtCallbackProc )r_any_cb_unfill, &gRA.wt_fill_val );
2568 XtSetSensitive( button2, True );
2569 XmStringFree( xstr );
2570 MCW_register_hint( button2 , "unfill all matter for the \"fill value\"" );
2571
2572
2573 /* suggest range button */
2574 ac = 0;
2575 XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET ); ac++;
2576 XtSetArg( al[ac], XmNleftWidget, button2 ); ac++;
2577 xstr = XmStringCreateLtoR( "suggest range", gRX.charset );
2578 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
2579 button1 = XmCreatePushButton( form, "suggest_range", al, ac );
2580 XtManageChild( button1 );
2581 XtAddCallback( button1, XmNactivateCallback,
2582 ( XtCallbackProc )r_wtgr_cb_suggest_limits, "white" );
2583 XtSetSensitive( button1, True );
2584 XmStringFree( xstr );
2585 MCW_register_hint( button1 , "suggest a white matter range" );
2586
2587
2588 /* stats button */
2589 ac = 0;
2590 XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET ); ac++;
2591 XtSetArg( al[ac], XmNleftWidget, button1 ); ac++;
2592 xstr = XmStringCreateLtoR( "stats", gRX.charset );
2593 XtSetArg( al[ac], XmNlabelString, xstr ); ac++;
2594 button2 = XmCreatePushButton( form, "stats", al, ac );
2595 XtManageChild( button2 );
2596 XtAddCallback( button2, XmNactivateCallback,
2597 ( XtCallbackProc )r_any_cb_fill_stats, &gRA.wt_fill_val );
2598 XtSetSensitive( button2, True );
2599 XmStringFree( xstr );
2600 MCW_register_hint( button2 , "get stats for this \"fill value\"" );
2601
2602
2603 XtManageChild( form );
2604 XtManageChild( frame );
2605
2606 EXRETURN;
2607 }
2608
2609
2610 /*----------------------------------------------------------------------
2611 **
2612 ** Create the diagonal connections frame.
2613 **
2614 ** This will be a radio button widget for the user flag.
2615 **
2616 **----------------------------------------------------------------------
2617 */
2618 static Widget
r_wt_mk_diag_conn_fr(r_X_s * X,Widget parent)2619 r_wt_mk_diag_conn_fr( r_X_s * X, Widget parent )
2620 {
2621 Widget junk, rc, frame;
2622 XmString xstr;
2623 Arg al[ 10 ];
2624 int ac;
2625 char string[ 15 ];
2626
2627 ENTRY("r_wt_mk_diag_conn_fr");
2628
2629 ac = 0;
2630 frame = XmCreateFrame( parent, "frame", al, ac );
2631
2632 ac = 0;
2633 XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT ); ac++;
2634 XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL ); ac++;
2635 rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
2636
2637 ac = 0;
2638 xstr = XmStringCreateLtoR( "connection constraint (0-2) : ", gRX.charset );
2639 XtSetArg( al[ ac ], XmNlabelString, xstr ); ac++;
2640 junk = XmCreateLabel( rc, "label", al, ac );
2641 XtManageChild( junk );
2642 XmStringFree( xstr );
2643
2644
2645 sprintf( string, "%d", gRA.wt_diag_connect );
2646
2647 ac = 0;
2648 XtSetArg( al[ ac ], XmNvalue, string ); ac++;
2649 XtSetArg( al[ ac ], XmNwidth, 80 ); ac++;
2650 X->wt_diag_conn_w = XmCreateText( rc, "text", al, ac );
2651 XtManageChild( X->wt_diag_conn_w );
2652 XtAddCallback( X->wt_diag_conn_w, XmNactivateCallback,
2653 ( XtCallbackProc )r_wt_cb_set_diag_conn, NULL );
2654 XtAddCallback( X->wt_diag_conn_w, XmNlosingFocusCallback,
2655 ( XtCallbackProc )r_wt_cb_set_diag_conn, NULL );
2656
2657
2658 XtManageChild( rc );
2659 XtManageChild( frame );
2660
2661 RETURN( frame );
2662 }
2663
2664 /*----------------------------------------------------------------------
2665 **
2666 ** Create the strong borders frame.
2667 **
2668 ** This will be a radio button widget.
2669 **
2670 **----------------------------------------------------------------------
2671 */
2672 static Widget
r_wt_mk_strong_bord_fr(r_X_s * X,Widget parent)2673 r_wt_mk_strong_bord_fr( r_X_s * X, Widget parent )
2674 {
2675 Widget junk, frame;
2676 XmString xstr;
2677 Arg al[ 10 ];
2678 int ac;
2679 char string[ 15 ];
2680
2681 ENTRY("r_wt_mk_strong_bord_fr");
2682
2683 ac = 0;
2684 frame = XmCreateFrame( parent, "frame", al, ac );
2685
2686 ac = 0;
2687 XtSetArg( al[ ac ], XmNset, True ); ac++;
2688 XtSetArg( al[ ac ], XmNwidth, 1 ); ac++;
2689 XtSetArg( al[ ac ], XmNspacing, 1 ); ac++;
2690 XtSetArg( al[ ac ], XmNmarginLeft, 1 ); ac++;
2691 xstr = XmStringCreateLtoR( "strong borders ", gRX.charset );
2692 XtSetArg( al[ ac ], XmNlabelString, xstr ); ac++;
2693 junk = XmCreateToggleButton( frame, "toggle", al, ac );
2694 XtManageChild( junk );
2695 XtAddCallback( junk, XmNvalueChangedCallback, r_wt_cb_SB_toggle, NULL);
2696 XmStringFree( xstr );
2697
2698 XtManageChild( frame );
2699
2700 RETURN( frame );
2701 }
2702
2703
2704 /*----------------------------------------------------------------------
2705 **
2706 ** Create the min_nbrs (minimum neighbors) frame.
2707 **
2708 **----------------------------------------------------------------------
2709 */
2710 static Widget
r_wt_mk_nbrs_fr(r_X_s * X,Widget parent)2711 r_wt_mk_nbrs_fr( r_X_s * X, Widget parent )
2712 {
2713 Widget junk, rc, frame;
2714 XmString xstr;
2715 Arg al[ 10 ];
2716 int ac;
2717 char string[ 15 ];
2718
2719 ENTRY("r_wt_mk_nbrs_fr");
2720
2721 ac = 0;
2722 frame = XmCreateFrame( parent, "frame", al, ac );
2723
2724 ac = 0;
2725 XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT ); ac++;
2726 XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL ); ac++;
2727 rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
2728
2729 ac = 0;
2730 xstr = XmStringCreateLtoR( "neighbors constraint (0-6) : ", gRX.charset );
2731 XtSetArg( al[ ac ], XmNlabelString, xstr ); ac++;
2732 junk = XmCreateLabel( rc, "label", al, ac );
2733 XtManageChild( junk );
2734 XmStringFree( xstr );
2735
2736
2737 sprintf( string, "%d", gRA.min_nbrs );
2738
2739 ac = 0;
2740 XtSetArg( al[ ac ], XmNvalue, string ); ac++;
2741 XtSetArg( al[ ac ], XmNwidth, 80 ); ac++;
2742 X->wt_min_nbrs_w = XmCreateText( rc, "text", al, ac );
2743 XtManageChild( X->wt_min_nbrs_w );
2744 XtAddCallback( X->wt_min_nbrs_w, XmNactivateCallback,
2745 ( XtCallbackProc )r_wt_cb_set_min_nbrs, NULL );
2746 XtAddCallback( X->wt_min_nbrs_w, XmNlosingFocusCallback,
2747 ( XtCallbackProc )r_wt_cb_set_min_nbrs, NULL );
2748
2749
2750 XtManageChild( rc );
2751 XtManageChild( frame );
2752
2753 RETURN( frame );
2754 }
2755
2756
2757 /*----------------------------------------------------------------------
2758 **
2759 ** Create the frame to handle max distance in the gray search.
2760 **
2761 **----------------------------------------------------------------------
2762 */
2763 static Widget
r_gr_mk_max_dist_w(r_X_s * X,Widget parent)2764 r_gr_mk_max_dist_w( r_X_s * X, Widget parent )
2765 {
2766 Widget junk, rc, frame;
2767 XmString xstr;
2768 Arg al[ 10 ];
2769 int ac;
2770 char string[ 15 ];
2771
2772 ENTRY("r_gr_mk_max_dist_w");
2773
2774 ac = 0;
2775 frame = XmCreateFrame( parent, "frame", al, ac );
2776
2777 ac = 0;
2778 XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT ); ac++;
2779 XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL ); ac++;
2780 rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
2781
2782 ac = 0;
2783 xstr = XmStringCreateLtoR( "max distance : ", gRX.charset );
2784 XtSetArg( al[ ac ], XmNlabelString, xstr ); ac++;
2785 junk = XmCreateLabel( rc, "label", al, ac );
2786 XtManageChild( junk );
2787 XmStringFree( xstr );
2788
2789
2790 sprintf( string, "%d", gRA.gr_max_dist );
2791
2792 ac = 0;
2793 XtSetArg( al[ ac ], XmNvalue, string ); ac++;
2794 XtSetArg( al[ ac ], XmNwidth, 80 ); ac++;
2795 junk = XmCreateText( rc, "text", al, ac );
2796 XtManageChild( junk );
2797 XtAddCallback( junk, XmNactivateCallback,
2798 ( XtCallbackProc )r_gr_cb_set_max_dist, NULL );
2799 XtAddCallback( junk, XmNlosingFocusCallback,
2800 ( XtCallbackProc )r_gr_cb_set_max_dist, NULL );
2801
2802
2803 XtManageChild( rc );
2804 XtManageChild( frame );
2805
2806 RETURN( frame );
2807 }
2808
2809
2810 /*----------------------------------------------------------------------
2811 **
2812 ** Create the "fill value" widgets.
2813 **
2814 **----------------------------------------------------------------------
2815 */
2816 static Widget
r_wt_mk_fillval_fr(r_X_s * X,Widget parent)2817 r_wt_mk_fillval_fr( r_X_s * X, Widget parent )
2818 {
2819 Widget junk, rc, frame;
2820 XmString xstr;
2821 Arg al[ 10 ];
2822 int ac;
2823 char string[ 15 ];
2824
2825
2826 ac = 0;
2827 frame = XmCreateFrame( parent, "frame", al, ac );
2828
2829 ac = 0;
2830 XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT ); ac++;
2831 XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL ); ac++;
2832 rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
2833
2834 ac = 0;
2835 xstr = XmStringCreateLtoR( "fill value : ", gRX.charset );
2836 XtSetArg( al[ ac ], XmNlabelString, xstr ); ac++;
2837 junk = XmCreateLabel( rc, "label", al, ac );
2838 XtManageChild( junk );
2839 XmStringFree( xstr );
2840
2841
2842 sprintf( string, "%d", gRA.wt_fill_val );
2843
2844 ac = 0;
2845 XtSetArg( al[ ac ], XmNvalue, string ); ac++;
2846 XtSetArg( al[ ac ], XmNwidth, 80 ); ac++;
2847 X->wt_fill_val_w = XmCreateText( rc, "text", al, ac );
2848 XtManageChild( X->wt_fill_val_w );
2849 XtAddCallback( X->wt_fill_val_w, XmNactivateCallback,
2850 ( XtCallbackProc )r_wt_cb_set_fill_val, NULL );
2851 XtAddCallback( X->wt_fill_val_w, XmNlosingFocusCallback,
2852 ( XtCallbackProc )r_wt_cb_set_fill_val, NULL );
2853
2854
2855 XtManageChild( rc );
2856 XtManageChild( frame );
2857
2858 return( frame );
2859 }
2860
2861
2862 /*----------------------------------------------------------------------
2863 **
2864 ** Create the "fill value" widget for the gray matter search.
2865 **
2866 **----------------------------------------------------------------------
2867 */
2868 static Widget
r_gr_mk_fillval_fr(r_X_s * X,Widget parent)2869 r_gr_mk_fillval_fr( r_X_s * X, Widget parent )
2870 {
2871 Widget junk, rc, frame;
2872 XmString xstr;
2873 Arg al[ 10 ];
2874 int ac;
2875 char string[ 15 ];
2876
2877
2878 ac = 0;
2879 frame = XmCreateFrame( parent, "frame", al, ac );
2880
2881 ac = 0;
2882 XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT ); ac++;
2883 XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL ); ac++;
2884 rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
2885
2886 ac = 0;
2887 xstr = XmStringCreateLtoR( "fill value : ", gRX.charset );
2888 XtSetArg( al[ ac ], XmNlabelString, xstr ); ac++;
2889 junk = XmCreateLabel( rc, "label", al, ac );
2890 XtManageChild( junk );
2891 XmStringFree( xstr );
2892
2893
2894 sprintf( string, "%d", gRA.gr_fill_val );
2895
2896 ac = 0;
2897 XtSetArg( al[ ac ], XmNvalue, string ); ac++;
2898 XtSetArg( al[ ac ], XmNwidth, 80 ); ac++;
2899 X->gr_fill_val_w = XmCreateText( rc, "text", al, ac );
2900 XtManageChild( X->gr_fill_val_w );
2901 XtAddCallback( X->gr_fill_val_w, XmNactivateCallback,
2902 ( XtCallbackProc )r_gr_set_fill_val, NULL );
2903 XtAddCallback( X->gr_fill_val_w, XmNlosingFocusCallback,
2904 ( XtCallbackProc )r_gr_set_fill_val, NULL );
2905
2906
2907 XtManageChild( rc );
2908 XtManageChild( frame );
2909
2910 return( frame );
2911 }
2912
2913
2914 /*----------------------------------------------------------------------
2915 **
2916 ** Create the gray matter range frame.
2917 **
2918 **----------------------------------------------------------------------
2919 */
2920 static Widget
r_gr_mk_range_fr(r_X_s * X,Widget parent)2921 r_gr_mk_range_fr( r_X_s * X, Widget parent )
2922 {
2923 Widget junk, rc, frame;
2924 XmString xstr;
2925 Arg al[ 10 ];
2926 int ac;
2927 char string[ 15 ];
2928
2929
2930 ac = 0;
2931 frame = XmCreateFrame( parent, "frame", al, ac );
2932
2933 ac = 0; /* to hold labels and text */
2934 XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT ); ac++;
2935 XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL ); ac++;
2936 rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
2937
2938 ac = 0;
2939 xstr = XmStringCreateLtoR( "search range : ", gRX.charset );
2940 XtSetArg( al[ ac ], XmNlabelString, xstr ); ac++;
2941 junk = XmCreateLabel( rc, "label", al, ac );
2942 XtManageChild( junk );
2943 XmStringFree( xstr );
2944
2945
2946 sprintf( string, "%d", gRA.gr_range_min ); /* init value */
2947
2948 ac = 0;
2949 XtSetArg( al[ ac ], XmNvalue, string ); ac++;
2950 XtSetArg( al[ ac ], XmNwidth, 80 ); ac++;
2951 X->gr_range_min_w = XmCreateText( rc, "text", al, ac );
2952 XtManageChild( X->gr_range_min_w );
2953 XtAddCallback( X->gr_range_min_w, XmNactivateCallback,
2954 ( XtCallbackProc )r_gr_cb_set_range, "from" );
2955 XtAddCallback( X->gr_range_min_w, XmNlosingFocusCallback,
2956 ( XtCallbackProc )r_gr_cb_set_range, "from" );
2957
2958 ac = 0;
2959 xstr = XmStringCreateLtoR( " to ", gRX.charset );
2960 XtSetArg( al[ ac ], XmNlabelString, xstr ); ac++;
2961 junk = XmCreateLabel( rc, "label", al, ac );
2962 XtManageChild( junk );
2963 XmStringFree( xstr );
2964
2965
2966 sprintf( string, "%d", gRA.gr_range_max );
2967
2968 ac = 0;
2969 XtSetArg( al[ ac ], XmNvalue, string ); ac++;
2970 XtSetArg( al[ ac ], XmNwidth, 80 ); ac++;
2971 X->gr_range_max_w = XmCreateText( rc, "text", al, ac );
2972 XtManageChild( X->gr_range_max_w );
2973 XtAddCallback( X->gr_range_max_w, XmNactivateCallback,
2974 ( XtCallbackProc )r_gr_cb_set_range, "to" );
2975 XtAddCallback( X->gr_range_max_w, XmNlosingFocusCallback,
2976 ( XtCallbackProc )r_gr_cb_set_range, "to" );
2977
2978 XtManageChild( rc );
2979 XtManageChild( frame );
2980
2981 return( frame );
2982 }
2983
2984
2985 /*----------------------------------------------------------------------
2986 **
2987 ** Create the range widgets.
2988 **
2989 **----------------------------------------------------------------------
2990 */
2991 static Widget
r_wt_mk_range_fr(r_X_s * X,Widget parent)2992 r_wt_mk_range_fr( r_X_s * X, Widget parent )
2993 {
2994 Widget junk, rc, frame;
2995 XmString xstr;
2996 Arg al[ 10 ];
2997 int ac;
2998 char string[ 15 ];
2999
3000
3001 ac = 0;
3002 frame = XmCreateFrame( parent, "frame", al, ac );
3003
3004 ac = 0; /* to hold labels and text */
3005 XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT ); ac++;
3006 XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL ); ac++;
3007 rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
3008
3009 ac = 0;
3010 xstr = XmStringCreateLtoR( "search range : ", gRX.charset );
3011 XtSetArg( al[ ac ], XmNlabelString, xstr ); ac++;
3012 junk = XmCreateLabel( rc, "label", al, ac );
3013 XtManageChild( junk );
3014 XmStringFree( xstr );
3015
3016
3017 sprintf( string, "%d", gRA.wt_range_min ); /* init value */
3018
3019 ac = 0;
3020 XtSetArg( al[ ac ], XmNvalue, string ); ac++;
3021 XtSetArg( al[ ac ], XmNwidth, 80 ); ac++;
3022 X->wt_range_min_w = XmCreateText( rc, "text", al, ac );
3023 XtManageChild( X->wt_range_min_w );
3024 XtAddCallback( X->wt_range_min_w, XmNactivateCallback,
3025 ( XtCallbackProc )r_wt_cb_set_range, "from" );
3026 XtAddCallback( X->wt_range_min_w, XmNlosingFocusCallback,
3027 ( XtCallbackProc )r_wt_cb_set_range, "from" );
3028
3029 ac = 0;
3030 xstr = XmStringCreateLtoR( " to ", gRX.charset );
3031 XtSetArg( al[ ac ], XmNlabelString, xstr ); ac++;
3032 junk = XmCreateLabel( rc, "label", al, ac );
3033 XtManageChild( junk );
3034 XmStringFree( xstr );
3035
3036
3037 sprintf( string, "%d", gRA.wt_range_max );
3038
3039 ac = 0;
3040 XtSetArg( al[ ac ], XmNvalue, string ); ac++;
3041 XtSetArg( al[ ac ], XmNwidth, 80 ); ac++;
3042 X->wt_range_max_w = XmCreateText( rc, "text", al, ac );
3043 XtManageChild( X->wt_range_max_w );
3044 XtAddCallback( X->wt_range_max_w, XmNactivateCallback,
3045 ( XtCallbackProc )r_wt_cb_set_range, "to" );
3046 XtAddCallback( X->wt_range_max_w, XmNlosingFocusCallback,
3047 ( XtCallbackProc )r_wt_cb_set_range, "to" );
3048
3049 XtManageChild( rc );
3050 XtManageChild( frame );
3051
3052 return( frame );
3053 }
3054
3055
3056 /*----------------------------------------------------------------------
3057 **
3058 ** Clear the filled region for the white matter search.
3059 **
3060 **----------------------------------------------------------------------
3061 */
3062 static void
r_any_cb_unfill(Widget w,XtPointer client_data,XtPointer call_data)3063 r_any_cb_unfill(
3064 Widget w,
3065 XtPointer client_data,
3066 XtPointer call_data
3067 )
3068 {
3069 short * fptr, * uptr;
3070 int count;
3071 int unfill_val = *((int *)client_data);
3072
3073 ENTRY("r_any_cb_unfill");
3074
3075 if ( ! gRA.fdata )
3076 EXRETURN;
3077
3078 /* first store to undo_data */
3079 fptr = gRA.fdata; uptr = gRA.undo_data;
3080 for ( count = 0; count < gRA.nvox; count++ )
3081 *uptr++ = *fptr++;
3082
3083 for ( count = 0, fptr = gRA.fdata; count < gRA.nvox; count++, fptr++ )
3084 if ( *fptr == unfill_val )
3085 *fptr = 0;
3086
3087 THD_load_statistics( gRA.func ) ;
3088 PLUTO_dset_redisplay( gRA.func ) ;
3089
3090 EXRETURN;
3091 }
3092
3093
3094 /*----------------------------------------------------------------------
3095 **
3096 ** Make the check to see if a user boundary neighbor exists.
3097 **
3098 ** Okay neighbors values are zero and testval.
3099 **
3100 **----------------------------------------------------------------------
3101 */
3102 static int
r_wt_bad_ngbr_exists(r_alg_s * A,int current,int testval)3103 r_wt_bad_ngbr_exists( r_alg_s * A, int current, int testval )
3104 {
3105 int last;
3106 int nx, nxy;
3107 short val;
3108 short * data;
3109
3110 ENTRY("r_wt_bad_ngbr_exists");
3111
3112 data = A->fdata + current;
3113 nx = A->nx;
3114 nxy = A->nxy;
3115 last = A->nvox - nxy;
3116
3117 if ( ( current < nxy ) || ( current >= last ) )
3118 RETURN(1);
3119
3120 val = data[ -1 ];
3121 if ( val && ( val != testval ) && ( val != R_BOUND_VAL ) )
3122 RETURN(1);
3123
3124 val = data[ 1 ];
3125 if ( val && ( val != testval ) && ( val != R_BOUND_VAL ) )
3126 RETURN(1);
3127
3128 val = data[ -nx ];
3129 if ( val && ( val != testval ) && ( val != R_BOUND_VAL ) )
3130 RETURN(1);
3131
3132 val = data[ nx ];
3133 if ( val && ( val != testval ) && ( val != R_BOUND_VAL ) )
3134 RETURN(1);
3135
3136 val = data[ -nxy ];
3137 if ( val && ( val != testval ) && ( val != R_BOUND_VAL ) )
3138 RETURN(1);
3139
3140 val = data[ nxy ];
3141 if ( val && ( val != testval ) && ( val != R_BOUND_VAL ) )
3142 RETURN(1);
3143
3144 RETURN(0);
3145 }
3146
3147
3148 /*----------------------------------------------------------------------
3149 **
3150 ** Make the check for adding a point to the border.
3151 **
3152 **----------------------------------------------------------------------
3153 */
3154 static int
r_wt_check_insert(r_alg_s * A,int current)3155 r_wt_check_insert( r_alg_s * A, int current )
3156 {
3157 short * aptr = A->adata;
3158 short * fptr = A->fdata;
3159 short * nptr = A->neighbors;
3160 short * fvp = fptr + current; /* pointer to function value */
3161
3162 int value, added = 0;
3163
3164 ENTRY("r_wt_check_insert");
3165
3166 value = aptr[ current ];
3167
3168 /* if new and in range, we will set as a result voxel */
3169 if ( *fvp == 0 )
3170 {
3171 if ( ( value >= A->wt_range_min ) &&
3172 ( value <= A->wt_range_max ) )
3173 {
3174 /* if it also has enough neighbors */
3175 if ( nptr[ current ] >= A->min_nbrs )
3176 {
3177 /* also check for neighbor in the user's boundary */
3178 if ( ( ! A->strong_borders ) ||
3179 ! r_wt_bad_ngbr_exists( A, current, A->wt_fill_val ) )
3180 {
3181 if ( ! r_add_to_boundary( &A->Bnew, current ) )
3182 RETURN(-1);
3183 else
3184 added = 1;
3185 }
3186 }
3187
3188 /* either way, set point as wt_fill_val */
3189 *fvp = A->wt_fill_val;
3190 }
3191 else /* add to the 3d boundary */
3192 {
3193 *fvp = R_BOUND_VAL; /* mark as in boundary, clear later */
3194
3195 if ( ! r_add_to_boundary( &A->border, current ) )
3196 RETURN(-1);
3197 }
3198 }
3199
3200 RETURN(added);
3201 }
3202
3203
3204 /*----------------------------------------------------------------------
3205 **
3206 ** Callback to fill the local region for a mask.
3207 **
3208 **----------------------------------------------------------------------
3209 */
3210 static void
r_wt_cb_fill(Widget w,XtPointer client_data,XtPointer call_data)3211 r_wt_cb_fill(
3212 Widget w,
3213 XtPointer client_data,
3214 XtPointer call_data
3215 )
3216 {
3217 short * nptr, * fnptr, * flptr, * aptr, * uptr;
3218 int count, value, current;
3219 int nxy = gRA.nxy, nx = gRA.nx;
3220 char * cp = (char *)client_data;
3221 points_t B;
3222
3223 ENTRY("r_wt_cb_fill");
3224
3225 /* check that we are ready to fill anything */
3226 if ( ( gRA.point_coord == -1 ) || ( ! gRA.fdata ) )
3227 {
3228 fputc( 7, stderr ); /* hard-code a beep */
3229 EXRETURN;
3230 }
3231
3232 if ( !gRA.Bold.points || !gRA.Bnew.points ||
3233 !gRA.neighbors || !gRA.undo_data)
3234 {
3235 fprintf( stderr, "Error: rcfr10\n"
3236 "Memory failure, addresses are %p, %p, %p and %p.\n",
3237 gRA.Bold.points, gRA.Bnew.points,
3238 gRA.neighbors, gRA.undo_data );
3239 EXRETURN;
3240 }
3241
3242 /* first store to undo_data */
3243 fnptr = gRA.fdata; uptr = gRA.undo_data;
3244 for ( count = 0; count < gRA.nvox; count++ )
3245 *uptr++ = *fnptr++;
3246
3247 /* give the user an idea of what is happening */
3248 rWARNING( "filling white matter" );
3249
3250 if ( ( cp == NULL ) || ( *cp != '0' ) )
3251 {
3252 for ( count = 0, fnptr = gRA.fdata; count < gRA.nvox; count++, fnptr++ ) if ( *fnptr == gRA.wt_fill_val )
3253 *fnptr = 0;
3254 }
3255
3256 r_wt_set_neighbors( &gRA );
3257
3258 /* set borders to nothing */
3259 gRA.Bold.used = 0;
3260 gRA.Bnew.used = 0;
3261 gRA.border.used = 0;
3262
3263 if ( r_wt_check_insert( &gRA, gRA.point_coord ) != 1 )
3264 EXRETURN;
3265
3266 while ( gRA.Bnew.used > 0 ) /* while boundary exists */
3267 {
3268 B = gRA.Bold; /* swap memory and reset Bnew.used to zero */
3269 gRA.Bold = gRA.Bnew; /* - this simply preserves the memory */
3270 gRA.Bnew = B;
3271 gRA.Bnew.used = 0;
3272 fputs( ".", stderr );
3273
3274 for ( count = 0; count < gRA.Bold.used; count++ )
3275 {
3276 current = gRA.Bold.points[count];
3277
3278 /* 6 'face sharing' points */
3279 r_wt_check_insert( &gRA, current - 1 );
3280 r_wt_check_insert( &gRA, current + 1 );
3281 r_wt_check_insert( &gRA, current - nx );
3282 r_wt_check_insert( &gRA, current + nx );
3283 r_wt_check_insert( &gRA, current - nxy );
3284 r_wt_check_insert( &gRA, current + nxy );
3285
3286 /* 12 'edge sharing' points */
3287 if ( gRA.wt_diag_connect < 2 )
3288 {
3289 r_wt_check_insert( &gRA, current + nx - 1 );
3290 r_wt_check_insert( &gRA, current + nx + 1 );
3291 r_wt_check_insert( &gRA, current - nx - 1 );
3292 r_wt_check_insert( &gRA, current - nx + 1 );
3293 r_wt_check_insert( &gRA, current + nxy - 1 );
3294 r_wt_check_insert( &gRA, current + nxy + 1 );
3295 r_wt_check_insert( &gRA, current - nxy - 1 );
3296 r_wt_check_insert( &gRA, current - nxy + 1 );
3297 r_wt_check_insert( &gRA, current + nxy - nx );
3298 r_wt_check_insert( &gRA, current + nxy + nx );
3299 r_wt_check_insert( &gRA, current - nxy - nx );
3300 r_wt_check_insert( &gRA, current - nxy + nx );
3301
3302 /* 8 'corner sharing' points */
3303 if ( gRA.wt_diag_connect == 0 )
3304 {
3305 r_wt_check_insert( &gRA, current - nxy - nx - 1 );
3306 r_wt_check_insert( &gRA, current - nxy - nx + 1 );
3307 r_wt_check_insert( &gRA, current - nxy + nx - 1 );
3308 r_wt_check_insert( &gRA, current - nxy + nx + 1 );
3309 r_wt_check_insert( &gRA, current + nxy - nx - 1 );
3310 r_wt_check_insert( &gRA, current + nxy - nx + 1 );
3311 r_wt_check_insert( &gRA, current + nxy + nx - 1 );
3312 r_wt_check_insert( &gRA, current + nxy + nx + 1 );
3313 }
3314 }
3315 }
3316 }
3317
3318 /* clear bound markings */
3319 for( count = 0, fnptr = gRA.fdata; count < gRA.nvox; count++, fnptr++ )
3320 if ( *fnptr == R_BOUND_VAL )
3321 *fnptr = 0;
3322
3323 /* recompute statistics, if the loaded value is big or small */
3324
3325 THD_load_statistics( gRA.func ) ;
3326
3327 /* now redisplay dataset, in case anyone is looking at it */
3328
3329 PLUTO_dset_redisplay( gRA.func ) ;
3330 dset_changed = 1;
3331
3332 fputs( "done\n\n", stderr );
3333 EXRETURN;
3334 }
3335
3336
3337 /*----------------------------------------------------------------------
3338 **
3339 ** Callback to fill the gray matter (or so we somewhat suppose).
3340 **
3341 **----------------------------------------------------------------------
3342 */
3343 static void
r_gr_cb_fill(Widget w,XtPointer client_data,XtPointer call_data)3344 r_gr_cb_fill(
3345 Widget w,
3346 XtPointer client_data,
3347 XtPointer call_data
3348 )
3349 {
3350 points_t B;
3351 short * fnptr, * uptr;
3352 int * iptr;
3353 int count, dist, added, current;
3354 int nx, nxy;
3355
3356 ENTRY("r_gr_cb_fill");
3357
3358 nx = gRA.nx;
3359 nxy = gRA.nxy;
3360
3361
3362 if ( ( gRA.point_coord == -1 ) || ( ! gRA.fdata ) )
3363 {
3364 fputc( 7, stderr ); /* hard-code a beep */
3365 EXRETURN;
3366 }
3367
3368 if ( gRA.gr_max_dist <= 0 )
3369 EXRETURN;
3370
3371 if ( !gRA.Bold.points || !gRA.Bnew.points ||
3372 !gRA.neighbors || !gRA.undo_data) {
3373 fprintf( stderr, "Error: rcfg10\n"
3374 "Memory failure, addresses are %p, %p, %p and %p.\n",
3375 gRA.Bold.points, gRA.Bnew.points,
3376 gRA.neighbors, gRA.undo_data );
3377 EXRETURN;
3378 }
3379
3380 /* give the user an idea of what is happening */
3381 rWARNING( "filling gray matter" );
3382
3383
3384 /* first store to undo_data */
3385 fnptr = gRA.fdata; uptr = gRA.undo_data;
3386 for ( count = 0; count < gRA.nvox; count++ )
3387 *uptr++ = *fnptr++;
3388
3389 /* clear old memory */
3390 for ( count = 0, fnptr = gRA.fdata; count < gRA.nvox; count++, fnptr++ )
3391 if ( *fnptr == gRA.gr_fill_val )
3392 *fnptr = 0;
3393
3394 /* set old and new borders to nothing */
3395 gRA.Bold.used = 0;
3396 gRA.Bnew.used = 0;
3397
3398 gRH.gr_edge.used = 0; /* trash the old gray edge */
3399
3400 iptr = gRA.border.points;
3401 for ( count = 0; count < gRA.border.used; count++ )
3402 {
3403 if ( ( added = r_gr_check_insert( &gRA, &gRA.Bold, *iptr ) ) == -1 )
3404 EXRETURN;
3405 iptr++;
3406 }
3407
3408
3409 dist = 1;
3410 fputc( '.', stdout );
3411 while ( ( gRA.Bold.used > 0 ) && ( dist < gRA.gr_max_dist ) )
3412 {
3413 iptr = gRA.Bold.points;
3414 for ( count = 0; count < gRA.Bold.used; count++ )
3415 {
3416 current = *iptr;
3417
3418 ( void )r_gr_check_insert( &gRA, &gRA.Bnew, current - 1 );
3419 ( void )r_gr_check_insert( &gRA, &gRA.Bnew, current + 1 );
3420 ( void )r_gr_check_insert( &gRA, &gRA.Bnew, current - nx );
3421 ( void )r_gr_check_insert( &gRA, &gRA.Bnew, current + nx );
3422 ( void )r_gr_check_insert( &gRA, &gRA.Bnew, current - nxy );
3423 ( void )r_gr_check_insert( &gRA, &gRA.Bnew, current + nxy );
3424
3425 iptr++;
3426 }
3427
3428 B = gRA.Bold;
3429 gRA.Bold = gRA.Bnew;
3430 gRA.Bnew = B;
3431 gRA.Bnew.used = 0;
3432
3433 dist++;
3434 fputc( '.', stdout );
3435 }
3436
3437 /* clear bound markings */
3438 for( count = 0, fnptr = gRA.fdata; count < gRA.nvox; count++, fnptr++ )
3439 if ( *fnptr == R_BOUND_VAL )
3440 *fnptr = 0;
3441
3442 fputs( "done\n\n", stdout );
3443
3444 /* recompute statistics, if the loaded value is big or small */
3445
3446 THD_load_statistics( gRA.func ) ;
3447
3448 /* now redisplay dataset, in case anyone is looking at it */
3449
3450 PLUTO_dset_redisplay( gRA.func ) ;
3451 dset_changed = 1;
3452 EXRETURN;
3453 }
3454
3455
3456 /*----------------------------------------------------------------------
3457 **
3458 ** Make the check for adding a point to the border.
3459 **
3460 **----------------------------------------------------------------------
3461 */
3462 static int
r_gr_check_insert(r_alg_s * A,points_t * B,int current)3463 r_gr_check_insert( r_alg_s * A, points_t * B, int current )
3464 {
3465 short * aptr = A->adata;
3466 short * fptr = A->fdata;
3467 short * nptr = A->neighbors;
3468 short * fvalp;
3469 int value, added = 0;
3470
3471 ENTRY("r_gr_check_insert");
3472
3473 if ( nptr[ current ] == -1 ) /* do not accept edge points */
3474 RETURN(0);
3475
3476 fvalp = fptr + current;
3477 value = aptr[ current ];
3478
3479 /* if new and in range, we will consider setting it as a result */
3480 if ( *fvalp == 0 )
3481 {
3482 if ( ( value >= A->gr_range_min ) &&
3483 ( value <= A->gr_range_max ) )
3484 {
3485 if ( ! r_add_to_boundary( B, current ) )
3486 RETURN(-1);
3487
3488 *fvalp = A->gr_fill_val;
3489
3490 added = 1;
3491 }
3492 else /* mark as in boundary, add to HOLE's search set */
3493 {
3494 *fvalp = R_BOUND_VAL;
3495 if ( ! r_add_to_boundary( &gRH.gr_edge, current ) )
3496 RETURN(-1);
3497 }
3498 }
3499
3500 RETURN(added);
3501 }
3502
3503
3504 /*----------------------------------------------------------------------
3505 **
3506 ** Add a point to the boundary.
3507 **
3508 **----------------------------------------------------------------------
3509 */
3510 static int
r_add_to_boundary(points_t * B,int index)3511 r_add_to_boundary( points_t * B, int index )
3512 {
3513 ENTRY("r_add_to_boundary");
3514
3515 if ( !B )
3516 {
3517 fprintf( stderr, "Error: atb10\n"
3518 "Unexpected error - missing memory for bound structure!\n" );
3519 RETURN(0);
3520 }
3521 else if ( ! B->points ) /* we need initial memory */
3522 {
3523 B->used = 0;
3524 B->M = 50;
3525 B->points = (int *)malloc( B->M * sizeof( int ) );
3526
3527 if ( B->points == NULL )
3528 {
3529 fprintf( stderr, "Error: atb15\n"
3530 "Failed to allocate %d ints for boundary.\n", B->M );
3531 RETURN(0);
3532 }
3533 }
3534 else if ( B->used == B->M ) /* then we need more memory */
3535 {
3536 B->M *= 2;
3537 B->points = (int *)realloc( B->points, B->M * sizeof( int ) );
3538
3539 if ( B->points == NULL )
3540 {
3541 fprintf( stderr, "Error: atb20\n"
3542 "Failed to reallocate %d ints for boundary.\n", B->M );
3543 RETURN(0);
3544 }
3545 }
3546
3547 B->points[B->used] = index;
3548 B->used++;
3549
3550 RETURN(1);
3551 }
3552
3553
3554 /*----------------------------------------------------------------------
3555 **
3556 ** Fill the neighbors-in-range array.
3557 **
3558 ** init values to zero
3559 ** for each inner value
3560 ** count the number of neighbors (max of 6 - no diagonals) in range
3561 ** ( skip all edges )
3562 **
3563 **----------------------------------------------------------------------
3564 */
3565 static void
r_wt_set_neighbors(r_alg_s * A)3566 r_wt_set_neighbors( r_alg_s * A )
3567 {
3568 short * aptr = A->adata;
3569 short * nptr = A->neighbors;
3570 int cx, cy, cz;
3571 int nxy = A->nxy, nx = A->nx;
3572
3573 ENTRY("r_wt_set_neighbors");
3574
3575
3576 for ( cz = 0; cz < A->nz; cz++ )
3577 for ( cy = 0; cy < A->ny; cy++ )
3578 for ( cx = 0; cx < A->nx; cx++ )
3579 {
3580 *nptr = 0;
3581
3582 if ( ( cx == 0 ) || ( cx == A->nx - 1 ) ||
3583 ( cy == 0 ) || ( cy == A->ny - 1 ) ||
3584 ( cz == 0 ) || ( cz == A->nz - 1 )
3585 )
3586 {
3587 aptr++;
3588 *nptr++ = -1; /* no future consideration */
3589 continue;
3590 }
3591 else if ( *aptr > A->wt_range_max || *aptr < A->wt_range_min )
3592 {
3593 aptr++;
3594 nptr++;
3595 continue;
3596 }
3597
3598 if ( ( *(aptr-1) <= A->wt_range_max ) &&
3599 ( *(aptr-1) >= A->wt_range_min ) )
3600 (*nptr)++;
3601
3602 if ( ( *(aptr+1) <= A->wt_range_max ) &&
3603 ( *(aptr+1) >= A->wt_range_min ) )
3604 (*nptr)++;
3605
3606 if ( ( *(aptr-nx) <= A->wt_range_max ) &&
3607 ( *(aptr-nx) >= A->wt_range_min ) )
3608 (*nptr)++;
3609
3610 if ( ( *(aptr+nx) <= A->wt_range_max ) &&
3611 ( *(aptr+nx) >= A->wt_range_min ) )
3612 (*nptr)++;
3613
3614 if ( ( *(aptr-nxy) <= A->wt_range_max ) &&
3615 ( *(aptr-nxy) >= A->wt_range_min) )
3616 (*nptr)++;
3617
3618 if ( ( *(aptr+nxy) <= A->wt_range_max ) &&
3619 ( *(aptr+nxy) >= A->wt_range_min) )
3620 (*nptr)++;
3621
3622 aptr++;
3623 nptr++;
3624 }
3625
3626 EXRETURN;
3627 }
3628
3629
3630 /*----------------------------------------------------------------------
3631 **
3632 ** Callback to set the minimum neighbors in search (1 to 6).
3633 **
3634 **----------------------------------------------------------------------
3635 */
3636 static void
r_wt_cb_set_diag_conn(Widget w,XtPointer client_data,XtPointer call_data)3637 r_wt_cb_set_diag_conn(
3638 Widget w,
3639 XtPointer client_data,
3640 XtPointer call_data
3641 )
3642 {
3643 char * text;
3644 int ival;
3645
3646 ENTRY("r_wt_cb_set_diag_conn");
3647
3648 text = XmTextGetString( w );
3649
3650 if ( ! text || ! *text ) /* nothing typed */
3651 {
3652 if ( text )
3653 XtFree( text );
3654 EXRETURN;
3655 }
3656
3657 /*
3658 ** Make sure a value has changed (to something acceptable)
3659 ** before applying.
3660 */
3661
3662 ival = atoi( text );
3663 if ( ( ival < 0 ) || ( ival > 2 ) )
3664 {
3665 sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 0, 2 );
3666 rERROR( gRmessage );
3667 EXRETURN;
3668 }
3669
3670 if ( gRA.wt_diag_connect != ival )
3671 gRA.wt_diag_connect = ival;
3672
3673 XtFree( text );
3674 EXRETURN;
3675 }
3676
3677
3678 /*----------------------------------------------------------------------
3679 **
3680 ** Callback to set the minimum neighbors in search (1 to 6).
3681 **
3682 **----------------------------------------------------------------------
3683 */
3684 static void
r_wt_cb_set_min_nbrs(Widget w,XtPointer client_data,XtPointer call_data)3685 r_wt_cb_set_min_nbrs(
3686 Widget w,
3687 XtPointer client_data,
3688 XtPointer call_data
3689 )
3690 {
3691 char * text;
3692 int ival;
3693
3694 text = XmTextGetString( w );
3695
3696 if ( ! text || ! *text ) /* nothing typed */
3697 {
3698 if ( text )
3699 XtFree( text );
3700 return;
3701 }
3702
3703 /*
3704 ** Make sure a value has changed (to something acceptable)
3705 ** before applying.
3706 */
3707
3708 ival = atoi( text );
3709 if ( ( ival < 0 ) || ( ival > 6 ) )
3710 {
3711 sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 0, 6 );
3712 rERROR( gRmessage );
3713 return;
3714 }
3715
3716 if ( gRA.min_nbrs != ival )
3717 gRA.min_nbrs = ival;
3718
3719
3720 XtFree( text );
3721 }
3722
3723
3724 /*----------------------------------------------------------------------
3725 **
3726 ** Callback to set the maximum distance in gray search.
3727 **
3728 **----------------------------------------------------------------------
3729 */
3730 static void
r_gr_cb_set_max_dist(Widget w,XtPointer client_data,XtPointer call_data)3731 r_gr_cb_set_max_dist(
3732 Widget w,
3733 XtPointer client_data,
3734 XtPointer call_data
3735 )
3736 {
3737 char * text;
3738 int ival;
3739
3740 text = XmTextGetString( w );
3741
3742 if ( ! text || ! *text ) /* nothing typed */
3743 {
3744 if ( text )
3745 XtFree( text );
3746 return;
3747 }
3748
3749 /*
3750 ** Make sure a value has changed (to something acceptable)
3751 ** before applying.
3752 */
3753
3754 ival = atoi( text );
3755 if ( ( ival < 1 ) || ( ival > 200 ) )
3756 {
3757 sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 1, 200 );
3758 rERROR( gRmessage );
3759 return;
3760 }
3761
3762 if ( gRA.gr_max_dist != ival )
3763 gRA.gr_max_dist = ival;
3764
3765
3766 XtFree( text );
3767 }
3768
3769
3770 /*----------------------------------------------------------------------
3771 **
3772 ** Callback to set the maximum fill size for the holes app.
3773 **
3774 **----------------------------------------------------------------------
3775 */
3776 static void
r_HL_cb_set_maxsize(Widget w,XtPointer client_data,XtPointer call_data)3777 r_HL_cb_set_maxsize(
3778 Widget w,
3779 XtPointer client_data,
3780 XtPointer call_data
3781 )
3782 {
3783 char * text;
3784 int ival;
3785
3786 text = XmTextGetString( w );
3787
3788 if ( ! text || ! *text ) /* nothing typed */
3789 {
3790 if ( text )
3791 XtFree( text );
3792 return;
3793 }
3794
3795 /*
3796 ** Make sure a value has changed (to something acceptable)
3797 ** before applying.
3798 */
3799
3800 ival = atoi( text );
3801 if ( ival < 1 )
3802 {
3803 sprintf( gRmessage, "Value %d is not in range [%d,oo).", ival, 1 );
3804 rERROR( gRmessage );
3805 return;
3806 }
3807
3808 if ( gRH.max_size != ival )
3809 gRH.max_size = ival;
3810
3811 XtFree( text );
3812 }
3813
3814
3815 /*----------------------------------------------------------------------
3816 **
3817 ** Callback to set the fill value for the holes app.
3818 **
3819 **----------------------------------------------------------------------
3820 */
3821 static void
r_HL_cb_set_fill_val(Widget w,XtPointer client_data,XtPointer call_data)3822 r_HL_cb_set_fill_val(
3823 Widget w,
3824 XtPointer client_data,
3825 XtPointer call_data
3826 )
3827 {
3828 char * text;
3829 int ival;
3830
3831 text = XmTextGetString( w );
3832
3833 if ( ! text || ! *text ) /* nothing typed */
3834 {
3835 if ( text )
3836 XtFree( text );
3837 return;
3838 }
3839
3840 /*
3841 ** Make sure a value has changed (to something acceptable)
3842 ** before applying.
3843 */
3844
3845 ival = atoi( text );
3846 if ( ( ival < 0 ) || ( ival > 255 ) )
3847 {
3848 sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 0, 255 );
3849 rERROR( gRmessage );
3850 return;
3851 }
3852 else if ( ival == 0 )
3853 {
3854 rWARNING( "Using hole fill value of 0." );
3855 }
3856
3857
3858 if ( gRH.fill_val != ival )
3859 gRH.fill_val = ival;
3860
3861
3862 XtFree( text );
3863 }
3864
3865
3866 /*----------------------------------------------------------------------
3867 **
3868 ** Callback to set the fill value.
3869 **
3870 **----------------------------------------------------------------------
3871 */
3872 static void
r_INT_cb_set_fill_val(Widget w,XtPointer client_data,XtPointer call_data)3873 r_INT_cb_set_fill_val(
3874 Widget w,
3875 XtPointer client_data,
3876 XtPointer call_data
3877 )
3878 {
3879 char * text;
3880 int ival;
3881
3882 text = XmTextGetString( w );
3883
3884 if ( ! text || ! *text ) /* nothing typed */
3885 {
3886 if ( text )
3887 XtFree( text );
3888 return;
3889 }
3890
3891 /*
3892 ** Make sure a value has changed (to something acceptable)
3893 ** before applying.
3894 */
3895
3896 ival = atoi( text );
3897 if ( ( ival < 0 ) || ( ival > 255 ) )
3898 {
3899 sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 0, 255 );
3900 rERROR( gRmessage );
3901 return;
3902 }
3903 else if ( ival == 0 )
3904 {
3905 rWARNING( "Using interpolation fill value of 0." );
3906 }
3907
3908 if ( gRI.fill_val != ival )
3909 gRI.fill_val = ival;
3910
3911
3912 XtFree( text );
3913 }
3914
3915
3916 /*----------------------------------------------------------------------
3917 **
3918 ** Callback to set the fill value.
3919 **
3920 **----------------------------------------------------------------------
3921 */
3922 static void
r_wt_cb_set_fill_val(Widget w,XtPointer client_data,XtPointer call_data)3923 r_wt_cb_set_fill_val(
3924 Widget w,
3925 XtPointer client_data,
3926 XtPointer call_data
3927 )
3928 {
3929 char * text;
3930 int ival;
3931
3932 text = XmTextGetString( w );
3933
3934 if ( ! text || ! *text ) /* nothing typed */
3935 {
3936 if ( text )
3937 XtFree( text );
3938 return;
3939 }
3940
3941 /*
3942 ** Make sure a value has changed (to something acceptable)
3943 ** before applying.
3944 */
3945
3946 ival = atoi( text );
3947 if ( ( ival < 0 ) || ( ival > 255 ) )
3948 {
3949 sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 0, 255 );
3950 rERROR( gRmessage );
3951 return;
3952 }
3953 else if ( ival == 0 )
3954 {
3955 rWARNING( "Warning : using white matter fill value of 0." );
3956 }
3957
3958 if ( gRA.wt_fill_val != ival )
3959 gRA.wt_fill_val = ival;
3960
3961
3962 XtFree( text );
3963 }
3964
3965
3966 /*----------------------------------------------------------------------
3967 **
3968 ** Callback to set the fill value.
3969 **
3970 **----------------------------------------------------------------------
3971 */
3972 static void
r_gr_set_fill_val(Widget w,XtPointer client_data,XtPointer call_data)3973 r_gr_set_fill_val(
3974 Widget w,
3975 XtPointer client_data,
3976 XtPointer call_data
3977 )
3978 {
3979 char * text;
3980 int ival;
3981
3982 text = XmTextGetString( w );
3983
3984 if ( ! text || ! *text ) /* nothing typed */
3985 {
3986 if ( text )
3987 XtFree( text );
3988 return;
3989 }
3990
3991 /*
3992 ** Make sure a value has changed (to something acceptable)
3993 ** before applying.
3994 */
3995
3996 ival = atoi( text );
3997 if ( ( ival < 1 ) || ( ival > 255 ) )
3998 {
3999 sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 1, 255 );
4000 rERROR( gRmessage );
4001 return;
4002 }
4003
4004 if ( gRA.gr_fill_val != ival )
4005 gRA.gr_fill_val = ival;
4006
4007
4008 XtFree( text );
4009 }
4010
4011
4012 /*----------------------------------------------------------------------
4013 **
4014 ** Callback to set the white search range.
4015 **
4016 **----------------------------------------------------------------------
4017 */
4018 static void
r_wt_cb_set_range(Widget w,XtPointer client_data,XtPointer call_data)4019 r_wt_cb_set_range(
4020 Widget w,
4021 XtPointer client_data,
4022 XtPointer call_data
4023 )
4024 {
4025 char * string = ( char * )client_data;
4026 char * text;
4027 int ival;
4028
4029 text = XmTextGetString( w );
4030
4031 if ( ! text || ! *text ) /* nothing typed */
4032 {
4033 if ( text )
4034 XtFree( text );
4035 return;
4036 }
4037
4038 if ( ! string ) /* strange error - complain and return */
4039 {
4040 fprintf( stderr, "r_wt_cb_set_range error - string is NULL\n" );
4041 return;
4042 }
4043 else if ( ! *string )
4044 {
4045 fprintf( stderr, "r_wt_cb_set_range error - string is empty\n" );
4046 return;
4047 }
4048 else if ( ! strcmp( string, "to" ) && ! strcmp( string, "from" ) )
4049 {
4050 fprintf( stderr, "r_wt_cb_set_range error -\n"
4051 "'%s' should be 'to' or 'from'.\n", string );
4052 return;
4053 }
4054
4055 /*
4056 ** Make sure a value has changed (to something acceptable)
4057 ** before applying. Use short range.
4058 */
4059
4060 ival = atoi( text );
4061 if ( ( ival < -32768 ) || ( ival > 32767 ) )
4062 {
4063 fprintf( stderr, "Value %d is not in range [%d,%d].\n",
4064 ival, -32768, 32767 );
4065 return;
4066 }
4067
4068 if ( ! strcmp( string, "from" ) )
4069 {
4070 if ( gRA.wt_range_min != ival )
4071 {
4072 gRA.wt_range_min = ival;
4073
4074 if ( gRA.wt_range_min > gRA.wt_range_max )
4075 {
4076 sprintf( gRmessage, "\nWarning!"
4077 " Min value should be less than max value.\n"
4078 "Value are %d and %d, respectively.\n",
4079 gRA.wt_range_min, gRA.wt_range_max );
4080 rERROR( gRmessage );
4081 }
4082 }
4083 }
4084 else
4085 {
4086 if ( gRA.wt_range_max != ival )
4087 {
4088 gRA.wt_range_max = ival;
4089
4090 if ( gRA.wt_range_min > gRA.wt_range_max )
4091 {
4092 sprintf( gRmessage, "\nWarning!"
4093 " Min value should be less than max value.\n"
4094 "Value are %d and %d, respectively.\n",
4095 gRA.wt_range_min, gRA.wt_range_max );
4096 rERROR( gRmessage );
4097 }
4098 }
4099 }
4100
4101 XtFree( text );
4102 }
4103
4104
4105 /*----------------------------------------------------------------------
4106 **
4107 ** Callback to set the search range.
4108 **
4109 **----------------------------------------------------------------------
4110 */
4111 static void
r_gr_cb_set_range(Widget w,XtPointer client_data,XtPointer call_data)4112 r_gr_cb_set_range(
4113 Widget w,
4114 XtPointer client_data,
4115 XtPointer call_data
4116 )
4117 {
4118 char * string = ( char * )client_data;
4119 char * text;
4120 int ival;
4121
4122 text = XmTextGetString( w );
4123
4124 if ( ! text || ! *text ) /* nothing typed */
4125 {
4126 if ( text )
4127 XtFree( text );
4128 return;
4129 }
4130
4131 if ( ! string ) /* strange error - complain and return */
4132 {
4133 fprintf( stderr, "r_gr_cb_set_range error - string is NULL\n" );
4134 return;
4135 }
4136 else if ( ! *string )
4137 {
4138 fprintf( stderr, "r_gr_cb_set_range error - string is empty\n" );
4139 return;
4140 }
4141 else if ( ! strcmp( string, "to" ) && ! strcmp( string, "from" ) )
4142 {
4143 fprintf( stderr, "r_gr_cb_set_range error -\n"
4144 "'%s' should be 'to' or 'from'.\n", string );
4145 return;
4146 }
4147
4148 /*
4149 ** Make sure a value has changed (to something acceptable)
4150 ** before applying. Use short range.
4151 */
4152
4153 ival = atoi( text );
4154 if ( ( ival < -32768 ) || ( ival > 32767 ) )
4155 {
4156 sprintf( gRmessage, "Value %d is not in range [%d,%d].",
4157 ival, -32768, 32767 );
4158 rERROR( gRmessage );
4159 return;
4160 }
4161
4162 if ( ! strcmp( string, "from" ) )
4163 {
4164 if ( gRA.gr_range_min != ival )
4165 {
4166 gRA.gr_range_min = ival;
4167
4168 if ( gRA.gr_range_min > gRA.gr_range_max )
4169 {
4170 sprintf( gRmessage, "\nWarning!"
4171 " Min value should be less than max value.\n"
4172 "Value are %d and %d, respectively.\n",
4173 gRA.gr_range_min, gRA.gr_range_max );
4174 rERROR( gRmessage );
4175 }
4176 }
4177 }
4178 else
4179 {
4180 if ( gRA.gr_range_max != ival )
4181 {
4182 gRA.gr_range_max = ival;
4183
4184 if ( gRA.gr_range_min > gRA.gr_range_max )
4185 {
4186 sprintf( gRmessage, "\nWarning!"
4187 " Min value should be less than max value.\n"
4188 "Value are %d and %d, respectively.\n",
4189 gRA.gr_range_min, gRA.gr_range_max );
4190 rERROR( gRmessage );
4191 }
4192 }
4193 }
4194
4195 XtFree( text );
4196 }
4197
4198
4199 /*----------------------------------------------------------------------
4200 **
4201 ** The user has selected an initial fill point.
4202 **
4203 ** Update the search range. If the user wants the initial point
4204 ** aligned (moved to local extrema), do it.
4205 **
4206 **----------------------------------------------------------------------
4207 */
4208 static int
r_afni_set_fill_point(int * coord,r_alg_s * A)4209 r_afni_set_fill_point(
4210 int * coord, /* offset of initial point (modifiable) */
4211 r_alg_s * A /* algorithm structure */
4212 )
4213 {
4214 ENTRY("r_afni_set_fill_point");
4215
4216 A->point_coord = *coord;
4217
4218 /*printf("A = %p, A->adata = %p, A->point_coord = %d\n",
4219 A,A->adata,A->point_coord);
4220 fflush(stdout);*/
4221
4222 if ( A->adata == NULL )
4223 {
4224 /*fprintf(stderr,"Loading data...\n");
4225 DSET_load(A->anat);*/
4226 fputs("r_afni_set_fill_point(): Error: No anatomical data. ( A->adata = NULL )\n",stderr);
4227 fputs("This may have been caused by selecting Talairach\n",stderr);
4228 fputs("view before Switch Underlay or Switch Overlay.\n",stderr);
4229 fputs("Try setting the environment variable AFNI_VIEW_ANAT_BRICK\n",stderr);
4230 fputs("(The value is irrelevant) and run afni again.\n",stderr);
4231 RETURN(-1);
4232 }
4233 A->point_value = A->adata[A->point_coord]; /* no anat factor? */
4234
4235
4236 printf( "coord = %d, adata = %d, fdata = %d, ndata = %d\n",
4237 *coord, A->adata[*coord], A->fdata[*coord], A->neighbors[*coord] );
4238
4239 RETURN(0);
4240 }
4241
4242
4243 /*----------------------------------------------------------------------
4244 **
4245 ** Create a scale bar.
4246 **
4247 **----------------------------------------------------------------------
4248 */
4249
4250 static Widget
r_mk_scale_bar(Widget parent,char * title,int min,int max,int value,int decimal_places,XtCallbackProc callback)4251 r_mk_scale_bar(
4252 Widget parent,
4253 char * title,
4254 int min,
4255 int max,
4256 int value,
4257 int decimal_places,
4258 XtCallbackProc callback
4259 )
4260 {
4261 int ac;
4262 Arg al[ 20 ];
4263 XmString Xtitle;
4264 Widget scale;
4265
4266 Xtitle = XmStringCreateLtoR( title, gRX.charset );
4267
4268 ac = 0;
4269 XtSetArg( al[ac], XmNtitleString, Xtitle ); ac++;
4270 XtSetArg( al[ac], XmNorientation, XmHORIZONTAL ); ac++;
4271 XtSetArg( al[ac], XmNminimum, min ); ac++;
4272 XtSetArg( al[ac], XmNmaximum, max ); ac++;
4273 XtSetArg( al[ac], XmNvalue, value ); ac++;
4274 XtSetArg( al[ac], XmNshowValue, True ); ac++;
4275
4276 if ( decimal_places > 0 )
4277 {
4278 XtSetArg( al[ac], XmNdecimalPoints, decimal_places );
4279 ac++;
4280 }
4281
4282
4283 scale = XmCreateScale( parent, "scale_bar", al, ac );
4284
4285 XmStringFree( Xtitle );
4286
4287 XtManageChild( scale );
4288
4289 XtAddCallback( scale, XmNvalueChangedCallback, callback, NULL );
4290
4291 return scale;
4292 }
4293
4294
4295 /*----------------------------------------------------------------------
4296 **
4297 ** Display the contents of the algorithm structure.
4298 **
4299 **---------------------------------------------------------------------
4300 */
4301
4302 static void
r_main_show_alg_vals(r_alg_s * A)4303 r_main_show_alg_vals( r_alg_s * A )
4304 {
4305 printf( "-----------------------------------\n" );
4306
4307 printf(
4308 "gRA :\n"
4309 "\n"
4310 "point value : %d\n"
4311 "point coord : %d\n"
4312 "adjust point : %d\n"
4313 "'save as' name : %s\n"
4314 "\n"
4315 "white fill value : %d\n"
4316 "white range min : %d\n"
4317 "white range max : %d\n"
4318 "white diag connect : %d\n"
4319 "\n"
4320 "gray fill value : %d\n"
4321 "gray range min : %d\n"
4322 "gray range max : %d\n"
4323 "gray max distance : %d\n"
4324 "\n"
4325 "anat dset (addr) : %p\n"
4326 "func dset (addr) : %p\n"
4327 "adata data (addr) : %p\n"
4328 "fdata data (addr) : %p\n"
4329 "factor : %f\n"
4330 "nx : %d\n"
4331 "ny : %d\n"
4332 "nz : %d\n"
4333 "nvox : %d\n"
4334 "\n"
4335 "old bound.M : %d\n"
4336 "old bound.used : %d\n"
4337 "old bound.points (addr) : %p\n"
4338 "new bound.M : %d\n"
4339 "new bound.used : %d\n"
4340 "new bound.points (addr) : %p\n"
4341 "border.M : %d\n"
4342 "border.used : %d\n"
4343 "border.points (addr) : %p\n"
4344 "\n"
4345 "neighbors (addr) : %p\n"
4346 "undo data (addr) : %p\n"
4347 "\n"
4348 "min neighbors : %d\n"
4349 "strong borders : %d\n",
4350 A->point_value, A->point_coord, A->adjust_point, A->save_as_name,
4351 A->wt_fill_val, A->wt_range_min, A->wt_range_max,
4352 A->wt_diag_connect,
4353 A->gr_fill_val, A->gr_range_min, A->gr_range_max, A->gr_max_dist,
4354 A->anat, A->func,
4355 A->adata, A->fdata,
4356 A->factor, A->nx, A->ny, A->nz, A->nvox,
4357 A->Bold.M, A->Bold.used, A->Bold.points,
4358 A->Bnew.M, A->Bnew.used, A->Bnew.points,
4359 A->border.M, A->border.used, A->border.points,
4360 A->neighbors, A->undo_data,
4361 A->min_nbrs, A->strong_borders
4362 );
4363
4364 printf( "-----------------------------------\n" );
4365 }
4366
4367
4368 /*----------------------------------------------------------------------
4369 **
4370 ** Display the contents of the interpolation structure.
4371 **
4372 **----------------------------------------------------------------------
4373 */
4374 static void
r_main_show_INT_vals(interp_s * I)4375 r_main_show_INT_vals( interp_s * I )
4376 {
4377 printf( "-----------------------------------\n" );
4378
4379 printf(
4380 "gRI :\n"
4381 "\n"
4382 "fill value : %d\n"
4383 "afni undo : %d\n"
4384 "\n"
4385 "A.M : %d\n"
4386 "A.used : %d\n"
4387 "A.points (addr) : %p\n"
4388 "B.M : %d\n"
4389 "B.used : %d\n"
4390 "B.points (addr) : %p\n",
4391 I->fill_val, I->afni_undo,
4392 I->A.M, I->A.used, I->A.points,
4393 I->B.M, I->B.used, I->B.points
4394 );
4395
4396 printf( "-----------------------------------\n" );
4397 }
4398
4399
4400 /*----------------------------------------------------------------------
4401 **
4402 ** Display the contents of the holes structure.
4403 **
4404 **----------------------------------------------------------------------
4405 */
4406 static void
r_main_show_HL_vals(holes_s * H)4407 r_main_show_HL_vals( holes_s * H )
4408 {
4409 printf( "-----------------------------------\n" );
4410 printf(
4411 "gRH :\n"
4412 "\n"
4413 "max size : %d\n"
4414 "fill value : %d\n"
4415 "wtgr_edge.M : %d\n"
4416 "wtgr_edge.used : %d\n"
4417 "wtgr_edge.points (addr) : %p\n"
4418 "filled.M : %d\n"
4419 "filled.used : %d\n"
4420 "filled.points (addr) : %p\n",
4421 H->max_size, H->fill_val,
4422 H->wtgr_edge.M, H->wtgr_edge.used, H->wtgr_edge.points,
4423 H->filled.M, H->filled.used, H->filled.points
4424 );
4425 printf( "-----------------------------------\n" );
4426 }
4427
4428
4429 /*----------------------------------------------------------------------
4430 **
4431 ** Display the contents of the point connection structure.
4432 **
4433 **----------------------------------------------------------------------
4434 */
4435 static void
r_main_show_pt_conn_vals(r_pt_conn_s * PC)4436 r_main_show_pt_conn_vals( r_pt_conn_s * PC )
4437 {
4438 printf( "-----------------------------------\n" );
4439 printf(
4440 "gRCP :\n"
4441 "\n"
4442 "plist.M : %d\n"
4443 "plist.used : %d\n"
4444 "plist.points (addr) : %p\n"
4445 "source point : (%d,%d,%d)\n"
4446 "dest point : (%d,%d,%d)\n"
4447 "which point : %d\n",
4448 PC->plist.M, PC->plist.used, PC->plist.points,
4449 PC->source.x, PC->source.y, PC->source.z,
4450 PC->dest.x, PC->dest.y, PC->dest.z,
4451 PC->cur_pt
4452 );
4453 printf( "-----------------------------------\n" );
4454 }
4455
4456
4457 /*----------------------------------------------------------------------
4458 **
4459 ** Callback to get help. This displays a general process overview.
4460 **
4461 **----------------------------------------------------------------------
4462 */
4463 static void
r_main_cb_help(Widget w,XtPointer client_data,XtPointer call_data)4464 r_main_cb_help(
4465 Widget w,
4466 XtPointer client_data,
4467 XtPointer call_data
4468 )
4469 {
4470 ( void )new_MCW_textwin( w,
4471
4472 #include "plug_roiedit.hhh"
4473
4474 "Compiled: "
4475 __DATE__
4476 ", "
4477 __TIME__
4478 "\n"
4479
4480 , TEXT_READONLY );
4481
4482 return;
4483 }
4484
4485
4486 /*----------------------------------------------------------------------
4487 **
4488 ** Callback to quit ( this merely unmanages all the widgets ).
4489 **
4490 **----------------------------------------------------------------------
4491 */
4492 static void
r_main_cb_quit(void)4493 r_main_cb_quit( void )
4494 {
4495 r_any_cb_hide( NULL, "all", NULL );
4496 XtUnmapWidget( gRX.main );
4497 gRX.main_is_open = 0;
4498 }
4499
4500
4501 /*----------------------------------------------------------------------
4502 **
4503 ** Callback to save the current dataset under a new name.
4504 **
4505 **----------------------------------------------------------------------
4506 */
4507 static void
r_main_cb_saveas(Widget w,int client_data,XtPointer call_data)4508 r_main_cb_saveas(
4509 Widget w,
4510 int client_data,
4511 XtPointer call_data
4512 )
4513 {
4514 XmSelectionBoxCallbackStruct * cbs;
4515 char * text;
4516 int ival;
4517
4518 ENTRY("r_main_cb_saveas");
4519
4520 cbs = ( XmSelectionBoxCallbackStruct * )call_data;
4521
4522 if ( ! XmStringGetLtoR( cbs->value, gRX.charset, &text ) )
4523 {
4524 rERROR( "Failed to get filename from text." );
4525 EXRETURN;
4526 }
4527 else if ( ! *text )
4528 {
4529 XtFree( text );
4530 EXRETURN;
4531 }
4532
4533 /* Make sure file name is not too long. */
4534
4535 if ( strlen( text ) > R_FILE_L - 14 ) /* leave from for +tlrc.BRIK.gz_ */
4536 {
4537 sprintf( gRmessage, "Output filename '%s' exceeds %d characters.\n",
4538 text, R_FILE_L - 14 );
4539 rERROR( gRmessage );
4540 }
4541 else
4542 strcpy( gRA.save_as_name, text );
4543
4544 XtFree( text );
4545
4546 r_save_dataset_as( gRA.save_as_name, client_data );
4547 EXRETURN;
4548 }
4549
4550
4551 /*----------------------------------------------------------------------
4552 **
4553 ** Actually save the new dataset. Make a copy of the original dset,
4554 ** change the prefix and save the file.
4555 **
4556 **----------------------------------------------------------------------
4557 */
4558 static int
r_save_dataset_as(char * filename,int overwrite)4559 r_save_dataset_as( char * filename, int overwrite )
4560 {
4561 THD_3dim_dataset * dset = NULL;
4562
4563 ENTRY("r_save_dataset_as");
4564
4565 if ( ! ( dset = PLUTO_copy_dset( gRA.func, filename ) ) )
4566 {
4567 sprintf( gRmessage,"Failed to copy dataset with name '%s'.", filename );
4568 rERROR( gRmessage );
4569 RETURN(0);
4570 }
4571
4572 if( ! overwrite && THD_is_file( dset->dblk->diskptr->header_name ) )
4573 {
4574 sprintf( gRmessage, "File '%s' already exists!", filename );
4575 rERROR( gRmessage );
4576 }
4577 else
4578 {
4579 DSET_overwrite( dset ) ;
4580
4581 sprintf( gRmessage, "Dataset copied as '%s'.", filename );
4582 rWARNING( gRmessage );
4583 }
4584
4585 THD_delete_3dim_dataset( dset, False );
4586
4587 RETURN(1);
4588 }
4589
4590
4591 /*----------------------------------------------------------------------
4592 **
4593 ** Display the contents of internal structures.
4594 **
4595 **----------------------------------------------------------------------
4596 */
4597 static void
r_main_cb_show_structs(void)4598 r_main_cb_show_structs( void )
4599 {
4600 ENTRY("r_main_cb_show_structs");
4601
4602 printf( "------------------------------------------------------------\n" );
4603
4604 r_main_show_alg_vals ( &gRA );
4605 r_main_show_INT_vals ( &gRI );
4606 r_main_show_HL_vals ( &gRH );
4607 r_main_show_pt_conn_vals( &gRCP );
4608
4609 printf( "------------------------------------------------------------\n" );
4610 EXRETURN;
4611 }
4612
4613
4614 /*----------------------------------------------------------------------
4615 **------ --------------------------------
4616 **------ Begin interpolation routines --------------------------------
4617 **------ --------------------------------
4618 **----------------------------------------------------------------------
4619 **
4620 ** The technique here is to keep two curves of data stored.
4621 **
4622 ** Operations that we need to consider are :
4623 **
4624 ** o inserting a new line ( on any line draw )
4625 ** if none { insert first }
4626 ** else if one { insert second }
4627 ** else { move second to first, insert second }
4628 ** o UNDO move
4629 ** if two { remove second }
4630 ** else { remove first }
4631 ** o interpolate ( use special interpolation value )
4632 ** - only with the two lines
4633 ** - store previous interpolation first
4634 ** ( change interpolation values to draw values )
4635 ** o undo interpolation
4636 ** remove all interpolation values
4637 **
4638 **----------------------------------------------------------------------
4639 */
4640
4641
4642 /*-------------------------------------------------------------------
4643 Callback for done button
4644 ---------------------------------------------------------------------*/
4645
DRAW_done_CB(Widget w,XtPointer client_data,XtPointer call_data)4646 static void DRAW_done_CB( Widget w, XtPointer client_data, XtPointer call_data )
4647 {
4648 ENTRY("DRAW_done_CB");
4649
4650 if( dset != NULL ){
4651 if( recv_open ) AFNI_receive_control( im3d, recv_key, DRAWING_SHUTDOWN, NULL ) ;
4652 if( dset_changed ){
4653 MCW_invert_widget( done_pb ) ;
4654 DSET_overwrite(dset) ;
4655 MCW_invert_widget( done_pb ) ;
4656 }
4657 DSET_unlock(dset) ; DSET_anyize(dset) ;
4658 dset = NULL ; dset_changed = 0 ;
4659 }
4660
4661 if( undo_buf != NULL ){
4662 free(undo_buf) ; free(undo_xyz) ;
4663 undo_buf = NULL; undo_xyz = NULL;
4664 undo_bufsiz = undo_bufnum = undo_bufuse = 0 ;
4665 }
4666
4667 XtUnmapWidget( shell ) ; editor_open = 0 ; recv_open = 0 ; recv_key = -1 ;
4668 EXRETURN;
4669 }
4670
4671 /*-------------------------------------------------------------------
4672 Callback for undo button
4673 ---------------------------------------------------------------------*/
4674
DRAW_undo_CB(Widget w,XtPointer client_data,XtPointer call_data)4675 static void DRAW_undo_CB( Widget w, XtPointer client_data, XtPointer call_data )
4676 {
4677 void * ub ; int * ux, * uy, * uz ;
4678 int ubs = undo_bufsiz , uis = sizeof(int)*undo_bufuse ;
4679
4680 ENTRY("DRAW_undo_CB");
4681
4682 if( undo_bufuse <= 0 ){ XBell( dc->display , 100 ) ; EXRETURN ; }
4683
4684 /* since the undo_stuff will be modified by the
4685 drawing function, we must make temporary copies */
4686
4687 ub = malloc(ubs) ; memcpy(ub,undo_buf,ubs) ;
4688 ux = (int *) malloc(uis) ; memcpy(ux,undo_xyz,uis) ;
4689
4690 gRI.afni_undo = 1;
4691 DRAW_into_dataset( undo_bufuse , ux,NULL,NULL , ub ) ;
4692 gRI.afni_undo = 0;
4693
4694 if ( ( mode_ival == MODE_CURVE ) || ( mode_ival == MODE_CLOSED ) ||
4695 ( mode_ival == MODE_CONN_PTS ) )
4696 {
4697 gRI.B.used = 0; /* RCR - clear any new I-data */
4698
4699 if ( mode_ival == MODE_CONN_PTS )
4700 gRCP.cur_pt = 1;
4701 }
4702
4703 free(ub) ; free(ux) ;
4704 EXRETURN ;
4705 }
4706
4707 /*-------------------------------------------------------------------
4708 Callback for quit button
4709 ---------------------------------------------------------------------*/
4710
DRAW_quit_CB(Widget w,XtPointer client_data,XtPointer call_data)4711 static void DRAW_quit_CB( Widget w, XtPointer client_data, XtPointer call_data )
4712 {
4713 ENTRY("DRAW_quit_CB");
4714
4715 if( dset != NULL ){
4716 if( recv_open ) AFNI_receive_control( im3d, recv_key, DRAWING_SHUTDOWN, NULL ) ;
4717 DSET_unlock(dset) ;
4718 DSET_unload(dset) ; DSET_anyize(dset) ;
4719 if( dset_changed ){
4720 MCW_invert_widget(quit_pb) ;
4721 THD_load_statistics( dset ) ;
4722 PLUTO_dset_redisplay( dset ) ;
4723 MCW_invert_widget(quit_pb) ;
4724 }
4725 dset = NULL ; dset_changed = 0 ;
4726 }
4727
4728 if( undo_buf != NULL ){
4729 free(undo_buf) ; free(undo_xyz) ;
4730 undo_buf = NULL; undo_xyz = NULL;
4731 undo_bufsiz = undo_bufnum = undo_bufuse = 0 ;
4732 }
4733
4734 XtUnmapWidget( shell ) ; editor_open = 0 ; recv_open = 0 ; recv_key = -1 ;
4735 EXRETURN ;
4736 }
4737
4738 /*-------------------------------------------------------------------
4739 Callback for save button
4740 ---------------------------------------------------------------------*/
4741
DRAW_save_CB(Widget w,XtPointer client_data,XtPointer call_data)4742 static void DRAW_save_CB( Widget w, XtPointer client_data, XtPointer call_data )
4743 {
4744 ENTRY("DRAW_save_CB");
4745
4746 if( dset == NULL ){ XBell( dc->display , 100 ) ; EXRETURN ; }
4747
4748 MCW_invert_widget(save_pb) ;
4749
4750 DSET_overwrite(dset); dset_changed = 0; SENSITIZE(choose_pb,1);
4751
4752 MCW_invert_widget(save_pb) ; SENSITIZE(save_pb,0) ;
4753 EXRETURN ;
4754 }
4755
4756 /*-------------------------------------------------------------------
4757 Callback for help button
4758 ---------------------------------------------------------------------*/
4759
DRAW_help_CB(Widget w,XtPointer client_data,XtPointer call_data)4760 static void DRAW_help_CB( Widget w, XtPointer client_data, XtPointer call_data )
4761 {
4762 (void ) new_MCW_textwin( help_pb ,
4763
4764 "The GyrusFinder plugin is based on the original 'Draw Dataset' plugin\n"
4765 "by RW Cox. The original help for that plugin is below. Help for the\n"
4766 "new features can be found in the new windows created by GyrusFinder.\n"
4767 "======================================================================\n"
4768 "This plugin can be used to edit interactively the voxel contents\n"
4769 "of a dataset. Since such changes are irreversible, it is best that\n"
4770 "you either edit a copy of a dataset, or create a dataset of all zeros.\n"
4771 "These tasks can be done with the 'Dataset Copy' plugin.\n"
4772 "\n"
4773 "***************** Read the WARNINGS section below. *****************\n"
4774 "\n"
4775 "---------------------- Bob Cox, February 1998 ----------------------\n"
4776 "\n"
4777 "Step 1) Choose a dataset to edit.\n"
4778 " * Only datasets that have data BRIKs stored at the current\n"
4779 " resolution can be edited.\n"
4780 " * Datasets may be copied with the 'Dataset Copy' plugin.\n"
4781 " * It is probably best that the dataset being edited be\n"
4782 " displayed. Otherwise it will be impossible to gauge\n"
4783 " the effect of the editing operations.\n"
4784 " * At this time, only datasets that have a single sub-brick\n"
4785 " can be edited.\n"
4786 "\n"
4787 "Step 2) Choose a drawing value.\n"
4788 " * This is the number that will be placed into the dataset\n"
4789 " voxels that are chosen.\n"
4790 " * Integer valued datasets can only receive integer values;\n"
4791 " float datasets can take floating point values.\n"
4792 "\n"
4793 "Step 3) Choose a drawing color.\n"
4794 " * This is the color that will be shown in the image windows\n"
4795 " while drawing is going on (that is, while mouse button 2\n"
4796 " is pressed).\n"
4797 " * See 5) for more details about the drawing process.\n"
4798 "\n"
4799 "Step 4) Choose a drawing mode.\n"
4800 " * 'Open Curve' means to select dataset voxels that lie under\n"
4801 " the pixel lines drawn on the image as you move the mouse\n"
4802 " with button 2 held down.\n"
4803 " * 'Closed Curve ' means to close the curve drawn from the last\n"
4804 " point drawn (where button 2 is released) back to the\n"
4805 " first point drawn (where button 2 was pressed).\n"
4806 " * 'Points' means to take only the voxels corresponding\n"
4807 " to the screen pixels about which X11 sends notice\n"
4808 " (this is not very useful).\n"
4809 " * 'Flood->Value' means to flood fill outwards from the first\n"
4810 " chosen voxel, stopping when the Dataset Value is reached.\n"
4811 " In conjunction with 'Closed Curve', it can be used to draw\n"
4812 " an entire region in a plane.\n"
4813 " * 'Flood->Nonzero' means to flood fill, but stopping when any\n"
4814 " nonzero voxel value is reached.\n"
4815 "\n"
4816 "Step 5) Draw something in an image window.\n"
4817 " * Drawing is done using mouse button 2.\n"
4818 " * In an image window, drawing a set of pixels is done\n"
4819 " by pressing and holding button 2, and dragging\n"
4820 " the cursor across the desired pixels. The drawing\n"
4821 " color will be painted over these pixels while the\n"
4822 " painting is going on (while button 2 is held down).\n"
4823 " * After mouse button 2 is released, the drawing value for\n"
4824 " the chosen voxels is copied into the dataset. The\n"
4825 " dataset is then redisplayed -- this will most likely\n"
4826 " change the color of the selected voxels, since display\n"
4827 " colors depend on the Define Function pbar (for Func\n"
4828 " datasets) or on the greyscale map (for Anat datasets).\n"
4829 " * That is, the drawing color is ONLY used while button2\n"
4830 " is pressed down. This color should simply be chosen\n"
4831 " to provide good contrast for the drawing operations.\n"
4832 " * Pressing and releasing button 2 in a graph window\n"
4833 " sub-graph will cause that single voxel to get the\n"
4834 " drawing value, as well. You cannot select a group\n"
4835 " of voxels in a graph window -- only one voxel per click.\n"
4836 "\n"
4837 "Step 6) Undo.\n"
4838 " * The last drawing operation can be undone -- that is,\n"
4839 " pressing 'Undo' will restore the voxel values before\n"
4840 " the last button 2 press-release operation.\n"
4841 " * There is only one level of undo. Undo-ing the undo\n"
4842 " will put things back the way they were. Anyone who\n"
4843 " implements a better undo system will be appreciated.\n"
4844 "\n"
4845 "Step 7) Save dataset (maybe).\n"
4846 " * While a dataset is being edited, it is locked into memory.\n"
4847 " * The edited values are saved to disk only when 'Save' or\n"
4848 " 'Done' are pressed.\n"
4849 " * The 'Quit' button can be used to discard the edits of\n"
4850 " a dataset. In that case, the dataset values are\n"
4851 " re-read from disk when it is redisplayed.\n"
4852 " * Closing the AFNI Editor window using the window manager\n"
4853 " is equivalent to pressing 'Quit'.\n"
4854 "\n"
4855 "WARNINGS:\n"
4856 " * It is important to understand the distinction between 'pixels'\n"
4857 " and 'voxels'. Pixels are on the screen, and while you are\n"
4858 " drawing, you are drawing pixels with the drawing color. When\n"
4859 " you release mouse button 2, those dataset voxels to which these\n"
4860 " pixels correspond are computed. The values stored in those\n"
4861 " voxels are then altered, and the dataset display is refreshed.\n"
4862 " * It is possible to draw on a montaged image window. However,\n"
4863 " only voxels from the first slice drawn into will be altered.\n"
4864 " * Using button 2 in an image or graph window before choosing a\n"
4865 " dataset to edit will cause the display to beep.\n"
4866 " * Closing the AFNI controller window that this was started from\n"
4867 " is the equivalent of pressing 'Quit'.\n"
4868 " * Doing something that causes the AFNI controller window to\n"
4869 " alter its 3D grid location or resolution is also the\n"
4870 " equivalent of pressing 'Quit'. This is because the 3D grid\n"
4871 " for the dataset being edited will no longer correspond to\n"
4872 " the 3D grid in the image and graph windows. Such actions\n"
4873 " include switching from 'View Brick' to 'Warp on Demand',\n"
4874 " switching datasets or sessions, and switching views.\n"
4875 " * You can only draw into the windows of the controller from which\n"
4876 " the Editor was started.\n"
4877 " * Only one copy of the Editor can be active at a time. If you\n"
4878 " use the plugin menu to call up the Editor when it is already\n"
4879 " open, that will simply pop the window up to the top of the\n"
4880 " stacking order. If you want to restart the Editor in a\n"
4881 " different AFNI controller, you must first close the Editor\n"
4882 " (via 'Done' or 'Quit') and then start it from the other\n"
4883 " controller's window.\n"
4884 " * Peculiar and confusing things can happen using 'Warp-on-Demand'\n"
4885 " with the Editor. My advice is not to try this.\n"
4886 " * Edit at your own risk! Be careful out there.\n"
4887 "\n"
4888 "SUGGESTIONS?\n"
4889 " * Please send them to " COXEMAIL "\n"
4890 " * Even better than suggestions are implementations.\n"
4891
4892
4893 , TEXT_READONLY ) ;
4894 return ;
4895 }
4896
4897 /*-------------------------------------------------------------------
4898 Callback for choose button.
4899 Criteria for datasets that can be edited:
4900 - must be in current session
4901 - must have actual bricks
4902 - only datasets with nvals=1 can be edited
4903 - bricks must be on same grid (dataxes) as AFNI controller
4904 Much of this code is adapted from PLUG_choose_dataset_CB.
4905 [28 Jul 2003] Modified for new THD_session struct.
4906 ---------------------------------------------------------------------*/
4907
4908 static int ndsl = 0 ;
4909 static PLUGIN_dataset_link * dsl = NULL ;
4910
DRAW_choose_CB(Widget w,XtPointer client_data,XtPointer call_data)4911 static void DRAW_choose_CB( Widget w, XtPointer client_data, XtPointer call_data )
4912 {
4913 THD_session * ss = im3d->ss_now ; /* current session */
4914 int vv = im3d->vinfo->view_type ; /* view type */
4915 THD_3dim_dataset * qset ;
4916 int id , ltop , llen ;
4917 char qnam[THD_MAX_NAME] , label[THD_MAX_NAME] ;
4918 static char ** strlist = NULL ;
4919
4920 ENTRY("DRAW_choose_CB");
4921
4922 /* can't do this if a dataset is already active and changed */
4923
4924 if( dset != NULL && dset_changed ){
4925 (void) MCW_popup_message( choose_pb ,
4926 "Can't change datasets until\n"
4927 "you save the changes you've\n"
4928 "already made. Or you could\n"
4929 "'Quit' and re-start the Editor" ,
4930 MCW_USER_KILL | MCW_TIMER_KILL ) ;
4931 XBell( dc->display , 100 ) ;
4932 EXRETURN ;
4933 }
4934
4935 /* RCR - If data is not on disk, do not accept it (must be a warp).
4936 Inform the user that they might have to write the anat.
4937 */
4938 if ( ! DSET_ONDISK( im3d->anat_now ) )
4939 {
4940 (void) MCW_popup_message( choose_pb ,
4941 "Anat data is not actually on disk!\n"
4942 "You may be in 'Warp-on-Demand' mode.\n"
4943 "\n"
4944 "Please take the following steps :\n"
4945 " 1. 'Write Anat'\n"
4946 " 2. 'Rescan This'\n"
4947 " 3. Set to 'View Anat Data Brick'",
4948 MCW_USER_KILL | MCW_TIMER_KILL ) ;
4949 XBell( dc->display , 100 ) ;
4950 EXRETURN ;
4951 }
4952
4953 /* initialize */
4954
4955 ndsl = 0 ;
4956
4957 /* scan anats */
4958
4959 for( id=0 ; id < ss->num_dsset ; id++ ){
4960 qset = GET_SESSION_DSET(ss, id, vv);
4961 /* qset = ss->dsset_xform_table[id][vv] ;*/
4962
4963 if( ! ISVALID_DSET (qset) ) continue ; /* skip */
4964 if( ! DSET_INMEMORY(qset) ) continue ;
4965 if( DSET_NVALS(qset) > 1 ) continue ;
4966 if( ! EQUIV_DATAXES(qset->daxes,im3d->wod_daxes) ) continue ;
4967
4968 ndsl++ ;
4969 dsl = (PLUGIN_dataset_link *)
4970 XtRealloc( (char *) dsl , sizeof(PLUGIN_dataset_link)*ndsl ) ;
4971
4972 make_PLUGIN_dataset_link( qset , dsl + (ndsl-1) ) ;
4973 }
4974
4975 /* found nothing? exit */
4976
4977 if( ndsl < 1 ){
4978 (void) MCW_popup_message( choose_pb ,
4979 "Didn't find any datasets to edit!\n"
4980 "Check if:\n"
4981 " - you are in 'Warp-on-Demand' mode\n"
4982 " - you are in the correct session" ,
4983 MCW_USER_KILL | MCW_TIMER_KILL ) ;
4984 XBell( dc->display , 100 ) ;
4985 EXRETURN ;
4986 }
4987
4988 /*--- 23 Nov 1996: loop over dataset links and patch their titles
4989 to include an indicator of the dataset type ---*/
4990
4991 ltop = 4 ;
4992 for( id=0 ; id < ndsl ; id++ ){
4993 llen = strlen(dsl[id].title) ;
4994 ltop = MAX(ltop,llen) ;
4995 }
4996
4997 for( id=0 ; id < ndsl ; id++ ){
4998 qset = PLUTO_find_dset( &(dsl[id].idcode) ) ;
4999 if( ! ISVALID_DSET(qset) ) continue ;
5000 if( ISANAT(qset) ){
5001 if( ISANATBUCKET(qset) ) /* 30 Nov 1997 */
5002 sprintf(qnam,"%-*s [%s:%d]" ,
5003 ltop,dsl[id].title ,
5004 ANAT_prefixstr[qset->func_type] , DSET_NVALS(qset) ) ;
5005
5006 else if( DSET_NUM_TIMES(qset) == 1 )
5007 sprintf(qnam,"%-*s [%s]" ,
5008 ltop,dsl[id].title ,
5009 ANAT_prefixstr[qset->func_type] ) ;
5010
5011 else
5012 sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
5013 ltop,dsl[id].title ,
5014 ANAT_prefixstr[qset->func_type] , DSET_NUM_TIMES(qset) ) ;
5015
5016 } else {
5017 if( ISFUNCBUCKET(qset) ) /* 30 Nov 1997 */
5018 sprintf(qnam,"%-*s [%s:%d]" ,
5019 ltop,dsl[id].title ,
5020 FUNC_prefixstr[qset->func_type] , DSET_NVALS(qset) ) ;
5021
5022 else if( DSET_NUM_TIMES(qset) == 1 )
5023 sprintf(qnam,"%-*s [%s]" ,
5024 ltop,dsl[id].title ,
5025 FUNC_prefixstr[qset->func_type] ) ;
5026
5027 else
5028 sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
5029 ltop,dsl[id].title ,
5030 FUNC_prefixstr[qset->func_type] , DSET_NVALS(qset) ) ;
5031 }
5032
5033 if( DSET_COMPRESSED(qset) ) strcat(qnam,"z") ;
5034
5035 strcpy( dsl[id].title , qnam ) ;
5036 }
5037
5038 /*--- make a popup chooser for the user to browse ---*/
5039
5040 POPDOWN_strlist_chooser ;
5041
5042 strlist = (char **) XtRealloc( (char *)strlist , sizeof(char *)*ndsl ) ;
5043 for( id=0 ; id < ndsl ; id++ ) strlist[id] = dsl[id].title ;
5044
5045 sprintf( label , "AFNI Dataset from\nthe %s" , VIEW_typestr[vv] ) ;
5046
5047 MCW_choose_strlist( w , label , ndsl , -1 , strlist ,
5048 DRAW_finalize_dset_CB , NULL ) ;
5049
5050 EXRETURN ;
5051 }
5052
DRAW_finalize_dset_CB(Widget w,XtPointer fd,MCW_choose_cbs * cbs)5053 static void DRAW_finalize_dset_CB( Widget w, XtPointer fd, MCW_choose_cbs * cbs )
5054 {
5055 int id = cbs->ival ;
5056 THD_3dim_dataset * qset ;
5057 XmString xstr ;
5058 char str[256] ;
5059
5060 ENTRY("DRAW_finalize_dset_CB");
5061
5062 /* check for errors */
5063
5064 if( ! editor_open ){ POPDOWN_strlist_chooser ; XBell(dc->display,100) ; EXRETURN ; }
5065
5066 if( dset != NULL && dset_changed ){ XBell(dc->display,100) ; EXRETURN ; }
5067
5068 if( id < 0 || id >= ndsl ){ XBell(dc->display,100) ; EXRETURN ; }
5069
5070 qset = PLUTO_find_dset( &(dsl[id].idcode) ) ; /* the new dataset? */
5071
5072 if( qset == NULL ){ XBell(dc->display,100) ; EXRETURN ; }
5073
5074 if( ! EQUIV_DATAXES( im3d->wod_daxes , qset->daxes ) ){
5075 XBell(dc->display,100) ; EXRETURN ;
5076 }
5077
5078 /* accept this dataset */
5079
5080 dset = qset ; dset_changed = 0 ; SENSITIZE(save_pb,0) ;
5081 dax_save = *(dset->daxes) ;
5082
5083 /* write the informational label */
5084
5085 if( DSET_BRICK_FACTOR(dset,0) == 0.0 ){
5086 strcpy(str,dsl[id].title) ;
5087 } else {
5088 char abuf[16] ;
5089 AV_fval_to_char( DSET_BRICK_FACTOR(dset,0) , abuf ) ;
5090 sprintf(str,"%s\nbrick factor: %s", dsl[id].title , abuf ) ;
5091 }
5092 xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
5093 XtVaSetValues( info_lab , XmNlabelString , xstr , NULL ) ;
5094 XmStringFree(xstr) ;
5095
5096 /* setup AFNI for drawing */
5097
5098 if( ! recv_open ){
5099 recv_key = AFNI_receive_init( im3d, RECEIVE_DRAWING_MASK,
5100 DRAW_receiver,NULL,"DRAW_receiver" ) ;
5101
5102 if( recv_key < 0 ){
5103 (void) MCW_popup_message( im3d->vwid->top_shell ,
5104 "Unable to establish\n"
5105 "connection to AFNI\n"
5106 "drawing routines!" ,
5107 MCW_USER_KILL | MCW_TIMER_KILL ) ;
5108
5109 dset = NULL ; XBell(dc->display,100) ; EXRETURN ;
5110 }
5111 }
5112
5113 DSET_mallocize(dset) ; DSET_lock(dset) ; DSET_load(dset) ;
5114
5115 AFNI_receive_control( im3d, recv_key , mode_index , NULL ) ;
5116 AFNI_receive_control( im3d, recv_key , DRAWING_OVCINDEX, ITOP(color_index) ) ;
5117 recv_open = 1 ;
5118
5119 undo_bufuse = 0 ; SENSITIZE(undo_pb,0) ;
5120
5121 r_init_afni_vars( &gRA, dset );
5122
5123 EXRETURN ;
5124 }
5125
5126 /*-------------------------------------------------------------------
5127 Callback for color menu
5128 ---------------------------------------------------------------------*/
5129
DRAW_color_CB(MCW_arrowval * av,XtPointer cd)5130 static void DRAW_color_CB( MCW_arrowval * av , XtPointer cd )
5131 {
5132 color_index = av->ival ;
5133
5134 if( dset != NULL && recv_open )
5135 AFNI_receive_control( im3d, recv_key, DRAWING_OVCINDEX, ITOP(color_index) ) ;
5136
5137 return ;
5138 }
5139
5140 /*-------------------------------------------------------------------
5141 Callback for mode menu
5142 ---------------------------------------------------------------------*/
5143
DRAW_mode_CB(MCW_arrowval * av,XtPointer cd)5144 static void DRAW_mode_CB( MCW_arrowval * av , XtPointer cd )
5145 {
5146 mode_ival = av->ival ;
5147 mode_index = mode_ints[mode_ival] ;
5148
5149 if( dset != NULL && recv_open )
5150 AFNI_receive_control( im3d, recv_key, mode_index , NULL ) ;
5151
5152 return ;
5153 }
5154
5155 /*-------------------------------------------------------------------
5156 Callback for value menu
5157 ---------------------------------------------------------------------*/
5158
DRAW_value_CB(MCW_arrowval * av,XtPointer cd)5159 static void DRAW_value_CB( MCW_arrowval * av , XtPointer cd )
5160 {
5161 value_int = av->ival ;
5162 value_float = av->fval ;
5163 return ;
5164 }
5165
5166 /*******************************************************************
5167 Receive data from AFNI after drawing, etc.
5168 ********************************************************************/
5169
DRAW_receiver(int why,int np,void * vp,void * cbd)5170 static void DRAW_receiver( int why , int np , void * vp , void * cbd )
5171 {
5172 ENTRY("DRAW_receiver");
5173
5174 switch( why ){
5175
5176 default:
5177 fprintf(stderr,"DRAW_receiver: illegal why=%d\n",why) ;
5178 EXRETURN ;
5179
5180 /*-- we like this one --*/
5181
5182 case RECEIVE_POINTS:{
5183 int **ip = (int **)vp ;
5184 int *xd=ip[0] , *yd=ip[1] , *zd=ip[2] ; /* pts coords */
5185 int mode=ip[3][0] ; /* how pts are organized */
5186 int plane ;
5187
5188 if( np <= 0 ) EXRETURN ; /* some error? */
5189
5190 plane = mode - SINGLE_MODE ;
5191 if( plane < 1 || plane > 3 ) plane = mode - PLANAR_MODE ;
5192 if( plane < 1 || plane > 3 ) plane = 0 ;
5193
5194 /* handle selection of initial point for vol_fill, otherwise, */
5195 /* anything but flood mode --> just draw given points */
5196
5197 if ( mode_ival == MODE_VOL_FILL )
5198 {
5199 int coord;
5200
5201 if ( yd == NULL )
5202 coord = *xd;
5203 else
5204 coord = *xd +
5205 *yd * DSET_NX(gRA.anat) +
5206 *zd * DSET_NX(gRA.anat) * DSET_NY(gRA.anat);
5207
5208 if ( r_afni_set_fill_point( &coord, &gRA ) < 0 )
5209 EXRETURN ;
5210
5211 DRAW_into_dataset( 0, &coord, NULL, NULL, NULL );
5212 }
5213 else if ( mode_ival == MODE_CONN_PTS )
5214 { /* store the points into xd and DRAW_into_dataset */
5215 r_ipt_t * pptr;
5216 int coord;
5217
5218 if ( gRCP.cur_pt == 1 )
5219 pptr = &gRCP.source;
5220 else if ( gRCP.cur_pt == 2 )
5221 pptr = &gRCP.dest;
5222 else
5223 {
5224 rERROR( "In DRAW_receiver() - gRCP.cur_pt is unset." );
5225 EXRETURN;
5226 }
5227
5228 if ( yd == NULL )
5229 *pptr = r_index2pt( *xd, gRA.nx, gRA.ny, gRA.nz );
5230 else
5231 {
5232 pptr->x = *xd;
5233 pptr->y = *yd;
5234 pptr->z = *zd;
5235 }
5236
5237 /* If first point, just store it. Otherwise draw entire line. */
5238
5239 if ( gRCP.cur_pt == 1 )
5240 {
5241 gRCP.cur_pt = 2;
5242 DRAW_into_dataset( 0, xd, yd, zd, NULL );
5243 EXRETURN;
5244 }
5245 else
5246 {
5247 points_t * Bp = &gRCP.plist;
5248 r_ipt_t p;
5249 float dx, dy, dz, fx, fy, fz, dcurr;
5250 float tot_dist = r_p_distance( gRCP.source, gRCP.dest );
5251 int pcount = 0;
5252
5253 Bp->used = 0;
5254
5255 dx = R_DIST_STEP * ( gRCP.dest.x - gRCP.source.x ) / tot_dist;
5256 dy = R_DIST_STEP * ( gRCP.dest.y - gRCP.source.y ) / tot_dist;
5257 dz = R_DIST_STEP * ( gRCP.dest.z - gRCP.source.z ) / tot_dist;
5258 fx = gRCP.source.x;
5259 fy = gRCP.source.y;
5260 fz = gRCP.source.z;
5261
5262 for ( dcurr = 0; dcurr < tot_dist; dcurr += R_DIST_STEP )
5263 {
5264 coord = (int)fx + gRA.nx*((int)fy + gRA.ny*(int)fz);
5265 r_add_to_boundary( Bp, coord );
5266
5267 fx += dx;
5268 fy += dy;
5269 fz += dz;
5270 }
5271
5272 coord = gRCP.dest.x + gRA.nx*(gRCP.dest.y+gRA.ny*gRCP.dest.z);
5273 r_add_to_boundary( Bp, coord ); /* add last point */
5274
5275 DRAW_into_dataset( Bp->used, Bp->points, NULL, NULL, NULL );
5276
5277 gRCP.cur_pt = 1;
5278
5279 /*
5280 ** store the line as an interpolator line :
5281 ** DRAW_into_dataset() was edited to check for MODE_CONN_PTS
5282 ** when it stores the incoming line (point set).
5283 */
5284 }
5285 }
5286 else if( plane == 0 ||
5287 ((mode_ival != MODE_FLOOD_VAL) && (mode_ival != MODE_FLOOD_NZ)) ){
5288
5289 DRAW_into_dataset( np , xd,yd,zd , NULL ) ;
5290
5291 } else {
5292
5293 /* flood mode! */
5294
5295 int ityp = DSET_BRICK_TYPE(dset,0) ;
5296 float bfac = DSET_BRICK_FACTOR(dset,0) ;
5297 int nx=DSET_NX(dset) , ny=DSET_NY(dset) , nz=DSET_NZ(dset) ,
5298 nxy = nx*ny , nxyz = nxy*nz , ii,jj , ixyz ;
5299 int base=0 , di=0,dj=0 , itop=0,jtop=0,nij , xx=xd[0],yy=yd[0],zz=zd[0] ,
5300 ix=0,jy=0 ;
5301 byte * pl ;
5302 int nfill , * xyzf , nf ;
5303
5304 /* compute stuff for which plane we are in:
5305 1 -> yz , 2 -> xz , 3 -> xy */
5306
5307 switch(plane){
5308 case 1: base=xx ; di=nx; dj=nxy; itop=ny; jtop=nz;
5309 ix=yy; jy=zz; break;
5310 case 2: base=yy*nx ; di=1 ; dj=nxy; itop=nx; jtop=nz;
5311 ix=xx; jy=zz; break;
5312 case 3: base=zz*nxy; di=1 ; dj=nx ; itop=nx; jtop=ny;
5313 ix=xx; jy=yy; break;
5314 }
5315
5316 /* create a 2D array with 0 where dataset != blocking value
5317 and with 1 where dataset == blocking value */
5318
5319 nij = itop*jtop ;
5320 pl = (byte *) malloc( sizeof(byte) * nij ) ;
5321 memset( pl , 0 , sizeof(byte) * nij ) ;
5322
5323 if( bfac == 0.0 ) bfac = 1.0 ;
5324 switch(ityp){
5325
5326 case MRI_short:{
5327 short * bp = (short *) DSET_BRICK_ARRAY(dset,0) ;
5328 short val = (short) (value_float/bfac) ;
5329
5330 if( mode_ival == MODE_FLOOD_VAL ){
5331 for( jj=0 ; jj < jtop ; jj++ )
5332 for( ii=0 ; ii < itop ; ii++ ){
5333 ixyz = base + ii*di + jj*dj ;
5334 if( bp[ixyz] == val ) pl[ii+jj*itop] = 1 ;
5335 }
5336 } else {
5337 for( jj=0 ; jj < jtop ; jj++ )
5338 for( ii=0 ; ii < itop ; ii++ ){
5339 ixyz = base + ii*di + jj*dj ;
5340 if( bp[ixyz] != 0 ) pl[ii+jj*itop] = 1 ;
5341 }
5342 }
5343 }
5344 break ;
5345
5346 case MRI_byte:{
5347 byte * bp = (byte *) DSET_BRICK_ARRAY(dset,0) ;
5348 byte val = (byte) (value_float/bfac) ;
5349
5350 if( mode_ival == MODE_FLOOD_VAL ){
5351 for( jj=0 ; jj < jtop ; jj++ )
5352 for( ii=0 ; ii < itop ; ii++ ){
5353 ixyz = base + ii*di + jj*dj ;
5354 if( bp[ixyz] == val ) pl[ii+jj*itop] = 1 ;
5355 }
5356 } else {
5357 for( jj=0 ; jj < jtop ; jj++ )
5358 for( ii=0 ; ii < itop ; ii++ ){
5359 ixyz = base + ii*di + jj*dj ;
5360 if( bp[ixyz] != 0 ) pl[ii+jj*itop] = 1 ;
5361 }
5362 }
5363 }
5364 break ;
5365
5366 case MRI_float:{
5367 float * bp = (float *) DSET_BRICK_ARRAY(dset,0) ;
5368 float val = (value_float/bfac) ;
5369
5370 if( mode_ival == MODE_FLOOD_VAL ){
5371 for( jj=0 ; jj < jtop ; jj++ )
5372 for( ii=0 ; ii < itop ; ii++ ){
5373 ixyz = base + ii*di + jj*dj ;
5374 if( bp[ixyz] == val ) pl[ii+jj*itop] = 1 ;
5375 }
5376 } else {
5377 for( jj=0 ; jj < jtop ; jj++ )
5378 for( ii=0 ; ii < itop ; ii++ ){
5379 ixyz = base + ii*di + jj*dj ;
5380 if( bp[ixyz] != 0.0 ) pl[ii+jj*itop] = 1 ;
5381 }
5382 }
5383 }
5384 break ;
5385
5386 default:
5387 free(pl) ;
5388 fprintf(stderr,
5389 "Flood not implemented for datasets of type %s\a\n",
5390 MRI_TYPE_name[ityp] ) ;
5391 EXRETURN ;
5392
5393 } /* end of switch on type */
5394
5395 /* start point must be a 0 (can't fill from an edge) */
5396
5397 if( pl[ix+jy*itop] == 1 ){
5398 free(pl) ; XBell(dc->display,100) ; EXRETURN ;
5399 }
5400
5401 /* call a routine to fill the array */
5402
5403 DRAW_2dfiller( itop,jtop , ix,jy , pl ) ;
5404
5405 /* all filled points are 2 --> these are the locations to draw */
5406
5407 nfill = 0 ;
5408 for( ii=0 ; ii < nij ; ii++ ) nfill += (pl[ii] == 2) ;
5409 if( nfill == 0 ){ free(pl) ; XBell(dc->display,100) ; EXRETURN ; }
5410
5411 xyzf = (int *) malloc( sizeof(int) * nfill ) ;
5412
5413 for( nf=0,jj=0 ; jj < jtop ; jj++ ){
5414 for( ii=0 ; ii < itop ; ii++ ){
5415 if( pl[ii+jj*itop] == 2 )
5416 xyzf[nf++] = base + ii*di + jj*dj ;
5417 }
5418 }
5419
5420 free(pl) ;
5421 DRAW_into_dataset( nfill , xyzf,NULL,NULL , NULL ) ;
5422 free(xyzf) ;
5423
5424 } /* end of flooding */
5425
5426 } /* end of dealing with drawn points */
5427 break ;
5428
5429 /*-- user closed the controller window!? (the fiend) */
5430
5431 case RECEIVE_CLOSURE:{
5432 if( dset != NULL && dset_changed ) XBell(dc->display,100) ; /* protest */
5433 DRAW_quit_CB(NULL,NULL,NULL) ; /* and die */
5434 }
5435 break ;
5436
5437 /*-- user altered the controller window!? */
5438
5439 case RECEIVE_ALTERATION:{
5440
5441 /* if we are already editing a dataset, then
5442 check if the grid has changed -- if it has, must quit */
5443
5444 if( dset != NULL ){
5445 if( ! EQUIV_DATAXES( im3d->wod_daxes , &dax_save ) ){
5446 XBell( dc->display , 100 ) ; /* feeble protest */
5447 DRAW_quit_CB(NULL,NULL,NULL) ; /* die */
5448
5449
5450 { /* RCR stuff */
5451
5452 printf("Initializing gRA...\n");
5453 gRA.anat = NULL;
5454 gRA.func = NULL;
5455 gRA.adata = NULL;
5456 gRA.fdata = NULL;
5457
5458 r_main_cb_quit();
5459 }
5460
5461 /* less feeble protest */
5462 (void) MCW_popup_message( im3d->vwid->top_shell ,
5463 "Controller grid was altered!\n"
5464 "Editor was forced to quit.\n"
5465 "Any un-Saved changes were lost." ,
5466 MCW_USER_KILL | MCW_TIMER_KILL ) ;
5467 }
5468 }
5469 }
5470 break ;
5471
5472 } /* end of switch on why */
5473
5474 EXRETURN ;
5475 }
5476
5477 /*--------------------------------------------------------------------------
5478 Routine to draw into a dataset.
5479 If yd & zd are NULL, then xd is used as the direct 3D array index,
5480 otherwise xd,yd,zd are used as the 3-index.
5481 If var == NULL, then the value_av is used, otherwise the array var[]
5482 will be the source of the data.
5483 ----------------------------------------------------------------------------*/
5484
DRAW_into_dataset(int np,int * xd,int * yd,int * zd,void * var)5485 static void DRAW_into_dataset( int np , int * xd , int * yd , int * zd , void * var )
5486 {
5487 int ityp = DSET_BRICK_TYPE(dset,0) ;
5488 float bfac = DSET_BRICK_FACTOR(dset,0) ;
5489 int nx=DSET_NX(dset) , ny=DSET_NY(dset) , nz=DSET_NZ(dset) ,
5490 nxy = nx*ny , nxyz = nxy*nz , ii , ixyz ;
5491 float vload = 0.0 ;
5492 int nbytes ;
5493
5494 ENTRY("DRAW_into_dataset");
5495
5496 /* sanity check */
5497
5498 if( dset==NULL || np <= 0 || xd==NULL ) EXRETURN ;
5499
5500 /* make space for undo */
5501
5502 nbytes = np * mri_datum_size((MRI_TYPE)ityp) ; /* bytes needed for save */
5503 if( nbytes > undo_bufsiz ){
5504 if( undo_buf != NULL ) free(undo_buf) ;
5505 undo_buf = malloc(nbytes) ;
5506 undo_bufsiz = nbytes ;
5507 }
5508 if( np > undo_bufnum ){
5509 if( undo_xyz != NULL ) free(undo_xyz);
5510 undo_xyz = (int *) malloc(sizeof(int)*np) ;
5511 undo_bufnum = np ;
5512 }
5513
5514 /* compute (or copy) data index into undo_xyz */
5515
5516 if( yd == NULL ){ /* direct supply of index */
5517 memcpy(undo_xyz,xd,sizeof(int)*np) ;
5518 } else { /* collapse 3-index into 1 */
5519 for( ii=0 ; ii < np ; ii++ )
5520 undo_xyz[ii] = xd[ii] + yd[ii] * nx + zd[ii] * nxy ;
5521 }
5522
5523 /* actually copy data, based on type */
5524
5525 if( bfac == 0.0 ) bfac = 1.0 ;
5526 vload = value_float ;
5527
5528 /* RCR - code for interpolation */
5529 if ( ! gRI.afni_undo &&
5530 ( ( mode_ival == MODE_CURVE ) || ( mode_ival == MODE_CLOSED ) ||
5531 ( mode_ival == MODE_CONN_PTS ) )
5532 )
5533 {
5534 /* insert the points into the interpolation structure */
5535
5536 int count, coord;
5537 int * ipA, * ipB, * ipc;
5538 points_t * Bp, tmpB;
5539
5540 if ( gRI.A.used == 0 ) /* if first IP set is empty, use it */
5541 Bp = &gRI.A;
5542 else if ( gRI.B.used == 0 ) /* else, similarly for second */
5543 Bp = &gRI.B;
5544 else /* else, move 2->1 and use second */
5545 {
5546 tmpB = gRI.A; /* swap and empty new one */
5547 gRI.A = gRI.B;
5548 gRI.B = tmpB;
5549 gRI.B.used = 0;
5550
5551 Bp = &gRI.B;
5552 }
5553
5554 for ( count = 0; count < np; count++ )
5555 {
5556 coord = undo_xyz[ count ];
5557
5558 if ( coord >= 0 && coord < nxyz )
5559 r_add_to_boundary( Bp, coord );
5560 }
5561 }
5562
5563 switch( ityp ){
5564
5565 default: fprintf(stderr,"Illegal brick type=%s in AFNI Editor!\n",
5566 MRI_TYPE_name[ityp] ) ;
5567 break ;
5568
5569 case MRI_short:{
5570 short * bp = (short *) DSET_BRICK_ARRAY(dset,0) ;
5571 short * up = (short *) undo_buf ;
5572 short * vvv = (short *) var ;
5573 short val = (short) (value_float/bfac) ;
5574
5575 for( ii=0 ; ii < np ; ii++ ){ /* save into undo buffer */
5576 ixyz = undo_xyz[ii] ;
5577 up[ii] = (ixyz >= 0 && ixyz < nxyz) ? bp[ixyz] : 0 ;
5578 }
5579
5580 for( ii=0 ; ii < np ; ii++ ){ /* put into dataset */
5581 ixyz = undo_xyz[ii] ;
5582 if( ixyz >= 0 && ixyz < nxyz )
5583 bp[ixyz] = (vvv==NULL) ? val : vvv[ii] ;
5584 }
5585 }
5586 break ;
5587
5588 case MRI_byte:{
5589 byte * bp = (byte *) DSET_BRICK_ARRAY(dset,0) ;
5590 byte * up = (byte *) undo_buf ;
5591 byte * vvv = (byte *) var ;
5592 byte val = (byte) (value_float/bfac) ;
5593
5594 for( ii=0 ; ii < np ; ii++ ){
5595 ixyz = undo_xyz[ii] ;
5596 up[ii] = (ixyz >= 0 && ixyz < nxyz) ? bp[ixyz] : 0 ;
5597 }
5598 for( ii=0 ; ii < np ; ii++ ){
5599 ixyz = undo_xyz[ii] ;
5600 if( ixyz >= 0 && ixyz < nxyz )
5601 bp[ixyz] = (vvv==NULL) ? val : vvv[ii] ;
5602 }
5603 }
5604 break ;
5605
5606 case MRI_float:{
5607 float * bp = (float *) DSET_BRICK_ARRAY(dset,0) ;
5608 float * up = (float *) undo_buf ;
5609 float * vvv = (float *) var ;
5610 float val = (value_float/bfac) ;
5611
5612 for( ii=0 ; ii < np ; ii++ ){
5613 ixyz = undo_xyz[ii] ;
5614 up[ii] = (ixyz >= 0 && ixyz < nxyz) ? bp[ixyz] : 0.0 ;
5615 }
5616 for( ii=0 ; ii < np ; ii++ ){
5617 ixyz = undo_xyz[ii] ;
5618 if( ixyz >= 0 && ixyz < nxyz )
5619 bp[ixyz] = (vvv==NULL) ? val : vvv[ii] ;
5620 }
5621 }
5622 break ;
5623
5624 case MRI_complex:{
5625 complex * bp = (complex *) DSET_BRICK_ARRAY(dset,0) ;
5626 complex * up = (complex *) undo_buf ;
5627 complex * vvv = (complex *) var ;
5628 complex val ;
5629 static complex cxzero = { 0.0 , 0.0 } ;
5630
5631 val = CMPLX( (value_float/bfac) , 0.0 ) ;
5632
5633 for( ii=0 ; ii < np ; ii++ ){
5634 ixyz = undo_xyz[ii] ;
5635 up[ii] = (ixyz >= 0 && ixyz < nxyz) ? bp[ixyz] : cxzero ;
5636 }
5637 for( ii=0 ; ii < np ; ii++ ){
5638 ixyz = undo_xyz[ii] ;
5639 if( ixyz >= 0 && ixyz < nxyz )
5640 bp[ixyz] = (vvv==NULL) ? val : vvv[ii] ;
5641 }
5642 }
5643 break ;
5644
5645 } /* end of switch on brick type */
5646
5647 /* recompute statistics, if the loaded value is big or small */
5648
5649 if( !ISVALID_STATISTIC(dset->stats) ||
5650 vload > dset->stats->bstat[0].max ||
5651 vload < dset->stats->bstat[0].min ) THD_load_statistics( dset ) ;
5652
5653 /* now redisplay dataset, in case anyone is looking at it */
5654
5655 PLUTO_dset_redisplay( dset ) ;
5656
5657 undo_bufuse = np ;
5658 dset_changed = 1 ;
5659 SENSITIZE(save_pb,1) ;
5660 SENSITIZE(choose_pb,0) ;
5661 SENSITIZE(undo_pb,1) ;
5662
5663 EXRETURN ;
5664 }
5665
5666 /*---------------------------------------------------------------------------
5667 Flood filling a byte array:
5668 nx = 1st dimension
5669 ny = 2nd dimension
5670 ix = start point
5671 jy = end point
5672 ar = array, with 0's everwhere except 1's as barriers to flooding
5673
5674 All filled points (starting with ix,jy) will get the value 2.
5675 -----------------------------------------------------------------------------*/
5676
DRAW_2dfiller(int nx,int ny,int ix,int jy,byte * ar)5677 static void DRAW_2dfiller( int nx , int ny , int ix , int jy , byte * ar )
5678 {
5679 int ii,jj , ip,jp , num ;
5680
5681 ENTRY("DRAW_2dfiller");
5682
5683 #define AR(i,j) ar[(i)+(j)*nx]
5684
5685 /* fill out in cross from 1st point */
5686
5687 ip = ix ; jp = jy ; AR(ip,jp) = 2 ;
5688
5689 for( ii=ip+1; ii < nx && AR(ii,jp) == 0; ii++ ) AR(ii,jp) = 2;
5690 for( ii=ip-1; ii >= 0 && AR(ii,jp) == 0; ii-- ) AR(ii,jp) = 2;
5691 for( jj=jp+1; jj < ny && AR(ip,jj) == 0; jj++ ) AR(ip,jj) = 2;
5692 for( jj=jp-1; jj >= 0 && AR(ip,jj) == 0; jj-- ) AR(ip,jj) = 2;
5693
5694 /* brute force repetition of the cross technique */
5695
5696 do {
5697 num = 0 ;
5698 for( jp=0 ; jp < ny ; jp++ ){
5699 for( ip=0 ; ip < nx ; ip++ ){
5700 if( AR(ip,jp) == 2 ){
5701 for( ii=ip+1; ii < nx && AR(ii,jp) == 0; ii++ ){ AR(ii,jp) = 2; num++; }
5702 for( ii=ip-1; ii >= 0 && AR(ii,jp) == 0; ii-- ){ AR(ii,jp) = 2; num++; }
5703 for( jj=jp+1; jj < ny && AR(ip,jj) == 0; jj++ ){ AR(ip,jj) = 2; num++; }
5704 for( jj=jp-1; jj >= 0 && AR(ip,jj) == 0; jj-- ){ AR(ip,jj) = 2; num++; }
5705 }
5706 }
5707 }
5708 } while( num > 0 ) ;
5709
5710 EXRETURN ;
5711 }
5712
5713