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  

SUMA_Engine.c

Go to the documentation of this file.
00001 #define DEBUG_1
00002 #ifdef DEBUG_1
00003    #define DEBUG_2
00004    #define DEBUG_3
00005 #endif
00006    
00007 /* Header FILES */
00008    
00009 #include "SUMA_suma.h"
00010 
00011 /* extern SUMA_SurfaceViewer *SUMAg_cSV; */   /* no longer used Tue Aug 13 16:07:41 EDT 2002 */
00012 extern SUMA_DO *SUMAg_DOv;   
00013 extern int SUMAg_N_DOv; 
00014 extern SUMA_CommonFields *SUMAg_CF;
00015 extern SUMA_SurfaceViewer *SUMAg_SVv;
00016 extern int SUMAg_N_SVv;
00017 
00018 /*!
00019    \brief This is the function that runs the viewers. 
00020    success = SUMA_Engine (listp);
00021    
00022    \param listp (DList **) pointer to doubly linked list pointer containing Engine commands
00023    
00024    \return success (YUP/NOPE)
00025    
00026    - *listp is destroyed just before SUMA_Engine returns and *listp is set to null
00027    - To add a new command:
00028    include it SUMA_define.h in SUMA_ENGINE_CODE's typedef
00029    include it in SUMA_ParseCommands.c, SUMA_CommandCode, SUMA_CommandString functions 
00030    - OLD Format: SUMA_Boolean SUMA_Engine (char *Command, SUMA_EngineData *EngineData, SUMA_SurfaceViewer *sv)
00031       
00032 */
00033 
00034 SUMA_Boolean SUMA_Engine (DList **listp)
00035 {
00036    static char FuncName[]={"SUMA_Engine"};
00037    char tmpcom[SUMA_MAX_COMMAND_LENGTH], sfield[100], sdestination[100];
00038    const char *NextCom;
00039    int NextComCode, ii, i, id, ND, ip, NP;
00040    SUMA_SurfaceObject *SO = NULL;
00041    float delta_t;
00042    struct  timeval tt;
00043    int it, Wait_tot, nn=0, N_SOlist, SOlist[SUMA_MAX_DISPLAYABLE_OBJECTS], iv200[200];
00044    float ft, **fm, fv15[15];
00045    XtPointer elvis=NULL;
00046    NI_element *nel;
00047    SUMA_Boolean Found;
00048    SUMA_SurfaceViewer *svi;
00049    SUMA_SurfaceViewer *sv = NULL;
00050    static char Command[]={"OBSOLETE-since:Thu Jan 23 16:55:03 EST 2003"};
00051    SUMA_EngineData *EngineData=NULL, *ED = NULL; /* EngineData is what get passed from a list element, 
00052                                                    ED is what gets added to the list inside SUMA_Engine */ 
00053    DListElmt *NextElem_CANT_TOUCH_THIS, *LocElm=NULL;
00054    DList *list= NULL;
00055    SUMA_CREATE_TEXT_SHELL_STRUCT *TextShell = NULL, *LogShell=NULL;
00056    SUMA_Boolean LocalHead = NOPE;
00057    
00058    /*int iv3[3], iv15[15], **im;
00059    float fv3[3];
00060    char s[SUMA_MAX_STRING_LENGTH];*/ /* keep standard unused variables undeclared, else compiler complains*/
00061    
00062    
00063    SUMA_ENTRY;
00064    
00065    list = *listp; /* listp is now passed instead of list so that I can set list to NULL from within this function */
00066    
00067    if (!list) {
00068       fprintf (SUMA_STDERR, "Error %s: Nothing to do.\n", FuncName);
00069       SUMA_RETURN (NOPE);
00070    }
00071    
00072    if (LocalHead) fprintf (SUMA_STDOUT,"%s: ", FuncName);
00073    while (list->size) {/* cycle through NextComs */
00074       if (LocalHead) fprintf (SUMA_STDERR,"%s: Fetching next element\n", FuncName);
00075      /* get the next command from the head of the list */
00076       NextElem_CANT_TOUCH_THIS = dlist_head(list);
00077       EngineData = (SUMA_EngineData *)NextElem_CANT_TOUCH_THIS->data;
00078       
00079       /* decide on what Srcp might be. Currently only sv is passed when the source is Suma*/
00080       sv = NULL;
00081       switch (EngineData->Src) {
00082          case SES_Suma: 
00083          case SES_SumaFromAfni:
00084          case SES_SumaWidget:
00085          case SES_SumaFromAny:
00086             sv = (SUMA_SurfaceViewer *)EngineData->Srcp;
00087          case SES_Afni:
00088             break;
00089          default:  
00090             break;
00091       } 
00092       
00093       NextComCode = EngineData->CommandCode;
00094       if (!NextComCode) {
00095          fprintf (stderr, "%s Error: Bad next element code\n", FuncName);
00096          SUMA_RETURN (NOPE);
00097       } 
00098       NextCom = SUMA_CommandString (NextComCode);
00099       if (LocalHead) fprintf (SUMA_STDERR,"->%s<-\t", NextCom);
00100       switch (NextComCode) {/* switch NextComCode */
00101          case SE_SendColorMapToAfni:
00102             /* expects in i the code of one of SUMA's standard colormaps */
00103             {
00104                SUMA_COLOR_MAP *cmap;
00105                NI_element *nel=NULL;
00106                int i;
00107                char sbuf[50], *stmp=NULL;
00108                
00109                if (EngineData->i_Dest != NextComCode ) {
00110                   fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n", \
00111                    FuncName, NextCom, NextComCode);
00112                   break;
00113                }
00114                
00115                /* get the CMAP */
00116                if (!(cmap = SUMA_GetStandardMap (EngineData->i))) {
00117                   SUMA_SLP_Err("Failed to create colormap");
00118                   break;
00119                }
00120                
00121                if (cmap->N_Col > 128) {
00122                   SUMA_SLP_Err(  "Cannot send more\n"
00123                                  "than 128 colors to\n"
00124                                  "AFNI.");
00125                   SUMA_Free_ColorMap(cmap); cmap = NULL;
00126                   break;
00127                }
00128                
00129                /* send AFNI the color map */
00130                nel = NI_new_data_element("ni_do", 0);
00131                NI_set_attribute ( nel, "ni_verb", "DRIVE_AFNI");
00132                stmp = SUMA_append_string("DEFINE_COLORSCALE ", cmap->Name);
00133                /* SEND COLORMAP In REVERSE ORDER TO AFNI,
00134                C'est la vie */
00135                for (i=cmap->N_Col-1; i >= 0; --i) {
00136                   sprintf(sbuf,"rgbi:%f/%f/%f", 
00137                            cmap->M[i][0], cmap->M[i][1], cmap->M[i][2]);
00138                   stmp = SUMA_append_replace_string(stmp, sbuf, " ", 1);
00139                }
00140                SUMA_LH(stmp);
00141                NI_set_attribute ( nel, "ni_object", stmp);
00142                
00143                /* SUMA_ShowNel(nel); */
00144                
00145                if (NI_write_element( SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] , nel, NI_BINARY_MODE ) < 0) {
00146                   SUMA_SLP_Err("Failed to send CMAP to afni");
00147                   NI_free_element(nel) ; nel = NULL;
00148                   if (stmp) SUMA_free(stmp); stmp = NULL;
00149                   SUMA_Free_ColorMap(cmap); cmap = NULL;
00150                   break;
00151                }
00152                
00153                NI_free_element(nel) ; nel = NULL;
00154                if (stmp) SUMA_free(stmp); stmp = NULL;
00155                
00156                /* Now set the colormap in AFNI */
00157                nel = NI_new_data_element("ni_do", 0);
00158                NI_set_attribute ( nel, "ni_verb", "DRIVE_AFNI");
00159                stmp = SUMA_append_string("SET_PBAR_ALL ", "A.+99");
00160                sprintf(sbuf, " 1 %s", cmap->Name);
00161                stmp = SUMA_append_replace_string(stmp, sbuf, "", 1);
00162                NI_set_attribute ( nel, "ni_object", stmp);
00163                
00164                /* SUMA_ShowNel(nel); */
00165                
00166                if (NI_write_element( SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] , nel, NI_BINARY_MODE ) < 0) {
00167                   SUMA_SLP_Err("Failed to send CMAP to afni");
00168                   NI_free_element(nel) ; nel = NULL;
00169                   if (stmp) SUMA_free(stmp); stmp = NULL;
00170                   SUMA_Free_ColorMap(cmap); cmap = NULL;
00171                   break;
00172                }
00173                
00174                NI_free_element(nel) ; nel = NULL;
00175                if (stmp) SUMA_free(stmp); stmp = NULL;
00176               
00177                /* set the autorange off */
00178                nel = NI_new_data_element("ni_do", 0);
00179                NI_set_attribute ( nel, "ni_verb", "DRIVE_AFNI");
00180                NI_set_attribute ( nel, "ni_object", "SET_FUNC_AUTORANGE A.-");
00181                if (NI_write_element( SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] , nel, NI_BINARY_MODE ) < 0) {
00182                   SUMA_SLP_Err("Failed to send CMAP to afni");
00183                   NI_free_element(nel) ; nel = NULL;
00184                   SUMA_Free_ColorMap(cmap); cmap = NULL;
00185                   break;
00186                }
00187                
00188                NI_free_element(nel) ; nel = NULL;
00189                
00190                /* set the range of the colorbar */
00191                nel = NI_new_data_element("ni_do", 0);
00192                NI_set_attribute ( nel, "ni_verb", "DRIVE_AFNI");
00193                sprintf(sbuf," %d", cmap->N_Col);
00194                stmp = SUMA_append_string("SET_FUNC_RANGE A.", sbuf);
00195                NI_set_attribute ( nel, "ni_object", stmp);
00196                if (NI_write_element( SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] , nel, NI_BINARY_MODE ) < 0) {
00197                   SUMA_SLP_Err("Failed to send CMAP to afni");
00198                   NI_free_element(nel) ; nel = NULL;
00199                   if (stmp) SUMA_free(stmp); stmp = NULL;
00200                   SUMA_Free_ColorMap(cmap); cmap = NULL;
00201                   break;
00202                }
00203                NI_free_element(nel) ; nel = NULL;
00204                if (stmp) SUMA_free(stmp); stmp = NULL;
00205                
00206                SUMA_Free_ColorMap(cmap); cmap = NULL;
00207             }
00208             break;
00209          case SE_OpenDrawnROIFileSelection:
00210             /* opens the open ROI file selection window. 
00211             Expects NULL in vp (to be used later and a position reference widget typecast to ip, the latter can be null.*/
00212             if (EngineData->vp_Dest != NextComCode || EngineData->ip_Dest != NextComCode ) {
00213                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n", \
00214                   FuncName, NextCom, NextComCode);
00215                break;
00216             }
00217             /* open the ROI file */
00218             if (!sv) sv = &(SUMAg_SVv[0]);
00219             if (!EngineData->ip) {
00220                SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialogStruct (sv->X->TOPLEVEL, SUMA_FILE_OPEN, YUP,
00221                                                         SUMA_OpenDrawnROI, (void *)EngineData->vp,
00222                                                         NULL, NULL,
00223                                                         "*.roi",
00224                                                         SUMAg_CF->X->FileSelectDlg);
00225             } else {
00226                SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialogStruct ((Widget) EngineData->ip, SUMA_FILE_OPEN, YUP,
00227                                                         SUMA_OpenDrawnROI, (void *)EngineData->vp,
00228                                                         NULL, NULL,
00229                                                         "*.roi",
00230                                                         SUMAg_CF->X->FileSelectDlg);
00231             }
00232             SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialog ("Select ROI File to Open", &SUMAg_CF->X->FileSelectDlg);
00233             break;
00234             
00235          case SE_SaveDrawnROIFileSelection:
00236             /* opens the save roi  file selection window. 
00237             Expects NULL in vp (to be used later and a position reference widget typecast to ip, the latter can be null.*/
00238             if (EngineData->vp_Dest != NextComCode || EngineData->ip_Dest != NextComCode ) {
00239                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n", \
00240                   FuncName, NextCom, NextComCode);
00241                break;
00242             }
00243             
00244             /* save ROI to file */
00245             if (!sv) sv = &(SUMAg_SVv[0]);
00246             if (!EngineData->ip) {
00247                SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialogStruct (sv->X->TOPLEVEL, SUMA_FILE_SAVE, YUP,
00248                                                         SUMA_SaveDrawnROI, (void *)EngineData->vp,
00249                                                         NULL, NULL,
00250                                                         "*.roi",
00251                                                         SUMAg_CF->X->FileSelectDlg);
00252             } else {
00253                SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialogStruct ((Widget) EngineData->ip, SUMA_FILE_SAVE, YUP,
00254                                                         SUMA_SaveDrawnROI, (void *)EngineData->vp,
00255                                                         NULL, NULL,
00256                                                         "*.roi",
00257                                                         SUMAg_CF->X->FileSelectDlg);
00258             }
00259             
00260             SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialog ("Select ROI Filename", &SUMAg_CF->X->FileSelectDlg);
00261             
00262             break;
00263 
00264          case SE_SaveSOFileSelection:
00265             /* saves a surface and its node colors to ascii files */
00266             /* expects SO in vp and a position reference widget typecast to ip, the latter can be null.*/
00267             if (EngineData->vp_Dest != NextComCode || EngineData->ip_Dest != NextComCode ) {
00268                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n", \
00269                   FuncName, NextCom, NextComCode);
00270                break;
00271             }
00272             if (!sv) sv = &(SUMAg_SVv[0]);
00273             
00274             {
00275                SUMA_SAVESO_STRUCT *SaveSO_data = NULL;
00276                
00277                SaveSO_data = (SUMA_SAVESO_STRUCT *) SUMA_malloc(sizeof(SUMA_SAVESO_STRUCT)); /* DO NOT FREE THIS POINTER,
00278                                                                                                 It is freed by the function 
00279                                                                                                 SUMA_SaveSOascii */
00280                SaveSO_data->SO = (SUMA_SurfaceObject *)EngineData->vp;
00281                SaveSO_data->sv = sv;
00282                
00283                if (!EngineData->ip) {
00284                   SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialogStruct (sv->X->TOPLEVEL, SUMA_FILE_SAVE, YUP,
00285                                                            SUMA_SaveSOascii, (void *)SaveSO_data,
00286                                                            NULL, NULL,
00287                                                            "*.1D.xyz",
00288                                                            SUMAg_CF->X->FileSelectDlg);
00289                } else {
00290                   SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialogStruct ((Widget) EngineData->ip, SUMA_FILE_SAVE, YUP,
00291                                                            SUMA_SaveSOascii, (void *)SaveSO_data,
00292                                                            NULL, NULL,
00293                                                            "*.1D.xyz",
00294                                                            SUMAg_CF->X->FileSelectDlg);
00295                }
00296 
00297                SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialog ("Select SO file prefix.", &SUMAg_CF->X->FileSelectDlg);
00298             }
00299             break;
00300             
00301          case SE_LoadSegDO:
00302             if (EngineData->ip_Dest != NextComCode ) {
00303                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n", \
00304                   FuncName, NextCom, NextComCode);
00305                break;
00306             }
00307             if (!sv) sv = &(SUMAg_SVv[0]);
00308             if (!EngineData->ip) {
00309                SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialogStruct (sv->X->TOPLEVEL, SUMA_FILE_OPEN, YUP,
00310                                                         SUMA_LoadSegDO, (void *)sv,
00311                                                         NULL, NULL,
00312                                                         "*",
00313                                                         SUMAg_CF->X->FileSelectDlg);
00314             } else {
00315                SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialogStruct ((Widget) EngineData->ip, SUMA_FILE_OPEN, YUP,
00316                                                         SUMA_LoadSegDO, (void *)sv,
00317                                                         NULL, NULL,
00318                                                         "*",
00319                                                         SUMAg_CF->X->FileSelectDlg);
00320             }
00321             SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialog ("Select Segment File", &SUMAg_CF->X->FileSelectDlg);
00322             break;
00323             
00324          case SE_LoadViewFileSelection:
00325             /* opens the view file selection window.
00326             Expects a position  reference widget typecast to ip, the latter can be null.*/
00327             
00328             if (EngineData->ip_Dest != NextComCode ) {
00329                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n", \
00330                   FuncName, NextCom, NextComCode);
00331                break;
00332             }
00333             if (!sv) sv = &(SUMAg_SVv[0]);
00334             if (!EngineData->ip) {
00335                SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialogStruct (sv->X->TOPLEVEL, SUMA_FILE_OPEN, YUP,
00336                                                         SUMA_LoadVisualState, (void *)sv,
00337                                                         NULL, NULL,
00338                                                         "*.vvs",
00339                                                         SUMAg_CF->X->FileSelectDlg);
00340             } else {
00341                SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialogStruct ((Widget) EngineData->ip, SUMA_FILE_OPEN, YUP,
00342                                                         SUMA_LoadVisualState, (void *)sv,
00343                                                         NULL, NULL,
00344                                                         "*.vvs",
00345                                                         SUMAg_CF->X->FileSelectDlg);
00346             }
00347             SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialog ("Select Viewer Settings File", &SUMAg_CF->X->FileSelectDlg);
00348             break;
00349             
00350          case SE_SaveViewFileSelection:
00351             /* opens the view file selection window.
00352             Expects a position  reference widget typecast to ip, the latter can be null.*/
00353             
00354             if (EngineData->ip_Dest != NextComCode ) {
00355                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n", \
00356                   FuncName, NextCom, NextComCode);
00357                break;
00358             }
00359             if (!sv) sv = &(SUMAg_SVv[0]);
00360             if (!EngineData->ip) {
00361                SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialogStruct (sv->X->TOPLEVEL, SUMA_FILE_SAVE, YUP,
00362                                                         SUMA_SaveVisualState, (void *)sv,
00363                                                         NULL, NULL,
00364                                                         "*.vvs",
00365                                                         SUMAg_CF->X->FileSelectDlg);
00366             } else {
00367                SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialogStruct ((Widget) EngineData->ip, SUMA_FILE_SAVE, YUP,
00368                                                         SUMA_SaveVisualState, (void *)sv,
00369                                                         NULL, NULL,
00370                                                         "*.vvs",
00371                                                         SUMAg_CF->X->FileSelectDlg);
00372             }
00373             SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialog ("Select Viewer Settings File", &SUMAg_CF->X->FileSelectDlg);
00374             break;
00375             
00376          case SE_OpenDsetFileSelection:
00377             /* opens the dataset file selection window. 
00378             Expects SO in vp and a position reference widget typecast to ip, the latter can be null.*/
00379             
00380             if (EngineData->vp_Dest != NextComCode || EngineData->ip_Dest != NextComCode ) {
00381                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n", \
00382                   FuncName, NextCom, NextComCode);
00383                break;
00384             }
00385             
00386             /*Load data from file */
00387             if (!sv) sv = &(SUMAg_SVv[0]);
00388             if (!EngineData->ip) {
00389                SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialogStruct (sv->X->TOPLEVEL, SUMA_FILE_OPEN, YUP,
00390                                                         SUMA_LoadDsetFile, (void *)EngineData->vp,
00391                                                         NULL, NULL,
00392                                                         "*.dset",
00393                                                         SUMAg_CF->X->FileSelectDlg);
00394             } else {
00395                SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialogStruct ((Widget) EngineData->ip, SUMA_FILE_OPEN, YUP,
00396                                                         SUMA_LoadDsetFile, (void *)EngineData->vp,
00397                                                         NULL, NULL,
00398                                                         "*.dset",
00399                                                         SUMAg_CF->X->FileSelectDlg);
00400             }
00401             
00402             SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialog ("Select Dset File", &SUMAg_CF->X->FileSelectDlg);
00403             
00404             break;
00405          
00406          case SE_OpenCmapFileSelection:
00407             /* opens the Cmap file selection window. 
00408             Expects SO in vp and a position reference widget typecast to ip, the latter can be null.*/
00409             
00410             if (EngineData->vp_Dest != NextComCode || EngineData->ip_Dest != NextComCode ) {
00411                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n", \
00412                   FuncName, NextCom, NextComCode);
00413                break;
00414             }
00415             
00416             /*Load colors from file */
00417             if (!sv) sv = &(SUMAg_SVv[0]);
00418             if (!EngineData->ip) {
00419                SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialogStruct (sv->X->TOPLEVEL, SUMA_FILE_OPEN, YUP,
00420                                                         SUMA_LoadCmapFile, (void *)EngineData->vp,
00421                                                         NULL, NULL,
00422                                                         "*.cmap",
00423                                                         SUMAg_CF->X->FileSelectDlg);
00424             } else {
00425                SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialogStruct ((Widget) EngineData->ip, SUMA_FILE_OPEN, YUP,
00426                                                         SUMA_LoadCmapFile, (void *)EngineData->vp,
00427                                                         NULL, NULL,
00428                                                         "*.cmap",
00429                                                         SUMAg_CF->X->FileSelectDlg);
00430             }
00431             
00432             SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialog ("Select Cmap File", &SUMAg_CF->X->FileSelectDlg);
00433             
00434             break;
00435          case SE_OpenColFileSelection:
00436             /* opens the color file selection window. 
00437             Expects SO in vp and a position reference widget typecast to ip, the latter can be null.*/
00438             
00439             if (EngineData->vp_Dest != NextComCode || EngineData->ip_Dest != NextComCode ) {
00440                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n", \
00441                   FuncName, NextCom, NextComCode);
00442                break;
00443             }
00444             
00445             /*Load colors from file */
00446             if (!sv) sv = &(SUMAg_SVv[0]);
00447             if (!EngineData->ip) {
00448                SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialogStruct (sv->X->TOPLEVEL, SUMA_FILE_OPEN, YUP,
00449                                                         SUMA_LoadColorPlaneFile, (void *)EngineData->vp,
00450                                                         NULL, NULL,
00451                                                         "*.col",
00452                                                         SUMAg_CF->X->FileSelectDlg);
00453             } else {
00454                SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialogStruct ((Widget) EngineData->ip, SUMA_FILE_OPEN, YUP,
00455                                                         SUMA_LoadColorPlaneFile, (void *)EngineData->vp,
00456                                                         NULL, NULL,
00457                                                         "*.col",
00458                                                         SUMAg_CF->X->FileSelectDlg);
00459             }
00460             
00461             SUMAg_CF->X->FileSelectDlg = SUMA_CreateFileSelectionDialog ("Select Node Color File", &SUMAg_CF->X->FileSelectDlg);
00462             
00463             break;
00464          
00465             
00466          case SE_OpenDrawROI:
00467             /* opens the DrawROI window, expects a surface viewer pointer in EngineData->Srcp*/
00468             {
00469                SUMA_DRAWN_ROI *DrawnROI=NULL;
00470                
00471                if (!sv) {
00472                   fprintf (SUMA_STDERR, "Error %s: Null sv.\n", FuncName);
00473                   SUMA_RETURN(NOPE);
00474                }   
00475                
00476                /* determine if there are ROIs being drawn on surfaces displayed here */
00477                DrawnROI = NULL;
00478                /* start with the Focus_SO */
00479                if (sv->Focus_SO_ID >= 0) {
00480                   SO = (SUMA_SurfaceObject *)SUMAg_DOv[sv->Focus_SO_ID].OP;
00481                   DrawnROI = SUMA_FetchROI_InCreation (SO, SUMAg_DOv,  SUMAg_N_DOv); 
00482                }
00483                if (!DrawnROI) { /* none found on focus surface, check other surfaces in this viewer */
00484                   N_SOlist = SUMA_RegisteredSOs(sv, SUMAg_DOv, SOlist);
00485                   if (N_SOlist) {
00486                      it = 0;
00487                      do {
00488                         DrawnROI = SUMA_FetchROI_InCreation (SO, SUMAg_DOv,  SUMAg_N_DOv);
00489                         ++it;
00490                      } while (!DrawnROI && it < N_SOlist);
00491                   }
00492                }
00493                
00494                /* call function to create ROI window */
00495                if (!SUMA_OpenDrawROIWindow (DrawnROI)) {
00496                   SUMA_RegisterMessage (SUMAg_CF->MessageList, "Failed to open Draw ROI window", FuncName, 
00497                                        SMT_Error, SMA_LogAndPopup);
00498 
00499                }
00500                break;
00501             
00502             }
00503          case SE_SetRenderMode:
00504             { /* sets the rendering mode of a surface, expects SO in vp and rendering mode in i*/
00505                SO = (SUMA_SurfaceObject *)EngineData->vp;
00506                SO->PolyMode = EngineData->i;                  
00507             }  
00508             break;
00509             
00510          case SE_UpdateLog:
00511             /* Updates the Log window if it is open */
00512             {
00513                if (SUMAg_CF->X->Log_TextShell) {
00514                   char *s = NULL;
00515                   s = SUMA_BuildMessageLog (SUMAg_CF->MessageList);
00516                   SUMAg_CF->X->Log_TextShell->CursorAtBottom = YUP;
00517                   (void) SUMA_CreateTextShell (s, "Message Log", SUMAg_CF->X->Log_TextShell);
00518                   XRaiseWindow(SUMAg_CF->X->DPY_controller1, XtWindow(SUMAg_CF->X->Log_TextShell->toplevel));
00519                   if (s) SUMA_free(s);
00520                }
00521             }
00522             break;
00523             
00524          case SE_Log:
00525             /* opens log window, needs nothing for the moment*/
00526             {
00527                char *s = NULL;
00528                if (SUMAg_CF->X->Log_TextShell) { /* just raise it */
00529                   XRaiseWindow(SUMAg_CF->X->DPY_controller1, XtWindow(SUMAg_CF->X->Log_TextShell->toplevel));
00530                   break;
00531                }else { /* create it */
00532                   s = SUMA_BuildMessageLog (SUMAg_CF->MessageList);
00533                   if (LocalHead) fprintf (SUMA_STDERR,"%s: Message string:\n%s\n", FuncName, s);
00534                   LogShell =  SUMA_CreateTextShellStruct (SUMA_Message_open, NULL, 
00535                                                           SUMA_Message_destroyed, NULL);
00536                   if (!LogShell) {
00537                      fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_CreateTextShellStruct.\n", FuncName);
00538                      break;
00539                   }
00540                   SUMAg_CF->X->Log_TextShell = SUMA_CreateTextShell(s, "SUMA log", LogShell);
00541                   SUMA_free(s);
00542                }
00543             }
00544             break;
00545             
00546          case SE_Help:
00547             /* opens help window, needs nothing for the moment*/
00548             {
00549                char *s = NULL;
00550                if (SUMAg_CF->X->Help_TextShell) { /* just raise it */
00551                      XRaiseWindow(SUMAg_CF->X->DPY_controller1, XtWindow(SUMAg_CF->X->Help_TextShell->toplevel));
00552                      break;
00553                }
00554                   
00555                s = SUMA_help_message_Info();
00556                if (!s) {
00557                   fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_help_message_Info.\n", FuncName);
00558                   break;
00559                }else {
00560                   TextShell =  SUMA_CreateTextShellStruct (SUMA_Help_open, NULL, 
00561                                                            SUMA_Help_destroyed, NULL);
00562                   if (!TextShell) {
00563                      fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_CreateTextShellStruct.\n", FuncName);
00564                      break;
00565                   }
00566                   SUMAg_CF->X->Help_TextShell = SUMA_CreateTextShell(s, "SUMA help", TextShell);
00567                   SUMA_free(s);   
00568                }
00569             }
00570             break;
00571          case SE_Help_Cmap:
00572             /* opens Cmap help window, needs Cmap in vp*/
00573             {
00574                char *s = NULL;
00575                SUMA_COLOR_MAP *Cmp;
00576                if (EngineData->vp_Dest != NextComCode) {
00577                   fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n", \
00578                      FuncName, NextCom, NextComCode);
00579                   break;
00580                } 
00581                Cmp = (SUMA_COLOR_MAP *)EngineData->vp;
00582                if (SUMAg_CF->X->Help_Cmap_TextShell) { /* just raise it */
00583                      XRaiseWindow(SUMAg_CF->X->DPY_controller1, XtWindow(SUMAg_CF->X->Help_Cmap_TextShell->toplevel));
00584                      break;
00585                }
00586                   
00587                s = SUMA_help_Cmap_message_Info(Cmp);
00588                if (!s) {
00589                   fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_help_Cmap_message_Info.\n", FuncName);
00590                   break;
00591                }else {
00592                   TextShell =  SUMA_CreateTextShellStruct (SUMA_Help_Cmap_open, NULL, 
00593                                                            SUMA_Help_Cmap_destroyed, NULL);
00594                   if (!TextShell) {
00595                      fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_CreateTextShellStruct.\n", FuncName);
00596                      break;
00597                   }
00598                   SUMAg_CF->X->Help_Cmap_TextShell = SUMA_CreateTextShell(s, "SUMA Colormap help", TextShell);
00599                   SUMA_free(s);   
00600                }
00601             }
00602             break;
00603          case SE_Load_Group:
00604             /* Does not need a sv 
00605                expects  a pointer to .spec filename in cp, 
00606                         if cp is NULL then it will look for a spec structure pointer in ip (sorry, ran out of places...) 
00607                         it will also determine if surfaces in a spec structure pointer have already been loaded from f (really, ran out of places...)
00608                         a VolumeParent name in vp,
00609                         the indices of the viewers to register the surfaces with in iv15. 
00610                         and the number of viewers specified in iv15 in i.
00611                         Surfaces are registered with all i viewers in iv15*/
00612             
00613             if (EngineData->cp_Dest != NextComCode || EngineData->vp_Dest != NextComCode 
00614                || EngineData->iv15_Dest != NextComCode || EngineData->i_Dest != NextComCode
00615                || EngineData->ip_Dest != NextComCode || EngineData->f_Dest != NextComCode) {
00616                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n%d %d %d %d %d %d\n", \
00617                   FuncName, NextCom, NextComCode, EngineData->cp_Dest, EngineData->vp_Dest, 
00618                   EngineData->iv15_Dest, EngineData->i_Dest , EngineData->ip_Dest, EngineData->f_Dest);
00619                break;
00620             } 
00621             {
00622                       SUMA_SurfSpecFile Spec;   
00623                char *VolParName = NULL, *specfilename = NULL;
00624                
00625                VolParName = (char *)EngineData->vp;
00626                specfilename = EngineData->cp;
00627                
00628                if (specfilename) {
00629                   /* Load The spec file */
00630                             if (LocalHead) fprintf (SUMA_STDERR, "%s: Reading Spec File ...\n", FuncName);
00631                   if (!SUMA_Read_SpecFile (specfilename, &Spec)) {
00632                                     fprintf(SUMA_STDERR,"Error %s: Error in SUMA_Read_SpecFile.\n", FuncName);
00633                                     exit(1);
00634                             }   
00635                } else {
00636                   if (!EngineData->ip) {
00637                      fprintf(SUMA_STDERR,"Error %s: Nothing in ip, nothing to do !\n", FuncName); exit(1);
00638                   }
00639                   Spec = *((SUMA_SurfSpecFile *)EngineData->ip); 
00640                }
00641                
00642                /* make sure only one group was read in */
00643                          if (Spec.N_Groups != 1) {
00644                                  fprintf(SUMA_STDERR,"Error %s: One and only one group of surfaces is allowed at the moment (%d found).\n", FuncName, Spec.N_Groups);
00645                                  exit(1);
00646                          }
00647 
00648                          if (!EngineData->f) {
00649                   /* load the surfaces specified in the specs file, one by one*/                        
00650                             if (LocalHead) fprintf (SUMA_STDERR, "%s: Loading Surfaces in Spec File ...\n", FuncName);
00651                             if (!SUMA_LoadSpec_eng (&Spec, SUMAg_DOv, &SUMAg_N_DOv, VolParName, 0, SUMAg_CF->DsetList)) {
00652                                     fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_LoadSpec.\n", FuncName);
00653                                     exit(1);
00654                             }
00655                }
00656                
00657                
00658                /* register the new group with SUMA */
00659                if (!SUMA_RegisterGroup(SUMAg_CF, &Spec)) {
00660                   SUMA_SL_Err("Failed to register group");
00661                   break;
00662                }
00663                
00664                     /* Register the surfaces in Spec file with the surface viewer and perform setups */
00665                     if (LocalHead) fprintf (SUMA_STDERR, "%s: Registering surfaces with surface viewers ...\n", FuncName);
00666                
00667                for (ii = 0; ii < EngineData->i; ++ii) {
00668                   if (!SUMA_SetupSVforDOs (Spec, SUMAg_DOv, SUMAg_N_DOv, &(SUMAg_SVv[EngineData->iv15[ii]]))) {
00669                                     fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_SetupSVforDOs function.\n", FuncName);
00670                                     exit(1);
00671                             }
00672                     }
00673 
00674                if (LocalHead) fprintf (SUMA_STDERR, "%s: Adding call to Home and Redisplay \n", FuncName);
00675                /* add a call to Home and a redisplay */
00676                if (!list) {
00677                   fprintf (SUMA_STDERR, "Error %s: Should not be inside SUMA_Engine: ZSS Feb 02 05.\n", FuncName);
00678                   /* list = SUMA_CreateList();*/
00679                   break;
00680                }else {
00681                   SUMA_LH("Appending to list ");
00682                }
00683                ED = SUMA_InitializeEngineListData (SE_Home_AllVisible);
00684                if (!SUMA_RegisterEngineListCommand (  list, ED, 
00685                                                       SEF_Empty, NULL, 
00686                                                       SES_Afni, NULL, NOPE, 
00687                                                       SEI_Tail, NULL )) {
00688                   fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
00689                   break;
00690                }
00691                ED = SUMA_InitializeEngineListData (SE_Redisplay_AllVisible);
00692                if (!SUMA_RegisterEngineListCommand (  list, ED, 
00693                                                       SEF_Empty, NULL, 
00694                                                       SES_Afni, NULL, NOPE, 
00695                                                       SEI_Tail, NULL )) {
00696                   fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
00697                   break;
00698                }
00699    
00700             }
00701             if (LocalHead) fprintf (SUMA_STDERR, "%s: Done in SE_Load_Spec.\n", FuncName);
00702             break;
00703             
00704          case SE_SetLookAt:
00705             /* expects a center XYZ in EngineData->fv3[0 .. 2] */
00706             if (EngineData->fv3_Dest != NextComCode) {
00707                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n",FuncName, NextCom, NextComCode);
00708                break;
00709             }
00710             /* calculate the transform required to bring the new look at location to the current one */
00711             {
00712                float ulook_old[3], ulook_new[3];
00713                int Step = 10, iStep;
00714                float fracUp, fracDown;
00715               
00716                ulook_old[0] = sv->GVS[sv->StdView].ViewFrom[0] - sv->GVS[sv->StdView].ViewCenter[0];
00717                ulook_old[1] = sv->GVS[sv->StdView].ViewFrom[1] - sv->GVS[sv->StdView].ViewCenter[1];
00718                ulook_old[2] = sv->GVS[sv->StdView].ViewFrom[2] - sv->GVS[sv->StdView].ViewCenter[2];
00719                ulook_new[0] = ulook_new[1] = ulook_new[2] = 0.0;
00720                fm = (float **)SUMA_allocate2D(4,4,sizeof(float));
00721                
00722                for (iStep = Step; iStep >= 1; --iStep) {
00723                   fracUp = (float)(iStep)/(float)Step;
00724                   fracDown = (float)(Step - iStep)/(float)Step;
00725                   if (LocalHead) fprintf (SUMA_STDERR,"%s:%d, fracUp %f, fracDown %f, fv3[%f %f %f]\n", 
00726                                  FuncName, iStep, fracUp, fracDown, EngineData->fv3[0], 
00727                                  EngineData->fv3[1], EngineData->fv3[2]);
00728                   ulook_new[0] = (EngineData->fv3[0] * fracUp + sv->GVS[sv->StdView].ViewFrom[0] * fracDown) \
00729                                  - sv->GVS[sv->StdView].ViewCenter[0];
00730                   ulook_new[1] = (EngineData->fv3[1] * fracUp + sv->GVS[sv->StdView].ViewFrom[1] * fracDown) \
00731                                  - sv->GVS[sv->StdView].ViewCenter[1];
00732                   ulook_new[2] = (EngineData->fv3[2] * fracUp + sv->GVS[sv->StdView].ViewFrom[2] * fracDown) \
00733                                  - sv->GVS[sv->StdView].ViewCenter[2];
00734                   if (fm == NULL) {
00735                      fprintf (SUMA_STDERR,"Error %s: Failed to allocate fm.\n",FuncName);
00736                      break;
00737                   }
00738                   if (!SUMA_FromToRotation (ulook_new, ulook_old, fm)) {
00739                      fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_FromToRotation.\n",FuncName);
00740                      break;
00741                   }
00742                   
00743                   /* add a SetRotMatrix to list*/
00744                   ED = SUMA_InitializeEngineListData (SE_SetRotMatrix);
00745                   ED->N_cols = 4;
00746                   ED->N_rows = 4;
00747                   if (!(LocElm = SUMA_RegisterEngineListCommand (  list, ED, 
00748                                                          SEF_fm, (void *)fm, 
00749                                                          EngineData->Src, EngineData->Srcp, NOPE, 
00750                                                          SEI_Head, NULL ))) {
00751                      fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
00752                      break;
00753                   }
00754                                     
00755                   /* add a redisplay call */
00756                   ED = SUMA_InitializeEngineListData (SE_RedisplayNow);
00757                   if (!SUMA_RegisterEngineListCommand (  list, ED, 
00758                                                          SEF_Empty, NULL, 
00759                                                          EngineData->Src, EngineData->Srcp, NOPE, 
00760                                                          SEI_After, LocElm )) {
00761                      fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
00762                      break;
00763                   }
00764                   
00765                }
00766                /* fm was copied into engine data, free it */
00767                SUMA_free2D((char **)fm, 4);
00768             }
00769             break;
00770          
00771          case SE_StartListening:
00772             /* expects nothing in EngineData */
00773             if (!SUMAg_CF->Listening) {
00774                SUMAg_CF->Listening = !SUMAg_CF->Listening;
00775                fprintf(SUMA_STDERR,"%s: Starting to listen ...\n", FuncName);
00776                /* start the listening WorkProcess */
00777                if (!SUMAg_CF->niml_work_on) {
00778                   SUMA_LH("registering SUMA_niml_workproc...");
00779                   SUMA_register_workproc(SUMA_niml_workproc, (XtPointer)sv);
00780                } else {
00781                   SUMA_LH("SUMA_niml_workproc Already on.");
00782                }
00783             } else {
00784                /* if already on, just close streams */
00785                /* closing the streams */
00786                fprintf(SUMA_STDERR,"%s: Closing streams, but still listening ...\n", FuncName);
00787                /* kill the streams */
00788                for (ii=0; ii< SUMA_MAX_STREAMS; ++ii) {
00789                   if (ii != SUMA_AFNI_STREAM_INDEX) {  /* leave AFNI connection separate */
00790                      NI_stream_close( SUMAg_CF->ns_v[ii] ) ;
00791                      SUMAg_CF->ns_v[ii] = NULL ;
00792                      SUMAg_CF->ns_flags_v[ii] = 0;
00793                      SUMAg_CF->TrackingId_v[ii] = 0;
00794                   }
00795                }
00796             } 
00797             break;
00798             
00799          case SE_ToggleConnected:
00800             /* expects nothing in EngineData */
00801             if (!SUMA_CanTalkToAfni (SUMAg_DOv, SUMAg_N_DOv)) {
00802                fprintf(SUMA_STDOUT,"%s: Cannot connect to AFNI.\n\tNot one of the surfaces is mappable and has a Surface Volume.\n\tDid you use the -sv option when launching SUMA ?\n", FuncName);
00803                break;
00804             }
00805                
00806             SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] = !SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX];
00807             if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX]) {
00808                if (!SUMA_niml_call (SUMAg_CF, SUMA_AFNI_STREAM_INDEX, YUP)) {
00809                   /* conection flag is reset in SUMA_niml_call */
00810                   break;
00811                }
00812                   
00813                /* start the listening WorkProcess */
00814                if (!SUMAg_CF->niml_work_on) {
00815                   SUMA_LH("registering SUMA_niml_workproc...");
00816                   SUMA_register_workproc(SUMA_niml_workproc, (XtPointer)sv); 
00817                } else {
00818                   SUMA_LH("SUMA_niml_workproc Already on.");
00819                }
00820 
00821                /* register a call for sending the surface to afni (SetAfniSurf)*/
00822                if (LocalHead) fprintf(SUMA_STDERR,"Notifying Afni of New surface...\n");
00823                ED = SUMA_InitializeEngineListData (SE_SetAfniSurf);
00824                SUMA_RegisterEngineListCommand (list, ED, 
00825                                                 SEF_Empty, NULL,
00826                                                 SES_Suma, (void *)sv, NOPE,
00827                                                 SEI_Head, NULL); 
00828                break;
00829             } else {
00830                fprintf(SUMA_STDOUT,"%s: Disconnecting from afni.\n", FuncName);
00831 
00832                if (!SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX]) {
00833                   /* It looks like the stream was closed, do the clean up */
00834                   fprintf(SUMA_STDERR,"Warning %s: sv->ns is null, stream must have gotten closed. Cleaning up ...\n", FuncName);
00835                   ED = SUMA_InitializeEngineListData (SE_CloseStream4All);
00836                   ii = SUMA_AFNI_STREAM_INDEX;
00837                   SUMA_RegisterEngineListCommand (list, ED, 
00838                                                 SEF_i, (void*)&ii,
00839                                                 SES_Suma, (void *)sv, NOPE,
00840                                                 SEI_Head, NULL); 
00841 
00842                   break;
00843                }
00844 
00845 
00846                /* Close the stream if nobody else wants it. 
00847                This is not a great condition, one should be able to leave the stream open 
00848                even if no viewer, for the moment, does not want to talk to AFNI.
00849                Perhaps in the future. */
00850                if (SUMAg_N_SVv == 1) {
00851                   fprintf(SUMA_STDERR,"%s: Nobody wants to talk to AFNI anymore, closing stream ...\n", FuncName);
00852                   NI_stream_close(SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX]);
00853                   SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] = NULL;
00854                   SUMAg_CF->ns_flags_v[SUMA_AFNI_STREAM_INDEX] = 0;
00855                   SUMAg_CF->TrackingId_v[SUMA_AFNI_STREAM_INDEX] = 0;
00856                }
00857                break;
00858             }
00859    
00860          case SE_CloseStream4All:
00861             /* expects the stream index in i in EngineData */
00862             if (EngineData->i_Dest != NextComCode) {
00863                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n",FuncName, NextCom, NextComCode);
00864                break;
00865             }   
00866             /* odds are communicating program died or closed stream, mark all surfaces as unsent */
00867             if (EngineData->i == SUMA_AFNI_STREAM_INDEX) {
00868                for (ii=0; ii<SUMAg_N_DOv; ++ii) {
00869                   if (SUMA_isSO(SUMAg_DOv[ii])) {
00870                      SO = (SUMA_SurfaceObject *)(SUMAg_DOv[ii].OP);
00871                      if (SO->SentToAfni) SO->SentToAfni = NOPE;
00872                   }
00873                }
00874             }
00875             
00876             /* same for parent fields */
00877             /* check first if stream in SUMAg_CF still good by any chance */
00878             nn = NI_stream_goodcheck(SUMAg_CF->ns_v[EngineData->i] , 1 ) ;
00879             
00880             if( nn >= 0 ){ 
00881                fprintf(stderr,"Error %s: Stream still alive, this should not be. Closing anyway.\n", FuncName); 
00882                NI_stream_close(SUMAg_CF->ns_v[EngineData->i]); 
00883             }
00884             
00885             /* clean up and get out of here*/         
00886             SUMAg_CF->ns_v[EngineData->i] = NULL;
00887             SUMAg_CF->ns_flags_v[EngineData->i] = 0;
00888             SUMAg_CF->TrackingId_v[EngineData->i] = 0;
00889  
00890             break;
00891             
00892          case SE_SetForceAfniSurf:
00893             /* expects nothing in EngineData */
00894             /* send to afni surfaces that can be sent even if they have been sent already */
00895             #if 0 /* pre Oct 26 */
00896             for (ii=0; ii<sv->N_DO; ++ii) {
00897                if (SUMA_isSO(SUMAg_DOv[sv->RegisteredDO[ii]])) {
00898                   SO = (SUMA_SurfaceObject *)(SUMAg_DOv[sv->RegisteredDO[ii]].OP);
00899                   if (SO->SentToAfni) SO->SentToAfni = NOPE;
00900                }
00901             }
00902             #else
00903                /* send all geometrically correct surfaces */
00904                for (ii=0; ii<SUMAg_N_DOv; ++ii) {
00905                   if (SUMA_isSO(SUMAg_DOv[ii])) {
00906                      SO = (SUMA_SurfaceObject *)(SUMAg_DOv[ii].OP);
00907                      if (SO->AnatCorrect && SO->SentToAfni) SO->SentToAfni = NOPE;
00908                   }
00909                }
00910             #endif
00911             /* proceed to SE_SetAfniSurf: */
00912             ED = SUMA_InitializeEngineListData (SE_SetAfniSurf);
00913             SUMA_RegisterEngineListCommand (list, ED, 
00914                                             SEF_Empty, NULL,
00915                                             SES_Suma, (void *)sv, NOPE,
00916                                             SEI_Head, NULL); 
00917             break;
00918             
00919          case SE_SetAfniSurfList:
00920             /* expects ivec in EngineData and a string in s saying what is to be sent, a flag in i 1=report transmission, 0 = be quiet*/
00921             { int nels_sent, N_Send, *SendList;
00922                
00923                if (EngineData->ivec_Dest != NextComCode || EngineData->s_Dest != NextComCode || EngineData->i_Dest != NextComCode) {
00924                   fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n",FuncName, NextCom, NextComCode);
00925                   break;
00926                }
00927                N_Send = EngineData->ivec->n;
00928                SendList = EngineData->ivec->v; 
00929                /* send to afni the list of surfaces in SendList*/
00930                if (N_Send) {
00931                   for (ii=0; ii<N_Send; ++ii) {
00932                      nels_sent = 0;
00933                      SO = (SUMA_SurfaceObject *)(SUMAg_DOv[SendList[ii]].OP);
00934                      if (EngineData->i && SO->Label) fprintf(SUMA_STDERR,"%s: Sending surface %s (%s)...\n", FuncName, SO->Label, EngineData->s);
00935                      if (SUMA_iswordin(EngineData->s,"NodeList") == 1) {
00936                         nel = SUMA_makeNI_SurfIXYZ (SO);
00937                         if (!nel) {
00938                            fprintf(SUMA_STDERR,"Error %s: SUMA_makeNI_SurfIXYZ failed\n", FuncName);
00939                            break;
00940                         }
00941                         /* send surface nel */
00942                         if (LocalHead) fprintf(SUMA_STDERR,"%s: Sending SURF_iXYZ nel...\n ", FuncName) ;
00943                         nn = NI_write_element( SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] , nel , NI_BINARY_MODE ) ;
00944 
00945                         if( nn < 0 ){
00946                              fprintf(SUMA_STDERR,"Error %s: NI_write_element failed\n", FuncName);
00947                         }
00948 
00949                         #if 0
00950                            {
00951                               NI_stream nstdout;
00952                                nstdout = NI_stream_open( "fd:1","w");
00953                                 if( nstdout == NULL ){ fprintf(SUMA_STDERR,"Can't open fd:1\n"); break; }
00954                                  NI_write_element( nstdout , nel , NI_TEXT_MODE ) ;
00955                                NI_stream_close(nstdout);
00956                            }
00957                         #endif
00958 
00959                         NI_free_element(nel);
00960                         nel = NULL;
00961                         ++nels_sent;
00962                      }
00963                      if (SUMA_iswordin(EngineData->s,"NodeNormList") == 1) {
00964                         /* send node normals       ZSS Oct 05 04 */
00965                         nel = SUMA_makeNI_SurfINORM (SO);
00966                         if (!nel) {
00967                            fprintf(SUMA_STDERR,"Error %s: SUMA_makeNI_SurfINORM failed\n", FuncName);
00968                            break;
00969                         }
00970                         /* send surface nel */
00971                         if (LocalHead) fprintf(SUMA_STDERR,"%s: Sending SURF_NORM nel ...\n", FuncName) ;
00972                         nn = NI_write_element( SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] , nel , NI_BINARY_MODE ) ;
00973 
00974                         if( nn < 0 ){
00975                              fprintf(SUMA_STDERR,"Error %s: NI_write_element failed\n", FuncName);
00976                         }
00977                         NI_free_element(nel);
00978                         nel = NULL;
00979                         ++nels_sent;
00980                      }
00981                      
00982                      if (SUMA_iswordin(EngineData->s,"FaceSetList") == 1) {
00983                         /* send triangles */
00984                         nel = SUMA_makeNI_SurfIJK (SO);
00985                         if (!nel) {
00986                            fprintf(SUMA_STDERR,"Error %s: SUMA_makeNI_SurfIJK failed\n", FuncName);
00987                            break;
00988                         }
00989                         /* send surface nel */
00990                         if (LocalHead) fprintf(SUMA_STDERR,"%s: Sending SURF_IJK nel ...\n", FuncName) ;
00991                         nn = NI_write_element( SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] , nel , NI_BINARY_MODE ) ;
00992 
00993                         if( nn < 0 ){
00994                              fprintf(SUMA_STDERR,"Error %s: NI_write_element failed\n", FuncName);
00995                         }
00996                         NI_free_element(nel);
00997                         nel = NULL;
00998                         ++nels_sent;
00999                      }
01000                      if (nels_sent) {
01001                         /* mark surface as sent to afni */
01002                         SO->SentToAfni = YUP;
01003                      } else {
01004                         SUMA_SL_Warn("Nothing sent dude, what's happening?");
01005                      }
01006                   }
01007                }
01008 
01009                break;
01010             }
01011             
01012          case SE_SetAfniSurf:
01013             /* expects nothing in EngineData */
01014             {  int N_Send, *SendList, ti=1;
01015                SUMA_IVEC ivec;
01016                /* send to afni the list of anatomically correct surfaces and with a surface volume*/
01017                /* No surfaces are sent twice because there should not be duplicate 
01018                local domain parent surfaces in SUMAg_DOv */
01019                /* prior to Wed Nov  6 17:47:20 EST 2002, only mappable surfaces that are related to the ones shown in the viewer
01020                were being sent to AFNI. Now all mappable surfaces loaded are sent regardless of what is shown */
01021                /* Jan. 08 04: All anatomically correct surfaces are now sent to AFNI */
01022                SendList = SUMA_FormSOListToSendToAFNI(SUMAg_DOv , SUMAg_N_DOv, &N_Send);
01023                if (N_Send) {
01024                   ivec.v = SendList;
01025                   ivec.n = N_Send;
01026                   ED = SUMA_InitializeEngineListData (SE_SetAfniSurfList);
01027                   if (!(LocElm = SUMA_RegisterEngineListCommand (  list, ED,
01028                                                          SEF_ivec, (void *)(&ivec), 
01029                                                          SES_Suma, (void *)sv, NOPE, 
01030                                                          SEI_Tail, NULL))) {
01031                      fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
01032                      break;
01033                   }
01034                   if (!(LocElm = SUMA_RegisterEngineListCommand (  list, ED,
01035                                                          SEF_s, (void *)("NodeList, FaceSetList, NodeNormList"), 
01036                                                          SES_Suma, (void *)sv, NOPE, 
01037                                                          SEI_In, LocElm))) {
01038                      fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
01039                      break;
01040                   }
01041                   if (!(LocElm = SUMA_RegisterEngineListCommand (  list, ED,
01042                                                          SEF_i, (void *)&ti, 
01043                                                          SES_Suma, (void *)sv, NOPE, 
01044                                                          SEI_In, LocElm))) {
01045                      fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
01046                      break;
01047                   }
01048                   if (SendList) SUMA_free(SendList); SendList = NULL;   
01049                }
01050 
01051                break;
01052             }
01053          
01054          case SE_SetAfniThisSurf:
01055             /* expects an idcode_str in EngineData->cp and what needs to be sent in EngineData->s for surface to be sent to AFNI */
01056             {
01057                SUMA_IVEC ivec;
01058                if (EngineData->s_Dest != NextComCode || EngineData->cp_Dest != NextComCode || EngineData->i_Dest != NextComCode) {
01059                   fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s ((%d %d %d) %d).\n",
01060                      FuncName, NextCom,  EngineData->s_Dest, EngineData->cp_Dest, EngineData->i_Dest, NextComCode);
01061                   break;
01062                }
01063                i = SUMA_findSO_inDOv(EngineData->cp, SUMAg_DOv, SUMAg_N_DOv);
01064                if (i<0) {
01065                   SUMA_SL_Err("Surface Not Found!");
01066                   break;
01067                }
01068                ivec.n = 1;
01069                ivec.v = (int*)SUMA_malloc(ivec.n*sizeof(int));
01070                ivec.v[0] = i;
01071                ED = SUMA_InitializeEngineListData (SE_SetAfniSurfList);
01072                if (!(LocElm = SUMA_RegisterEngineListCommand (  list, ED,
01073                                                       SEF_ivec, (void *)(&ivec), 
01074                                                       SES_Suma, (void *)sv, NOPE, 
01075                                                       SEI_Tail, NULL))) {
01076                   fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
01077                   break;
01078                }
01079                if (!(LocElm = SUMA_RegisterEngineListCommand (  list, ED,
01080                                                       SEF_s, (void *)(EngineData->s), 
01081                                                       SES_Suma, (void *)sv, NOPE, 
01082                                                       SEI_In, LocElm))) {
01083                   fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
01084                   break;
01085                }
01086                if (!(LocElm = SUMA_RegisterEngineListCommand (  list, ED,
01087                                                          SEF_i, (void *)&(EngineData->i), 
01088                                                          SES_Suma, (void *)sv, NOPE, 
01089                                                          SEI_In, LocElm))) {
01090                   fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
01091                   break;
01092                }
01093                SUMA_free(ivec.v);
01094                break;
01095             }
01096                
01097          case SE_ToggleShowSelectedNode:
01098             /* expects nothing in EngineData */
01099             {
01100                int CommonState = -1;
01101                
01102                for (ii=0; ii<sv->N_DO; ++ii) {
01103                   if (SUMA_isSO(SUMAg_DOv[sv->RegisteredDO[ii]])) {
01104                      if (CommonState < 0) {
01105                         SO = (SUMA_SurfaceObject *)(SUMAg_DOv[sv->RegisteredDO[ii]].OP);
01106                         SO->ShowSelectedNode = !SO->ShowSelectedNode;
01107                         CommonState = SO->ShowSelectedNode;
01108                         fprintf(SUMA_STDOUT,"SO->ShowSelectedNode = %d\n", SO->ShowSelectedNode);
01109                      } else {
01110                         SO->ShowSelectedNode = CommonState;
01111                      }
01112                   }
01113                 
01114                }
01115             
01116             XmToggleButtonSetState (sv->X->ViewMenu[SW_ViewNodeInFocus], 
01117                   CommonState, NOPE); 
01118                 
01119             }
01120             break;
01121          
01122          case SE_SetSelectedNode:
01123             /* expects a node index in i */
01124             if (EngineData->i_Dest != NextComCode) {
01125                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n",FuncName, NextCom, NextComCode);
01126                break;
01127             } 
01128             SO = (SUMA_SurfaceObject *)(SUMAg_DOv[sv->Focus_SO_ID].OP);
01129             if (EngineData->i >= 0 && EngineData->i < SO->N_Node) {
01130                SO->SelectedNode = EngineData->i;
01131             } else {
01132                /* ignore -1, used in initializations */
01133                if (EngineData->i != -1) { SUMA_SLP_Err("Node index < 0 || > Number of nodes in surface"); }
01134                break;
01135             }
01136             SUMA_UpdateNodeField(SO);
01137             break;
01138             
01139          case SE_ToggleShowSelectedFaceSet:
01140             /* expects nothing ! */
01141             { int CommonState = -1;
01142                for (ii=0; ii<sv->N_DO; ++ii) {
01143                   if (SUMA_isSO(SUMAg_DOv[sv->RegisteredDO[ii]])) {
01144                      SO = (SUMA_SurfaceObject *)(SUMAg_DOv[sv->RegisteredDO[ii]].OP);
01145                      if (CommonState < 0) { /* first surface, set the common state */
01146                         SO->ShowSelectedFaceSet = !SO->ShowSelectedFaceSet;
01147                         CommonState = SO->ShowSelectedFaceSet;
01148                         fprintf(SUMA_STDOUT,"SO->ShowSelectedFaceSet = %d\n", \
01149                            SO->ShowSelectedFaceSet);
01150                       }else {
01151                         SO->ShowSelectedFaceSet = CommonState;
01152                      }
01153                   }
01154                }
01155             XmToggleButtonSetState (sv->X->ViewMenu[SW_ViewSelectedFaceset], 
01156                   CommonState, NOPE);  
01157             }          
01158             break;
01159          
01160          case SE_SetSelectedFaceSet:
01161             /* expects the index for the selected FaceSet */
01162             if (EngineData->i_Dest != NextComCode) {
01163                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n",FuncName, NextCom, NextComCode);
01164                break;
01165             } 
01166             SO = (SUMA_SurfaceObject *)(SUMAg_DOv[sv->Focus_SO_ID].OP);
01167             if (EngineData->i < 0 || EngineData->i >= SO->N_FaceSet) {
01168                if (EngineData->i != -1) { /* ignore -1, used in initialization */
01169                   SUMA_SLP_Err("Node index < 0 || > Number of FaceSets in surface");
01170                } 
01171                break;
01172             }
01173             ND = SO->NodeDim;
01174             NP = SO->FaceSetDim;
01175             ip = NP * EngineData->i;
01176             id = ND * SO->FaceSetList[ip];
01177             SO->FaceSetMarker->n0[0] = SO->NodeList[id];
01178             SO->FaceSetMarker->n0[1] = SO->NodeList[id+1];
01179             SO->FaceSetMarker->n0[2] = SO->NodeList[id+2];
01180             id = ND * SO->FaceSetList[ip+1];
01181             SO->FaceSetMarker->n1[0] = SO->NodeList[id];
01182             SO->FaceSetMarker->n1[1] = SO->NodeList[id+1];
01183             SO->FaceSetMarker->n1[2] = SO->NodeList[id+2];
01184             id = ND * SO->FaceSetList[ip+2];
01185             SO->FaceSetMarker->n2[0] = SO->NodeList[id];
01186             SO->FaceSetMarker->n2[1] = SO->NodeList[id+1];
01187             SO->FaceSetMarker->n2[2] = SO->NodeList[id+2];
01188             SO->FaceSetMarker->NormVect[0] = SO->FaceNormList[ip];
01189             SO->FaceSetMarker->NormVect[1] = SO->FaceNormList[ip+1];
01190             SO->FaceSetMarker->NormVect[2] = SO->FaceNormList[ip+2];
01191             
01192             SO->SelectedFaceSet = EngineData->i;
01193             SUMA_UpdateTriField(SO);
01194             break;
01195             
01196          case SE_ToggleCrossHair:
01197             /* expects nothing in EngineData */
01198             sv->ShowCrossHair = !sv->ShowCrossHair;
01199             XmToggleButtonSetState (sv->X->ViewMenu[SW_ViewCrossHair], 
01200                sv->ShowCrossHair, NOPE);            
01201             break;
01202             
01203          case SE_SetCrossHair:
01204             /* Expects Cross Hair coordinates in fv3 */
01205             if (EngineData->fv3_Dest != NextComCode) {
01206                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n",FuncName, NextCom, NextComCode);
01207                break;
01208             }
01209             if (LocalHead) fprintf(SUMA_STDERR,"%s: Setting cross hair at %f %f %f\n", FuncName, EngineData->fv3[0], EngineData->fv3[1],EngineData-> fv3[2]);
01210             sv->Ch->c[0] = EngineData->fv3[0]; sv->Ch->c[1]= EngineData->fv3[1]; sv->Ch->c[2]= EngineData->fv3[2];
01211             /* Attempt to update crosshair corrdinates in open surface controllers */
01212             SUMA_UpdateXhairField(sv); 
01213             break;
01214          
01215          case SE_BindCrossHair:
01216             /* expects SurfaceID to bind cross hair to*/
01217             if (EngineData->iv3_Dest != NextComCode) {
01218                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n",FuncName, NextCom, NextComCode);
01219                break;
01220             }
01221             sv->Ch->SurfaceID = EngineData->iv3[0];
01222             sv->Ch->NodeID = EngineData->iv3[1];
01223             
01224             break;
01225          
01226          case SE_SetSOinFocus:
01227             /* expects surface ID in i */
01228             if (EngineData->i_Dest != NextComCode) {
01229                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n",FuncName, NextCom, NextComCode);
01230                break;
01231             }
01232             if (sv->Focus_SO_ID != EngineData->i) {
01233                /* a new one, update */
01234                sv->Focus_SO_ID = EngineData->i;
01235                SUMA_UpdateViewerTitle(sv);
01236            }
01237             break;
01238             
01239          case SE_ToggleLockView:
01240             /* expects index of viewer in i to toggle its lock view */
01241             /* toggles the lock view button */
01242             if (EngineData->i_Dest != NextComCode) {
01243                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n",FuncName, NextCom, NextComCode);
01244                break;
01245             }
01246             SUMAg_CF->ViewLocked[EngineData->i] = !SUMAg_CF->ViewLocked[EngineData->i];
01247             /* update button if needed*/
01248             if (EngineData->Src != SES_SumaWidget) {
01249                XmToggleButtonSetState (SUMAg_CF->X->SumaCont->LockView_tbg[EngineData->i], SUMAg_CF->ViewLocked[EngineData->i], NOPE);
01250             }
01251             
01252             /* call function to update the AllLock button */
01253             SUMA_set_LockView_atb ();
01254             
01255             break;
01256          
01257          case SE_ToggleLockAllViews:
01258             /* expects nothing, toggles all locked view buttons */
01259             
01260             /* get the current value of the button */
01261             {
01262                SUMA_Boolean CurState;
01263                CurState = XmToggleButtonGetState (SUMAg_CF->X->SumaCont->LockAllView_tb);
01264                for (ii=0; ii< SUMA_MAX_SURF_VIEWERS; ++ii) { /* set all buttons accrodingly */
01265                   XmToggleButtonSetState (SUMAg_CF->X->SumaCont->LockView_tbg[ii], CurState, NOPE);
01266                   SUMAg_CF->ViewLocked[ii] = CurState;
01267                }
01268             }
01269             break;
01270          
01271          case SE_ToggleLockAllCrossHair:
01272             /* expects nothing, toggles cross hair lock for all viewers */
01273             {
01274                char LockName[100];
01275                SUMA_LockEnum_LockType (SUMAg_CF->Locked[0], LockName);
01276                fprintf (SUMA_STDERR,"%s: Switching Locktype from %s", FuncName, LockName);
01277                /* change the locking type of viewer 0 */
01278                SUMAg_CF->Locked[0] = (int)fmod(SUMAg_CF->Locked[0]+1, SUMA_N_Lock_Types);
01279                SUMA_LockEnum_LockType (SUMAg_CF->Locked[0], LockName);
01280                fprintf (SUMA_STDERR," %s\n", LockName);
01281                /* update the widget*/
01282                SUMA_set_Lock_rb (SUMAg_CF->X->SumaCont->Lock_rbg, 0, SUMAg_CF->Locked[0]);
01283                /* Change the locking type of all remaining viewers, including unopen ones */
01284                for (ii=1; ii< SUMA_MAX_SURF_VIEWERS; ++ii) {
01285                   SUMAg_CF->Locked[ii] = SUMAg_CF->Locked[0];                  
01286                   SUMA_set_Lock_rb (SUMAg_CF->X->SumaCont->Lock_rbg, ii, SUMAg_CF->Locked[ii]);
01287                }
01288 
01289                /* now update the all lock keys */
01290                SUMA_set_Lock_arb (SUMAg_CF->X->SumaCont->Lock_rbg);
01291 
01292             }
01293             break;
01294          
01295          case SE_SetLockAllCrossHair:
01296             /* expects a Lock value in i , sets the lock of all viewers */
01297             if (EngineData->i_Dest != NextComCode) {
01298                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n",FuncName, NextCom, NextComCode);
01299                break;
01300             }
01301             {
01302                
01303                /* Change the locking type of all remaining viewers, including unopen ones */
01304                for (ii=0; ii< SUMA_MAX_SURF_VIEWERS; ++ii) {
01305                   SUMAg_CF->Locked[ii] = EngineData->i;                  
01306                   SUMA_set_Lock_rb (SUMAg_CF->X->SumaCont->Lock_rbg, ii, SUMAg_CF->Locked[ii]);
01307                }
01308 
01309                /* now update the all lock keys */
01310                SUMA_set_Lock_arb (SUMAg_CF->X->SumaCont->Lock_rbg);
01311             }
01312             break;
01313             
01314          case SE_LockCrossHair:
01315             /* expects nothing in EngineData */
01316 
01317             /* calls other viewers and determine if the cross hair needs to be locked to the calling sv */
01318 
01319             /* check to see if other viewers need to share the fate */
01320             ii = SUMA_WhichSV(sv, SUMAg_SVv, SUMAg_N_SVv);
01321             if (ii < 0) {
01322                fprintf (SUMA_STDERR,"Error %s: Failed to find index of sv.\n", FuncName);
01323                break;
01324             }
01325             if (SUMAg_CF->Locked[ii]) { /* This one's locked, find out which other viewers are locked to this one */
01326                for (i=0; i < SUMAg_N_SVv; ++i) {
01327                   svi = &SUMAg_SVv[i];
01328                   if (i != ii) {
01329                      switch (SUMAg_CF->Locked[i]) { 
01330                         case SUMA_No_Lock:
01331                            if (LocalHead) fprintf (SUMA_STDERR, "%s: No lock for viewer %d.\n", FuncName, i);
01332                            break;
01333                         case SUMA_XYZ_Lock:
01334                            if (LocalHead) fprintf (SUMA_STDERR, "%s: Try to XYZ lock viewer %d.\n", FuncName, i);
01335                            /* just set the XYZ, and free the binding to the surfaces */
01336                            svi->Ch->c[0] = sv->Ch->c[0];
01337                            svi->Ch->c[1] = sv->Ch->c[1];
01338                            svi->Ch->c[2] = sv->Ch->c[2];
01339                            svi->Ch->NodeID = -1;
01340                            svi->Ch->SurfaceID = -1;
01341                            /* FORCE a redisplay */
01342                            svi->ResetGLStateVariables = YUP;
01343                            SUMA_handleRedisplay((XtPointer)svi->X->GLXAREA);                           
01344                            break;
01345                         case SUMA_I_Lock: 
01346                            {
01347                               SUMA_SurfaceObject *SO1 = NULL, *SO2 = NULL;
01348                               
01349                               if (LocalHead) fprintf (SUMA_STDERR, "%s: Try to I lock viewer %d to node %d.\n", FuncName, i, sv->Ch->NodeID);
01350                               
01351                               /* determine the list of shown surfaces */
01352                               N_SOlist = SUMA_RegisteredSOs(svi, SUMAg_DOv, SOlist);
01353 
01354                               /* first find the surface that the cross hair is bound to */
01355                               if (sv->Ch->SurfaceID < 0) {
01356                                  fprintf (SUMA_STDERR, "%s: Cannot link from this viewer's cross hair. No bound surface.\n", FuncName);
01357                                  break;
01358                               }
01359                               if (sv->Ch->NodeID < 0) {
01360                                  fprintf (SUMA_STDERR, "%s: Cannot link from this viewer's cross hair. No NodeID.\n", FuncName);
01361                                  break;
01362                               }
01363                               SO1 = (SUMA_SurfaceObject *)SUMAg_DOv[sv->Ch->SurfaceID].OP;
01364                               Found = NOPE;
01365                               it = 0;
01366                               while (it < N_SOlist && !Found) {
01367                                  SO2 = (SUMA_SurfaceObject *)SUMAg_DOv[SOlist[it]].OP;
01368                                  if (SUMA_isRelated (SO1, SO2, 2)) { /* high level relationship is allowed */
01369                                     svi->Ch->SurfaceID = SOlist[it];
01370                                     if (sv->Ch->NodeID > SO2->N_Node) {
01371                                        fprintf (SUMA_STDERR,"Error %s: NodeID is larger than N_Node. Setting NodeID to 0.\n", FuncName);
01372                                        svi->Ch->NodeID = 0;
01373                                     }else{
01374                                        svi->Ch->NodeID = sv->Ch->NodeID;
01375                                     }
01376                                     
01377                                     /* set the XYZ */
01378                                     svi->Ch->c[0] = SO2->NodeList[SO2->NodeDim*svi->Ch->NodeID];
01379                                     svi->Ch->c[1] = SO2->NodeList[SO2->NodeDim*svi->Ch->NodeID+1];
01380                                     svi->Ch->c[2] = SO2->NodeList[SO2->NodeDim*svi->Ch->NodeID+2];
01381                                     fprintf (SUMA_STDERR,"%s: new XYZ %f %f %f\n", FuncName, 
01382                                        svi->Ch->c[0], svi->Ch->c[1], svi->Ch->c[2]); 
01383                                     Found = YUP;
01384                                  }
01385                                  ++it;
01386                               }
01387                               if (!Found) {
01388                                  if (LocalHead) fprintf (SUMA_STDERR,"%s: No related surfaces found in viewer, cross hair will not be touched .\n", FuncName);
01389                                  break;
01390                               } else {
01391                                  /* FORCE a redisplay */
01392                                  svi->ResetGLStateVariables = YUP;
01393                                  SUMA_handleRedisplay((XtPointer)svi->X->GLXAREA);
01394                               }
01395                               
01396                            }
01397                            break;
01398                         default:
01399                            fprintf(SUMA_STDERR,"Error %s: Lock type (%d) undefined.\n", FuncName, SUMAg_CF->Locked[ii]);
01400                            break;
01401                      }
01402                   }
01403                }
01404             }else{
01405                /* not locked to anything */
01406             }
01407             break;
01408                         
01409          case SE_SetAfniCrossHair:
01410             /* expects nothing in EngineData */
01411             /* sends the current cross hair to afni */
01412             /* form nel */
01413             nel = SUMA_makeNI_CrossHair (sv);
01414             if (!nel) {
01415                fprintf(SUMA_STDERR,"Error %s: SUMA_makeNI_CrossHair failed\n", FuncName);
01416                break;
01417                }
01418             /*send it to afni */
01419             /*fprintf(SUMA_STDERR,"Sending cross hair nel ") ;*/
01420             nn = NI_write_element( SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] , nel , NI_TEXT_MODE ) ;
01421             /*SUMA_nel_stdout (nel);*/
01422       
01423             if( nn < 0 ){
01424                    fprintf(SUMA_STDERR,"Error %s: NI_write_element failed\n", FuncName);
01425             }
01426             
01427             NI_free_element(nel);
01428 
01429             break;
01430                   
01431          case SE_SetLookAtNode:
01432             /* expects a center XYZ in EngineData->fv15[0 .. 2]
01433             expects a normal vector in EngineData->fv15[3 .. 5] */
01434             if (EngineData->fv15_Dest != NextComCode) {
01435                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n",FuncName, NextCom, NextComCode);
01436                break;
01437             } 
01438             
01439             { float CurrentDistance;
01440               float fm2_3[2][3], *dir;
01441               
01442             /* modify the ViewFrom Value such that the viewing distance remains the same */
01443             CurrentDistance = sqrt((sv->GVS[sv->StdView].ViewFrom[0]-sv->GVS[sv->StdView].ViewCenter[0])*(sv->GVS[sv->StdView].ViewFrom[0]-sv->GVS[sv->StdView].ViewCenter[0]) +\
01444                                     (sv->GVS[sv->StdView].ViewFrom[1]-sv->GVS[sv->StdView].ViewCenter[1])*(sv->GVS[sv->StdView].ViewFrom[1]-sv->GVS[sv->StdView].ViewCenter[1]) +\
01445                                     (sv->GVS[sv->StdView].ViewFrom[2]-sv->GVS[sv->StdView].ViewCenter[2])*(sv->GVS[sv->StdView].ViewFrom[2]-sv->GVS[sv->StdView].ViewCenter[2]));
01446             
01447             /* set the ViewCenter Value to that of the node's XYZ*/
01448             sv->GVS[sv->StdView].ViewCenter[0] = EngineData->fv15[0];
01449             sv->GVS[sv->StdView].ViewCenter[1] = EngineData->fv15[1]; 
01450             sv->GVS[sv->StdView].ViewCenter[2] = EngineData->fv15[2];
01451             
01452             /* obtain the LookFrom point based on CurrentDistance and the normal vector */
01453             dir = &(EngineData->fv15[3]);
01454             SUMA_POINT_AT_DISTANCE(dir, sv->GVS[sv->StdView].ViewCenter, CurrentDistance, fm2_3);
01455             
01456             fprintf(SUMA_STDOUT,"\nPoints: %f %f %f\n%f %f %f\n", \
01457                fm2_3[0][0], fm2_3[0][1], fm2_3[0][2], \
01458                fm2_3[1][0], fm2_3[1][1], fm2_3[1][2]);
01459             
01460             sv->GVS[sv->StdView].ViewFrom[0] = fm2_3[0][0]; 
01461             sv->GVS[sv->StdView].ViewFrom[1] = fm2_3[0][1]; 
01462             sv->GVS[sv->StdView].ViewFrom[2] = fm2_3[0][2]; 
01463                         
01464             gluLookAt (sv->GVS[sv->StdView].ViewFrom[0], sv->GVS[sv->StdView].ViewFrom[1], sv->GVS[sv->StdView].ViewFrom[2], sv->GVS[sv->StdView].ViewCenter[0], sv->GVS[sv->StdView].ViewCenter[1], sv->GVS[sv->StdView].ViewCenter[2], sv->GVS[sv->StdView].ViewCamUp[0], sv->GVS[sv->StdView].ViewCamUp[1], sv->GVS[sv->StdView].ViewCamUp[2]);
01465             }
01466             
01467             break;
01468          case SE_SetLookFrom:
01469             /* expects a center XYZ in EngineData->fv3[0 .. 2] */
01470             if (EngineData->fv3_Dest != NextComCode) {
01471                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n",FuncName, NextCom, NextComCode);
01472                break;
01473             } 
01474             /* set the LookFrom option */
01475             sv->GVS[sv->StdView].ViewFrom[0] = EngineData->fv3[0];
01476             sv->GVS[sv->StdView].ViewFrom[1] = EngineData->fv3[1]; 
01477             sv->GVS[sv->StdView].ViewFrom[2] = EngineData->fv3[2];
01478             gluLookAt (sv->GVS[sv->StdView].ViewFrom[0], sv->GVS[sv->StdView].ViewFrom[1], sv->GVS[sv->StdView].ViewFrom[2], sv->GVS[sv->StdView].ViewCenter[0], sv->GVS[sv->StdView].ViewCenter[1], sv->GVS[sv->StdView].ViewCenter[2], sv->GVS[sv->StdView].ViewCamUp[0], sv->GVS[sv->StdView].ViewCamUp[1], sv->GVS[sv->StdView].ViewCamUp[2]);
01479             break;
01480 
01481          case SE_Redisplay_AllVisible:
01482             /* expects nothing in EngineData */
01483             /* post a redisplay to all visible viewers */
01484             for (ii=0; ii<SUMAg_N_SVv; ++ii) {
01485                if (LocalHead) fprintf (SUMA_STDERR,"%s: Checking viewer %d.\n", FuncName, ii);
01486                if (!SUMAg_SVv[ii].isShaded && SUMAg_SVv[ii].X->TOPLEVEL) {
01487                   /* you must check for both conditions because by default 
01488                   all viewers are initialized to isShaded = NOPE, even before they are ever opened */
01489                   if (LocalHead) fprintf (SUMA_STDERR,"%s: Redisplaying viewer %d.\n", FuncName, ii);
01490                   SUMAg_SVv[ii].ResetGLStateVariables = YUP;
01491                   SUMA_postRedisplay(SUMAg_SVv[ii].X->GLXAREA, NULL, NULL);
01492                }
01493             }
01494             break;
01495             
01496          
01497          case SE_Redisplay:
01498             /* expects nothing in EngineData */
01499             /*post a redisplay to one specific viewer*/
01500             if (LocalHead) fprintf (SUMA_STDOUT,"%s: Redisplay ...", FuncName);
01501             SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
01502             if (LocalHead) fprintf (SUMA_STDOUT," Done\n");
01503             break;
01504          
01505          case SE_RedisplayNow:
01506             /* expects nothing in EngineData */
01507             /*call handle redisplay immediately to one specific viewer*/
01508             if (LocalHead) fprintf (SUMA_STDOUT,"%s: Redisplaying NOW ...", FuncName);
01509             sv->ResetGLStateVariables = YUP;
01510             SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
01511             if (LocalHead) fprintf (SUMA_STDOUT," Done\n");
01512             break;
01513             
01514          case SE_RedisplayNow_AllVisible:
01515             /* expects nothing in EngineData */
01516             /* causes  an immediate redisplay to all visible viewers */
01517             for (ii=0; ii<SUMAg_N_SVv; ++ii) {
01518                if (LocalHead) fprintf (SUMA_STDERR,"%s: Checking viewer %d.\n", FuncName, ii);
01519                if (!SUMAg_SVv[ii].isShaded && SUMAg_SVv[ii].X->TOPLEVEL) {
01520                   /* you must check for both conditions because by default 
01521                   all viewers are initialized to isShaded = NOPE, even before they are ever opened */
01522                   if (LocalHead) fprintf (SUMA_STDERR,"%s: Redisplaying viewer %d.\n", FuncName, ii);
01523                   SUMAg_SVv[ii].ResetGLStateVariables = YUP;
01524                   SUMA_handleRedisplay((XtPointer)SUMAg_SVv[ii].X->GLXAREA);
01525                }
01526             }
01527             break;
01528          
01529          case SE_RedisplayNow_AllOtherVisible:
01530             /* expects nothing in EngineData, expects sv in srcp*/
01531             /* causes an immediate redisplay to all visible viewers other than sv*/
01532             for (ii=0; ii<SUMAg_N_SVv; ++ii) {
01533                if (LocalHead) fprintf (SUMA_STDERR,"%s: Checking viewer %d.\n", FuncName, ii);
01534                if (!SUMAg_SVv[ii].isShaded && SUMAg_SVv[ii].X->TOPLEVEL && &(SUMAg_SVv[ii]) != sv) {
01535                   /* you must check for both conditions because by default 
01536                   all viewers are initialized to isShaded = NOPE, even before they are ever opened */
01537                   if (LocalHead) fprintf (SUMA_STDERR,"%s: Redisplaying viewer %d.\n", FuncName, ii);
01538                   SUMAg_SVv[ii].ResetGLStateVariables = YUP;
01539                   SUMA_handleRedisplay((XtPointer)SUMAg_SVv[ii].X->GLXAREA);
01540                }
01541             }
01542             break;
01543 
01544          case SE_ResetOpenGLState:
01545             /* reset OPEN GL's state variables */
01546             /* expects the surface viewer pointer in vp */
01547             if (EngineData->vp_Dest != NextComCode) {
01548                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n",FuncName, NextCom, NextComCode);
01549                break;
01550             } 
01551             if (LocalHead) fprintf (SUMA_STDOUT,"%s: Resetting OpenGL state variables.\n", FuncName);
01552             
01553             /* No need to call SUMA_OpenGLStateReset, that is now done in SUMA_display */
01554             svi = (SUMA_SurfaceViewer *)EngineData->vp;
01555             svi->ResetGLStateVariables = YUP;
01556             break;
01557             
01558          case SE_ToggleForeground:
01559             /* expects nothing in EngineData */
01560             /* Show/hide the foreground */
01561             sv->ShowForeground = !sv->ShowForeground;
01562             if (!sv->ShowForeground) {
01563                fprintf(SUMA_STDOUT,"%s: Foreground Colors Off.\n", FuncName);
01564             } else {
01565                fprintf(SUMA_STDOUT,"%s: Foreground Colors ON.\n", FuncName);
01566             }
01567             /* set the color remix flag */
01568             if (!SUMA_SetShownLocalRemixFlag (sv)) {
01569                fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_SetShownLocalRemixFlag.\n", FuncName);
01570                break;
01571             }
01572             break;
01573          
01574          case SE_ToggleBackground:
01575             /* expects nothing in EngineData */
01576             /* Show/hide the background */
01577             sv->ShowBackground = !sv->ShowBackground;
01578             if (!sv->ShowBackground) {
01579                fprintf(SUMA_STDOUT,"%s: Background Colors OFF.\n", FuncName);
01580             } else {
01581                fprintf(SUMA_STDOUT,"%s: Background Colors ON.\n", FuncName);
01582             }
01583             /* set the color remix flag */
01584             if (!SUMA_SetShownLocalRemixFlag (sv)) {
01585                fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_SetShownLocalRemixFlag.\n", FuncName);
01586                break;
01587             }
01588             break;
01589                      
01590          case SE_Home:
01591             /* expects nothing in EngineData, needs sv */
01592             sv->GVS[sv->StdView].translateVec[0]=0; sv->GVS[sv->StdView].translateVec[1]=0;
01593             glMatrixMode(GL_PROJECTION);
01594             /* sv->FOV[sv->iState] = FOV_INITIAL;   *//* Now done in SE_FOVreset *//* reset the zooming */
01595             sv->GVS[sv->StdView].ViewFrom[0] = sv->GVS[sv->StdView].ViewFromOrig[0];
01596             sv->GVS[sv->StdView].ViewFrom[1] = sv->GVS[sv->StdView].ViewFromOrig[1];
01597             sv->GVS[sv->StdView].ViewFrom[2] = sv->GVS[sv->StdView].ViewFromOrig[2];
01598             sv->GVS[sv->StdView].ViewCenter[0] = sv->GVS[sv->StdView].ViewCenterOrig[0];
01599             sv->GVS[sv->StdView].ViewCenter[1] = sv->GVS[sv->StdView].ViewCenterOrig[1];
01600             sv->GVS[sv->StdView].ViewCenter[2] = sv->GVS[sv->StdView].ViewCenterOrig[2];
01601             
01602             glMatrixMode(GL_MODELVIEW);
01603             glLoadIdentity();
01604             gluLookAt (sv->GVS[sv->StdView].ViewFrom[0], sv->GVS[sv->StdView].ViewFrom[1], sv->GVS[sv->StdView].ViewFrom[2], sv->GVS[sv->StdView].ViewCenter[0], sv->GVS[sv->StdView].ViewCenter[1], sv->GVS[sv->StdView].ViewCenter[2], sv->GVS[sv->StdView].ViewCamUp[0], sv->GVS[sv->StdView].ViewCamUp[1], sv->GVS[sv->StdView].ViewCamUp[2]);
01605             break;
01606          
01607          case SE_Home_AllVisible:
01608             /* expects nothing in EngineData, needs no sv */
01609             {
01610                for (ii=0; ii<SUMAg_N_SVv; ++ii) {
01611                   if (LocalHead) fprintf (SUMA_STDERR,"%s: Checking viewer %d.\n", FuncName, ii);
01612                   if (!SUMAg_SVv[ii].isShaded && SUMAg_SVv[ii].X->TOPLEVEL) {
01613                      /* you must check for both conditions because by default 
01614                      all viewers are initialized to isShaded = NOPE, even before they are ever opened */
01615                      if (LocalHead) fprintf (SUMA_STDERR,"%s: Home call viewer %d.\n", FuncName, ii);
01616                      if (!list) {
01617                         fprintf (SUMA_STDERR, "Error %s: Should not be inside SUMA_Engine: ZSS Feb 02 05.\n", FuncName);
01618                         /* list = SUMA_CreateList();*/
01619                         break;
01620                      }
01621                      SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Home, SES_Suma, &SUMAg_SVv[ii]);
01622                   }
01623                }
01624             }
01625             break;
01626          
01627          case SE_FOVreset:
01628             /* expects nothing in EngineData */
01629             sv->FOV[sv->iState] = FOV_INITIAL;   /* reset the zooming */
01630             break;
01631             
01632          case SE_SetNodeColor:
01633             /* expects a four-columned fm in EngineData->fm[0 .. N][0..3] 
01634             [Node Index] [R] [G] [B] RGB between 0 and 1*/
01635             if (EngineData->fm_Dest != NextComCode) {
01636                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n",FuncName, NextCom, NextComCode);
01637                break;
01638             }
01639             SO = (SUMA_SurfaceObject *)(SUMAg_DOv[sv->Focus_SO_ID].OP);
01640             {
01641                GLfloat *glar_ColorList;
01642                glar_ColorList = SUMA_GetColorList(sv, SO->idcode_str);
01643                if (!glar_ColorList) {
01644                   fprintf (SUMA_STDERR,"Error %s: NULL color list array. Trouble.\n", FuncName);
01645                   break;
01646                }
01647                for (i=0; i < EngineData->N_rows; ++i){
01648                   ii = (int)(EngineData->fm[i][0]);
01649                   glar_ColorList[4*ii] = EngineData->fm[i][1];
01650                   glar_ColorList[4*ii+1] = EngineData->fm[i][2];
01651                   glar_ColorList[4*ii+2] = EngineData->fm[i][3];
01652                   glar_ColorList[4*ii+3] = 0.5;
01653                }
01654             }
01655             break;
01656             
01657          case SE_FlipLight0Pos:
01658             /* expects nothing in EngineData */
01659             sv->light0_position[0] *= -1;
01660             sv->light0_position[1] *= -1;
01661             sv->light0_position[2] *= -1;
01662             glLightfv(GL_LIGHT0, GL_POSITION, sv->light0_position);
01663             break;
01664          
01665          case SE_SetLight0Pos:
01666             /* expects light XYZ position in fv[3] */
01667             if (EngineData->fv3_Dest != NextComCode) {
01668                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n",FuncName, NextCom, NextComCode);
01669                break;
01670             }
01671             sv->light0_position[0] = EngineData->fv3[0];
01672             sv->light0_position[1] = EngineData->fv3[1];
01673             sv->light0_position[2] = EngineData->fv3[2];
01674             glLightfv(GL_LIGHT0, GL_POSITION, sv->light0_position);
01675             break;
01676             
01677          case SE_HighlightNodes:
01678             /* highlight nodes inside the search box */
01679             /* expects Node XYZ in EngineData->fv15[0..2]
01680             Box dimensions in EngineData->fv15[3..5] */
01681             if (EngineData->fv15_Dest != NextComCode) {
01682                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n",FuncName, NextCom, NextComCode);
01683                break;
01684             }
01685             {
01686                SUMA_ISINBOX IB;
01687                
01688                SO = (SUMA_SurfaceObject *)(SUMAg_DOv[sv->Focus_SO_ID].OP);
01689                ND = SO->NodeDim;
01690             
01691                SUMA_etime (&tt, 0);
01692                IB = SUMA_isinbox (SO->NodeList, SO->N_Node, &(EngineData->fv15[0]), &(EngineData->fv15[3]),  YUP);
01693                delta_t = SUMA_etime (&tt, 1);
01694                fprintf (SUMA_STDOUT,"Elapsed time for isinbox operation: %f\n", delta_t);
01695                fprintf (SUMA_STDOUT,"\t%d nodes (out of %d) found in box\n",IB.nIsIn, SO->N_Node);
01696                
01697                if (IB.nIsIn) { /* found some, find the closest node */
01698                   /* locate the closest node and store it's id in EngineData*/
01699                   SUMA_MIN_LOC_VEC (IB.d, IB.nIsIn, ft, it);
01700                   
01701                   /* XYZ and normal of the closest to the center */
01702                   #ifdef STUFF
01703                      /* This is not being used and if it is to be used, EngineData should 
01704                      not be set manually */
01705                      id = ND * IB.IsIn[it];
01706                      EngineData->fv15[0] = SO->NodeList[id];
01707                      EngineData->fv15[1] = SO->NodeList[id+1];
01708                      EngineData->fv15[2] = SO->NodeList[id+2];
01709                      EngineData->fv15[3] = SO->NodeNormList[id];
01710                      EngineData->fv15[4] = SO->NodeNormList[id+1];
01711                      EngineData->fv15[5] = SO->NodeNormList[id+2];
01712                   #endif
01713                   /* Color the nodes*/
01714                   fm = (float **)SUMA_allocate2D(IB.nIsIn, 4, sizeof(float));
01715                   if (fm == NULL) {
01716                      fprintf(SUMA_STDERR,"Error %s: Could not allocate for fm.\n", FuncName);
01717                      break;
01718                   }
01719                   for (i=0; i < IB.nIsIn; ++i) {
01720                       /* id = ND * IB.IsIn[i]; */
01721                       /*fprintf (SUMA_STDOUT,"\t[%d] %f %f %f\n", IB.IsIn[i] ,\
01722                                    SO->NodeList[id], SO->NodeList[id+1], SO->NodeList[id+2]);*/
01723                      /* color those nodes in yellow, just for kicks */
01724                      fm[i][0] = (float)IB.IsIn[i];
01725                      fm[i][1] = 0; 
01726                      fm[i][2] = 0.4;
01727                      fm[i][3] = 0.4; 
01728                   }
01729 
01730                   /* Place a call to Redisplay and SetNodeColor */
01731                   ED = SUMA_InitializeEngineListData (SE_SetNodeColor);
01732                   ED->N_cols = 4;
01733                   ED->N_rows = IB.nIsIn;
01734                   if (!SUMA_RegisterEngineListCommand (  list, ED, 
01735                                                          SEF_fm, (void*)fm,
01736                                                          SES_Suma, (void *)sv, NOPE,
01737                                                          SEI_Head, NULL)) {
01738                      fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
01739                      break;                                      
01740                   } 
01741                   ED = SUMA_InitializeEngineListData (SE_Redisplay);
01742                   SUMA_RegisterEngineListCommand (  list, ED, 
01743                                                     SEF_Empty, NULL,
01744                                                     SES_Suma, (void *)sv, NOPE, 
01745                                                     SEI_Head, NULL);
01746 
01747                   /* free fm since it was copied to EngineData*/
01748                   if (fm) SUMA_free2D ((char **)fm, IB.nIsIn);
01749                   
01750                   /* get ridd of IB's vectors */
01751                   if (!SUMA_Free_IsInBox (&IB)) {
01752                      fprintf(SUMA_STDERR,"Error %s: Failed to free IB\n", FuncName);
01753                   }
01754                } else { /* no node is close enough */
01755                   /* Do nothing yet */
01756                   fprintf (SUMA_STDOUT,"\nNo nodes found inside the specified box.\n");
01757                }
01758             }
01759             break;
01760 
01761          case SE_GetNearestNode:
01762             /* lookfor nodes inside the search box */
01763             /* expects Node XYZ in EngineData->fv15[0..2]
01764             Box dimensions in EngineData->fv15[3..5] */
01765             if (EngineData->fv15_Dest != NextComCode) {
01766                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n",FuncName, NextCom, NextComCode);
01767                break;
01768             }
01769             {
01770                SUMA_ISINBOX IB;
01771                
01772                SO = (SUMA_SurfaceObject *)(SUMAg_DOv[sv->Focus_SO_ID].OP);
01773                ND = SO->NodeDim;
01774                SUMA_etime (&tt, 0);
01775                IB = SUMA_isinbox (SO->NodeList, SO->N_Node, &(EngineData->fv15[0]), &(EngineData->fv15[3]),  YUP);
01776                delta_t = SUMA_etime (&tt, 1);
01777                fprintf (SUMA_STDOUT,"Elapsed time for isinbox operation: %f\n", delta_t);
01778                fprintf (SUMA_STDOUT,"\t%d nodes (out of %d) found in box\n",IB.nIsIn, SO->N_Node);
01779                
01780                if (IB.nIsIn) { /* found some, find the closest node */
01781                   /* locate the closest node and store it's id in EngineData*/
01782                   SUMA_MIN_LOC_VEC (IB.d, IB.nIsIn, ft, it);
01783                   
01784                   /* get the XYZ and normal of that node */
01785                   id = ND * IB.IsIn[it];
01786                   fv15[0] = SO->NodeList[id];
01787                   fv15[1] = SO->NodeList[id+1];
01788                   fv15[2] = SO->NodeList[id+2];
01789                   fv15[3] = SO->NodeNormList[id];
01790                   fv15[4] = SO->NodeNormList[id+1];
01791                   fv15[5] = SO->NodeNormList[id+2];
01792                   
01793                   ED = SUMA_InitializeEngineListData (SE_SetLookAtNode);
01794                   if (!SUMA_RegisterEngineListCommand (  list, ED,
01795                                                          SEF_fv15, (void *)fv15, 
01796                                                          SES_Suma, (void *)sv, NOPE, 
01797                                                          SEI_Head, NULL)) {
01798                      fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
01799                      break;
01800                   }
01801                   
01802                   /* get ridd of IB's vectors */
01803                   if (!SUMA_Free_IsInBox (&IB)) {
01804                      fprintf(SUMA_STDERR,"Error %s: Failed to free IB\n", FuncName);
01805                   }
01806                } else { /* no node is close enough */
01807                   /* Do nothing yet */
01808                }
01809             }
01810             break;
01811             
01812          case SE_SetRotMatrix:
01813             /* expects a rotation matrix in fm, 4x4 */
01814             /* takes the rotation matrix 3x3 with 0 in 4th row and column and 1.0 at 4,4 
01815             makes a quaternion from it and sets csv->currentQuat and posts redisplay */
01816             if (EngineData->fm_Dest != NextComCode) {
01817                fprintf (SUMA_STDERR,"Error %s: Data not destined correctly for %s (%d).\n",FuncName, NextCom, NextComCode);
01818                break;
01819             }
01820             if (EngineData->N_rows != 4 || EngineData->N_cols != 4) {
01821                fprintf(SUMA_STDERR,"Error %s: fm must have 4 cols and 4 rows in SetRotMatrix\n", FuncName);
01822                break;
01823             }
01824             if (!SUMA_mattoquat (EngineData->fm, sv->GVS[sv->StdView].currentQuat))
01825                {
01826                   fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_mattoquat\n", FuncName);
01827                   break;
01828                }
01829             break;
01830             
01831          /*case SE_Something:
01832             break;*/
01833 
01834          case SE_BadCode:
01835             fprintf(SUMA_STDERR,"Error SUMA_Engine: Command ->%s<- Not understood. Perhaps Code is not defined in SUMA_CommandCode\n", NextCom);
01836             break;
01837          
01838       } /* switch NextComCode */
01839       
01840       /* release used Element */
01841       if (LocalHead) fprintf (SUMA_STDERR, "\n%s: Releasing Engine Element.\n", FuncName);
01842       if (!SUMA_ReleaseEngineListElement (list, NextElem_CANT_TOUCH_THIS)) {
01843             fprintf(SUMA_STDERR,"Error SUMA_Engine: Failed to Release element \n");
01844          }
01845          
01846    } /* cycle through NextCom */
01847    
01848    if (LocalHead) fprintf (SUMA_STDERR, "\n%s: Destroying List.\n", FuncName);
01849    /* If you get here, all is well, destroy the list since it is empty*/
01850    list = SUMA_DestroyList (list);
01851    *listp = NULL; 
01852    
01853    SUMA_RETURN (YUP);
01854 }
01855 
01856 /*!
01857    ans = SUMA_RegisteredSOs (sv, dov, SO_IDs);
01858    gets the IDs (indices into dov) and number of the Surface Objects shown in sv
01859    \param sv (SUMA_SurfaceViewer *) the surface viewer structure
01860    \param dov (SUMA_DO *) the Displayable Objects vector (accessible to sv)
01861    \param SO_IDs (int *) pre-allocated integer vector that will contain the IDs of the SO shown in sv
01862          send NULL if you do not care for it and all you'll get is ans
01863    \ret ans (int) the number of SOs shown in SV
01864    Still confused ? read the code for the function, it is shorter than the documentation.
01865 */
01866 int SUMA_RegisteredSOs (SUMA_SurfaceViewer *sv, SUMA_DO *dov, int *SO_IDs)
01867 {
01868    static char FuncName[]={"SUMA_RegisteredSOs"};
01869    int i, k = 0;
01870    
01871    SUMA_ENTRY;
01872 
01873    for (i=0; i< sv->N_DO; ++i) {
01874       if (SUMA_isSO_G(dov[sv->RegisteredDO[i]], sv->CurGroupName)) {
01875          if (SO_IDs != NULL) SO_IDs[k] = sv->RegisteredDO[i];
01876          ++k;
01877       }
01878    }
01879 
01880    SUMA_RETURN (k);
01881 }
01882 /*!
01883    ans = SUMA_VisibleSOs (sv, dov, SO_IDs);
01884    gets the IDs (indices into dov) and number of the Surface Objects 
01885          registered with sv and with the SO->Side matching sv->ShowRight/
01886          sv->ShowLeft and with SO->Show set to YUP
01887    \param sv (SUMA_SurfaceViewer *) the surface viewer structure
01888    \param dov (SUMA_DO *) the Displayable Objects vector (accessible to sv)
01889    \param SO_IDs (int *) pre-allocated integer vector that will contain the IDs of the SO shown in sv
01890          send NULL if you do not care for it and all you'll get is ans
01891    \ret ans (int) the number of SOs shown in SV
01892    Still confused ? read the code for the function, it is shorter than the documentation.
01893    
01894    \sa SUMA_isVisibleSO
01895 */
01896 int SUMA_VisibleSOs (SUMA_SurfaceViewer *sv, SUMA_DO *dov, int *SO_IDs)
01897 {
01898    static char FuncName[]={"SUMA_VisibleSOs"};
01899    SUMA_SurfaceObject *SO=NULL;
01900    int i, k = 0;
01901    
01902    SUMA_ENTRY;
01903 
01904    for (i=0; i< sv->N_DO; ++i) {
01905       if (SUMA_isSO_G(dov[sv->RegisteredDO[i]], sv->CurGroupName)) {
01906          SO = (SUMA_SurfaceObject *)dov[sv->RegisteredDO[i]].OP;
01907          if (SO->Show) {
01908             if ( SO->Side == SUMA_NO_SIDE || SO->Side == SUMA_SIDE_ERROR ) {
01909                if (SO_IDs) {
01910                   SO_IDs[k] = sv->RegisteredDO[i];
01911                }
01912                ++k;
01913             } else if (  (SO->Side == SUMA_RIGHT && sv->ShowRight) || 
01914                          (SO->Side == SUMA_LEFT && sv->ShowLeft) ) {
01915                if (SO_IDs) {
01916                   SO_IDs[k] = sv->RegisteredDO[i];
01917                }
01918                ++k;
01919             }
01920          }
01921       }
01922    }
01923 
01924    SUMA_RETURN (k);
01925 }
01926 
01927 /*!
01928    \brief YUP if surface is visible in a viewer
01929    \sa SUMA_VisibleSOs 
01930 */
01931 SUMA_Boolean SUMA_isVisibleSO (SUMA_SurfaceViewer *sv, SUMA_DO *dov, SUMA_SurfaceObject *curSO)
01932 {
01933    static char FuncName[]={"SUMA_isVisibleSO"};
01934    SUMA_SurfaceObject *SO=NULL;
01935    int i, k = 0;
01936    
01937    SUMA_ENTRY;
01938    
01939    for (i=0; i< sv->N_DO; ++i) {
01940       if (SUMA_isSO_G(dov[sv->RegisteredDO[i]], sv->CurGroupName)) {
01941          SO = (SUMA_SurfaceObject *)dov[sv->RegisteredDO[i]].OP;
01942          if (curSO == SO) {
01943             if (SO->Show) {
01944                if ( SO->Side == SUMA_NO_SIDE || SO->Side == SUMA_SIDE_ERROR ) {
01945                   SUMA_RETURN(YUP);
01946                   ++k;
01947                } else if (  (SO->Side == SUMA_RIGHT && sv->ShowRight) || 
01948                             (SO->Side == SUMA_LEFT && sv->ShowLeft) ) {
01949                   SUMA_RETURN(YUP);
01950                   ++k;
01951                }
01952             }
01953          }
01954       }
01955    }
01956    
01957    SUMA_RETURN(NOPE);
01958    
01959 }
01960 /*! 
01961    nxtState = SUMA_NextState(sv);
01962 
01963    get the next Viewing State available in sv
01964    \param sv (SUMA_SurfaceViewer *) pointer to surface viewer structure 
01965    \ret nxtState (int) the index into sv->VSv of the next state
01966       -1 if there is trouble
01967       icur is returned if there is no next state of the group sv->CurGroupName
01968    \sa SUMA_PrevState 
01969 */
01970 int SUMA_NextState(SUMA_SurfaceViewer *sv)
01971 {
01972    static char FuncName[] = {"SUMA_NextState"};
01973    int inxt, icur;
01974    SUMA_Boolean LocalHead = NOPE;
01975    
01976    SUMA_ENTRY;
01977    
01978    icur = SUMA_WhichState (sv->State, sv, sv->CurGroupName);
01979    if (icur < 0) {
01980       fprintf(SUMA_STDERR,"Error %s: SUMA_WhichState failed.\n", FuncName);
01981       SUMA_RETURN (-1);
01982    } else {
01983       inxt = (icur + 1) % sv->N_VSv;
01984       do {
01985          /* Now see if the upcoming one is of the same group */
01986          if (inxt == icur) {
01987             /* back where we started */
01988             SUMA_RETURN(inxt);
01989          } else {
01990             if (!strcmp(sv->VSv[inxt].Group, sv->CurGroupName)) { /* group match, good, go back */
01991                SUMA_RETURN(inxt);
01992             }
01993          }
01994          inxt = (inxt + 1) % sv->N_VSv;
01995       } while (1);
01996    }
01997    
01998    /* should not get here */
01999    SUMA_SL_Err("Flow error");
02000    SUMA_RETURN (-1);
02001 }
02002 
02003 /*!
02004    precState = SUMA_PreviState (sv);
02005    get the previous Viewing State available in sv
02006    \sa SUMA_NextState
02007 */
02008 int SUMA_PrevState(SUMA_SurfaceViewer *sv)
02009 {
02010    static char FuncName[] = {"SUMA_PrevState"};
02011    int inxt, icur;
02012    SUMA_Boolean LocalHead = NOPE;
02013    
02014    SUMA_ENTRY;
02015    
02016    icur = SUMA_WhichState (sv->State, sv, sv->CurGroupName);   
02017    if (icur < 0) {
02018       fprintf(SUMA_STDERR,"Error %s: SUMA_WhichState failed.\n", FuncName);
02019       SUMA_RETURN (-1);
02020    } else {
02021       inxt = icur -1; if (inxt < 0) inxt = sv->N_VSv + inxt;
02022       do {
02023          /* Now see if the upcoming one is of the same group */
02024          if (inxt == icur) {
02025             /* back where we started */
02026             SUMA_RETURN(inxt);
02027          } else {
02028             if (!strcmp(sv->VSv[inxt].Group, sv->CurGroupName)) { /* group match, good, go back */
02029                SUMA_RETURN(inxt);
02030             }
02031          }
02032          inxt = inxt -1; if (inxt < 0) inxt = sv->N_VSv + inxt;
02033       } while (1);
02034    }
02035    
02036    SUMA_RETURN (-1);
02037 }
02038 
02039 
02040 
02041 /*!
02042    SOnxtID = SUMA_NextSO (dov, n_dov, CurrentIDcode, SOnxt);
02043    Get the next Surface Object in DOv
02044    \param dov (SUMA_DO *) vector containing all displayable objects
02045    \param n_dov (int) number of elements in dov
02046    \param CurrentIDcode (char *) idcode of current surface
02047    \param SOnxt (SUMA_SurfaceObject *) pointer to next surface object 
02048    \ret SOnxtID (int) index into dov of SOnxt (-1) if there's an error
02049 */
02050 
02051 int SUMA_NextSO (SUMA_DO *dov, int n_dov, char *idcode, SUMA_SurfaceObject *SOnxt)
02052 {
02053    static char FuncName[] = {"SUMA_NextSO"};
02054    int icur, icheck, ncheck;
02055 
02056    SUMA_ENTRY;
02057 
02058    if (SOnxt != NULL) {
02059       fprintf(SUMA_STDERR,"Error %s: SOnxt should be null when you call this function.\n", FuncName);
02060       SUMA_RETURN (-1);
02061    }
02062    if (n_dov < 1) {
02063       fprintf(SUMA_STDERR,"Error %s: dov contains no elements.\n", FuncName);
02064       SUMA_RETURN (-1);
02065    }
02066    icur = SUMA_findSO_inDOv (idcode, dov, n_dov);
02067    if (icur < 0) {
02068       fprintf (SUMA_STDERR,"Error %s: idcode not found in dov.\n", FuncName);
02069       SUMA_RETURN (-1);
02070    }
02071    
02072    ncheck = 0;
02073    icheck = icur;
02074    while (ncheck < n_dov) {
02075       icheck = (icheck + 1) % n_dov;
02076       /*fprintf(SUMA_STDERR,"%s: Checking %d\n", FuncName, icheck);*/
02077       if (SUMA_isSO(dov[icheck])) {
02078          /*fprintf(SUMA_STDERR,"%s: Settling on %d\n", FuncName, icheck);*/
02079          SOnxt = (SUMA_SurfaceObject *)dov[icheck].OP;
02080          SUMA_RETURN (icheck);
02081       }
02082       ++ncheck;
02083    }
02084    /* should not get here */
02085    SUMA_RETURN (-1);
02086 }
02087 
02088 /*! 
02089    Replaces one surface in RegisteredDO with another 
02090 
02091 */
02092 SUMA_Boolean SUMA_SwitchSO (SUMA_DO *dov, int N_dov, int SOcurID, int SOnxtID, SUMA_SurfaceViewer *sv)
02093 {
02094    static char FuncName[]={"SUMA_SwitchSO"};
02095    SUMA_Axis *EyeAxis;
02096    int EyeAxis_ID;
02097    char CommString[100];
02098    SUMA_EngineData ED;
02099    DList *list = NULL;
02100    
02101    SUMA_ENTRY;
02102 
02103    /* unregister the current surface from RegisteredDO */
02104    /*fprintf(SUMA_STDERR,"%s: Unregistering DOv[%d]...\n", FuncName, SOcurID);*/
02105    if (!SUMA_UnRegisterDO(SOcurID, sv)) {
02106       fprintf(SUMA_STDERR,"Error %s: Failed to UnRegisterDO.\n", FuncName);
02107       SUMA_RETURN (NOPE);
02108    }
02109 
02110    /* set the focus ID to the current surface */
02111    sv->Focus_SO_ID = SOnxtID;
02112 
02113    /* register the new surface in RegisteredDO */
02114    /*fprintf(SUMA_STDERR,"%s: Registering DOv[%d]...\n", FuncName, sv->Focus_SO_ID); */
02115    if (!SUMA_RegisterDO(sv->Focus_SO_ID, sv)) {
02116       fprintf(SUMA_STDERR,"Error %s: Failed to RegisterDO.\n", FuncName);
02117       SUMA_RETURN (NOPE);
02118    }
02119 
02120    /* modify the rotation center */
02121    if (!SUMA_UpdateRotaCenter(sv, dov, N_dov)) {
02122       fprintf (SUMA_STDERR,"Error %s: Failed to update center of rotation", FuncName);
02123       SUMA_RETURN (NOPE);
02124    }
02125    
02126    /* set the viewing points */
02127    if (!SUMA_UpdateViewPoint(sv, dov, N_dov)) {
02128       fprintf (SUMA_STDERR,"Error %s: Failed to update view point", FuncName);
02129       SUMA_RETURN (NOPE);
02130    }
02131    
02132    /* Change the defaults of the eye axis to fit standard EyeAxis */
02133    EyeAxis_ID = SUMA_GetEyeAxis (sv, dov);
02134 
02135    if (EyeAxis_ID < 0) {
02136       fprintf(SUMA_STDERR,"Error %s: No Eye Axis. %d\n", FuncName, EyeAxis_ID);
02137    } else {
02138       EyeAxis = (SUMA_Axis *)(dov[EyeAxis_ID].OP);
02139       SUMA_EyeAxisStandard (EyeAxis, sv);
02140    }
02141    
02142    /* do the axis setup */
02143    SUMA_WorldAxisStandard (sv->WAx, sv);
02144 
02145 
02146    /* Home call baby */
02147    if (!list) list = SUMA_CreateList();
02148    SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Home, SES_Suma, sv);
02149 
02150    if (!SUMA_Engine (&list)) {
02151       fprintf(stderr, "Error SUMA_input: SUMA_Engine call failed.\n");
02152    }
02153 
02154    
02155    /* take care of the cross hair's XYZ */
02156 
02157    /* to do elsewhere */
02158    /* when a cross hair needs to be communicated, you must use the LocalDomainParentID surface and not the Focus_Surface */
02159    SUMA_RETURN (YUP);
02160 }
02161 
02162 /*!
02163    \brief gets overlays from parent surface SO_prec to child surface SO_nxt
02164    
02165 */
02166 SUMA_Boolean SUMA_GetOverlaysFromParent(SUMA_SurfaceObject *SO_nxt, SUMA_SurfaceObject *SO_prec) 
02167 {
02168    static char FuncName[]={"SUMA_GetOverlaysFromParent"};
02169    int j, OverInd=-1;
02170    SUMA_Boolean LocalHead = NOPE;
02171 
02172    SUMA_ENTRY;
02173 
02174    if (!SO_nxt || !SO_prec) {
02175       SUMA_SL_Err("Null input");
02176       SUMA_RETURN(NOPE);
02177    }
02178    if (!SUMA_isRelated(SO_prec, SO_nxt, 1)) {
02179       SUMA_SL_Err("Surfaces are not level 1 related");
02180       SUMA_RETURN(NOPE);
02181    }
02182 
02183    /* Create a link to each overlay plane in the precursor unless such a plane exists already  */
02184    for (j=0; j < SO_prec->N_Overlays; ++j) {
02185       if (!SUMA_Fetch_OverlayPointer (SO_nxt->Overlays, SO_nxt->N_Overlays, SO_prec->Overlays[j]->Name, &OverInd)) {
02186          /* plane not found, create a link to it */
02187          if (LocalHead) fprintf (SUMA_STDERR,"Local Debug %s: Overlay plane %s not found, creating the link.\n", FuncName, SO_prec->Overlays[j]->Name);
02188          SO_nxt->Overlays[SO_nxt->N_Overlays] = (SUMA_OVERLAYS *)SUMA_LinkToPointer((void*)SO_prec->Overlays[j]);
02189          /* it happens at times, that an overlay carries coordinate bias with it. 
02190          When that happens, the bias should be added immediately */
02191          if (SO_nxt->Overlays[SO_nxt->N_Overlays]->OptScl) {
02192             if (SO_nxt->Overlays[SO_nxt->N_Overlays]->OptScl->BiasVect) {
02193                SUMA_LH("Adding coordbias");
02194                SUMA_ADD_COORD_BIAS_VECT(  SO_nxt,
02195                                           SO_nxt->Overlays[SO_nxt->N_Overlays], 
02196                                           SO_nxt->Overlays[SO_nxt->N_Overlays]->OptScl->DoBias, 
02197                                           SO_nxt->Overlays[SO_nxt->N_Overlays]->OptScl->BiasVect);
02198                /* Update surface geometry properties */
02199                SUMA_NewSurfaceGeometry(SO_nxt);
02200             }
02201          }
02202          /*increment the number of overlay planes */
02203          ++SO_nxt->N_Overlays;
02204       } else {
02205          /* plane found, do nothing */
02206          if (LocalHead) fprintf (SUMA_STDERR,"Local Debug %s: Overlay plane %s found. Index#%d\n.", FuncName, SO_prec->Overlays[j]->Name, OverInd);
02207       }
02208    }   
02209 
02210    SUMA_RETURN(YUP);
02211 }
02212 
02213 /*! 
02214    ans = SUMA_SwitchState (dov, N_dov, sv, nxtstateID, nxtgroup);
02215    
02216    Replaces one viewing state with another
02217 
02218 */
02219 SUMA_Boolean SUMA_SwitchState (SUMA_DO *dov, int N_dov, SUMA_SurfaceViewer *sv, int nxtstateID, char *nxtgroup)
02220 {
02221    static char FuncName[]={"SUMA_SwitchState"};
02222    SUMA_Axis *EyeAxis;
02223    int EyeAxis_ID, I_C, ND, id;
02224    char CommString[100];
02225    SUMA_EngineData ED;
02226    int curstateID, i, j, jmax, prec_ID;
02227    SUMA_SurfaceObject *SO_nxt, *SO_prec;
02228    float *XYZ, *XYZmap;
02229    DList *list = NULL;
02230    SUMA_Boolean LocalHead = NOPE;
02231    
02232    SUMA_ENTRY;
02233 
02234    XYZ = NULL;
02235    XYZmap = NULL;
02236    
02237    curstateID = SUMA_WhichState(sv->State, sv, sv->CurGroupName);
02238    
02239    /* unregister all the surfaces for the current view */
02240    if (LocalHead) fprintf(SUMA_STDERR,"%s: Unregistering state %d\n", FuncName, curstateID);
02241    for (i=0; i<sv->VSv[curstateID].N_MembSOs; ++i) {
02242       if (!SUMA_UnRegisterDO(sv->VSv[curstateID].MembSOs[i], sv)) {
02243          fprintf(SUMA_STDERR,"Error %s: Failed to UnRegisterDO.\n", FuncName);
02244          SUMA_RETURN (NOPE);
02245       }
02246    }
02247    
02248    /* adopt the new group */
02249    if (strcmp(sv->CurGroupName, nxtgroup)) { 
02250       SUMA_LH("Changing group...");
02251       if (!SUMA_AdoptGroup(sv, nxtgroup)) {
02252          SUMA_SLP_Err("Failed to adopt new group");
02253          SUMA_RETURN(NOPE);
02254       }
02255    } else {
02256       SUMA_LH("No group change...");
02257    }
02258    
02259    /* register all the surfaces from the next view */
02260    if (LocalHead) fprintf(SUMA_STDERR,"%s: Registering DOv of state %d...\n", FuncName, nxtstateID);
02261    for (i=0; i<sv->VSv[nxtstateID].N_MembSOs; ++i) {
02262       if (!SUMA_RegisterDO(sv->VSv[nxtstateID].MembSOs[i], sv)) {
02263          fprintf(SUMA_STDERR,"Error %s: Failed to RegisterDO.\n", FuncName);
02264          SUMA_RETURN (NOPE);
02265       }
02266    }
02267       
02268    #if 0
02269    {/* trying to keep two surfaces from riding on top of each other - An initial pass*/
02270       /* This method works OK but you should not be applying it to 
02271       geometrically correct surfaces (like the pial surfaces whose containing
02272       boxes intersect although slightly). Since you're modifying the coordinates
02273       here, you will be throwing them out of alignment with the volume.
02274       Since I have not such field yet, this method will be put on hold for a while
02275       */
02276       int RegSO[SUMA_MAX_DISPLAYABLE_OBJECTS], N_RegSO, im;
02277       float Ep1, Ep2, d1, d2, dc, dd, xShift1=0.0, xShift2=0.0;
02278       SUMA_SurfaceObject *SO1, *SO2;
02279       /* find out how many SOs are registered in the current view */
02280       N_RegSO = SUMA_RegisteredSOs (sv, dov, RegSO);
02281       if (N_RegSO > 2) {
02282          SUMA_SLP_Note( "Will not attempt\n"
02283                         "to separate more than\n"
02284                         "2 surfaces.\n");
02285       }
02286       if (N_RegSO == 2) {
02287          SO1 = (SUMA_SurfaceObject *)dov[RegSO[0]].OP;
02288          SO2 = (SUMA_SurfaceObject *)dov[RegSO[1]].OP;
02289          
02290          /* THIS IS AN EXTREMELY CRUDE TEST */
02291          /* check if bounding boxes overlap */
02292          /* Usually, problem is in the x direction*/
02293          /* what extreme points fall within the two centroids ? */
02294          if ( ((SO1->MaxDims[0] - SO1->Center[0]) * (SO1->MaxDims[0] - SO2->Center[0]) ) < 0 ) {
02295             Ep1 = SO1->MaxDims[0];
02296          }else {
02297             Ep1 = SO1->MinDims[0];
02298          }
02299          
02300          if ( ((SO2->MaxDims[0] - SO2->Center[0]) * (SO2->MaxDims[0] - SO1->Center[0]) ) < 0 ) {
02301             Ep2 = SO2->MaxDims[0];
02302          }else {
02303             Ep2 = SO2->MinDims[0];
02304          }
02305          
02306          /* Do the surfaces intersect each other in that direction ? */
02307          d1 = (float)fabs(Ep1 - SO1->Center[0]);
02308          d2 = (float)fabs(Ep2 - SO2->Center[0]);
02309          dc = (float)fabs(SO1->Center[0] -SO2->Center[0]);
02310          dd = d1 + d2 - dc;
02311          if (dd > 0) {
02312             if (SO1->Center[0] > SO2->Center[0]) {
02313                xShift1 = 1.1 * dd / 2.0;
02314                xShift2 = 1.1 * -dd / 2.0;
02315             }else {
02316                xShift1 = 1.1 * -dd / 2.0;
02317                xShift2 = 1.1 * +dd / 2.0;
02318             }
02319          } 
02320          
02321          if (xShift1) {
02322             if (LocalHead) fprintf (SUMA_STDERR,"%s: Shifting by +- %f\n", FuncName, xShift1);
02323             /* modify the coordinates */
02324             for (im=0; im< SO1->N_Node; ++im) SO1->NodeList[3*im] += xShift1;
02325             SO1->Center[0] += xShift1;
02326             SO1->MaxDims[0] += xShift1;
02327             SO1->MinDims[0] += xShift1;
02328             for (im=0; im< SO2->N_Node; ++im) SO2->NodeList[3*im] += xShift2;
02329             SO2->Center[0] += xShift2;
02330             SO2->MaxDims[0] += xShift2;
02331             SO2->MinDims[0] += xShift2;
02332          } else {
02333             SUMA_LH("No shift necessary");
02334          }
02335       } 
02336    }
02337    #endif
02338    
02339    /*set the Color Remix flag */
02340    if (!SUMA_SetShownLocalRemixFlag (sv)) {
02341       fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_SetShownLocalRemixFlag.\n", FuncName);
02342       SUMA_RETURN (NOPE);
02343    }
02344 
02345    
02346    /* if no coloroverlay exists, link to MapReference surface, if possible */
02347    for (i=0; i<sv->VSv[nxtstateID].N_MembSOs; ++i) {
02348       /* next surface being checked */
02349       SO_nxt = (SUMA_SurfaceObject *)(dov[sv->VSv[nxtstateID].MembSOs[i]].OP);
02350 
02351       /* Get the Mapping Reference surface, that's the precursor*/
02352       if (!SO_nxt->LocalDomainParentID) {
02353          prec_ID = -1;
02354       }else {
02355          prec_ID = SUMA_findSO_inDOv(SO_nxt->LocalDomainParentID, SUMAg_DOv, SUMAg_N_DOv);
02356       }
02357       if (prec_ID < 0) {
02358          /* no precursors found, notify user */
02359          fprintf(SUMA_STDERR, "\n\aWarning %s: No precursors found for surface %d.\nColors, selected nodes and facesets will not be reflect those in previous state.\n.",\
02360           FuncName, sv->VSv[nxtstateID].MembSOs[i]);
02361          continue;
02362       }
02363 
02364       SO_prec = (SUMA_SurfaceObject *)(dov[prec_ID].OP);
02365 
02366       /* check for risk of node inconsistencies */
02367 
02368       if (SO_prec->N_Node >= SO_nxt->N_Node ) {/* > or equal number of nodes*/
02369          /* matching number of nodes */
02370          if (!SUMA_GetOverlaysFromParent(SO_nxt,SO_prec)) {
02371             SUMA_SL_Err("Failed to get overlays from parents");
02372             SUMA_RETURN(NOPE);
02373          }
02374 
02375          if (SO_prec->N_Node > SO_nxt->N_Node) {/* More in prec */
02376             /* just warn */
02377             fprintf(SUMA_STDERR, "Warning %s: More nodes (%d) in precursor surface. \n Assuming upcoming surface is a subset of precursor.\n", FuncName, SO_prec->N_Node - SO_nxt->N_Node);
02378          }/* More in prec */ 
02379 
02380          /* link the selected nodes and facesets, if possible */
02381          /*fprintf(SUMA_STDERR, "%s: Linking selected nodes  ...\n", FuncName);*/
02382          /* check for risk of node inconsistencies */
02383          if (SO_prec->N_Node == SO_nxt->N_Node) {
02384             SO_nxt->SelectedNode = SO_prec->SelectedNode;
02385             } else { /* more nodes in precursor, make sure selected node is OK */
02386             if (SO_prec->SelectedNode < SO_nxt->N_Node) {
02387                SO_nxt->SelectedNode = SO_prec->SelectedNode;
02388                } else { /* this node does not exist in the upcoming thing */
02389                fprintf(SUMA_STDERR, "\n\aWarning %s: Slected node in precursor state does not exist in current state.\n Selected Node is left at previous setting in this view state.\n", FuncName);
02390                }
02391             }
02392 
02393          } /* > or equal number of nodes */ else { /* less in prec */
02394             fprintf(SUMA_STDERR, "\n\aWarning %s: More nodes (%d) in upcoming surface. Colors, selected nodes and facesets are not carried through from precursor.\n", FuncName, SO_nxt->N_Node - SO_prec->N_Node);
02395          }
02396 
02397          #if 0
02398          /* You do not want to mix colors yet, the flag for doing that has already been set*/
02399          /* Here you need to remix the colors */
02400          if (!SUMA_Overlays_2_GLCOLAR4(SO_nxt->Overlays, SO_nxt->N_Overlays, SUMA_GetColorList (sv, SO_nxt->idcode_str), SO_nxt->N_Node,\
02401              sv->Back_Modfact, sv->ShowBackground, sv->ShowForeground)) {
02402             fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_Overlays_2_GLCOLAR4.\n", FuncName);
02403             SUMA_RETURN (NOPE);
02404          }
02405          #endif
02406          
02407       }
02408    
02409    /* Bind the cross hair to a reasonable surface, if possible */
02410    if (sv->Ch->SurfaceID >= 0) {      
02411       if (LocalHead) fprintf(SUMA_STDERR, "Local Debug %s: Linking Cross Hair via SurfaceID...\n", FuncName);
02412       j = SUMA_MapRefRelative (sv->Ch->SurfaceID, sv->VSv[nxtstateID].MembSOs, sv->VSv[nxtstateID].N_MembSOs, dov);
02413       if (LocalHead) fprintf(SUMA_STDERR, "Local Debug %s: Cross Hair's  New SurfaceID = %d\n", FuncName, j );
02414       
02415       /* set the XYZ of the cross hair based on the coordinates of the upcoming surface, if possible */
02416       if (j >= 0) {
02417          SO_nxt = (SUMA_SurfaceObject *)(dov[j].OP);
02418          ND = SO_nxt->NodeDim;
02419          id = ND * sv->Ch->NodeID;
02420          if (sv->Ch->NodeID >= 0) {
02421             if (LocalHead) fprintf(SUMA_STDERR, "Local Debug %s: Using NodeID for link.\n", FuncName);
02422             sv->Ch->c[0] = SO_nxt->NodeList[id];
02423             sv->Ch->c[1] = SO_nxt->NodeList[id+1];
02424             sv->Ch->c[2] = SO_nxt->NodeList[id+2];
02425          } else {
02426             /* no node associated with cross hair, use XYZ */
02427             if (LocalHead) fprintf(SUMA_STDERR, "Local Debug %s: Using XYZ for link.\n", FuncName);
02428             SO_prec = (SUMA_SurfaceObject *)(dov[sv->Ch->SurfaceID].OP);
02429             /* go from XYZ to XYZmap on current surface then from XYZmap to XYZ on new surface */
02430             I_C = -1;
02431             XYZmap = SUMA_XYZ_XYZmap (sv->Ch->c, SO_prec, dov, N_dov, &I_C);
02432             if (XYZmap == NULL) {
02433                fprintf(SUMA_STDERR, "Error %s: Failed in SUMA_XYZ_XYZmap\n", FuncName); 
02434             }else {
02435                XYZ = SUMA_XYZmap_XYZ (XYZmap, SO_nxt, dov, N_dov, &I_C);
02436                if (XYZ == NULL) {
02437                   fprintf(SUMA_STDERR, "Error %s: Failed in SUMA_XYZmap_XYZ\n", FuncName); 
02438                } else {
02439                   sv->Ch->c[0] = XYZ[0];
02440                   sv->Ch->c[1] = XYZ[1];
02441                   sv->Ch->c[2] = XYZ[2];
02442                }
02443                
02444             }
02445             if (XYZ) SUMA_free(XYZ);
02446             if (XYZmap) SUMA_free(XYZmap);
02447          }
02448          
02449          /* if the surface controller is open, update it */
02450          if (SO_nxt->SurfCont->TopLevelShell)   { 
02451             SUMA_Init_SurfCont_SurfParam(SO_nxt);
02452          }
02453 
02454       } else {
02455          fprintf(SUMA_STDERR, "%s: No relatives between states. CrossHair location will not correspond between states\n", FuncName); 
02456       }
02457        sv->Ch->SurfaceID = j;
02458       if (LocalHead) fprintf(SUMA_STDERR, "Local Debug %s: Linking Cross Hair Via NodeID Done.\n", FuncName);
02459    }
02460    
02461 
02462 
02463    /* switch the state accordingly */
02464    sv->State =  sv->VSv[nxtstateID].Name;
02465    sv->iState = nxtstateID;
02466    
02467    /* set the focus ID to the first surface in the next view */
02468    sv->Focus_SO_ID = sv->VSv[nxtstateID].MembSOs[0];
02469    
02470    /* Now update the cross hair info if needed for the surface in focus */
02471    if (sv->Ch->SurfaceID >= 0)   { 
02472       SUMA_SurfaceObject *SOtmp=(SUMA_SurfaceObject *)(dov[sv->Focus_SO_ID].OP);
02473       if (SOtmp->SurfCont->TopLevelShell) {
02474          SUMA_Init_SurfCont_CrossHair(SOtmp);
02475       }
02476    }
02477 
02478    if (LocalHead) {
02479       SUMA_SurfaceObject *SOtmp=(SUMA_SurfaceObject *)(dov[sv->Focus_SO_ID].OP);
02480       fprintf(SUMA_STDERR,"%s: Setting new Focus ID to surface %s\n", FuncName, SOtmp->Label);
02481    }
02482    
02483    /* decide what the best state is */
02484    sv->StdView = SUMA_BestStandardView (sv,dov, N_dov);
02485    if (LocalHead) fprintf(SUMA_STDOUT,"%s: Standard View Now %d\n", FuncName, sv->StdView);
02486    if (sv->StdView == SUMA_Dunno) {
02487       fprintf(SUMA_STDERR,"Error %s: Could not determine the best standard view. Choosing default SUMA_3D\n", FuncName);
02488       sv->StdView = SUMA_3D;
02489    }
02490 
02491    /* modify the rotation center */
02492    if (!SUMA_UpdateRotaCenter(sv, dov, N_dov)) {
02493       fprintf (SUMA_STDERR,"Error %s: Failed to update center of rotation", FuncName);
02494       SUMA_RETURN (NOPE);
02495    }
02496    
02497    /* set the viewing points */
02498    if (!SUMA_UpdateViewPoint(sv, dov, N_dov)) {
02499       fprintf (SUMA_STDERR,"Error %s: Failed to update view point", FuncName);
02500       SUMA_RETURN (NOPE);
02501    }
02502    
02503    /* Change the defaults of the eye axis to fit standard EyeAxis */
02504    EyeAxis_ID = SUMA_GetEyeAxis (sv, dov);
02505 
02506    if (EyeAxis_ID < 0) {
02507       fprintf(SUMA_STDERR,"Error %s: No Eye Axis. %d\n", FuncName, EyeAxis_ID);
02508    } else {
02509       EyeAxis = (SUMA_Axis *)(dov[EyeAxis_ID].OP);
02510       SUMA_EyeAxisStandard (EyeAxis, sv);
02511    }
02512 
02513    /* do the axis setup */
02514    SUMA_WorldAxisStandard (sv->WAx, sv);
02515     
02516    /* Home call baby */
02517    if (!list) list = SUMA_CreateList();
02518    SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Home, SES_Suma, sv);
02519    if (!SUMA_Engine (&list)) {
02520       fprintf(stderr, "Error SUMA_input: SUMA_Engine call failed.\n");
02521    }
02522 
02523    SUMA_RETURN (YUP);
02524 }
02525 
02526 /*!
02527    Call this function whenever you have new geometry in the viewer
02528    This happens when you switch states or when you modify the coordinates of a surface
02529    The succession of function calls is replicated in parts elsewhere in the code
02530    like in the SwitchState function
02531 */
02532 SUMA_Boolean SUMA_NewGeometryInViewer (SUMA_DO *dov, int N_dov, SUMA_SurfaceViewer *sv)
02533 {
02534    static char FuncName[]={"SUMA_NewGeometryInViewer"};
02535    SUMA_Axis *EyeAxis;
02536    int EyeAxis_ID, I_C, OverInd, ND, id;
02537    char CommString[100];
02538    SUMA_EngineData ED;
02539    int  i, j, jmax, prec_ID;
02540    SUMA_SurfaceObject *SO_nxt, *SO_prec;
02541    SUMA_Boolean LocalHead = NOPE;
02542    
02543    SUMA_ENTRY;   
02544    
02545    /* decide what the best std view is */
02546    sv->StdView = SUMA_BestStandardView (sv,dov, N_dov);
02547    if (LocalHead) fprintf(SUMA_STDOUT,"%s: Standard View Now %d\n", FuncName, sv->StdView);
02548    if (sv->StdView == SUMA_Dunno) {
02549       fprintf(SUMA_STDERR,"Error %s: Could not determine the best standard view. Choosing default SUMA_3D\n", FuncName);
02550       sv->StdView = SUMA_3D;
02551    }
02552    
02553    /* modify the rotation center */
02554    if (!SUMA_UpdateRotaCenter(sv, dov, N_dov)) {
02555       fprintf (SUMA_STDERR,"Error %s: Failed to update center of rotation", FuncName);
02556       SUMA_RETURN (NOPE);
02557    }
02558    
02559    /* set the viewing points */
02560    if (!SUMA_UpdateViewPoint(sv, dov, N_dov)) {
02561       fprintf (SUMA_STDERR,"Error %s: Failed to update view point", FuncName);
02562       SUMA_RETURN (NOPE);
02563    }
02564    
02565    
02566    /* Change the defaults of the eye axis to fit standard EyeAxis */
02567    EyeAxis_ID = SUMA_GetEyeAxis (sv, dov);
02568 
02569    if (EyeAxis_ID < 0) {
02570       fprintf(SUMA_STDERR,"Error %s: No Eye Axis. %d\n", FuncName, EyeAxis_ID);
02571    } else {
02572       EyeAxis = (SUMA_Axis *)(dov[EyeAxis_ID].OP);
02573       SUMA_EyeAxisStandard (EyeAxis, sv);
02574    }
02575    
02576    /* Need to update where you're looking at*/
02577    glMatrixMode(GL_MODELVIEW);
02578    glLoadIdentity();
02579    gluLookAt ( sv->GVS[sv->StdView].ViewFrom[0], sv->GVS[sv->StdView].ViewFrom[1], 
02580                sv->GVS[sv->StdView].ViewFrom[2], sv->GVS[sv->StdView].ViewCenter[0], 
02581                sv->GVS[sv->StdView].ViewCenter[1], sv->GVS[sv->StdView].ViewCenter[2], 
02582                sv->GVS[sv->StdView].ViewCamUp[0], sv->GVS[sv->StdView].ViewCamUp[1], 
02583                sv->GVS[sv->StdView].ViewCamUp[2]);
02584    
02585    /* do the axis setup */
02586    SUMA_WorldAxisStandard (sv->WAx, sv);
02587 
02588    /* You still need to call SUMA_display via SUMA_postRedisplay but that is done after this function returns */ 
02589 
02590    SUMA_RETURN (YUP);
02591 }
02592 
02593 /*!
02594 \brief ans = SUMA_OpenGLStateReset (dov, N_dov, sv);
02595 Used when going from one surface viewer to another. The OpenGL state variables 
02596 need to be reset when moving from one viewer to the next. Otherwise you risk having 
02597 unpredictable results the first time you do something in one viewer after you'd been
02598 in another. 
02599 This function is a stripped down version of SUMA_SwitchState and should 
02600 be followed by a call to SUMA_postRedisplay for all the changes to take effect.
02601 Do not try executing all the commands in SUMA_display that affect the modelview 
02602 matrix and the projection matrix without calling for a display the changes will not take effect.
02603 
02604 \param dov (SUMA_DO *) Pointer to vector of displayable objects, typically SUMAg_DOv
02605 \param N_dov (int) number of elements in dov, typically SUMAg_N_DOv
02606 \param sv (SUMA_SurfaceViewer *) viewer making the request.
02607 \return YUP/NOPE Good/Bad
02608 \sa SUMA_NewGeometryInViewer
02609 
02610 */
02611 SUMA_Boolean SUMA_OpenGLStateReset (SUMA_DO *dov, int N_dov, SUMA_SurfaceViewer *sv)
02612 {
02613    static char FuncName[]={"SUMA_OpenGLStateReset"};
02614    SUMA_Axis *EyeAxis;
02615    int EyeAxis_ID, I_C, OverInd, ND, id;
02616    char CommString[100];
02617    SUMA_EngineData ED;
02618    int  i, j, jmax, prec_ID;
02619    SUMA_SurfaceObject *SO_nxt, *SO_prec;
02620    SUMA_Boolean LocalHead = NOPE;
02621    
02622    SUMA_ENTRY;   
02623    
02624    #if 0
02625    /* modify the rotation center */
02626    if (!SUMA_UpdateRotaCenter(sv, dov, N_dov)) {
02627       fprintf (SUMA_STDERR,"Error %s: Failed to update center of rotation", FuncName);
02628       SUMA_RETURN (NOPE);
02629    }
02630    
02631    /* set the viewing points */
02632    if (!SUMA_UpdateViewPoint(sv, dov, N_dov)) {
02633       fprintf (SUMA_STDERR,"Error %s: Failed to update view point", FuncName);
02634       SUMA_RETURN (NOPE);
02635    }
02636    #endif
02637    
02638    /* This is all that is needed, the others above do not need to be updated at this stage*/
02639    
02640    /* Change the defaults of the eye axis to fit standard EyeAxis */
02641    EyeAxis_ID = SUMA_GetEyeAxis (sv, dov);
02642 
02643    if (EyeAxis_ID < 0) {
02644       fprintf(SUMA_STDERR,"Error %s: No Eye Axis. %d\n", FuncName, EyeAxis_ID);
02645    } else {
02646       EyeAxis = (SUMA_Axis *)(dov[EyeAxis_ID].OP);
02647       SUMA_EyeAxisStandard (EyeAxis, sv);
02648    }
02649    
02650 
02651    #if 0
02652    /* force an axis drawing to set the projection matrix correctly */
02653    SUMA_SET_GL_PROJECTION(sv);   
02654    #endif
02655    
02656    /* You still need to call SUMA_display via SUMA_postRedisplay but that is done after this function returns */ 
02657 
02658    SUMA_RETURN (YUP);
02659 }
02660 
02661 /*!
02662    EyeAxisID = SUMA_GetEyeAxis (sv, dov);
02663    gets the ID (indices into dov) of the Eye Axis in sv
02664    \param sv (SUMA_SurfaceViewer *) the surface viewer structure
02665    \param dov (SUMA_DO *) the Displayable Objects vector (accessible to sv)
02666    \param Ax (SUMA_Axis *) a pointer to the Eye Axis structure (NULL if error )
02667    \ret EyeAxisID (int) the index into dov of the Eye Axis 
02668       if an error is encountered, including more than one Eye Axis, a -1 is returned
02669 */
02670 int SUMA_GetEyeAxis (SUMA_SurfaceViewer *sv, SUMA_DO *dov)
02671 {
02672    static char FuncName[]={"SUMA_GetEyeAxis"};
02673    int i, k = -1, cnt = 0;
02674    SUMA_Axis *AO;
02675    
02676    SUMA_ENTRY;
02677 
02678    for (i=0; i< sv->N_DO; ++i) {
02679       if (dov[sv->RegisteredDO[i]].ObjectType == AO_type) {
02680          AO = (SUMA_Axis *)(dov[sv->RegisteredDO[i]].OP);
02681          if (strcmp(AO->Name, "Eye Axis") == 0) {
02682             k = sv->RegisteredDO[i];
02683             ++cnt;
02684          }
02685       }
02686    }
02687    if (cnt > 1) {
02688       fprintf (SUMA_STDERR,"Error %s: Found more than one Eye Axis. \n", FuncName);
02689       SUMA_RETURN (-1);
02690    }
02691    
02692    SUMA_RETURN (k);
02693 }
02694 
02695 /*! 
02696    transform current XYZ to XYZmap 
02697    The XYZ on an auxilliary surface are of no relevance to the volume. They must be transformed
02698    to mappable XYZ (in mm, RAI, in alignment with the Parent Volume)   
02699    XYZmap = SUMA_XYZ_XYZmap (XYZ, SO, dov, N_dov, I_C);
02700 
02701    \param XYZ (float *) XYZ triplet in SO's native coordinate space
02702    \param SO (SUMA_SurfaceObject *SO) obvious, ain't it
02703    \param dov (SUMA_DO*) vector containing all displayable objects
02704    \param N_dov (int) number of elements in dov
02705    \param I_C (int *) (pre allocated) pointer to the index of the closest (or representative) node 
02706                        in SO to the XYZ location. If you do not have it, make sure *I_C = -1. If you
02707                        do so, the function will search for nodes contained in a box mm wide
02708                        and centered on XYZ. If nodes are found in the box the I_C is set to the
02709                        index of the closest node and XYZmap contains the coordinates of I_C in the 
02710                        SO->LocalDomainParentID surface.
02711    \ret XYZmap (float *) Mappable XYZ coordinates. NULL in case of trouble.
02712 
02713 */
02714 
02715 float * SUMA_XYZ_XYZmap (float *XYZ, SUMA_SurfaceObject *SO, SUMA_DO* dov, int N_dov, int *I_C)
02716 {/* SUMA_XYZ_XYZmap */
02717    static char FuncName[]={"SUMA_XYZ_XYZmap"};
02718    float *XYZmap;
02719    int iclosest, id, ND;
02720    SUMA_SurfaceObject *SOmap;
02721    int SOmapID;
02722    SUMA_Boolean LocalHead = NOPE;
02723    
02724    SUMA_ENTRY;
02725 
02726    /* allocate for return */
02727    XYZmap = (float *)SUMA_calloc (3, sizeof(float));
02728    if (XYZmap == NULL) {
02729       fprintf(SUMA_STDERR,"Error %s: Could not allocate for XYZmap.\n", FuncName);
02730       SUMA_RETURN (NULL);
02731    } 
02732    
02733    /* if surface is a local domain parent, do the obivious */
02734    if (SUMA_isLocalDomainParent(SO)){
02735       /*fprintf(SUMA_STDERR,"%s: Surface is a local domain parent. XYZmap = XYZ.\n", FuncName); */
02736       SUMA_COPY_VEC (XYZ, XYZmap, 3, float, float);
02737       SUMA_RETURN (XYZmap);   
02738    }
02739    /* if surface is not a  local domain parent , do the deed */
02740    if (!SUMA_ismappable(SO)){
02741       fprintf(SUMA_STDERR,"%s: Surface is NOT mappable, returning NULL.\n", FuncName);
02742       SUMA_free(XYZmap);
02743       SUMA_RETURN (NULL);
02744    }
02745 
02746    /* surface is mappable, things will get more complicated */
02747 
02748    /* find the closest node in SO */
02749    if (*I_C < 0) { /* user has not specified closest node ID*/
02750       /* must find closest node on my own */
02751          {
02752             SUMA_ISINBOX IB;
02753             float Bd[3], distance;
02754             int ii;
02755             
02756             /* set the search box dimensions */
02757             Bd[0] = Bd[1] = Bd[2] = SUMA_XYZ_XFORM_BOXDIM_MM;
02758             IB = SUMA_isinbox (SO->NodeList, SO->N_Node, XYZ, Bd,  YUP);
02759             fprintf (SUMA_STDOUT,"%s: %d nodes (out of %d) found in box\n",FuncName, IB.nIsIn, SO->N_Node);
02760 
02761             if (IB.nIsIn) { /* found some, find the closest node */
02762                /* locate the closest node and store it's id in EngineData*/
02763                /*for (ii=0; ii<IB.nIsIn; ++ii) {
02764                   fprintf (SUMA_STDERR,"%d\t%.3f\t\t", IB.IsIn[ii], IB.d[ii]);
02765                }*/
02766                SUMA_MIN_LOC_VEC (IB.d, IB.nIsIn, distance, iclosest);
02767                iclosest = IB.IsIn[iclosest];
02768                /* get ridd of IB's vectors */
02769                if (!SUMA_Free_IsInBox (&IB)) {
02770                   fprintf(SUMA_STDERR,"Error %s: Failed to free IB\n", FuncName);
02771                }
02772 
02773             } else { /* no node is close enough */
02774                fprintf (SUMA_STDERR,"%s: No node was close enough to XYZ, no linkage possible\n", FuncName);
02775                SUMA_free(XYZmap);
02776                SUMA_RETURN (NULL);
02777             }
02778             /* store iclosest for lazy user */
02779             *I_C = iclosest;
02780          }
02781    } else { 
02782       iclosest = *I_C;
02783    }
02784    
02785    if (LocalHead) fprintf (SUMA_STDERR,"%s: Node identified for linking purposes is %d\n", FuncName, *I_C);
02786    /* find the SO that is the Mappable cahuna */
02787    SOmapID = SUMA_findSO_inDOv(SO->LocalDomainParentID, dov, N_dov);
02788    if (SOmapID < 0) {
02789       fprintf (SUMA_STDERR,"%s: Failed in SUMA_findSO_inDOv This should not happen.\n", FuncName);
02790       SUMA_free(XYZmap);
02791       SUMA_RETURN (NULL);
02792    }
02793 
02794    SOmap = (SUMA_SurfaceObject *)(dov[SOmapID].OP);
02795    ND = SOmap->NodeDim;
02796    id = ND * iclosest;
02797    XYZmap[0]=SOmap->NodeList[id];
02798    XYZmap[1]=SOmap->NodeList[id+1];
02799    XYZmap[2]=SOmap->NodeList[id+2];
02800 
02801    /* all is done */
02802 
02803    SUMA_RETURN (XYZmap);
02804 }/* SUMA_XYZ_XYZmap */
02805 
02806 /*! 
02807    transform  XYZmap to XYZ on current surface
02808    
02809    XYZ = SUMA_XYZmap_XYZ (XYZmap, SO, dov, N_dov, I_C);
02810 
02811    \param XYZmap (float *) XYZmap triplet in SO's MapRef coordinate space
02812    \param SO (SUMA_SurfaceObject *SO) obvious, ain't it
02813    \param dov (SUMA_DO*) vector containing all displayable objects
02814    \param N_dov (int) number of elements in dov
02815    \param I_C (int *) (pre allocated) pointer to the index of the closest (or representative) node 
02816                        in SO's MapRef to the XYZmap location. If you do not have it, make sure *I_C = -1. If you
02817                        do so, the function will search for nodes contained in a box mm wide
02818                        and centered on XYZmap. If nodes are found in the box the I_C is set to the
02819                        index of the closest node and XYZ contains the coordinates of I_C in the 
02820                        SO surface.
02821    \ret XYZ (float *) Equivalent of XYZmap on the auxilliary surface SO. NULL in case of trouble.
02822 
02823    \sa SUMA_XYZ_XYZmap
02824 */
02825 
02826 float * SUMA_XYZmap_XYZ (float *XYZmap, SUMA_SurfaceObject *SO, SUMA_DO* dov, int N_dov, int *I_C)
02827 {/* SUMA_XYZmap_XYZ */
02828    static char FuncName[]={"SUMA_XYZmap_XYZ"};
02829    float *XYZ;
02830    int iclosest, id, ND;
02831    SUMA_SurfaceObject *SOmap;
02832    int SOmapID;
02833    SUMA_Boolean LocalHead = NOPE;
02834    
02835    SUMA_ENTRY;
02836 
02837    /* allocate for return */
02838    XYZ = (float *)SUMA_calloc (3, sizeof(float));
02839    if (XYZ == NULL) {
02840       fprintf(SUMA_STDERR,"Error %s: Could not allocate for XYZ.\n", FuncName);
02841       SUMA_RETURN (NULL);
02842    } 
02843    
02844    /* if surface is not mappable, do the deed */
02845    if (!SUMA_ismappable(SO)){
02846       fprintf(SUMA_STDERR,"%s: Surface is NOT mappable, returning NULL.\n", FuncName);
02847       SUMA_free(XYZ);
02848       SUMA_RETURN (NULL);
02849    }
02850 
02851    /* if surface is a local domain parent, do the obivious */
02852    if (SUMA_isLocalDomainParent(SO)){
02853       if (LocalHead) fprintf(SUMA_STDERR,"%s: Surface is a local domain parent. XYZ = XYZmap.\n", FuncName);
02854       SUMA_COPY_VEC (XYZmap, XYZ, 3, float, float);
02855       SOmap = SO;
02856       /* do not return yet, must fix the node id too */
02857    } else {
02858       /* surface is mappable, things will get more complicated */
02859       /* find the SO that is the Mappable cahuna */
02860       SOmapID = SUMA_findSO_inDOv(SO->LocalDomainParentID, dov, N_dov);
02861       if (SOmapID < 0) {
02862          fprintf (SUMA_STDERR,"%s: Failed in SUMA_findSO_inDOv This should not happen.\n", FuncName);
02863          SUMA_free(XYZ);
02864          SUMA_RETURN (NULL);
02865       }
02866       SOmap = (SUMA_SurfaceObject *)(dov[SOmapID].OP);
02867    }
02868    /* find the closest node in SO */
02869    if (*I_C < 0) { /* user has not specified closest node ID*/
02870       /* must find closest node on my own */
02871          {
02872             SUMA_ISINBOX IB;
02873             float Bd[3], distance;
02874             int ii;
02875             
02876             /* set the search box dimensions */
02877             Bd[0] = Bd[1] = Bd[2] = SUMA_XYZ_XFORM_BOXDIM_MM;
02878             IB = SUMA_isinbox (SOmap->NodeList, SOmap->N_Node, XYZmap, Bd,  YUP);
02879             if (LocalHead) fprintf (SUMA_STDERR,"%s: %d nodes (out of %d) found in box\n",FuncName, IB.nIsIn, SOmap->N_Node);
02880 
02881             if (IB.nIsIn) { /* found some, find the closest node */
02882                /* locate the closest node and store it's id in EngineData*/
02883                /*for (ii=0; ii<IB.nIsIn; ++ii) {
02884                   fprintf (SUMA_STDERR,"%d\t%.3f\t\t", IB.IsIn[ii], IB.d[ii]);
02885                }*/
02886                SUMA_MIN_LOC_VEC (IB.d, IB.nIsIn, distance, iclosest);
02887                iclosest = IB.IsIn[iclosest];
02888                /* get ridd of IB's vectors */
02889                if (!SUMA_Free_IsInBox (&IB)) {
02890                   fprintf(SUMA_STDERR,"Error %s: Failed to free IB\n", FuncName);
02891                }
02892 
02893             } else { /* no node is close enough */
02894                if (SO != SOmap) {
02895                   SUMA_SL_Warn(  "No node was close enough\n"
02896                                  "to XYZmap, no linkage possible."   );
02897                   SUMA_free(XYZ);
02898                   SUMA_RETURN (NULL);
02899                } else {
02900                   /* comes from inherrently mappable stuff, makes sense to leave XYZ */
02901                   SUMA_SL_Warn(  "No node was close enough\n"
02902                                  "to XYZmap, linking by coordinate."   );
02903                   SUMA_RETURN (XYZ);
02904                }
02905             }
02906             /* store iclosest for lazy user */
02907             *I_C = iclosest;
02908          }
02909    } else { 
02910       iclosest = *I_C;
02911    }
02912    if (LocalHead) fprintf (SUMA_STDERR,"%s: Node identified for linking purposes is %d\n", FuncName, *I_C);
02913    ND = SO->NodeDim;
02914    id = ND * iclosest;
02915    XYZ[0]=SO->NodeList[id];
02916    XYZ[1]=SO->NodeList[id+1];
02917    XYZ[2]=SO->NodeList[id+2];
02918 
02919    /* all is done */
02920    SUMA_RETURN (XYZ);
02921 }/* SUMA_XYZmap_XYZ */
02922 
02923 /*! 
02924    Prec_ID = SUMA_MapRefRelative (Cur_ID, Prec_List, N_Prec_List, dov);
02925    Returns the ID (index into dov) of the surface object in Prec_List that is related 
02926    (via MapRef) to the surface object Cur_ID.
02927    This means that SOcur.LocalDomainParentID = SOprec.MapRef_icode_str or SOprec.idcode_str
02928 
02929    \param Cur_ID (int) index into dov of the current surface object
02930    \param Prec_List (int *) indices into dov of the precursor surface objects 
02931    \param N_Prec_List (int) number of indices in Prec_List
02932    \param dov (SUMA_DO *) the vector of Displayable Object Structures
02933    \ret Prec_ID (int) index into dov of the surface object that is related to Cur_ID
02934 
02935 */
02936 int SUMA_MapRefRelative (int cur_id, int *prec_list, int N_prec_list, SUMA_DO *dov) 
02937 {
02938    int i, rel_id = -1;
02939    static char FuncName[]={"SUMA_MapRefRelative"};
02940    SUMA_SurfaceObject *SOcur, *SO_prec;
02941 
02942    SUMA_ENTRY;
02943 
02944    SOcur = (SUMA_SurfaceObject *)(dov[cur_id].OP);
02945    /* if surface has no MapRef then it cannot receive colors from precursors */
02946    if (!SUMA_ismappable(SOcur)) {
02947       SUMA_RETURN (-1);
02948    }
02949    
02950     
02951    for (i=0; i<N_prec_list; ++i) {
02952       SO_prec = (SUMA_SurfaceObject *)(dov[prec_list[i]].OP);
02953       
02954       if (  SO_prec == SOcur ||
02955             strcmp(SOcur->idcode_str, SO_prec->idcode_str) == 0 ) {
02956          if (N_prec_list == 1) {
02957             /* if all you have is one surface in one state in SUMA then you need not worry about the rest */
02958          } else {
02959             fprintf(SUMA_STDERR,"Error %s: Flow problem. Did not expect identical surfaces in this condition (N_prec_list = %d)\n", FuncName, N_prec_list);
02960             SUMA_BEEP; 
02961          }
02962          /* 
02963          I changed the next condition: 
02964          if (  strcmp(SOcur->LocalDomainParentID, SO_prec->LocalDomainParentID) == 0 || 
02965             strcmp(SOcur->LocalDomainParentID, SO_prec->idcode_str) == 0 )
02966          to
02967          if (  SUMA_isRelated(SOcur, SO_prec, 1) )
02968          The two are the same except for the condition when the two surfaces are identical.
02969          So I put in a error message when that would happen and I'll deal with it then.
02970          ZSS Jan 08 04
02971          */
02972          
02973       }
02974       
02975       if (  SUMA_isRelated(SOcur, SO_prec, 1) ) { /* Change made Jan 08 04, see note above */
02976          /* there's some relationship here, save it for return */
02977          if (rel_id < 0) {
02978             rel_id = prec_list[i];
02979          } else {
02980             fprintf (SUMA_STDERR,"Error %s: I did not think that would occur! Ignoring other relatives for now.\n", FuncName); 
02981          }
02982 
02983       }
02984    }
02985 
02986    SUMA_RETURN (rel_id);
02987 
02988 }
02989 
02990 /*!
02991    \brief creates a list of surfaces that are to be sent to AFNI
02992 */
02993 int *SUMA_FormSOListToSendToAFNI(SUMA_DO *dov, int N_dov, int *N_Send) 
02994 {
02995    static char FuncName[]={"SUMA_FormSOListToSendToAFNI"};
02996    int *SendList = NULL, ii, j, s, *is_listed=NULL;
02997    SUMA_SurfaceObject *SO=NULL;
02998    SUMA_SO_SIDE side=SUMA_NO_SIDE;
02999    SUMA_Boolean LocalHead = NOPE;
03000    
03001    SUMA_ENTRY;
03002 
03003    *N_Send = 0;
03004    SendList = (int *)SUMA_malloc(N_dov * sizeof(int));
03005    is_listed = (int *)SUMA_calloc(N_dov,  sizeof(int));
03006    if (!SendList || !is_listed) {
03007       SUMA_SL_Crit("Failed to allocate");
03008       SUMA_RETURN(SendList);
03009    }
03010    
03011    
03012    for (s=0;s<5; ++s) {
03013       for (ii=0; ii<N_dov; ++ii) {
03014          if (SUMA_isSO(dov[ii])) {
03015             SO = (SUMA_SurfaceObject *)(dov[ii].OP);      
03016             if (SO->AnatCorrect && !SO->SentToAfni && SO->VolPar) {
03017                switch (s) {
03018                   case 0:
03019                      if (SO->Side == SUMA_LEFT && SUMA_isTypicalSOforVolSurf(SO) ==  -1) { SendList[*N_Send] = ii; *N_Send = *N_Send + 1; is_listed[ii] = 1;}
03020                      break;
03021                   case 1:
03022                      if (SO->Side == SUMA_LEFT && SUMA_isTypicalSOforVolSurf(SO) ==   1) { SendList[*N_Send] = ii; *N_Send = *N_Send + 1; is_listed[ii] = 1;}
03023                      break;
03024                   case 2:
03025                      if (SO->Side == SUMA_RIGHT && SUMA_isTypicalSOforVolSurf(SO) == -1) { SendList[*N_Send] = ii; *N_Send = *N_Send + 1; is_listed[ii] = 1;}
03026                      break;
03027                   case 3:
03028                      if (SO->Side == SUMA_RIGHT && SUMA_isTypicalSOforVolSurf(SO) ==  1) { SendList[*N_Send] = ii; *N_Send = *N_Send + 1; is_listed[ii] = 1;}
03029                      break;
03030                   default:
03031                      if (!is_listed[ii]) { SendList[*N_Send] = ii; *N_Send = *N_Send + 1; is_listed[ii] = 1;}
03032                      break;
03033                }
03034             }
03035          }
03036       }
03037    }
03038    
03039    #if 0
03040    for (s=0; s<3; ++s) {
03041       if (s==0) side = SUMA_LEFT;
03042       else if (s == 1) side = SUMA_RIGHT;
03043       else side = SUMA_NO_SIDE;
03044       for (j=0; j<3; ++j) {
03045          for (ii=0; ii<N_dov; ++ii) {
03046             if (SUMA_isSO(dov[ii])) {
03047                SO = (SUMA_SurfaceObject *)(dov[ii].OP);
03048                if (s==0) {
03049                   if (SO->Side != side) { continue;}
03050                } else if (s == 1){
03051                   if (SO->Side != side) { continue;}
03052                } else {
03053                   /* let it proceed */
03054                }
03055                #if 1 
03056                /* Jan. 08 04 this is the right thing to do but 
03057                AFNI is not ready to deal with this
03058                and things can get confusing. See 
03059                confusing fat point in Readme_Modify.log,
03060                date: Thu Jan  8 13:55:33 EST 2004 */
03061                if (!SO->AnatCorrect) {
03062                   continue;
03063                }
03064                #else 
03065                /* Jan. 08 04 the old and not confusing way. 
03066                Turn it off as soon as AFNI is ready 
03067                for the option  above.
03068                See labbook NIH-3 page 146 */
03069                if (!SUMA_isLocalDomainParent(SO)) {
03070                   continue;
03071                }
03072                #endif
03073                if (j==0) { /* inner surfaces */
03074                   if (SUMA_isTypicalSOforVolSurf(SO) != -1 ) {
03075                      continue;
03076                   }
03077                }else if (j==1) { /* outer surfaces */
03078                   if (SUMA_isTypicalSOforVolSurf(SO)  != 1 ) {
03079                      continue;
03080                   }
03081                }else if (j==2) { /* other */
03082                   if (SUMA_isTypicalSOforVolSurf(SO)  != 0 ) {
03083                      continue;
03084                   }
03085                }
03086                /* if this surface has been sent to AFNI before, bypass it */
03087                if (SO->SentToAfni) {
03088                   if (LocalHead) fprintf(SUMA_STDERR, "Warning %s: Surface %s has been sent to AFNI before.\n", \
03089                      FuncName, SO->idcode_str);
03090                   continue;
03091                }else {
03092                   if (LocalHead) fprintf(SUMA_STDERR, "Warning %s: Surface %s Will be sent to AFNI.\n", \
03093                      FuncName, SO->idcode_str);
03094                }
03095                SendList[*N_Send] = ii; *N_Send = *N_Send + 1;
03096             }
03097          }
03098       }
03099    }
03100    #endif
03101    SUMA_RETURN(SendList);
03102 
03103 }
03104 
 

Powered by Plone

This site conforms to the following standards: