Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

plug_roiedit.c

Go to the documentation of this file.
00001 /*****************************************************************************
00002    Major portions of this software are copyrighted by the Medical College
00003    of Wisconsin, 1994-2000, and are released under the Gnu General Public
00004    License, Version 2.  See the file README.Copyright for details.
00005 ******************************************************************************/
00006    
00007 /***********************************************************************
00008  *
00009  * plug_roiedit.c               - a region of interest editor (afni plugin)
00010  *
00011  * Rick Reynolds
00012  * Medical College of WI
00013  *
00014  *************
00015  * history:
00016  *
00017  * October 7, 2003  [rickr]
00018  *   - renamed old and new fields of r_alg_s to Bold and Bnew
00019  * June 10, 2005 [rickr]
00020  *   - added lots of ENTRY/RETURN pairs
00021  *   - continue on 'set fill point' with no data
00022  *   - use DSET_load in case use has not opened afni windows yet
00023  ***********************************************************************
00024  */
00025 
00026 #include <Xm/FileSB.h>
00027 
00028 #include "afni.h"
00029 
00030 #ifndef ALLOW_PLUGINS
00031 #  error "Plugins not properly set up -- see machdep.h"
00032 #endif
00033 
00034 #include "plug_roiedit.h"               /* RCR stuff */
00035 
00036 /***********************************************************************
00037   Plugin to draw values into a dataset.
00038   Makes a custom interface.
00039 ************************************************************************/
00040 
00041 /*---------- prototypes for internal routines ----------*/
00042 
00043 static char * DRAW_main( PLUGIN_interface * ) ;
00044 
00045 static void DRAW_make_widgets(void) ;
00046 
00047 static void DRAW_done_CB  ( Widget , XtPointer , XtPointer ) ;
00048 static void DRAW_undo_CB  ( Widget , XtPointer , XtPointer ) ;
00049 static void DRAW_help_CB  ( Widget , XtPointer , XtPointer ) ;
00050 static void DRAW_quit_CB  ( Widget , XtPointer , XtPointer ) ;
00051 static void DRAW_save_CB  ( Widget , XtPointer , XtPointer ) ;
00052 static void DRAW_choose_CB( Widget , XtPointer , XtPointer ) ;
00053 static void DRAW_color_CB ( MCW_arrowval * , XtPointer ) ;
00054 static void DRAW_mode_CB  ( MCW_arrowval * , XtPointer ) ;
00055 static void DRAW_value_CB ( MCW_arrowval * , XtPointer ) ;
00056 
00057 static void DRAW_receiver( int , int , void * , void * ) ;
00058 static void DRAW_into_dataset( int , int * , int * , int * , void * ) ;
00059 static void DRAW_finalize_dset_CB( Widget , XtPointer , MCW_choose_cbs * ) ;
00060 static void DRAW_2dfiller( int nx , int ny , int ix , int jy , byte * ar ) ;
00061 
00062 static PLUGIN_interface * plint = NULL ;
00063 
00064 /***********************************************************************
00065    Set up the interface to the user.  Note that we bypass the
00066    normal interface creation, and simply have the menu selection
00067    directly call the main function, which will create a custom
00068    set of interface widgets.
00069 ************************************************************************/
00070 
00071 
00072 DEFINE_PLUGIN_PROTOTYPE
00073 
00074 PLUGIN_interface * PLUGIN_init( int ncall )
00075 {
00076    if( ncall > 0 ) return NULL ;  /* only one interface */
00077 
00078    plint = PLUTO_new_interface( "Gyrus Finder" , NULL , NULL ,
00079                                 PLUGIN_CALL_IMMEDIATELY , DRAW_main ) ;
00080 
00081    PLUTO_add_hint( plint , "Interactive Region of Interest Editor" ) ;
00082 
00083    PLUTO_set_sequence( plint , "z:Reynolds" ) ;
00084 
00085    return plint ;
00086 }
00087 
00088 /***************************************************************************
00089   Will be called from AFNI when user selects from Plugins menu.
00090 ****************************************************************************/
00091 
00092 /* Interface widgets */
00093 
00094 static Widget shell=NULL , rowcol , info_lab , choose_pb ;
00095 static Widget done_pb , undo_pb , help_pb , quit_pb , save_pb ;
00096 static MCW_arrowval * value_av , * color_av , * mode_av ;
00097 
00098 /* Other data */
00099 
00100 #define MODE_CURVE       0
00101 #define MODE_CLOSED      1
00102 #define MODE_POINTS      2
00103 #define MODE_FLOOD_VAL   3
00104 #define MODE_FLOOD_NZ    4
00105 #define MODE_VOL_FILL    5
00106 #define MODE_CONN_PTS    6
00107 
00108 static char * mode_strings[] = {
00109   "Open Curve" , "Closed Curve" , "Points" , "Flood->Value",
00110   "Flood->Nonzero", "Set Fill Point", "Connect Points" };
00111 
00112 static int    mode_ints[] = {
00113   DRAWING_LINES , DRAWING_FILL , DRAWING_POINTS , DRAWING_POINTS ,
00114   DRAWING_POINTS, DRAWING_POINTS, DRAWING_POINTS };
00115 
00116 #define NUM_modes (sizeof(mode_ints)/sizeof(int))
00117 
00118 static MCW_DC * dc ;                /* display context */
00119 static Three_D_View * im3d ;        /* AFNI controller */
00120 static THD_3dim_dataset * dset ;    /* The dataset!    */
00121 
00122 static int   color_index = 1 ;               /* from color_av */
00123 static int   mode_ival   = MODE_CURVE ;
00124 static int   mode_index  = DRAWING_LINES ;   /* from mode_av  */
00125 static int   value_int   = 1 ;               /* from value_av */
00126 static float value_float = 1.0 ;             /* ditto         */
00127 
00128 static int editor_open  = 0 ;
00129 static int dset_changed = 0 ;
00130 static int recv_open    = 0 ;
00131 static int recv_key     = -1 ;   /* 15 Jun 1999 by RWCox */
00132 
00133 static int undo_bufsiz = 0 ;     /* size of undo_buf in bytes */
00134 static int undo_bufnum = 0 ;     /* size of undo_xyz in ints */
00135 static int undo_bufuse = 0 ;     /* number of entries in undo buffer */
00136 static void * undo_buf = NULL ;  /* stores data to be copied back to dataset */
00137 static int  * undo_xyz = NULL ;  /* stores voxel indices for copying */
00138 
00139 static THD_dataxes dax_save ;    /* save this for later referenc */
00140 
00141 char * DRAW_main( PLUGIN_interface * plint )
00142 {
00143    XmString xstr ;
00144 
00145    ENTRY("DRAW_main");
00146 
00147 #if 0
00148    /* RCR - this plugin is not authorized outside of the mcw domain */
00149    if ( ! r_check_host( ) )
00150       return NULL;
00151 #endif
00152 
00153    /*-- sanity checks --*/
00154 
00155    if( ! IM3D_OPEN(plint->im3d) ) RETURN( "AFNI Controller\nnot opened?!") ;
00156 
00157    if( editor_open )
00158    {
00159       XMapRaised( XtDisplay(shell) , XtWindow(shell) ) ;
00160 
00161       if ( gRX.main_is_open )
00162       {
00163           XMapRaised( XtDisplay( gRX.main ) , XtWindow( gRX.main ) ) ;
00164       }
00165       else
00166       {
00167           XtMapWidget( gRX.main );
00168           gRX.main_is_open = 1;
00169       }
00170 
00171       RETURN(NULL);
00172    }
00173 
00174    im3d = plint->im3d ;  /* save for local use */
00175 
00176    /*-- create widgets, first time through --*/
00177 
00178    if( shell == NULL ){
00179       dc = im3d->dc ;        /* save this too */
00180       DRAW_make_widgets() ;
00181       PLUTO_set_topshell( plint , shell ) ;  /* 22 Sep 2000 */
00182       RWC_visibilize_widget( shell ) ;       /* 27 Sep 2000 */
00183    }
00184 
00185    /*-- set titlebar --*/
00186 
00187    { static char clabel[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ" ; /* see afni_func.c */
00188      char ttl[PLUGIN_STRING_SIZE] ; int ic ;
00189 
00190      ic = AFNI_controller_index(im3d) ;  /* find out which controller */
00191 
00192      if( ic >=0 && ic < 26 ){
00193         sprintf( ttl , "'AFNI' GyrusFinder [%c]" , clabel[ic] ) ;
00194         XtVaSetValues( shell , XmNtitle , ttl , NULL ) ;
00195      }
00196    }
00197 
00198    /*-- set the info label --*/
00199 
00200    xstr = XmStringCreateLtoR( "[No dataset]" ,
00201                               XmFONTLIST_DEFAULT_TAG ) ;
00202    XtVaSetValues( info_lab , XmNlabelString , xstr , NULL ) ;
00203    XmStringFree(xstr) ;
00204 
00205    /*-- pop the widget up --*/
00206 
00207    XtMapWidget(shell) ;
00208 
00209    if ( gRX.main_is_open )
00210    {
00211       XMapRaised( XtDisplay( gRX.main ) , XtWindow( gRX.main ) ) ;
00212    }
00213    else
00214    {
00215       XtMapWidget( gRX.main );
00216       gRX.main_is_open = 1;
00217    }
00218 
00219 
00220    /*-- misc initialization --*/
00221 
00222    dset         = NULL ;   /* not editing anything   */
00223    dset_changed = 0 ;      /* not yet changed */
00224    editor_open  = 1 ;      /* editor is now open for business */
00225    recv_open    = 0 ;      /* receiver is not yet open */
00226    recv_key     = -1;
00227 
00228    SENSITIZE(undo_pb,0) ;  undo_bufuse = 0 ;
00229    SENSITIZE(save_pb,0) ;
00230    SENSITIZE(choose_pb,1) ;
00231 
00232    RETURN(NULL) ;
00233 }
00234 
00235 /*------------------------------------------------------------------------
00236   Make the control popup for this thing
00237 --------------------------------------------------------------------------*/
00238 
00239 /*-- structures defining action buttons (at bottom of popup) --*/
00240 
00241 #define NACT 5  /* number of action buttons */
00242 
00243 static MCW_action_item DRAW_actor[NACT] = {
00244  {"Undo",DRAW_undo_CB,NULL,
00245   "Undoes previous draw\naction, if possible","Undo last change",0} ,
00246 
00247  {"Help",DRAW_help_CB,NULL,
00248   "Displays more help" , "Displays more help",0} ,
00249 
00250  {"Quit",DRAW_quit_CB,NULL,
00251   "Discard edits since last Save\nand close Editor" ,
00252    "Discard edits and close",0} ,
00253 
00254  {"Save",DRAW_save_CB,NULL,
00255   "Save edits to disk\nand continue" , "Save to disk and continue",0} ,
00256 
00257  {"Done",DRAW_done_CB,NULL,
00258   "Save edits to disk\nand close Editor" , "Save and close",1}
00259 } ;
00260 
00261 static void DRAW_make_widgets(void)
00262 {
00263    XmString xstr ;
00264 
00265    ENTRY("DRAW_make_widgets");
00266 
00267    /*** top level shell for window manager ***/
00268 
00269    shell =
00270       XtVaAppCreateShell(
00271            "AFNI" , "AFNI" , topLevelShellWidgetClass , dc->display ,
00272            XmNtitle             , "GFinder Editor", /* top of window */
00273            XmNiconName          , "GFinder"       , /* label on icon */
00274            XmNdeleteResponse    , XmDO_NOTHING    , /* deletion handled below */
00275            XmNallowShellResize  , True ,            /* let code resize shell? */
00276            XmNmappedWhenManaged , False ,           /* must map it manually */
00277            XmNinitialResourcesPersistent , False ,
00278       NULL ) ;
00279 
00280    if( afni48_good )             /* set icon pixmap */
00281       XtVaSetValues( shell ,
00282                         XmNiconPixmap , afni48_pixmap ,
00283                      NULL ) ;
00284 
00285    if( MCW_isitmwm(shell) )      /* remove some MWM functions */
00286       XtVaSetValues( shell ,
00287                        XmNmwmFunctions ,
00288                        MWM_FUNC_MOVE | MWM_FUNC_CLOSE | MWM_FUNC_MINIMIZE ,
00289                      NULL ) ;
00290 
00291    XmAddWMProtocolCallback(      /* make "Close" window menu work */
00292            shell ,
00293            XmInternAtom( dc->display , "WM_DELETE_WINDOW" , False ) ,
00294            DRAW_quit_CB , (XtPointer) plint ) ;
00295 
00296    /*** rowcolumn widget to hold all user interface stuff ***/
00297 
00298    rowcol = XtVaCreateWidget(
00299              "AFNI" , xmRowColumnWidgetClass , shell ,
00300                 XmNpacking     , XmPACK_TIGHT ,
00301                 XmNorientation , XmVERTICAL ,
00302                 XmNtraversalOn , False ,
00303                 XmNinitialResourcesPersistent , False ,
00304              NULL ) ;
00305 
00306    /*** label at top to let user know who we are ***/
00307 
00308    xstr = XmStringCreateLtoR( "[No dataset]" ,
00309                               XmFONTLIST_DEFAULT_TAG ) ;
00310    info_lab = XtVaCreateManagedWidget(
00311                  "AFNI" , xmLabelWidgetClass , rowcol ,
00312                     XmNlabelString , xstr ,
00313                     XmNinitialResourcesPersistent , False ,
00314                  NULL ) ;
00315    XmStringFree(xstr) ;
00316    MCW_register_help( info_lab , "Shows dataset being edited" ) ;
00317    MCW_register_hint( info_lab , "Shows dataset being edited" ) ;
00318 
00319    /*** separator for visual neatness ***/
00320 
00321    (void) XtVaCreateManagedWidget(
00322              "AFNI" , xmSeparatorWidgetClass , rowcol ,
00323                 XmNseparatorType , XmSINGLE_LINE ,
00324                 XmNinitialResourcesPersistent , False ,
00325              NULL ) ;
00326 
00327    /*** button to let user choose dataset to edit ***/
00328 
00329    xstr = XmStringCreateLtoR( "Choose Dataset" , XmFONTLIST_DEFAULT_TAG ) ;
00330    choose_pb = XtVaCreateManagedWidget(
00331                   "AFNI" , xmPushButtonWidgetClass , rowcol ,
00332                      XmNlabelString , xstr ,
00333                      XmNtraversalOn , False ,
00334                      XmNinitialResourcesPersistent , False ,
00335                   NULL ) ;
00336    XmStringFree(xstr) ;
00337    XtAddCallback( choose_pb, XmNactivateCallback, DRAW_choose_CB, NULL ) ;
00338    MCW_register_help( choose_pb ,
00339                       "Use this to popup a\n"
00340                       "'chooser' that lets\n"
00341                       "you select which\n"
00342                       "dataset to edit."
00343                     ) ;
00344    MCW_register_hint( choose_pb , "Popup a dataset chooser" ) ;
00345 
00346    /***  arrowval to choose value that is drawn into dataset voxels  ***/
00347 
00348    value_av = new_MCW_arrowval( rowcol , "Drawing Value " ,
00349                                 MCW_AV_downup , -32767,32767,value_int ,
00350                                 MCW_AV_editext , 0 ,
00351                                 DRAW_value_CB , NULL , NULL,NULL ) ;
00352 
00353    MCW_reghelp_children( value_av->wrowcol ,
00354                          "Use this to set the value that\n"
00355                          "will be drawn into the dataset\n"
00356                          "using mouse button 2."
00357                        ) ;
00358    MCW_reghint_children( value_av->wrowcol , "Goes into dataset voxels" ) ;
00359 
00360    /*** option menu to choose drawing color ***/
00361 
00362    color_av = new_MCW_colormenu( rowcol , "Drawing Color " , dc ,
00363                                  1 , dc->ovc->ncol_ov - 1 , color_index ,
00364                                  DRAW_color_CB , NULL ) ;
00365 
00366    MCW_reghelp_children( color_av->wrowcol ,
00367                          "Use this to set the color that is\n"
00368                          "shown during mouse button 2 drawing.\n"
00369                          "N.B.: After drawing is completed,\n"
00370                          "  the dataset will be displayed\n"
00371                          "  with the chosen value replacing\n"
00372                          "  the drawing color.  This color\n"
00373                          "  is used ONLY while button 2 is\n"
00374                          "  actually pressed down."
00375                        ) ;
00376    MCW_reghint_children( color_av->wrowcol , "Used when button 2 is drawing" ) ;
00377 
00378    /*** arrowval to choose drawing mode ***/
00379 
00380    mode_av = new_MCW_optmenu( rowcol , "Drawing Mode  " ,
00381                               0 , NUM_modes-1 , 0,0 ,
00382                               DRAW_mode_CB , NULL ,
00383                               MCW_av_substring_CB , mode_strings ) ;
00384 
00385    MCW_reghelp_children( mode_av->wrowcol ,
00386                          "Use this to set the way in which\n"
00387                          "drawing pixels on the screen is\n"
00388                          "used to select dataset voxels:\n"
00389                          "Open Curve     = voxels picked along lines drawn;\n"
00390                          "Closed Curve   = voxels forming a closed curve\n"
00391                          "Points         = only voxels at X11 notify pixels;\n"
00392                          "Flood->Value   = flood fill from the chosen point\n"
00393                          "                 out to points = Drawing Value\n"
00394                          "Flood->Nonzero = flood fill from chosen point out\n"
00395                          "                 to any nonzero point"
00396                        ) ;
00397    MCW_reghint_children( mode_av->wrowcol , "How voxels are chosen") ;
00398 
00399    /*** separator for visual neatness ***/
00400 
00401    (void) XtVaCreateManagedWidget(
00402              "AFNI" , xmSeparatorWidgetClass , rowcol ,
00403                 XmNseparatorType , XmSINGLE_LINE ,
00404                 XmNinitialResourcesPersistent , False ,
00405              NULL ) ;
00406 
00407    /*** a set of action buttons below the line ***/
00408 
00409    (void) MCW_action_area( rowcol , DRAW_actor , NACT ) ;
00410 
00411    undo_pb = (Widget) DRAW_actor[0].data ;
00412    help_pb = (Widget) DRAW_actor[1].data ;
00413    quit_pb = (Widget) DRAW_actor[2].data ;
00414    save_pb = (Widget) DRAW_actor[3].data ;
00415    done_pb = (Widget) DRAW_actor[4].data ;
00416 
00417    /*** that's all  (for Bob) ***/
00418 
00419    XtManageChild(rowcol) ;
00420    XtRealizeWidget(shell) ;             /* will not be mapped */
00421 
00422    r_main_mk_main_shell( );
00423 
00424    EXRETURN;
00425 }
00426 
00427 
00428 /*----------------------------------------------------------------------
00429 **
00430 **  Check the hostname of the computer.  If the name is not part of the
00431 **  mcw.edu domain, then the machine is not authorized to use this plugin.
00432 **
00433 **----------------------------------------------------------------------
00434  */
00435 #if 0
00436 static int
00437 r_check_host( void )
00438 {
00439     long hostid = 0;
00440 
00441     hostid = gethostid( );
00442 
00443     if ( ( hostid & R_HOSTID_MASK ) != R_HOSTID_VAL )
00444     {
00445         rERROR( "Your machine is not currently authorized to use this plugin.");
00446 
00447         system( "echo GF usage :`whoami`@`hostname`|mail rickr@mcw.edu" );
00448 
00449         return 0;
00450     }
00451 
00452     return 1;
00453 }
00454 #endif
00455 
00456 /*----------------------------------------------------------------------
00457 **
00458 **  Create main GyrusFinder shell.
00459 **
00460 **----------------------------------------------------------------------
00461  */
00462 static void
00463 r_main_mk_main_shell( void )
00464 {
00465     ENTRY("r_main_mk_main_shell");
00466 #ifdef R_LOG_INFO_D
00467     if ( ! r_open_log_file( ) )
00468         return 0;
00469 #endif
00470 
00471     r_wtgr_mk_main_shell  ( &gRX );
00472     r_INT_mk_main_shell   ( &gRI );             /* interpolation shell */
00473     r_HL_mk_main_shell    ( &gRH );             /* hole filler shell */
00474     r_main_mk_show_buttons( );
00475 
00476     EXRETURN;
00477 }
00478 
00479 
00480 #ifdef R_LOG_INFO_D
00481 /*----------------------------------------------------------------------
00482 **
00483 **  Open R_LOG_FILE to log messages to.
00484 **
00485 **----------------------------------------------------------------------
00486  */
00487 static int
00488 r_open_log_file( void )
00489 {
00490     if ( ( gr_logfile = fopen( R_LOG_FILE, "a" ) ) == NULL )
00491     {
00492         sprintf( gRmessage, "Failed to open '%s' for append.", R_LOG_FILE );
00493         rERROR( gRmessage );
00494 
00495         return 0;
00496     }
00497 
00498     return 1;
00499 }
00500 #endif
00501 
00502 
00503 /*----------------------------------------------------------------------
00504 **
00505 **  Main window for buttons to show other windows.
00506 **
00507 **----------------------------------------------------------------------
00508  */
00509 static void
00510 r_main_mk_show_buttons( void )
00511 {
00512     int      ac;
00513     Arg      al[ 10 ];
00514     Widget   button, tmpb, tmpb2;
00515     XmString xstr;
00516 
00517     ENTRY("r_main_mk_show_buttons");
00518 
00519     gRX.main_is_open = 1;
00520 
00521     ac = 0;
00522     XtSetArg( al[ac], XmNinitialResourcesPersistent, False );  ac++;
00523     XtSetArg( al[ac], XmNdeleteResponse, XmDO_NOTHING );  ac++;
00524     gRX.main = XtAppCreateShell( "GyrusFinder", "rshell",
00525                         topLevelShellWidgetClass, gRX.display, al, ac );
00526 
00527     XmAddWMProtocolCallback( gRX.main,
00528         XmInternAtom( gRX.display, "WM_DELETE_WINDOW", False ),
00529         ( XtCallbackProc )r_main_cb_quit, ( XtPointer )NULL );
00530 
00531     ac = 0;
00532     gRX.mainForm = XmCreateForm( gRX.main, "form", al, ac );
00533 
00534 
00535     /* raise interpolator button */
00536     ac = 0;
00537     XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER );  ac++;
00538     XtSetArg( al[ac], XmNwidth, 220 );  ac++;
00539     xstr = XmStringCreateLtoR( "Interpolator", gRX.charset );
00540     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
00541     button = XmCreatePushButton( gRX.mainForm, "INT", al, ac );
00542     XtManageChild( button );
00543     XtAddCallback( button, XmNactivateCallback,
00544                    ( XtCallbackProc )r_any_cb_raise, "INT" );
00545     XtSetSensitive( button, True );
00546     XmStringFree(xstr) ;
00547     tmpb = button;
00548 
00549     /* raise wtgr button */
00550     ac = 0;
00551     XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER );  ac++;
00552     XtSetArg( al[ac], XmNtopAttachment, XmATTACH_WIDGET );  ac++;
00553     XtSetArg( al[ac], XmNtopWidget, tmpb );  ac++;
00554     XtSetArg( al[ac], XmNwidth, 220 );  ac++;
00555     xstr = XmStringCreateLtoR( "White/Gray Finder", gRX.charset );
00556     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
00557     button = XmCreatePushButton( gRX.mainForm, "WhiteGray", al, ac );
00558     XtManageChild( button );
00559     XtAddCallback( button, XmNactivateCallback,
00560                    ( XtCallbackProc )r_any_cb_raise, "wtgr" );
00561     XtSetSensitive( button, True );
00562     XmStringFree( xstr );
00563     tmpb = button;
00564 
00565 
00566     /* raise holes button */
00567     ac = 0;
00568     XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER );  ac++;
00569     XtSetArg( al[ac], XmNtopAttachment, XmATTACH_WIDGET );  ac++;
00570     XtSetArg( al[ac], XmNtopWidget, tmpb );  ac++;
00571     XtSetArg( al[ac], XmNwidth, 220 );  ac++;
00572     xstr = XmStringCreateLtoR( "Hole Filler", gRX.charset );
00573     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
00574     button = XmCreatePushButton( gRX.mainForm, "fillholes", al, ac );
00575     XtManageChild( button );
00576     XtAddCallback( button, XmNactivateCallback,
00577                    ( XtCallbackProc )r_any_cb_raise, "HL" );
00578     XtSetSensitive( button, True );
00579     XmStringFree( xstr );
00580     tmpb = button;
00581 
00582 
00583     /* UNDO button */
00584 
00585     ac = 0;
00586     XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER );  ac++;
00587     XtSetArg( al[ac], XmNtopAttachment, XmATTACH_WIDGET );  ac++;
00588     XtSetArg( al[ac], XmNtopWidget, tmpb );  ac++;
00589     XtSetArg( al[ac], XmNwidth, 110 );  ac++;
00590     xstr = XmStringCreateLtoR( "UNDO", gRX.charset );
00591     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
00592     button = XmCreatePushButton( gRX.mainForm, "saveas", al, ac );
00593     XtManageChild( button );
00594     XtAddCallback( button, XmNactivateCallback,
00595                    ( XtCallbackProc )r_any_cb_undo, NULL );
00596     XtSetSensitive( button, True );
00597     XmStringFree( xstr );
00598     tmpb2 = button;
00599 
00600 
00601     /* save as button */
00602 
00603     ac = 0;
00604     XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER );  ac++;
00605     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
00606     XtSetArg( al[ac], XmNleftWidget, button );  ac++;
00607     XtSetArg( al[ac], XmNtopAttachment, XmATTACH_WIDGET );  ac++;
00608     XtSetArg( al[ac], XmNtopWidget, tmpb );  ac++;
00609     XtSetArg( al[ac], XmNwidth, 110 );  ac++;
00610     xstr = XmStringCreateLtoR( "Save As", gRX.charset );
00611     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
00612     button = XmCreatePushButton( gRX.mainForm, "saveas", al, ac );
00613     XtManageChild( button );
00614     XtAddCallback( button, XmNactivateCallback,
00615                    ( XtCallbackProc )r_any_cb_raise, "saveas" );
00616     XtSetSensitive( button, True );
00617     XmStringFree( xstr );
00618     tmpb = button;
00619 
00620     /*
00621     **  We're going to cheat a little here.  The "save as" widget will
00622     **  be implemented as a child of the main RC.  So we need to create
00623     **  the widget now, so the main "save as" button can raise/manage it.
00624     */
00625 
00626     r_main_mk_save_as_fr( gRX.mainForm );
00627 
00628 
00629     /* help button */
00630     ac = 0;
00631     XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER );  ac++;
00632     XtSetArg( al[ac], XmNtopAttachment, XmATTACH_WIDGET );  ac++;
00633     XtSetArg( al[ac], XmNtopWidget, tmpb2 );  ac++;
00634     XtSetArg( al[ac], XmNwidth, 110 );  ac++;
00635     xstr = XmStringCreateLtoR( "Help", gRX.charset );
00636     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
00637     button = XmCreatePushButton( gRX.mainForm, "help", al, ac );
00638     XtManageChild( button );
00639     XtAddCallback( button, XmNactivateCallback,
00640                    ( XtCallbackProc )r_main_cb_help, NULL );
00641     XtSetSensitive( button, True );
00642     XmStringFree( xstr );
00643 
00644 
00645     /* show data structures button */
00646     ac = 0;
00647     XtSetArg( al[ac], XmNalignment, XmALIGNMENT_CENTER );  ac++;
00648     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
00649     XtSetArg( al[ac], XmNleftWidget, button );  ac++;
00650     XtSetArg( al[ac], XmNtopAttachment, XmATTACH_WIDGET );  ac++;
00651     XtSetArg( al[ac], XmNtopWidget, tmpb );  ac++;
00652     XtSetArg( al[ac], XmNwidth, 110 );  ac++;
00653     xstr = XmStringCreateLtoR( "structs", gRX.charset );
00654     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
00655     button = XmCreatePushButton( gRX.mainForm, "structs", al, ac );
00656     XtManageChild( button );
00657     XtAddCallback( button, XmNactivateCallback,
00658                    ( XtCallbackProc )r_main_cb_show_structs, NULL );
00659     XtSetSensitive( button, True );
00660     XmStringFree( xstr );
00661 
00662 
00663     XtManageChild( gRX.mainForm );
00664     XtRealizeWidget( gRX.main );
00665 
00666     EXRETURN;
00667 }
00668 
00669 
00670 /*----------------------------------------------------------------------
00671 **
00672 **  Create the save as widget under the main RC.
00673 **
00674 **----------------------------------------------------------------------
00675  */
00676 static void
00677 r_main_mk_save_as_fr( Widget parent )
00678 {
00679     Widget   button, junk, hrc, vrc, frame;
00680     Arg      al[ 10 ];
00681     int      ac;
00682     char     string[ 25 ];
00683 
00684     ENTRY("r_main_mk_save_as_fr");
00685 
00686       XtVaSetValues( shell ,
00687                        XmNmwmFunctions ,
00688                        MWM_FUNC_MOVE | MWM_FUNC_CLOSE | MWM_FUNC_MINIMIZE ,
00689                      NULL ) ;
00690     ac = 0;
00691     XtSetArg( al[ ac ], XmNdialogTitle,
00692             XmStringCreateLtoR( "Save As", gRX.charset ) );  ac++;
00693     XtSetArg( al[ ac ], XmNtextString, 
00694             XmStringCreateLtoR( gRA.save_as_name, gRX.charset ) );  ac++;
00695     XtSetArg( al[ ac ], XmNselectionLabelString, 
00696             XmStringCreateLtoR( "AFNI prefix : ", gRX.charset ) );  ac++;
00697     XtSetArg( al[ ac ], XmNokLabelString, 
00698             XmStringCreateLtoR( "save", gRX.charset ) );            ac++;
00699     XtSetArg( al[ ac ], XmNapplyLabelString, 
00700             XmStringCreateLtoR( "overwrite", gRX.charset ) );       ac++;
00701     XtSetArg( al[ ac ], XmNcancelLabelString, 
00702             XmStringCreateLtoR( "hide", gRX.charset ) );            ac++;
00703     XtSetArg( al[ ac ], XmNminimizeButtons, True );                 ac++;
00704     XtSetArg( al[ac], XmNinitialResourcesPersistent, False );       ac++;
00705     XtSetArg( al[ac], XmNmappedWhenManaged, False );                ac++;
00706     XtSetArg( al[ac], XmNdeleteResponse, XmDO_NOTHING );            ac++;
00707     gRX.save_as_file_d = XmCreatePromptDialog( parent, "dialog", al, ac );
00708 
00709     XmAddWMProtocolCallback( gRX.save_as_file_d,
00710         XmInternAtom( gRX.display, "WM_DELETE_WINDOW", False ),
00711         ( XtCallbackProc )r_any_cb_hide, "saveas" );
00712 
00713     XtAddCallback( gRX.save_as_file_d, XmNokCallback, 
00714             ( XtCallbackProc )r_main_cb_saveas, ( XtPointer )0 );
00715     XtAddCallback( gRX.save_as_file_d, XmNapplyCallback, 
00716             ( XtCallbackProc )r_main_cb_saveas, ( XtPointer )1 );
00717     XtAddCallback( gRX.save_as_file_d, XmNcancelCallback, 
00718             ( XtCallbackProc )r_any_cb_hide, "saveas" );
00719 
00720     XtManageChild( XmSelectionBoxGetChild( gRX.save_as_file_d,
00721                                              XmDIALOG_APPLY_BUTTON ) );
00722     XtUnmanageChild( XmSelectionBoxGetChild( gRX.save_as_file_d,
00723                                              XmDIALOG_HELP_BUTTON ) );
00724 
00725     XtManageChild( gRX.save_as_file_d );
00726 
00727     VISIBILIZE_WHEN_MAPPED(gRX.save_as_file_d) ; /* 27 Sep 2000 */
00728 
00729     /*
00730     ** Once we prevent it from popping up immediately, set it to display
00731     ** anytime it's managed.
00732     */
00733     ac = 0;
00734     XtSetArg( al[ac], XmNmappedWhenManaged, True );  ac++;
00735     XtSetValues( gRX.save_as_file_d, al, ac );
00736 
00737     EXRETURN;
00738 }
00739 
00740 
00741 /*----------------------------------------------------------------------
00742 **
00743 **  Create main shell and gray and white matter function frames.
00744 **
00745 **----------------------------------------------------------------------
00746  */
00747 static void
00748 r_wtgr_mk_main_shell( r_X_s * X )
00749 {
00750     Widget    junk, frame, rc;
00751     XmString  xstring;
00752     Arg       al[ 20 ];
00753     int       ac;
00754 
00755     ENTRY("r_wtgr_mk_main_shell");
00756 
00757 /* create a main RC widget with four frame children */
00758     
00759     if ( ! r_init_Alg_values( &gRA ) )
00760         EXRETURN;
00761 
00762     if ( ! r_init_pt_conn_s( &gRCP ) )
00763         EXRETURN;
00764 
00765     X->display = dc->display;
00766     X->charset = XmSTRING_DEFAULT_CHARSET;
00767 
00768     ac = 0;
00769     XtSetArg( al[ac], XmNinitialResourcesPersistent, False );  ac++;
00770     XtSetArg( al[ac], XmNdeleteResponse, XmDO_NOTHING );  ac++;
00771     XtSetArg( al[ac], XmNmappedWhenManaged, False );  ac++;
00772     X->wtgr_main = XtAppCreateShell( "White/Gray Finder", "rshell",
00773                 topLevelShellWidgetClass, X->display, al, ac );
00774 
00775     XmAddWMProtocolCallback( gRX.wtgr_main,
00776         XmInternAtom( gRX.display, "WM_DELETE_WINDOW", False ),
00777         ( XtCallbackProc )r_any_cb_hide, "wtgr" );
00778 
00779     ac = 0;
00780     XtSetArg( al[ac], XmNspacing,      15 );  ac++;
00781     XtSetArg( al[ac], XmNmarginWidth,  10 );  ac++;
00782     XtSetArg( al[ac], XmNmarginHeight, 10 );  ac++;
00783     X->wtgr_mainRC = XmCreateRowColumn( X->wtgr_main, "rowcolumn", al, ac );
00784 
00785     /* create the main white and gray selection frames */
00786     ( void )r_wt_mk_main_frame( X, X->wtgr_mainRC );
00787     ( void )r_gr_mk_main_frame( X, X->wtgr_mainRC );
00788 
00789 
00790     XtManageChild( X->wtgr_mainRC );
00791     XtRealizeWidget( X->wtgr_main );
00792 
00793     EXRETURN ;
00794 }
00795 
00796 
00797 /*----------------------------------------------------------------------
00798 **
00799 **  Create the Hole Filler shell.
00800 **
00801 **----------------------------------------------------------------------
00802  */
00803 static void
00804 r_HL_mk_main_shell( holes_s * H )
00805 {
00806     Widget    junk, frame, rc;
00807     XmString  xstring;
00808     Arg       al[ 20 ];
00809     int       ac;
00810 
00811     ENTRY("r_HL_mk_main_shell");
00812 
00813     if ( ! r_init_holes_vals( H ) )
00814         EXRETURN;
00815 
00816     ac = 0;
00817     XtSetArg( al[ac], XmNinitialResourcesPersistent, False );  ac++;
00818     XtSetArg( al[ac], XmNdeleteResponse, XmDO_NOTHING );  ac++;
00819     XtSetArg( al[ac], XmNmappedWhenManaged, False );  ac++;
00820     H->main = XtAppCreateShell( "Hole Filler", "rshell",
00821                         topLevelShellWidgetClass, gRX.display, al, ac );
00822 
00823     XmAddWMProtocolCallback( gRH.main,
00824         XmInternAtom( gRX.display, "WM_DELETE_WINDOW", False ),
00825         ( XtCallbackProc )r_any_cb_hide, "HL" );
00826 
00827     ac = 0;
00828     XtSetArg( al[ac], XmNspacing,      15 );  ac++;
00829     XtSetArg( al[ac], XmNmarginWidth,  10 );  ac++;
00830     XtSetArg( al[ac], XmNmarginHeight, 10 );  ac++;
00831     H->mainRC = XmCreateRowColumn( H->main, "rowcolumn", al, ac );
00832 
00833     ( void )r_HL_mk_fillval_fr( H, H->mainRC );
00834     ( void )r_HL_mk_maxsize_fr( H, H->mainRC );
00835     ( void )r_HL_mk_buttons   ( H, H->mainRC );
00836 
00837     XtManageChild  ( H->mainRC );
00838     XtRealizeWidget( H->main );
00839 
00840     EXRETURN;
00841 }
00842 
00843 
00844 /*----------------------------------------------------------------------
00845 **
00846 **  Create buttons for the "hole filling" app.
00847 **
00848 **----------------------------------------------------------------------
00849  */
00850 static Widget
00851 r_HL_mk_buttons( holes_s * H, Widget parent )
00852 {
00853     int      ac;
00854     Arg      al[ 10 ];
00855     Widget   form, frame, button1, button2;
00856     XmString xstr;
00857 
00858     ENTRY("r_HL_mk_buttons");
00859 
00860     /* create frame to hold form and buttons */
00861     ac = 0;
00862     frame = XmCreateFrame( parent, "frame", al, ac );
00863 
00864     /* create form to hold push buttons */
00865     ac = 0;
00866     XtSetArg( al[ac], XmNhorizontalSpacing, R_BUTTON_SPACE );  ac++;
00867     form = XmCreateForm( frame, "form", al, ac );
00868 
00869 
00870     /* region fill button */
00871     ac = 0;
00872     xstr = XmStringCreateLtoR( "FILL", gRX.charset );
00873     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
00874     button1 = XmCreatePushButton( form, "fill", al, ac );
00875     XtManageChild( button1 );
00876     XtAddCallback( button1, XmNactivateCallback,
00877                    ( XtCallbackProc )r_HL_cb_fill, H );
00878     XtSetSensitive( button1, True );
00879     XmStringFree( xstr );
00880 
00881     /* unfill button */
00882     ac = 0;
00883     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
00884     XtSetArg( al[ac], XmNleftWidget, button1 );  ac++;
00885     xstr = XmStringCreateLtoR( "unfill", gRX.charset );
00886     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
00887     button2 = XmCreatePushButton( form, "unfill", al, ac );
00888     XtManageChild( button2 );
00889     XtAddCallback( button2, XmNactivateCallback,
00890                    ( XtCallbackProc )r_any_cb_unfill, &H->fill_val );
00891     XtSetSensitive( button2, True );
00892     XmStringFree( xstr );
00893 
00894 
00895     /* stats button */
00896     ac = 0;
00897     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
00898     XtSetArg( al[ac], XmNleftWidget, button2 );  ac++;
00899     xstr = XmStringCreateLtoR( "stats", gRX.charset );
00900     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
00901     button1 = XmCreatePushButton( form, "stats", al, ac );
00902     XtManageChild( button1 );
00903     XtAddCallback( button1, XmNactivateCallback,
00904                    ( XtCallbackProc )r_any_cb_fill_stats, &gRH.fill_val );
00905     XtSetSensitive( button1, True );
00906     XmStringFree( xstr );
00907 
00908     /* hide button */
00909     ac = 0;
00910     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
00911     XtSetArg( al[ac], XmNleftWidget, button1 );  ac++;
00912     xstr = XmStringCreateLtoR( "hide", gRX.charset );
00913     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
00914     button2 = XmCreatePushButton( form, "hide", al, ac );
00915     XtManageChild( button2 );
00916     XtAddCallback( button2, XmNactivateCallback,
00917                    ( XtCallbackProc )r_any_cb_hide, "HL" );
00918     XtSetSensitive( button2, True );
00919     XmStringFree( xstr );
00920 
00921 
00922     XtManageChild( form );
00923     XtManageChild( frame );
00924 
00925     RETURN( frame );
00926 }
00927 
00928 
00929 /*----------------------------------------------------------------------
00930 **
00931 **  Create the "max hole size" widget for hole filler window.
00932 **
00933 **----------------------------------------------------------------------
00934  */
00935 static Widget
00936 r_HL_mk_maxsize_fr( holes_s * H, Widget parent )
00937 {
00938     Widget   junk, rc, frame;
00939     XmString xstr;
00940     Arg      al[ 10 ];
00941     int      ac;
00942     char     string[ 15 ];
00943 
00944     ENTRY("r_HL_mk_maxsize_fr");
00945 
00946     ac = 0;
00947     frame = XmCreateFrame( parent, "frame", al, ac );
00948     
00949     ac = 0;
00950     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
00951     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
00952     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
00953 
00954 
00955     sprintf( string, "%d", H->max_size );
00956 
00957     ac = 0;
00958     xstr = XmStringCreateLtoR( "max size      : ", gRX.charset );
00959     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
00960     junk = XmCreateLabel( rc, "label", al, ac );
00961     XtManageChild( junk );
00962     XmStringFree( xstr );
00963 
00964     ac = 0;
00965     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
00966     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
00967     H->maxsize_w = XmCreateText( rc, "text", al, ac );
00968     XtManageChild( H->maxsize_w );
00969     XtAddCallback( H->maxsize_w, XmNactivateCallback, 
00970             ( XtCallbackProc )r_HL_cb_set_maxsize, NULL );
00971     XtAddCallback( H->maxsize_w, XmNlosingFocusCallback, 
00972             ( XtCallbackProc )r_HL_cb_set_maxsize, NULL );
00973     
00974     
00975     XtManageChild( rc );
00976     XtManageChild( frame );
00977 
00978     RETURN( frame );
00979 }
00980 
00981 
00982 /*----------------------------------------------------------------------
00983 **
00984 **  Create the "fill value" widget for hole filler window.
00985 **
00986 **----------------------------------------------------------------------
00987 */
00988 static Widget
00989 r_HL_mk_fillval_fr( holes_s * H, Widget parent )
00990 {
00991     Widget   junk, rc, frame;
00992     XmString xstr;
00993     Arg      al[ 10 ];
00994     int      ac;
00995     char     string[ 15 ];
00996 
00997     ENTRY("r_HL_mk_fillval_fr");
00998 
00999     ac = 0;
01000     frame = XmCreateFrame( parent, "frame", al, ac );
01001     
01002     ac = 0;
01003     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
01004     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
01005     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
01006 
01007 
01008     sprintf( string, "%d", H->fill_val );
01009 
01010     ac = 0;
01011     xstr = XmStringCreateLtoR( "fill value    : ", gRX.charset );
01012     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
01013     junk = XmCreateLabel( rc, "label", al, ac );
01014     XtManageChild( junk );
01015     XmStringFree( xstr );
01016 
01017     ac = 0;
01018     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
01019     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
01020     H->fillval_w = XmCreateText( rc, "text", al, ac );
01021     XtManageChild( H->fillval_w );
01022     XtAddCallback( H->fillval_w, XmNactivateCallback, 
01023             ( XtCallbackProc )r_HL_cb_set_fill_val, NULL );
01024     XtAddCallback( H->fillval_w, XmNlosingFocusCallback, 
01025             ( XtCallbackProc )r_HL_cb_set_fill_val, NULL );
01026     
01027     
01028     XtManageChild( rc );
01029     XtManageChild( frame );
01030 
01031     RETURN( frame );
01032 }
01033 
01034 
01035 /*----------------------------------------------------------------------
01036 **
01037 **  Initialize the holes_s structure.
01038 **
01039 **----------------------------------------------------------------------
01040  */
01041 static int
01042 r_init_holes_vals( holes_s * H )
01043 {
01044     ENTRY("r_init_holes_vals");
01045 
01046     H->max_size = 6;
01047     H->fill_val = 3;
01048 
01049     H->filled.points = NULL;
01050     H->filled.used   = 0;
01051     H->filled.M      = 0;
01052 
01053     RETURN(1);
01054 }
01055 
01056 
01057 /*----------------------------------------------------------------------
01058 **
01059 **  Fill all interior holes, subject to a size restriction.
01060 **
01061 **----------------------------------------------------------------------
01062  */
01063 static void
01064 r_HL_cb_fill(
01065         Widget w,
01066         XtPointer client_data,
01067         XtPointer call_data
01068         )
01069 {
01070     points_t   Marked, Search;
01071     holes_s  * H = (holes_s *)client_data;
01072     short    * fdata = gRA.fdata;
01073     short    * fptr, * uptr;
01074     int      * wgpts, *tmpp;
01075     int        count, fill_size, coord, status, pcount;
01076 
01077     ENTRY("r_HL_cb_fill");
01078 
01079     /* first store fdata to undo_data  */
01080     fptr = gRA.fdata; uptr = gRA.undo_data;
01081     for ( count = 0; count < gRA.nvox; count++ )
01082         *uptr++ = *fptr++;
01083 
01084 
01085     Search.points = Marked.points = NULL;
01086 
01087     /* add gRA.border and gr_edge to wtgr_edge */
01088     H->wtgr_edge.used = 0;
01089     for ( count = 0, wgpts = H->gr_edge.points;
01090           count < H->gr_edge.used;
01091           count++, wgpts++ )
01092         if ( ! r_add_to_boundary( &H->wtgr_edge, *wgpts ) )
01093             EXRETURN;
01094 
01095     for ( count = 0, wgpts = gRA.border.points;
01096           count < gRA.border.used;
01097           count++, wgpts++ )
01098         if ( ! r_add_to_boundary( &H->wtgr_edge, *wgpts ) )
01099             EXRETURN;
01100 
01101     /* for each point in white/gray boundary - try to grow */
01102     /* (watch for 3-D brick edges) */
01103     for ( count = 0, wgpts = H->wtgr_edge.points;
01104           count < H->wtgr_edge.used;
01105           count++, wgpts++ )
01106     {
01107 
01108         fill_size = 0;                  /* init for current fill region */
01109 
01110         fptr = fdata + *wgpts;          /* addr + coordinate (offset) */
01111         if ( *fptr )
01112            continue;
01113 
01114         if ( ! r_add_to_boundary( &Search, *wgpts ) )
01115             EXRETURN;
01116 
01117         while ( Search.used > 0 )
01118         {
01119             coord = Search.points[Search.used - 1];
01120             Search.used--;
01121 
01122             *(fdata + coord) = H->fill_val;     /* mark as found */
01123             if ( ! r_add_to_boundary( &Marked, coord ) )
01124                 EXRETURN;
01125 
01126             fill_size++;
01127 
01128             /* 1 = OK, 0 = BAD point found, -1 = memory error */
01129             if ( ( status = r_HL_check_neighbors( &Search, coord ) ) == -1 )
01130                 EXRETURN;
01131             
01132             if ( ( fill_size > H->max_size ) || ( status == 0 ) )
01133             {
01134                 status = 0;     /* if we enter through fill_size */
01135 
01136                 for ( pcount = 0, tmpp = Search.points;
01137                       pcount < Search.used;
01138                       pcount++, tmpp++ )
01139                     *(fdata + *tmpp) = R_HL_BAD_VAL;
01140 
01141                 Search.used = 0;        /* will terminate search loop */
01142 
01143                 for ( pcount = 0, tmpp = Marked.points;
01144                       pcount < Marked.used;
01145                       pcount++, tmpp++ )
01146                     *(fdata + *tmpp) = R_HL_BAD_VAL;
01147 
01148                 Marked.used = 0;
01149             }
01150         }
01151 
01152         Marked.used = 0;
01153     }
01154 
01155     /* reset all BAD_VAL points - we haven't saved them */
01156     for ( count = 0, fptr = fdata; count < gRA.nvox; count++, fptr++ )
01157         if ( *fptr == R_HL_BAD_VAL )
01158             *fptr = 0;
01159 
01160 
01161     THD_load_statistics( gRA.func ) ;
01162     PLUTO_dset_redisplay( gRA.func ) ;
01163 
01164     dset_changed = 1;
01165 
01166     EXRETURN;
01167 }
01168 
01169 
01170 /*----------------------------------------------------------------------
01171 **
01172 **  Check neighbors for insertion into searchlist, or for BAD values.
01173 **
01174 **  Make sure we don't "leave" the 3-D image.
01175 **
01176 **  return 1 - normal
01177 **         0 - BAD point found
01178 **        -1 - memory error ( r_add_to_boundary() )
01179 **
01180 **----------------------------------------------------------------------
01181  */
01182 static int
01183 r_HL_check_neighbors( points_t * P, int coord )
01184 {
01185     short * nptr  = gRA.neighbors;
01186     short * fvalp = NULL;
01187     int     nx, nxy, value;
01188 
01189     ENTRY("r_HL_check_neighbors");
01190 
01191     nx  = gRA.nx;
01192     nxy = gRA.nxy;
01193 
01194     if ( nptr[ coord ] == -1 )  /* do not accept edge points */
01195         RETURN(1);  /* normal return */
01196 
01197     fvalp = gRA.fdata + coord;
01198 
01199     value = *(fvalp - 1);
01200     if ( value == R_HL_BAD_VAL )
01201         RETURN(0);
01202     else if ( ! value )
01203         if ( ! r_add_to_boundary( P, coord - 1 ) )
01204             RETURN(-1);
01205 
01206     value = *(fvalp + 1);
01207     if ( value == R_HL_BAD_VAL )
01208         RETURN(0);
01209     else if ( ! value )
01210         if ( ! r_add_to_boundary( P, coord + 1 ) )
01211             RETURN(-1);
01212 
01213     value = *(fvalp - nx);
01214     if ( value == R_HL_BAD_VAL )
01215         RETURN(0);
01216     else if ( ! value )
01217         if ( ! r_add_to_boundary( P, coord - nx ) )
01218             RETURN(-1);
01219 
01220     value = *(fvalp + nx);
01221     if ( value == R_HL_BAD_VAL )
01222         RETURN(0);
01223     else if ( ! value )
01224         if ( ! r_add_to_boundary( P, coord + nx ) )
01225             RETURN(-1);
01226 
01227     value = *(fvalp - nxy);
01228     if ( value == R_HL_BAD_VAL )
01229         RETURN(0);
01230     else if ( ! value )
01231         if ( ! r_add_to_boundary( P, coord - nxy ) )
01232             RETURN(-1);
01233 
01234     value = *(fvalp + nxy);
01235     if ( value == R_HL_BAD_VAL )
01236         RETURN(0);
01237     else if ( ! value )
01238         if ( ! r_add_to_boundary( P, coord + nxy ) )
01239             RETURN(-1);
01240 
01241     RETURN(0);
01242 }
01243 
01244 
01245 /*----------------------------------------------------------------------
01246 **
01247 **  Create interpolation shell.
01248 **
01249 **----------------------------------------------------------------------
01250  */
01251 static void
01252 r_INT_mk_main_shell( interp_s * I )
01253 {
01254     Widget    junk, frame, rc;
01255     XmString  xstring;
01256     Arg       al[ 20 ];
01257     int       ac;
01258 
01259     ENTRY("r_INT_mk_main_shell");
01260 
01261     if ( ! r_init_interp_vals( I ) )
01262         EXRETURN;
01263 
01264     ac = 0;
01265     XtSetArg( al[ac], XmNinitialResourcesPersistent, False );  ac++;
01266     XtSetArg( al[ac], XmNdeleteResponse, XmDO_NOTHING );  ac++;
01267     XtSetArg( al[ac], XmNmappedWhenManaged, False );  ac++;
01268     I->main = XtAppCreateShell( "The Interpolator",
01269                 "rshell", topLevelShellWidgetClass, gRX.display, al, ac );
01270 
01271     XmAddWMProtocolCallback( I->main,
01272         XmInternAtom( gRX.display, "WM_DELETE_WINDOW", False ),
01273         ( XtCallbackProc )r_any_cb_hide, "INT" );
01274 
01275     ac = 0;
01276     XtSetArg( al[ac], XmNspacing,      15 );  ac++;
01277     XtSetArg( al[ac], XmNmarginWidth,  10 );  ac++;
01278     XtSetArg( al[ac], XmNmarginHeight, 10 );  ac++;
01279     I->mainRC = XmCreateRowColumn( I->main, "rowcolumn", al, ac );
01280 
01281     /* create the main white and gray selection frames */
01282     ( void )r_INT_mk_fillval_fr ( I, I->mainRC );
01283     ( void )r_INT_mk_app_buttons( I, I->mainRC );
01284 
01285     XtManageChild( I->mainRC );
01286     XtRealizeWidget( I->main );
01287 
01288     EXRETURN ;
01289 }
01290 
01291 
01292 /*----------------------------------------------------------------------
01293 **
01294 **  Create boundary (gray matter) buttons.
01295 **
01296 **----------------------------------------------------------------------
01297  */
01298 static Widget
01299 r_INT_mk_app_buttons( interp_s * I, Widget parent )
01300 {
01301     int      ac;
01302     Arg      al[ 10 ];
01303     Widget   form, frame, button1, button2;
01304     XmString xstr;
01305 
01306     ENTRY("r_INT_mk_app_buttons");
01307 
01308     /* create frame to hold form and buttons */
01309     ac = 0;
01310     frame = XmCreateFrame( parent, "frame", al, ac );
01311 
01312     /* create form to hold push buttons */
01313     ac = 0;
01314     XtSetArg( al[ac], XmNhorizontalSpacing, R_BUTTON_SPACE );  ac++;
01315     form = XmCreateForm( frame, "form", al, ac );
01316 
01317 
01318     /* region fill button */
01319     ac = 0;
01320     xstr = XmStringCreateLtoR( "FILL", gRX.charset );
01321     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
01322     button1 = XmCreatePushButton( form, "fill", al, ac );
01323     XtManageChild( button1 );
01324     XtAddCallback( button1, XmNactivateCallback,
01325                    ( XtCallbackProc )r_INT_cb_fill, I );
01326     XtSetSensitive( button1, True );
01327     XmStringFree( xstr );
01328     MCW_register_hint( button1 , "interpolate between the last two lines" );
01329 
01330     /* unfill button */
01331     ac = 0;
01332     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
01333     XtSetArg( al[ac], XmNleftWidget, button1 );  ac++;
01334     xstr = XmStringCreateLtoR( "unfill", gRX.charset );
01335     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
01336     button2 = XmCreatePushButton( form, "unfill", al, ac );
01337     XtManageChild( button2 );
01338     XtAddCallback( button2, XmNactivateCallback,
01339                    ( XtCallbackProc )r_any_cb_unfill, &gRI.fill_val );
01340     XtSetSensitive( button2, True );
01341     XmStringFree( xstr );
01342     MCW_register_hint( button2 , "unfill at interpolation \"fill value\"" );
01343 
01344     /* apply button - set interpolation values to draw values */
01345     ac = 0;
01346     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
01347     XtSetArg( al[ac], XmNleftWidget, button2 );  ac++;
01348     xstr = XmStringCreateLtoR( "apply", gRX.charset );
01349     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
01350     button1 = XmCreatePushButton( form, "apply", al, ac );
01351     XtManageChild( button1 );
01352     XtAddCallback( button1, XmNactivateCallback,
01353                    ( XtCallbackProc )r_any_cb_apply, &gRI.fill_val );
01354     XtSetSensitive( button1, True );
01355     XmStringFree( xstr );
01356     MCW_register_hint( button1 , "sets fill values to main draw values" );
01357 
01358 
01359     /* stats button */
01360     ac = 0;
01361     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
01362     XtSetArg( al[ac], XmNleftWidget, button1 );  ac++;
01363     xstr = XmStringCreateLtoR( "stats", gRX.charset );
01364     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
01365     button2 = XmCreatePushButton( form, "stats", al, ac );
01366     XtManageChild( button2 );
01367     XtAddCallback( button2, XmNactivateCallback,
01368                    ( XtCallbackProc )r_any_cb_fill_stats, &gRI.fill_val );
01369     XtSetSensitive( button2, True );
01370     XmStringFree( xstr );
01371 
01372     /* hide button */
01373     ac = 0;
01374     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
01375     XtSetArg( al[ac], XmNleftWidget, button2 );  ac++;
01376     xstr = XmStringCreateLtoR( "hide", gRX.charset );
01377     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
01378     button1 = XmCreatePushButton( form, "hide", al, ac );
01379     XtManageChild( button1 );
01380     XtAddCallback( button1, XmNactivateCallback,
01381                    ( XtCallbackProc )r_any_cb_hide, "INT" );
01382     XtSetSensitive( button1, True );
01383     XmStringFree( xstr );
01384 
01385 
01386     XtManageChild( form );
01387     XtManageChild( frame );
01388 
01389     RETURN( frame );
01390 }
01391 
01392 
01393 /*----------------------------------------------------------------------
01394 **
01395 **  Create the "fill value" widget for interpolation window.
01396 **
01397 **----------------------------------------------------------------------
01398  */
01399 static Widget
01400 r_INT_mk_fillval_fr( interp_s * I, Widget parent )
01401 {
01402     Widget   junk, rc, frame;
01403     XmString xstr;
01404     Arg      al[ 10 ];
01405     int      ac;
01406     char     string[ 15 ];
01407 
01408     ENTRY("r_INT_mk_fillval_fr");
01409 
01410     ac = 0;
01411     frame = XmCreateFrame( parent, "frame", al, ac );
01412     
01413     ac = 0;
01414     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
01415     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
01416     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
01417 
01418 
01419     sprintf( string, "%d", I->fill_val );
01420 
01421     ac = 0;
01422     xstr = XmStringCreateLtoR( "fill value   : ", gRX.charset );
01423     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
01424     junk = XmCreateLabel( rc, "label", al, ac );
01425     XtManageChild( junk );
01426     XmStringFree( xstr );
01427 
01428     ac = 0;
01429     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
01430     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
01431     I->fillval_w = XmCreateText( rc, "text", al, ac );
01432     XtManageChild( I->fillval_w );
01433     XtAddCallback( I->fillval_w, XmNactivateCallback, 
01434             ( XtCallbackProc )r_INT_cb_set_fill_val, NULL );
01435     XtAddCallback( I->fillval_w, XmNlosingFocusCallback, 
01436             ( XtCallbackProc )r_INT_cb_set_fill_val, NULL );
01437     
01438     
01439     XtManageChild( rc );
01440     XtManageChild( frame );
01441 
01442     RETURN( frame );
01443 }
01444 
01445 
01446 /*----------------------------------------------------------------------
01447 **
01448 **  Callback to apply the interpolation values (change them to
01449 **  drawn values).
01450 **
01451 **----------------------------------------------------------------------
01452  */
01453 static void
01454 r_any_cb_apply(
01455         Widget w,
01456         XtPointer client_data,
01457         XtPointer call_data
01458         )
01459 {
01460     short  * fptr, * uptr;
01461     int      clear_val = *( (int *)client_data );
01462     int      count;
01463 
01464     ENTRY("r_any_cb_apply");
01465 
01466     if ( ! gRA.fdata )  /* error beep */
01467     {
01468         fprintf( stderr, "%c", 7 );
01469         EXRETURN;
01470     }
01471 
01472     /* first store to undo_data */
01473     fptr = gRA.fdata; uptr = gRA.undo_data;
01474     for ( count = 0; count < gRA.nvox; count++ )
01475         *uptr++ = *fptr++;
01476 
01477     for ( count = 0, fptr = gRA.fdata; count < gRA.nvox; count++, fptr++ )
01478         if ( *fptr == clear_val )
01479             *fptr = value_int;
01480 
01481     THD_load_statistics( gRA.func ) ;
01482     PLUTO_dset_redisplay( gRA.func ) ;
01483 
01484     EXRETURN;
01485 }
01486 
01487 
01488 /*----------------------------------------------------------------------
01489 **
01490 **  Callback to hide windows.
01491 **
01492 **----------------------------------------------------------------------
01493  */
01494 static void
01495 r_any_cb_hide( 
01496         Widget w,
01497         char *    client_data,
01498         XtPointer call_data
01499         )
01500 {
01501     ENTRY("r_any_cb_hide");
01502 
01503     if      ( ! strcmp( client_data, "INT" ) )
01504         XtUnmapWidget( gRI.main );
01505     else if ( ! strcmp( client_data, "HL" ) )
01506         XtUnmapWidget( gRH.main );
01507     else if ( ! strcmp( client_data, "wtgr" ) )
01508         XtUnmapWidget( gRX.wtgr_main );
01509     else if ( ! strcmp( client_data, "saveas" ) )
01510         XtUnmanageChild( gRX.save_as_file_d );
01511     else if ( ! strcmp( client_data, "all" ) )
01512     {
01513         XtUnmapWidget( gRI.main );
01514         XtUnmapWidget( gRH.main );
01515         XtUnmapWidget( gRX.wtgr_main );
01516         XtUnmanageChild( gRX.save_as_file_d );
01517     }
01518     else
01519     {
01520         sprintf( gRmessage, "rach_10 : client_data is '%s'\n", client_data );
01521         rERROR( gRmessage );
01522     }
01523 
01524     EXRETURN;
01525 }
01526 
01527 
01528 /*----------------------------------------------------------------------
01529 **
01530 **  Callback to raise windows.
01531 **
01532 **----------------------------------------------------------------------
01533  */
01534 static void
01535 r_any_cb_raise( 
01536         Widget w,
01537         char    * client_data,
01538         XtPointer call_data
01539         )
01540 {
01541     ENTRY("r_any_cb_raise");
01542 
01543     if      ( ! strcmp( client_data, "INT" ) )
01544     {
01545         XMapRaised( XtDisplay( gRI.main ) , XtWindow( gRI.main ) );
01546     }
01547     else if ( ! strcmp( client_data, "HL" ) )
01548     {
01549         XMapRaised( XtDisplay( gRH.main ) , XtWindow( gRH.main ) );
01550     }
01551     else if ( ! strcmp( client_data, "wtgr" ) )
01552     {
01553         XMapRaised( XtDisplay( gRX.wtgr_main ) , XtWindow( gRX.wtgr_main ) );
01554     }
01555     else if ( ! strcmp( client_data, "saveas" ) )
01556     {
01557         XtManageChild( gRX.save_as_file_d );
01558         XtPopup( XtParent( gRX.save_as_file_d ), XtGrabNone );
01559     }
01560     else if ( ! strcmp( client_data, "all" ) )
01561     {
01562         XMapRaised( XtDisplay( gRI.main ) , XtWindow( gRI.main ) );
01563         XMapRaised( XtDisplay( gRH.main ) , XtWindow( gRH.main ) );
01564         XMapRaised( XtDisplay( gRX.wtgr_main ) , XtWindow( gRX.wtgr_main ) );
01565         XtManageChild( gRX.save_as_file_d );
01566         XtPopup( XtParent( gRX.save_as_file_d ), XtGrabNone );
01567     }
01568     else
01569     {
01570         sprintf( gRmessage, "racr_10 : client_data is '%s'\n", client_data );
01571         rERROR( gRmessage );
01572     }
01573 
01574     EXRETURN;
01575 }
01576 
01577 
01578 /*----------------------------------------------------------------------
01579 **
01580 **  Callback to undo previous action (restore fdata from undo_data).
01581 **
01582 **----------------------------------------------------------------------
01583  */
01584 static void
01585 r_any_cb_undo( 
01586         Widget    w,
01587         XtPointer client_data,
01588         XtPointer call_data
01589         )
01590 {
01591     short * fptr, * uptr;
01592     int     count;
01593 
01594     ENTRY("r_any_cb_undo");
01595 
01596     fptr = gRA.fdata; uptr = gRA.undo_data;
01597     if ( !fptr || !uptr )
01598     {
01599         fprintf(stderr,"** undo without pointers: (%p,%p)\n",fptr,uptr);
01600         EXRETURN;
01601     }
01602 
01603     for ( count = 0; count < gRA.nvox; count++ )
01604         *fptr++ = *uptr++;
01605 
01606     THD_load_statistics( gRA.func ) ;
01607     PLUTO_dset_redisplay( gRA.func ) ;
01608 
01609     EXRETURN;
01610 }
01611 
01612 
01613 /*----------------------------------------------------------------------
01614 **
01615 **  Callback to interpolate between user drawn lines.
01616 **
01617 **----------------------------------------------------------------------
01618  */
01619 static void
01620 r_INT_cb_fill(
01621         Widget w,
01622         XtPointer client_data,
01623         XtPointer call_data
01624         )
01625 {
01626     r_ipt_t    sourcep, destp;
01627     interp_s * I = (interp_s *)client_data;
01628     points_t * lb, * sb;
01629     double     index_ratio, tot_dist;
01630     double     dx, dy, dz, dcurr;
01631     double     fx, fy, fz;
01632     short    * fnptr = gRA.fdata, * sptr;
01633     short    * fptr, * uptr;
01634     int      * ip1;
01635     int        count, dest_index, coord;
01636     int        nx = gRA.nx, ny = gRA.ny, nz = gRA.nz;
01637 
01638     ENTRY("r_INT_cb_fill");
01639 
01640     if ( ! gRA.fdata )
01641     {
01642         fprintf( stderr, "%c", 7 );
01643         EXRETURN;
01644     }
01645 
01646     if ( ! I )
01647     {
01648         rERROR( "Error : entered r_INT_cb_fill() without client_data." );
01649         EXRETURN;
01650     }
01651 
01652     /* check that neither border is empty */
01653     if ( I->A.used <= 0 || I->B.used <= 0 )
01654     {
01655         fprintf( stderr, "%c", 7 );
01656         rWARNING( "Missing bounding curve for interpolation." );
01657         EXRETURN;
01658     }
01659 
01660     /* first store to undo_data */
01661     fptr = gRA.fdata; uptr = gRA.undo_data;
01662     for ( count = 0; count < gRA.nvox; count++ )
01663         *uptr++ = *fptr++;
01664 
01665     if ( I->A.used >= I->B.used )
01666     {
01667         lb = &I->A;
01668         sb = &I->B;
01669         index_ratio = I->B.used / (double)I->A.used;
01670     }
01671     else
01672     {
01673         lb = &I->B;
01674         sb = &I->A;
01675         index_ratio = I->A.used / (double)I->B.used;
01676     }
01677 
01678     for ( count = 0, ip1 = lb->points; count < lb->used; count++, ip1++ )
01679     {
01680         sourcep    = r_index2pt( *ip1, nx, ny, nz );
01681         dest_index = count * index_ratio + 0.0001;
01682         destp      = r_index2pt( sb->points[dest_index], nx, ny, nz );
01683 
01684         tot_dist   = r_p_distance( sourcep, destp );
01685         dx         = R_DIST_STEP * ( destp.x - sourcep.x ) / tot_dist;
01686         dy         = R_DIST_STEP * ( destp.y - sourcep.y ) / tot_dist;
01687         dz         = R_DIST_STEP * ( destp.z - sourcep.z ) / tot_dist;
01688         fx         = sourcep.x + dx;
01689         fy         = sourcep.y + dy;
01690         fz         = sourcep.z + dz;
01691 
01692         for ( dcurr = R_DIST_STEP; dcurr < tot_dist; dcurr += R_DIST_STEP )
01693         {
01694             coord = (int)fx + nx * ( (int)fy + ny  * (int)fz );
01695 
01696             sptr = fnptr + coord;
01697 
01698             /* if ( ! *sptr )   -  draw through anything? */
01699             *sptr = I->fill_val;
01700 
01701             fx += dx;
01702             fy += dy;
01703             fz += dz;
01704         }
01705     }
01706 
01707     THD_load_statistics( gRA.func );
01708     PLUTO_dset_redisplay( gRA.func );
01709     dset_changed = 1;
01710 
01711     EXRETURN;
01712 }
01713 
01714 
01715 /*----------------------------------------------------------------------
01716 **
01717 **  Compute the distance between two points.
01718 **
01719 **----------------------------------------------------------------------
01720  */
01721 static double
01722 r_p_distance( r_ipt_t p1, r_ipt_t p2 )
01723 {
01724     return( sqrt( ( p1.x - p2.x ) * ( p1.x - p2.x ) +
01725                   ( p1.y - p2.y ) * ( p1.y - p2.y ) +
01726                   ( p1.z - p2.z ) * ( p1.z - p2.z ) )
01727           );
01728 }
01729 
01730 
01731 /*----------------------------------------------------------------------
01732 **
01733 **  Convert the coordinate to a point.
01734 **
01735 **  We assume coord is of the form coord = X + nx * ( Y + ny * Z ).
01736 **  The resulting point is P = { X, Y, Z }.
01737 **
01738 **----------------------------------------------------------------------
01739  */
01740 static r_ipt_t
01741 r_index2pt( int coord, int nx, int ny, int nz )
01742 {
01743     r_ipt_t p = { 0, 0, 0 };
01744     int     tmp;
01745 
01746     ENTRY("r_index2pt");
01747 
01748     if ( coord < 0 )
01749     {
01750         sprintf( gRmessage, "Coordinate %d is out of range!\n", coord );
01751         rERROR( gRmessage );
01752         RETURN(p);
01753     }
01754 
01755     p.x = coord % nx;
01756     tmp = coord / nx;
01757     p.y = tmp   % ny;
01758     p.z = tmp   / ny;
01759 
01760     if ( p.z >= nz )
01761     {
01762         sprintf( gRmessage, "Coordinate %d is out of range!\n"
01763                  "Associated point is (%d,%d,%d).\n",
01764                  coord, p.x, p.y, p.z );
01765         rERROR( gRmessage );
01766     }
01767 
01768     RETURN(p);
01769 }
01770 
01771 
01772 /*----------------------------------------------------------------------
01773 **
01774 **  Initialize the point connection structure.
01775 **
01776 **  structure : 
01777 **
01778 ** typedef struct
01779 ** {
01780 **     r_ipt_t   source;
01781 **     r_ipt_t   dest;
01782 ** 
01783 **     int       cur_pt;        * flag denoting first or second point *
01784 ** } r_pt_conn_s;
01785 **
01786 **----------------------------------------------------------------------
01787  */
01788 static int
01789 r_init_pt_conn_s( r_pt_conn_s * P )
01790 {
01791     r_ipt_t p = { 0, 0, 0 };
01792 
01793     P->cur_pt = 1;              /* may be either 1 or 2            */
01794     P->source = p;              /* just to initialize to SOMEthing */
01795     P->dest   = p;
01796 
01797     P->plist.points = NULL;     /* init border structure */
01798     P->plist.used   = 0;
01799     P->plist.M      = 0;
01800 
01801     return 1;
01802 }
01803 
01804 
01805 /*----------------------------------------------------------------------
01806 **
01807 **  Initialize the Algorithm values.
01808 **
01809 **  structure : 
01810 **
01811 **  typedef struct
01812 **  {
01813 **      Widget    main;         * main application widget *
01814 **      Widget    mainRC;       * main rowcolumn widget   *
01815 **
01816 **      int       fill_val;
01817 **      int       afni_undo;
01818 **
01819 **      points_t  A, B;         * two point structures for interpolation *
01820 **  } interp_s;
01821 **
01822 **----------------------------------------------------------------------
01823  */
01824 static int
01825 r_init_interp_vals( interp_s * I )
01826 {
01827     ENTRY("r_init_interp_vals");
01828 
01829     I->fill_val  = 2;
01830     I->afni_undo = 0;
01831 
01832     I->A.used   = 0;
01833     I->A.M      = 100;
01834     I->A.points = (int *)malloc( I->A.M * sizeof( int ) );
01835 
01836     if ( I->A.points == NULL )
01837     {
01838         fprintf( stderr, "\nError: riiv10\n"
01839                  "Failed to allocate %d ints for interpolation struct.\n\n",
01840                  I->A.M );
01841         RETURN(0);
01842     }
01843 
01844     I->B.used   = 0;
01845     I->B.M      = 100;
01846     I->B.points = (int *)malloc( I->B.M * sizeof( int ) );
01847 
01848     if ( I->B.points == NULL )
01849     {
01850         fprintf( stderr, "\nError: riiv20\n"
01851                  "Failed to allocate %d ints for interpolation struct.\n\n",
01852                  I->B.M );
01853         RETURN(0);
01854     }
01855 
01856     RETURN(1);
01857 }
01858 
01859 
01860 /*----------------------------------------------------------------------
01861 **
01862 **  Create main filling widgets.
01863 **
01864 **----------------------------------------------------------------------
01865  */
01866 static Widget
01867 r_wt_mk_main_frame( r_X_s * X, Widget parent )
01868 {
01869     Widget    frame, rc, label;
01870     XmString  xstring;
01871     Arg       al[ 20 ];
01872     int       ac;
01873 
01874     ENTRY("r_wt_mk_main_frame");
01875 
01876     ac = 0;
01877     XtSetArg( al[ ac ], XmNmarginHeight, 3 );  ac++;
01878     frame = XmCreateFrame( parent, "frame", al, ac );
01879 
01880     ac = 0;
01881     XtSetArg( al[ ac ], XmNlabelString,
01882                 XmStringCreate( "White Matter Fill :", X->charset ) );  ac++;
01883     XtSetArg( al[ ac ], XmNchildType, XmFRAME_TITLE_CHILD );  ac++;
01884     XtSetArg( al[ ac ], XmNchildVerticalAlignment,
01885                 XmALIGNMENT_BASELINE_BOTTOM);  ac++;
01886     label = XmCreateLabel( frame, "label", al, ac );
01887     XtManageChild( label );
01888     
01889     ac = 0;
01890     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
01891 
01892     ( void )r_wt_mk_range_fr      ( X, rc );
01893     ( void )r_wt_mk_fillval_fr    ( X, rc );
01894     ( void )r_wt_mk_nbrs_fr       ( X, rc );
01895     ( void )r_wt_mk_diag_conn_fr  ( X, rc );
01896     ( void )r_wt_mk_strong_bord_fr( X, rc );
01897 
01898     r_wt_mk_fill_buttons( X, rc );
01899 
01900 
01901     XtManageChild( rc );
01902     XtManageChild( frame );
01903 
01904     RETURN(frame);
01905 }
01906 
01907 
01908 /*----------------------------------------------------------------------
01909 **
01910 **  Create the main gray matter function frame.
01911 **
01912 **----------------------------------------------------------------------
01913  */
01914 static Widget
01915 r_gr_mk_main_frame( r_X_s * X, Widget parent )
01916 {
01917     Widget    frame, rc, label;
01918     XmString  xstring;
01919     Arg       al[ 20 ];
01920     int       ac;
01921 
01922     ENTRY("r_gr_mk_main_frame");
01923 
01924     ac = 0;
01925     XtSetArg( al[ ac ], XmNmarginHeight, 3 );  ac++;
01926     frame = XmCreateFrame( parent, "frame", al, ac );
01927 
01928     ac = 0;
01929     XtSetArg( al[ ac ], XmNlabelString,
01930                 XmStringCreate( "Gray Matter Fill :", X->charset ) );  ac++;
01931     XtSetArg( al[ ac ], XmNchildType, XmFRAME_TITLE_CHILD );  ac++;
01932     XtSetArg( al[ ac ], XmNchildVerticalAlignment,
01933                 XmALIGNMENT_BASELINE_BOTTOM);  ac++;
01934     label = XmCreateLabel( frame, "label", al, ac );
01935     XtManageChild( label );
01936     
01937     ac = 0;
01938     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
01939 
01940 
01941     ( void )r_gr_mk_range_fr    ( X, rc );
01942     ( void )r_gr_mk_fillval_fr  ( X, rc );
01943     ( void )r_gr_mk_max_dist_w  ( X, rc );
01944     ( void )r_gr_mk_fill_buttons( X, rc );
01945 
01946 
01947 
01948     XtManageChild( rc );
01949     XtManageChild( frame );
01950 
01951     RETURN(frame);
01952 }
01953 
01954 
01955 /*----------------------------------------------------------------------
01956 **
01957 **  Initialize the Algorithm values.
01958 **
01959 **----------------------------------------------------------------------
01960  */
01961 static int
01962 r_init_Alg_values( r_alg_s * A )
01963 {
01964     ENTRY("r_init_Alg_values");
01965 
01966     A->point_value       = 75;
01967     A->point_coord       = -1;  /* means user has not yet selected a point */
01968     A->adjust_point      = 0;
01969 
01970     strcpy( A->save_as_name, "default" );
01971 
01972     A->wt_fill_val       = 5;
01973     A->wt_range_min      = r_wtgr_calc_min_frm_val( A->point_value );
01974     A->wt_range_max      = r_wtgr_calc_max_frm_val( A->point_value );
01975     A->wt_diag_connect   = 0;   /* any connection */
01976 
01977     A->gr_fill_val       = 10;
01978     A->gr_range_min      = r_wtgr_calc_min_frm_val( 42 );
01979     A->gr_range_max      = r_wtgr_calc_max_frm_val( 42 );
01980     A->gr_max_dist       = 4;
01981 
01982     A->anat              = plint->im3d->anat_now;
01983 
01984     fprintf(stderr,"r_init_Alg_values(): A->anat = %p\n",A->anat);
01985     if ( A->anat )
01986     {
01987         if ( ! DSET_LOADED(A->anat) )
01988         {
01989             DSET_load( A->anat );
01990             fprintf(stderr,"-d loading anat...\n");
01991         }
01992         A->adata = (short *)DSET_BRICK_ARRAY( A->anat, 0 );
01993         /*fprintf(stderr,"Set A->adata to %p\n",A->adata);*/
01994     }
01995     
01996     /*
01997     ** Create boundary memory and check for malloc success.
01998     */
01999     A->Bold.used   = 0;
02000     A->Bold.M      = 1000;
02001     A->Bold.points = (int *)malloc( A->Bold.M * sizeof( int ) );
02002 
02003     if ( A->Bold.points == NULL )
02004     {
02005         fprintf( stderr, "Error: riAv10\n"
02006                  "Failed to allocate %d ints for boundary.\n", A->Bold.M );
02007         RETURN(0);
02008     }
02009 
02010     A->Bnew.used   = 0;
02011     A->Bnew.M      = 1000;
02012     A->Bnew.points = (int *)malloc( A->Bnew.M * sizeof( int ) );
02013 
02014     if ( A->Bnew.points == NULL )
02015     {
02016         fprintf( stderr, "\nError: riAv20\n"
02017                  "Failed to allocate %d ints for boundary.\n\n", A->Bnew.M );
02018         RETURN(0);
02019     }
02020 
02021     A->border.used   = 0;
02022     A->border.M      = 1000;
02023     A->border.points = (int *)malloc( A->border.M * sizeof( int ) );
02024 
02025     if ( A->border.points == NULL )
02026     {
02027         fprintf( stderr, "\nError: riAv30\n"
02028                  "Failed to allocate %d ints for boundary.\n\n",
02029                  A->border.M );
02030         RETURN(0);
02031     }
02032 
02033     /* we will initialize this after we know we have data */
02034     A->neighbors = NULL;                /* - will be nvox */
02035     A->undo_data = NULL;                /* - will be nvox */
02036 
02037     A->min_nbrs  = 0;
02038     A->strong_borders = 1;
02039 
02040 
02041     RETURN(1);
02042 }
02043 
02044 
02045 /*----------------------------------------------------------------------
02046 **
02047 **  Initialize the afni values.
02048 **
02049 **----------------------------------------------------------------------
02050  */
02051 static void
02052 r_init_afni_vars( r_alg_s * A, THD_3dim_dataset * func )
02053 {
02054     ENTRY("r_init_afni_vars");
02055 
02056     A->anat              = plint->im3d->anat_now;
02057 
02058     if ( func )
02059     {
02060         if ( DSET_BRICK_TYPE( func, 0 ) != MRI_short )
02061         {
02062             ( void )MCW_popup_message( gRX.main,
02063                         "Serious error.\n"
02064                         "\n"
02065                         "Functional data is not of\n"
02066                         "type short.  Please choose\n"
02067                         "another dataset.\n",
02068                         MCW_USER_KILL | MCW_TIMER_KILL );
02069             EXRETURN;
02070         }
02071 
02072         A->func   = func;
02073 
02074         A->factor = DSET_BRICK_FACTOR( A->func, 0 );
02075         A->factor = ( A->factor == 0.0 ) ? 1.0 : A->factor;
02076         A->fdata  = (short *)DSET_BRICK_ARRAY( A->func, 0 );
02077 
02078         A->nx     = DSET_NX( A->func );
02079         A->ny     = DSET_NY( A->func );
02080         A->nz     = DSET_NZ( A->func );
02081         A->nxy    = A->nx * A->ny;
02082         A->nvox   = A->nx * A->ny * A->nz;
02083 
02084         if ( A->neighbors == NULL )
02085         {
02086             A->neighbors = malloc( A->nvox * sizeof( short ) );
02087             if ( A->neighbors == NULL )
02088             {
02089                 fprintf( stderr, "\nError: riav10\n"
02090                 "Failed to allocate %d ints for neighbors.\n\n", A->nvox );
02091             }
02092 
02093             A->undo_data = calloc( A->nvox, sizeof( short ) );
02094             if ( A->undo_data == NULL )
02095             {
02096                 fprintf( stderr, "\nError: riav20\n"
02097                 "Failed to allocate %d ints for undo_data.\n\n", A->nvox );
02098             }
02099         }
02100     }
02101     else
02102         ( void )MCW_popup_message( gRX.main,
02103                     "Serious error.\n"
02104                     "\n"
02105                     "Missing functional dataset.\n"
02106                     "Please choose another dataset.\n",
02107                     MCW_USER_KILL | MCW_TIMER_KILL );
02108 
02109     fprintf(stderr,"r_init_afni_vars(): A->anat = %p\n",A->anat);
02110     if ( A->anat )
02111     {
02112         if ( DSET_BRICK_TYPE( A->anat, 0 ) != MRI_short )
02113         {
02114             ( void )MCW_popup_message( gRX.main,
02115                         "Serious error.\n"
02116                         "\n"
02117                         "Anatomical data is not of\n"
02118                         "type short.  Please choose\n"
02119                         "another dataset.\n",
02120                         MCW_USER_KILL | MCW_TIMER_KILL );
02121             EXRETURN;
02122         }
02123 
02124         if ( ! DSET_LOADED(A->anat) )
02125         {
02126             fprintf(stderr,"-d loading anat...\n");
02127             DSET_load( A->anat );
02128         }
02129 
02130         A->adata = (short *)DSET_BRICK_ARRAY( A->anat, 0 );
02131         /*fprintf(stderr,"Set A->adata to %p\n",A->adata);*/
02132     }
02133     else
02134         ( void )MCW_popup_message( gRX.main,
02135                     "Serious error.\n"
02136                     "\n"
02137                     "Missing anatomical dataset.\n"
02138                     "Please choose another dataset.\n",
02139                     MCW_USER_KILL | MCW_TIMER_KILL );
02140 
02141     EXRETURN;
02142 }
02143 
02144 
02145 /*----------------------------------------------------------------------
02146 **
02147 **  Callback to output statistics on selected matter.
02148 **
02149 **----------------------------------------------------------------------
02150  */
02151 static void
02152 r_any_cb_fill_stats(
02153         Widget w,
02154         XtPointer client_data,
02155         XtPointer call_data
02156         )
02157 {
02158     short * fptr = gRA.fdata;
02159     short * aptr = gRA.adata;
02160     int     fillval = *(int *)client_data;
02161     int     count, min = 30000, max = -30000, size = 0;
02162 
02163     ENTRY("r_any_cb_fill_stats");
02164 
02165     if ( ! gRA.fdata )
02166     {
02167         fputc( 7, stderr );      /* hard-code a beep */
02168         EXRETURN;
02169     }
02170 
02171     for ( count = 0; count < gRA.nvox; count++ )
02172     {
02173         if ( *fptr == fillval )
02174         {
02175             if ( *aptr > max )
02176                 max = *aptr;
02177             if ( *aptr < min )
02178                 min = *aptr;
02179             size++;
02180         }
02181 
02182         aptr++;
02183         fptr++;
02184     }
02185         
02186     printf( "------------------------------------------------------------\n" );
02187 
02188     if ( size > 0 )
02189     {
02190         printf( "fill region min  = %d\n", min  );
02191         printf( "fill region max  = %d\n", max  );
02192         printf( "fill region size = %d\n", size );
02193         printf( "\n" );
02194 
02195         r_histogram( &gRA, min, max, fillval );
02196     }
02197     else
02198         rWARNING( "Fill region is empty." );
02199 
02200     printf( "------------------------------------------------------------\n" );
02201 
02202     EXRETURN;
02203 }
02204 
02205 
02206 /*----------------------------------------------------------------------
02207 **
02208 **  Make a histogram from the selected data.
02209 **
02210 **----------------------------------------------------------------------
02211  */
02212 static void
02213 r_histogram( r_alg_s * A, int min, int max, int check_val )
02214 {
02215     int   * hist;
02216 
02217     short * fptr = gRA.fdata;
02218     short * aptr = gRA.adata;
02219     int     count, size = max - min + 1, total = 0;
02220 
02221     ENTRY("r_histogram");
02222 
02223     if ( ( hist = (int *)malloc( size * sizeof( int ) ) ) == NULL )
02224     {
02225         sprintf( gRmessage, "Error: pr_rh_10\n"
02226                  "Failed alloca for %d ints.", size );
02227         rWARNING( gRmessage );
02228         EXRETURN;
02229     }
02230 
02231     for ( count = 0; count < size; count++ )
02232         hist[count] = 0;
02233 
02234     for ( count = 0; count < A->nvox; count++ )
02235     {
02236         if ( *fptr == check_val )
02237         {
02238             hist[*aptr - min]++;
02239             total++;
02240         }
02241 
02242         aptr++;
02243         fptr++;
02244     }
02245         
02246     printf( "  value   \t   nvox    \t    %%\n" );
02247     printf( "--------- \t --------- \t --------- \n" );
02248 
02249     for ( count = 0; count < size; count++)
02250         printf( " %6d   \t %7d   \t  %7.3f\n",
02251                 min + count, hist[ count ], 100.0 * hist[ count ] / total );
02252     free(hist);
02253     EXRETURN;
02254 }
02255 
02256 
02257 /*----------------------------------------------------------------------
02258 **
02259 **  Callback to toggle the strong borders flag.
02260 **
02261 **----------------------------------------------------------------------
02262 */
02263 static void
02264 r_wt_cb_SB_toggle(
02265         Widget w,
02266         XtPointer client_data,
02267         XtPointer call_data
02268         )
02269 {
02270     Boolean set;
02271     Arg     al[ 10 ];
02272     int     ac;
02273 
02274     ac = 0;
02275     XtSetArg( al[ ac ], XmNset, &set );  ac++;
02276     XtGetValues( w, al, ac );
02277 
02278     if ( set )
02279         gRA.strong_borders = 1;
02280     else
02281         gRA.strong_borders = 0;
02282 
02283     return;
02284 }
02285 
02286 
02287 /*----------------------------------------------------------------------
02288 **
02289 **  Given an integer value, return the suggested minimum search value.
02290 **
02291 **----------------------------------------------------------------------
02292  */
02293 static int
02294 r_wtgr_calc_min_frm_val( int value )
02295 {
02296     return( (int)(0.94 * value - 5) );
02297 }
02298 
02299 
02300 /*----------------------------------------------------------------------
02301 **
02302 **  Given an integer value, return the suggested minimum search value.
02303 **
02304 **----------------------------------------------------------------------
02305  */
02306 static int
02307 r_wtgr_calc_max_frm_val( int value )
02308 {
02309     return( (int)(1.06 * value + 5) );
02310 }
02311 
02312 
02313 /*----------------------------------------------------------------------
02314 **
02315 **  Hide the main white/gray matter finder.
02316 **
02317 **----------------------------------------------------------------------
02318  */
02319 static void
02320 r_wtgr_cb_hide( void )
02321 {
02322     XtUnmapWidget( gRX.wtgr_main );
02323 }
02324 
02325 
02326 /*----------------------------------------------------------------------
02327 **
02328 **  Callback to suggest range limits for white AND gray matter search.
02329 **
02330 **  Values will be set in the wt_range_min_w and wt_range_max_w widgets.
02331 **
02332 **----------------------------------------------------------------------
02333  */
02334 static void
02335 r_wtgr_cb_suggest_limits(
02336         Widget w,
02337         XtPointer client_data,
02338         XtPointer call_data
02339         )
02340 {
02341     Widget minw, maxw;
02342     char * cdptr = (char *)client_data;
02343     char   string[ 10 ] = "";
02344     Arg    al[ 10 ];
02345     int    ac, min, max;
02346 
02347     ENTRY("r_wtgr_cb_suggest_limits");
02348 
02349     if ( ! cdptr )
02350     {
02351         fprintf( stderr,
02352                  "Entered r_wtgr_cb_suggest_limits() without a type.\n" );
02353         EXRETURN;
02354     }
02355 
02356     min = r_wtgr_calc_min_frm_val( gRA.point_value );
02357     max = r_wtgr_calc_max_frm_val( gRA.point_value );
02358 
02359     if ( ! strcmp( cdptr, "white" ) )
02360     {
02361         gRA.wt_range_min = min;         /* apply the new values */
02362         gRA.wt_range_max = max;
02363 
02364         minw = gRX.wt_range_min_w;      /* set the widgets to be updated */
02365         maxw = gRX.wt_range_max_w;
02366     }
02367     else        /* then gray */
02368     {
02369         max = min - 1;                  /* assume the gray starts below white */
02370         min = 0.60 * min;
02371 
02372         gRA.gr_range_max = max;
02373         gRA.gr_range_min = min;
02374 
02375         minw = gRX.gr_range_min_w;
02376         maxw = gRX.gr_range_max_w;
02377     }
02378 
02379     /* set the values into the range widgets */
02380 
02381     sprintf( string, "%d", min );
02382 
02383     ac = 0;
02384     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
02385     XtSetValues( minw, al, ac );
02386 
02387 
02388     sprintf( string, "%d", max );
02389 
02390     ac = 0;
02391     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
02392     XtSetValues( maxw, al, ac );
02393 
02394     EXRETURN;
02395 }
02396 
02397 
02398 /*----------------------------------------------------------------------
02399 **
02400 **  Create boundary (gray matter) buttons.
02401 **
02402 **----------------------------------------------------------------------
02403  */
02404 static Widget
02405 r_gr_mk_fill_buttons( r_X_s * X, Widget parent )
02406 {
02407     int      ac;
02408     Arg      al[ 10 ];
02409     Widget   form, frame, button;
02410     XmString xstr;
02411 
02412     ENTRY("r_gr_mk_fill_buttons");
02413 
02414     /* create frame to hold form and buttons */
02415     ac = 0;
02416     frame = XmCreateFrame( parent, "frame", al, ac );
02417 
02418     /* create form to hold push buttons */
02419     ac = 0;
02420     XtSetArg( al[ac], XmNhorizontalSpacing, R_BUTTON_SPACE );  ac++;
02421     form = XmCreateForm( frame, "form", al, ac );
02422 
02423 
02424     /* region fill button */
02425     ac = 0;
02426     xstr = XmStringCreateLtoR( "FILL", gRX.charset );
02427     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
02428     button = XmCreatePushButton( form, "fill", al, ac );
02429     XtManageChild( button );
02430     XtAddCallback( button, XmNactivateCallback,
02431                    ( XtCallbackProc )r_gr_cb_fill, NULL );
02432     XtSetSensitive( button, True );
02433     XmStringFree( xstr );
02434     MCW_register_hint( button , "fill the gray matter region" );
02435 
02436     /* unfill button */
02437     ac = 0;
02438     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
02439     XtSetArg( al[ac], XmNleftWidget, button );  ac++;
02440     xstr = XmStringCreateLtoR( "unfill", gRX.charset );
02441     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
02442     button = XmCreatePushButton( form, "unfill", al, ac );
02443     XtManageChild( button );
02444     XtAddCallback( button, XmNactivateCallback,
02445                    ( XtCallbackProc )r_any_cb_unfill, &gRA.gr_fill_val );
02446     XtSetSensitive( button, True );
02447     XmStringFree( xstr );
02448     MCW_register_hint( button , "unfill the \"fill value\" region" );
02449 
02450 
02451     /* suggest range button */
02452     ac = 0;
02453     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
02454     XtSetArg( al[ac], XmNleftWidget, button );  ac++;
02455     xstr = XmStringCreateLtoR( "suggest range", gRX.charset );
02456     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
02457     button = XmCreatePushButton( form, "suggest_range", al, ac );
02458     XtManageChild( button );
02459     XtAddCallback( button, XmNactivateCallback,
02460                    ( XtCallbackProc )r_wtgr_cb_suggest_limits, "gray" );
02461     XtSetSensitive( button, True );
02462     XmStringFree( xstr );
02463     MCW_register_hint( button , "suggest a range for gray matter values" );
02464 
02465 
02466     /* stats button */
02467     ac = 0;
02468     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
02469     XtSetArg( al[ac], XmNleftWidget, button );  ac++;
02470     xstr = XmStringCreateLtoR( "stats", gRX.charset );
02471     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
02472     button = XmCreatePushButton( form, "stats", al, ac );
02473     XtManageChild( button );
02474     XtAddCallback( button, XmNactivateCallback,
02475                    ( XtCallbackProc )r_any_cb_fill_stats, &gRA.gr_fill_val );
02476     XtSetSensitive( button, True );
02477     XmStringFree( xstr );
02478     MCW_register_hint( button , "get stats for this \"fill value\"" );
02479 
02480 
02481     /* hide window button */
02482     ac = 0;
02483     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
02484     XtSetArg( al[ac], XmNleftWidget, button );  ac++;
02485     xstr = XmStringCreateLtoR( "hide", gRX.charset );
02486     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
02487     button = XmCreatePushButton( form, "hide", al, ac );
02488     XtManageChild( button );
02489     XtAddCallback( button, XmNactivateCallback,
02490                    ( XtCallbackProc )r_any_cb_hide, "wtgr" );
02491     XtSetSensitive( button, True );
02492     XmStringFree( xstr );
02493     MCW_register_hint( button , "temporarily close this window" );
02494 
02495 
02496     XtManageChild( form );
02497     XtManageChild( frame );
02498 
02499     RETURN( frame );
02500 }
02501 
02502 
02503 /*----------------------------------------------------------------------
02504 **
02505 **  Create FILL type buttons for the white matter search.
02506 **
02507 **----------------------------------------------------------------------
02508  */
02509 static void
02510 r_wt_mk_fill_buttons( r_X_s * X, Widget parent )
02511 {
02512     int      ac;
02513     Arg      al[ 10 ];
02514     Widget   form, frame, button1, button2, button3;
02515     XmString xstr;
02516 
02517     ENTRY("r_wt_mk_fill_buttons");
02518 
02519     /* create frame to hold form and buttons */
02520     ac = 0;
02521     frame = XmCreateFrame( parent, "frame", al, ac );
02522 
02523     /* create form to hold push buttons */
02524     ac = 0;
02525     XtSetArg( al[ac], XmNhorizontalSpacing, R_BUTTON_SPACE );  ac++;
02526     form = XmCreateForm( frame, "form", al, ac );
02527 
02528 
02529     /* region fill button */
02530     ac = 0;
02531     xstr = XmStringCreateLtoR( "FILL", gRX.charset );
02532     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
02533     button1 = XmCreatePushButton( form, "fill", al, ac );
02534     XtManageChild( button1 );
02535     XtAddCallback( button1, XmNactivateCallback,
02536                    ( XtCallbackProc )r_wt_cb_fill, NULL );
02537     XtSetSensitive( button1, True );
02538     XmStringFree( xstr );
02539     MCW_register_hint( button1 , "fill the white matter region" );
02540 
02541 
02542     /* MORE region fill button */
02543     ac = 0;
02544     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
02545     XtSetArg( al[ac], XmNleftWidget, button1 );  ac++;
02546     xstr = XmStringCreateLtoR( "MORE", gRX.charset );
02547     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
02548     button3 = XmCreatePushButton( form, "more", al, ac );
02549     XtManageChild( button3 );
02550     XtAddCallback( button3, XmNactivateCallback,
02551                    ( XtCallbackProc )r_wt_cb_fill, "0" );
02552     XtSetSensitive( button3, True );
02553     XmStringFree( xstr );
02554     MCW_register_hint( button3 , "fill more white matter (no unfill)" );
02555 
02556 
02557     /* unfill button */
02558     ac = 0;
02559     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
02560     XtSetArg( al[ac], XmNleftWidget, button3 );  ac++;
02561     xstr = XmStringCreateLtoR( "unfill", gRX.charset );
02562     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
02563     button2 = XmCreatePushButton( form, "unfill", al, ac );
02564     XtManageChild( button2 );
02565     XtAddCallback( button2, XmNactivateCallback,
02566                    ( XtCallbackProc )r_any_cb_unfill, &gRA.wt_fill_val );
02567     XtSetSensitive( button2, True );
02568     XmStringFree( xstr );
02569     MCW_register_hint( button2 , "unfill all matter for the \"fill value\"" );
02570 
02571 
02572     /* suggest range button */
02573     ac = 0;
02574     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
02575     XtSetArg( al[ac], XmNleftWidget, button2 );  ac++;
02576     xstr = XmStringCreateLtoR( "suggest range", gRX.charset );
02577     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
02578     button1 = XmCreatePushButton( form, "suggest_range", al, ac );
02579     XtManageChild( button1 );
02580     XtAddCallback( button1, XmNactivateCallback,
02581                    ( XtCallbackProc )r_wtgr_cb_suggest_limits, "white" );
02582     XtSetSensitive( button1, True );
02583     XmStringFree( xstr );
02584     MCW_register_hint( button1 , "suggest a white matter range" );
02585 
02586 
02587     /* stats button */
02588     ac = 0;
02589     XtSetArg( al[ac], XmNleftAttachment, XmATTACH_WIDGET );  ac++;
02590     XtSetArg( al[ac], XmNleftWidget, button1 );  ac++;
02591     xstr = XmStringCreateLtoR( "stats", gRX.charset );
02592     XtSetArg( al[ac], XmNlabelString, xstr );  ac++;
02593     button2 = XmCreatePushButton( form, "stats", al, ac );
02594     XtManageChild( button2 );
02595     XtAddCallback( button2, XmNactivateCallback,
02596                    ( XtCallbackProc )r_any_cb_fill_stats, &gRA.wt_fill_val );
02597     XtSetSensitive( button2, True );
02598     XmStringFree( xstr );
02599     MCW_register_hint( button2 , "get stats for this \"fill value\"" );
02600 
02601 
02602     XtManageChild( form );
02603     XtManageChild( frame );
02604 
02605     EXRETURN;
02606 }
02607 
02608 
02609 /*----------------------------------------------------------------------
02610 **
02611 **  Create the diagonal connections frame.
02612 **
02613 **  This will be a radio button widget for the user flag.
02614 **
02615 **----------------------------------------------------------------------
02616  */
02617 static Widget
02618 r_wt_mk_diag_conn_fr( r_X_s * X, Widget parent )
02619 {
02620     Widget   junk, rc, frame;
02621     XmString xstr;
02622     Arg      al[ 10 ];
02623     int      ac;
02624     char     string[ 15 ];
02625 
02626     ENTRY("r_wt_mk_diag_conn_fr");
02627 
02628     ac = 0;
02629     frame = XmCreateFrame( parent, "frame", al, ac );
02630 
02631     ac = 0;
02632     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
02633     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
02634     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
02635 
02636     ac = 0;
02637     xstr = XmStringCreateLtoR( "connection constraint (0-2) : ", gRX.charset );
02638     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
02639     junk = XmCreateLabel( rc, "label", al, ac );
02640     XtManageChild( junk );
02641     XmStringFree( xstr );
02642 
02643 
02644     sprintf( string, "%d", gRA.wt_diag_connect );
02645 
02646     ac = 0;
02647     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
02648     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
02649     X->wt_diag_conn_w = XmCreateText( rc, "text", al, ac );
02650     XtManageChild( X->wt_diag_conn_w );
02651     XtAddCallback( X->wt_diag_conn_w, XmNactivateCallback,
02652             ( XtCallbackProc )r_wt_cb_set_diag_conn, NULL );
02653     XtAddCallback( X->wt_diag_conn_w, XmNlosingFocusCallback,
02654             ( XtCallbackProc )r_wt_cb_set_diag_conn, NULL );
02655 
02656 
02657     XtManageChild( rc );
02658     XtManageChild( frame );
02659 
02660     RETURN( frame );
02661 }
02662 
02663 /*----------------------------------------------------------------------
02664 **
02665 **  Create the strong borders frame.
02666 **
02667 **  This will be a radio button widget.
02668 **
02669 **----------------------------------------------------------------------
02670  */
02671 static Widget
02672 r_wt_mk_strong_bord_fr( r_X_s * X, Widget parent )
02673 {
02674     Widget   junk, frame;
02675     XmString xstr;
02676     Arg      al[ 10 ];
02677     int      ac;
02678     char     string[ 15 ];
02679 
02680     ENTRY("r_wt_mk_strong_bord_fr");
02681 
02682     ac = 0;
02683     frame = XmCreateFrame( parent, "frame", al, ac );
02684     
02685     ac = 0;
02686     XtSetArg( al[ ac ], XmNset,     True );  ac++;
02687     XtSetArg( al[ ac ], XmNwidth, 1 ); ac++;
02688     XtSetArg( al[ ac ], XmNspacing, 1 ); ac++;
02689     XtSetArg( al[ ac ], XmNmarginLeft, 1 ); ac++;
02690     xstr = XmStringCreateLtoR( "strong borders                ", gRX.charset );
02691     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
02692     junk = XmCreateToggleButton( frame, "toggle", al, ac );
02693     XtManageChild( junk );
02694     XtAddCallback( junk, XmNvalueChangedCallback, r_wt_cb_SB_toggle, NULL);
02695     XmStringFree( xstr );
02696 
02697     XtManageChild( frame );
02698 
02699     RETURN( frame );
02700 }
02701 
02702 
02703 /*----------------------------------------------------------------------
02704 **
02705 **  Create the min_nbrs (minimum neighbors) frame.
02706 **
02707 **----------------------------------------------------------------------
02708  */
02709 static Widget
02710 r_wt_mk_nbrs_fr( r_X_s * X, Widget parent )
02711 {
02712     Widget   junk, rc, frame;
02713     XmString xstr;
02714     Arg      al[ 10 ];
02715     int      ac;
02716     char     string[ 15 ];
02717 
02718     ENTRY("r_wt_mk_nbrs_fr");
02719 
02720     ac = 0;
02721     frame = XmCreateFrame( parent, "frame", al, ac );
02722     
02723     ac = 0;
02724     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
02725     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
02726     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
02727 
02728     ac = 0;
02729     xstr = XmStringCreateLtoR( "neighbors  constraint (0-6) : ", gRX.charset );
02730     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
02731     junk = XmCreateLabel( rc, "label", al, ac );
02732     XtManageChild( junk );
02733     XmStringFree( xstr );
02734 
02735 
02736     sprintf( string, "%d", gRA.min_nbrs );
02737 
02738     ac = 0;
02739     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
02740     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
02741     X->wt_min_nbrs_w = XmCreateText( rc, "text", al, ac );
02742     XtManageChild( X->wt_min_nbrs_w );
02743     XtAddCallback( X->wt_min_nbrs_w, XmNactivateCallback, 
02744             ( XtCallbackProc )r_wt_cb_set_min_nbrs, NULL );
02745     XtAddCallback( X->wt_min_nbrs_w, XmNlosingFocusCallback, 
02746             ( XtCallbackProc )r_wt_cb_set_min_nbrs, NULL );
02747     
02748     
02749     XtManageChild( rc );
02750     XtManageChild( frame );
02751 
02752     RETURN( frame );
02753 }
02754 
02755 
02756 /*----------------------------------------------------------------------
02757 **
02758 **  Create the frame to handle max distance in the gray search.
02759 **
02760 **----------------------------------------------------------------------
02761  */
02762 static Widget
02763 r_gr_mk_max_dist_w( r_X_s * X, Widget parent )
02764 {
02765     Widget   junk, rc, frame;
02766     XmString xstr;
02767     Arg      al[ 10 ];
02768     int      ac;
02769     char     string[ 15 ];
02770 
02771     ENTRY("r_gr_mk_max_dist_w");
02772 
02773     ac = 0;
02774     frame = XmCreateFrame( parent, "frame", al, ac );
02775     
02776     ac = 0;
02777     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
02778     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
02779     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
02780 
02781     ac = 0;
02782     xstr = XmStringCreateLtoR( "max distance : ", gRX.charset );
02783     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
02784     junk = XmCreateLabel( rc, "label", al, ac );
02785     XtManageChild( junk );
02786     XmStringFree( xstr );
02787 
02788 
02789     sprintf( string, "%d", gRA.gr_max_dist );
02790 
02791     ac = 0;
02792     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
02793     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
02794     junk = XmCreateText( rc, "text", al, ac );
02795     XtManageChild( junk );
02796     XtAddCallback( junk, XmNactivateCallback, 
02797             ( XtCallbackProc )r_gr_cb_set_max_dist, NULL );
02798     XtAddCallback( junk, XmNlosingFocusCallback, 
02799             ( XtCallbackProc )r_gr_cb_set_max_dist, NULL );
02800     
02801     
02802     XtManageChild( rc );
02803     XtManageChild( frame );
02804 
02805     RETURN( frame );
02806 }
02807 
02808 
02809 /*----------------------------------------------------------------------
02810 **
02811 **  Create the "fill value" widgets.
02812 **
02813 **----------------------------------------------------------------------
02814  */
02815 static Widget
02816 r_wt_mk_fillval_fr( r_X_s * X, Widget parent )
02817 {
02818     Widget   junk, rc, frame;
02819     XmString xstr;
02820     Arg      al[ 10 ];
02821     int      ac;
02822     char     string[ 15 ];
02823 
02824 
02825     ac = 0;
02826     frame = XmCreateFrame( parent, "frame", al, ac );
02827     
02828     ac = 0;
02829     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
02830     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
02831     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
02832 
02833     ac = 0;
02834     xstr = XmStringCreateLtoR( "fill value   : ", gRX.charset );
02835     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
02836     junk = XmCreateLabel( rc, "label", al, ac );
02837     XtManageChild( junk );
02838     XmStringFree( xstr );
02839 
02840 
02841     sprintf( string, "%d", gRA.wt_fill_val );
02842 
02843     ac = 0;
02844     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
02845     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
02846     X->wt_fill_val_w = XmCreateText( rc, "text", al, ac );
02847     XtManageChild( X->wt_fill_val_w );
02848     XtAddCallback( X->wt_fill_val_w, XmNactivateCallback, 
02849             ( XtCallbackProc )r_wt_cb_set_fill_val, NULL );
02850     XtAddCallback( X->wt_fill_val_w, XmNlosingFocusCallback, 
02851             ( XtCallbackProc )r_wt_cb_set_fill_val, NULL );
02852     
02853     
02854     XtManageChild( rc );
02855     XtManageChild( frame );
02856 
02857     return( frame );
02858 }
02859 
02860 
02861 /*----------------------------------------------------------------------
02862 **
02863 **  Create the "fill value" widget for the gray matter search.
02864 **
02865 **----------------------------------------------------------------------
02866  */
02867 static Widget
02868 r_gr_mk_fillval_fr( r_X_s * X, Widget parent )
02869 {
02870     Widget   junk, rc, frame;
02871     XmString xstr;
02872     Arg      al[ 10 ];
02873     int      ac;
02874     char     string[ 15 ];
02875 
02876 
02877     ac = 0;
02878     frame = XmCreateFrame( parent, "frame", al, ac );
02879     
02880     ac = 0;
02881     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
02882     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
02883     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
02884 
02885     ac = 0;
02886     xstr = XmStringCreateLtoR( "fill value   : ", gRX.charset );
02887     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
02888     junk = XmCreateLabel( rc, "label", al, ac );
02889     XtManageChild( junk );
02890     XmStringFree( xstr );
02891 
02892 
02893     sprintf( string, "%d", gRA.gr_fill_val );
02894 
02895     ac = 0;
02896     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
02897     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
02898     X->gr_fill_val_w = XmCreateText( rc, "text", al, ac );
02899     XtManageChild( X->gr_fill_val_w );
02900     XtAddCallback( X->gr_fill_val_w, XmNactivateCallback, 
02901             ( XtCallbackProc )r_gr_set_fill_val, NULL );
02902     XtAddCallback( X->gr_fill_val_w, XmNlosingFocusCallback, 
02903             ( XtCallbackProc )r_gr_set_fill_val, NULL );
02904     
02905     
02906     XtManageChild( rc );
02907     XtManageChild( frame );
02908 
02909     return( frame );
02910 }
02911 
02912 
02913 /*----------------------------------------------------------------------
02914 **
02915 **  Create the gray matter range frame.
02916 **
02917 **----------------------------------------------------------------------
02918  */
02919 static Widget
02920 r_gr_mk_range_fr( r_X_s * X, Widget parent )
02921 {
02922     Widget   junk, rc, frame;
02923     XmString xstr;
02924     Arg      al[ 10 ];
02925     int      ac;
02926     char     string[ 15 ];
02927 
02928 
02929     ac = 0;
02930     frame = XmCreateFrame( parent, "frame", al, ac );
02931     
02932     ac = 0;                     /* to hold labels and text */
02933     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
02934     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
02935     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
02936 
02937     ac = 0;
02938     xstr = XmStringCreateLtoR( "search range : ", gRX.charset );
02939     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
02940     junk = XmCreateLabel( rc, "label", al, ac );
02941     XtManageChild( junk );
02942     XmStringFree( xstr );
02943 
02944 
02945     sprintf( string, "%d", gRA.gr_range_min );  /* init value */
02946 
02947     ac = 0;
02948     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
02949     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
02950     X->gr_range_min_w = XmCreateText( rc, "text", al, ac );
02951     XtManageChild( X->gr_range_min_w );
02952     XtAddCallback( X->gr_range_min_w, XmNactivateCallback, 
02953             ( XtCallbackProc )r_gr_cb_set_range, "from" );
02954     XtAddCallback( X->gr_range_min_w, XmNlosingFocusCallback, 
02955             ( XtCallbackProc )r_gr_cb_set_range, "from" );
02956     
02957     ac = 0;
02958     xstr = XmStringCreateLtoR( " to ", gRX.charset );
02959     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
02960     junk = XmCreateLabel( rc, "label", al, ac );
02961     XtManageChild( junk );
02962     XmStringFree( xstr );
02963     
02964 
02965     sprintf( string, "%d", gRA.gr_range_max );
02966 
02967     ac = 0;
02968     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
02969     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
02970     X->gr_range_max_w = XmCreateText( rc, "text", al, ac );
02971     XtManageChild( X->gr_range_max_w );
02972     XtAddCallback( X->gr_range_max_w, XmNactivateCallback, 
02973             ( XtCallbackProc )r_gr_cb_set_range, "to" );
02974     XtAddCallback( X->gr_range_max_w, XmNlosingFocusCallback, 
02975             ( XtCallbackProc )r_gr_cb_set_range, "to" );
02976     
02977     XtManageChild( rc );
02978     XtManageChild( frame );
02979 
02980     return( frame );
02981 }
02982 
02983 
02984 /*----------------------------------------------------------------------
02985 **
02986 **  Create the range widgets.
02987 **
02988 **----------------------------------------------------------------------
02989  */
02990 static Widget
02991 r_wt_mk_range_fr( r_X_s * X, Widget parent )
02992 {
02993     Widget   junk, rc, frame;
02994     XmString xstr;
02995     Arg      al[ 10 ];
02996     int      ac;
02997     char     string[ 15 ];
02998 
02999 
03000     ac = 0;
03001     frame = XmCreateFrame( parent, "frame", al, ac );
03002     
03003     ac = 0;                     /* to hold labels and text */
03004     XtSetArg( al[ ac ], XmNpacking, XmPACK_TIGHT );  ac++;
03005     XtSetArg( al[ ac ], XmNorientation, XmHORIZONTAL );  ac++;
03006     rc = XmCreateRowColumn( frame, "rowcolumn", al, ac );
03007 
03008     ac = 0;
03009     xstr = XmStringCreateLtoR( "search range : ", gRX.charset );
03010     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
03011     junk = XmCreateLabel( rc, "label", al, ac );
03012     XtManageChild( junk );
03013     XmStringFree( xstr );
03014 
03015 
03016     sprintf( string, "%d", gRA.wt_range_min );  /* init value */
03017 
03018     ac = 0;
03019     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
03020     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
03021     X->wt_range_min_w = XmCreateText( rc, "text", al, ac );
03022     XtManageChild( X->wt_range_min_w );
03023     XtAddCallback( X->wt_range_min_w, XmNactivateCallback, 
03024             ( XtCallbackProc )r_wt_cb_set_range, "from" );
03025     XtAddCallback( X->wt_range_min_w, XmNlosingFocusCallback, 
03026             ( XtCallbackProc )r_wt_cb_set_range, "from" );
03027     
03028     ac = 0;
03029     xstr = XmStringCreateLtoR( " to ", gRX.charset );
03030     XtSetArg( al[ ac ], XmNlabelString, xstr );  ac++;
03031     junk = XmCreateLabel( rc, "label", al, ac );
03032     XtManageChild( junk );
03033     XmStringFree( xstr );
03034     
03035 
03036     sprintf( string, "%d", gRA.wt_range_max );
03037 
03038     ac = 0;
03039     XtSetArg( al[ ac ], XmNvalue, string );  ac++;
03040     XtSetArg( al[ ac ], XmNwidth, 80 );  ac++;
03041     X->wt_range_max_w = XmCreateText( rc, "text", al, ac );
03042     XtManageChild( X->wt_range_max_w );
03043     XtAddCallback( X->wt_range_max_w, XmNactivateCallback, 
03044             ( XtCallbackProc )r_wt_cb_set_range, "to" );
03045     XtAddCallback( X->wt_range_max_w, XmNlosingFocusCallback, 
03046             ( XtCallbackProc )r_wt_cb_set_range, "to" );
03047     
03048     XtManageChild( rc );
03049     XtManageChild( frame );
03050 
03051     return( frame );
03052 }
03053 
03054 
03055 /*----------------------------------------------------------------------
03056 **
03057 **  Clear the filled region for the white matter search.
03058 **
03059 **----------------------------------------------------------------------
03060  */
03061 static void
03062 r_any_cb_unfill(
03063         Widget w,
03064         XtPointer client_data,
03065         XtPointer call_data
03066         )
03067 {
03068     short * fptr, * uptr;
03069     int     count;
03070     int     unfill_val = *((int *)client_data);
03071 
03072     ENTRY("r_any_cb_unfill");
03073 
03074     if ( ! gRA.fdata )
03075         EXRETURN;
03076 
03077     /* first store to undo_data */
03078     fptr = gRA.fdata; uptr = gRA.undo_data;
03079     for ( count = 0; count < gRA.nvox; count++ )
03080         *uptr++ = *fptr++;
03081 
03082     for ( count = 0, fptr = gRA.fdata; count < gRA.nvox; count++, fptr++ )
03083         if ( *fptr == unfill_val )
03084             *fptr = 0;
03085 
03086     THD_load_statistics( gRA.func ) ;
03087     PLUTO_dset_redisplay( gRA.func ) ;
03088 
03089     EXRETURN;
03090 }
03091 
03092 
03093 /*----------------------------------------------------------------------
03094 **
03095 **  Make the check to see if a user boundary neighbor exists.
03096 ** 
03097 **  Okay neighbors values are zero and testval.
03098 ** 
03099 **----------------------------------------------------------------------
03100  */
03101 static int
03102 r_wt_bad_ngbr_exists( r_alg_s * A, int current, int testval )
03103 {
03104     int     last;
03105     int     nx, nxy;
03106     short   val;
03107     short * data;
03108 
03109     ENTRY("r_wt_bad_ngbr_exists");
03110 
03111     data = A->fdata + current;
03112     nx   = A->nx;
03113     nxy  = A->nxy;
03114     last = A->nvox - nxy;
03115 
03116     if ( ( current < nxy ) || ( current >= last ) )
03117         RETURN(1);
03118 
03119     val = data[ -1 ];
03120     if ( val && ( val != testval ) && ( val != R_BOUND_VAL )  )
03121         RETURN(1);
03122 
03123     val = data[ 1 ];
03124     if ( val && ( val != testval ) && ( val != R_BOUND_VAL )  )
03125         RETURN(1);
03126 
03127     val = data[ -nx ];
03128     if ( val && ( val != testval ) && ( val != R_BOUND_VAL )  )
03129         RETURN(1);
03130 
03131     val = data[ nx ];
03132     if ( val && ( val != testval ) && ( val != R_BOUND_VAL )  )
03133         RETURN(1);
03134 
03135     val = data[ -nxy ];
03136     if ( val && ( val != testval ) && ( val != R_BOUND_VAL )  )
03137         RETURN(1);
03138 
03139     val = data[ nxy ];
03140     if ( val && ( val != testval ) && ( val != R_BOUND_VAL )  )
03141         RETURN(1);
03142 
03143     RETURN(0);
03144 }
03145 
03146 
03147 /*----------------------------------------------------------------------
03148 **
03149 **  Make the check for adding a point to the border.
03150 ** 
03151 **----------------------------------------------------------------------
03152  */
03153 static int
03154 r_wt_check_insert( r_alg_s * A, int current )
03155 {
03156     short * aptr = A->adata;
03157     short * fptr = A->fdata;
03158     short * nptr = A->neighbors;
03159     short * fvp  = fptr + current;      /* pointer to function value */
03160 
03161     int value, added = 0;
03162 
03163     ENTRY("r_wt_check_insert");
03164 
03165     value = aptr[ current ];
03166 
03167     /* if new and in range, we will set as a result voxel */
03168     if ( *fvp == 0 )
03169     {
03170         if ( ( value >= A->wt_range_min ) &&
03171              ( value <= A->wt_range_max ) )
03172         {
03173             /* if it also has enough neighbors */
03174             if ( nptr[ current ] >= A->min_nbrs )
03175             {
03176                 /* also check for neighbor in the user's boundary */
03177                 if ( ( ! A->strong_borders ) ||
03178                      ! r_wt_bad_ngbr_exists( A, current, A->wt_fill_val ) )
03179                 {
03180                     if ( ! r_add_to_boundary( &A->Bnew, current ) )
03181                         RETURN(-1);
03182                     else
03183                         added = 1;
03184                 }
03185             }
03186 
03187             /* either way, set point as wt_fill_val */
03188             *fvp = A->wt_fill_val;
03189         }
03190         else    /* add to the 3d boundary */
03191         {
03192             *fvp = R_BOUND_VAL; /* mark as in boundary, clear later */
03193 
03194             if ( ! r_add_to_boundary( &A->border, current ) )
03195                 RETURN(-1);
03196         }
03197     }
03198 
03199     RETURN(added);
03200 }
03201 
03202 
03203 /*----------------------------------------------------------------------
03204 **
03205 **  Callback to fill the local region for a mask.
03206 **
03207 **----------------------------------------------------------------------
03208  */
03209 static void
03210 r_wt_cb_fill(
03211         Widget w,
03212         XtPointer client_data,
03213         XtPointer call_data
03214         )
03215 {
03216     short  * nptr, * fnptr, * flptr, * aptr, * uptr;
03217     int      count, value, current;
03218     int      nxy = gRA.nxy, nx = gRA.nx;
03219     char   * cp = (char *)client_data;
03220     points_t B;
03221 
03222     ENTRY("r_wt_cb_fill");
03223 
03224     /* check that we are ready to fill anything */
03225     if ( ( gRA.point_coord == -1 ) || ( ! gRA.fdata ) )
03226     {
03227         fputc( 7, stderr );      /* hard-code a beep */
03228         EXRETURN;
03229     }
03230 
03231     if ( !gRA.Bold.points || !gRA.Bnew.points ||
03232            !gRA.neighbors || !gRA.undo_data)
03233     {
03234         fprintf( stderr, "Error: rcfr10\n"
03235                  "Memory failure, addresses are %p, %p, %p and %p.\n",
03236                  gRA.Bold.points, gRA.Bnew.points,
03237                  gRA.neighbors, gRA.undo_data );
03238         EXRETURN;
03239     }
03240 
03241     /* first store to undo_data */
03242     fnptr = gRA.fdata; uptr = gRA.undo_data;
03243     for ( count = 0; count < gRA.nvox; count++ )
03244         *uptr++ = *fnptr++;
03245 
03246     /* give the user an idea of what is happening */
03247     rWARNING( "filling white matter" );
03248 
03249     if ( ( cp == NULL ) || ( *cp != '0' ) )
03250     {
03251         for ( count = 0, fnptr = gRA.fdata; count < gRA.nvox; count++, fnptr++ )            if ( *fnptr == gRA.wt_fill_val )
03252                 *fnptr = 0;
03253     }
03254 
03255     r_wt_set_neighbors( &gRA );
03256 
03257     /* set borders to nothing */
03258     gRA.Bold.used    = 0;
03259     gRA.Bnew.used    = 0;
03260     gRA.border.used  = 0;
03261 
03262     if ( r_wt_check_insert( &gRA, gRA.point_coord ) != 1 )
03263         EXRETURN;
03264 
03265     while ( gRA.Bnew.used > 0 )  /* while boundary exists */
03266     {
03267         B             = gRA.Bold; /* swap memory and reset Bnew.used to zero */
03268         gRA.Bold      = gRA.Bnew; /*    - this simply preserves the memory  */
03269         gRA.Bnew      = B;
03270         gRA.Bnew.used = 0;
03271         fputs( ".", stderr );
03272 
03273         for ( count = 0; count < gRA.Bold.used; count++ )
03274         {
03275             current = gRA.Bold.points[count];
03276 
03277             /* 6 'face sharing' points */
03278             r_wt_check_insert( &gRA, current - 1 );
03279             r_wt_check_insert( &gRA, current + 1 );
03280             r_wt_check_insert( &gRA, current - nx );
03281             r_wt_check_insert( &gRA, current + nx );
03282             r_wt_check_insert( &gRA, current - nxy );
03283             r_wt_check_insert( &gRA, current + nxy );
03284 
03285             /* 12 'edge sharing' points */
03286             if ( gRA.wt_diag_connect < 2 )
03287             {
03288                 r_wt_check_insert( &gRA, current + nx - 1 );
03289                 r_wt_check_insert( &gRA, current + nx + 1 );
03290                 r_wt_check_insert( &gRA, current - nx - 1 );
03291                 r_wt_check_insert( &gRA, current - nx + 1 );
03292                 r_wt_check_insert( &gRA, current + nxy - 1 );
03293                 r_wt_check_insert( &gRA, current + nxy + 1 );
03294                 r_wt_check_insert( &gRA, current - nxy - 1 );
03295                 r_wt_check_insert( &gRA, current - nxy + 1 );
03296                 r_wt_check_insert( &gRA, current + nxy - nx );
03297                 r_wt_check_insert( &gRA, current + nxy + nx );
03298                 r_wt_check_insert( &gRA, current - nxy - nx );
03299                 r_wt_check_insert( &gRA, current - nxy + nx );
03300 
03301                 /* 8 'corner sharing' points */
03302                 if ( gRA.wt_diag_connect == 0 )
03303                 {
03304                     r_wt_check_insert( &gRA, current - nxy - nx - 1 );
03305                     r_wt_check_insert( &gRA, current - nxy - nx + 1 );
03306                     r_wt_check_insert( &gRA, current - nxy + nx - 1 );
03307                     r_wt_check_insert( &gRA, current - nxy + nx + 1 );
03308                     r_wt_check_insert( &gRA, current + nxy - nx - 1 );
03309                     r_wt_check_insert( &gRA, current + nxy - nx + 1 );
03310                     r_wt_check_insert( &gRA, current + nxy + nx - 1 );
03311                     r_wt_check_insert( &gRA, current + nxy + nx + 1 );
03312                 }
03313             }
03314         }
03315     }
03316 
03317     /* clear bound markings */
03318     for( count = 0, fnptr = gRA.fdata; count < gRA.nvox; count++, fnptr++ )
03319         if ( *fnptr == R_BOUND_VAL )
03320             *fnptr = 0;
03321 
03322     /* recompute statistics, if the loaded value is big or small */
03323 
03324     THD_load_statistics( gRA.func ) ;
03325 
03326     /* now redisplay dataset, in case anyone is looking at it */
03327 
03328     PLUTO_dset_redisplay( gRA.func ) ;
03329     dset_changed = 1;
03330 
03331     fputs( "done\n\n", stderr );
03332     EXRETURN;
03333 }
03334 
03335 
03336 /*----------------------------------------------------------------------
03337 **
03338 **  Callback to fill the gray matter (or so we somewhat suppose).
03339 **
03340 **----------------------------------------------------------------------
03341  */
03342 static void
03343 r_gr_cb_fill(
03344         Widget w,
03345         XtPointer client_data,
03346         XtPointer call_data
03347         )
03348 {
03349     points_t B;
03350     short  * fnptr, * uptr;
03351     int    * iptr;
03352     int      count, dist, added, current;
03353     int      nx, nxy;
03354 
03355     ENTRY("r_gr_cb_fill");
03356 
03357     nx   = gRA.nx;
03358     nxy  = gRA.nxy;
03359 
03360 
03361     if ( ( gRA.point_coord == -1 ) || ( ! gRA.fdata ) )
03362     {
03363         fputc( 7, stderr );      /* hard-code a beep */
03364         EXRETURN;
03365     }
03366 
03367     if ( gRA.gr_max_dist <= 0 )
03368         EXRETURN;
03369 
03370     if ( !gRA.Bold.points || !gRA.Bnew.points ||
03371            !gRA.neighbors || !gRA.undo_data)    {
03372         fprintf( stderr, "Error: rcfg10\n"
03373                  "Memory failure, addresses are %p, %p, %p and %p.\n",
03374                  gRA.Bold.points, gRA.Bnew.points,
03375                  gRA.neighbors, gRA.undo_data );
03376         EXRETURN;
03377     }
03378 
03379     /* give the user an idea of what is happening */
03380     rWARNING( "filling gray matter" );
03381 
03382 
03383     /* first store to undo_data */
03384     fnptr = gRA.fdata; uptr = gRA.undo_data;
03385     for ( count = 0; count < gRA.nvox; count++ )
03386         *uptr++ = *fnptr++;
03387 
03388     /* clear old memory */
03389     for ( count = 0, fnptr = gRA.fdata; count < gRA.nvox; count++, fnptr++ )
03390         if ( *fnptr == gRA.gr_fill_val )
03391             *fnptr = 0;
03392 
03393     /* set old and new borders to nothing */
03394     gRA.Bold.used     = 0;
03395     gRA.Bnew.used     = 0;
03396 
03397     gRH.gr_edge.used = 0;               /* trash the old gray edge */
03398 
03399     iptr = gRA.border.points;
03400     for ( count = 0; count < gRA.border.used; count++ )
03401     {
03402         if ( ( added = r_gr_check_insert( &gRA, &gRA.Bold, *iptr ) ) == -1 )
03403             EXRETURN;
03404         iptr++;
03405     }
03406 
03407 
03408     dist = 1;
03409     fputc( '.', stdout );
03410     while ( ( gRA.Bold.used > 0 ) && ( dist < gRA.gr_max_dist ) )
03411     {
03412         iptr = gRA.Bold.points;
03413         for ( count = 0; count < gRA.Bold.used; count++ )
03414         {
03415             current = *iptr;
03416 
03417             ( void )r_gr_check_insert( &gRA, &gRA.Bnew, current - 1 );
03418             ( void )r_gr_check_insert( &gRA, &gRA.Bnew, current + 1 );
03419             ( void )r_gr_check_insert( &gRA, &gRA.Bnew, current - nx );
03420             ( void )r_gr_check_insert( &gRA, &gRA.Bnew, current + nx );
03421             ( void )r_gr_check_insert( &gRA, &gRA.Bnew, current - nxy );
03422             ( void )r_gr_check_insert( &gRA, &gRA.Bnew, current + nxy );
03423 
03424             iptr++;
03425         }
03426 
03427         B             = gRA.Bold;
03428         gRA.Bold      = gRA.Bnew;
03429         gRA.Bnew      = B;
03430         gRA.Bnew.used = 0;
03431 
03432         dist++;
03433         fputc( '.', stdout );
03434     }
03435 
03436     /* clear bound markings */
03437     for( count = 0, fnptr = gRA.fdata; count < gRA.nvox; count++, fnptr++ )
03438         if ( *fnptr == R_BOUND_VAL )
03439             *fnptr = 0;
03440 
03441     fputs( "done\n\n", stdout );
03442 
03443     /* recompute statistics, if the loaded value is big or small */
03444 
03445     THD_load_statistics( gRA.func ) ;
03446 
03447     /* now redisplay dataset, in case anyone is looking at it */
03448 
03449     PLUTO_dset_redisplay( gRA.func ) ;
03450     dset_changed = 1;
03451     EXRETURN;
03452 }
03453 
03454 
03455 /*----------------------------------------------------------------------
03456 **
03457 **  Make the check for adding a point to the border.
03458 **
03459 **----------------------------------------------------------------------
03460  */
03461 static int
03462 r_gr_check_insert( r_alg_s * A, points_t * B, int current )
03463 {
03464     short    * aptr = A->adata;
03465     short    * fptr = A->fdata;
03466     short    * nptr = A->neighbors;
03467     short    * fvalp;
03468     int        value, added = 0;
03469 
03470     ENTRY("r_gr_check_insert");
03471 
03472     if ( nptr[ current ] == -1 )        /* do not accept edge points */
03473         RETURN(0);
03474 
03475     fvalp = fptr + current;
03476     value = aptr[ current ];
03477 
03478     /* if new and in range, we will consider setting it as a result */
03479     if ( *fvalp == 0 )
03480     {
03481         if ( ( value >= A->gr_range_min ) &&
03482              ( value <= A->gr_range_max ) )
03483         {
03484             if ( ! r_add_to_boundary( B, current ) )
03485                 RETURN(-1);
03486 
03487             *fvalp = A->gr_fill_val;
03488 
03489             added = 1;
03490         }
03491         else    /* mark as in boundary, add to HOLE's search set */
03492         {
03493             *fvalp = R_BOUND_VAL;
03494             if ( ! r_add_to_boundary( &gRH.gr_edge, current ) )
03495                 RETURN(-1);
03496         }
03497     }
03498 
03499     RETURN(added);
03500 }
03501 
03502 
03503 /*----------------------------------------------------------------------
03504 **
03505 **  Add a point to the boundary.
03506 **
03507 **----------------------------------------------------------------------
03508  */
03509 static int
03510 r_add_to_boundary( points_t * B, int index )
03511 {
03512     ENTRY("r_add_to_boundary");
03513 
03514     if ( !B )
03515     {
03516         fprintf( stderr, "Error: atb10\n"
03517                  "Unexpected error - missing memory for bound structure!\n" );
03518         RETURN(0);
03519     }
03520     else if ( ! B->points )             /* we need initial memory */
03521     {
03522         B->used = 0;
03523         B->M    = 50;
03524         B->points = (int *)malloc( B->M * sizeof( int ) );
03525 
03526         if ( B->points == NULL )
03527         {
03528             fprintf( stderr, "Error: atb15\n"
03529                      "Failed to allocate %d ints for boundary.\n", B->M );
03530             RETURN(0);
03531         }
03532     }
03533     else if ( B->used == B->M )         /* then we need more memory */
03534     {
03535         B->M     *= 2;
03536         B->points = (int *)realloc( B->points, B->M * sizeof( int ) );
03537 
03538         if ( B->points == NULL )
03539         {
03540             fprintf( stderr, "Error: atb20\n"
03541                      "Failed to reallocate %d ints for boundary.\n", B->M );
03542             RETURN(0);
03543         }
03544     }
03545 
03546     B->points[B->used] = index;
03547     B->used++;
03548 
03549     RETURN(1);
03550 }
03551 
03552 
03553 /*----------------------------------------------------------------------
03554 **
03555 **  Fill the neighbors-in-range array.
03556 **
03557 **  init values to zero
03558 **  for each inner value
03559 **      count the number of neighbors (max of 6 - no diagonals) in range
03560 **      ( skip all edges )
03561 **
03562 **----------------------------------------------------------------------
03563  */
03564 static void
03565 r_wt_set_neighbors( r_alg_s * A )
03566 {
03567     short * aptr = A->adata;
03568     short * nptr = A->neighbors;
03569     int     cx, cy, cz;
03570     int     nxy = A->nxy, nx = A->nx;
03571 
03572     ENTRY("r_wt_set_neighbors");
03573 
03574 
03575     for ( cz = 0; cz < A->nz; cz++ )
03576         for ( cy = 0; cy < A->ny; cy++ )
03577             for ( cx = 0; cx < A->nx; cx++ )
03578             {
03579                 *nptr = 0;
03580 
03581                 if ( ( cx == 0 ) || ( cx == A->nx - 1 ) ||
03582                      ( cy == 0 ) || ( cy == A->ny - 1 ) ||
03583                      ( cz == 0 ) || ( cz == A->nz - 1 )
03584                    )
03585                 {
03586                     aptr++;
03587                     *nptr++ = -1;    /* no future consideration */
03588                     continue;
03589                 }
03590                 else if ( *aptr > A->wt_range_max || *aptr < A->wt_range_min )
03591                 {
03592                     aptr++;
03593                     nptr++;
03594                     continue;
03595                 }
03596 
03597                 if ( ( *(aptr-1) <= A->wt_range_max ) &&
03598                      ( *(aptr-1) >= A->wt_range_min ) )
03599                     (*nptr)++;
03600 
03601                 if ( ( *(aptr+1) <= A->wt_range_max ) && 
03602                      ( *(aptr+1) >= A->wt_range_min ) )
03603                     (*nptr)++;
03604 
03605                 if ( ( *(aptr-nx) <= A->wt_range_max ) && 
03606                      ( *(aptr-nx) >= A->wt_range_min ) )
03607                     (*nptr)++;
03608 
03609                 if ( ( *(aptr+nx) <= A->wt_range_max ) &&
03610                      ( *(aptr+nx) >= A->wt_range_min ) )
03611                     (*nptr)++;
03612 
03613                 if ( ( *(aptr-nxy) <= A->wt_range_max ) && 
03614                      ( *(aptr-nxy) >= A->wt_range_min) )
03615                     (*nptr)++;
03616 
03617                 if ( ( *(aptr+nxy) <= A->wt_range_max ) &&
03618                      ( *(aptr+nxy) >= A->wt_range_min) )
03619                     (*nptr)++;
03620 
03621                 aptr++;
03622                 nptr++;
03623             }
03624 
03625     EXRETURN;
03626 }
03627 
03628 
03629 /*----------------------------------------------------------------------
03630 **
03631 **  Callback to set the minimum neighbors in search (1 to 6).
03632 **
03633 **----------------------------------------------------------------------
03634  */
03635 static void
03636 r_wt_cb_set_diag_conn(
03637         Widget w,
03638         XtPointer client_data,
03639         XtPointer call_data
03640         )
03641 {
03642     char * text;
03643     int    ival;
03644 
03645     ENTRY("r_wt_cb_set_diag_conn");
03646 
03647     text = XmTextGetString( w );
03648 
03649     if ( ! text || ! *text )    /* nothing typed */
03650     {
03651         if ( text )
03652             XtFree( text );
03653         EXRETURN;
03654     }
03655 
03656     /*
03657     **  Make sure a value has changed (to something acceptable)
03658     **  before applying.
03659     */
03660 
03661     ival = atoi( text );
03662     if ( ( ival < 0 ) || ( ival > 2 ) )
03663     {
03664         sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 0, 2 );
03665         rERROR( gRmessage );
03666         EXRETURN;
03667     }
03668 
03669     if ( gRA.wt_diag_connect != ival )
03670         gRA.wt_diag_connect = ival;
03671 
03672     XtFree( text );
03673     EXRETURN;
03674 }
03675 
03676 
03677 /*----------------------------------------------------------------------
03678 **
03679 **  Callback to set the minimum neighbors in search (1 to 6).
03680 **
03681 **----------------------------------------------------------------------
03682  */
03683 static void
03684 r_wt_cb_set_min_nbrs(
03685         Widget w,
03686         XtPointer client_data,
03687         XtPointer call_data
03688         )
03689 {
03690     char * text;
03691     int    ival;
03692 
03693     text = XmTextGetString( w );
03694 
03695     if ( ! text || ! *text )    /* nothing typed */
03696     {
03697         if ( text )
03698             XtFree( text );
03699         return;
03700     }
03701 
03702     /*
03703     **  Make sure a value has changed (to something acceptable)
03704     **  before applying.
03705     */
03706 
03707     ival = atoi( text );
03708     if ( ( ival < 0 ) || ( ival > 6 ) )
03709     {
03710         sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 0, 6 );
03711         rERROR( gRmessage );
03712         return;
03713     }
03714 
03715     if ( gRA.min_nbrs != ival )
03716         gRA.min_nbrs = ival;
03717 
03718 
03719     XtFree( text );
03720 }
03721 
03722 
03723 /*----------------------------------------------------------------------
03724 **
03725 **  Callback to set the maximum distance in gray search.
03726 **
03727 **----------------------------------------------------------------------
03728  */
03729 static void
03730 r_gr_cb_set_max_dist(
03731         Widget w,
03732         XtPointer client_data,
03733         XtPointer call_data
03734         )
03735 {
03736     char * text;
03737     int    ival;
03738 
03739     text = XmTextGetString( w );
03740 
03741     if ( ! text || ! *text )    /* nothing typed */
03742     {
03743         if ( text )
03744             XtFree( text );
03745         return;
03746     }
03747 
03748     /*
03749     **  Make sure a value has changed (to something acceptable)
03750     **  before applying.
03751     */
03752 
03753     ival = atoi( text );
03754     if ( ( ival < 1 ) || ( ival > 200 ) )
03755     {
03756         sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 1, 200 );
03757         rERROR( gRmessage );
03758         return;
03759     }
03760 
03761     if ( gRA.gr_max_dist != ival )
03762         gRA.gr_max_dist = ival;
03763 
03764 
03765     XtFree( text );
03766 }
03767 
03768 
03769 /*----------------------------------------------------------------------
03770 **
03771 **  Callback to set the maximum fill size for the holes app.
03772 **
03773 **----------------------------------------------------------------------
03774  */
03775 static void
03776 r_HL_cb_set_maxsize(
03777         Widget w,
03778         XtPointer client_data,
03779         XtPointer call_data
03780         )
03781 {
03782     char * text;
03783     int    ival;
03784 
03785     text = XmTextGetString( w );
03786 
03787     if ( ! text || ! *text )    /* nothing typed */
03788     {
03789         if ( text )
03790             XtFree( text );
03791         return;
03792     }
03793 
03794     /*
03795     **  Make sure a value has changed (to something acceptable)
03796     **  before applying.
03797     */
03798 
03799     ival = atoi( text );
03800     if ( ival < 1 )
03801     {
03802         sprintf( gRmessage, "Value %d is not in range [%d,oo).", ival, 1 );
03803         rERROR( gRmessage );
03804         return;
03805     }
03806 
03807     if ( gRH.max_size != ival )
03808         gRH.max_size = ival;
03809 
03810     XtFree( text );
03811 }
03812 
03813 
03814 /*----------------------------------------------------------------------
03815 **
03816 **  Callback to set the fill value for the holes app.
03817 **
03818 **----------------------------------------------------------------------
03819  */
03820 static void
03821 r_HL_cb_set_fill_val(
03822         Widget w,
03823         XtPointer client_data,
03824         XtPointer call_data
03825         )
03826 {
03827     char * text;
03828     int    ival;
03829 
03830     text = XmTextGetString( w );
03831 
03832     if ( ! text || ! *text )    /* nothing typed */
03833     {
03834         if ( text )
03835             XtFree( text );
03836         return;
03837     }
03838 
03839     /*
03840     **  Make sure a value has changed (to something acceptable)
03841     **  before applying.
03842     */
03843 
03844     ival = atoi( text );
03845     if ( ( ival < 0 ) || ( ival > 255 ) )
03846     {
03847         sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 0, 255 );
03848         rERROR( gRmessage );
03849         return;
03850     }
03851     else if ( ival == 0 )
03852     {
03853         rWARNING( "Using hole fill value of 0." );
03854     }
03855 
03856 
03857     if ( gRH.fill_val != ival )
03858         gRH.fill_val = ival;
03859 
03860 
03861     XtFree( text );
03862 }
03863 
03864 
03865 /*----------------------------------------------------------------------
03866 **
03867 **  Callback to set the fill value.
03868 **
03869 **----------------------------------------------------------------------
03870  */
03871 static void
03872 r_INT_cb_set_fill_val(
03873         Widget w,
03874         XtPointer client_data,
03875         XtPointer call_data
03876         )
03877 {
03878     char * text;
03879     int    ival;
03880 
03881     text = XmTextGetString( w );
03882 
03883     if ( ! text || ! *text )    /* nothing typed */
03884     {
03885         if ( text )
03886             XtFree( text );
03887         return;
03888     }
03889 
03890     /*
03891     **  Make sure a value has changed (to something acceptable)
03892     **  before applying.
03893     */
03894 
03895     ival = atoi( text );
03896     if ( ( ival < 0 ) || ( ival > 255 ) )
03897     {
03898         sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 0, 255 );
03899         rERROR( gRmessage );
03900         return;
03901     }
03902     else if ( ival == 0 )
03903     {
03904         rWARNING( "Using interpolation fill value of 0." );
03905     }
03906 
03907     if ( gRI.fill_val != ival )
03908         gRI.fill_val = ival;
03909 
03910 
03911     XtFree( text );
03912 }
03913 
03914 
03915 /*----------------------------------------------------------------------
03916 **
03917 **  Callback to set the fill value.
03918 **
03919 **----------------------------------------------------------------------
03920  */
03921 static void
03922 r_wt_cb_set_fill_val(
03923         Widget w,
03924         XtPointer client_data,
03925         XtPointer call_data
03926         )
03927 {
03928     char * text;
03929     int    ival;
03930 
03931     text = XmTextGetString( w );
03932 
03933     if ( ! text || ! *text )    /* nothing typed */
03934     {
03935         if ( text )
03936             XtFree( text );
03937         return;
03938     }
03939 
03940     /*
03941     **  Make sure a value has changed (to something acceptable)
03942     **  before applying.
03943     */
03944 
03945     ival = atoi( text );
03946     if ( ( ival < 0 ) || ( ival > 255 ) )
03947     {
03948         sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 0, 255 );
03949         rERROR( gRmessage );
03950         return;
03951     }
03952     else if ( ival == 0 )
03953     {
03954         rWARNING( "Warning : using white matter fill value of 0." );
03955     }
03956 
03957     if ( gRA.wt_fill_val != ival )
03958         gRA.wt_fill_val = ival;
03959 
03960 
03961     XtFree( text );
03962 }
03963 
03964 
03965 /*----------------------------------------------------------------------
03966 **
03967 **  Callback to set the fill value.
03968 **
03969 **----------------------------------------------------------------------
03970  */
03971 static void
03972 r_gr_set_fill_val(
03973         Widget w,
03974         XtPointer client_data,
03975         XtPointer call_data
03976         )
03977 {
03978     char * text;
03979     int    ival;
03980 
03981     text = XmTextGetString( w );
03982 
03983     if ( ! text || ! *text )    /* nothing typed */
03984     {
03985         if ( text )
03986             XtFree( text );
03987         return;
03988     }
03989 
03990     /*
03991     **  Make sure a value has changed (to something acceptable)
03992     **  before applying.
03993     */
03994 
03995     ival = atoi( text );
03996     if ( ( ival < 1 ) || ( ival > 255 ) )
03997     {
03998         sprintf( gRmessage, "Value %d is not in range [%d,%d].", ival, 1, 255 );
03999         rERROR( gRmessage );
04000         return;
04001     }
04002 
04003     if ( gRA.gr_fill_val != ival )
04004         gRA.gr_fill_val = ival;
04005 
04006 
04007     XtFree( text );
04008 }
04009 
04010 
04011 /*----------------------------------------------------------------------
04012 **
04013 **  Callback to set the white search range.
04014 **
04015 **----------------------------------------------------------------------
04016  */
04017 static void
04018 r_wt_cb_set_range(
04019         Widget w,
04020         XtPointer client_data,
04021         XtPointer call_data
04022         )
04023 {
04024     char * string = ( char * )client_data;
04025     char * text;
04026     int    ival;
04027 
04028     text = XmTextGetString( w );
04029 
04030     if ( ! text || ! *text )    /* nothing typed */
04031     {
04032         if ( text )
04033             XtFree( text );
04034         return;
04035     }
04036 
04037     if ( ! string )  /* strange error - complain and return */
04038     {
04039         fprintf( stderr, "r_wt_cb_set_range error - string is NULL\n" );
04040         return;
04041     }
04042     else if ( ! *string )
04043     {
04044         fprintf( stderr, "r_wt_cb_set_range error - string is empty\n" );
04045         return;
04046     }
04047     else if ( ! strcmp( string, "to" ) && ! strcmp( string, "from" ) )
04048     {
04049         fprintf( stderr, "r_wt_cb_set_range error -\n"
04050                          "'%s' should be 'to' or 'from'.\n", string );
04051         return;
04052     }
04053 
04054     /*
04055     **  Make sure a value has changed (to something acceptable)
04056     **  before applying.  Use short range.
04057     */
04058 
04059     ival = atoi( text );
04060     if ( ( ival < -32768 ) || ( ival > 32767 ) )
04061     {
04062         fprintf( stderr, "Value %d is not in range [%d,%d].\n",
04063                          ival, -32768, 32767 );
04064         return;
04065     }
04066 
04067     if ( ! strcmp( string, "from" ) )
04068     {
04069         if ( gRA.wt_range_min != ival )
04070         {
04071             gRA.wt_range_min = ival;
04072 
04073             if ( gRA.wt_range_min > gRA.wt_range_max )
04074             {
04075                 sprintf( gRmessage, "\nWarning!"
04076                     "  Min value should be less than max value.\n"
04077                     "Value are %d and %d, respectively.\n",
04078                          gRA.wt_range_min, gRA.wt_range_max );
04079                 rERROR( gRmessage );
04080             }
04081         }
04082     }
04083     else
04084     {
04085         if ( gRA.wt_range_max != ival )
04086         {
04087             gRA.wt_range_max = ival;
04088 
04089             if ( gRA.wt_range_min > gRA.wt_range_max )
04090             {
04091                 sprintf( gRmessage, "\nWarning!"
04092                          "  Min value should be less than max value.\n"
04093                          "Value are %d and %d, respectively.\n",
04094                          gRA.wt_range_min, gRA.wt_range_max );
04095                 rERROR( gRmessage );
04096             }
04097         }
04098     }
04099 
04100     XtFree( text );
04101 }
04102 
04103 
04104 /*----------------------------------------------------------------------
04105 **
04106 **  Callback to set the search range.
04107 **
04108 **----------------------------------------------------------------------
04109  */
04110 static void
04111 r_gr_cb_set_range(
04112         Widget w,
04113         XtPointer client_data,
04114         XtPointer call_data
04115         )
04116 {
04117     char * string = ( char * )client_data;
04118     char * text;
04119     int    ival;
04120 
04121     text = XmTextGetString( w );
04122 
04123     if ( ! text || ! *text )    /* nothing typed */
04124     {
04125         if ( text )
04126             XtFree( text );
04127         return;
04128     }
04129 
04130     if ( ! string )  /* strange error - complain and return */
04131     {
04132         fprintf( stderr, "r_gr_cb_set_range error - string is NULL\n" );
04133         return;
04134     }
04135     else if ( ! *string )
04136     {
04137         fprintf( stderr, "r_gr_cb_set_range error - string is empty\n" );
04138         return;
04139     }
04140     else if ( ! strcmp( string, "to" ) && ! strcmp( string, "from" ) )
04141     {
04142         fprintf( stderr, "r_gr_cb_set_range error -\n"
04143                          "'%s' should be 'to' or 'from'.\n", string );
04144         return;
04145     }
04146 
04147     /*
04148     **  Make sure a value has changed (to something acceptable)
04149     **  before applying.  Use short range.
04150     */
04151 
04152     ival = atoi( text );
04153     if ( ( ival < -32768 ) || ( ival > 32767 ) )
04154     {
04155         sprintf( gRmessage, "Value %d is not in range [%d,%d].",
04156                          ival, -32768, 32767 );
04157         rERROR( gRmessage );
04158         return;
04159     }
04160 
04161     if ( ! strcmp( string, "from" ) )
04162     {
04163         if ( gRA.gr_range_min != ival )
04164         {
04165             gRA.gr_range_min = ival;
04166 
04167             if ( gRA.gr_range_min > gRA.gr_range_max )
04168             {
04169                 sprintf( gRmessage, "\nWarning!"
04170                     "  Min value should be less than max value.\n"
04171                     "Value are %d and %d, respectively.\n",
04172                          gRA.gr_range_min, gRA.gr_range_max );
04173                 rERROR( gRmessage );
04174             }
04175         }
04176     }
04177     else
04178     {
04179         if ( gRA.gr_range_max != ival )
04180         {
04181             gRA.gr_range_max = ival;
04182 
04183             if ( gRA.gr_range_min > gRA.gr_range_max )
04184             {
04185                 sprintf( gRmessage, "\nWarning!"
04186                          "  Min value should be less than max value.\n"
04187                          "Value are %d and %d, respectively.\n",
04188                          gRA.gr_range_min, gRA.gr_range_max );
04189                 rERROR( gRmessage );
04190             }
04191         }
04192     }
04193 
04194     XtFree( text );
04195 }
04196 
04197 
04198 /*----------------------------------------------------------------------
04199 **
04200 **  The user has selected an initial fill point.
04201 **
04202 **  Update the search range.  If the user wants the initial point
04203 **  aligned (moved to local extrema), do it.
04204 **
04205 **----------------------------------------------------------------------
04206  */
04207 static int
04208 r_afni_set_fill_point(
04209         int       * coord,      /* offset of initial point (modifiable) */
04210         r_alg_s * A             /* algorithm structure                  */
04211         )
04212 {
04213     ENTRY("r_afni_set_fill_point");
04214 
04215     A->point_coord = *coord;
04216 
04217     /*printf("A = %p,  A->adata = %p,  A->point_coord = %d\n",
04218             A,A->adata,A->point_coord);
04219     fflush(stdout);*/
04220     
04221     if ( A->adata == NULL )
04222     {
04223         /*fprintf(stderr,"Loading data...\n");
04224         DSET_load(A->anat);*/
04225         fputs("r_afni_set_fill_point(): Error: No anatomical data. ( A->adata = NULL )\n",stderr);
04226         fputs("This may have been caused by selecting Talairach\n",stderr);
04227         fputs("view before Switch Underlay or Switch Overlay.\n",stderr);
04228         fputs("Try setting the environment variable AFNI_VIEW_ANAT_BRICK\n",stderr);
04229         fputs("(The value is irrelevant) and run afni again.\n",stderr);
04230         RETURN(-1);
04231     }
04232     A->point_value = A->adata[A->point_coord];   /* no anat factor? */
04233 
04234 
04235     printf( "coord = %d, adata = %d, fdata = %d, ndata = %d\n",
04236              *coord, A->adata[*coord], A->fdata[*coord], A->neighbors[*coord] );
04237 
04238     RETURN(0);
04239 }
04240 
04241 
04242 /*----------------------------------------------------------------------
04243 **
04244 **  Create a scale bar.
04245 **
04246 **----------------------------------------------------------------------
04247  */
04248 
04249 static Widget
04250 r_mk_scale_bar(
04251         Widget          parent,
04252         char          * title,
04253         int             min,
04254         int             max,
04255         int             value,
04256         int             decimal_places,
04257         XtCallbackProc  callback
04258         )
04259 {
04260     int         ac;
04261     Arg         al[ 20 ];
04262     XmString    Xtitle;
04263     Widget      scale;
04264 
04265     Xtitle = XmStringCreateLtoR( title, gRX.charset );
04266 
04267     ac = 0;
04268     XtSetArg( al[ac], XmNtitleString,      Xtitle );         ac++;
04269     XtSetArg( al[ac], XmNorientation,      XmHORIZONTAL );   ac++;
04270     XtSetArg( al[ac], XmNminimum,          min    );         ac++;
04271     XtSetArg( al[ac], XmNmaximum,          max    );         ac++;
04272     XtSetArg( al[ac], XmNvalue,            value  );         ac++;
04273     XtSetArg( al[ac], XmNshowValue,        True   );         ac++;
04274 
04275     if ( decimal_places > 0 )
04276     {
04277         XtSetArg( al[ac], XmNdecimalPoints, decimal_places );
04278         ac++;
04279     }
04280 
04281 
04282     scale = XmCreateScale( parent, "scale_bar", al, ac );
04283 
04284     XmStringFree( Xtitle );
04285 
04286     XtManageChild( scale );
04287 
04288     XtAddCallback( scale, XmNvalueChangedCallback, callback, NULL );
04289 
04290     return scale;
04291 }
04292 
04293 
04294 /*----------------------------------------------------------------------
04295 **
04296 **  Display the contents of the algorithm structure.
04297 **
04298 **--------------------------------------------------------------------- 
04299  */
04300 
04301 static void
04302 r_main_show_alg_vals( r_alg_s * A )
04303 {
04304     printf( "-----------------------------------\n" );
04305 
04306     printf(
04307         "gRA :\n"
04308         "\n"
04309         "point value             : %d\n"
04310         "point coord             : %d\n"
04311         "adjust point            : %d\n"
04312         "'save as' name          : %s\n"
04313         "\n"
04314         "white fill value        : %d\n"
04315         "white range min         : %d\n"
04316         "white range max         : %d\n"
04317         "white diag connect      : %d\n"
04318         "\n"
04319         "gray fill value         : %d\n"
04320         "gray range min          : %d\n"
04321         "gray range max          : %d\n"
04322         "gray max distance       : %d\n"
04323         "\n"
04324         "anat dset        (addr) : %p\n"
04325         "func dset        (addr) : %p\n"
04326         "adata data       (addr) : %p\n"
04327         "fdata data       (addr) : %p\n"
04328         "factor                  : %f\n"
04329         "nx                      : %d\n"
04330         "ny                      : %d\n"
04331         "nz                      : %d\n"
04332         "nvox                    : %d\n"
04333         "\n"
04334         "old bound.M             : %d\n"
04335         "old bound.used          : %d\n"
04336         "old bound.points (addr) : %p\n"
04337         "new bound.M             : %d\n"
04338         "new bound.used          : %d\n"
04339         "new bound.points (addr) : %p\n"
04340         "border.M                : %d\n"
04341         "border.used             : %d\n"
04342         "border.points    (addr) : %p\n"
04343         "\n"
04344         "neighbors        (addr) : %p\n"
04345         "undo data        (addr) : %p\n"
04346         "\n"
04347         "min neighbors           : %d\n"
04348         "strong borders          : %d\n",
04349         A->point_value, A->point_coord, A->adjust_point, A->save_as_name,
04350         A->wt_fill_val, A->wt_range_min, A->wt_range_max,
04351             A->wt_diag_connect,
04352         A->gr_fill_val, A->gr_range_min, A->gr_range_max, A->gr_max_dist,
04353         A->anat, A->func,
04354         A->adata, A->fdata,
04355         A->factor, A->nx, A->ny, A->nz, A->nvox,
04356         A->Bold.M, A->Bold.used, A->Bold.points,
04357         A->Bnew.M, A->Bnew.used, A->Bnew.points,
04358         A->border.M, A->border.used, A->border.points,
04359         A->neighbors, A->undo_data,
04360         A->min_nbrs, A->strong_borders
04361         );
04362 
04363     printf( "-----------------------------------\n" );
04364 }
04365 
04366 
04367 /*----------------------------------------------------------------------
04368 **
04369 **  Display the contents of the interpolation structure.
04370 **
04371 **----------------------------------------------------------------------
04372  */
04373 static void
04374 r_main_show_INT_vals( interp_s * I )
04375 {
04376     printf( "-----------------------------------\n" );
04377 
04378     printf(
04379         "gRI :\n"
04380         "\n"
04381         "fill value       : %d\n"
04382         "afni undo        : %d\n"
04383         "\n"
04384         "A.M              : %d\n"
04385         "A.used           : %d\n"
04386         "A.points  (addr) : %p\n"
04387         "B.M              : %d\n"
04388         "B.used           : %d\n"
04389         "B.points  (addr) : %p\n",
04390         I->fill_val, I->afni_undo,
04391         I->A.M, I->A.used, I->A.points,
04392         I->B.M, I->B.used, I->B.points
04393         );
04394 
04395     printf( "-----------------------------------\n" );
04396 }
04397 
04398 
04399 /*----------------------------------------------------------------------
04400 **
04401 **  Display the contents of the holes structure.
04402 **
04403 **----------------------------------------------------------------------
04404  */
04405 static void
04406 r_main_show_HL_vals( holes_s * H )
04407 {
04408     printf( "-----------------------------------\n" );
04409     printf(
04410         "gRH :\n"
04411         "\n"
04412         "max size                : %d\n"
04413         "fill value              : %d\n"
04414         "wtgr_edge.M             : %d\n"
04415         "wtgr_edge.used          : %d\n"
04416         "wtgr_edge.points (addr) : %p\n"
04417         "filled.M                : %d\n"
04418         "filled.used             : %d\n"
04419         "filled.points (addr)    : %p\n",
04420         H->max_size, H->fill_val,
04421         H->wtgr_edge.M, H->wtgr_edge.used, H->wtgr_edge.points,
04422         H->filled.M, H->filled.used, H->filled.points
04423         );
04424     printf( "-----------------------------------\n" );
04425 }
04426 
04427 
04428 /*----------------------------------------------------------------------
04429 **
04430 **  Display the contents of the point connection structure.
04431 **
04432 **----------------------------------------------------------------------
04433  */
04434 static void
04435 r_main_show_pt_conn_vals( r_pt_conn_s * PC )
04436 {
04437     printf( "-----------------------------------\n" );
04438     printf(
04439         "gRCP :\n"
04440         "\n"
04441         "plist.M             : %d\n"
04442         "plist.used          : %d\n"
04443         "plist.points (addr) : %p\n"
04444         "source point        : (%d,%d,%d)\n"
04445         "dest point          : (%d,%d,%d)\n"
04446         "which point         : %d\n",
04447         PC->plist.M, PC->plist.used, PC->plist.points,
04448         PC->source.x, PC->source.y, PC->source.z,
04449         PC->dest.x, PC->dest.y, PC->dest.z,
04450         PC->cur_pt
04451         );
04452     printf( "-----------------------------------\n" );
04453 }
04454 
04455 
04456 /*----------------------------------------------------------------------
04457 **
04458 **  Callback to get help.  This displays a general process overview.
04459 **
04460 **----------------------------------------------------------------------
04461  */
04462 static void
04463 r_main_cb_help(
04464         Widget    w,
04465         XtPointer client_data,
04466         XtPointer call_data
04467         )
04468 {
04469     ( void )new_MCW_textwin( w,
04470 
04471 #include "plug_roiedit.hhh"
04472 
04473          "Compiled: "
04474          __DATE__
04475          ", "
04476          __TIME__
04477          "\n"
04478 
04479         , TEXT_READONLY );
04480 
04481     return;
04482 }
04483 
04484 
04485 /*----------------------------------------------------------------------
04486 **
04487 **  Callback to quit ( this merely unmanages all the widgets ).
04488 **
04489 **----------------------------------------------------------------------
04490  */
04491 static void
04492 r_main_cb_quit( void )
04493 {
04494     r_any_cb_hide( NULL, "all", NULL );
04495     XtUnmapWidget( gRX.main );
04496     gRX.main_is_open = 0;
04497 }
04498 
04499 
04500 /*----------------------------------------------------------------------
04501 **
04502 **  Callback to save the current dataset under a new name.
04503 **
04504 **----------------------------------------------------------------------
04505  */
04506 static void
04507 r_main_cb_saveas(
04508         Widget w,
04509         int       client_data,
04510         XtPointer call_data
04511         )
04512 {
04513     XmSelectionBoxCallbackStruct * cbs;
04514     char * text;
04515     int    ival;
04516 
04517     ENTRY("r_main_cb_saveas");
04518 
04519     cbs = ( XmSelectionBoxCallbackStruct * )call_data;
04520 
04521     if ( ! XmStringGetLtoR( cbs->value, gRX.charset, &text ) )
04522     {
04523         rERROR( "Failed to get filename from text." );
04524         EXRETURN;
04525     }
04526     else if ( ! *text )
04527     {
04528         XtFree( text );
04529         EXRETURN;
04530     }
04531 
04532     /* Make sure file name is not too long.  */
04533 
04534     if ( strlen( text ) > R_FILE_L - 14 )  /* leave from for +tlrc.BRIK.gz_ */
04535     {
04536         sprintf( gRmessage, "Output filename '%s' exceeds %d characters.\n",
04537                             text, R_FILE_L - 14 );
04538         rERROR( gRmessage );
04539     }
04540     else
04541         strcpy( gRA.save_as_name, text );
04542 
04543     XtFree( text );
04544 
04545     r_save_dataset_as( gRA.save_as_name, client_data );
04546     EXRETURN;
04547 }
04548 
04549 
04550 /*----------------------------------------------------------------------
04551 **
04552 **  Actually save the new dataset.  Make a copy of the original dset,
04553 **  change the prefix and save the file.
04554 **
04555 **----------------------------------------------------------------------
04556  */
04557 static int
04558 r_save_dataset_as( char * filename, int overwrite )
04559 {
04560     THD_3dim_dataset * dset = NULL;
04561 
04562     ENTRY("r_save_dataset_as");
04563 
04564     if ( ! ( dset = PLUTO_copy_dset( gRA.func, filename ) ) )
04565     {
04566         sprintf( gRmessage,"Failed to copy dataset with name '%s'.", filename );
04567         rERROR( gRmessage );
04568         RETURN(0);
04569     }
04570 
04571     if( ! overwrite && THD_is_file( dset->dblk->diskptr->header_name ) )
04572     {
04573         sprintf( gRmessage, "File '%s' already exists!", filename );
04574         rERROR( gRmessage );
04575     }
04576     else
04577     {
04578         THD_load_statistics( dset );
04579         THD_write_3dim_dataset( NULL, NULL, dset, True );
04580 
04581         sprintf( gRmessage, "Dataset copied as '%s'.", filename );
04582         rWARNING( gRmessage );
04583     }
04584 
04585     THD_delete_3dim_dataset( dset, False );
04586 
04587     RETURN(1);
04588 }
04589 
04590 
04591 /*----------------------------------------------------------------------
04592 **
04593 **  Display the contents of internal structures.
04594 **
04595 **----------------------------------------------------------------------
04596  */
04597 static void
04598 r_main_cb_show_structs( void )
04599 {
04600     ENTRY("r_main_cb_show_structs");
04601 
04602     printf( "------------------------------------------------------------\n" );
04603         
04604     r_main_show_alg_vals    ( &gRA );
04605     r_main_show_INT_vals    ( &gRI );
04606     r_main_show_HL_vals     ( &gRH );
04607     r_main_show_pt_conn_vals( &gRCP );
04608 
04609     printf( "------------------------------------------------------------\n" );
04610     EXRETURN;
04611 }
04612 
04613 
04614 /*----------------------------------------------------------------------
04615 **------                                --------------------------------
04616 **------  Begin interpolation routines  --------------------------------
04617 **------                                --------------------------------
04618 **----------------------------------------------------------------------
04619 **
04620 **  The technique here is to keep two curves of data stored.
04621 **
04622 **  Operations that we need to consider are :   
04623 **
04624 **      o  inserting a new line ( on any line draw )
04625 **              if none     { insert first  }
04626 **              else if one { insert second }
04627 **              else        { move second to first, insert second }
04628 **      o  UNDO move
04629 **              if two      { remove second }
04630 **              else        { remove first  }
04631 **      o  interpolate  ( use special interpolation value )
04632 **              - only with the two lines
04633 **              - store previous interpolation first
04634 **                  ( change interpolation values to draw values )
04635 **      o  undo interpolation
04636 **              remove all interpolation values
04637 **
04638 **----------------------------------------------------------------------
04639  */
04640 
04641 
04642 /*-------------------------------------------------------------------
04643   Callback for done button
04644 ---------------------------------------------------------------------*/
04645 
04646 static void DRAW_done_CB( Widget w, XtPointer client_data, XtPointer call_data )
04647 {
04648     ENTRY("DRAW_done_CB");
04649 
04650    if( dset != NULL ){
04651       if( recv_open ) AFNI_receive_control( im3d, recv_key, DRAWING_SHUTDOWN, NULL ) ;
04652       if( dset_changed ){
04653          MCW_invert_widget( done_pb ) ;
04654          DSET_write(dset) ;
04655          MCW_invert_widget( done_pb ) ;
04656       }
04657       DSET_unlock(dset) ; DSET_anyize(dset) ;
04658       dset = NULL ; dset_changed = 0 ;
04659    }
04660 
04661    if( undo_buf != NULL ){
04662       free(undo_buf) ; free(undo_xyz) ;
04663       undo_buf = NULL; undo_xyz = NULL;
04664       undo_bufsiz = undo_bufnum = undo_bufuse = 0 ;
04665    }
04666 
04667    XtUnmapWidget( shell ) ; editor_open = 0 ; recv_open = 0 ; recv_key = -1 ;
04668    EXRETURN;
04669 }
04670 
04671 /*-------------------------------------------------------------------
04672   Callback for undo button
04673 ---------------------------------------------------------------------*/
04674 
04675 static void DRAW_undo_CB( Widget w, XtPointer client_data, XtPointer call_data )
04676 {
04677    void * ub ; int * ux, * uy, * uz ;
04678    int ubs = undo_bufsiz , uis = sizeof(int)*undo_bufuse ;
04679 
04680    ENTRY("DRAW_undo_CB");
04681 
04682    if( undo_bufuse <= 0 ){ XBell( dc->display , 100 ) ; EXRETURN ; }
04683 
04684    /* since the undo_stuff will be modified by the
04685       drawing function, we must make temporary copies */
04686 
04687    ub =         malloc(ubs) ; memcpy(ub,undo_buf,ubs) ;
04688    ux = (int *) malloc(uis) ; memcpy(ux,undo_xyz,uis) ;
04689 
04690    gRI.afni_undo = 1;
04691    DRAW_into_dataset( undo_bufuse , ux,NULL,NULL , ub ) ;
04692    gRI.afni_undo = 0;
04693 
04694    if ( ( mode_ival == MODE_CURVE ) || ( mode_ival == MODE_CLOSED ) ||
04695         ( mode_ival == MODE_CONN_PTS ) )
04696    {
04697         gRI.B.used = 0;         /* RCR - clear any new I-data */
04698 
04699         if ( mode_ival == MODE_CONN_PTS )
04700             gRCP.cur_pt = 1;
04701    }
04702 
04703    free(ub) ; free(ux) ;
04704    EXRETURN ;
04705 }
04706 
04707 /*-------------------------------------------------------------------
04708   Callback for quit button
04709 ---------------------------------------------------------------------*/
04710 
04711 static void DRAW_quit_CB( Widget w, XtPointer client_data, XtPointer call_data )
04712 {
04713    ENTRY("DRAW_quit_CB");
04714 
04715    if( dset != NULL ){
04716       if( recv_open ) AFNI_receive_control( im3d, recv_key, DRAWING_SHUTDOWN, NULL ) ;
04717       DSET_unlock(dset) ;
04718       DSET_unload(dset) ; DSET_anyize(dset) ;
04719       if( dset_changed ){
04720          MCW_invert_widget(quit_pb) ;
04721          THD_load_statistics( dset ) ;
04722          PLUTO_dset_redisplay( dset ) ;
04723          MCW_invert_widget(quit_pb) ;
04724       }
04725       dset = NULL ; dset_changed = 0 ;
04726    }
04727 
04728    if( undo_buf != NULL ){
04729       free(undo_buf) ; free(undo_xyz) ;
04730       undo_buf = NULL; undo_xyz = NULL;
04731       undo_bufsiz = undo_bufnum = undo_bufuse = 0 ;
04732    }
04733 
04734    XtUnmapWidget( shell ) ; editor_open = 0 ; recv_open = 0 ; recv_key = -1 ;
04735    EXRETURN ;
04736 }
04737 
04738 /*-------------------------------------------------------------------
04739   Callback for save button
04740 ---------------------------------------------------------------------*/
04741 
04742 static void DRAW_save_CB( Widget w, XtPointer client_data, XtPointer call_data )
04743 {
04744    ENTRY("DRAW_save_CB");
04745 
04746    if( dset == NULL ){ XBell( dc->display , 100 ) ; EXRETURN ; }
04747 
04748    MCW_invert_widget(save_pb) ;
04749 
04750    DSET_write(dset) ; dset_changed = 0 ; SENSITIZE(choose_pb,1) ;
04751 
04752    MCW_invert_widget(save_pb) ; SENSITIZE(save_pb,0) ;
04753    EXRETURN ;
04754 }
04755 
04756 /*-------------------------------------------------------------------
04757   Callback for help button
04758 ---------------------------------------------------------------------*/
04759 
04760 static void DRAW_help_CB( Widget w, XtPointer client_data, XtPointer call_data )
04761 {
04762    (void ) new_MCW_textwin( help_pb ,
04763 
04764   "The GyrusFinder plugin is based on the original 'Draw Dataset' plugin\n"
04765   "by RW Cox.  The original help for that plugin is below.  Help for the\n"
04766   "new features can be found in the new windows created by GyrusFinder.\n"
04767   "======================================================================\n"
04768   "This plugin can be used to edit interactively the voxel contents\n"
04769   "of a dataset.  Since such changes are irreversible, it is best that\n"
04770   "you either edit a copy of a dataset, or create a dataset of all zeros.\n"
04771   "These tasks can be done with the 'Dataset Copy' plugin.\n"
04772   "\n"
04773   "***************** Read the WARNINGS section below. *****************\n"
04774   "\n"
04775   "---------------------- Bob Cox, February 1998 ----------------------\n"
04776   "\n"
04777   "Step 1) Choose a dataset to edit.\n"
04778   "        * Only datasets that have data BRIKs stored at the current\n"
04779   "            resolution can be edited.\n"
04780   "        * Datasets may be copied with the 'Dataset Copy' plugin.\n"
04781   "        * It is probably best that the dataset being edited be\n"
04782   "            displayed.  Otherwise it will be impossible to gauge\n"
04783   "            the effect of the editing operations.\n"
04784   "        * At this time, only datasets that have a single sub-brick\n"
04785   "            can be edited.\n"
04786   "\n"
04787   "Step 2) Choose a drawing value.\n"
04788   "        * This is the number that will be placed into the dataset\n"
04789   "            voxels that are chosen.\n"
04790   "        * Integer valued datasets can only receive integer values;\n"
04791   "            float datasets can take floating point values.\n"
04792   "\n"
04793   "Step 3) Choose a drawing color.\n"
04794   "        * This is the color that will be shown in the image windows\n"
04795   "            while drawing is going on (that is, while mouse button 2\n"
04796   "            is pressed).\n"
04797   "        * See 5) for more details about the drawing process.\n"
04798   "\n"
04799   "Step 4) Choose a drawing mode.\n"
04800   "        * 'Open Curve' means to select dataset voxels that lie under\n"
04801   "            the pixel lines drawn on the image as you move the mouse\n"
04802   "            with button 2 held down.\n"
04803   "        * 'Closed Curve ' means to close the curve drawn from the last\n"
04804   "            point drawn (where button 2 is released) back to the\n"
04805   "            first point drawn (where button 2 was pressed).\n"
04806   "        * 'Points' means to take only the voxels corresponding\n"
04807   "            to the screen pixels about which X11 sends notice\n"
04808   "            (this is not very useful).\n"
04809   "        * 'Flood->Value' means to flood fill outwards from the first\n"
04810   "            chosen voxel, stopping when the Dataset Value is reached.\n"
04811   "            In conjunction with 'Closed Curve', it can be used to draw\n"
04812   "            an entire region in a plane.\n"
04813   "        * 'Flood->Nonzero' means to flood fill, but stopping when any\n"
04814   "            nonzero voxel value is reached.\n"
04815   "\n"
04816   "Step 5) Draw something in an image window.\n"
04817   "        * Drawing is done using mouse button 2.\n"
04818   "        * In an image window, drawing a set of pixels is done\n"
04819   "            by pressing and holding button 2, and dragging\n"
04820   "            the cursor across the desired pixels.  The drawing\n"
04821   "            color will be painted over these pixels while the\n"
04822   "            painting is going on (while button 2 is held down).\n"
04823   "        * After mouse button 2 is released, the drawing value for\n"
04824   "            the chosen voxels is copied into the dataset.  The\n"
04825   "            dataset is then redisplayed -- this will most likely\n"
04826   "            change the color of the selected voxels, since display\n"
04827   "            colors depend on the Define Function pbar (for Func\n"
04828   "            datasets) or on the greyscale map (for Anat datasets).\n"
04829   "        * That is, the drawing color is ONLY used while button2\n"
04830   "            is pressed down.  This color should simply be chosen\n"
04831   "            to provide good contrast for the drawing operations.\n"
04832   "        * Pressing and releasing button 2 in a graph window\n"
04833   "            sub-graph will cause that single voxel to get the\n"
04834   "            drawing value, as well.  You cannot select a group\n"
04835   "            of voxels in a graph window -- only one voxel per click.\n"
04836   "\n"
04837   "Step 6) Undo.\n"
04838   "        * The last drawing operation can be undone -- that is,\n"
04839   "            pressing 'Undo' will restore the voxel values before\n"
04840   "            the last button 2 press-release operation.\n"
04841   "        * There is only one level of undo.  Undo-ing the undo\n"
04842   "            will put things back the way they were.  Anyone who\n"
04843   "            implements a better undo system will be appreciated.\n"
04844   "\n"
04845   "Step 7) Save dataset (maybe).\n"
04846   "        * While a dataset is being edited, it is locked into memory.\n"
04847   "        * The edited values are saved to disk only when 'Save' or\n"
04848   "            'Done' are pressed.\n"
04849   "        * The 'Quit' button can be used to discard the edits of\n"
04850   "            a dataset.  In that case, the dataset values are\n"
04851   "            re-read from disk when it is redisplayed.\n"
04852   "        * Closing the AFNI Editor window using the window manager\n"
04853   "            is equivalent to pressing 'Quit'.\n"
04854   "\n"
04855   "WARNINGS:\n"
04856   "  * It is important to understand the distinction between 'pixels'\n"
04857   "      and 'voxels'.  Pixels are on the screen, and while you are\n"
04858   "      drawing, you are drawing pixels with the drawing color.  When\n"
04859   "      you release mouse button 2, those dataset voxels to which these\n"
04860   "      pixels correspond are computed.  The values stored in those\n"
04861   "      voxels are then altered, and the dataset display is refreshed.\n"
04862   "  * It is possible to draw on a montaged image window.  However,\n"
04863   "      only voxels from the first slice drawn into will be altered.\n"
04864   "  * Using button 2 in an image or graph window before choosing a\n"
04865   "      dataset to edit will cause the display to beep.\n"
04866   "  * Closing the AFNI controller window that this was started from\n"
04867   "      is the equivalent of pressing 'Quit'.\n"
04868   "  * Doing something that causes the AFNI controller window to\n"
04869   "      alter its 3D grid location or resolution is also the\n"
04870   "      equivalent of pressing 'Quit'.  This is because the 3D grid\n"
04871   "      for the dataset being edited will no longer correspond to\n"
04872   "      the 3D grid in the image and graph windows.  Such actions\n"
04873   "      include switching from 'View Brick' to 'Warp on Demand',\n"
04874   "      switching datasets or sessions, and switching views.\n"
04875   "  * You can only draw into the windows of the controller from which\n"
04876   "      the Editor was started.\n"
04877   "  * Only one copy of the Editor can be active at a time.  If you\n"
04878   "      use the plugin menu to call up the Editor when it is already\n"
04879   "      open, that will simply pop the window up to the top of the\n"
04880   "      stacking order.  If you want to restart the Editor in a\n"
04881   "      different AFNI controller, you must first close the Editor\n"
04882   "      (via 'Done' or 'Quit') and then start it from the other\n"
04883   "      controller's window.\n"
04884   "  * Peculiar and confusing things can happen using 'Warp-on-Demand'\n"
04885   "      with the Editor.  My advice is not to try this.\n"
04886   "  * Edit at your own risk!  Be careful out there.\n"
04887   "\n"
04888   "SUGGESTIONS?\n"
04889   "  * Please send them to " COXEMAIL "\n"
04890   "  * Even better than suggestions are implementations.\n"
04891 
04892 
04893     , TEXT_READONLY ) ;
04894    return ;
04895 }
04896 
04897 /*-------------------------------------------------------------------
04898   Callback for choose button.
04899   Criteria for datasets that can be edited:
04900     - must be in current session
04901     - must have actual bricks
04902     - only datasets with nvals=1 can be edited
04903     - bricks must be on same grid (dataxes) as AFNI controller
04904   Much of this code is adapted from PLUG_choose_dataset_CB.
04905   [28 Jul 2003] Modified for new THD_session struct.
04906 ---------------------------------------------------------------------*/
04907 
04908 static int                  ndsl = 0 ;
04909 static PLUGIN_dataset_link * dsl = NULL ;
04910 
04911 static void DRAW_choose_CB( Widget w, XtPointer client_data, XtPointer call_data )
04912 {
04913    THD_session * ss  = im3d->ss_now ;           /* current session */
04914    int           vv  = im3d->vinfo->view_type ; /* view type */
04915    THD_3dim_dataset * qset ;
04916    int id , ltop , llen ;
04917    char qnam[THD_MAX_NAME] , label[THD_MAX_NAME] ;
04918    static char ** strlist = NULL ;
04919 
04920    ENTRY("DRAW_choose_CB");
04921 
04922    /* can't do this if a dataset is already active and changed */
04923 
04924    if( dset != NULL && dset_changed ){
04925       (void) MCW_popup_message( choose_pb ,
04926                                    "Can't change datasets until\n"
04927                                    "you save the changes you've\n"
04928                                    "already made.  Or you could\n"
04929                                    "'Quit' and re-start the Editor" ,
04930                                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
04931       XBell( dc->display , 100 ) ;
04932       EXRETURN ;
04933    }
04934 
04935    /* RCR - If data is not on disk, do not accept it (must be a warp).
04936         Inform the user that they might have to write the anat.
04937    */
04938    if ( ! DSET_ONDISK( im3d->anat_now ) )
04939    {
04940       (void) MCW_popup_message( choose_pb ,
04941                    "Anat data is not actually on disk!\n"
04942                    "You may be in 'Warp-on-Demand' mode.\n"
04943                    "\n"
04944                    "Please take the following steps :\n"
04945                    "   1. 'Write Anat'\n"
04946                    "   2. 'Rescan This'\n"
04947                    "   3. Set to 'View Anat Data Brick'",
04948                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
04949       XBell( dc->display , 100 ) ;
04950       EXRETURN ;
04951    }
04952 
04953    /* initialize */
04954 
04955    ndsl = 0 ;
04956 
04957    /* scan anats */
04958 
04959    for( id=0 ; id < ss->num_dsset ; id++ ){
04960       qset = ss->dsset[id][vv] ;
04961 
04962       if( ! ISVALID_DSET (qset)                        ) continue ;  /* skip */
04963       if( ! DSET_INMEMORY(qset)                        ) continue ;
04964       if(   DSET_NVALS(qset) > 1                       ) continue ;
04965       if( ! EQUIV_DATAXES(qset->daxes,im3d->wod_daxes) ) continue ;
04966 
04967       ndsl++ ;
04968       dsl = (PLUGIN_dataset_link *)
04969               XtRealloc( (char *) dsl , sizeof(PLUGIN_dataset_link)*ndsl ) ;
04970 
04971       make_PLUGIN_dataset_link( qset , dsl + (ndsl-1) ) ;
04972    }
04973 
04974    /* found nothing?  exit */
04975 
04976    if( ndsl < 1 ){
04977       (void) MCW_popup_message( choose_pb ,
04978                                    "Didn't find any datasets to edit!\n"
04979                                    "Check if:\n"
04980                                    " - you are in 'Warp-on-Demand' mode\n"
04981                                    " - you are in the correct session" ,
04982                                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
04983       XBell( dc->display , 100 ) ;
04984       EXRETURN ;
04985    }
04986 
04987    /*--- 23 Nov 1996: loop over dataset links and patch their titles
04988                       to include an indicator of the dataset type    ---*/
04989 
04990    ltop = 4 ;
04991    for( id=0 ; id < ndsl ; id++ ){
04992       llen = strlen(dsl[id].title) ;
04993       ltop = MAX(ltop,llen) ;
04994    }
04995 
04996    for( id=0 ; id < ndsl ; id++ ){
04997       qset = PLUTO_find_dset( &(dsl[id].idcode) ) ;
04998       if( ! ISVALID_DSET(qset) ) continue ;
04999       if( ISANAT(qset) ){
05000          if( ISANATBUCKET(qset) )         /* 30 Nov 1997 */
05001             sprintf(qnam,"%-*s [%s:%d]" ,
05002                     ltop,dsl[id].title ,
05003                     ANAT_prefixstr[qset->func_type] , DSET_NVALS(qset) ) ;
05004 
05005          else if( DSET_NUM_TIMES(qset) == 1 )
05006             sprintf(qnam,"%-*s [%s]" ,
05007                     ltop,dsl[id].title ,
05008                     ANAT_prefixstr[qset->func_type] ) ;
05009 
05010          else
05011             sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
05012                     ltop,dsl[id].title ,
05013                     ANAT_prefixstr[qset->func_type] , DSET_NUM_TIMES(qset) ) ;
05014 
05015       } else {
05016          if( ISFUNCBUCKET(qset) )         /* 30 Nov 1997 */
05017             sprintf(qnam,"%-*s [%s:%d]" ,
05018                     ltop,dsl[id].title ,
05019                     FUNC_prefixstr[qset->func_type] , DSET_NVALS(qset) ) ;
05020 
05021          else if( DSET_NUM_TIMES(qset) == 1 )
05022             sprintf(qnam,"%-*s [%s]" ,
05023                     ltop,dsl[id].title ,
05024                     FUNC_prefixstr[qset->func_type] ) ;
05025 
05026          else
05027             sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
05028                     ltop,dsl[id].title ,
05029                     FUNC_prefixstr[qset->func_type] , DSET_NVALS(qset) ) ;
05030       }
05031 
05032       if( DSET_COMPRESSED(qset) ) strcat(qnam,"z") ;
05033 
05034       strcpy( dsl[id].title , qnam ) ;
05035    }
05036 
05037    /*--- make a popup chooser for the user to browse ---*/
05038 
05039    POPDOWN_strlist_chooser ;
05040 
05041    strlist = (char **) XtRealloc( (char *)strlist , sizeof(char *)*ndsl ) ;
05042    for( id=0 ; id < ndsl ; id++ ) strlist[id] = dsl[id].title ;
05043 
05044    sprintf( label , "AFNI Dataset from\nthe %s" , VIEW_typestr[vv] ) ;
05045 
05046    MCW_choose_strlist( w , label , ndsl , -1 , strlist ,
05047                        DRAW_finalize_dset_CB , NULL     ) ;
05048 
05049    EXRETURN ;
05050 }
05051 
05052 static void DRAW_finalize_dset_CB( Widget w, XtPointer fd, MCW_choose_cbs * cbs )
05053 {
05054    int id = cbs->ival ;
05055    THD_3dim_dataset * qset ;
05056    XmString xstr ;
05057    char str[256] ;
05058 
05059    ENTRY("DRAW_finalize_dset_CB");
05060 
05061    /* check for errors */
05062 
05063    if( ! editor_open ){ POPDOWN_strlist_chooser ; XBell(dc->display,100) ; EXRETURN ; }
05064 
05065    if( dset != NULL && dset_changed ){ XBell(dc->display,100) ; EXRETURN ; }
05066 
05067    if( id < 0 || id >= ndsl ){ XBell(dc->display,100) ; EXRETURN ; }
05068 
05069    qset = PLUTO_find_dset( &(dsl[id].idcode) ) ;  /* the new dataset? */
05070 
05071    if( qset == NULL ){ XBell(dc->display,100) ; EXRETURN ; }
05072 
05073    if( ! EQUIV_DATAXES( im3d->wod_daxes , qset->daxes ) ){
05074       XBell(dc->display,100) ; EXRETURN ;
05075    }
05076 
05077    /* accept this dataset */
05078 
05079    dset = qset ; dset_changed = 0 ; SENSITIZE(save_pb,0) ;
05080    dax_save = *(dset->daxes) ;
05081 
05082    /* write the informational label */
05083 
05084    if( DSET_BRICK_FACTOR(dset,0) == 0.0 ){
05085       strcpy(str,dsl[id].title) ;
05086    } else {
05087       char abuf[16] ;
05088       AV_fval_to_char( DSET_BRICK_FACTOR(dset,0) , abuf ) ;
05089       sprintf(str,"%s\nbrick factor: %s", dsl[id].title , abuf ) ;
05090    }
05091    xstr = XmStringCreateLtoR( str , XmFONTLIST_DEFAULT_TAG ) ;
05092    XtVaSetValues( info_lab , XmNlabelString , xstr , NULL ) ;
05093    XmStringFree(xstr) ;
05094 
05095    /* setup AFNI for drawing */
05096 
05097    if( ! recv_open ){
05098       recv_key = AFNI_receive_init( im3d, RECEIVE_DRAWING_MASK,
05099                                     DRAW_receiver,NULL,"DRAW_receiver" ) ;
05100 
05101       if( recv_key < 0 ){
05102          (void) MCW_popup_message( im3d->vwid->top_shell ,
05103                                      "Unable to establish\n"
05104                                      "connection to AFNI\n"
05105                                      "drawing routines!" ,
05106                                    MCW_USER_KILL | MCW_TIMER_KILL ) ;
05107 
05108          dset = NULL ; XBell(dc->display,100) ; EXRETURN ;
05109       }
05110    }
05111 
05112    DSET_mallocize(dset) ; DSET_lock(dset) ; DSET_load(dset) ;
05113 
05114    AFNI_receive_control( im3d, recv_key , mode_index , NULL ) ;
05115    AFNI_receive_control( im3d, recv_key , DRAWING_OVCINDEX, (void *)color_index ) ;
05116    recv_open = 1 ;
05117 
05118    undo_bufuse = 0 ; SENSITIZE(undo_pb,0) ;
05119 
05120    r_init_afni_vars( &gRA, dset );
05121 
05122    EXRETURN ;
05123 }
05124 
05125 /*-------------------------------------------------------------------
05126   Callback for color menu
05127 ---------------------------------------------------------------------*/
05128 
05129 static void DRAW_color_CB( MCW_arrowval * av , XtPointer cd )
05130 {
05131    color_index = av->ival ;
05132 
05133    if( dset != NULL && recv_open )
05134       AFNI_receive_control( im3d, recv_key, DRAWING_OVCINDEX, (void *)color_index ) ;
05135 
05136    return ;
05137 }
05138 
05139 /*-------------------------------------------------------------------
05140   Callback for mode menu
05141 ---------------------------------------------------------------------*/
05142 
05143 static void DRAW_mode_CB( MCW_arrowval * av , XtPointer cd )
05144 {
05145    mode_ival  = av->ival ;
05146    mode_index = mode_ints[mode_ival] ;
05147 
05148    if( dset != NULL && recv_open )
05149       AFNI_receive_control( im3d, recv_key, mode_index , NULL ) ;
05150 
05151    return ;
05152 }
05153 
05154 /*-------------------------------------------------------------------
05155   Callback for value menu
05156 ---------------------------------------------------------------------*/
05157 
05158 static void DRAW_value_CB( MCW_arrowval * av , XtPointer cd )
05159 {
05160    value_int   = av->ival ;
05161    value_float = av->fval ;
05162    return ;
05163 }
05164 
05165 /*******************************************************************
05166    Receive data from AFNI after drawing, etc.
05167 ********************************************************************/
05168 
05169 static void DRAW_receiver( int why , int np , void * vp , void * cbd )
05170 {
05171    ENTRY("DRAW_receiver");
05172 
05173    switch( why ){
05174 
05175       default:
05176          fprintf(stderr,"DRAW_receiver: illegal why=%d\n",why) ;
05177       EXRETURN ;
05178 
05179       /*-- we like this one --*/
05180 
05181       case RECEIVE_POINTS:{
05182          int **ip = (int **)vp ;
05183          int *xd=ip[0] , *yd=ip[1] , *zd=ip[2] ; /* pts coords */
05184          int mode=ip[3][0] ;                     /* how pts are organized */
05185          int plane ;
05186 
05187          if( np <= 0 ) EXRETURN ;  /* some error? */
05188 
05189          plane = mode - SINGLE_MODE ;
05190          if( plane < 1 || plane > 3 ) plane = mode - PLANAR_MODE ;
05191          if( plane < 1 || plane > 3 ) plane = 0 ;
05192 
05193          /* handle selection of initial point for vol_fill, otherwise, */
05194          /* anything but flood mode --> just draw given points         */
05195 
05196          if ( mode_ival == MODE_VOL_FILL )
05197          {
05198              int coord;
05199 
05200              if ( yd == NULL )
05201                  coord = *xd;
05202              else
05203                  coord = *xd +
05204                          *yd * DSET_NX(gRA.anat) +
05205                          *zd * DSET_NX(gRA.anat) * DSET_NY(gRA.anat);
05206 
05207              if ( r_afni_set_fill_point( &coord, &gRA ) < 0 )
05208                 EXRETURN ;
05209 
05210              DRAW_into_dataset( 0, &coord, NULL, NULL, NULL );
05211          }
05212          else if ( mode_ival == MODE_CONN_PTS )
05213          {   /* store the points into xd and DRAW_into_dataset */
05214              r_ipt_t * pptr;
05215              int       coord;
05216 
05217              if ( gRCP.cur_pt == 1 )
05218                  pptr = &gRCP.source;
05219              else if ( gRCP.cur_pt == 2 )
05220                  pptr = &gRCP.dest;
05221              else
05222              {
05223                  rERROR( "In DRAW_receiver() - gRCP.cur_pt is unset." );
05224                  EXRETURN;
05225              }
05226 
05227              if ( yd == NULL )
05228                  *pptr = r_index2pt( *xd, gRA.nx, gRA.ny, gRA.nz );
05229              else
05230              {
05231                  pptr->x = *xd;
05232                  pptr->y = *yd;
05233                  pptr->z = *zd;
05234              }
05235 
05236              /* If first point, just store it.   Otherwise draw entire line. */
05237 
05238              if ( gRCP.cur_pt == 1 )
05239              {
05240                  gRCP.cur_pt = 2;
05241                  DRAW_into_dataset( 0, xd, yd, zd, NULL );
05242                  EXRETURN;
05243              }
05244              else
05245              {
05246                  points_t * Bp = &gRCP.plist;
05247                  r_ipt_t    p;
05248                  float      dx, dy, dz, fx, fy, fz, dcurr;
05249                  float      tot_dist = r_p_distance( gRCP.source, gRCP.dest );
05250                  int        pcount = 0;
05251 
05252                  Bp->used = 0;
05253 
05254                  dx = R_DIST_STEP * ( gRCP.dest.x - gRCP.source.x ) / tot_dist;
05255                  dy = R_DIST_STEP * ( gRCP.dest.y - gRCP.source.y ) / tot_dist;
05256                  dz = R_DIST_STEP * ( gRCP.dest.z - gRCP.source.z ) / tot_dist;
05257                  fx = gRCP.source.x;
05258                  fy = gRCP.source.y;
05259                  fz = gRCP.source.z;
05260 
05261                  for ( dcurr = 0; dcurr < tot_dist; dcurr += R_DIST_STEP )
05262                  {
05263                      coord = (int)fx + gRA.nx*((int)fy + gRA.ny*(int)fz);
05264                      r_add_to_boundary( Bp, coord );
05265 
05266                      fx += dx;
05267                      fy += dy;
05268                      fz += dz;
05269                  }
05270 
05271                  coord = gRCP.dest.x + gRA.nx*(gRCP.dest.y+gRA.ny*gRCP.dest.z);
05272                  r_add_to_boundary( Bp, coord );        /* add last point */
05273 
05274                  DRAW_into_dataset( Bp->used, Bp->points, NULL, NULL, NULL );
05275 
05276                  gRCP.cur_pt = 1;
05277 
05278                  /*
05279                  ** store the line as an interpolator line :
05280                  ** DRAW_into_dataset() was edited to check for MODE_CONN_PTS
05281                  ** when it stores the incoming line (point set).
05282                  */
05283              }
05284          }
05285          else if( plane == 0 ||
05286              ((mode_ival != MODE_FLOOD_VAL) && (mode_ival != MODE_FLOOD_NZ)) ){
05287 
05288             DRAW_into_dataset( np , xd,yd,zd , NULL ) ;
05289 
05290          } else {
05291 
05292             /* flood mode! */
05293 
05294             int   ityp = DSET_BRICK_TYPE(dset,0) ;
05295             float bfac = DSET_BRICK_FACTOR(dset,0) ;
05296             int nx=DSET_NX(dset) , ny=DSET_NY(dset) , nz=DSET_NZ(dset) ,
05297                 nxy = nx*ny , nxyz = nxy*nz , ii,jj , ixyz ;
05298             int base , di,dj , itop,jtop,nij , xx=xd[0],yy=yd[0],zz=zd[0] ,
05299                 ix,jy ;
05300             byte * pl ;
05301             int nfill , * xyzf , nf ;
05302 
05303             /* compute stuff for which plane we are in:
05304                 1 -> yz , 2 -> xz , 3 -> xy            */
05305 
05306             switch(plane){
05307                case 1: base=xx    ; di=nx; dj=nxy; itop=ny; jtop=nz;
05308                         ix=yy; jy=zz; break;
05309                case 2: base=yy*nx ; di=1 ; dj=nxy; itop=nx; jtop=nz;
05310                         ix=xx; jy=zz; break;
05311                case 3: base=zz*nxy; di=1 ; dj=nx ; itop=nx; jtop=ny;
05312                         ix=xx; jy=yy; break;
05313             }
05314 
05315             /* create a 2D array with 0 where dataset != blocking value
05316                              and with 1 where dataset == blocking value */
05317 
05318             nij = itop*jtop ;
05319             pl  = (byte *) malloc( sizeof(byte) * nij ) ;
05320             memset( pl , 0 , sizeof(byte) * nij ) ;
05321 
05322             if( bfac == 0.0 ) bfac = 1.0 ;
05323             switch(ityp){
05324 
05325                case MRI_short:{
05326                   short * bp  = (short *) DSET_BRICK_ARRAY(dset,0) ;
05327                   short   val = (short)   (value_float/bfac) ;
05328 
05329                   if( mode_ival == MODE_FLOOD_VAL ){
05330                      for( jj=0 ; jj < jtop ; jj++ )
05331                         for( ii=0 ; ii < itop ; ii++ ){
05332                            ixyz = base + ii*di + jj*dj ;
05333                            if( bp[ixyz] == val ) pl[ii+jj*itop] = 1 ;
05334                         }
05335                   } else {
05336                      for( jj=0 ; jj < jtop ; jj++ )
05337                         for( ii=0 ; ii < itop ; ii++ ){
05338                            ixyz = base + ii*di + jj*dj ;
05339                            if( bp[ixyz] != 0 ) pl[ii+jj*itop] = 1 ;
05340                         }
05341                   }
05342                }
05343                break ;
05344 
05345                case MRI_byte:{
05346                   byte * bp  = (byte *) DSET_BRICK_ARRAY(dset,0) ;
05347                   byte   val = (byte)   (value_float/bfac) ;
05348 
05349                   if( mode_ival == MODE_FLOOD_VAL ){
05350                      for( jj=0 ; jj < jtop ; jj++ )
05351                         for( ii=0 ; ii < itop ; ii++ ){
05352                            ixyz = base + ii*di + jj*dj ;
05353                            if( bp[ixyz] == val ) pl[ii+jj*itop] = 1 ;
05354                         }
05355                   } else {
05356                      for( jj=0 ; jj < jtop ; jj++ )
05357                         for( ii=0 ; ii < itop ; ii++ ){
05358                            ixyz = base + ii*di + jj*dj ;
05359                            if( bp[ixyz] != 0 ) pl[ii+jj*itop] = 1 ;
05360                         }
05361                   }
05362                }
05363                break ;
05364 
05365                case MRI_float:{
05366                   float * bp  = (float *) DSET_BRICK_ARRAY(dset,0) ;
05367                   float   val = (value_float/bfac) ;
05368 
05369                   if( mode_ival == MODE_FLOOD_VAL ){
05370                      for( jj=0 ; jj < jtop ; jj++ )
05371                         for( ii=0 ; ii < itop ; ii++ ){
05372                            ixyz = base + ii*di + jj*dj ;
05373                            if( bp[ixyz] == val ) pl[ii+jj*itop] = 1 ;
05374                         }
05375                   } else {
05376                      for( jj=0 ; jj < jtop ; jj++ )
05377                         for( ii=0 ; ii < itop ; ii++ ){
05378                            ixyz = base + ii*di + jj*dj ;
05379                            if( bp[ixyz] != 0.0 ) pl[ii+jj*itop] = 1 ;
05380                         }
05381                   }
05382                }
05383                break ;
05384 
05385                default:
05386                   free(pl) ;
05387                   fprintf(stderr,
05388                          "Flood not implemented for datasets of type %s\a\n",
05389                          MRI_TYPE_name[ityp] ) ;
05390                EXRETURN ;
05391 
05392             } /* end of switch on type */
05393 
05394             /* start point must be a 0 (can't fill from an edge) */
05395 
05396             if( pl[ix+jy*itop] == 1 ){
05397                free(pl) ; XBell(dc->display,100) ; EXRETURN ;
05398             }
05399 
05400             /* call a routine to fill the array */
05401 
05402             DRAW_2dfiller( itop,jtop , ix,jy , pl ) ;
05403 
05404             /* all filled points are 2 --> these are the locations to draw */
05405 
05406             nfill = 0 ;
05407             for( ii=0 ; ii < nij ; ii++ ) nfill += (pl[ii] == 2) ;
05408             if( nfill == 0 ){ free(pl) ; XBell(dc->display,100) ; EXRETURN ; }
05409 
05410             xyzf = (int *) malloc( sizeof(int) * nfill ) ;
05411 
05412             for( nf=0,jj=0 ; jj < jtop ; jj++ ){
05413                for( ii=0 ; ii < itop ; ii++ ){
05414                   if( pl[ii+jj*itop] == 2 )
05415                      xyzf[nf++] = base + ii*di + jj*dj ;
05416                }
05417             }
05418 
05419             free(pl) ;
05420             DRAW_into_dataset( nfill , xyzf,NULL,NULL , NULL ) ;
05421             free(xyzf) ;
05422 
05423          } /* end of flooding */
05424 
05425       } /* end of dealing with drawn points */
05426       break ;
05427 
05428       /*-- user closed the controller window!? (the fiend) */
05429 
05430       case RECEIVE_CLOSURE:{
05431          if( dset != NULL && dset_changed ) XBell(dc->display,100) ; /* protest */
05432          DRAW_quit_CB(NULL,NULL,NULL) ;                              /* and die */
05433       }
05434       break ;
05435 
05436       /*-- user altered the controller window!? */
05437 
05438       case RECEIVE_ALTERATION:{
05439 
05440          /* if we are already editing a dataset, then
05441             check if the grid has changed -- if it has, must quit */
05442 
05443          if( dset != NULL ){
05444             if( ! EQUIV_DATAXES( im3d->wod_daxes , &dax_save ) ){
05445                XBell( dc->display , 100 ) ;    /* feeble protest */
05446                DRAW_quit_CB(NULL,NULL,NULL) ;  /* die */
05447 
05448 
05449                 {       /* RCR stuff */
05450 
05451                     printf("Initializing gRA...\n");
05452                     gRA.anat  = NULL;
05453                     gRA.func  = NULL;
05454                     gRA.adata = NULL;
05455                     gRA.fdata = NULL;
05456 
05457                     r_main_cb_quit();
05458                 }
05459 
05460                /* less feeble protest */
05461                (void) MCW_popup_message( im3d->vwid->top_shell ,
05462                                            "Controller grid was altered!\n"
05463                                            "Editor was forced to quit.\n"
05464                                            "Any un-Saved changes were lost." ,
05465                                          MCW_USER_KILL | MCW_TIMER_KILL ) ;
05466             }
05467          }
05468       }
05469       break ;
05470 
05471    } /* end of switch on why */
05472 
05473    EXRETURN ;
05474 }
05475 
05476 /*--------------------------------------------------------------------------
05477   Routine to draw into a dataset.
05478   If yd & zd are NULL, then xd is used as the direct 3D array index,
05479     otherwise xd,yd,zd are used as the 3-index.
05480   If var == NULL, then the value_av is used, otherwise the array var[]
05481     will be the source of the data.
05482 ----------------------------------------------------------------------------*/
05483 
05484 static void DRAW_into_dataset( int np , int * xd , int * yd , int * zd , void * var )
05485 {
05486    int   ityp = DSET_BRICK_TYPE(dset,0) ;
05487    float bfac = DSET_BRICK_FACTOR(dset,0) ;
05488    int nx=DSET_NX(dset) , ny=DSET_NY(dset) , nz=DSET_NZ(dset) ,
05489        nxy = nx*ny , nxyz = nxy*nz , ii , ixyz ;
05490    float vload = 0.0 ;
05491    int nbytes ;
05492 
05493    ENTRY("DRAW_into_dataset");
05494 
05495    /* sanity check */
05496 
05497    if( dset==NULL || np <= 0 || xd==NULL ) EXRETURN ;
05498 
05499    /* make space for undo */
05500 
05501    nbytes = np * mri_datum_size((MRI_TYPE)ityp) ; /* bytes needed for save */
05502    if( nbytes > undo_bufsiz ){
05503       if( undo_buf != NULL ) free(undo_buf) ;
05504       undo_buf    = malloc(nbytes) ;
05505       undo_bufsiz = nbytes ;
05506    }
05507    if( np > undo_bufnum ){
05508       if( undo_xyz != NULL ) free(undo_xyz);
05509       undo_xyz    = (int *) malloc(sizeof(int)*np) ;
05510       undo_bufnum = np ;
05511    }
05512 
05513    /* compute (or copy) data index into undo_xyz */
05514 
05515    if( yd == NULL ){                       /* direct supply of index */
05516       memcpy(undo_xyz,xd,sizeof(int)*np) ;
05517    } else {                                /* collapse 3-index into 1 */
05518       for( ii=0 ; ii < np ; ii++ )
05519          undo_xyz[ii] = xd[ii] + yd[ii] * nx + zd[ii] * nxy ;
05520    }
05521 
05522    /* actually copy data, based on type */
05523 
05524    if( bfac == 0.0 ) bfac = 1.0 ;
05525    vload = value_float ;
05526 
05527    /* RCR - code for interpolation */
05528    if ( ! gRI.afni_undo && 
05529         ( ( mode_ival == MODE_CURVE ) || ( mode_ival == MODE_CLOSED ) ||
05530           ( mode_ival == MODE_CONN_PTS ) )
05531       )
05532    {
05533         /* insert the points into the interpolation structure */
05534 
05535         int        count, coord;
05536         int      * ipA, * ipB, * ipc;
05537         points_t * Bp, tmpB;
05538         
05539         if ( gRI.A.used == 0 )  /* if first IP set is empty, use it */
05540             Bp = &gRI.A;
05541         else if ( gRI.B.used == 0 )     /* else, similarly for second       */
05542             Bp = &gRI.B;
05543         else                            /* else, move 2->1 and use second   */
05544         {
05545             tmpB       = gRI.A;         /* swap and empty new one */
05546             gRI.A      = gRI.B;
05547             gRI.B      = tmpB;
05548             gRI.B.used = 0;
05549 
05550             Bp = &gRI.B;
05551         }
05552 
05553         for ( count = 0; count < np; count++ )
05554         {
05555             coord = undo_xyz[ count ];
05556 
05557             if ( coord >= 0 && coord < nxyz )
05558                 r_add_to_boundary( Bp, coord );
05559         }
05560    }
05561 
05562    switch( ityp ){
05563 
05564       default: fprintf(stderr,"Illegal brick type=%s in AFNI Editor!\n",
05565                        MRI_TYPE_name[ityp] ) ;
05566       break ;
05567 
05568       case MRI_short:{
05569          short * bp  = (short *) DSET_BRICK_ARRAY(dset,0) ;
05570          short * up  = (short *) undo_buf ;
05571          short * vvv = (short *) var ;
05572          short   val = (short)   (value_float/bfac) ;
05573 
05574          for( ii=0 ; ii < np ; ii++ ){  /* save into undo buffer */
05575             ixyz = undo_xyz[ii] ;
05576             up[ii] = (ixyz >= 0 && ixyz < nxyz) ? bp[ixyz] : 0 ;
05577          }
05578 
05579          for( ii=0 ; ii < np ; ii++ ){  /* put into dataset */
05580             ixyz = undo_xyz[ii] ;
05581             if( ixyz >= 0 && ixyz < nxyz )
05582                bp[ixyz] = (vvv==NULL) ? val : vvv[ii] ;
05583          }
05584       }
05585       break ;
05586 
05587       case MRI_byte:{
05588          byte * bp  = (byte *) DSET_BRICK_ARRAY(dset,0) ;
05589          byte * up  = (byte *) undo_buf ;
05590          byte * vvv = (byte *) var ;
05591          byte   val = (byte)   (value_float/bfac) ;
05592 
05593          for( ii=0 ; ii < np ; ii++ ){
05594             ixyz = undo_xyz[ii] ;
05595             up[ii] = (ixyz >= 0 && ixyz < nxyz) ? bp[ixyz] : 0 ;
05596          }
05597          for( ii=0 ; ii < np ; ii++ ){
05598             ixyz = undo_xyz[ii] ;
05599             if( ixyz >= 0 && ixyz < nxyz )
05600                bp[ixyz] = (vvv==NULL) ? val : vvv[ii] ;
05601          }
05602       }
05603       break ;
05604 
05605       case MRI_float:{
05606          float * bp  = (float *) DSET_BRICK_ARRAY(dset,0) ;
05607          float * up  = (float *) undo_buf ;
05608          float * vvv = (float *) var ;
05609          float   val = (value_float/bfac) ;
05610 
05611          for( ii=0 ; ii < np ; ii++ ){
05612             ixyz = undo_xyz[ii] ;
05613             up[ii] = (ixyz >= 0 && ixyz < nxyz) ? bp[ixyz] : 0.0 ;
05614          }
05615          for( ii=0 ; ii < np ; ii++ ){
05616             ixyz = undo_xyz[ii] ;
05617             if( ixyz >= 0 && ixyz < nxyz )
05618                bp[ixyz] = (vvv==NULL) ? val : vvv[ii] ;
05619          }
05620       }
05621       break ;
05622 
05623       case MRI_complex:{
05624          complex * bp  = (complex *) DSET_BRICK_ARRAY(dset,0) ;
05625          complex * up  = (complex *) undo_buf ;
05626          complex * vvv = (complex *) var ;
05627          complex   val ;
05628          static complex cxzero = { 0.0 , 0.0 } ;
05629 
05630          val = CMPLX( (value_float/bfac) , 0.0 ) ;
05631 
05632          for( ii=0 ; ii < np ; ii++ ){
05633             ixyz = undo_xyz[ii] ;
05634             up[ii] = (ixyz >= 0 && ixyz < nxyz) ? bp[ixyz] : cxzero ;
05635          }
05636          for( ii=0 ; ii < np ; ii++ ){
05637             ixyz = undo_xyz[ii] ;
05638             if( ixyz >= 0 && ixyz < nxyz )
05639                bp[ixyz] = (vvv==NULL) ? val : vvv[ii] ;
05640          }
05641       }
05642       break ;
05643 
05644    } /* end of switch on brick type */
05645 
05646    /* recompute statistics, if the loaded value is big or small */
05647 
05648    if( !ISVALID_STATISTIC(dset->stats)   ||
05649        vload > dset->stats->bstat[0].max ||
05650        vload < dset->stats->bstat[0].min   ) THD_load_statistics( dset ) ;
05651 
05652    /* now redisplay dataset, in case anyone is looking at it */
05653 
05654    PLUTO_dset_redisplay( dset ) ;
05655 
05656    undo_bufuse  = np ;
05657    dset_changed = 1 ;
05658    SENSITIZE(save_pb,1) ;
05659    SENSITIZE(choose_pb,0) ;
05660    SENSITIZE(undo_pb,1) ;
05661 
05662    EXRETURN ;
05663 }
05664 
05665 /*---------------------------------------------------------------------------
05666    Flood filling a byte array:
05667      nx = 1st dimension
05668      ny = 2nd dimension
05669      ix = start point
05670      jy = end point
05671      ar = array, with 0's everwhere except 1's as barriers to flooding
05672 
05673    All filled points (starting with ix,jy) will get the value 2.
05674 -----------------------------------------------------------------------------*/
05675 
05676 static void DRAW_2dfiller( int nx , int ny , int ix , int jy , byte * ar )
05677 {
05678    int ii,jj , ip,jp , num ;
05679 
05680    ENTRY("DRAW_2dfiller");
05681 
05682 #define AR(i,j) ar[(i)+(j)*nx]
05683 
05684    /* fill out in cross from 1st point */
05685 
05686    ip = ix ; jp = jy ; AR(ip,jp) = 2 ;
05687 
05688    for( ii=ip+1; ii < nx && AR(ii,jp) == 0; ii++ ) AR(ii,jp) = 2;
05689    for( ii=ip-1; ii >= 0 && AR(ii,jp) == 0; ii-- ) AR(ii,jp) = 2;
05690    for( jj=jp+1; jj < ny && AR(ip,jj) == 0; jj++ ) AR(ip,jj) = 2;
05691    for( jj=jp-1; jj >= 0 && AR(ip,jj) == 0; jj-- ) AR(ip,jj) = 2;
05692 
05693    /* brute force repetition of the cross technique */
05694 
05695    do {
05696       num = 0 ;
05697       for( jp=0 ; jp < ny ; jp++ ){
05698          for( ip=0 ; ip < nx ; ip++ ){
05699             if( AR(ip,jp) == 2 ){
05700                for( ii=ip+1; ii < nx && AR(ii,jp) == 0; ii++ ){ AR(ii,jp) = 2; num++; }
05701                for( ii=ip-1; ii >= 0 && AR(ii,jp) == 0; ii-- ){ AR(ii,jp) = 2; num++; }
05702                for( jj=jp+1; jj < ny && AR(ip,jj) == 0; jj++ ){ AR(ip,jj) = 2; num++; }
05703                for( jj=jp-1; jj >= 0 && AR(ip,jj) == 0; jj-- ){ AR(ip,jj) = 2; num++; }
05704             }
05705          }
05706       }
05707    } while( num > 0 ) ;
05708 
05709    EXRETURN ;
05710 }
05711 
 

Powered by Plone

This site conforms to the following standards: