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_nudge.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 #include "vecmat.h"
00008 
00009 #include "afni.h"
00010 
00011 #ifndef ALLOW_PLUGINS
00012 #  error "Plugins not properly set up -- see machdep.h"
00013 #endif
00014 
00015 /***********************************************************************
00016   Plugin to nudge a dataset around.
00017   Makes a custom interface.
00018   -- RWCox -- April 2000
00019 ************************************************************************/
00020 
00021 /*----------------- prototypes for internal routines -----------------*/
00022 
00023 static PLUGIN_interface * plint = NULL ;
00024 
00025 char * NUD_main( PLUGIN_interface * ) ;  /* the entry point */
00026 
00027 static void NUD_make_widgets(void) ;
00028 
00029 static void NUD_nudge_CB ( Widget , XtPointer , XtPointer ) ;
00030 static void NUD_clear_CB ( Widget , XtPointer , XtPointer ) ;
00031 static void NUD_undo_CB  ( Widget , XtPointer , XtPointer ) ;
00032 static void NUD_redo_CB  ( Widget , XtPointer , XtPointer ) ;
00033 static void NUD_help_CB  ( Widget , XtPointer , XtPointer ) ;
00034 static void NUD_quit_CB  ( Widget , XtPointer , XtPointer ) ;
00035 static void NUD_doall_CB ( Widget , XtPointer , XtPointer ) ;
00036 static void NUD_choose_CB( Widget , XtPointer , XtPointer ) ;
00037 static void NUD_print_CB ( Widget , XtPointer , XtPointer ) ;
00038 
00039 static void NUD_finalize_dset_CB( Widget , XtPointer , MCW_choose_cbs * ) ;
00040 
00041 static void NUD_brick_av_CB( MCW_arrowval * , XtPointer ) ; /* Sub-brick menu */
00042 
00043 static void NUD_undopush(void) ;
00044 static void NUD_setcumlab(void) ;
00045 
00046 static void NUD_rotate( MRI_IMAGE * im ) ;
00047 static void NUD_update_base( Widget ) ;
00048 
00049 /***********************************************************************
00050    Set up the interface to the user
00051 ************************************************************************/
00052 
00053 
00054 DEFINE_PLUGIN_PROTOTYPE
00055 
00056 PLUGIN_interface * PLUGIN_init( int ncall )
00057 {
00058    if( ncall > 0 ) return NULL ;  /* only one interface */
00059 
00060    plint = PLUTO_new_interface( "Nudge Dataset" ,
00061                                 "Move bricks around" ,
00062                                 NULL ,
00063                                 PLUGIN_CALL_IMMEDIATELY , NUD_main  ) ;
00064 
00065    PLUTO_add_hint( plint , "Move bricks around" ) ;
00066 
00067    PLUTO_set_sequence( plint , "A:olddset:nudger" ) ;
00068 
00069    return plint ;
00070 }
00071 
00072 /**************************************************************************
00073   return a label string for 3 floats with 3 suffix characters
00074 --------------------------------------------------------------------------*/
00075 
00076 #define EPS 0.005
00077 
00078 static char * NUD_threestring( float a,float b,float c,char ca,char cb,char cc )
00079 {
00080    static char label[64] ;
00081    if( fabs(a) < EPS ) a = 0.0 ;
00082    if( fabs(b) < EPS ) b = 0.0 ;
00083    if( fabs(c) < EPS ) c = 0.0 ;
00084    sprintf(label,"%6.2f%c %6.2f%c %6.2f%c ", a,ca,b,cb,c,cc ) ;
00085    return label ;
00086 }
00087 
00088 static char * NUD_3string( float a,float b,float c,char ca,char cb,char cc )
00089 {
00090    static char label[64] ;
00091    if( fabs(a) < EPS ) a = 0.0 ;
00092    if( fabs(b) < EPS ) b = 0.0 ;
00093    if( fabs(c) < EPS ) c = 0.0 ;
00094    sprintf(label,"%.2f%c %.2f%c %.2f%c", a,ca,b,cb,c,cc ) ;
00095    return label ;
00096 }
00097 
00098 /***************************************************************************
00099   Will be called from AFNI when user selects from Plugins menu.
00100 ****************************************************************************/
00101 
00102 /* Interface widgets */
00103 
00104 static Widget shell=NULL , rowcol , info_lab , choose_pb ;
00105 static Widget nudge_pb, clear_pb, undo_pb, redo_pb, help_pb, quit_pb, doall_pb, print_pb ;
00106 static MCW_arrowval * roll_av , * pitch_av , * yaw_av ,
00107                     * dS_av   , * dL_av    , * dP_av  , * brick_av ;
00108 static Widget angle_cum_lab , shift_cum_lab ;
00109 
00110 static MCW_arrowval * interp_av , * clip_av ;
00111 
00112 /* other data */
00113 
00114 static int nudger_open = 0 ;
00115 
00116 static MCW_DC * dc ;                   /* display context */
00117 static Three_D_View * im3d ;           /* AFNI controller */
00118 static THD_3dim_dataset * dset ;       /* The dataset!    */
00119 static MCW_idcode         dset_idc ;
00120 static int new_dset = 0 ;              /* Is it new?      */
00121 static int dset_ival = 0 ;             /* Sub-brick index */
00122 static char dset_title[THD_MAX_NAME] ; /* Title string    */
00123 
00124 static char * NUD_dummy_av_label[2] = { "[Nothing At All]", "[Nothing At All]" };
00125 
00126 static int iha=1,ax1=0,ax2=1,ax3=2,hax1=1,hax2=2,hax3=3,adx=1,ady=2,adz=3 ;
00127 
00128 static int undo_nall , undo_nuse , undo_ntop ;
00129 static THD_dmat33 * undo_rmat=NULL ;
00130 static THD_dfvec3 * undo_svec=NULL ;
00131 
00132 static THD_dmat33 rmat ; /* current rotation matrix = undo_rmat[undo_nuse-1] */
00133 static THD_dfvec3 svec ; /* current shift vector    = undo_svec[undo_nuse-1] */
00134 
00135 #define NRESAM 7
00136 #define NYESNO 2
00137 static char * REG_resam_strings[NRESAM] = {
00138   "NN" ,  "Linear" ,  "Cubic" ,  "Quintic" ,  "Heptic" ,  "Fourier" ,  "Fourier_nopad" } ;
00139 
00140 static char * REG_resam_options[NRESAM] = {
00141  "-NN" , "-linear" , "-cubic" , "-quintic" , "-heptic" , "-Fourier" , "-Fourier_nopad" } ;
00142 
00143 static int REG_resam_ints[NRESAM] = {
00144   MRI_NN, MRI_LINEAR, MRI_CUBIC, MRI_QUINTIC, MRI_HEPTIC, MRI_FOURIER, MRI_FOURIER_NOPAD } ;
00145 
00146 static char * YESNO_strings[NYESNO] = { "No" , "Yes" } ;
00147 
00148 MRI_IMAGE * imbase = NULL ;
00149 
00150 /*-------------------------------------------------------------------------------*/
00151 
00152 char * NUD_main( PLUGIN_interface * plint )
00153 {
00154    XmString xstr ;
00155 
00156    /*-- sanity checks --*/
00157 
00158    if( ! IM3D_OPEN(plint->im3d) )
00159       return " \n AFNI Controller\nnot opened?! \n " ;
00160 
00161    if( nudger_open ){
00162       if( plint->im3d != im3d ){ /* different controller => close it */
00163          NUD_quit_CB(NULL,NULL,NULL) ;
00164       } else {                   /* same controller => just raise up */
00165          XtMapWidget(shell) ;
00166          XRaiseWindow( XtDisplay(shell) , XtWindow(shell) ) ;
00167          return NULL ;
00168       }
00169    }
00170 
00171    im3d = plint->im3d ;  /* save for local use */
00172 
00173    /*-- create widgets, first time through --*/
00174 
00175    if( shell == NULL ){
00176       dc = im3d->dc ;        /* save this too */
00177       NUD_make_widgets() ;
00178       PLUTO_set_topshell( plint , shell ) ;  /* 22 Sep 2000 */
00179       RWC_visibilize_widget( shell ) ;       /* 27 Sep 2000 */
00180    }
00181 
00182    /*-- set titlebar --*/
00183 
00184    { char ttl[PLUGIN_STRING_SIZE] ;
00185      sprintf(ttl , "AFNI Nudger %s" , AFNI_controller_label(im3d) ) ;
00186      XtVaSetValues( shell , XmNtitle , ttl , NULL ) ;
00187    }
00188 
00189    /*-- set the info label --*/
00190 
00191    xstr = XmStringCreateLtoR( "[No dataset]" ,
00192                               XmFONTLIST_DEFAULT_TAG ) ;
00193    XtVaSetValues( info_lab , XmNlabelString , xstr , NULL ) ;
00194    XmStringFree(xstr) ;
00195 
00196    /*-- pop the widget up --*/
00197 
00198    XtMapWidget(shell) ;
00199    PLUTO_cursorize(shell) ;
00200 
00201    /*-- misc initialization --*/
00202 
00203    dset = NULL ;           /* not editing anything */
00204    ZERO_IDCODE(dset_idc) ;
00205    dset_ival = 0 ; AV_assign_ival(brick_av,0) ;
00206    if( imbase != NULL ){ mri_free(imbase); imbase = NULL; }
00207 
00208    nudger_open = 1 ;      /* editor is now open for business */
00209 
00210    SENSITIZE(nudge_pb ,0) ;
00211    SENSITIZE(undo_pb  ,0) ;
00212    SENSITIZE(redo_pb  ,0) ;
00213    SENSITIZE(doall_pb ,0) ;
00214 
00215    SENSITIZE(choose_pb,1) ; AV_SENSITIZE(brick_av,0) ;
00216 
00217    /* initialize nudgerosity */
00218 
00219    NUD_clear_CB(NULL,NULL,NULL) ;
00220 
00221    LOAD_DIAG_DMAT(rmat,1.0,1.0,1.0) ;
00222    LOAD_DFVEC3(svec,0.0,0.0,0.0)    ;
00223    NUD_setcumlab() ;
00224 
00225    /* initialize undo stack */
00226 
00227    if( undo_rmat != NULL ){ free(undo_rmat); undo_rmat = NULL; }
00228    if( undo_svec != NULL ){ free(undo_svec); undo_svec = NULL; }
00229    undo_nuse = 0 ;
00230    undo_ntop = 0 ;
00231    undo_nall = 1 ;
00232    undo_rmat = (THD_dmat33 *) malloc(sizeof(THD_dmat33)) ;
00233    undo_svec = (THD_dfvec3 *) malloc(sizeof(THD_dfvec3)) ;
00234    NUD_undopush() ;  /* top of stack = current transformation */
00235 
00236    return NULL ;
00237 }
00238 
00239 /*------------------------------------------------------------------------
00240   Make the control popup for this thing
00241 --------------------------------------------------------------------------*/
00242 
00243 #define SEP_HOR(ww)  XtVaCreateManagedWidget(                     \
00244                        "AFNI" , xmSeparatorWidgetClass , (ww) ,   \
00245                           XmNseparatorType , XmSINGLE_LINE ,      \
00246                           XmNinitialResourcesPersistent , False , \
00247                        NULL )
00248 
00249 #define SEP_VER(ww) XtVaCreateManagedWidget(                      \
00250                        "AFNI" , xmSeparatorWidgetClass , (ww) ,   \
00251                           XmNseparatorType , XmDOUBLE_LINE ,      \
00252                           XmNorientation   , XmVERTICAL ,         \
00253                           XmNinitialResourcesPersistent , False , \
00254                        NULL )
00255 
00256 /*-- structures defining action buttons (at bottom of popup) --*/
00257 
00258 #define NACT 8  /* number of action buttons */
00259 
00260 static MCW_action_item NUD_actor[NACT] = {
00261  {"Nudge",NUD_nudge_CB,NULL,
00262   "Applies Angles and Shifts\nto chosen Brick of dataset","Apply Angles/Shifts",1} ,
00263 
00264  {"Clear",NUD_clear_CB,NULL,
00265   "Clears Angles and\nShifts entry fields","Clear Angles/Shifts",0} ,
00266 
00267  {"Undo",NUD_undo_CB,NULL,
00268   "Undoes previous nudge, if possible","Undo last nudge",0} ,
00269 
00270  {"Redo",NUD_redo_CB,NULL,
00271   "Redoes previously undone nudge","Redo last undone nudge",0} ,
00272 
00273  {"Help",NUD_help_CB,NULL,
00274   "Displays more help" , "Displays more help",0} ,
00275 
00276  {"Quit",NUD_quit_CB,NULL,
00277   "Discard nudges since last\n'Do All' and close down",
00278   "Discard nudges and close",0} ,
00279 
00280  {"Do All",NUD_doall_CB,NULL,
00281   "Apply Angles and Shifts to all sub-\nbricks and save dataset to disk" ,
00282   "Apply Angles/Shifts; write to disk" , 1 } ,
00283 
00284  {"Print",NUD_print_CB,NULL,
00285   "Print current Angles and Shifts as\na '3drotate' command, to stderr" ,
00286   "Print 3drotate command to screen" , 0 }
00287 } ;
00288 
00289 /*------------------------------------------------------------------------*/
00290 
00291 static void NUD_make_widgets(void)
00292 {
00293    XmString xstr ;
00294    Widget hrc ;
00295 
00296    /*** top level shell for window manager ***/
00297 
00298    shell =
00299       XtVaAppCreateShell(
00300            "AFNI" , "AFNI" , topLevelShellWidgetClass , dc->display ,
00301 
00302            XmNtitle             , "AFNI Nudger" , /* top of window */
00303            XmNiconName          , "Nudger"      , /* label on icon */
00304            XmNdeleteResponse    , XmDO_NOTHING  , /* deletion handled below */
00305            XmNallowShellResize  , True ,          /* let code resize shell? */
00306            XmNmappedWhenManaged , False ,         /* must map it manually */
00307            XmNinitialResourcesPersistent , False ,
00308       NULL ) ;
00309 
00310    DC_yokify( shell , dc ) ; /* 14 Sep 1998 */
00311 
00312 #ifndef DONT_INSTALL_ICONS
00313    if( afni48_good )             /* set icon pixmap */
00314       XtVaSetValues( shell ,
00315                         XmNiconPixmap , afni48_pixmap ,
00316                      NULL ) ;
00317 #endif
00318 
00319    if( MCW_isitmwm(shell) )      /* remove some MWM functions */
00320       XtVaSetValues( shell ,
00321                        XmNmwmFunctions ,
00322                        MWM_FUNC_MOVE | MWM_FUNC_CLOSE | MWM_FUNC_MINIMIZE ,
00323                      NULL ) ;
00324 
00325    XmAddWMProtocolCallback(      /* make "Close" window menu work */
00326            shell ,
00327            XmInternAtom( dc->display , "WM_DELETE_WINDOW" , False ) ,
00328            NUD_quit_CB , (XtPointer) plint ) ;
00329 
00330    /*** rowcolumn widget to hold all user interface stuff ***/
00331 
00332    rowcol = XtVaCreateWidget(
00333              "AFNI" , xmRowColumnWidgetClass , shell ,
00334                 XmNpacking     , XmPACK_TIGHT ,
00335                 XmNorientation , XmVERTICAL ,
00336                 XmNtraversalOn , False ,
00337                 XmNinitialResourcesPersistent , False ,
00338              NULL ) ;
00339 
00340    /*** label at top to let user know who we are ***/
00341 
00342    xstr = XmStringCreateLtoR( "[No dataset]" ,
00343                               XmFONTLIST_DEFAULT_TAG ) ;
00344    info_lab = XtVaCreateManagedWidget(
00345                  "AFNI" , xmLabelWidgetClass , rowcol ,
00346                     XmNlabelString , xstr ,
00347                     XmNinitialResourcesPersistent , False ,
00348                  NULL ) ;
00349    XmStringFree(xstr) ;
00350    MCW_register_help( info_lab , "Shows dataset being nudged" ) ;
00351    MCW_register_hint( info_lab , "Shows dataset being nudged" ) ;
00352 
00353    /***** top row of widgets to choose dataset and sub-brick *****/
00354 
00355    SEP_HOR(rowcol) ;
00356 
00357    hrc =  XtVaCreateWidget(
00358            "AFNI" , xmRowColumnWidgetClass , rowcol ,
00359               XmNorientation  , XmHORIZONTAL ,
00360               XmNpacking      , XmPACK_TIGHT ,
00361               XmNadjustLast   , False ,
00362               XmNadjustMargin , False ,
00363               XmNtraversalOn  , False ,
00364               XmNmarginWidth  , 0 ,
00365               XmNmarginHeight , 0 ,
00366               XmNinitialResourcesPersistent , False ,
00367            NULL ) ;
00368 
00369    /*** button to let user choose dataset to edit ***/
00370 
00371    xstr = XmStringCreateLtoR( "Choose Dataset" , XmFONTLIST_DEFAULT_TAG ) ;
00372    choose_pb = XtVaCreateManagedWidget(
00373                   "AFNI" , xmPushButtonWidgetClass , hrc ,
00374                      XmNlabelString , xstr ,
00375                      XmNtraversalOn , False ,
00376                      XmNinitialResourcesPersistent , False ,
00377                   NULL ) ;
00378    XmStringFree(xstr) ;
00379    XtAddCallback( choose_pb, XmNactivateCallback, NUD_choose_CB, NULL ) ;
00380    MCW_register_help( choose_pb ,
00381                       "Use this to popup a\n"
00382                       "'chooser' that lets\n"
00383                       "you select which\n"
00384                       "dataset to nudge."
00385                     ) ;
00386    MCW_register_hint( choose_pb , "Popup dataset chooser" ) ;
00387 
00388    /*** menu to let user choose sub-brick to deal with ***/
00389 
00390    SEP_VER(hrc) ;
00391 
00392    brick_av = new_MCW_arrowval(
00393                           hrc ,                   /* parent Widget */
00394                           "Brick" ,               /* label */
00395                           MCW_AV_optmenu ,        /* option menu style */
00396                           0 ,                     /* first option */
00397                           1 ,                     /* last option */
00398                           0 ,                     /* initial selection */
00399                           MCW_AV_readtext ,       /* ignored but needed */
00400                           0 ,                     /* decimal shift */
00401                           NUD_brick_av_CB ,       /* callback when changed */
00402                           NULL ,                  /* data for above */
00403                           MCW_av_substring_CB ,   /* text creation routine */
00404                           NUD_dummy_av_label      /* data for above */
00405                         ) ;
00406    MCW_reghelp_children( brick_av->wrowcol ,
00407                          "Choose the sub-brick\n"
00408                          "to nudge interactively;\n"
00409                          "you should also be\n"
00410                          "viewing this sub-brick" ) ;
00411    MCW_reghint_children( brick_av->wrowcol , "Sub-brick to nudge" ) ;
00412 
00413    /** some miscellaneous controls **/
00414 
00415    SEP_VER(hrc) ;
00416 
00417    interp_av = new_MCW_arrowval(
00418                         hrc ,                   /* parent Widget */
00419                         "Resampling" ,          /* label */
00420                         MCW_AV_optmenu ,        /* option menu style */
00421                         0 ,                     /* first option */
00422                         NRESAM-1 ,              /* last option */
00423                         3 ,                     /* initial selection */
00424                         MCW_AV_readtext ,       /* ignored but needed */
00425                         0 ,                     /* decimal shift */
00426                         NULL ,                  /* callback when changed */
00427                         NULL ,                  /* data for above */
00428                         MCW_av_substring_CB ,   /* text creation routine */
00429                         REG_resam_strings       /* data for above */
00430                       ) ;
00431    MCW_reghint_children( interp_av->wrowcol , "Set interpolation method" ) ;
00432 
00433    SEP_VER(hrc) ;
00434 
00435    clip_av = new_MCW_arrowval(
00436                         hrc ,                   /* parent Widget */
00437                         "Clip" ,                /* label */
00438                         MCW_AV_optmenu ,        /* option menu style */
00439                         0 ,                     /* first option */
00440                         NYESNO-1 ,              /* last option */
00441                         1 ,                     /* initial selection */
00442                         MCW_AV_readtext ,       /* ignored but needed */
00443                         0 ,                     /* decimal shift */
00444                         NULL ,                  /* callback when changed */
00445                         NULL ,                  /* data for above */
00446                         MCW_av_substring_CB ,   /* text creation routine */
00447                         YESNO_strings           /* data for above */
00448                       ) ;
00449    MCW_reghint_children( clip_av->wrowcol , "Clip after interpolation?" ) ;
00450 
00451    XtManageChild(hrc) ;
00452 
00453    /********** Angle choosers ***********/
00454 
00455    SEP_HOR(rowcol) ;
00456 
00457    hrc =  XtVaCreateWidget(
00458            "AFNI" , xmRowColumnWidgetClass , rowcol ,
00459               XmNorientation  , XmHORIZONTAL ,
00460               XmNpacking      , XmPACK_TIGHT ,
00461               XmNadjustLast   , False ,
00462               XmNadjustMargin , False ,
00463               XmNtraversalOn  , False ,
00464               XmNmarginWidth  , 0 ,
00465               XmNmarginHeight , 0 ,
00466               XmNinitialResourcesPersistent , False ,
00467            NULL ) ;
00468 
00469    xstr = XmStringCreateLtoR( "Angles: " ,
00470                               XmFONTLIST_DEFAULT_TAG ) ;
00471    (void) XtVaCreateManagedWidget(
00472                  "AFNI" , xmLabelWidgetClass , hrc ,
00473                     XmNlabelString , xstr ,
00474                     XmNinitialResourcesPersistent , False ,
00475                  NULL ) ;
00476    XmStringFree(xstr) ;
00477 
00478    /** the actual angles **/
00479 
00480    roll_av = new_MCW_arrowval( hrc, "I" ,
00481                                 MCW_AV_downup , -300,300,0 ,
00482                                 MCW_AV_editext , 1 ,
00483                                 NULL , NULL , NULL,NULL ) ;
00484    MCW_reghint_children( roll_av->wrowcol , "Roll angle [I-axis]" ) ;
00485    XtVaSetValues( roll_av->wtext , XmNcolumns , 6 , NULL ) ;
00486    SEP_VER(hrc) ;
00487 
00488    pitch_av = new_MCW_arrowval( hrc, "R" ,
00489                                 MCW_AV_downup , -300,300,0 ,
00490                                 MCW_AV_editext , 1 ,
00491                                 NULL , NULL , NULL,NULL ) ;
00492    MCW_reghint_children( pitch_av->wrowcol , "Pitch angle [R-axis]" ) ;
00493    XtVaSetValues( pitch_av->wtext , XmNcolumns , 6 , NULL ) ;
00494    SEP_VER(hrc) ;
00495 
00496    yaw_av = new_MCW_arrowval( hrc, "A" ,
00497                                 MCW_AV_downup , -300,300,0 ,
00498                                 MCW_AV_editext , 1 ,
00499                                 NULL , NULL , NULL,NULL ) ;
00500    MCW_reghint_children( yaw_av->wrowcol , "Yaw angle [A-axis]" ) ;
00501    XtVaSetValues( yaw_av->wtext , XmNcolumns , 6 , NULL ) ;
00502    SEP_VER(hrc) ;
00503 
00504    /** cumulative label **/
00505 
00506    xstr = XmStringCreateLtoR( "--" , XmFONTLIST_DEFAULT_TAG ) ;
00507    angle_cum_lab = XtVaCreateManagedWidget(
00508                      "AFNI" , xmLabelWidgetClass , hrc ,
00509                         XmNlabelString , xstr ,
00510                         XmNalignment , XmALIGNMENT_CENTER ,
00511                         XmNinitialResourcesPersistent , False ,
00512                         XmNrecomputeSize , True ,
00513 #if 0
00514                         XmNmarginHeight  , 0 ,
00515                         XmNmarginBottom  , 0 ,
00516                         XmNmarginLeft    , 0 ,
00517                         XmNmarginRight   , 0 ,
00518                         XmNmarginTop     , 0 ,
00519                         XmNmarginWidth   , 0 ,
00520 #endif
00521                         XmNtraversalOn , False ,
00522                      NULL ) ;
00523    XmStringFree(xstr) ;
00524    MCW_register_hint( angle_cum_lab , "Cumulative [degrees]" ) ;
00525 
00526    XtManageChild(hrc) ;
00527 
00528    /********** Shift choosers ***********/
00529 
00530    /*** SEP_HOR(rowcol) ; ***/
00531 
00532    hrc =  XtVaCreateWidget(
00533            "AFNI" , xmRowColumnWidgetClass , rowcol ,
00534               XmNorientation  , XmHORIZONTAL ,
00535               XmNpacking      , XmPACK_TIGHT ,
00536               XmNadjustLast   , False ,
00537               XmNadjustMargin , False ,
00538               XmNtraversalOn  , False ,
00539               XmNmarginWidth  , 0 ,
00540               XmNmarginHeight , 0 ,
00541               XmNinitialResourcesPersistent , False ,
00542            NULL ) ;
00543 
00544    xstr = XmStringCreateLtoR( "Shifts: " ,
00545                               XmFONTLIST_DEFAULT_TAG ) ;
00546    (void) XtVaCreateManagedWidget(
00547                  "AFNI" , xmLabelWidgetClass , hrc ,
00548                     XmNlabelString , xstr ,
00549                     XmNinitialResourcesPersistent , False ,
00550                  NULL ) ;
00551    XmStringFree(xstr) ;
00552 
00553    /** the actual shifts **/
00554 
00555    dS_av = new_MCW_arrowval( hrc, "S" ,
00556                                 MCW_AV_downup , -999,999,0 ,
00557                                 MCW_AV_editext , 1 ,
00558                                 NULL , NULL , NULL,NULL ) ;
00559    MCW_reghint_children( dS_av->wrowcol , "Delta Superior" ) ;
00560    XtVaSetValues( dS_av->wtext , XmNcolumns , 6 , NULL ) ;
00561    SEP_VER(hrc) ;
00562 
00563    dL_av = new_MCW_arrowval( hrc, "L" ,
00564                                 MCW_AV_downup , -999,999,0 ,
00565                                 MCW_AV_editext , 1 ,
00566                                 NULL , NULL , NULL,NULL ) ;
00567    MCW_reghint_children( dL_av->wrowcol , "Delta Left" ) ;
00568    XtVaSetValues( dL_av->wtext , XmNcolumns , 6 , NULL ) ;
00569    SEP_VER(hrc) ;
00570 
00571    dP_av = new_MCW_arrowval( hrc, "P" ,
00572                                 MCW_AV_downup , -999,999,0 ,
00573                                 MCW_AV_editext , 1 ,
00574                                 NULL , NULL , NULL,NULL ) ;
00575    MCW_reghint_children( dP_av->wrowcol , "Delta Posterior" ) ;
00576    XtVaSetValues( dP_av->wtext , XmNcolumns , 6 , NULL ) ;
00577    SEP_VER(hrc) ;
00578 
00579    /** cumulative label **/
00580 
00581    xstr = XmStringCreateLtoR( "--" , XmFONTLIST_DEFAULT_TAG ) ;
00582    shift_cum_lab = XtVaCreateManagedWidget(
00583                      "AFNI" , xmLabelWidgetClass , hrc ,
00584                         XmNalignment , XmALIGNMENT_BEGINNING ,
00585                         XmNlabelString , xstr ,
00586                         XmNinitialResourcesPersistent , False ,
00587                         XmNrecomputeSize , True ,
00588 #if 0
00589                         XmNmarginHeight  , 0 ,
00590                         XmNmarginHeight  , 0 ,
00591                         XmNmarginBottom  , 0 ,
00592                         XmNmarginLeft    , 0 ,
00593                         XmNmarginRight   , 0 ,
00594                         XmNmarginTop     , 0 ,
00595                         XmNmarginWidth   , 0 ,
00596 #endif
00597                         XmNtraversalOn , False ,
00598                      NULL ) ;
00599    XmStringFree(xstr) ;
00600    MCW_register_hint( shift_cum_lab , "Cumulative [mm]" ) ;
00601 
00602    XtManageChild(hrc) ;
00603 
00604    /*** a set of action buttons below the line ***/
00605 
00606    SEP_HOR(rowcol) ;
00607 
00608    (void) MCW_action_area( rowcol , NUD_actor , NACT ) ;
00609 
00610    nudge_pb = (Widget) NUD_actor[0].data ;
00611    clear_pb = (Widget) NUD_actor[1].data ;
00612    undo_pb  = (Widget) NUD_actor[2].data ;
00613    redo_pb  = (Widget) NUD_actor[3].data ;
00614    help_pb  = (Widget) NUD_actor[4].data ;
00615    quit_pb  = (Widget) NUD_actor[5].data ;
00616    doall_pb = (Widget) NUD_actor[6].data ;
00617    print_pb = (Widget) NUD_actor[7].data ;
00618 
00619    /*** that's all ***/
00620 
00621    XtManageChild(rowcol) ;
00622    XtRealizeWidget(shell) ;  /* will not be mapped */
00623    return ;
00624 }
00625 
00626 /*--------------------------------------------------------------------------
00627    Compute a rotation matrix specified by 3 angles:
00628       Q = R3 R2 R1, where Ri is rotation about axis axi by angle thi.
00629    In these routines, the axis codes (ax1,ax2,ax3, hax1,hax2,hax3, and
00630    adx,ady,adz) are globals, computed when the dataset is loaded.
00631 ----------------------------------------------------------------------------*/
00632 
00633 static THD_dmat33 rotmatrix( double th1 , double th2 , double th3  )
00634 {
00635    THD_dmat33 q , p ;
00636 
00637    if( hax1 < 0 ) th1 = -th1 ;
00638    if( hax2 < 0 ) th2 = -th2 ;
00639    if( hax3 < 0 ) th3 = -th3 ;
00640 
00641    LOAD_ROT_DMAT( q , th1 , ax1 ) ;
00642    LOAD_ROT_DMAT( p , th2 , ax2 ) ; q = DMAT_MUL( p , q ) ;
00643    LOAD_ROT_DMAT( p , th3 , ax3 ) ; q = DMAT_MUL( p , q ) ;
00644 
00645    return q ;
00646 }
00647 
00648 /*-----------------------------------------------------------------------
00649   Compute the rotation angles from the matrix
00650   [the signs of these may need to be munged]
00651 -------------------------------------------------------------------------*/
00652 
00653 static void rotangles( THD_dmat33 rm, double *th1, double *th2, double *th3 )
00654 {
00655    *th2 = asin( rm.mat[ax3][ax1] ) ;
00656    *th1 = atan2( -rm.mat[ax3][ax2] , rm.mat[ax3][ax3] ) ;
00657    *th3 = atan2( -rm.mat[ax2][ax1] , rm.mat[ax1][ax1] ) ;
00658 
00659    if( hax1 < 0 ) *th1 = -(*th1) ;
00660    if( hax2 < 0 ) *th2 = -(*th2) ;
00661    if( hax3 < 0 ) *th3 = -(*th3) ;
00662 
00663    return ;
00664 }
00665 
00666 /*-----------------------------------------------------------------------
00667    Compute the shift vector in dataset coordinates from the user inputs.
00668 -------------------------------------------------------------------------*/
00669 
00670 static THD_dfvec3 shiftvec( double dx , double dy , double dz )
00671 {
00672    double qdx=0.0,qdy=0.0,qdz=0.0 ;
00673    THD_dfvec3 qv ;
00674 
00675    switch( adx ){
00676       case  1: qdx = -dx ; break ;
00677       case -1: qdx =  dx ; break ;
00678       case  2: qdy = -dx ; break ;
00679       case -2: qdy =  dx ; break ;
00680       case  3: qdz = -dx ; break ;
00681       case -3: qdz =  dx ; break ;
00682    }
00683 
00684    switch( ady ){
00685       case  1: qdx = -dy ; break ;
00686       case -1: qdx =  dy ; break ;
00687       case  2: qdy = -dy ; break ;
00688       case -2: qdy =  dy ; break ;
00689       case  3: qdz = -dy ; break ;
00690       case -3: qdz =  dy ; break ;
00691    }
00692 
00693    switch( adz ){
00694       case  1: qdx = -dz ; break ;
00695       case -1: qdx =  dz ; break ;
00696       case  2: qdy = -dz ; break ;
00697       case -2: qdy =  dz ; break ;
00698       case  3: qdz = -dz ; break ;
00699       case -3: qdz =  dz ; break ;
00700    }
00701 
00702    LOAD_DFVEC3(qv,qdx,qdy,qdz) ; return qv ;
00703 }
00704 
00705 /*-----------------------------------------------------------------------
00706    Compute the user-coordinate shifts from the dataset-coordinate vector
00707 -------------------------------------------------------------------------*/
00708 
00709 static void shiftdeltas( THD_dfvec3 sv, double *d1, double *d2, double *d3   )
00710 {
00711    double qdx,qdy,qdz , dx=0.0,dy=0.0,dz=0.0 ;
00712 
00713    UNLOAD_DFVEC3( sv , qdx,qdy,qdz ) ;
00714 
00715    switch( adx ){
00716       case  1: dx = -qdx ; break ;
00717       case -1: dx =  qdx ; break ;
00718       case  2: dx = -qdy ; break ;
00719       case -2: dx =  qdy ; break ;
00720       case  3: dx = -qdz ; break ;
00721       case -3: dx =  qdz ; break ;
00722    }
00723 
00724    switch( ady ){
00725       case  1: dy = -qdx ; break ;
00726       case -1: dy =  qdx ; break ;
00727       case  2: dy = -qdy ; break ;
00728       case -2: dy =  qdy ; break ;
00729       case  3: dy = -qdz ; break ;
00730       case -3: dy =  qdz ; break ;
00731    }
00732 
00733    switch( adz ){
00734       case  1: dz = -qdx ; break ;
00735       case -1: dz =  qdx ; break ;
00736       case  2: dz = -qdy ; break ;
00737       case -2: dz =  qdy ; break ;
00738       case  3: dz = -qdz ; break ;
00739       case -3: dz =  qdz ; break ;
00740    }
00741 
00742    *d1 = dx ; *d2 = dy ; *d3 = dz ; return ;
00743 }
00744 
00745 /*-----------------------------------------------------------------------
00746    Set the cumulative angles/shifts labels from the current state
00747    (stored in globals rmat and svec)
00748 -------------------------------------------------------------------------*/
00749 
00750 static void NUD_setcumlab(void)
00751 {
00752    double th1,th2,th3 ;
00753    XmString xstr ;
00754 
00755    rotangles( rmat, &th1,&th2,&th3 ) ;
00756    th1 *= iha*(180.0/PI) ; th2 *= iha*(180.0/PI) ; th3 *= iha*(180.0/PI) ;
00757    xstr = XmStringCreateLtoR( NUD_threestring(th1,th2,th3,'I','R','A') ,
00758                               XmFONTLIST_DEFAULT_TAG ) ;
00759    XtVaSetValues( angle_cum_lab , XmNlabelString , xstr , NULL ) ;
00760    XmStringFree(xstr) ;
00761 
00762    shiftdeltas( svec , &th1,&th2,&th3 ) ;
00763    xstr = XmStringCreateLtoR( NUD_threestring(th1,th2,th3,'S','L','P') ,
00764                               XmFONTLIST_DEFAULT_TAG ) ;
00765    XtVaSetValues( shift_cum_lab , XmNlabelString , xstr , NULL ) ;
00766    XmStringFree(xstr) ;
00767 
00768    return ;
00769 }
00770 
00771 /*-----------------------------------------------------------------------
00772   Write a 3drotate partial command to the screen corresponding
00773   to the current nudge -- 31 Aug 2000
00774 -------------------------------------------------------------------------*/
00775 
00776 static void NUD_print_CB( Widget w , XtPointer cd , XtPointer cb )
00777 {
00778    double th1,th2,th3 ;
00779    char cbuf[256] = "3drotate" ;
00780 
00781    strcat( cbuf , " " ) ;
00782    strcat( cbuf , REG_resam_options[interp_av->ival] ) ;
00783 
00784    if( clip_av->ival ) strcat( cbuf , " -clipit" ) ;
00785 
00786    rotangles( rmat, &th1,&th2,&th3 ) ;
00787    th1 *= iha*(180.0/PI) ; th2 *= iha*(180.0/PI) ; th3 *= iha*(180.0/PI) ;
00788    strcat( cbuf , " -rotate " ) ;
00789    strcat( cbuf , NUD_3string(th1,th2,th3,'I','R','A') ) ;
00790 
00791    shiftdeltas( svec , &th1,&th2,&th3 ) ;
00792    strcat( cbuf , " -ashift " ) ;
00793    strcat( cbuf , NUD_3string(th1,th2,th3,'S','L','P') ) ;
00794 
00795    strcat( cbuf , " -prefix ???  inputdataset" ) ;
00796 
00797    fprintf(stderr,"\nCurrent Nudge command is:\n%s\n",cbuf ) ;
00798    return ;
00799 }
00800 
00801 /*-----------------------------------------------------------------------
00802    Push the current state (rmat and svec) onto the undo stack
00803 -------------------------------------------------------------------------*/
00804 
00805 static void NUD_undopush(void)
00806 {
00807    if( undo_nuse >= undo_nall ){
00808       undo_nall = undo_nuse + 4 ;
00809       undo_rmat = (THD_dmat33 *)realloc( undo_rmat, sizeof(THD_dmat33)*undo_nall );
00810       undo_svec = (THD_dfvec3 *)realloc( undo_svec, sizeof(THD_dfvec3)*undo_nall );
00811    }
00812 
00813    undo_rmat[undo_nuse] = rmat ;
00814    undo_svec[undo_nuse] = svec ;
00815    undo_nuse++ ; undo_ntop = undo_nuse ; SENSITIZE(redo_pb,0) ;
00816    return ;
00817 }
00818 
00819 /*-------------------------------------------------------------------
00820   Callback for Nudge button
00821 ---------------------------------------------------------------------*/
00822 
00823 static void NUD_nudge_CB( Widget w, XtPointer client_data, XtPointer call_data )
00824 {
00825    float roll,pitch,yaw , dS,dL,dP ;
00826    THD_dmat33 new_rmat ;
00827    THD_dfvec3 new_svec , qv ;
00828 
00829    if( dset == NULL ){ XBell(dc->display,100); return; }  /* shouldn't happen */
00830 
00831    roll  = (PI/180.0)*roll_av->fval  ;
00832    pitch = (PI/180.0)*pitch_av->fval ;
00833    yaw   = (PI/180.0)*yaw_av->fval   ;
00834    dS    = dS_av->fval ;
00835    dL    = dL_av->fval ;
00836    dP    = dP_av->fval ;
00837 
00838    if( roll==0.0 && pitch==0.0 && yaw==0.0 && dS==0.0 && dL==0.0 && dP==0.0 ){
00839       (void) MCW_popup_message( nudge_pb ,
00840                                    " \n"
00841                                    "** Can't nudge dataset! **\n"
00842                                    "** All Angle and Shifts **\n"
00843                                    "** are zero.            **\n" ,
00844                                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
00845       XBell( dc->display , 100 ) ;
00846       return ;
00847    }
00848 
00849    SENSITIZE(undo_pb,1)   ; SENSITIZE(doall_pb,1)    ;
00850    SENSITIZE(choose_pb,0) ; AV_SENSITIZE(brick_av,0) ;
00851 
00852    new_rmat = rotmatrix( roll, pitch, yaw ) ;
00853    rmat     = DMAT_MUL( new_rmat , rmat ) ;
00854 
00855    new_svec = DMATVEC( new_rmat , svec )  ;
00856    qv       = shiftvec( dS , dL , dP ) ;
00857    svec     = ADD_DFVEC3( new_svec , qv ) ;
00858 
00859    NUD_undopush() ;       /* push new transformatin onto undo list */
00860    NUD_setcumlab() ;      /* draw the cumulative labels */
00861 
00862    /* actually do something here */
00863 
00864    if( imbase == NULL )                             /* first time: get base */
00865       imbase = mri_copy( DSET_BRICK(dset,dset_ival) ) ;
00866 
00867    NUD_update_base( nudge_pb ) ; return ;
00868 }
00869 
00870 /*-------------------------------------------------------------------
00871   Callback for Clear button
00872 ---------------------------------------------------------------------*/
00873 
00874 static void NUD_clear_CB( Widget w, XtPointer client_data, XtPointer call_data )
00875 {
00876    AV_assign_fval( roll_av  , 0.0 ) ;
00877    AV_assign_fval( pitch_av , 0.0 ) ;
00878    AV_assign_fval( yaw_av   , 0.0 ) ;
00879    AV_assign_fval( dS_av    , 0.0 ) ;
00880    AV_assign_fval( dL_av    , 0.0 ) ;
00881    AV_assign_fval( dP_av    , 0.0 ) ;
00882    return ;
00883 }
00884 
00885 /*-------------------------------------------------------------------
00886   Callback for Undo button
00887 ---------------------------------------------------------------------*/
00888 
00889 static void NUD_undo_CB( Widget w, XtPointer client_data, XtPointer call_data )
00890 {
00891    if( undo_nuse <= 1 ){ XBell(dc->display,100); return; }
00892 
00893    undo_nuse-- ;
00894    rmat = undo_rmat[undo_nuse-1] ;
00895    svec = undo_svec[undo_nuse-1] ;
00896    NUD_setcumlab() ;
00897    if( undo_nuse <= 1 ){ SENSITIZE(undo_pb,0); SENSITIZE(doall_pb,0); }
00898    SENSITIZE(redo_pb,1) ;
00899 
00900    /* actually do something here */
00901 
00902    NUD_update_base( undo_pb ) ; return ;
00903 }
00904 
00905 /*-------------------------------------------------------------------
00906   Callback for Redo button
00907 ---------------------------------------------------------------------*/
00908 
00909 static void NUD_redo_CB( Widget w, XtPointer client_data, XtPointer call_data )
00910 {
00911    if( undo_ntop <= undo_nuse ){ XBell(dc->display,100); return; }
00912 
00913    rmat = undo_rmat[undo_nuse] ;
00914    svec = undo_svec[undo_nuse] ;
00915    undo_nuse++ ;
00916    NUD_setcumlab() ;
00917    if( undo_nuse >= undo_ntop ) SENSITIZE(redo_pb,0) ;
00918    SENSITIZE(undo_pb,1) ; SENSITIZE(doall_pb,1) ;
00919 
00920    /* actually do something here */
00921 
00922    NUD_update_base( redo_pb ) ; return ;
00923 }
00924 
00925 /*-------------------------------------------------------------------
00926   Callback for Quit button
00927 ---------------------------------------------------------------------*/
00928 
00929 static void NUD_quit_CB( Widget w, XtPointer client_data, XtPointer call_data )
00930 {
00931    if( dset != NULL ){
00932       DSET_unlock(dset) ; DSET_unload(dset) ; DSET_anyize(dset) ;
00933       if( undo_nuse > 1 ){                 /* if not at the null nudge */
00934          MCW_invert_widget(quit_pb) ;
00935          THD_load_statistics( dset ) ;
00936          PLUTO_dset_redisplay( dset ) ;
00937          AFNI_process_drawnotice( im3d ) ;
00938          MCW_invert_widget(quit_pb) ;
00939       }
00940       dset = NULL ;
00941    }
00942 
00943    if( imbase != NULL ){ mri_free(imbase); imbase = NULL; }
00944 
00945    if( undo_rmat != NULL ){ free(undo_rmat); undo_rmat = NULL; }
00946    if( undo_svec != NULL ){ free(undo_svec); undo_svec = NULL; }
00947    undo_nall = undo_nuse = 0 ;
00948 
00949    XtUnmapWidget( shell ) ; nudger_open = 0 ;
00950    return ;
00951 }
00952 
00953 /*-------------------------------------------------------------------
00954   Callback for help button
00955 ---------------------------------------------------------------------*/
00956 
00957 static void NUD_help_CB( Widget w, XtPointer client_data, XtPointer call_data )
00958 {
00959    (void ) new_MCW_textwin( help_pb ,
00960 
00961      "PURPOSE: Nudge a dataset's position a little.\n"
00962      "\n"
00963      "CONTROLS:\n"
00964      "Choose Dataset: button to choose which dataset to move around.\n"
00965      "Brick:          which single sub-brick of the dataset will be moved,\n"
00966      "                  prior to use of 'Do All'.\n"
00967      "Resampling:     choose interpolation method for brick resampling\n"
00968      "Clip:           clip each brick after interpolation?\n"
00969      "---------------------------------------------------------------------\n"
00970      "Angles: the entry fields are the rotational angles to be applied:\n"
00971      "          positive I = roll  = looking to the left\n"
00972      "          positive R = pitch = nodding the head forward\n"
00973      "          positive A = yaw   = tilting left ear towards shoulder\n"
00974      "Shifts: the entry fields are the translational shifts to be applied.\n"
00975      "          positive S = superior  = shifting head upwards\n"
00976      "          positive L = left      = shifting head leftwards\n"
00977      "          positive P = posterior = shifting head backwards\n"
00978      "---------------------------------------------------------------------\n"
00979      "Nudge:  apply the Angles and Shifts entered above to the chosen Brick;\n"
00980      "          also updates the cumulative angles/shifts\n"
00981      "Clear:  set the Angles and Shifts to zero\n"
00982      "Undo:   undo the previous Nudge\n"
00983      "Redo:   redo the previously undone Nudge\n"
00984      "Quit:   exit, restoring the dataset to its values stored on disk\n"
00985      "Do All: apply cumulative angles/shifts to all sub-bricks; write to disk\n"
00986      "Print:  print (to stderr) 3drotate command equivalent to current nudge\n"
00987      "        [use 'Print' before 'Do All', since 'Do All' sets nudge to 0]\n"
00988      "=======================================================================\n"
00989      "USAGE SUGGESTIONS:\n"
00990      "* Load the dataset and brick to nudge into this plugin.\n"
00991      "* Switch the image viewers to the same dataset and brick;\n"
00992      "    as the brick is nudged, then images will be redrawn.\n"
00993      "* You can also use the rendering plugin - if DynaDraw is on,\n"
00994      "    the brick will be re-rendered with each nudge.\n"
00995      "* If you are comparing the nudged dataset to a reference, and\n"
00996      "    trying to realign the two, one way is to temporarily make\n"
00997      "    one of them a fim dataset (using '3drefit -fim'), and then\n"
00998      "    display it as a color overlay.  When you are happy with\n"
00999      "    the alignment, you can quit AFNI and use 3drefit to change\n"
01000      "    the dataset back to whatever it was before.\n"
01001      "* When using the '-fim' trick on the nudged dataset, you will\n"
01002      "    have to set the colors and color scaling range appropriately\n"
01003      "    on the 'Define Function' control panel, otherwise the color\n"
01004      "    overlay will look so peculiar as to be useless.\n"
01005      "* Nudge-ing on the single sub-brick is done only in memory, so if\n"
01006      "    you Quit, the dataset on disk will be unchanged.  When you use\n"
01007      "    'Do All', all sub-bricks will be nudged the same way and then\n"
01008      "    be written out to disk, overwriting the original dataset .BRIK.\n"
01009      "* Instead of using 'Do All', you can use 'Print' to see the 3drotate\n"
01010      "    parameters to use.  You can then apply these to as many datasets\n"
01011      "    you want (e.g., in a shell script, to nudge a whole bunch of\n"
01012      "    datasets exactly the same way).\n"
01013      "* I suggest you do NOT nudge functional activation maps.  It is better\n"
01014      "    to nudge the anatomical underlay, or nudge the original EPI time\n"
01015      "    series.  Nudging a dataset implies interpolating to a new grid,\n"
01016      "    and this is problematical for the non-smooth activation maps.\n"
01017      "=======================================================================\n"
01018      "WARNINGS:\n"
01019      "* Values past the edge of the dataset are 0, and if they are shifted\n"
01020      "    into the volume covered by the dataset, you will get 0's there.\n"
01021      "* Values shifted past the edge of the volume covered by the dataset\n"
01022      "    will be LOST.  This may seem obvious, but when you are shifting\n"
01023      "    a functional dataset that is smaller than the anatomical underlay,\n"
01024      "    it can look mysterious.\n"
01025      "* One solution to the problem above is to use 3dZeropad to explicitly\n"
01026      "    put a layer of 0's around the outside of the functional dataset\n"
01027      "    volume.  Shifted values will then go into this 0 buffer, and\n"
01028      "    will not be lost.\n"
01029      "=======================================================================\n"
01030      "ALGORITHM:\n"
01031      "* Uses the same basic routines as program 3drotate; see\n"
01032      "      RW Cox and A Jesmanowicz.\n"
01033      "      Real-time 3D image registration for functional MRI.\n"
01034      "      Magnetic Resonance in Medicine, 42: 1014-1018, 1999.\n"
01035      "    Also see 3drotate.c, 3dvolreg.c, and thd_rot3d.c.\n"
01036      "* Bricks are not repeatedly interpolated as you nudge - each nudge\n"
01037      "    takes place using the cumulative angles/shifts starting from the\n"
01038      "    brick read in from disk.  However, if you re-nudge a dataset\n"
01039      "    after using 'Do All' to write to disk, you will then be re-\n"
01040      "    interpolating an already interpolated dataset.\n"
01041      "* Note that cumulative angles/shifts may not be exactly the sum of\n"
01042      "    the incremental nudges.  This effect is due to the non-Abelian\n"
01043      "    nature of 3D rotation (i.e., doing rotation A then B is not the\n"
01044      "    same as doing rotation B then A).\n"
01045      "* The angle and shift parameters are specified in the same order\n"
01046      "    as output by 3dvolreg, and would be input to 3drotate as\n"
01047      "      -rotate <roll>I <pitch>R <yaw>A  -ashift <dS>S <dL>L <dP>P\n"
01048      "* Rotations are about the center of the rectangular volume of the\n"
01049      "    dataset.  This is not likely to be the center of the brain.\n"
01050      "=======================================================================\n"
01051      "AUTHOR: RWCox, April 2000\n"
01052      "=======================================================================\n"
01053 
01054     , TEXT_READONLY ) ;
01055    return ;
01056 }
01057 
01058 /*-------------------------------------------------------------------
01059   Callback for choose button - give the user some dataset choices.
01060   Criteria for datasets that can be nudged:
01061     - must be in current session
01062     - must have actual bricks
01063 ---------------------------------------------------------------------*/
01064 
01065 static int                  ndsl = 0 ;
01066 static PLUGIN_dataset_link * dsl = NULL ;
01067 
01068 static void NUD_choose_CB( Widget w, XtPointer client_data, XtPointer call_data )
01069 {
01070    THD_session * ss  = im3d->ss_now ;           /* current session */
01071    int           vv  = im3d->vinfo->view_type ; /* view type */
01072    THD_3dim_dataset * qset ;
01073    int id , ltop , llen ;
01074    char qnam[THD_MAX_NAME] , label[THD_MAX_NAME] ;
01075    static char ** strlist = NULL ;
01076 
01077    /* can't do this if a dataset is already active and changed */
01078 
01079    if( dset != NULL && undo_nuse > 1 ){
01080       (void) MCW_popup_message( choose_pb ,
01081                                    "Can't change datasets until\n"
01082                                    "you save the changes you've\n"
01083                                    "already made.  Or you could\n"
01084                                    "'Quit' and re-start the Editor" ,
01085                                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
01086       XBell( dc->display , 100 ) ;
01087       return ;
01088    }
01089 
01090    /* initialize */
01091 
01092    ndsl = 0 ;
01093 
01094    /* scan datasets */
01095 
01096    for( id=0 ; id < ss->num_dsset ; id++ ){
01097       qset = ss->dsset[id][vv] ;
01098 
01099       if( ! ISVALID_DSET (qset) ) continue ;  /* skip */
01100       if( ! DSET_INMEMORY(qset) ) continue ;
01101       if( DSET_BRICK_TYPE(qset,0) == MRI_complex ) continue ;
01102 
01103       ndsl++ ;
01104       dsl = (PLUGIN_dataset_link *)
01105               XtRealloc( (char *) dsl , sizeof(PLUGIN_dataset_link)*ndsl ) ;
01106 
01107       make_PLUGIN_dataset_link( qset , dsl + (ndsl-1) ) ;
01108    }
01109 
01110    /* found nothing? exit */
01111 
01112    if( ndsl < 1 ){
01113       (void) MCW_popup_message( choose_pb ,
01114                                    " \nDidn't find any datasets to edit!\n" ,
01115                                 MCW_USER_KILL | MCW_TIMER_KILL ) ;
01116       XBell( dc->display , 100 ) ;
01117       return ;
01118    }
01119 
01120    /*--- 23 Nov 1996: loop over dataset links and patch their titles
01121                       to include an indicator of the dataset type    ---*/
01122 
01123    ltop = 4 ;
01124    for( id=0 ; id < ndsl ; id++ ){
01125       llen = strlen(dsl[id].title) ;
01126       ltop = MAX(ltop,llen) ;
01127    }
01128 
01129    for( id=0 ; id < ndsl ; id++ ){
01130       qset = PLUTO_find_dset( &(dsl[id].idcode) ) ;
01131       if( ! ISVALID_DSET(qset) ) continue ;
01132       if( ISANAT(qset) ){
01133          if( ISANATBUCKET(qset) )         /* 30 Nov 1997 */
01134             sprintf(qnam,"%-*s [%s:%d]" ,
01135                     ltop,dsl[id].title ,
01136                     ANAT_prefixstr[qset->func_type] , DSET_NVALS(qset) ) ;
01137 
01138          else if( DSET_NUM_TIMES(qset) == 1 )
01139             sprintf(qnam,"%-*s [%s]" ,
01140                     ltop,dsl[id].title ,
01141                     ANAT_prefixstr[qset->func_type] ) ;
01142 
01143          else
01144             sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
01145                     ltop,dsl[id].title ,
01146                     ANAT_prefixstr[qset->func_type] , DSET_NUM_TIMES(qset) ) ;
01147 
01148       } else {
01149          if( ISFUNCBUCKET(qset) )         /* 30 Nov 1997 */
01150             sprintf(qnam,"%-*s [%s:%d]" ,
01151                     ltop,dsl[id].title ,
01152                     FUNC_prefixstr[qset->func_type] , DSET_NVALS(qset) ) ;
01153 
01154          else if( DSET_NUM_TIMES(qset) == 1 )
01155             sprintf(qnam,"%-*s [%s]" ,
01156                     ltop,dsl[id].title ,
01157                     FUNC_prefixstr[qset->func_type] ) ;
01158 
01159          else
01160             sprintf(qnam,"%-*s [%s:3D+t:%d]" ,
01161                     ltop,dsl[id].title ,
01162                     FUNC_prefixstr[qset->func_type] , DSET_NVALS(qset) ) ;
01163       }
01164 
01165       if( DSET_COMPRESSED(qset) ) strcat(qnam,"z") ;
01166 
01167       strcpy( dsl[id].title , qnam ) ;
01168    }
01169 
01170    /*--- make a popup chooser for the user to browse ---*/
01171 
01172    POPDOWN_strlist_chooser ;
01173 
01174    strlist = (char **) XtRealloc( (char *)strlist , sizeof(char *)*ndsl ) ;
01175    for( id=0 ; id < ndsl ; id++ ) strlist[id] = dsl[id].title ;
01176 
01177    sprintf( label , "AFNI Dataset from\nthe %s" , VIEW_typestr[vv] ) ;
01178 
01179    MCW_choose_strlist( w , label , ndsl , -1 , strlist ,
01180                        NUD_finalize_dset_CB , NULL     ) ;
01181 
01182    return ;
01183 }
01184 
01185 /*---------------------------------------------------------------------------
01186    Make a label for a sub-brick selector menu
01187 -----------------------------------------------------------------------------*/
01188 
01189 static char * NUD_brick_av_label_CB( MCW_arrowval * av , XtPointer cd )
01190 {
01191    static char blab[32] ;
01192    THD_3dim_dataset * dset = (THD_3dim_dataset *) cd ;
01193    static char *lfmt[3] = { "#%1d %-14.14s", "#%2d %-14.14s", "#%3d %-14.14s" };
01194    static char *rfmt[3] = { "%-14.14s #%1d", "%-14.14s #%2d", "%-14.14s #%3d" };
01195 
01196    if( ISVALID_3DIM_DATASET(dset) ){
01197 
01198 #ifdef USE_RIGHT_BUCK_LABELS
01199       if( DSET_NVALS(dset) < 10 )
01200         sprintf(blab, rfmt[0] , DSET_BRICK_LABEL(dset,av->ival) , av->ival ) ;
01201       else if( DSET_NVALS(dset) < 100 )
01202         sprintf(blab, rfmt[1] , DSET_BRICK_LABEL(dset,av->ival) , av->ival ) ;
01203       else
01204         sprintf(blab, rfmt[2] , DSET_BRICK_LABEL(dset,av->ival) , av->ival ) ;
01205 #else
01206       if( DSET_NVALS(dset) < 10 )
01207         sprintf(blab, lfmt[0] , av->ival , DSET_BRICK_LABEL(dset,av->ival) ) ;
01208       else if( DSET_NVALS(dset) < 100 )
01209         sprintf(blab, lfmt[1] , av->ival , DSET_BRICK_LABEL(dset,av->ival) ) ;
01210       else
01211         sprintf(blab, lfmt[2] , av->ival , DSET_BRICK_LABEL(dset,av->ival) ) ;
01212 #endif
01213    }
01214    else
01215       sprintf(blab," #%d ",av->ival) ;  /* should not happen! */
01216 
01217    return blab ;
01218 }
01219 
01220 /*------------------------------------------------------------------------------
01221   Called when the user actually makes the choice of dataset
01222 --------------------------------------------------------------------------------*/
01223 
01224 static void NUD_finalize_dset_CB( Widget w, XtPointer fd, MCW_choose_cbs * cbs )
01225 {
01226    int id = cbs->ival ;
01227    THD_3dim_dataset * qset ;
01228    XmString xstr ;
01229    char str[256] ;
01230 
01231    /* check for errors */
01232 
01233    if( !nudger_open ){ POPDOWN_strlist_chooser; XBell(dc->display,100); return; }
01234 
01235    if( dset != NULL && undo_nuse > 1 ){ XBell(dc->display,100); return; }
01236 
01237    if( id < 0 || id >= ndsl ){ XBell(dc->display,100); return; }
01238 
01239    qset = PLUTO_find_dset( &(dsl[id].idcode) ) ;  /* the new dataset */
01240 
01241    if( qset == NULL ){ XBell(dc->display,100); return; } /* shouldn't happen */
01242 
01243    /* if not same as old dataset, close that one down */
01244 
01245    if( dset != NULL && qset != dset ){
01246       DSET_unlock(dset) ; DSET_unload(dset) ; DSET_anyize(dset) ;
01247    }
01248 
01249    /* accept this dataset */
01250 
01251    dset = qset ; dset_idc = dset->idcode ;
01252 
01253    undo_nuse = 1 ;
01254    undo_ntop = 1 ;
01255    rmat = undo_rmat[0] ;
01256    svec = undo_svec[0] ; NUD_setcumlab() ;
01257 
01258    SENSITIZE(undo_pb ,0) ;
01259    SENSITIZE(redo_pb ,0) ;
01260    SENSITIZE(nudge_pb,1) ;
01261    SENSITIZE(doall_pb,0) ;
01262 
01263    /* write the informational label */
01264 
01265    xstr = XmStringCreateLtoR( dsl[id].title , XmFONTLIST_DEFAULT_TAG ) ;
01266    XtVaSetValues( info_lab , XmNlabelString , xstr , NULL ) ;
01267    XmStringFree(xstr) ;
01268 
01269    /* lock and load this one into memory (not mmap) */
01270 
01271    DSET_mallocize(dset) ; DSET_lock(dset) ; DSET_load(dset) ;
01272 
01273    if( imbase != NULL ){ mri_free(imbase); imbase = NULL; }
01274 
01275    /* refit the sub-brick selector menu */
01276 
01277    if( dset_ival >= DSET_NVALS(dset) ) dset_ival = DSET_NVALS(dset)-1 ;
01278 
01279    refit_MCW_optmenu( brick_av ,
01280                       0 ,                       /* new minval */
01281                       DSET_NVALS(dset)-1 ,      /* new maxval */
01282                       dset_ival ,               /* new inival */
01283                       0 ,                       /* new decim? */
01284                       NUD_brick_av_label_CB ,   /* text routine */
01285                       dset                      /* text data */
01286                     ) ;
01287 
01288    AV_SENSITIZE( brick_av , (DSET_NVALS(dset) > 1) ) ;
01289 
01290    /* set codes indicating rotation axes:
01291       iha = left or right handed coordinate order in dataset
01292       ax1 = axis index for 'I'   hax1 = sign for roll angle
01293       ax2 = axis index for 'R'   hax2 = sign for pitch angle
01294       ax3 = axis index for 'A'   hax3 = sign for yaw angle   */
01295 
01296    iha = THD_handedness( dset ) ;
01297    ax1 = THD_axcode(dset,'I') ; hax1 = ax1 ; ax1 = abs(ax1)-1 ; /* roll */
01298    ax2 = THD_axcode(dset,'R') ; hax2 = ax2 ; ax2 = abs(ax2)-1 ; /* pitch */
01299    ax3 = THD_axcode(dset,'A') ; hax3 = ax3 ; ax3 = abs(ax3)-1 ; /* yaw */
01300 
01301    adx = THD_axcode(dset,'S') ;  /* for shifts */
01302    ady = THD_axcode(dset,'L') ;
01303    adz = THD_axcode(dset,'P') ;
01304 
01305 #if 0
01306    fprintf(stderr,"NUD_finalize_dset_CB: iha=%d\n"
01307                   "  ax1 =%2d ax2 =%2d ax3 =%2d\n"
01308                   "  hax1=%2d hax2=%2d hax3=%2d\n"
01309                   "  adx =%2d ady =%2d adz =%2d\n" ,
01310            iha , ax1,ax2,ax3 , hax1,hax2,hax3 , adx,ady,adz ) ;
01311 #endif
01312 
01313    return ;
01314 }
01315 
01316 /*-------------------------------------------------------------------
01317   Callback for sub-brick index arrowval
01318 ---------------------------------------------------------------------*/
01319 
01320 static void NUD_brick_av_CB( MCW_arrowval * av , XtPointer cd )
01321 {
01322    if( imbase != NULL ){ XBell(dc->display,100); return; }
01323    dset_ival = av->ival ;
01324    return ;
01325 }
01326 
01327 /*-------------------------------------------------------------------
01328    Rotate an image in place according to the current specs
01329 ---------------------------------------------------------------------*/
01330 
01331 static void NUD_rotate( MRI_IMAGE *im )
01332 {
01333    int clipit=clip_av->ival , mode=REG_resam_ints[interp_av->ival] ;
01334    float cbot,ctop ;
01335    float *fvol ;
01336    double th1,th2,th3 , dx,dy,dz ;
01337 
01338    if( im == NULL || dset == NULL ) return ;
01339 
01340    rotangles( rmat, &th1,&th2,&th3 ) ;
01341    if( hax1 < 0 ) th1 = -th1 ;
01342    if( hax2 < 0 ) th2 = -th2 ;
01343    if( hax3 < 0 ) th3 = -th3 ;
01344    UNLOAD_DFVEC3( svec , dx,dy,dz ) ;
01345 
01346 #if 0
01347 fprintf(stderr,"th1=%g th2=%g th3=%g\n",th1,th2,th3) ;
01348 #endif
01349 
01350    /* nothing to do? */
01351 
01352    if( fabs(th1) < EPS && fabs(th2) < EPS && fabs(th3) < EPS &&
01353        fabs(dx)  < EPS && fabs(dy)  < EPS && fabs(dz)  < EPS   ) return ;
01354 
01355 #if 0
01356    if( clipit && (mode == MRI_LINEAR || mode == MRI_NN) ) clipit = 0 ;
01357 #endif
01358 
01359    /*--- 09 May 2005: RGB input image ==> do each channel separately ---*/
01360 
01361 #undef  BCLIP
01362 #define BCLIP(x)  if((x)<0.0f)(x)=0.0f; else if((x)>255.0)(x)=255.0
01363 
01364    if( im->kind == MRI_rgb ){
01365      MRI_IMARR *imtriple ;
01366      MRI_IMAGE *rim, *gim, *bim, *newim ;
01367      float *fr, *fg, *fb ;
01368      register int ii ;
01369 
01370      imtriple = mri_rgb_to_3float( im ) ;
01371      if( imtriple == NULL ){
01372        fprintf(stderr,"*** mri_rgb_to_3float fails in NUD_rotate!\n"); return;
01373      }
01374      rim = IMAGE_IN_IMARR(imtriple,0) ;
01375      gim = IMAGE_IN_IMARR(imtriple,1) ;
01376      bim = IMAGE_IN_IMARR(imtriple,2) ; FREE_IMARR(imtriple) ;
01377      NUD_rotate(rim); NUD_rotate(gim); NUD_rotate(bim);
01378      fr = MRI_FLOAT_PTR(rim); fg = MRI_FLOAT_PTR(gim); fb = MRI_FLOAT_PTR(bim);
01379      for( ii=0 ; ii < im->nvox ; ii++ ){
01380        BCLIP(fr[ii]) ; BCLIP(fg[ii]) ; BCLIP(fb[ii]) ;
01381      }
01382      newim = mri_3to_rgb( rim, gim, bim ) ;
01383      mri_free(rim) ; mri_free(gim) ; mri_free(bim) ;
01384      memcpy( MRI_RGB_PTR(im) , MRI_RGB_PTR(newim) , 3*im->nvox ) ;
01385      mri_free(newim) ;
01386      return ;
01387    }
01388 
01389    /*--- need a floating point copy? ---*/
01390 
01391    if( im->kind != MRI_float ){
01392       fvol = (float *) malloc( sizeof(float) * im->nvox ) ;
01393       EDIT_coerce_type( im->nvox  ,
01394                         im->kind  , mri_data_pointer(im) ,
01395                         MRI_float , fvol ) ;
01396    } else {
01397       fvol = MRI_FLOAT_PTR(im) ;
01398    }
01399 
01400    /* compute bounds? */
01401 
01402    if( clipit ){
01403       register int ii ; register float bb,tt ;
01404       bb = tt = fvol[0] ;
01405       for( ii=1 ; ii < im->nvox ; ii++ ){
01406               if( fvol[ii] < bb ) bb = fvol[ii] ;
01407          else if( fvol[ii] > tt ) tt = fvol[ii] ;
01408       }
01409       cbot = bb ; ctop = tt ;
01410    }
01411 
01412    /* actually rotate! */
01413 
01414    THD_rota_method( mode ) ;  /* this line fixed 28 Nov 2000 */
01415 
01416    THD_rota_vol( im->nx , im->ny , im->nz ,
01417                  fabs(DSET_DX(dset)), fabs(DSET_DY(dset)), fabs(DSET_DZ(dset)),
01418                  fvol , ax1,th1 , ax2,th2 , ax3,th3 , DELTA_AFTER,dx,dy,dz ) ;
01419 
01420    /* apply bounds? */
01421 
01422    if( clipit ){
01423      register int ii ; register float bb,tt ;
01424      bb = cbot ; tt = ctop ;
01425      for( ii=0 ; ii < im->nvox ; ii++ ){
01426             if( fvol[ii] < bb ) fvol[ii] = bb ;
01427        else if( fvol[ii] > tt ) fvol[ii] = tt ;
01428      }
01429    }
01430 
01431    /* convert type? */
01432 
01433    if( im->kind != MRI_float ){
01434       EDIT_coerce_type( im->nvox , MRI_float , fvol ,
01435                         im->kind  , mri_data_pointer(im) ) ;
01436       free(fvol) ;
01437    }
01438 
01439    return ;
01440 }
01441 
01442 /*--------------------------------------------------------------------------
01443   Actually nudge the base brick, and then redisplay it.
01444 ----------------------------------------------------------------------------*/
01445 
01446 static void NUD_update_base(Widget w)
01447 {
01448    MRI_IMAGE * im ;
01449 
01450    if( dset == NULL || imbase == NULL || dset_ival >= DSET_NVALS(dset) ) return;
01451 
01452    if( w != NULL ) MCW_invert_widget(w) ;
01453 
01454    im = mri_copy(imbase) ;                                  /* copy base */
01455    NUD_rotate( im ) ;                                       /* rotate copy */
01456    EDIT_substitute_brick( dset , dset_ival ,                /* put into dset */
01457                           im->kind , mri_data_pointer(im) );
01458 
01459    if( ISVALID_STATISTIC(dset->stats) )                     /* 27 Nov 2000 */
01460       THD_update_statistics( dset ) ;
01461 
01462    mri_clear_data_pointer( im ) ; mri_free(im) ;            /* toss the trash */
01463 
01464    PLUTO_dset_redisplay( dset ) ;                           /* re-show it */
01465    AFNI_process_drawnotice( im3d ) ;                        /* anyone cares? */
01466    if( w != NULL ) MCW_invert_widget(w) ;
01467    return ;
01468 }
01469 
01470 /*-------------------------------------------------------------------
01471   Callback for Do All button - nudge all bricks
01472 ---------------------------------------------------------------------*/
01473 
01474 static void NUD_doall_CB( Widget w, XtPointer client_data, XtPointer call_data )
01475 {
01476    int iv , nvals ;
01477    MRI_IMAGE * im ;
01478    char str[256] ;
01479    double th1,th2,th3 ;
01480    Widget meter ;
01481 
01482    if( dset == NULL || imbase == NULL || undo_nuse == 1 ){  /* bad bad bad */
01483       XBell(dc->display,100); return;
01484    }
01485 
01486    /*----- actually do something -----*/
01487 
01488    /* copy imbase back into dataset */
01489 
01490    EDIT_substitute_brick( dset , dset_ival ,
01491                           imbase->kind , mri_data_pointer(imbase) ) ;
01492    mri_clear_data_pointer(imbase) ; mri_free(imbase) ; imbase = NULL ;
01493 
01494    /* nudge each sub-brick */
01495 
01496    nvals = DSET_NVALS(dset) ;
01497    if( nvals > 1 )
01498       meter = MCW_popup_meter( shell , METER_TOP_WIDE ) ;
01499 
01500    for( iv=0 ; iv < nvals ; iv++ ){
01501       MCW_invert_widget(doall_pb) ;
01502 
01503       im = mri_copy( DSET_BRICK(dset,iv) ) ;
01504       NUD_rotate( im ) ;
01505       EDIT_substitute_brick( dset , iv ,
01506                              im->kind , mri_data_pointer(im) ) ;
01507       mri_clear_data_pointer( im ) ; mri_free(im) ;
01508 
01509       if( nvals > 1 )
01510          MCW_set_meter( meter , (int)(100.0*(iv+0.5)/nvals) ) ;
01511    }
01512 
01513    /* store the history of what we just did */
01514 
01515    rotangles( rmat, &th1,&th2,&th3 ) ;
01516    th1 *= iha*(180.0/PI) ; th2 *= iha*(180.0/PI) ; th3 *= iha*(180.0/PI) ;
01517    sprintf(str,"plug_nudge: -rotate %s",
01518            NUD_threestring(th1,th2,th3,'I','R','A') ) ;
01519 
01520    iv = strlen(str) ;
01521    shiftdeltas( svec , &th1,&th2,&th3 ) ;
01522    sprintf(str+iv," -ashift %s" ,
01523            NUD_threestring(th1,th2,th3,'S','L','P') ) ;
01524 
01525    tross_Append_History( dset , str );
01526 
01527    /* write to disk, and redisplay */
01528 
01529    if( nvals > 1 ) MCW_set_meter( meter , 100 ) ;
01530 
01531    DSET_write( dset ) ;
01532    PLUTO_dset_redisplay( dset ) ;
01533    AFNI_process_drawnotice( im3d ) ;
01534 
01535    /*----- reset to 0 nudge -----*/
01536 
01537    rmat = undo_rmat[0] ; svec = undo_svec[0] ; NUD_setcumlab() ;
01538 
01539    /* clear undo stack */
01540 
01541    undo_nuse = undo_ntop = 1 ;
01542    SENSITIZE(undo_pb,0)  ; SENSITIZE(redo_pb,0) ;
01543 
01544    /* can't Do All again right now */
01545 
01546    SENSITIZE(doall_pb,0) ;
01547 
01548    /* allow user to change datasets again */
01549 
01550    SENSITIZE(choose_pb,1) ;
01551    AV_SENSITIZE( brick_av , (nvals > 1) ) ;
01552 
01553    if( nvals > 1 )
01554       MCW_popdown_meter(meter) ;
01555    if( nvals%2 == 1 ) MCW_invert_widget(doall_pb) ;
01556 
01557    return ;
01558 }
 

Powered by Plone

This site conforms to the following standards: