00001 #include "SUMA_suma.h"
00002 
00003  
00004 extern int SUMAg_N_DOv; 
00005 extern SUMA_DO *SUMAg_DOv;
00006 extern SUMA_CommonFields *SUMAg_CF; 
00007 extern SUMA_SurfaceViewer *SUMAg_SVv;
00008 extern int SUMAg_N_SVv;
00009 
00010 
00011 
00012 
00013 
00014 void SUMA_input(Widget w, XtPointer clientData, XtPointer callData)
00015 {
00016    static char FuncName[]= {"SUMA_input"};
00017    GLwDrawingAreaCallbackStruct *cd;
00018    char buffer[10], cbuf = '\0', cbuf2='\0';
00019    KeySym keysym;
00020    int xls, ntot, id = 0, ND, ip, NP;
00021    float ArrowDeltaRot = 0.05; 
00022    SUMA_EngineData *ED = NULL; 
00023    char CommString[SUMA_MAX_COMMAND_LENGTH];
00024    char s[SUMA_MAX_STRING_LENGTH], sfield[100], sdestination[100];
00025    static char ssource[]={"suma"};
00026    int it, ii, iv3[3], hit = 0;
00027    float **fm, fv3[3], fv15[15];
00028    XKeyEvent Kev;
00029    XButtonEvent Bev;
00030    XMotionEvent Mev;
00031    int isv;
00032    SUMA_SurfaceViewer *sv, *svi = NULL;
00033    GLfloat *glar_ColorList = NULL;
00034    static Time B1time = 0;
00035    static int pButton, mButton, rButton;
00036    SUMA_Boolean ROI_mode; 
00037    static SUMA_Boolean DoubleClick = NOPE;
00038    DList *list = NULL;
00039    DListElmt *NextElm= NULL;
00040    float bevx, bevy, mevx, mevy, wwid, whei, zc_fac;
00041    SUMA_PROMPT_DIALOG_STRUCT *prmpt=NULL; 
00042    SUMA_Boolean LocalHead = NOPE; 
00043 
00044    
00045  
00046 
00047    SUMA_ENTRY;
00048    
00049    
00050    cd = (GLwDrawingAreaCallbackStruct *) callData;
00051    
00052    
00053    SUMA_GLXAREA_WIDGET2SV(w, sv, isv);
00054    if (isv < 0) {
00055       fprintf (SUMA_STDERR, "Error %s: Failed in macro SUMA_GLXAREA_WIDGET2SV.\n", FuncName);
00056       SUMA_RETURNe;
00057    }
00058    if (LocalHead) fprintf (SUMA_STDERR,"%s: A call from SUMA_SurfaceViewer[%d], Pointer %p\n", FuncName, isv, sv);
00059    
00060 
00061    Kev = *(XKeyEvent *) &cd->event->xkey; 
00062    Bev = *(XButtonEvent *) &cd->event->xbutton;
00063    Mev = *(XMotionEvent *) &cd->event->xmotion;
00064    
00065    
00066    #if 0
00067       if (Kev.state & ShiftMask) {
00068          fprintf (SUMA_STDERR,"%s: Shift down\n", FuncName);
00069       }else if (Kev.state & ControlMask){
00070          fprintf (SUMA_STDERR,"%s: Control down\n", FuncName);
00071       }else if (Kev.state & Mod1Mask){
00072          fprintf (SUMA_STDERR,"%s: alt down\n", FuncName);
00073       }else if (Kev.state & Mod2Mask){
00074          fprintf (SUMA_STDERR,"%s: Mod2 down (apple on mac)\n", FuncName);
00075       }else if (Kev.state & Mod3Mask){
00076          fprintf (SUMA_STDERR,"%s: Mod3 down\n", FuncName);
00077       }else if (Kev.state & Mod4Mask){
00078          fprintf (SUMA_STDERR,"%s: Mod4 down\n", FuncName);
00079       }else if (Kev.state & Mod5Mask){
00080          fprintf (SUMA_STDERR,"%s: Mod5 down\n", FuncName);
00081       }else {
00082          
00083       }
00084    #endif
00085    
00086   switch (Kev.type) { 
00087   case KeyPress:
00088       xls = XLookupString((XKeyEvent *) cd->event, buffer, 8, &keysym, NULL);
00089       
00090        
00091       switch (keysym) { 
00092          case XK_bracketleft: 
00093             
00094             {
00095                #if 0
00096                int Registered_IDs[SUMAg_N_DOv], N_RegisteredSOs, k;
00097                SUMA_SurfaceObject *SO = NULL;
00098 
00099                   N_RegisteredSOs = SUMA_RegisteredSOs (sv, SUMAg_DOv, Registered_IDs);
00100                   for (k=0; k< N_RegisteredSOs; ++k) {
00101                      SO = (SUMA_SurfaceObject *)SUMAg_DOv[Registered_IDs[k]].OP;
00102                      if (SO->Side == SUMA_LEFT) SO->Show = !SO->Show;
00103                   }
00104                #endif
00105                sv->ShowLeft = !sv->ShowLeft;
00106             }
00107             
00108             SUMA_WorldAxisStandard (sv->WAx, sv);
00109             SUMA_UpdateViewerTitle(sv);   
00110             SUMA_postRedisplay(w, clientData, callData);
00111             break;
00112          
00113          case XK_bracketright: 
00114             
00115             {
00116                #if 0
00117                int Registered_IDs[SUMAg_N_DOv], N_RegisteredSOs, k;
00118                SUMA_SurfaceObject *SO = NULL;
00119 
00120                   N_RegisteredSOs = SUMA_RegisteredSOs (sv, SUMAg_DOv, Registered_IDs);
00121                   for (k=0; k< N_RegisteredSOs; ++k) {
00122                      SO = (SUMA_SurfaceObject *)SUMAg_DOv[Registered_IDs[k]].OP;
00123                      if (SO->Side == SUMA_RIGHT) SO->Show = !SO->Show;
00124                   }
00125                #endif
00126                sv->ShowRight = !sv->ShowRight;
00127             }
00128             
00129             SUMA_WorldAxisStandard (sv->WAx, sv);            
00130             SUMA_UpdateViewerTitle(sv);   
00131             SUMA_postRedisplay(w, clientData, callData);
00132             break;
00133                     
00134          case XK_space:   
00135             
00136             {
00137                SUMA_SurfaceObject *SO = NULL, *SOmap = NULL;
00138                int curstateID = -1, nxtstateID = -1, dov_ID = -1;
00139 
00140                
00141                curstateID = SUMA_WhichState(sv->State, sv, sv->CurGroupName);
00142                SO = (SUMA_SurfaceObject *)SUMAg_DOv[sv->Focus_SO_ID].OP;
00143                if (SUMA_isLocalDomainParent (SO)) {
00144                   
00145                   if (sv->LastNonMapStateID < 0) { 
00146                      fprintf(SUMA_STDERR,"Warning %s: Nothing defined to toggle with yet.\n", FuncName); 
00147                      break;
00148                   }
00149                   
00150                   if (LocalHead) 
00151                      fprintf (SUMA_STDERR,"%s: surface is inherrently mappable, switching to last non mappable state %d.\n", \
00152                         FuncName, sv->LastNonMapStateID);
00153                         
00154                   if (!SUMA_SwitchState (SUMAg_DOv, SUMAg_N_DOv, sv, sv->LastNonMapStateID, sv->CurGroupName)) {
00155                      fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_SwitchState.\n", FuncName);
00156                      break;
00157                   }
00158 
00159                } else {
00160                   if (LocalHead) 
00161                      fprintf (SUMA_STDERR,"%s: surface is not inherrently mappable, searching for mapping reference and its state.\n", \
00162                         FuncName);
00163                         
00164                   
00165                   dov_ID = SUMA_findSO_inDOv(SO->LocalDomainParentID, SUMAg_DOv, SUMAg_N_DOv);
00166                   SOmap = (SUMA_SurfaceObject *)SUMAg_DOv[dov_ID].OP;
00167                   nxtstateID = SUMA_WhichState(SOmap->State, sv, sv->CurGroupName);
00168                   
00169                   if (nxtstateID < 0) {
00170                      fprintf (SUMA_STDERR,"%s: Failed in SUMA_findSO_inDOv This should not happen.\n", FuncName);
00171                      break;
00172                   }
00173                   
00174                   if (LocalHead) 
00175                      fprintf (SUMA_STDERR,"%s: Found mapping reference in viewer state %d.\n", FuncName, nxtstateID);
00176                      
00177                   
00178                   sv->LastNonMapStateID = curstateID;
00179 
00180                   
00181                   if (!SUMA_SwitchState (SUMAg_DOv, SUMAg_N_DOv, sv, nxtstateID, sv->CurGroupName)) {
00182                      fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_SwitchState.\n", FuncName);
00183                      break;
00184                   }
00185                }
00186 
00187             }
00188             SUMA_postRedisplay(w, clientData, callData);
00189             break;
00190 
00191          case XK_Escape: 
00192             
00193             if (Kev.state & ShiftMask){
00194                if( SUMAg_CF->X->WarnClose) {
00195                   if (SUMA_ForceUser_YesNo(sv->X->TOPLEVEL, "Close All Viewers?", SUMA_YES, SWP_DONT_CARE) != SUMA_YES) {
00196                      break;   
00197                   }
00198                } 
00199                XtCloseDisplay( SUMAg_CF->X->DPY_controller1 ) ;
00200                exit(0);
00201             }else { 
00202                if( SUMAg_CF->X->WarnClose) {
00203                   #ifdef DARWIN
00204                      if (SUMA_ForceUser_YesNo(sv->X->TOPLEVEL, 
00205                                              "Close This Viewer?\n"
00206                                              "OS-X users: If answering YES,\n"
00207                                              "this prompt should not lie \n"
00208                                              "over viewer to be closed.\n"
00209                                              "Blame Bill Gates for this bug.",
00210                                               SUMA_YES, SWP_TOP_RIGHT) != SUMA_YES) {
00211                         break;   
00212                      }
00213                   #else
00214                      if (SUMA_ForceUser_YesNo(sv->X->TOPLEVEL, "Close This Viewer?", SUMA_YES, SWP_DONT_CARE) != SUMA_YES) {
00215                         break;   
00216                      }
00217                   #endif
00218                }
00219                SUMA_ButtClose_pushed (w, clientData, callData);
00220             }
00221             break;
00222 
00223          case XK_a:
00224             
00225 
00226             if (sv->Back_Modfact) {
00227                fprintf (SUMA_STDOUT,"%s: Modulation by background intensity OFF.\n", FuncName);
00228                sv->Back_Modfact = 0;
00229             } else {
00230                fprintf (SUMA_STDOUT,"%s: Modulation by background intensity ON.\n", FuncName);
00231                sv->Back_Modfact = SUMA_BACKGROUND_MODULATION_FACTOR;
00232             }
00233             
00234             
00235             if (!SUMA_SetShownLocalRemixFlag (sv)) {
00236                fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_SetShownLocalRemixFlag.\n", FuncName);
00237                break;
00238             }
00239             
00240             #if 0
00241             {
00242                SUMA_SurfaceObject *SO = NULL;
00243 
00244                for (ii=0; ii< sv->N_DO; ++ii) {
00245                   if (SUMA_isSO_G(SUMAg_DOv[sv->RegisteredDO[ii]], sv->Group)) {
00246                      SO = (SUMA_SurfaceObject*)SUMAg_DOv[sv->RegisteredDO[ii]].OP;
00247                      
00248                      glar_ColorList = SUMA_GetColorList (sv, SO->idcode_str);
00249                      if (!glar_ColorList) {
00250                         fprintf (SUMA_STDERR,"Error %s: NULL glar_ColorList.\n", FuncName);
00251                         SUMA_RETURNe;
00252                      }
00253                      if (!SUMA_Overlays_2_GLCOLAR4(SO->Overlays, SO->N_Overlays, glar_ColorList, SO->N_Node, \
00254                         sv->Back_Modfact, sv->ShowBackground, sv->ShowForeground)) {
00255                         fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_Overlays_2_GLCOLAR4.\n", FuncName);
00256                         SUMA_RETURNe;
00257                      }
00258                   }
00259                }
00260             }
00261             #endif
00262 
00263             SUMA_postRedisplay(w, clientData, callData);
00264             break;
00265 
00266          case XK_B:
00267                sv->BF_Cull = !sv->BF_Cull;
00268                if (sv->BF_Cull) {
00269                   glCullFace (GL_BACK);
00270                   glEnable (GL_CULL_FACE);
00271                   SUMA_SLP_Note ("BackFace Culling enabled.");
00272                } else {
00273                   glDisable(GL_CULL_FACE);
00274                   SUMA_SLP_Note ("BackFace Culling disabled.");
00275                }
00276                SUMA_postRedisplay(w, clientData, callData);
00277             break;
00278 
00279          case XK_b:
00280             
00281             if (!list) list = SUMA_CreateList();
00282             ED = SUMA_InitializeEngineListData (SE_ToggleBackground);
00283             if (!SUMA_RegisterEngineListCommand (  list, ED,
00284                                                    SEF_Empty, NULL,
00285                                                    SES_Suma, (void *)sv, NOPE,
00286                                                    SEI_Head, NULL)) {
00287                fprintf (SUMA_STDERR, "Error %s: Failed to register command.\n", FuncName);
00288             }
00289             
00290             ED = SUMA_InitializeEngineListData (SE_Redisplay);
00291             if (!SUMA_RegisterEngineListCommand (  list, ED,
00292                                                    SEF_Empty, NULL,
00293                                                    SES_Suma, (void *)sv, NOPE,
00294                                                    SEI_Head, NULL)) {
00295                fprintf (SUMA_STDERR, "Error %s: Failed to register command.\n", FuncName);
00296             }
00297                                                     
00298             if (!SUMA_Engine (&list)) {
00299                fprintf(SUMA_STDERR, "Error SUMA_input: SUMA_Engine call failed.\n");
00300             }
00301             break;            
00302 
00303          case XK_c:
00304             if (!list) list = SUMA_CreateList();
00305             ED = SUMA_InitializeEngineListData (SE_OpenColFileSelection);
00306             if (!(NextElm = SUMA_RegisterEngineListCommand (  list, ED,
00307                                                    SEF_vp, (void *)(SUMAg_DOv[sv->Focus_SO_ID].OP),
00308                                                    SES_Suma, (void *)sv, NOPE,
00309                                                    SEI_Head, NULL))) {
00310                fprintf (SUMA_STDERR, "Error %s: Failed to register command.\n", FuncName);
00311             }
00312             
00313             if (!SUMA_RegisterEngineListCommand (  list, ED,
00314                                           SEF_ip, sv->X->TOPLEVEL,
00315                                           SES_Suma, (void *)sv, NOPE,
00316                                           SEI_In, NextElm)) {
00317                fprintf (SUMA_STDERR, "Error %s: Failed to register command.\n", FuncName);
00318             }  
00319             
00320             if (!SUMA_Engine (&list)) {
00321                fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
00322             }
00323             
00324             break;
00325              
00326             #if 0
00327             
00328             
00329             fm = (float **)SUMA_allocate2D (ntot/4, 4, sizeof(float));
00330             if (fm == NULL) {
00331                fprintf(stderr,"Error SUMA_input: Failed to allocate space for fm\n");
00332                SUMA_RETURNe;
00333             }
00334 
00335             if (SUMA_Read_2Dfile (s, fm, 4, ntot/4) != ntot/4 ) {
00336                fprintf(stderr,"SUMA_input Error: Failed to read full matrix from %s\n", s);
00337                SUMA_RETURNe;
00338             }
00339                
00340             if (!list) list = SUMA_CreateList();
00341             ED = SUMA_InitializeEngineListData (SE_SetNodeColor);
00342             ED->N_cols = 4;
00343             ED->N_rows = ntot/4;
00344             if (!SUMA_RegisterEngineListCommand (  list, ED, 
00345                                                    SEF_fm, (void*)fm,
00346                                                    SES_Suma, (void *)sv, YUP,
00347                                                    SEI_Head, NULL)) {
00348                fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
00349                break;                                      
00350             } 
00351 
00352             
00353             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
00354 
00355             if (!SUMA_Engine (&list)) {
00356                fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
00357             }
00358 
00359             
00360             if (fm) SUMA_free2D ((char **)fm, ntot/4);
00361             break;
00362             #endif 
00363             
00364 
00365          case XK_d:
00366             if (SUMAg_CF->Dev) {
00367                SUMA_Show_DOv(SUMAg_DOv, SUMAg_N_DOv, stdout);
00368             }
00369             break;
00370 
00371          case XK_e:
00372             if (SUMAg_CF->Dev) {
00373                if (Kev.state & Mod1Mask || Kev.state & Mod2Mask){ 
00374                   int error, cnt = 0;
00375                   fprintf (SUMA_STDERR, "%s: Looking for OpenGL errors ...\n", FuncName);
00376                   while ((error = glGetError()) != GL_NO_ERROR) {
00377                      ++cnt;
00378                     fprintf (SUMA_STDERR, "GL error %d: %s\n", cnt, gluErrorString(error)); 
00379                   }
00380                   if (!cnt) {
00381                      fprintf (SUMA_STDERR, "%s: No errors found.\n", FuncName);
00382                   }
00383                }
00384             }
00385             break;
00386             
00387          case XK_F:
00388             
00389             if (!list) list = SUMA_CreateList(); 
00390             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_FlipLight0Pos, SES_Suma, sv);
00391             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
00392 
00393             if (!SUMA_Engine (&list)) {
00394                fprintf(stderr, "Error SUMA_input: SUMA_Engine call failed.\n");
00395             }
00396             break;
00397 
00398          case XK_f:
00399             
00400             if (!list) list = SUMA_CreateList(); 
00401             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_ToggleForeground, SES_Suma, sv);
00402             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
00403 
00404             if (!SUMA_Engine (&list)) {
00405                fprintf(stderr, "Error SUMA_input: SUMA_Engine call failed.\n");
00406             }
00407             break;            
00408 
00409          case XK_H:
00410                sv->X->HighlightBox_prmpt = SUMA_CreatePromptDialogStruct (SUMA_OK_APPLY_CLEAR_CANCEL, 
00411                                                       "Enter XYZ of box's center\n"
00412                                                       "followed by it's size (6 values)", 
00413                                                       "",
00414                                                       sv->X->TOPLEVEL, YUP,
00415                                                       SUMA_APPLY_BUTTON,
00416                                                       SUMA_HighlightBox, (void *)sv,
00417                                                       NULL, NULL,
00418                                                       NULL, NULL,
00419                                                       SUMA_isNumString, (void*)6,  
00420                                                       sv->X->HighlightBox_prmpt);
00421                
00422                sv->X->HighlightBox_prmpt = SUMA_CreatePromptDialog(sv->X->Title, sv->X->HighlightBox_prmpt);
00423                
00424             break;
00425 
00426          case XK_h:
00427             if (Kev.state & ControlMask){
00428               if (!list) list = SUMA_CreateList();
00429               SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Help, SES_Suma, NULL); 
00430               if (!SUMA_Engine (&list)) {
00431                   fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
00432               }    
00433             }else{
00434                if (SUMAg_CF->Dev) {
00435                   SUMA_SLP_Note("Please use ctrl+h for help.\nh alone will be reassigned\nin future versions.");
00436                   #if 0
00437                   
00438                   SUMA_RegisterMessage (SUMAg_CF->MessageList, "Test Notice", FuncName, SMT_Notice, SMA_Log);
00439                   SUMA_RegisterMessage (SUMAg_CF->MessageList, "Test Notice2", FuncName, SMT_Notice, SMA_LogAndPopup);
00440                   SUMA_RegisterMessage (SUMAg_CF->MessageList, "Test Warning", FuncName, SMT_Warning, SMA_LogAndPopup);
00441                   SUMA_RegisterMessage (SUMAg_CF->MessageList, "Test Error", FuncName, SMT_Error, SMA_LogAndPopup);
00442                   SUMA_RegisterMessage (SUMAg_CF->MessageList, "Test Critical", FuncName, SMT_Critical, SMA_LogAndPopup);
00443                   #endif
00444                }
00445             }
00446             break;
00447 
00448          case XK_j:
00449                if (Kev.state & ControlMask){     
00450                  sv->X->JumpXYZ_prmpt = SUMA_CreatePromptDialogStruct (SUMA_OK_APPLY_CLEAR_CANCEL, 
00451                                                       "Enter XYZ to send the cross hair to:", 
00452                                                       "",
00453                                                       sv->X->TOPLEVEL, YUP,
00454                                                       SUMA_APPLY_BUTTON,
00455                                                       SUMA_JumpXYZ, (void *)sv,
00456                                                       NULL, NULL,
00457                                                       NULL, NULL,
00458                                                       SUMA_isNumString, (void*)3,  
00459                                                       sv->X->JumpXYZ_prmpt);
00460                
00461                   sv->X->JumpXYZ_prmpt = SUMA_CreatePromptDialog(sv->X->Title, sv->X->JumpXYZ_prmpt);  
00462 
00463                } else if (Kev.state & Mod1Mask || Kev.state & Mod2Mask){     
00464                   sv->X->JumpFocusNode_prmpt = SUMA_CreatePromptDialogStruct (SUMA_OK_APPLY_CLEAR_CANCEL, 
00465                                                       "Enter index of focus node\nCross hair's XYZ will not be affected:", 
00466                                                       "",
00467                                                       sv->X->TOPLEVEL, YUP,
00468                                                       SUMA_APPLY_BUTTON,
00469                                                       SUMA_JumpFocusNode, (void *)sv,
00470                                                       NULL, NULL,
00471                                                       NULL, NULL,
00472                                                       SUMA_isNumString, (void*)1,  
00473                                                       sv->X->JumpFocusNode_prmpt);
00474                
00475                   sv->X->JumpFocusNode_prmpt = SUMA_CreatePromptDialog(sv->X->Title, sv->X->JumpFocusNode_prmpt);
00476                   
00477                } else {
00478                   sv->X->JumpIndex_prmpt = SUMA_CreatePromptDialogStruct (SUMA_OK_APPLY_CLEAR_CANCEL, 
00479                                                       "Enter index of node \nto send the cross hair to:", 
00480                                                       "",
00481                                                       sv->X->TOPLEVEL, YUP,
00482                                                       SUMA_APPLY_BUTTON,
00483                                                       SUMA_JumpIndex, (void *)sv,
00484                                                       NULL, NULL,
00485                                                       NULL, NULL,
00486                                                       SUMA_isNumString, (void*)1,  
00487                                                       sv->X->JumpIndex_prmpt);
00488                
00489                   sv->X->JumpIndex_prmpt = SUMA_CreatePromptDialog(sv->X->Title, sv->X->JumpIndex_prmpt);
00490                }
00491 
00492             break;
00493          
00494          case XK_J:
00495                sv->X->JumpFocusFace_prmpt = SUMA_CreatePromptDialogStruct (SUMA_OK_APPLY_CLEAR_CANCEL, 
00496                                                    "Enter index of FaceSet\nto highlight (this viewer only):", 
00497                                                    "",
00498                                                    sv->X->TOPLEVEL, YUP,
00499                                                    SUMA_APPLY_BUTTON,
00500                                                    SUMA_JumpFocusFace, (void *)sv,
00501                                                    NULL, NULL,
00502                                                    NULL, NULL,
00503                                                    SUMA_isNumString, (void*)1,  
00504                                                    sv->X->JumpFocusFace_prmpt);
00505 
00506                sv->X->JumpFocusFace_prmpt = SUMA_CreatePromptDialog(sv->X->Title, sv->X->JumpFocusFace_prmpt);
00507                
00508             break; 
00509               
00510          case XK_l:
00511             if (Kev.state & ControlMask){
00512                
00513                if (SUMAg_CF->Dev) {
00514                   if (!list) list = SUMA_CreateList();
00515                   ED = SUMA_InitializeEngineListData (SE_ToggleLockAllCrossHair);
00516                   if (!SUMA_RegisterEngineListCommand (  list, ED, 
00517                                                          SEF_Empty, NULL, 
00518                                                         SES_Suma, (void *)sv, NOPE, 
00519                                                         SEI_Head, NULL )) {
00520                      fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
00521                      break;
00522                   }
00523                   if (!SUMA_Engine (&list)) {
00524                      fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
00525                   }
00526                }
00527             } if (Kev.state & Mod1Mask  || Kev.state & Mod2Mask){ 
00528                
00529                if (!list) list = SUMA_CreateList();
00530                ED = SUMA_InitializeEngineListData (SE_SetLookAt);
00531                if (!SUMA_RegisterEngineListCommand (  list, ED, 
00532                                                       SEF_fv3, (void *)sv->Ch->c, 
00533                                                       SES_Suma, (void *)sv, NOPE, 
00534                                                       SEI_Head, NULL )) {
00535                   fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
00536                   SUMA_RETURNe;
00537                }
00538                if (!SUMA_Engine (&list)) {
00539                   fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
00540                }   
00541             } else {
00542                sv->X->LookAt_prmpt = SUMA_CreatePromptDialogStruct (SUMA_OK_APPLY_CLEAR_CANCEL, "X,Y,Z coordinates to look at:", 
00543                                                       "0,0,0",
00544                                                       sv->X->TOPLEVEL, YUP,
00545                                                       SUMA_APPLY_BUTTON,
00546                                                       SUMA_LookAtCoordinates, (void *)sv,
00547                                                       NULL, NULL,
00548                                                       NULL, NULL,
00549                                                       SUMA_isNumString, (void*)3,  
00550                                                       sv->X->LookAt_prmpt);
00551                
00552                sv->X->LookAt_prmpt = SUMA_CreatePromptDialog(sv->X->Title, sv->X->LookAt_prmpt);
00553                
00554             }
00555             break;
00556 
00557          case XK_L:
00558                prmpt = SUMA_CreatePromptDialogStruct (SUMA_OK_APPLY_CLEAR_CANCEL, "X,Y,Z coordinates of light0:", 
00559                                                       "",
00560                                                       sv->X->TOPLEVEL, NOPE,
00561                                                       SUMA_APPLY_BUTTON,
00562                                                       SUMA_SetLight0, (void *)sv,
00563                                                       NULL, NULL,
00564                                                       NULL, NULL,
00565                                                       SUMA_isNumString, (void*)3,  
00566                                                       NULL);
00567                
00568                prmpt = SUMA_CreatePromptDialog(sv->X->Title, prmpt);
00569                
00570             break;
00571 
00572          case XK_M:
00573             if ((Kev.state & Mod1Mask || Kev.state & Mod2Mask) && (Kev.state & ControlMask) ){
00574                   #ifndef DONT_USE_MCW_MALLOC
00575                   
00576                   if (!mcw_malloc_enabled) {
00577                      SUMA_SLP_Warn("Memory tracing\n"
00578                                   "is not enabled.\n"
00579                                   "Use Help-->MemTrace.");
00580                      SUMA_RETURNe;
00581                   } else {
00582                      SUMA_SLP_Note("Dumping memory tracing\n"
00583                                   "to latest ./malldump.???\n"
00584                                   "file (if possible).");
00585                      mcw_malloc_dump();
00586                   }
00587                   #else
00588                      SUMA_SLP_Warn("Sorry, memory tracing\n"
00589                                    "was not enabled at compile.\n"
00590                                    "time. You are out of luck\n"
00591                                    "if using SUN.");
00592                      SUMA_RETURNe;
00593                   #endif
00594             }
00595             break;
00596             
00597          case XK_m:
00598                if (Kev.state & ControlMask){
00599                   if (SUMAg_CF->Dev) {
00600                      SUMA_SurfaceObject *SO;
00601                      
00602                      fprintf(SUMA_STDOUT, "%s: Enter mm distance [RAI] to move center of all mappable surfaces in DOv by.\n", FuncName);
00603                      it = SUMA_ReadNumStdin (fv3, 3);
00604                      if (it > 0 && it < 3) {
00605                         fprintf(SUMA_STDERR,"Error %s: read %d values, expected 3.\n", FuncName, it);
00606                         SUMA_RETURNe;
00607                      }else if (it < 0) {
00608                         fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ReadNumStdin.\n", FuncName);
00609                         SUMA_RETURNe;
00610                      }else if (it == 0) {
00611                         fprintf(SUMA_STDERR,"%s: Nothing read.\n", FuncName);
00612                         SUMA_RETURNe;
00613                      }
00614                      
00615                      for (it = 0; it < SUMAg_N_DOv; ++it) {
00616                         if (SUMA_isSO_G (SUMAg_DOv[it], sv->CurGroupName)) {
00617                            SO = (SUMA_SurfaceObject *)SUMAg_DOv[it].OP;
00618                            if (SUMA_isLocalDomainParent(SO)) {
00619                               int imax;
00620                               
00621                               fprintf (SUMA_STDERR,"%s: Shifting %s by %f %f %f mm RAI.\n", FuncName, SO->Label, fv3[0], fv3[1], fv3[2]);
00622                               ii = 0;
00623                               imax = 3 * SO->N_Node;
00624                               while (ii < imax) {
00625                                  SO->NodeList[ii] += fv3[0]; ++ii;
00626                                  SO->NodeList[ii] += fv3[1]; ++ii;
00627                                  SO->NodeList[ii] += fv3[2]; ++ii;
00628                               }
00629                            }
00630                         }
00631                      }
00632                      
00633                      SUMA_postRedisplay(w, clientData, callData);
00634                   }
00635                } else {
00636                   sv->GVS[sv->StdView].ApplyMomentum = !sv->GVS[sv->StdView].ApplyMomentum;
00637                   SUMA_UpdateViewerTitle(sv);
00638                   if (sv->GVS[sv->StdView].ApplyMomentum) {
00639                       sv->X->MOMENTUMID = XtAppAddTimeOut(SUMAg_CF->X->App, 1, SUMA_momentum, (XtPointer) w);
00640                       
00641                      sv->GVS[sv->StdView].spinDeltaX = 0; sv->GVS[sv->StdView].spinDeltaY = 0;
00642                      sv->GVS[sv->StdView].translateDeltaX = 0; sv->GVS[sv->StdView].translateDeltaY = 0;
00643                   } else {
00644                      if (sv->X->MOMENTUMID)  {
00645                         XtRemoveTimeOut(sv->X->MOMENTUMID);
00646                         sv->X->MOMENTUMID = 0;
00647                      }
00648                   }
00649                }
00650              break;
00651 
00652          case XK_n:
00653                if (Kev.state & ControlMask){
00654                   if (LocalHead) fprintf(SUMA_STDOUT, "%s: Opening a new controller...\n", FuncName);
00655                   
00656                   if (!SUMA_X_SurfaceViewer_Create ()) {
00657                      fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_X_SurfaceViewer_Create.\n", FuncName);
00658                      SUMA_RETURNe;
00659                   } 
00660                }else {
00661                   if (SUMAg_CF->Dev) {
00662                      fprintf(stdout,"BAD IDEA Enter XYZ of center followed by size of Box (enter nothing to cancel):\n");
00663 
00664                      it = SUMA_ReadNumStdin (fv15, 6);
00665                      if (it > 0 && it < 6) {
00666                         fprintf(SUMA_STDERR,"Error %s: read %d values, expected 6.\n", FuncName, it);
00667                         SUMA_RETURNe;
00668                      }else if (it < 0) {
00669                         fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ReadNumStdin.\n", FuncName);
00670                         SUMA_RETURNe;
00671                      }else if (it == 0) {
00672                         SUMA_RETURNe;
00673                      }
00674 
00675                      fprintf (SUMA_STDOUT, "Parsed Input:\n\tCenter %f, %f, %f.\n\tBox Size %f, %f, %f\n", \
00676                         fv15[0], fv15[1],fv15[2],\
00677                         fv15[3], fv15[4],fv15[5]);
00678 
00679                      
00680                      if (!list) list = SUMA_CreateList ();
00681                      ED = SUMA_InitializeEngineListData (SE_GetNearestNode);
00682                      if (!SUMA_RegisterEngineListCommand (  list, ED, 
00683                                                             SEF_fv15, (void *)fv15, 
00684                                                             SES_Suma, (void *)sv, NOPE, 
00685                                                             SEI_Head, NULL )) {
00686                         fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
00687                         break;
00688                      }
00689 
00690                      SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
00691                      if (!SUMA_Engine (&list)) {
00692                         fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
00693                      }
00694                   }
00695                }
00696             break;
00697 
00698          case XK_p:
00699             sv->PolyMode = ((sv->PolyMode+1) % SRM_N_RenderModes);
00700             if (sv->PolyMode <= SRM_ViewerDefault) sv->PolyMode = SRM_Fill;
00701             
00702             SUMA_SET_GL_RENDER_MODE(sv->PolyMode);
00703             SUMA_postRedisplay(w, clientData, callData);
00704             break;
00705          
00706          case XK_r:
00707             {
00708                GLvoid *pixels;
00709                pixels = SUMA_grabPixels(1, sv->X->WIDTH, sv->X->HEIGHT);
00710                if (pixels) {
00711                  ISQ_snapsave (sv->X->WIDTH, -sv->X->HEIGHT, (unsigned char *)pixels, sv->X->GLXAREA ); 
00712                  SUMA_free(pixels);
00713                }else {
00714                   SUMA_SLP_Err("Failed to record image.");
00715                }
00716             }
00717             break;
00718 
00719          case XK_R:
00720             sv->Record = !sv->Record;
00721             if (sv->Record) { SUMA_SLP_Note ("Recording ON"); }
00722             else { SUMA_SLP_Note ("Recording OFF"); }
00723             SUMA_UpdateViewerTitle(sv);
00724             break;
00725             
00726          case XK_S:
00727             if (SUMAg_CF->Dev) {
00728                int *do_id, n_do_id;
00729                do_id = SUMA_GetDO_Type(SUMAg_DOv, SUMAg_N_DOv, SO_type, &n_do_id);
00730                if (n_do_id) {
00731                   while (n_do_id) {
00732                      SUMA_Print_Surface_Object((SUMA_SurfaceObject *)SUMAg_DOv[do_id[n_do_id-1]].OP, stdout);
00733                      --n_do_id;
00734                   }
00735                   SUMA_free(do_id);
00736                }
00737                break;
00738             }
00739          case XK_s:
00740             if ((Kev.state & Mod1Mask || Kev.state & Mod2Mask) && (Kev.state & ControlMask) && SUMAg_CF->Dev){
00741                if (!list) list = SUMA_CreateList();
00742                ED = SUMA_InitializeEngineListData (SE_LoadSegDO);
00743                if (!SUMA_RegisterEngineListCommand (  list, ED,
00744                                           SEF_ip, sv->X->TOPLEVEL,
00745                                           SES_Suma, (void *)sv, NOPE,
00746                                           SEI_Head, NULL)) {
00747                   fprintf (SUMA_STDERR, "Error %s: Failed to register command.\n", FuncName);
00748                }
00749                if (!SUMA_Engine (&list)) {
00750                      fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
00751                }               
00752    
00753             } else if (Kev.state & Mod1Mask || Kev.state & Mod2Mask){
00754                
00755                SUMAg_CF->SwapButtons_1_3 = !SUMAg_CF->SwapButtons_1_3;
00756                if (SUMAg_CF->SwapButtons_1_3) {
00757                   fprintf (SUMA_STDOUT,"%s: Buttons 1 and 3 are swapped.\n", FuncName);
00758                } else {
00759                   fprintf (SUMA_STDOUT,"%s: Default functions for buttons 1 and 3.\n", FuncName);
00760                }               
00761             } else if (SUMAg_CF->Dev) {
00762                #if 0
00763 
00764                for (ii=0; ii< sv->N_DO; ++ii) {
00765                   if (SUMA_isSO(SUMAg_DOv[sv->RegisteredDO[ii]])) 
00766                      SUMA_Print_Surface_Object((SUMA_SurfaceObject*)SUMAg_DOv[sv->RegisteredDO[ii]].OP, stdout);
00767                }
00768                #endif
00769             }
00770             break;
00771 
00772          case XK_t:
00773             if ((Kev.state & ControlMask)){
00774                   SUMA_SLP_Note("Forcing a resend of Surfaces to Afni...");
00775                   if (!list) list = SUMA_CreateList();
00776                   SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_SetForceAfniSurf, SES_Suma, sv);
00777                   
00778                   if (!SUMA_Engine (&list)) {
00779                      fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
00780                   }
00781             } else {
00782                if (!list) list = SUMA_CreateList();
00783                SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_ToggleConnected, SES_Suma, sv);
00784                
00785                if (!SUMA_Engine (&list)) {
00786                      fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
00787                }
00788             }
00789             break;
00790          
00791          case XK_T:
00792             if (!list) list = SUMA_CreateList();
00793                SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_StartListening, SES_Suma, sv);
00794                
00795             if (!SUMA_Engine (&list)) {
00796                   fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
00797             } 
00798             break;
00799             
00800          case XK_v:
00801             #if 0
00802             
00803             if (SUMAg_CF->Dev) {
00804                SUMA_Show_SurfaceViewer_Struct (sv, stdout, 0);
00805             }
00806             #endif
00807             break;
00808 
00809          case XK_W:
00810             {
00811                SUMA_SurfaceObject *SO;
00812                
00813                SO = (SUMA_SurfaceObject *)SUMAg_DOv[sv->Focus_SO_ID].OP;
00814                if (SO) {
00815                   if (!list) list = SUMA_CreateList();
00816                   ED = SUMA_InitializeEngineListData (SE_SaveSOFileSelection);
00817                   if (!(NextElm = SUMA_RegisterEngineListCommand (  list, ED,
00818                                                    SEF_vp, (void *)SO,
00819                                                    SES_Suma, (void *)sv, NOPE,
00820                                                    SEI_Head, NULL))) {
00821                      fprintf (SUMA_STDERR, "Error %s: Failed to register command.\n", FuncName);
00822                   }
00823             
00824                   if (!SUMA_RegisterEngineListCommand (  list, ED,
00825                                              SEF_ip, sv->X->TOPLEVEL,
00826                                              SES_Suma, (void *)sv, NOPE,
00827                                              SEI_In, NextElm)) {
00828                      fprintf (SUMA_STDERR, "Error %s: Failed to register command.\n", FuncName);
00829                   }  
00830             
00831                   if (!SUMA_Engine (&list)) {
00832                      fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
00833                   }
00834                }
00835             }
00836             break;
00837 
00838          case XK_w:
00839             SUMA_SLP_Warn("Option 'w' no longer supported.\nUse 'R' or 'r' instead.");
00840             #if 0
00841                fprintf(SUMA_STDOUT,"%s: Began rendering to file. Please wait ...\n", FuncName);
00842                if (!SUMA_RenderToPixMap (sv, SUMAg_DOv)) {
00843                   fprintf(SUMA_STDERR, "Error %s: Failed to write image.\n", FuncName);
00844                } 
00845             #endif
00846             break;
00847 
00848          case XK_Z:
00849             
00850             sv->FOV[sv->iState] /= FOV_IN_FACT; if (sv->FOV[sv->iState] < FOV_MIN) { SUMA_BEEP; sv->FOV[sv->iState] = FOV_MIN; }
00851             
00852             if (sv->ZoomCompensate) {
00853                sv->ZoomCompensate = sv->FOV[sv->iState] / FOV_INITIAL;
00854                if (sv->ZoomCompensate > 1) sv->ZoomCompensate = 1.0; 
00855                else if (sv->ZoomCompensate < 0.005) sv->ZoomCompensate = 0.005; 
00856             }
00857             SUMA_postRedisplay(w, clientData, callData);
00858             break;
00859 
00860          case XK_z:
00861             
00862             sv->FOV[sv->iState] /= FOV_OUT_FACT; if (sv->FOV[sv->iState] > FOV_MAX) { SUMA_BEEP; sv->FOV[sv->iState] = FOV_MAX; }
00863             
00864             if (sv->ZoomCompensate) {
00865                sv->ZoomCompensate = sv->FOV[sv->iState] / FOV_INITIAL;
00866                if (sv->ZoomCompensate > 1) sv->ZoomCompensate = 1.0; 
00867                else if (sv->ZoomCompensate < 0.005) sv->ZoomCompensate = 0.005;  
00868             }
00869             SUMA_postRedisplay(w, clientData, callData);
00870             break;
00871 
00872          case XK_8:
00873             {
00874                char stmp[100];
00875                sprintf(stmp, "%d", SUMAg_CF->X->NumForeSmoothing);
00876                SUMAg_CF->X->N_ForeSmooth_prmpt = SUMA_CreatePromptDialogStruct (SUMA_OK_APPLY_CLEAR_CANCEL, "Foreground smoothing iterations", 
00877                                                          stmp,
00878                                                          sv->X->TOPLEVEL, YUP,
00879                                                          SUMA_APPLY_BUTTON,
00880                                                          SUMA_SetNumForeSmoothing, (void *)sv,
00881                                                          NULL, NULL,
00882                                                          NULL, NULL,
00883                                                          SUMA_isNumString, (void*)1,  
00884                                                          SUMAg_CF->X->N_ForeSmooth_prmpt);
00885 
00886                SUMAg_CF->X->N_ForeSmooth_prmpt = SUMA_CreatePromptDialog("Foreground smoothing iterations", SUMAg_CF->X->N_ForeSmooth_prmpt);
00887             }
00888             break;
00889             
00890          case XK_asterisk:
00891             fprintf(SUMA_STDOUT, "%s: smoothing node attributes ...\n", FuncName);
00892             {
00893                SUMA_SurfaceObject *SO;
00894                float * attr_sm;
00895                float *attrbuf;
00896                int ic, cnt;
00897                int allcols;
00898                
00899                SO = (SUMA_SurfaceObject *)SUMAg_DOv[sv->Focus_SO_ID].OP;
00900                attrbuf = (float *)SUMA_calloc(SO->N_Node, sizeof(int));
00901                if (attrbuf == NULL) {
00902                   fprintf(stderr,"Error SUMA_input: Failed to allocate for attrbuf.\n");
00903                   break;
00904                }
00905 
00906                allcols = 4 * SO->N_Node;
00907                
00908                glar_ColorList = SUMA_GetColorList (sv, SO->idcode_str);
00909                if (!glar_ColorList) {
00910                   fprintf(SUMA_STDERR, "Error %s: Null glar_ColorList.\n", FuncName);
00911                   break;
00912                }
00913                for (ic=0; ic < 3; ++ic) { 
00914                   ii = ic;
00915                   cnt = 0;
00916                   while (ii < allcols) {
00917                      attrbuf[cnt] = glar_ColorList[ii];
00918                      ii += 4;
00919                      cnt += 1;
00920                   } 
00921 
00922                   attr_sm = SUMA_SmoothAttr_Neighb (attrbuf, SO->N_Node, NULL, SO->FN, 1); 
00923                   if (attr_sm == NULL) {
00924                      fprintf(stderr,"Error SUMA_input: Failed in SUMA_SmoothAttr_Neighb\n");
00925                      break;
00926                   }
00927 
00928                   
00929                   ii = ic; 
00930                   cnt = 0;
00931                   while (ii < allcols) {
00932                      glar_ColorList[ii] = attr_sm[cnt];
00933                      ii += 4;
00934                      cnt += 1;
00935                   } 
00936                }    
00937 
00938                SUMA_free(attr_sm);
00939                SUMA_free(attrbuf);
00940                
00941                SUMA_postRedisplay(w, clientData, callData);
00942             }
00943 
00944             break;
00945 
00946           case XK_at:
00947             if (SUMAg_CF->Dev) {
00948                
00949                fprintf(SUMA_STDOUT, "%s: Calculating surface curvature ...\n", FuncName);
00950                {
00951                   SUMA_SurfaceObject *SO;
00952                   SO = (SUMA_SurfaceObject *)SUMAg_DOv[sv->Focus_SO_ID].OP;
00953                   if (!SO->PolyArea) {
00954                      fprintf(SUMA_STDOUT, "%s: Computing required mesh area.\n", FuncName);
00955                      if (!SUMA_SurfaceMetrics (SO, "PolyArea", NULL)) {
00956                         fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_SurfaceMetrics.\n", FuncName);
00957                         break;
00958                      }
00959                   }
00960                   SO->SC = SUMA_Surface_Curvature (SO->NodeList, SO->N_Node, SO->NodeNormList, SO->PolyArea, SO->N_FaceSet, SO->FN, SO->EL);
00961                   if (SO->SC == NULL) {
00962                         fprintf(stderr,"Error %s: Failed in SUMA_Surface_Curvature\n", FuncName);
00963                         break;
00964                      }               
00965                }   
00966             }
00967             break;
00968 
00969          case XK_parenleft:
00970             if (SUMAg_CF->Dev) {
00971                SUMA_SurfaceObject *SO;
00972                SUMA_COLOR_MAP *CM;
00973                SUMA_SCALE_TO_MAP_OPT * OptScl;
00974                SUMA_STANDARD_CMAP MapType;
00975                SUMA_COLOR_SCALED_VECT * SV;
00976                float IntRange[2], *Vsort;
00977                float * attr_sm;
00978                float *Cx = NULL;
00979 
00980                fprintf(SUMA_STDOUT, "%s: Calculating convexity ...\n", FuncName);
00981                SO = (SUMA_SurfaceObject *)SUMAg_DOv[sv->Focus_SO_ID].OP;   
00982                Cx = (float *)SUMA_GetCx(SO->idcode_str, SUMAg_CF->DsetList, 0);
00983                if (Cx) {
00984                   fprintf(stderr,"Error %s: Cx must be null prior to new assignment\n", FuncName);
00985                   break;
00986                }
00987                Cx = SUMA_Convexity   (SO->NodeList, SO->N_Node, SO->NodeNormList, SO->FN);   
00988                if (Cx == NULL) {
00989                      fprintf(stderr,"Error %s: Failed in SUMA_Convexity\n", FuncName);
00990                      break;
00991                }   
00992                
00993                attr_sm = SUMA_SmoothAttr_Neighb (Cx, SO->N_Node, NULL, SO->FN, 1);
00994                if (attr_sm == NULL) {
00995                      fprintf(stderr,"Error %s: Failed in SUMA_SmoothAttr_Neighb\n", FuncName);
00996                      break;
00997                }   
00998                Cx = SUMA_SmoothAttr_Neighb (attr_sm, SO->N_Node, Cx, SO->FN, 1);
00999                if (attr_sm) SUMA_free(attr_sm);
01000 
01001                fprintf(SUMA_STDOUT, "%s: Use SUMA_ScaleToMap to colorize Conv.txt and display it on surface.\n", FuncName);
01002                CM = SUMA_GetStandardMap (SUMA_CMAP_nGRAY20);
01003                if (CM == NULL) {
01004                   fprintf (SUMA_STDERR,"Error %s: Could not get standard colormap.\n", FuncName);
01005                   exit (1); 
01006                }
01007 
01008                
01009                OptScl = SUMA_ScaleToMapOptInit();
01010                if (!OptScl) {
01011                   fprintf (SUMA_STDERR,"Error %s: Could not get scaling option structure.\n", FuncName);
01012                   exit (1); 
01013                }
01014 
01015                
01016                OptScl->ApplyClip = YUP;
01017                IntRange[0] = 5; IntRange[1] = 95;  
01018                Vsort = SUMA_PercRange (Cx, NULL, SO->N_Node, IntRange, IntRange, NULL); 
01019                OptScl->IntRange[0] = IntRange[0]; OptScl->IntRange[1] = IntRange[1];
01020 
01021                OptScl->BrightFact = 0.4;
01022 
01023                
01024                   
01025                   SV = SUMA_Create_ColorScaledVect(SO->N_Node);
01026                   if (!SV) {
01027                      fprintf (SUMA_STDERR,"Error %s: Could not allocate for SV.\n", FuncName);
01028                      exit(1);
01029                   }
01030 
01031                   
01032                   
01033                   if (!SUMA_ScaleToMap (Cx, SO->N_Node, Vsort[0], Vsort[SO->N_Node-1], CM, OptScl, SV)) {
01034                      fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_ScaleToMap.\n", FuncName);
01035                      exit(1);
01036                   }
01037 
01038                   
01039                   glar_ColorList = SUMA_GetColorList (sv, SO->idcode_str);
01040                   if (!glar_ColorList) {
01041                      fprintf (SUMA_STDERR,"Error %s: NULL glar_ColorList. BAD.\n", FuncName);
01042                      break;
01043                   }  
01044                   SUMA_RGBvec_2_GLCOLAR4(SV->cV, glar_ColorList, SO->N_Node);
01045 
01046                   
01047                   if (Vsort) SUMA_free(Vsort);
01048                   if (CM) SUMA_Free_ColorMap (CM);
01049                    if (OptScl) SUMA_free(OptScl);
01050                   if (SV) SUMA_Free_ColorScaledVect (SV);
01051                   if (Cx) {
01052                      SUMA_free(Cx);
01053                      Cx = NULL;
01054                   }
01055 
01056                fprintf(SUMA_STDOUT, "%s: Convexity mapping done ...\n", FuncName);
01057                SUMA_postRedisplay(w, clientData, callData);   
01058             }
01059             break;
01060          case XK_comma:
01061             {
01062                
01063                int nxtstateID = -1, curstateID = -1;
01064                int origState = sv->iState;
01065                char *note=NULL;
01066                
01067                if (sv->N_VSv < 2) break;
01068 
01069                curstateID = SUMA_WhichState (sv->State, sv, sv->CurGroupName);
01070                if (curstateID < 0) {
01071                   SUMA_SL_Err("Current State not found.\n"
01072                               "Should not happen here.");
01073                   SUMA_RETURNe;
01074                }
01075                
01076                if (SUMAg_N_SVv > 1) {
01077                   ii = SUMA_WhichViewerInMomentum (SUMAg_SVv, SUMAg_N_SVv, sv);
01078                   if (ii >= 0) {
01079                      sprintf (s, "You cannot switch states while other viewers\n"
01080                                  "(like %c) are in momentum mode.\n", ii+65);
01081                      SUMA_RegisterMessage (SUMAg_CF->MessageList, 
01082                                            s, FuncName, SMT_Error, SMA_LogAndPopup);
01083                      SUMA_RETURNe;
01084                   }
01085                }
01086                   
01087                do {
01088                   if (nxtstateID > -1) {
01089                      note = SUMA_append_string("Skipping state ",sv->State);
01090                      note = SUMA_append_replace_string(note, ".\nNo surfaces visible.", "", 1);
01091                      SUMA_SLP_Note(note);
01092                      SUMA_free(note);   note = NULL;
01093                   }
01094 
01095                   
01096                   
01097                   nxtstateID = SUMA_PrevState(sv);
01098                   if (nxtstateID == curstateID) break;
01099                   if (nxtstateID < 0) {
01100                      fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_PrevState.\n", FuncName);
01101                      break;
01102                   }
01103                   fprintf(SUMA_STDERR,"%s: Switching from %s to %s viewing state.\n", \
01104                      FuncName, sv->State, sv->VSv[nxtstateID].Name);
01105 
01106                   if (!SUMA_SwitchState (SUMAg_DOv, SUMAg_N_DOv, sv, nxtstateID, sv->CurGroupName)) {
01107                      fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_SwitchState.\n", FuncName);
01108                      break;
01109                   }
01110                   
01111                   
01112                   
01113                } while (!SUMA_VisibleSOs (sv, SUMAg_DOv, NULL) && sv->iState != origState);
01114                
01115                
01116                if (!list) list = SUMA_CreateList();
01117                SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
01118                if (!SUMA_Engine (&list)) {
01119                   fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
01120                }
01121                
01122                
01123                SUMA_UpdateViewerTitle(sv);
01124             }
01125             break;
01126 
01127          case XK_period:
01128             {
01129                
01130                int nxtstateID=-1, curstateID = -1;
01131                int origState = sv->iState;
01132                char *note=NULL;
01133                
01134                if (sv->N_VSv < 2) break;
01135                
01136                curstateID = SUMA_WhichState (sv->State, sv, sv->CurGroupName);
01137                if (curstateID < 0) {
01138                   SUMA_SL_Err("Current State not found.\n"
01139                               "Should not happen here.");
01140                   SUMA_RETURNe;
01141                }
01142                
01143                if (SUMAg_N_SVv > 1) {
01144                   ii = SUMA_WhichViewerInMomentum (SUMAg_SVv, SUMAg_N_SVv, sv);
01145                   if (ii >= 0) {
01146                      sprintf (s, "You cannot switch states while other viewers\n"
01147                                  "(like %c) are in momentum mode.\n", ii+65);
01148                      SUMA_RegisterMessage (SUMAg_CF->MessageList, 
01149                                            s, FuncName, SMT_Error, SMA_LogAndPopup);
01150                      SUMA_RETURNe;
01151                   }
01152                }
01153                
01154                do {
01155                   if (nxtstateID > -1) {
01156                      note = SUMA_append_string("Skipping state ",sv->State);
01157                      note = SUMA_append_replace_string(note, ".\nNo surfaces visible.", "", 1);
01158                      SUMA_SLP_Note(note);
01159                      SUMA_free(note);   note = NULL;
01160                   }
01161                   
01162                   if (LocalHead) fprintf(SUMA_STDERR,"%s: Current viewing state is %s ...\n", FuncName, sv->State);
01163                   
01164                   
01165                   nxtstateID = SUMA_NextState(sv);
01166                   if (nxtstateID == curstateID) break;
01167                   if (nxtstateID < 0) {
01168                      fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_NextState.\n", FuncName);
01169                      break;
01170                   }
01171                   fprintf(SUMA_STDERR,"%s: Switching from %s to %s viewing state.\n", FuncName, sv->State, sv->VSv[nxtstateID].Name);
01172 
01173                   if (!SUMA_SwitchState (SUMAg_DOv, SUMAg_N_DOv, sv, nxtstateID, sv->CurGroupName)) {
01174                      fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_SwitchState.\n", FuncName);
01175                      break;
01176                   }
01177 
01178                } while (!SUMA_VisibleSOs (sv, SUMAg_DOv, NULL) && sv->iState != origState);
01179                
01180 
01181                if (!list) list = SUMA_CreateList();
01182                SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
01183                if (!SUMA_Engine (&list)) {
01184                   fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
01185                }
01186 
01187                
01188                SUMA_UpdateViewerTitle(sv);
01189             }
01190             break;
01191 
01192          case XK_F1: 
01193             
01194             sv->ShowEyeAxis = !sv->ShowEyeAxis;
01195             SUMA_postRedisplay(w, clientData, callData);
01196             break;
01197 
01198          case XK_F2:
01199             
01200             {
01201                int *do_id, n_do_id;
01202                ++sv->ShowWorldAxis; sv->ShowWorldAxis = sv->ShowWorldAxis % SUMA_N_WAX_OPTIONS; 
01203                sv->ShowMeshAxis = 0; 
01204                do_id = SUMA_GetDO_Type(SUMAg_DOv, SUMAg_N_DOv, SO_type, &n_do_id);
01205                if (n_do_id) {
01206                   while (n_do_id) {
01207                     ((SUMA_SurfaceObject *)SUMAg_DOv[do_id[n_do_id-1]].OP)->ShowMeshAxis = sv->ShowMeshAxis;
01208                      --n_do_id;
01209                   }
01210                   SUMA_free(do_id);
01211                }
01212             }
01213             SUMA_postRedisplay(w, clientData, callData);
01214             break;
01215 
01216          case XK_F3: 
01217             if (!list) list = SUMA_CreateList();
01218             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_ToggleCrossHair, SES_Suma, sv);
01219             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
01220             if (!SUMA_Engine (&list)) {
01221                   fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
01222             }
01223             break;
01224 
01225          case XK_F4: 
01226             if (!list) list = SUMA_CreateList();
01227             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_ToggleShowSelectedNode, SES_Suma, sv);
01228             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
01229             if (!SUMA_Engine (&list)) {
01230                   fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
01231             }
01232             break;
01233 
01234          case XK_F5: 
01235             if (!list) list = SUMA_CreateList();
01236             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_ToggleShowSelectedFaceSet, SES_Suma, sv);
01237             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
01238             if (!SUMA_Engine (&list)) {
01239                   fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
01240             }
01241             break;
01242 
01243          case XK_F6: 
01244             sv->clear_color[0] = 1 - sv->clear_color[0];
01245             sv->clear_color[1] = 1 - sv->clear_color[1];
01246             sv->clear_color[2] = 1 - sv->clear_color[2];
01247             
01248             if (!list) list = SUMA_CreateList();
01249             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
01250             if (!SUMA_Engine (&list)) {
01251                   fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
01252             }
01253             break; 
01254          
01255          case XK_F7: 
01256             ++SUMAg_CF->ColMixMode;
01257             if (SUMAg_CF->ColMixMode >= SUMA_MAX_MODES) {
01258                SUMAg_CF->ColMixMode = SUMA_ORIG_MIX_MODE;
01259             }
01260             {
01261                char stmp[200];
01262                sprintf(stmp,"Using %s color mixing mode.", SUMA_ColMixModeString(SUMAg_CF->ColMixMode)); 
01263                SUMA_SLP_Note(stmp);
01264             }
01265             
01266             SUMA_SetAllRemixFlag (SUMAg_SVv, SUMAg_N_SVv);
01267             
01268             if (!list) list = SUMA_CreateList();
01269             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay_AllVisible, SES_Suma, NULL);
01270             if (!SUMA_Engine (&list)) {
01271                   fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
01272             }
01273             break; 
01274               
01275          case XK_F8: 
01276             sv->ortho = !sv->ortho;
01277             
01278             {
01279                char stmp[200];
01280                if (sv->ortho) sprintf(stmp,"Using orthographic projection viewing"); 
01281                else sprintf(stmp,"Using perspective viewing");
01282                SUMA_SLP_Note(stmp);
01283             }
01284             
01285             SUMA_SET_GL_PROJECTION(sv);
01286             SUMA_postRedisplay(w, clientData, callData);
01287             break; 
01288          
01289          case XK_F12: 
01290             
01291             {
01292                int i, nd = 20, N_vis, *Vis_IDs=NULL, NodeTot, FaceTot;
01293                GLfloat buf; 
01294                float delta_t;
01295                SUMA_SurfaceObject *SO=NULL;
01296                struct  timeval tti;
01297                char stmp[500];
01298                SUMA_STRING *SS = NULL;
01299                
01300                SS = SUMA_StringAppend (NULL, NULL);
01301 
01302                buf = sv->light0_position[2];
01303                SUMA_SLP_Note ("Timing Display speed\n"
01304                               "(20 displays): \n"); 
01305                SUMA_etime (&tti, 0);
01306                for (i=0; i< nd-1; ++i) {
01307                   fprintf (SUMA_STDOUT,"%d\t", i); fflush (SUMA_STDOUT);
01308                   sv->light0_position[2] *= -1;
01309                   glLightfv(GL_LIGHT0, GL_POSITION, sv->light0_position);
01310                   
01311                   SUMA_display(sv, SUMAg_DOv);
01312                   
01313                   glFinish();
01314                }
01315                fprintf (SUMA_STDOUT,"\n");
01316                delta_t = SUMA_etime (&tti, 1);
01317                sv->light0_position[2] = buf;
01318                glLightfv(GL_LIGHT0, GL_POSITION, sv->light0_position);
01319                SUMA_postRedisplay(w, clientData, callData);
01320                sprintf (stmp,"Elapsed time: %f seconds.\n%.2f displays/second.\n", delta_t, nd/delta_t);
01321                SS = SUMA_StringAppend (SS, stmp);
01322                
01323                
01324                Vis_IDs = (int *)SUMA_malloc(sizeof(int)*SUMAg_N_DOv);
01325                N_vis = SUMA_VisibleSOs (sv, SUMAg_DOv, Vis_IDs);
01326                NodeTot = 0;
01327                FaceTot = 0;
01328                for (i=0; i<N_vis;++i) {
01329                   SO = (SUMA_SurfaceObject *)SUMAg_DOv[Vis_IDs[i]].OP;
01330                   FaceTot += SO->N_FaceSet;
01331                   NodeTot += SO->N_Node;   
01332                }
01333                if (N_vis) {
01334                   sprintf (stmp,"In Polymode %d, rendered \n%.2f Ktri/sec %.2f Kpnt/sec.\n",
01335                      sv->PolyMode,
01336                      (float)FaceTot / 1000.0 / delta_t  , 
01337                      (float)NodeTot / 1000.0 / delta_t );
01338                   SS = SUMA_StringAppend (SS, stmp);
01339                }
01340                
01341                SUMA_SLP_Note(SS->s);
01342                
01343                if (Vis_IDs) SUMA_free(Vis_IDs);
01344                SUMA_free(SS->s);
01345                SUMA_free(SS);
01346                
01347             } 
01348             break;
01349          
01350          case XK_Home:   
01351             
01352             if (!list) list = SUMA_CreateList();
01353             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Home, SES_Suma, sv);
01354             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_FOVreset, SES_Suma, sv);
01355             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
01356             if (!SUMA_Engine (&list)) {
01357                   fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
01358             }
01359             break;
01360          
01361          case XK_Left:   
01362             
01363             if ((Kev.state & ControlMask) && (Kev.state & ShiftMask)) {
01364                
01365             }else if (Kev.state & ShiftMask) {
01366                
01367                sv->GVS[sv->StdView].translateVec[0] -= (GLfloat)sv->GVS[sv->StdView].ArrowtranslateDeltaX/(float)sv->WindWidth*sv->GVS[sv->StdView].TranslateGain;
01368                
01369                SUMA_postRedisplay(w, clientData, callData);
01370             }else if (Kev.state & ControlMask){
01371                float a[3], cQ[4], dQ[4];
01372                 
01373                a[0] = 1.0; a[1] = 0.0;
01374                axis_to_quat(a, SUMA_PI/2.0, cQ);
01375                
01376                a[0] = 0.0; a[1] = 1.0; a[2] = 0.0;
01377                axis_to_quat(a, SUMA_PI/2.0, dQ);
01378                
01379                add_quats (dQ, cQ, sv->GVS[sv->StdView].currentQuat);
01380                SUMA_postRedisplay(w, clientData, callData);
01381             }else if (Kev.state & Mod1Mask  || Kev.state & Mod2Mask) {
01382                
01383             }else {
01384                
01385                trackball_Phi(sv->GVS[sv->StdView].deltaQuat, 
01386                   ArrowDeltaRot, 0.0, 
01387                   -ArrowDeltaRot, 0.0, 
01388                   sv->ArrowRotationAngle);
01389                add_quats (sv->GVS[sv->StdView].deltaQuat, sv->GVS[sv->StdView].currentQuat, sv->GVS[sv->StdView].currentQuat);
01390                sv->GVS[sv->StdView].spinDeltaX = -2.0*ArrowDeltaRot*sv->WindWidth;
01391                sv->GVS[sv->StdView].spinDeltaY = 0;
01392                SUMA_postRedisplay(w, clientData, callData);
01393             }
01394                
01395             break;
01396 
01397          case XK_Right:   
01398             
01399             if ((Kev.state & ControlMask) && (Kev.state & ShiftMask)) {
01400                
01401             }else if (Kev.state & ShiftMask) {
01402                
01403                sv->GVS[sv->StdView].translateVec[0] += (GLfloat)sv->GVS[sv->StdView].ArrowtranslateDeltaX/(float)sv->WindWidth*sv->GVS[sv->StdView].TranslateGain;
01404                
01405                SUMA_postRedisplay(w, clientData, callData);
01406             }else if (Kev.state & ControlMask){
01407                float a[3], cQ[4], dQ[4];
01408                 
01409                a[0] = 1.0; a[1] = 0.0; a[2] = 0.0;
01410                axis_to_quat(a, SUMA_PI/2.0, cQ);
01411                
01412                a[0] = 0.0; a[1] = 1.0;
01413                axis_to_quat(a, -SUMA_PI/2.0, dQ);
01414                
01415                add_quats (dQ, cQ, sv->GVS[sv->StdView].currentQuat);
01416                SUMA_postRedisplay(w, clientData, callData);
01417                
01418             }else if (Kev.state & Mod1Mask || Kev.state & Mod2Mask) {
01419                
01420             }else {
01421                
01422                trackball_Phi(sv->GVS[sv->StdView].deltaQuat, 
01423                   -ArrowDeltaRot, 0.0, 
01424                   ArrowDeltaRot, 0.0, 
01425                   sv->ArrowRotationAngle);
01426                add_quats (sv->GVS[sv->StdView].deltaQuat, sv->GVS[sv->StdView].currentQuat, sv->GVS[sv->StdView].currentQuat);
01427                sv->GVS[sv->StdView].spinDeltaX = 2.0*ArrowDeltaRot*sv->WindWidth;
01428                sv->GVS[sv->StdView].spinDeltaY = 0;
01429                SUMA_postRedisplay(w, clientData, callData);
01430             }
01431             break;
01432 
01433          case XK_Down:   
01434             
01435             if ((Kev.state & ControlMask) && (Kev.state & ShiftMask)) {
01436                float a[3], cQ[4], dQ[4];
01437                
01438                
01439                a[0] = 1.0; a[1] = 0.0; a[2] = 0.0;
01440                axis_to_quat(a, SUMA_PI/2, cQ);
01441                
01442                a[0] = 0.0; a[1] = 1.0; a[2] = 0.0;
01443                axis_to_quat(a, SUMA_PI, dQ);
01444                
01445                add_quats (dQ, cQ, sv->GVS[sv->StdView].currentQuat);
01446                SUMA_postRedisplay(w, clientData, callData);
01447             }else if (Kev.state & ShiftMask) {
01448                
01449                
01450                sv->GVS[sv->StdView].translateVec[1] -=  (GLfloat)sv->GVS[sv->StdView].ArrowtranslateDeltaY/(float)sv->WindHeight*sv->GVS[sv->StdView].TranslateGain;
01451                SUMA_postRedisplay(w, clientData, callData);
01452             }else if (Kev.state & ControlMask){
01453                
01454                
01455                float a[3];
01456                
01457                a[0] = 0.0; a[1] = 1.0; a[2] = 0.0;
01458                axis_to_quat(a, SUMA_PI, sv->GVS[sv->StdView].currentQuat);
01459                SUMA_postRedisplay(w, clientData, callData);
01460             }else if (Kev.state & Mod1Mask || Kev.state & Mod2Mask) {
01461                
01462             }else {
01463                
01464                trackball_Phi(sv->GVS[sv->StdView].deltaQuat, 
01465                   0.0, ArrowDeltaRot, 
01466                   0.0, -ArrowDeltaRot, 
01467                   sv->ArrowRotationAngle);
01468                
01469 
01470                add_quats (sv->GVS[sv->StdView].deltaQuat, sv->GVS[sv->StdView].currentQuat, sv->GVS[sv->StdView].currentQuat);
01471                
01472                sv->GVS[sv->StdView].spinDeltaX = 0;
01473                sv->GVS[sv->StdView].spinDeltaY = -2.0*ArrowDeltaRot*sv->WindHeight;
01474                SUMA_postRedisplay(w, clientData, callData);
01475             }
01476             
01477             break;
01478 
01479          case XK_Up: 
01480             
01481             if ((Kev.state & ControlMask) && (Kev.state & ShiftMask)) {
01482                float a[3];
01483                
01484                
01485                a[0] = 1.0; a[1] = 0.0; a[2] = 0.0;
01486                axis_to_quat(a, SUMA_PI/2, sv->GVS[sv->StdView].currentQuat);
01487                SUMA_postRedisplay(w, clientData, callData);
01488             }else if (Kev.state & ShiftMask) {
01489                
01490                sv->GVS[sv->StdView].translateVec[1] +=  (GLfloat)sv->GVS[sv->StdView].ArrowtranslateDeltaY/(float)sv->WindHeight*sv->GVS[sv->StdView].TranslateGain;
01491                SUMA_postRedisplay(w, clientData, callData);
01492             }else if (Kev.state & ControlMask){
01493                
01494                
01495                float a[3];
01496                
01497                a[0] = 1.0; a[1] = 0.0; a[2] = 0.0;
01498                axis_to_quat(a, 0, sv->GVS[sv->StdView].currentQuat);
01499                SUMA_postRedisplay(w, clientData, callData);
01500             }else if (Kev.state & Mod1Mask || Kev.state & Mod2Mask) {
01501                
01502             }else {
01503                if (LocalHead) fprintf (SUMA_STDERR,"%s: Vanilla kind.\n", FuncName);
01504                trackball_Phi(sv->GVS[sv->StdView].deltaQuat, 
01505                   0.0, -ArrowDeltaRot, 
01506                   0.0, ArrowDeltaRot, 
01507                   sv->ArrowRotationAngle);
01508                if (LocalHead) {
01509                   fprintf(stdout,"\ncurrentQuat\n");
01510                   for (ii=0; ii<4; ++ii) { 
01511                      fprintf(stdout,"%f\t", sv->GVS[sv->StdView].currentQuat[ii]);
01512                   } 
01513                   fprintf(stdout,"\n");
01514                   fprintf(stdout,"\ndeltaQuat\n");
01515                   for (ii=0; ii<4; ++ii) { 
01516                      fprintf(stdout,"%f\t", sv->GVS[sv->StdView].deltaQuat[ii]);
01517                   } 
01518                   fprintf(stdout,"\n");
01519                }
01520                add_quats (sv->GVS[sv->StdView].deltaQuat, sv->GVS[sv->StdView].currentQuat, sv->GVS[sv->StdView].currentQuat);
01521                if (LocalHead) {
01522                   fprintf(stdout,"\nnewQuat\n");
01523                   for (ii=0; ii<4; ++ii) { 
01524                      fprintf(stdout,"%f\t", sv->GVS[sv->StdView].currentQuat[ii]);
01525                   } 
01526                   fprintf(stdout,"\n");
01527                }
01528                sv->GVS[sv->StdView].spinDeltaX = 0;
01529                sv->GVS[sv->StdView].spinDeltaY = 2.0*ArrowDeltaRot*sv->WindHeight;
01530                SUMA_postRedisplay(w, clientData, callData);
01531                   
01532             }
01533             
01534             break;
01535 
01536          default:
01537             break;
01538 
01539       } 
01540    break;
01541    
01542    case ButtonPress:
01543       if (LocalHead) fprintf(stdout,"In ButtonPress\n");      
01544       pButton = Bev.button;
01545       if (SUMAg_CF->SwapButtons_1_3 || (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
01546          if (pButton == Button1) pButton = Button3;
01547          else if (pButton == Button3) pButton = Button1;
01548       }
01549      
01550      
01551       if (Bev.time - B1time < SUMA_DOUBLE_CLICK_MAX_DELAY) {
01552          if (LocalHead) fprintf(SUMA_STDERR, "%s: Double click.\n", FuncName);
01553          DoubleClick = YUP;
01554       } else {
01555          DoubleClick = NOPE;
01556       }
01557       B1time = Bev.time; 
01558             
01559       switch (pButton) { 
01560          case Button1:
01561             if (Bev.state & Button2Mask) {
01562                
01563                
01564                sv->GVS[sv->StdView].zoomBegin = (float)Bev.y;
01565                sv->GVS[sv->StdView].zoomDelta = 0;   
01566             }else {
01567                bevx=(float)Bev.x; bevy = (float)Bev.y;
01568                
01569                
01570                sv->GVS[sv->StdView].spinBeginX = bevx;
01571                sv->GVS[sv->StdView].spinBeginY = bevy;
01572                sv->GVS[sv->StdView].spinDeltaX = 0;
01573                sv->GVS[sv->StdView].spinDeltaY = 0;   
01574                
01575                ii = SUMA_WhichSV(sv, SUMAg_SVv, SUMAg_N_SVv);
01576                if (SUMAg_CF->ViewLocked[ii]) {
01577                   for (it=0; it < SUMAg_N_SVv; ++it) {
01578                      svi = &SUMAg_SVv[it];
01579                      if (it != ii && SUMAg_CF->ViewLocked[it]) {
01580                         svi->GVS[svi->StdView].spinBeginX = bevx;
01581                         svi->GVS[svi->StdView].spinBeginY = bevy;
01582                         svi->GVS[svi->StdView].spinDeltaX = 0;
01583                         svi->GVS[svi->StdView].spinDeltaY = 0; 
01584                      }  
01585                   }
01586                }
01587             }
01588             break;
01589             
01590          case Button2:
01591             if (Bev.state & ShiftMask) {
01592                
01593                
01594                sv->GVS[sv->StdView].zoomBegin = (float)Bev.y;
01595                sv->GVS[sv->StdView].zoomDelta = 0;   
01596             } else {   
01597                
01598                
01599                bevx = (float)Bev.x; bevy = (float)Bev.y;
01600                sv->GVS[sv->StdView].translateBeginX = bevx;;
01601                sv->GVS[sv->StdView].translateBeginY = bevy;
01602                sv->GVS[sv->StdView].translateDeltaX = 0.0;
01603                sv->GVS[sv->StdView].translateDeltaY = 0.0;
01604             }
01605             break;
01606             
01607          case Button3:
01608                if (LocalHead) fprintf(SUMA_STDERR,"%s: Button 3 downplain jane, viewer #%d : X=%f, Y = %f\n", \
01609                   FuncName, SUMA_WhichSV(sv, SUMAg_SVv, SUMAg_N_SVv), (float)Bev.x, (float)Bev.y);
01610                
01611                #if 0
01612                
01613                if (Bev.state & ShiftMask && SUMAg_CF->ROI_mode && sv->Focus_SO_ID >= 0) {
01614                   
01615                   ROI_mode = YUP;     
01616                }else {
01617                   ROI_mode = NOPE;
01618                }
01619                #endif
01620                
01621                if (SUMAg_CF->ROI_mode && sv->Focus_SO_ID >= 0 && !(Bev.state & ShiftMask)) {
01622                   
01623                   ROI_mode = YUP;     
01624                }else {
01625                   ROI_mode = NOPE;
01626                }
01627                
01628                if (!DoubleClick) {
01629                
01630                   
01631                   if (SUMAg_N_SVv > 1) {
01632                      ii = SUMA_WhichViewerInMomentum (SUMAg_SVv, SUMAg_N_SVv, NULL);
01633                      if (ii >= 0) {
01634                         sprintf (s, "You cannot select or draw while viewers\n"
01635                                     "(like %c) are in momentum mode.\n", ii+65);
01636                         SUMA_RegisterMessage (SUMAg_CF->MessageList, 
01637                                               s, FuncName, SMT_Error, SMA_LogAndPopup);
01638                         SUMA_RETURNe;
01639                      }
01640                   }  
01641                   
01642                   
01643                   ii = SUMA_RegisteredSOs(sv, SUMAg_DOv, NULL);
01644                   if (ii == 0) { 
01645                      break;
01646                   }
01647 
01648 
01649                   if (!SUMA_GetSelectionLine (sv, (int)Bev.x, (int)Bev.y, sv->Pick0, sv->Pick1, 0, NULL, NULL, NULL)) {
01650                      fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_GetSelectionLine.\n", FuncName);
01651                      break;
01652                   } 
01653 
01654 
01655                   
01656                   hit = SUMA_MarkLineSurfaceIntersect (sv, SUMAg_DOv);
01657                   if (hit < 0) {
01658                      fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_MarkLineSurfaceIntersect.\n", FuncName);
01659                      break;
01660                   }else if (hit == 0) { 
01661                      break;
01662                   }
01663 
01664                   
01665                }
01666                
01667                if (ROI_mode) {
01668                   
01669                   if (!SUMA_CreateBrushStroke (sv)) {
01670                      SUMA_RegisterMessage (SUMAg_CF->MessageList, 
01671                                            "Failed to create BrushStroke.", FuncName, 
01672                                            SMT_Error, SMA_LogAndPopup);
01673                      SUMA_RETURNe;
01674 
01675                   }
01676 
01677                   SUMA_AddToBrushStroke (sv, (int)Bev.x, (int)Bev.y, sv->Pick0,
01678                      sv->Pick1, YUP); 
01679                }
01680                
01681                
01682                
01683                
01684                sv->ResetGLStateVariables = YUP;
01685                SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA); 
01686                
01687                
01688             break;
01689       } 
01690       break;
01691       
01692    case ButtonRelease:
01693       if (LocalHead) fprintf(SUMA_STDERR,"%s: In ButtonRelease\n", FuncName); 
01694       rButton = Bev.button;
01695       if (SUMAg_CF->SwapButtons_1_3 || (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
01696          if (rButton == Button1) rButton = Button3;
01697          else if (rButton == Button3) rButton = Button1;
01698       }
01699       switch (rButton) { 
01700          case Button3:
01701             if (LocalHead) fprintf(SUMA_STDERR,"%s: In ButtonRelease3\n", FuncName); 
01702             if (SUMAg_CF->ROI_mode) {
01703                SUMA_DRAWN_ROI *DrawnROI = NULL;
01704                SUMA_SurfaceObject *SO = NULL;
01705                SUMA_BRUSH_STROKE_ACTION BsA=SUMA_BSA_Undefined;
01706                
01707                if (sv->BS) { 
01708                   
01709                   if (DoubleClick) BsA = SUMA_BSA_JoinEnds;
01710                   else BsA = SUMA_BSA_AppendStrokeOrFill;
01711                   if (!(DrawnROI = SUMA_ProcessBrushStroke (sv, BsA))) {
01712                      if (LocalHead) fprintf (SUMA_STDERR, "%s: NULL DrawnROI returned.\n", FuncName);
01713                      SUMA_ClearBrushStroke (sv);
01714                      break;
01715                   }
01716 
01717                   
01718                   if (LocalHead) SUMA_ShowDrawnROI (DrawnROI, NULL, NOPE);
01719 
01720                   
01721                   if (LocalHead) SUMA_ShowBrushStroke (sv, NULL);
01722 
01723                   
01724                   SUMA_ClearBrushStroke (sv);
01725 
01726                   
01727                   if (!list) list = SUMA_CreateList ();
01728                   SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list, SE_RedisplayNow_AllOtherVisible, SES_SumaWidget, sv);
01729                   SUMA_Engine (&list);
01730                
01731                   
01732                   sv->ResetGLStateVariables = YUP;
01733                   SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
01734 
01735                }
01736             } 
01737             
01738          break;
01739       } 
01740       break;
01741       
01742    case MotionNotify:
01743       if (LocalHead) fprintf(stdout,"In MotionNotify\n"); 
01744       if (SUMAg_CF->SwapButtons_1_3 || (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
01745         if (((Mev.state & Button3MotionMask) && (Mev.state & Button2MotionMask)) || ((Mev.state & Button2MotionMask) && (Mev.state & ShiftMask))) {
01746             mButton = SUMA_Button_12_Motion;
01747          } else if(Mev.state & Button3MotionMask) {
01748             mButton = SUMA_Button_1_Motion;
01749          }else if(Mev.state & Button2MotionMask) { 
01750             mButton = SUMA_Button_2_Motion;
01751          }else if(Mev.state & Button1MotionMask) { 
01752             mButton = SUMA_Button_3_Motion;
01753          }else {
01754             break;
01755          } 
01756       } else {
01757          if (((Mev.state & Button1MotionMask) && (Mev.state & Button2MotionMask)) || ((Mev.state & Button2MotionMask) && (Mev.state & ShiftMask))) {
01758             mButton = SUMA_Button_12_Motion;
01759          } else if(Mev.state & Button1MotionMask) {
01760             mButton = SUMA_Button_1_Motion;
01761          }else if(Mev.state & Button2MotionMask) { 
01762             mButton = SUMA_Button_2_Motion;
01763          } else if(Mev.state & Button3MotionMask) { 
01764             mButton = SUMA_Button_3_Motion;
01765          }else {
01766             break;
01767          }
01768       }
01769       
01770       switch (mButton) {
01771          case SUMA_Button_12_Motion:
01772          case SUMA_Button_2_Shift_Motion:
01773             
01774             sv->GVS[sv->StdView].zoomDelta = 1.0 + (float)((int)Mev.y - sv->GVS[sv->StdView].zoomBegin)/MOUSE_ZOOM_FACT;
01775             if (sv->GVS[sv->StdView].zoomDelta > 2.0) sv->GVS[sv->StdView].zoomDelta = 2.0;
01776             else if (sv->GVS[sv->StdView].zoomDelta < 0.5) sv->GVS[sv->StdView].zoomDelta = 0.5;
01777             sv->FOV[sv->iState] /= sv->GVS[sv->StdView].zoomDelta;
01778             if (sv->FOV[sv->iState] < FOV_MIN) sv->FOV[sv->iState] = FOV_MIN;
01779             else if (sv->FOV[sv->iState] > FOV_MAX) sv->FOV[sv->iState] = FOV_MAX;
01780                sv->GVS[sv->StdView].zoomBegin = (float)(int)Mev.y;
01781                
01782             
01783             if (sv->ZoomCompensate) {
01784                sv->ZoomCompensate = sv->FOV[sv->iState] / FOV_INITIAL;
01785                if (sv->ZoomCompensate > 1) sv->ZoomCompensate = 1.0; 
01786                else if (sv->ZoomCompensate < 0.005) sv->ZoomCompensate = 0.005;  
01787             }
01788             ii = SUMA_WhichSV (sv, SUMAg_SVv, SUMAg_N_SVv);
01789             SUMA_postRedisplay(w, clientData, callData);    
01790             break;
01791             
01792          case SUMA_Button_1_Motion:     
01793             
01794             mevx = (float)Mev.x;
01795             mevy = (float)Mev.y;
01796             wwid = (float)sv->WindWidth;
01797             whei = (float)sv->WindHeight;
01798             
01799             if (sv->ZoomCompensate) {
01800                zc_fac = sv->ZoomCompensate;
01801             }else {
01802                zc_fac = 1.0;
01803             }            
01804             sv->GVS[sv->StdView].spinDeltaX = (mevx - sv->GVS[sv->StdView].spinBeginX);
01805             sv->GVS[sv->StdView].spinDeltaY = (mevy - sv->GVS[sv->StdView].spinBeginY);
01806             
01807             
01808 
01809 
01810 
01811 
01812 
01813 
01814 
01815 
01816 
01817 
01818             if (sv->GVS[sv->StdView].spinDeltaX || sv->GVS[sv->StdView].spinDeltaY){
01819                trackball(  sv->GVS[sv->StdView].deltaQuat, 
01820                            (2*sv->GVS[sv->StdView].spinBeginX - wwid)/wwid*zc_fac, 
01821                            (whei - 2*sv->GVS[sv->StdView].spinBeginY)/whei*zc_fac,
01822                            (2*mevx - wwid)/wwid*zc_fac, 
01823                            (whei - 2*mevy)/whei*zc_fac); 
01824                sv->GVS[sv->StdView].spinBeginX = mevx;
01825                sv->GVS[sv->StdView].spinBeginY = mevy;
01826                add_quats (sv->GVS[sv->StdView].deltaQuat, sv->GVS[sv->StdView].currentQuat, sv->GVS[sv->StdView].currentQuat);
01827                
01828                ii = SUMA_WhichSV(sv, SUMAg_SVv, SUMAg_N_SVv);
01829                if (ii < 0) {
01830                   fprintf (SUMA_STDERR,"Error %s: Failed to find index of sv.\n", FuncName);
01831                   break;
01832                }
01833                if (!SUMAg_CF->ViewLocked[ii]) { 
01834                   SUMA_postRedisplay(w, clientData, callData);    
01835                } else { 
01836                   DList *list = NULL;
01837                   SUMA_EngineData *ED = NULL;
01838                   SUMA_STANDARD_VIEWS ed_sv, ed_svi;
01839                   
01840                   list = SUMA_CreateList ();
01841                   ED = SUMA_InitializeEngineListData (SE_RedisplayNow);
01842                   SUMA_RegisterEngineListCommand (list, ED,
01843                                                    SEF_Empty, NULL,
01844                                                    SES_Suma, (void *)sv, NOPE,
01845                                                    SEI_Head, NULL);
01846                   ed_sv = SUMA_BestStandardView(sv, SUMAg_DOv, SUMAg_N_DOv);
01847                   for (it=0; it < SUMAg_N_SVv; ++it) {
01848                      svi = &SUMAg_SVv[it];
01849                      ed_svi = SUMA_BestStandardView(svi, SUMAg_DOv, SUMAg_N_DOv);
01850                      if (it != ii && SUMAg_CF->ViewLocked[it] && ed_svi == ed_sv) {
01851                         
01852                         svi->GVS[svi->StdView].spinBeginX = sv->GVS[sv->StdView].spinBeginX;
01853                         svi->GVS[svi->StdView].spinBeginY = sv->GVS[sv->StdView].spinBeginY;
01854                         SUMA_COPY_VEC(sv->GVS[sv->StdView].deltaQuat, svi->GVS[svi->StdView].deltaQuat, 4, float, float);
01855                         SUMA_COPY_VEC(sv->GVS[sv->StdView].currentQuat, svi->GVS[svi->StdView].currentQuat, 4, float, float);
01856                        
01857                         
01858                         ED = SUMA_InitializeEngineListData (SE_RedisplayNow);
01859                         SUMA_RegisterEngineListCommand ( list, ED,
01860                                                          SEF_Empty, NULL,
01861                                                          SES_Suma, (void *)svi, NOPE,
01862                                                          SEI_Head, NULL); 
01863                      }
01864                   }
01865                   if (!SUMA_Engine (&list)) {
01866                      fprintf (SUMA_STDERR, "Error %s: Failed calling SUMA_Engine.\n", FuncName);
01867                      break;
01868                   }
01869                }
01870             }
01871 
01872             break;
01873             
01874          case SUMA_Button_2_Motion:
01875             
01876             mevx = (float)Mev.x; mevy = (float)Mev.y;
01877             if (sv->ZoomCompensate) {
01878                zc_fac = sv->ZoomCompensate;
01879             }else {
01880                zc_fac = 1.0;
01881             }
01882             sv->GVS[sv->StdView].translateDeltaX =  (mevx - sv->GVS[sv->StdView].translateBeginX)/(float)sv->WindWidth*sv->GVS[sv->StdView].TranslateGain;
01883             sv->GVS[sv->StdView].translateDeltaY = -(mevy - sv->GVS[sv->StdView].translateBeginY)/(float)sv->WindHeight*sv->GVS[sv->StdView].TranslateGain;
01884             
01885             if (sv->GVS[sv->StdView].translateDeltaX || sv->GVS[sv->StdView].translateDeltaY){
01886                sv->GVS[sv->StdView].translateVec[0] += (GLfloat)sv->GVS[sv->StdView].translateDeltaX * zc_fac;
01887                sv->GVS[sv->StdView].translateVec[1] += (GLfloat)sv->GVS[sv->StdView].translateDeltaY * zc_fac;
01888                sv->GVS[sv->StdView].translateBeginX = mevx;
01889                sv->GVS[sv->StdView].translateBeginY = mevy;
01890                SUMA_postRedisplay(w, clientData, callData);
01891             }  
01892             break;
01893          
01894          case SUMA_Button_3_Motion:
01895             if (LocalHead) fprintf(SUMA_STDERR,"%s: In motion, Butt3 \n", FuncName); 
01896             
01897             if (SUMAg_CF->ROI_mode && sv->Focus_SO_ID >= 0 && sv->BS) {
01898                
01899                ii = SUMA_RegisteredSOs(sv, SUMAg_DOv, NULL);
01900                if (ii == 0) { 
01901                   break;
01902                }
01903 
01904 
01905                if (!SUMA_GetSelectionLine (sv, (int)Mev.x, (int)Mev.y, sv->Pick0, sv->Pick1, 0, NULL, NULL, NULL)) {
01906                   fprintf (SUMA_STDERR, "Error %s: Failed in "
01907                                        "SUMA_GetSelectionLine.\n", FuncName);
01908                   break;
01909                } 
01910 
01911                if (!SUMA_AddToBrushStroke (sv, (int)Mev.x, (int)Mev.y,
01912                      sv->Pick0, sv->Pick1, YUP)) {
01913                   SUMA_RegisterMessage (SUMAg_CF->MessageList, 
01914                                         "Failed to add to BrushStroke.", 
01915                                         FuncName, 
01916                                         SMT_Error, SMA_LogAndPopup);
01917                   break;
01918                }
01919             }
01920             
01921             break;
01922       }
01923       
01924       
01925       break;
01926   }
01927 
01928    SUMA_RETURNe;
01929 }
01930 
01931 
01932 
01933 
01934 
01935 
01936 void SUMA_momentum(XtPointer clientData, XtIntervalId *id)
01937 {
01938    static char FuncName[]={"SUMA_momentum"};
01939    static int ReDisp;
01940    Widget w;
01941    int isv;
01942    SUMA_SurfaceViewer *sv;
01943    
01944    SUMA_ENTRY;
01945    
01946    
01947    w = (Widget)clientData;
01948    
01949    
01950    SUMA_ANY_WIDGET2SV((Widget)clientData, sv, isv);
01951    if (isv < 0) {
01952       fprintf (SUMA_STDERR, "Error %s: Failed in macro SUMA_ANY_WIDGET2SV.\n", FuncName);
01953       SUMA_RETURNe;
01954    }
01955 
01956    
01957    ReDisp = 0;
01958    if ( ((sv->GVS[sv->StdView].spinDeltaX*sv->GVS[sv->StdView].spinDeltaX) > sv->GVS[sv->StdView].MinIdleDelta ) || ((sv->GVS[sv->StdView].spinDeltaY*sv->GVS[sv->StdView].spinDeltaY) > sv->GVS[sv->StdView].MinIdleDelta ) ) 
01959       {  
01960          
01961          add_quats (sv->GVS[sv->StdView].deltaQuat, sv->GVS[sv->StdView].currentQuat, sv->GVS[sv->StdView].currentQuat);
01962          ReDisp = 1;
01963       }
01964    if ( ((sv->GVS[sv->StdView].translateDeltaX*sv->GVS[sv->StdView].translateDeltaX) > sv->GVS[sv->StdView].MinIdleDelta ) || ((sv->GVS[sv->StdView].translateDeltaY*sv->GVS[sv->StdView].translateDeltaY) > sv->GVS[sv->StdView].MinIdleDelta ) )
01965       { 
01966          sv->GVS[sv->StdView].translateVec[0] += (GLfloat)sv->GVS[sv->StdView].translateDeltaX;
01967          sv->GVS[sv->StdView].translateVec[1] += (GLfloat)sv->GVS[sv->StdView].translateDeltaY;
01968          ReDisp = 1;
01969       }
01970    if (ReDisp) {
01971       
01972       SUMA_postRedisplay(w, NULL, NULL);
01973    }
01974     sv->X->MOMENTUMID = XtAppAddTimeOut(SUMAg_CF->X->App, 1, SUMA_momentum, (XtPointer) w); 
01975 
01976   SUMA_RETURNe;         
01977 }
01978 
01979  
01980 
01981 
01982 
01983 
01984 
01985 
01986 
01987 
01988 
01989 
01990 
01991 int SUMA_MarkLineSurfaceIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov)
01992 {
01993    float P0f[3], P1f[3];
01994    static char FuncName[]={"SUMA_MarkLineSurfaceIntersect"};
01995    int NP; 
01996    SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL, *MTIi = NULL;
01997    float delta_t_tmp, dmin; 
01998    struct timeval tt_tmp; 
01999    int ip, it, id, iv3[3], ii, N_SOlist, SOlist[SUMA_MAX_DISPLAYABLE_OBJECTS], imin;
02000    char sfield[100], sdestination[100], CommString[SUMA_MAX_COMMAND_LENGTH];
02001    SUMA_EngineData *ED = NULL;
02002    DList *list = NULL;
02003    DListElmt *SetNodeElem = NULL;
02004    SUMA_SurfaceObject *SO = NULL;
02005    SUMA_Boolean LocalHead = NOPE;
02006 
02007    SUMA_ENTRY;
02008 
02009 
02010    P0f[0] = sv->Pick0[0];
02011    P0f[1] = sv->Pick0[1];
02012    P0f[2] = sv->Pick0[2];
02013    P1f[0] = sv->Pick1[0];
02014    P1f[1] = sv->Pick1[1];
02015    P1f[2] = sv->Pick1[2];
02016    
02017    N_SOlist = SUMA_VisibleSOs(sv, dov, SOlist);
02018    imin = -1;
02019    dmin = 10000000.0;
02020    for (ii=0; ii < N_SOlist; ++ii) { 
02021       if (LocalHead) fprintf (SUMA_STDERR, "%s: working %d/%d shown surfaces ...\n", FuncName, ii, N_SOlist);
02022       SO = (SUMA_SurfaceObject *)dov[SOlist[ii]].OP;
02023       if (SO->FaceSetDim != 3) {
02024          fprintf(SUMA_STDERR,"Error %s: SUMA_MT_intersect_triangle only works for triangular meshes.\n", FuncName);
02025       } else {
02026 
02027          SUMA_etime (&tt_tmp, 0);
02028 
02029          MTIi = SUMA_MT_intersect_triangle(P0f, P1f, SO->NodeList, SO->N_Node, SO->FaceSetList, SO->N_FaceSet, NULL);
02030 
02031          delta_t_tmp = SUMA_etime (&tt_tmp, 1);
02032          if (LocalHead) fprintf (SUMA_STDERR, "Local Debug %s: Intersection took %f seconds.\n", FuncName, delta_t_tmp);
02033 
02034          if (MTIi == NULL) {
02035             fprintf(SUMA_STDERR,"Error %s: SUMA_MT_intersect_triangle failed.\n", FuncName);
02036             SUMA_RETURN (-1);
02037          }
02038          
02039          if (MTIi->N_hits) { 
02040             if (MTIi->t[MTIi->ifacemin] < dmin) {
02041                if (LocalHead) fprintf (SUMA_STDERR, "%s: A minimum for surface %d.\n", FuncName, ii);
02042                dmin = MTIi->t[MTIi->ifacemin];
02043                imin = SOlist[ii];
02044                MTI = MTIi;
02045             }else {     
02046                
02047                if (LocalHead) fprintf (SUMA_STDERR, "%s: ii=%d freeing MTIi...\n", FuncName, ii);
02048                MTIi = SUMA_Free_MT_intersect_triangle(MTIi); 
02049             }
02050          }else {
02051             
02052            if (LocalHead) fprintf (SUMA_STDERR, "%s: ii=%d freeing MTIi no hits...\n", FuncName, ii);
02053            MTIi = SUMA_Free_MT_intersect_triangle(MTIi); 
02054         }
02055       }
02056     } 
02057 
02058    if (LocalHead) fprintf (SUMA_STDERR, "%s: Closest surface is indexed %d in DOv.\n", FuncName, imin);
02059       
02060    
02061    if (imin >= 0) {
02062       sv->Focus_SO_ID = imin;
02063       SUMA_UpdateViewerTitle(sv);
02064       SO = (SUMA_SurfaceObject *)dov[imin].OP;
02065       NP = SO->FaceSetDim;
02066       ip = NP * MTI->ifacemin;
02067 
02068       
02069       if (SO->SurfCont->TopLevelShell)   SUMA_Init_SurfCont_SurfParam(SO);
02070 
02071       
02072       fprintf(SUMA_STDOUT, "\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
02073       fprintf(SUMA_STDOUT, "Selected surface %s (Focus_SO_ID # %d). FaceSet %d, Closest Node %d\n", 
02074          SO->Label, sv->Focus_SO_ID, MTI->ifacemin, MTI->inodemin);
02075       fprintf(SUMA_STDOUT, "Nodes forming closest FaceSet:\n");
02076       fprintf(SUMA_STDOUT, "%d, %d, %d\n", \
02077       SO->FaceSetList[ip], SO->FaceSetList[ip+1],SO->FaceSetList[ip+2]);
02078 
02079       fprintf (SUMA_STDOUT,"Coordinates of Nodes forming closest FaceSet:\n");
02080       for (it=0; it < 3; ++it) { 
02081 
02082          id = SO->NodeDim * SO->FaceSetList[ip+it];
02083          fprintf(SUMA_STDOUT, "%f, %f, %f\n", SO->NodeList[id],\
02084                                                 SO->NodeList[id+1],\
02085                                                 SO->NodeList[id+2]);
02086       }
02087       fprintf(SUMA_STDOUT, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
02088 
02089       
02090       it = MTI->inodemin;
02091       if (!list) list = SUMA_CreateList();
02092       ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
02093       SetNodeElem = SUMA_RegisterEngineListCommand (  list, ED, 
02094                                              SEF_i, (void*)&it,
02095                                              SES_Suma, (void *)sv, NOPE,
02096                                              SEI_Head, NULL);
02097       if (!SetNodeElem) {
02098          fprintf(SUMA_STDERR,"Error %s: Failed to register SetNodeElem\n", FuncName);
02099          SUMA_RETURN (-1);
02100       }
02101 
02102       
02103       it = MTI->ifacemin;
02104       ED = SUMA_InitializeEngineListData (SE_SetSelectedFaceSet);
02105       if (!SUMA_RegisterEngineListCommand (  list, ED, 
02106                                              SEF_i, (void*)&it,
02107                                              SES_Suma, (void *)sv, NOPE,
02108                                              SEI_Head, NULL)) {
02109          fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
02110          SUMA_RETURN (-1);
02111       }
02112       
02113       
02114       ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
02115       if (!SUMA_RegisterEngineListCommand (  list, ED, 
02116                                              SEF_fv3, (void*)MTI->P,
02117                                              SES_Suma, (void *)sv, NOPE,
02118                                              SEI_Head, NULL)) {
02119          fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
02120          SUMA_RETURN (-1);
02121       }
02122 
02123       
02124       iv3[0] = SUMA_findSO_inDOv(SO->idcode_str, SUMAg_DOv, SUMAg_N_DOv);
02125       iv3[1] = MTI->inodemin;
02126       ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
02127       if (!SUMA_RegisterEngineListCommand (  list, ED, 
02128                                              SEF_iv3, (void*)iv3,
02129                                              SES_Suma, (void *)sv, NOPE,
02130                                              SEI_Head, NULL)) {
02131          fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
02132          SUMA_RETURN (-1);
02133       }
02134       
02135       
02136       if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
02137          if (LocalHead) fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
02138          
02139          if (!list) list = SUMA_CreateList();
02140          SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list, SE_SetAfniCrossHair, SES_Suma, sv);
02141          if (!SUMA_Engine (&list)) {
02142             fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
02143             SUMA_RETURN (-1);
02144          }
02145       }else {
02146          if (LocalHead) fprintf(SUMA_STDERR,"%s: No Notification to AFNI.\n", FuncName);
02147       }
02148 
02149       
02150 
02151 
02152       if (!list) list = SUMA_CreateList();
02153       ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
02154       if (!SUMA_RegisterEngineListCommand (  list, ED, 
02155                                              SEF_iv3, (void*)iv3,
02156                                              SES_Suma, (void *)sv, NOPE,
02157                                              SEI_Tail, NULL)) {
02158          fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
02159          SUMA_RETURN (-1);
02160       }
02161       
02162       if (!SUMA_Engine (&list)) {
02163          fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
02164          SUMA_RETURN (-1);
02165       }
02166       
02167 
02168    } 
02169    
02170    if (MTI) {
02171       MTI = SUMA_Free_MT_intersect_triangle(MTI);
02172    }
02173    
02174    if (imin >= 0) {
02175       SUMA_RETURN (1); 
02176    } else {
02177       SUMA_RETURN (0); 
02178    }
02179 }
02180 
02181 
02182 
02183 
02184 
02185 
02186 void SUMA_ShowBrushStroke (SUMA_SurfaceViewer *sv, FILE *out)
02187 {
02188    static char FuncName[]={"SUMA_ShowBrushStroke"};
02189    int i, k, N=0;
02190    SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
02191    DListElmt *Next_Elm = NULL;
02192    
02193    SUMA_ENTRY;
02194    
02195    if (!out) out = SUMA_STDERR;
02196    
02197    if (!sv->BS) {
02198       fprintf(out, "%s: NULL sv->BS\n", FuncName);
02199       SUMA_RETURNe;
02200    }
02201    
02202    N = dlist_size(sv->BS);
02203    if (!N) {
02204       fprintf(out, "%s: Empty sv->BS. (N = 0)\n", FuncName);
02205       SUMA_RETURNe;
02206    }
02207    
02208    fprintf(out, "%s: Brush stroke has %d elements:\n", FuncName, N);
02209    
02210    i = 0;
02211    do {
02212       if (Next_Elm==NULL) Next_Elm = dlist_head(sv->BS);
02213       else Next_Elm = Next_Elm->next;
02214       if (!Next_Elm->data) {
02215          fprintf(out, "%s: Element->data %d is NULL!\n", FuncName, i);
02216       }else {
02217          bsd = (SUMA_BRUSH_STROKE_DATUM *)Next_Elm->data; 
02218          fprintf(out, "%d: (%f %f) [%.2f, %.2f, %.2f <--> %.2f, %.2f, %.2f]\t Node  %d, Tri %d\n", 
02219                      i, bsd->x, bsd->y,
02220                      bsd->NP[0], bsd->NP[1], bsd->NP[2],
02221                      bsd->FP[0], bsd->FP[1], bsd->FP[2],
02222                      bsd->SurfNode, bsd->SurfTri);
02223       }
02224       ++i;
02225    }while (dlist_tail(sv->BS) != Next_Elm);
02226    
02227    fprintf(out, "\n");
02228    
02229    SUMA_RETURNe;
02230 }
02231 
02232 
02233 
02234 
02235 
02236 
02237 
02238 
02239 
02240 void  SUMA_ClearBrushStroke (SUMA_SurfaceViewer *sv)
02241 {
02242    static char FuncName[]={"SUMA_ClearBrushStroke"};
02243    
02244    SUMA_ENTRY;
02245    
02246    
02247    if (sv->BS) {
02248       SUMA_EmptyDestroyList(sv->BS);
02249       sv->BS = NULL;
02250    }
02251    
02252    SUMA_RETURNe;
02253 }
02254 
02255 
02256 
02257 
02258 
02259 
02260 
02261 
02262 
02263 
02264 
02265 
02266 SUMA_Boolean  SUMA_CreateBrushStroke (SUMA_SurfaceViewer *sv)
02267 {
02268    static char FuncName[]={"SUMA_CreateBrushStroke"};
02269    
02270    SUMA_ENTRY;
02271       
02272    
02273    if (sv->BS) {  
02274       SUMA_RegisterMessage (SUMAg_CF->MessageList, 
02275                             "Brush Stroke not NULL.", FuncName, 
02276                             SMT_Critical, SMA_LogAndPopup);
02277       SUMA_RETURN(NOPE); 
02278       
02279    }
02280    sv->BS = (DList *)SUMA_malloc(sizeof(DList));
02281    dlist_init(sv->BS, SUMA_FreeBSDatum);  
02282    
02283    SUMA_RETURN (YUP);
02284 }
02285 
02286 SUMA_BRUSH_STROKE_DATUM * SUMA_CreateBSDatum(void)
02287 {
02288    static char FuncName[]={"SUMA_CreateBSDatum"};
02289    SUMA_BRUSH_STROKE_DATUM *bsd = NULL;
02290    
02291    SUMA_ENTRY;
02292    
02293    bsd = (SUMA_BRUSH_STROKE_DATUM *)SUMA_malloc(sizeof(SUMA_BRUSH_STROKE_DATUM));
02294    if (!bsd) {
02295       SUMA_RegisterMessage (SUMAg_CF->MessageList, 
02296                             "Failed to allocate.", FuncName, 
02297                             SMT_Critical, SMA_LogAndPopup);
02298       SUMA_RETURN(NULL); 
02299    }
02300    
02301    bsd->x = bsd->y = 0.0;
02302    bsd->NP[0] = bsd->NP[1] = bsd->NP[2] = 0.0;
02303    bsd->FP[0] = bsd->FP[1] = bsd->FP[2] = 0.0;
02304    bsd->SurfNode = -1;
02305    bsd->SurfTri = -1;
02306    bsd->Decimated = NOPE;
02307    
02308    SUMA_RETURN(bsd);
02309 }
02310 
02311 
02312 
02313 
02314 void SUMA_FreeBSDatum (void *bsd)
02315 {
02316    static char FuncName[]={"SUMA_FreeBSDatum"};
02317    
02318    SUMA_ENTRY;
02319    
02320    
02321    if (bsd) SUMA_free(bsd);
02322    
02323    SUMA_RETURNe;
02324 }
02325 
02326 
02327 
02328 
02329 
02330 
02331 
02332 
02333 
02334 
02335 
02336 
02337 
02338 
02339 
02340 
02341 SUMA_Boolean  SUMA_AddToBrushStroke (SUMA_SurfaceViewer *sv, int x, int y, GLdouble *NP, GLdouble *FP, SUMA_Boolean Show)
02342 {
02343    static char FuncName[]={"SUMA_AddToBrushStroke"};
02344    int ip;
02345    SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
02346    
02347    SUMA_ENTRY;
02348    
02349    
02350    bsd = SUMA_CreateBSDatum();
02351    bsd->x = (float)x;
02352    bsd->y = (float)y;
02353    bsd->NP[0] = NP[0]; bsd->NP[1] = NP[1]; bsd->NP[2] = NP[2];
02354    bsd->FP[0] = FP[0]; bsd->FP[1] = FP[1]; bsd->FP[2] = FP[2]; 
02355    dlist_ins_next (sv->BS, dlist_tail(sv->BS), (void*)bsd);
02356    
02357    
02358    if (Show) SUMA_DrawBrushStroke (sv, YUP);
02359    
02360    SUMA_RETURN (YUP);
02361 }
02362 
02363 
02364 
02365 
02366 void SUMA_SetSVForegroundColor (SUMA_SurfaceViewer *sv, const char *Color)
02367 {
02368    static char FuncName[]={"SUMA_SetSVForegroundColor"};
02369    XColor col, unused;
02370    
02371    SUMA_ENTRY;
02372         
02373 
02374 
02375    if (!XAllocNamedColor (sv->X->DPY, DefaultColormapOfScreen(XtScreen(sv->X->GLXAREA)),
02376       Color, &col, &unused)) {
02377       fprintf (SUMA_STDERR, "Error %s: Can't allocate for %s color.\n", FuncName, Color);
02378       SUMA_RETURNe;  
02379    }
02380    XSetForeground (sv->X->DPY, sv->X->gc, col.pixel);
02381    
02382    SUMA_RETURNe;  
02383 }
02384 
02385 
02386 
02387 
02388 
02389 
02390 
02391 
02392 
02393 
02394 
02395 
02396 
02397 
02398 
02399 void SUMA_DrawBrushStroke (SUMA_SurfaceViewer *sv, SUMA_Boolean incr)
02400 {
02401    static char FuncName[]={"SUMA_DrawBrushStroke"};
02402    int i, N;
02403    DListElmt *NE=NULL, *NEn=NULL;
02404    SUMA_BRUSH_STROKE_DATUM *bsd=NULL, *bsdn = NULL;
02405    
02406    SUMA_ENTRY;
02407    
02408         if (!sv->BS) SUMA_RETURNe;
02409    
02410    N = dlist_size(sv->BS);
02411    if (N < 2) SUMA_RETURNe;
02412    
02413    if (!incr) {   
02414       do {
02415          if (!NE) NE = dlist_head(sv->BS);
02416          else NE = NE->next;
02417          
02418          NEn = NE->next;
02419          
02420          bsd = (SUMA_BRUSH_STROKE_DATUM *)NE->data;
02421          bsdn = (SUMA_BRUSH_STROKE_DATUM *)NEn->data;
02422          
02423          SUMA_DrawWindowLine(sv, (int)bsd->x, (int)bsd->y, (int)bsdn->x, (int)bsdn->y, 1);
02424       } while (NEn != dlist_tail(sv->BS));
02425       
02426    } else {
02427       NEn = dlist_tail(sv->BS);
02428       NE = NEn->prev;
02429       
02430       bsd = (SUMA_BRUSH_STROKE_DATUM *)NE->data;
02431       bsdn = (SUMA_BRUSH_STROKE_DATUM *)NEn->data;
02432       
02433       SUMA_DrawWindowLine(sv, (int)bsd->x, (int)bsd->y, (int)bsdn->x, (int)bsdn->y, 1 );
02434           
02435    }
02436    SUMA_RETURNe;
02437 
02438 }
02439 
02440 
02441 
02442 
02443 
02444 SUMA_DRAWN_ROI * SUMA_ProcessBrushStroke (SUMA_SurfaceViewer *sv, SUMA_BRUSH_STROKE_ACTION BsA)
02445 {
02446    static char FuncName[]={"SUMA_ProcessBrushStroke"};
02447    SUMA_DRAWN_ROI *DrawnROI = NULL;
02448    SUMA_ROI_DATUM *ROIstroke = NULL, *ROIlink=NULL, *ROIfill=NULL;
02449    SUMA_SurfaceObject *SO = NULL;
02450    int ii=0, TailNode = -1, FirstSurfNode = -1, ft = -1, N_SurfNode = 0;
02451    int HeadNode = -1, *ROI_Mask=NULL, N_ROI_Mask = 0;
02452    DListElmt *El = NULL;
02453    SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
02454    char *sbuf;
02455    SUMA_ROI_ACTION_STRUCT *ROIA;
02456    DListElmt *tmpStackPos=NULL;
02457    SUMA_Boolean Shaded = NOPE, LocalHead = NOPE;
02458 
02459       
02460    SO = (SUMA_SurfaceObject *)SUMAg_DOv[sv->Focus_SO_ID].OP;
02461    
02462    SUMA_ENTRY;
02463 
02464    if (!SO) {
02465       fprintf (SUMA_STDERR, "%s: No surface object in focus, nothing to do.\n", FuncName); 
02466       SUMA_RETURN (DrawnROI);
02467    }
02468    
02469    if (!sv->BS) {
02470       fprintf (SUMA_STDERR, "%s: No Brushstroke (BS), nothing to do.\n", FuncName); 
02471       SUMA_RETURN (DrawnROI);
02472    }
02473    
02474    if (!SUMAg_CF->ROI_mode) {
02475       fprintf (SUMA_STDERR, "%s: Not in ROI mode, nothing to do.\n", FuncName); 
02476       SUMA_RETURN (DrawnROI);
02477    }
02478    
02479    
02480    if (SUMAg_CF->X->DrawROI->curDrawnROI) {
02481       if (SUMA_isdROIrelated(SUMAg_CF->X->DrawROI->curDrawnROI, SO) && SUMAg_CF->X->DrawROI->curDrawnROI->DrawStatus != SUMA_ROI_Finished) {
02482          if (LocalHead) fprintf (SUMA_STDERR,"%s: using currDrawnROI.\n", FuncName);
02483          DrawnROI = SUMAg_CF->X->DrawROI->curDrawnROI;
02484       }else {
02485          if (LocalHead) fprintf (SUMA_STDERR,"%s: No match between currDrawnROI and SO.\n", FuncName);
02486          DrawnROI = NULL;
02487       }
02488    }
02489    if (!DrawnROI) { 
02490       if ((DrawnROI = SUMA_FetchROI_InCreation (SO, SUMAg_DOv, SUMAg_N_DOv))){
02491          if (LocalHead) fprintf (SUMA_STDERR,"%s: using ROI in creation.\n", FuncName);
02492          
02493          SUMA_InitializeDrawROIWindow(DrawnROI);
02494       } else {
02495          
02496          if (LocalHead) fprintf (SUMA_STDERR,"%s: will create a new ROI.\n", FuncName);
02497       }
02498    }
02499    
02500    if (!DrawnROI && BsA == SUMA_BSA_JoinEnds) {
02501       SUMA_SLP_Err ("NO ROI to close.");
02502       SUMA_RETURN (DrawnROI);
02503    }
02504    
02505    if (!DrawnROI) { 
02506       if (LocalHead) fprintf (SUMA_STDERR, "%s: No ROI found, creating a new one.\n", FuncName);
02507       SUMA_GET_TEXT_FIELD(SUMAg_CF->X->DrawROI->ROIlbl->textfield, sbuf);
02508       DrawnROI = SUMA_AllocateDrawnROI (SO->idcode_str, SUMA_ROI_InCreation, SUMA_ROI_OpenPath, 
02509                                         sbuf, 
02510                                         SUMAg_CF->X->DrawROI->ROIval->value);
02511       if (!DrawnROI) {
02512          SUMA_RegisterMessage (SUMAg_CF->MessageList, 
02513                                "Failed to allocate for DrawnROI.", FuncName, 
02514                                SMT_Critical, SMA_LogAndPopup);
02515          SUMA_RETURN (NULL);
02516       }
02517 
02518       
02519 
02520 
02521 
02522       
02523       if (!SUMA_AddDO (SUMAg_DOv, &SUMAg_N_DOv, (void *)DrawnROI, ROIdO_type, SUMA_LOCAL)) {
02524                            fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AddDO.\n", FuncName);
02525       }
02526 
02527       
02528       SUMA_IS_DRAW_ROI_SWITCH_ROI_SHADED(Shaded);
02529       if (!Shaded) {
02530          SUMA_cb_DrawROI_SwitchROI (NULL, (XtPointer) SUMAg_CF->X->DrawROI->SwitchROIlst, NULL);
02531       }
02532    
02533 
02534    } else {
02535       if (LocalHead) fprintf(SUMA_STDOUT,"%s: ROI %p fetched. Status %d.\n", FuncName, DrawnROI, DrawnROI->DrawStatus); 
02536    } 
02537 
02538    if (BsA == SUMA_BSA_AppendStrokeOrFill) {
02539       if (DrawnROI->Type == SUMA_ROI_ClosedPath || DrawnROI->Type == SUMA_ROI_FilledArea) BsA = SUMA_BSA_FillArea;
02540       else if (DrawnROI->Type == SUMA_ROI_OpenPath) BsA = SUMA_BSA_AppendStroke;
02541    }
02542    if (DrawnROI->Type == SUMA_ROI_ClosedPath && BsA != SUMA_BSA_FillArea) {
02543       SUMA_SLP_Err ("You can only fill a closed path.\nYou cannot append more paths to it.");
02544       SUMA_RETURN (DrawnROI);
02545    }
02546    if (DrawnROI->Type == SUMA_ROI_FilledArea && BsA != SUMA_BSA_FillArea) {
02547       SUMA_SLP_Err ("You cannot add paths to a filled ROI.");
02548       SUMA_RETURN (DrawnROI);
02549    }
02550    
02551    
02552    if (SUMAg_CF->X->DrawROI->curDrawnROI != DrawnROI) {
02553       if (!SUMA_InitializeDrawROIWindow (DrawnROI)) {
02554          SUMA_SL_Err("Failed to initialize DrawWindow.");
02555       }
02556    }
02557 
02558    
02559    if (LocalHead) fprintf (SUMA_STDERR, "%s: Turning BrushStroke to NodeStroke ...\n", FuncName);
02560    if (!SUMA_BrushStrokeToNodeStroke (sv)) {
02561       SUMA_RegisterMessage (SUMAg_CF->MessageList, 
02562                          "Failed in SUMA_BrushStrokeToNodeStroke.", FuncName, 
02563                          SMT_Error, SMA_LogAndPopup);
02564       SUMA_RETURN(NULL);
02565    }
02566       
02567    switch (BsA) {
02568       case SUMA_BSA_AppendStroke:
02569          
02570          if (LocalHead) fprintf (SUMA_STDERR, "%s: Turning NodeStroke to ROIStroke ...\n", FuncName);
02571          if (!(ROIstroke = SUMA_NodeStrokeToConnectedNodes (sv))) {
02572             SUMA_RegisterMessage (SUMAg_CF->MessageList, 
02573                                "Failed in SUMA_NodeStrokeToConnectedNodes.", FuncName, 
02574                                SMT_Critical, SMA_LogAndPopup);
02575             if (ROIlink) SUMA_FreeROIDatum((void *)ROIlink); ROIlink = NULL;
02576             if (ROIstroke) SUMA_FreeROIDatum((void *)ROIstroke); ROIstroke = NULL;
02577             SUMA_RETURN(NULL);
02578          }
02579 
02580          if (LocalHead) fprintf (SUMA_STDERR, "%s: Turning NodeStroke to ROIStroke . DONE.\n", FuncName);
02581          
02582          if (dlist_size(DrawnROI->ROIstrokelist)) {
02583             
02584             if (LocalHead) fprintf (SUMA_STDERR, "%s: Adding ROIstroke to previous ones ...\n", FuncName);
02585             
02586             SUMA_DRAWN_ROI_TAIL_NODE(DrawnROI,TailNode);
02587 
02588             SUMA_BS_FIRST_SURF_NODE(sv->BS, FirstSurfNode, ft, El);
02589             SUMA_BS_COUNT_SURF_NODES(sv->BS, N_SurfNode);
02590             if (FirstSurfNode == TailNode && N_SurfNode == 1) {
02591                
02592                fprintf (SUMA_STDERR, "%s: New stroke has one node that is identical to tail node. Dumping element.\n", FuncName);
02593                SUMA_RETURN(DrawnROI);
02594             }
02595 
02596             
02597             if (FirstSurfNode != TailNode) {
02598                if (LocalHead) fprintf (SUMA_STDERR, "%s: linking Tail Node to New stroke.\n", FuncName);
02599 
02600                ROIlink = SUMA_LinkTailNodeToNodeStroke (sv, DrawnROI);
02601                if (!ROIlink) {
02602                   SUMA_SL_Err("Failed to connect Tail node to Node stroke, try again.");
02603                   SUMA_RETURN(NULL);
02604                }
02605                if (LocalHead) {
02606                   fprintf (SUMA_STDERR, "%s: RIOlink, before prepending:\n", FuncName);
02607                   SUMA_ShowDrawnROIDatum (ROIlink, NULL, NOPE);
02608                }
02609 
02610                
02611                if (LocalHead) {
02612                   fprintf (SUMA_STDERR, "%s: RIOstroke, before prepending:\n", FuncName);
02613                   SUMA_ShowDrawnROIDatum (ROIstroke, NULL, NOPE);
02614                }
02615                if (!SUMA_PrependToROIdatum (ROIlink, ROIstroke)) {
02616                   SUMA_RegisterMessage (SUMAg_CF->MessageList, 
02617                                      "Failed to merge ROIs.", FuncName,
02618                                      SMT_Critical, SMA_LogAndPopup);
02619                   if (ROIlink) SUMA_FreeROIDatum((void *)ROIlink); ROIlink = NULL;
02620                   if (ROIstroke) SUMA_FreeROIDatum((void *)ROIstroke); ROIstroke = NULL;
02621                   SUMA_RETURN(NULL);   
02622                }
02623 
02624                if (LocalHead) {
02625                   fprintf (SUMA_STDERR, "%s: RIOstroke, after prepending:\n", FuncName);
02626                   SUMA_ShowDrawnROIDatum (ROIstroke, NULL, NOPE);
02627                }
02628               
02629                if (ROIlink) SUMA_FreeROIDatum ((void *)ROIlink); ROIlink = NULL;
02630             }
02631          }else{
02632             if (LocalHead) fprintf (SUMA_STDERR, "%s: First ROIStroke of ROI.\n", FuncName);
02633          }
02634          break;
02635       case SUMA_BSA_JoinEnds:
02636          
02637          if (DrawnROI) { 
02638             SUMA_DRAWN_ROI_HEAD_NODE(DrawnROI,HeadNode);         
02639             SUMA_BS_FIRST_SURF_NODE(sv->BS, FirstSurfNode, ft, El);
02640             bsd = (SUMA_BRUSH_STROKE_DATUM *)El->data;
02641             if (LocalHead) fprintf(SUMA_STDERR, "%s: Trying to join node %d to node %d.\n", FuncName, FirstSurfNode, HeadNode);
02642             
02643             ROIstroke = SUMA_Surf_Plane_Intersect_ROI (SO, FirstSurfNode, HeadNode, bsd->NP);
02644 
02645             if (!ROIstroke) {
02646                SUMA_SL_Err ("Failed to close path. Repeat new stroke.");
02647                SUMA_RETURN(DrawnROI);
02648             }
02649             
02650 
02651 
02652             if (LocalHead) fprintf(SUMA_STDERR, "%s: Last node of ROIstroke is %d\n", FuncName, ROIstroke->nPath[ROIstroke->N_n-1]); 
02653             if (ROIstroke->nPath[ROIstroke->N_n-1] != HeadNode) {
02654                
02655                BsA = SUMA_BSA_AppendStroke;
02656                SUMA_SL_Err ("Failed to close path. Continue with stroke.");
02657                SUMA_RETURN(DrawnROI);
02658             }else {
02659                
02660             } 
02661          } else {
02662             
02663          }
02664          break;
02665       case SUMA_BSA_FillArea:
02666          SUMA_BS_FIRST_SURF_NODE(sv->BS, FirstSurfNode, ft, El);
02667          if (LocalHead) fprintf (SUMA_STDERR, "%s: Should be filling from node %d\n", FuncName, FirstSurfNode);
02668          
02669          
02670          switch (SUMAg_CF->ROI_FillMode) {
02671             case SUMA_ROI_FILL_TO_ALLROI:
02672                ROI_Mask = SUMA_Build_Mask_AllROI (SUMAg_DOv, SUMAg_N_DOv, SO, NULL, &N_ROI_Mask);
02673                break;
02674             case SUMA_ROI_FILL_TO_THISROI:
02675                ROI_Mask = (int *)SUMA_calloc (SO->N_Node, sizeof(int));
02676                if (!ROI_Mask) {
02677                   SUMA_SLP_Crit("Failed to allocate");
02678                   SUMA_RETURN(DrawnROI);
02679                }
02680                SUMA_Build_Mask_DrawnROI (DrawnROI, ROI_Mask);
02681                break;
02682             default:
02683                SUMA_SLP_Err("No such mode.");
02684                SUMA_RETURN(DrawnROI);
02685                break;
02686          }
02687                
02688          
02689          ROIfill = SUMA_FillToMask (SO, ROI_Mask, FirstSurfNode);
02690          if (ROI_Mask) SUMA_free(ROI_Mask); ROI_Mask = NULL;
02691          if (!ROIfill) {
02692             SUMA_SLP_Err("Failed to fill area:\nPerhaps seed on edge\nor nothing to fill.");
02693             SUMA_RETURN(DrawnROI);
02694          }
02695          
02696          break;
02697       default:
02698          fprintf (SUMA_STDERR, "Error %s: Why are you doing this to me ?.\n", FuncName);
02699          break;
02700    }
02701         
02702    
02703    
02704    
02705    switch (BsA) {
02706       case SUMA_BSA_AppendStroke:
02707          
02708          ROIstroke->action = SUMA_BSA_AppendStroke;
02709          
02710          if (LocalHead) fprintf (SUMA_STDERR, "%s: Adding ROIStroke to DrawnROI->ROIstrokelist\n", FuncName);
02711          ROIA = (SUMA_ROI_ACTION_STRUCT *) SUMA_malloc (sizeof(SUMA_ROI_ACTION_STRUCT)); 
02712          ROIA->DrawnROI = DrawnROI;
02713          ROIA->ROId = ROIstroke;
02714          tmpStackPos = SUMA_PushActionStack (DrawnROI->ActionStack, DrawnROI->StackPos, SUMA_AddToTailROIDatum, (void *)ROIA, SUMA_DestroyROIActionData);
02715          if (tmpStackPos) DrawnROI->StackPos = tmpStackPos;
02716          else {
02717             fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_PushActionStack.\n", FuncName);
02718             SUMA_RETURN (DrawnROI);
02719          }
02720          if (SUMAg_CF->X->DrawROI->WhatDist == SW_DrawROI_WhatDistTrace ||  SUMAg_CF->X->DrawROI->WhatDist == SW_DrawROI_WhatDistAll) 
02721             SUMA_ReportDrawnROIDatumLength(SO, ROIA->ROId, NULL, SUMAg_CF->X->DrawROI->WhatDist);
02722          break;
02723       case SUMA_BSA_JoinEnds:
02724          
02725          ROIstroke->action = SUMA_BSA_JoinEnds;
02726          if (LocalHead) fprintf (SUMA_STDERR, "%s: Closing path.\n", FuncName);
02727          ROIA = (SUMA_ROI_ACTION_STRUCT *) SUMA_malloc (sizeof(SUMA_ROI_ACTION_STRUCT)); 
02728          ROIA->DrawnROI = DrawnROI;
02729          ROIA->ROId = ROIstroke;
02730          tmpStackPos = SUMA_PushActionStack (DrawnROI->ActionStack, DrawnROI->StackPos, SUMA_AddToTailJunctionROIDatum, (void *)ROIA, SUMA_DestroyROIActionData);
02731          if (tmpStackPos) DrawnROI->StackPos = tmpStackPos;
02732          else {
02733             fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_PushActionStack.\n", FuncName);
02734             SUMA_RETURN (DrawnROI);
02735          }
02736          if (SUMAg_CF->X->DrawROI->WhatDist == SW_DrawROI_WhatDistTrace ||  SUMAg_CF->X->DrawROI->WhatDist == SW_DrawROI_WhatDistAll) 
02737             SUMA_ReportDrawnROIDatumLength(SO, ROIA->ROId, NULL, SUMAg_CF->X->DrawROI->WhatDist);
02738          break;
02739       case SUMA_BSA_FillArea:
02740          
02741          ROIfill->action = SUMA_BSA_FillArea;
02742          
02743          ROIA = (SUMA_ROI_ACTION_STRUCT *) SUMA_malloc (sizeof(SUMA_ROI_ACTION_STRUCT)); 
02744          ROIA->DrawnROI = DrawnROI;
02745          ROIA->ROId = ROIfill;
02746          tmpStackPos = SUMA_PushActionStack (DrawnROI->ActionStack, DrawnROI->StackPos, SUMA_AddFillROIDatum, (void *)ROIA, SUMA_DestroyROIActionData);
02747          if (tmpStackPos) DrawnROI->StackPos = tmpStackPos;
02748          else {
02749             fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_PushActionStack.\n", FuncName);
02750             SUMA_RETURN (DrawnROI);
02751          } 
02752          break;
02753       default:
02754          fprintf (SUMA_STDERR, "Error %s: Why are you doing this to me ?.\n", FuncName);
02755          break; 
02756    }      
02757    
02758    
02759    if (!SUMA_Paint_SO_ROIplanes_w (SO, SUMAg_DOv, SUMAg_N_DOv)) {
02760       SUMA_SLP_Err("Failed in SUMA_Paint_SO_ROIplanes_w.");
02761       SUMA_RETURN(DrawnROI);
02762    }
02763    
02764    SUMA_RETURN(DrawnROI);
02765 }
02766 
02767 
02768 
02769 
02770 
02771 
02772 
02773 
02774 SUMA_Boolean SUMA_BrushStrokeToNodeStroke (SUMA_SurfaceViewer *sv)
02775 {
02776    static char FuncName[]={"SUMA_BrushStrokeToNodeStroke"};
02777    DList * NS=NULL;
02778    SUMA_SurfaceObject *SO=NULL;
02779    SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL;
02780    float delta_t_tmp; 
02781    struct timeval tt_tmp;
02782    int N = -1;
02783    SUMA_Boolean LocalHead=NOPE;
02784    SUMA_BRUSH_STROKE_DATUM *bsd=NULL, *obsd=NULL;
02785    DListElmt *Elmt = NULL, *oElmt=NULL;
02786    
02787    SUMA_ENTRY;
02788    
02789    
02790    SO = (SUMA_SurfaceObject *)SUMAg_DOv[sv->Focus_SO_ID].OP;
02791    
02792    if (SO->FaceSetDim != 3) {
02793       fprintf(SUMA_STDERR,"Error %s: SUMA_MT_intersect_triangle only works for triangular meshes.\n", FuncName);
02794       SUMA_RETURN(NOPE);
02795    }
02796    
02797    N = dlist_size(sv->BS);
02798    if (!N) {
02799       fprintf (SUMA_STDERR, "%s: Empty brushstroke, nothing to do.\n", FuncName);
02800       SUMA_RETURN(NOPE);
02801    }else if (LocalHead) fprintf (SUMA_STDERR, "%s: %d element(s) in sv->BS.\n", FuncName, N);
02802    
02803     
02804    Elmt = dlist_head(sv->BS);
02805    bsd = (SUMA_BRUSH_STROKE_DATUM *)Elmt->data;
02806    
02807    bsd->SurfNode = SO->SelectedNode;
02808    bsd->SurfTri = SO->SelectedFaceSet;
02809    
02810    #ifdef DISASTER_LOOP 
02811       
02812 
02813       if (N > 1) {
02814          if (LocalHead) {
02815             fprintf (SUMA_STDERR, "%s: Disaster loop, hold on .\n", FuncName);  
02816             SUMA_etime (&tt_tmp, 0);
02817          }
02818 
02819          MTI = NULL;
02820          do {
02821             Elmt = Elmt->next;
02822             bsd = (SUMA_BRUSH_STROKE_DATUM *)Elmt->data;
02823 
02824             MTI = SUMA_MT_intersect_triangle(   bsd->NP, bsd->FP, 
02825                                                 SO->NodeList, SO->N_Node, 
02826                                                 SO->FaceSetList, SO->N_FaceSet, 
02827                                                 MTI);
02828 
02829             if (!MTI) {
02830                fprintf(SUMA_STDERR,"Error %s: SUMA_MT_intersect_triangle failed.\n", FuncName);
02831                SUMA_RETURN (NOPE);
02832             }
02833 
02834             if (MTI->N_hits) { 
02835                oElmt = Elmt->prev;
02836                obsd = (SUMA_BRUSH_STROKE_DATUM *)oElmt->data;
02837                if (obsd->SurfNode != MTI->inodemin) { 
02838                   bsd->SurfNode = MTI->inodemin;
02839                   bsd->SurfTri = MTI->ifacemin;
02840                }else {
02841                   
02842                   if (LocalHead) fprintf (SUMA_STDERR, "%s: Removing redundant BS element.\n", FuncName);
02843                   dlist_remove (sv->BS, Elmt, (void*)(&bsd));
02844                   SUMA_FreeBSDatum (bsd);
02845                   Elmt = oElmt;
02846                }
02847             }
02848 
02849          }while (Elmt != dlist_tail(sv->BS));
02850 
02851          
02852          MTI = SUMA_Free_MT_intersect_triangle(MTI); 
02853 
02854          if (LocalHead) {   
02855             delta_t_tmp = SUMA_etime (&tt_tmp, 1);
02856             if (LocalHead) fprintf (SUMA_STDERR, "Local Debug %s: Intersections took %f seconds.\n", FuncName, delta_t_tmp);
02857          }
02858 
02859       }
02860    #else
02861    if (N > 1) {    
02862       DListElmt *Eli=NULL, *Eln=NULL;
02863       float ip[3], d[3];
02864       int IncTri[100], N_IncTri=0, n1=-1, n2=-1, n3=-1, ni = -1, ti = -1, N_Neighb=0,DeciLevel = 0, i, j, Removed=0;
02865       int DeciReentry=0, UsedNode[3];
02866       SUMA_BRUSH_STROKE_DATUM *bsdi=NULL, *bsdn=NULL, *bsd_deci=NULL;
02867       SUMA_Boolean  DoesInters=NOPE; 
02868       SUMA_Boolean  TrackOscillation = YUP; 
02869       SUMA_Boolean  TryBruteForce = NOPE;
02870       int *Visited = NULL;
02871       
02872       if (TrackOscillation) {
02873          Visited = (int *)SUMA_calloc(SO->N_Node, sizeof(int)); 
02874          if (!Visited) {
02875             SUMA_SLP_Err("Failed to allocate for Visited.\n");
02876             SUMA_RETURN(NOPE);
02877          }
02878       }
02879       
02880       Eli = Elmt; 
02881       MTI = NULL;
02882       TryBruteForce = NOPE;
02883       do {   
02884          bsdi = (SUMA_BRUSH_STROKE_DATUM *)Eli->data;
02885          n1 = bsdi->SurfNode;
02886          
02887          Eln = Eli->next; 
02888          bsdn = (SUMA_BRUSH_STROKE_DATUM *)Eln->data;
02889          
02890          if (LocalHead) fprintf(SUMA_STDERR,"%s: Working from node %d.\n", FuncName, n1);
02891 
02892          if (!TryBruteForce) { 
02893             N_Neighb = SO->FN->N_Neighb[n1];
02894             if (N_Neighb < 3) {
02895                
02896                SUMA_SLP_Err ("Node has less than 3 neighbors.\n.This method will not apply.");
02897                SUMA_RETURN(NOPE);
02898             }
02899 
02900             
02901             if (LocalHead) fprintf (SUMA_STDERR, "%s: Searching incident triangles:\n", FuncName);
02902             i=0;
02903             DoesInters = NOPE;
02904             while ((i < N_Neighb ) && (!DoesInters)) { 
02905                n2 = SO->FN->FirstNeighb[n1][i];
02906                if ( i+1 == N_Neighb) n3 = SO->FN->FirstNeighb[n1][0];
02907                else n3 = SO->FN->FirstNeighb[n1][i+1];
02908                #if 0
02909                   if (LocalHead) {
02910                      fprintf (SUMA_STDERR, " %d: [%d %d %d] Tri %d\n", i, n1, n2, n3, SUMA_whichTri(SO->EL, n1, n2, n3, 1));
02911                      fprintf (SUMA_STDERR, " %d: [%.2f, %.2f, %.2f]\n", 
02912                                              n1, SO->NodeList[3*n1], SO->NodeList[3*n1+1], SO->NodeList[3*n1+2]);
02913                      fprintf (SUMA_STDERR, " %d: [%.2f, %.2f, %.2f]\n", 
02914                                              n2, SO->NodeList[3*n2], SO->NodeList[3*n2+1], SO->NodeList[3*n2+2]);
02915                      fprintf (SUMA_STDERR, " %d: [%.2f, %.2f, %.2f]\n", 
02916                                              n3, SO->NodeList[3*n3], SO->NodeList[3*n3+1], SO->NodeList[3*n3+2]);                        
02917                      fprintf (SUMA_STDERR, " NP: [%.2f, %.2f, %.2f] FP: [%.3f, %.2f, %.2f]\n", 
02918                                              bsdn->NP[0], bsdn->NP[1], bsdn->NP[2], 
02919                                              bsdn->FP[0], bsdn->FP[1], bsdn->FP[2]);
02920                   }
02921                #endif
02922                DoesInters = SUMA_MT_isIntersect_Triangle (bsdn->NP, bsdn->FP, 
02923                                                           &(SO->NodeList[3*n1]), &(SO->NodeList[3*n2]), &(SO->NodeList[3*n3]),
02924                                                           ip, d, &ni);
02925                if (DoesInters) {
02926                   if (ni == 0) ni = n1;
02927                   else if (ni == 1) ni = n2;
02928                   else ni = n3;
02929 
02930                   ti = SUMA_whichTri(SO->EL, n1, n2, n3, 1);
02931                }
02932 
02933                #if 0
02934                   if (LocalHead) fprintf (SUMA_STDERR, "%s: DoesInters = %d, ni = %d\n", FuncName, DoesInters, ni);
02935                   {
02936                                                                 
02937                      MTI = NULL;MTI = SUMA_MT_intersect_triangle(   bsdn->NP, bsdn->FP, 
02938                                                       SO->NodeList, SO->N_Node, 
02939                                                       SO->FaceSetList, SO->N_FaceSet, 
02940                                                       MTI);
02941                      fprintf (SUMA_STDERR, "%s: Intersection would be with triangle %d, node %d\n", FuncName, MTI->ifacemin, MTI->inodemin);                                 
02942                   }
02943                #endif
02944                ++i;
02945             } 
02946             if (LocalHead) fprintf (SUMA_STDERR, "\n");
02947             
02948          } else  { 
02949          
02950             if (LocalHead) fprintf (SUMA_STDERR, "%s: Trying brute force here \n", FuncName);
02951             
02952             SUMA_REMOVE_NEXT_NON_DECIMATED (sv->BS, Eli, Eln);
02953             DeciLevel = 0;
02954             DeciReentry = 0;
02955             if (!Eln) {
02956              SUMA_SL_Err ("I tried hard to figure out your trace.\nI failed, now you try again.");
02957              SUMA_RETURN(YUP);
02958             }
02959 
02960             bsdn = (SUMA_BRUSH_STROKE_DATUM *)Eln->data;
02961             MTI = SUMA_MT_intersect_triangle(   bsdn->NP, bsdn->FP, 
02962                                     SO->NodeList, SO->N_Node, 
02963                                     SO->FaceSetList, SO->N_FaceSet, 
02964                                     MTI);
02965 
02966             if (!MTI) {
02967                SUMA_SL_Err ("I tried harder to figure out your trace.\nI failed, do try again.");
02968                SUMA_RETURN (YUP);
02969             }
02970 
02971             if (MTI->N_hits) { 
02972                DoesInters = YUP;
02973                if (bsdi->SurfNode != MTI->inodemin) { 
02974                   if (LocalHead) fprintf (SUMA_STDERR, "%s: Brute Force: Found intersection at new node %d.\n", FuncName, MTI->inodemin);
02975                   ni = MTI->inodemin;
02976                   ti = MTI->ifacemin;
02977                }else {
02978                   
02979                   if (LocalHead) fprintf (SUMA_STDERR, "%s: Brute Force: Found intersection at n1 = %d!.\n", FuncName, MTI->inodemin);
02980                   ni = n1;
02981                }
02982             } else {
02983                
02984                SUMA_SL_Err ("Why are you drawing out of bounds ?");
02985                SUMA_RETURN (YUP);
02986             }
02987             
02988             TryBruteForce = NOPE;
02989          }
02990          
02991          if (!DoesInters) { 
02992             ++DeciLevel;
02993             if (LocalHead) fprintf (SUMA_STDERR, "%s: No intersection found. Decimating, level %d.\n", FuncName, DeciLevel);
02994             
02995             if (DeciLevel > 3000) { 
02996                if (LocalHead) fprintf (SUMA_STDERR,"%s: Decimation method failed. Trying from brute force", FuncName);
02997                TryBruteForce = YUP;
02998             } else {
02999                bsd_deci = SUMA_CreateBSDatum();
03000                bsd_deci->Decimated = YUP;
03001                bsd_deci->x = (bsdi->x + bsdn->x)/2.0;
03002                bsd_deci->y = (bsdi->y + bsdn->y)/2.0;
03003                for (j=0; j < 3; ++j) bsd_deci->NP[j] = (bsdi->NP[j] + bsdn->NP[j])/2.0;
03004                for (j=0; j < 3; ++j) bsd_deci->FP[j] = (bsdi->FP[j] + bsdn->FP[j])/2.0;
03005                bsd_deci->SurfNode = -1;
03006                bsd_deci->SurfTri = -1;
03007 
03008                dlist_ins_next (sv->BS, Eli, bsd_deci);
03009             }
03010          } else {
03011             
03012             if (ni == n1 && !DeciLevel) { 
03013                
03014                ++Removed;
03015                if (LocalHead) fprintf (SUMA_STDERR, "%s: Same node reached without decimation, deleting for the %dth time.\n",
03016                    FuncName, Removed);
03017                dlist_remove(sv->BS, Eln, (void*)&bsdn);
03018                SUMA_FreeBSDatum(bsdn);
03019             } else {
03020                if (ni == n1 && DeciLevel) {
03021                   
03022                   if (DeciLevel) { 
03023                      #if 0
03024                         
03025                         TryBruteForce = YUP;
03026                         
03027                         DoesInters = NOPE;
03028                      #else
03029                         
03030                         if (!DeciReentry) {
03031                            UsedNode[0] = n1;
03032                            if (LocalHead) fprintf (SUMA_STDERR, "%s: Same node reached during decimation.\n Switching to second closest node.\n", FuncName);
03033                            if (d[1] < d[2]) {
03034                               ni = n2;
03035                               UsedNode[1] = n2;
03036                            } else {
03037                               ni = n3;
03038                               UsedNode[1] = n3;
03039                            }
03040                         } else if (DeciReentry == 1){
03041                            
03042                            if (LocalHead) fprintf (SUMA_STDERR, "%s: Last chance!\n", FuncName);
03043                            if (n2 != UsedNode[0] && n2 != UsedNode[1]) ni = n2; 
03044                            else if (n3 != UsedNode[0] && n3 != UsedNode[1]) ni = n3; 
03045                         } else {
03046                            
03047                            TryBruteForce = YUP;
03048                            
03049                            DoesInters = NOPE;
03050                         }
03051                      #endif
03052                      ++DeciReentry;
03053                   }
03054                }else {
03055                   
03056                   DeciLevel = 0;
03057                   DeciReentry = 0;
03058                }
03059 
03060                
03061 
03062 
03063                if (TrackOscillation) {
03064                   ++Visited[ni];
03065                   if (Visited[ni] == 9) {
03066                      DoesInters = NOPE;
03067                      TryBruteForce = YUP;
03068                      SUMA_SL_Err ("Path tracing oscillation. Trying with brute force.");
03069                   }
03070                   if (Visited[ni] > 9) {
03071                      SUMA_SL_Err ("Path tracing oscillation remaining. Quitting tracing.");
03072                      SUMA_RETURN(YUP);
03073                   }
03074                }
03075 
03076                if (DoesInters) { 
03077                   if (LocalHead) fprintf (SUMA_STDERR, "%s: Found new node.\n", FuncName);
03078                   
03079                   bsdn->SurfNode = ni;
03080                   bsdn->SurfTri = ti;
03081                   
03082                   Eli = Eln; 
03083                }
03084             }
03085          }
03086          
03087       } while (Eli != dlist_tail(sv->BS));
03088        
03089       if (MTI) MTI = SUMA_Free_MT_intersect_triangle(MTI); 
03090       if (TrackOscillation) {
03091          if (Visited) SUMA_free(Visited);
03092       }
03093    }   
03094    #endif
03095    SUMA_RETURN(YUP);
03096 }
03097 
03098 
03099 
03100 
03101 
03102 
03103 
03104 
03105 
03106 
03107 SUMA_ROI_DATUM *SUMA_LinkThisNodeToNodeInStroke (SUMA_SurfaceViewer *sv, int NonSurf, DListElmt *ELinStroke)
03108 {
03109    static char FuncName[]={"SUMA_LinkThisNodeToNodeInStroke"};
03110    SUMA_Boolean LocalHead = NOPE;
03111    SUMA_ROI_DATUM *ROId=NULL;
03112    SUMA_SurfaceObject *SO=NULL;
03113    int Nfrom, Nto;
03114    SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
03115    
03116    SUMA_ENTRY;
03117    
03118    SO = (SUMA_SurfaceObject *)SUMAg_DOv[sv->Focus_SO_ID].OP;
03119    
03120    Nfrom = NonSurf;
03121    bsd = (SUMA_BRUSH_STROKE_DATUM *)ELinStroke->data;
03122    Nto = bsd->SurfNode;
03123    
03124    
03125    ROId = SUMA_Surf_Plane_Intersect_ROI (SO, Nfrom, Nto, bsd->NP);
03126    
03127    if (!ROId) {
03128       fprintf (SUMA_STDERR, "Error %s: Failed to link tail node to first node in new stroke. Repeat new stroke.\n", FuncName);
03129       SUMA_RETURN(NULL);
03130    }
03131    
03132    SUMA_RETURN(ROId);
03133 }
03134 
03135 
03136 
03137 
03138 
03139 
03140 
03141 
03142 
03143 SUMA_ROI_DATUM *SUMA_LinkTailNodeToNodeStroke (SUMA_SurfaceViewer *sv, SUMA_DRAWN_ROI *DrawnROI)
03144 {
03145  
03146    static char FuncName[]={"SUMA_LinkTailNodeToNodeStroke"};
03147    SUMA_ROI_DATUM *ROId=NULL;
03148    SUMA_SurfaceObject *SO=NULL;
03149    SUMA_Boolean LocalHead = NOPE;
03150    int Nfrom=-1, Nto=-1, Trito=-1;
03151    DListElmt *Elm=NULL;
03152    SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
03153    
03154    SUMA_ENTRY;
03155    
03156    SO = (SUMA_SurfaceObject *)SUMAg_DOv[sv->Focus_SO_ID].OP;
03157    
03158    
03159    SUMA_DRAWN_ROI_TAIL_NODE(DrawnROI, Nfrom);
03160    if (Nfrom < 0) {
03161       fprintf (SUMA_STDERR, "Error %s: No tail node found.\n", FuncName);
03162       SUMA_RETURN(NULL);
03163    }
03164    
03165    
03166    SUMA_BS_FIRST_SURF_NODE(sv->BS, Nto, Trito, Elm);
03167    if (Nto < 0 || !Elm) {
03168       SUMA_SLP_Err ("Failed in SUMA_BS_FIRST_SURF_NODE macro.");
03169       SUMA_RETURN(NULL); 
03170    }
03171    bsd = (SUMA_BRUSH_STROKE_DATUM *)Elm->data;
03172    
03173    
03174    ROId = SUMA_Surf_Plane_Intersect_ROI (SO, Nfrom, Nto, bsd->NP);
03175    
03176    if (!ROId) {
03177       fprintf (SUMA_STDERR, "Error %s: Failed to link tail node to first node in new stroke. Repeat new stroke.\n", FuncName);
03178       SUMA_RETURN(NULL);
03179    }
03180    
03181    SUMA_RETURN(ROId);
03182 }
03183 
03184 
03185 
03186 
03187 
03188 SUMA_ROI_DATUM *SUMA_NodeStrokeToConnectedNodes (SUMA_SurfaceViewer *sv) 
03189 {
03190    static char FuncName[]={"SUMA_NodeStrokeToConnectedNodes"};
03191    SUMA_Boolean LocalHead = NOPE;
03192    SUMA_ROI_DATUM *ROId=NULL, *ROIlink = NULL;
03193    int i=0;
03194    SUMA_SurfaceObject *SO=NULL;
03195    DListElmt *Elmt = NULL, *oElmt = NULL;
03196    SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
03197    
03198    SUMA_ENTRY;
03199    
03200    
03201    ROId = SUMA_AllocROIDatum();
03202 
03203    
03204    ROId->N_n = 1;
03205    ROId->N_t = 1;
03206    ROId->nPath = (int *) SUMA_calloc (ROId->N_n, sizeof(int));
03207    ROId->tPath = (int *) SUMA_calloc (ROId->N_t, sizeof(int));
03208    
03209    SUMA_BS_FIRST_SURF_NODE(sv->BS, ROId->nPath[0], ROId->tPath[0], Elmt);
03210    ROId->Type = SUMA_ROI_NodeSegment;
03211    
03212    
03213    SO = (SUMA_SurfaceObject *)SUMAg_DOv[sv->Focus_SO_ID].OP;
03214    oElmt = Elmt;
03215    do {
03216       
03217      SUMA_BS_NEXT_SURF_NODE(sv->BS, oElmt, Elmt);
03218     
03219      if (!Elmt) {
03220       
03221       SUMA_S_Note("Reached EOL without finding Elmt.\nNot necessarily a bad thing.");
03222       SUMA_RETURN(ROId);
03223      } else {
03224       if (LocalHead) {
03225          fprintf (SUMA_STDERR, "%s: Working with element %p.\n", FuncName, Elmt);
03226       }
03227      }
03228      bsd = (SUMA_BRUSH_STROKE_DATUM *)Elmt->data;
03229      if (LocalHead) fprintf (SUMA_STDERR, "%s: %d %d\nWill look for edge %d %d\n", 
03230                      FuncName, ROId->N_n, bsd->SurfNode,
03231                      ROId->nPath[ROId->N_n-1], bsd->SurfNode);
03232      if (SUMA_FindEdge(SO->EL, ROId->nPath[ROId->N_n-1], bsd->SurfNode) < 0) {
03233          
03234          if (LocalHead) fprintf (SUMA_STDERR, "%s: Edge not found, linking together.\n", FuncName);
03235          if (!(ROIlink = SUMA_LinkThisNodeToNodeInStroke (sv, ROId->nPath[ROId->N_n-1],  Elmt))) {
03236             SUMA_SLP_Err ("Failed to connect nodes in stroke.");
03237             SUMA_RETURN (ROId);
03238          }
03239          
03240          if (LocalHead) fprintf (SUMA_STDERR, "%s: Merging ROIs together.\n", FuncName);
03241          if (!SUMA_AppendToROIdatum (ROIlink, ROId)) {
03242                SUMA_RegisterMessage (SUMAg_CF->MessageList, 
03243                                   "Failed to merge ROIs.", FuncName,
03244                                   SMT_Critical, SMA_LogAndPopup);
03245                if (ROIlink) SUMA_FreeROIDatum((void *)ROIlink); ROIlink = NULL;
03246                SUMA_RETURN(ROId);   
03247          }
03248          if (ROIlink) SUMA_FreeROIDatum((void *)ROIlink); ROIlink = NULL;
03249       }else {
03250          if (LocalHead) fprintf (SUMA_STDERR, "%s: Nodes connected.\n", FuncName);
03251          
03252          ++ROId->N_n;
03253          ROId->nPath = (int *) SUMA_realloc (ROId->nPath, sizeof(int)*ROId->N_n);
03254          ROId->nPath[ROId->N_n-1] = bsd->SurfNode;
03255       }     
03256    
03257       oElmt = Elmt;
03258    } while (Elmt != dlist_tail(sv->BS));
03259       
03260    SUMA_RETURN (ROId);
03261 }
03262 
03263 
03264 
03265 
03266 
03267 
03268 
03269 
03270 
03271 DListElmt * SUMA_PushActionStack (DList *ActionStack, DListElmt *StackPos, 
03272                                   SUMA_ACTION_RESULT (*ActionFunction)(void *ActionData, SUMA_ACTION_POLARITY Pol), 
03273                                   void *ActionData, 
03274                                   void (*ActionDataDestructor)(void *Actiondata))
03275 {
03276    static char FuncName[]={"SUMA_PushActionStack"};
03277    SUMA_Boolean LocalHead = NOPE;
03278    SUMA_ACTION_STACK_DATA *AS_data=NULL;
03279    SUMA_ACTION_RESULT ActionResult = SAR_Undefined;
03280    
03281    SUMA_ENTRY;
03282 
03283    
03284    if (LocalHead) fprintf (SUMA_STDERR, "%s: Executing Action.\n", FuncName);
03285    ActionResult = ActionFunction (ActionData, SAP_Do);
03286    switch (ActionResult) {
03287       case SAR_Fail:
03288          SUMA_SLP_Err("Action failed.");
03289          SUMA_RETURN(NULL);
03290          break;
03291       case SAR_Succeed:
03292          break;
03293       default:
03294          SUMA_SLP_Err("Action result not understood.");
03295          SUMA_RETURN(NULL);
03296          break;
03297    }
03298    
03299    
03300    if (LocalHead) fprintf (SUMA_STDERR, "%s: Removing Action Stack Elements above current position.\n", FuncName);
03301    while (StackPos != dlist_tail(ActionStack)) {
03302       void *asdata=NULL;
03303       
03304       dlist_remove(ActionStack, dlist_tail(ActionStack), &asdata);
03305       
03306       
03307       SUMA_FreeActionStackData(asdata);
03308    }
03309    
03310    
03311    if (LocalHead) fprintf (SUMA_STDERR, "%s: Pushing the action and its data onto the stack.\n", FuncName);
03312    AS_data = (SUMA_ACTION_STACK_DATA *)SUMA_malloc (sizeof(SUMA_ACTION_STACK_DATA));
03313    AS_data->ActionDataDestructor = ActionDataDestructor;
03314    AS_data->ActionFunction = ActionFunction;
03315    AS_data->ActionData = ActionData;
03316    dlist_ins_next (ActionStack, dlist_tail(ActionStack), (void*)AS_data);
03317    if (LocalHead) fprintf (SUMA_STDERR, "%s: Updating StackPos ...\n", FuncName);
03318    StackPos = dlist_tail(ActionStack);
03319    
03320    SUMA_RETURN(StackPos);
03321 }
03322 
03323 
03324 
03325 
03326 
03327 DListElmt * SUMA_RedoAction (DList *ActionStack, DListElmt *StackPos)
03328 {
03329    static char FuncName[]={"SUMA_RedoAction"};
03330    SUMA_ACTION_STACK_DATA *AS_data=NULL;
03331    SUMA_ACTION_RESULT ActionResult = SAR_Undefined;
03332    SUMA_Boolean LocalHead = NOPE;
03333    
03334    SUMA_ENTRY;
03335    
03336    if (!StackPos) {
03337       if (LocalHead) fprintf (SUMA_STDERR, "%s: At bottom of stack. Working up.\n", FuncName);
03338       StackPos = dlist_head(ActionStack);
03339    } else if (StackPos == dlist_tail(ActionStack)) {
03340       SUMA_SLP_Err("At top of stack, nothing to do.");
03341       SUMA_RETURN(StackPos);
03342    } else {
03343       StackPos = dlist_next(StackPos);
03344    }
03345    
03346    
03347    AS_data = (SUMA_ACTION_STACK_DATA *)StackPos->data;
03348    ActionResult = AS_data->ActionFunction (AS_data->ActionData, SAP_Redo);
03349    switch (ActionResult) {
03350       case SAR_Fail:
03351          SUMA_SLP_Err("Action failed.");
03352          SUMA_RETURN(NULL);
03353          break;
03354       case SAR_Succeed:
03355          break;
03356       default:
03357          SUMA_SLP_Err("Action result not understood.");
03358          SUMA_RETURN(NULL);
03359          break;
03360    }
03361    
03362    SUMA_RETURN(StackPos);   
03363 }   
03364 
03365 
03366 
03367 
03368 
03369 
03370 
03371 
03372 
03373 DListElmt * SUMA_UndoAction (DList *ActionStack, DListElmt *StackPos)
03374 {
03375    static char FuncName[]={"SUMA_UndoAction"};
03376    SUMA_ACTION_STACK_DATA *AS_data=NULL;
03377    SUMA_ACTION_RESULT ActionResult = SAR_Undefined;
03378    SUMA_Boolean LocalHead = NOPE;
03379    
03380    SUMA_ENTRY;
03381    
03382    if (!StackPos) {
03383       SUMA_SLP_Err("At bottom of stack.");
03384       SUMA_RETURN(StackPos);
03385    }
03386    
03387    AS_data = (SUMA_ACTION_STACK_DATA *)StackPos->data;
03388    
03389    
03390    ActionResult = AS_data->ActionFunction (AS_data->ActionData, SAP_Undo);
03391    switch (ActionResult) {
03392       case SAR_Fail:
03393          SUMA_SLP_Err("Action failed.");
03394          SUMA_RETURN(NULL);
03395          break;
03396       case SAR_Succeed:
03397          break;
03398       default:
03399          SUMA_SLP_Err("Action result not understood.");
03400          SUMA_RETURN(NULL);
03401          break;
03402    }
03403    
03404    
03405    if (StackPos == dlist_head(ActionStack)) {
03406       
03407    } else {
03408       StackPos = dlist_prev(StackPos);
03409    }
03410    
03411    SUMA_RETURN(StackPos);
03412 }
03413 
03414 
03415 
03416 
03417 SUMA_ACTION_RESULT SUMA_FinishedROI (void *data, SUMA_ACTION_POLARITY Pol)
03418 {
03419    static char FuncName[]={"SUMA_FinishedROI"};
03420    SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
03421    SUMA_SurfaceObject *SOparent=NULL;
03422    SUMA_Boolean LocalHead = NOPE;
03423    
03424    SUMA_ENTRY;
03425    
03426    ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
03427    
03428    switch (Pol) {
03429       case SAP_Do:
03430       case SAP_Redo:
03431          if (LocalHead) fprintf (SUMA_STDERR, "%s: Marking as finished...\n", FuncName);
03432          
03433          ROIA->DrawnROI->DrawStatus = SUMA_ROI_Finished;
03434          
03435          SOparent = SUMA_findSOp_inDOv(ROIA->DrawnROI->Parent_idcode_str, SUMAg_DOv, SUMAg_N_DOv);
03436          if (!SOparent) {
03437             SUMA_SLP_Warn( "Parent surface\n"
03438                            "not found for ROI\n"
03439                            "No contour will\n"
03440                            "be determined." );
03441             SUMA_RETURN(SAR_Succeed);
03442          }else {
03443                
03444             
03445             if (!ROIA->DrawnROI->CE) { 
03446                int *Nodes, N_Nodes;
03447                SUMA_Boolean Unique = NOPE;
03448 
03449                SUMA_LH("Getting Contour ");
03450                N_Nodes = 0;
03451                Unique = YUP; 
03452                Nodes = SUMA_NodesInROI (ROIA->DrawnROI, &N_Nodes, Unique);
03453                if (Nodes) {
03454                   ROIA->DrawnROI->CE = SUMA_GetContour (
03455                                  SOparent, 
03456                                  Nodes, N_Nodes, &(ROIA->DrawnROI->N_CE), 0, NULL);
03457                   if (!ROIA->DrawnROI->CE) { SUMA_LH("Null DrawnROI->CE"); }
03458                   else { SUMA_LH("Good DrawnROI->CE"); }
03459                   SUMA_free(Nodes);
03460                }
03461             }else {
03462                SUMA_SLP_Err("Unexpected Contour");
03463                SUMA_RETURN(SAR_Fail);
03464             }
03465          }
03466 
03467          break;
03468       case SAP_Undo:
03469          if (LocalHead) fprintf (SUMA_STDERR, "%s: Marking as InCreation...\n", FuncName);
03470          ROIA->DrawnROI->DrawStatus = SUMA_ROI_InCreation;
03471          
03472          if (ROIA->DrawnROI->CE) SUMA_free(ROIA->DrawnROI->CE); ROIA->DrawnROI->CE = NULL;
03473          ROIA->DrawnROI->N_CE = -1;
03474          break;
03475       default:
03476          fprintf (SUMA_STDERR, "Error %s: Should not be here.\n", FuncName);
03477          break;
03478    }
03479    
03480    SUMA_RETURN(SAR_Succeed);
03481 }
03482 
03483 
03484 
03485 
03486 
03487 
03488 
03489 
03490 SUMA_ACTION_RESULT SUMA_AddFillROIDatum (void *data, SUMA_ACTION_POLARITY Pol)
03491 {
03492    static char FuncName[]={"SUMA_AddFillROIDatum"};
03493    SUMA_Boolean LocalHead = NOPE;
03494    SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
03495    void *eldata=NULL;
03496    DListElmt *tail_elm=NULL;
03497    SUMA_ROI_DATUM *ROId=NULL;
03498    
03499    SUMA_ENTRY;
03500 
03501    ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
03502    
03503    switch (Pol) {
03504       case SAP_Do:
03505       case SAP_Redo:
03506          if (LocalHead) fprintf (SUMA_STDERR, "%s: Adding to ROIstrokelist...\n", FuncName);
03507          dlist_ins_next(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), (void *)ROIA->ROId);
03508          ROIA->DrawnROI->Type = SUMA_ROI_FilledArea;
03509          break;
03510       case SAP_Undo:
03511          if (LocalHead) fprintf (SUMA_STDERR, "%s: Removing from ROIstrokelist...\n", FuncName);
03512          dlist_remove(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), &eldata);
03513          
03514 
03515          
03516          tail_elm = dlist_tail(ROIA->DrawnROI->ROIstrokelist);
03517          ROId = (SUMA_ROI_DATUM *)tail_elm->data;
03518          if (ROId->Type == SUMA_ROI_NodeSegment) { 
03519             ROIA->DrawnROI->Type = SUMA_ROI_ClosedPath;
03520          }
03521          break;
03522       default:
03523          fprintf (SUMA_STDERR, "Error %s: Should not be here.\n", FuncName);
03524          break;
03525    }
03526    
03527    SUMA_RETURN(SAR_Succeed);
03528 }
03529 
03530 
03531 
03532 
03533 
03534 
03535 
03536 SUMA_ACTION_RESULT SUMA_AddToTailJunctionROIDatum (void *data, SUMA_ACTION_POLARITY Pol)
03537 {
03538    static char FuncName[]={"SUMA_AddToTailJunctionROIDatum"};
03539    SUMA_Boolean LocalHead = NOPE;
03540    SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
03541    void *eldata=NULL;
03542    
03543    SUMA_ENTRY;
03544 
03545    ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
03546    
03547    switch (Pol) {
03548       case SAP_Do:
03549       case SAP_Redo:
03550          if (ROIA->DrawnROI->Type == SUMA_ROI_ClosedPath) {
03551             SUMA_SLP_Err ("Trying to close a closed path!");
03552             SUMA_RETURN(SAR_Fail);
03553          }
03554          if (LocalHead) fprintf (SUMA_STDERR, "%s: Adding to ROIstrokelist...\n", FuncName);
03555          dlist_ins_next(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), (void *)ROIA->ROId);
03556          ROIA->DrawnROI->Type = SUMA_ROI_ClosedPath;
03557          break;
03558       case SAP_Undo:
03559          if (ROIA->DrawnROI->Type == SUMA_ROI_OpenPath) {
03560             SUMA_SLP_Err ("Trying to open an open path!");
03561             SUMA_RETURN(SAR_Fail);
03562          }
03563          if (LocalHead) fprintf (SUMA_STDERR, "%s: Removing from ROIstrokelist...\n", FuncName);
03564          dlist_remove(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), &eldata);
03565          
03566 
03567          ROIA->DrawnROI->Type = SUMA_ROI_OpenPath;
03568          break;
03569       default:
03570          fprintf (SUMA_STDERR, "Error %s: Should not be here.\n", FuncName);
03571          break;
03572    }
03573    
03574    SUMA_RETURN(SAR_Succeed);
03575 }
03576 
03577 
03578 
03579 
03580 
03581 
03582 
03583 
03584 SUMA_ACTION_RESULT SUMA_AddToTailROIDatum (void *data, SUMA_ACTION_POLARITY Pol)
03585 {
03586    static char FuncName[]={"SUMA_AddToTailROIDatum"};
03587    SUMA_Boolean LocalHead = NOPE;
03588    SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
03589    void *eldata=NULL;
03590    
03591    SUMA_ENTRY;
03592 
03593    ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
03594    
03595    switch (Pol) {
03596       case SAP_Do:
03597       case SAP_Redo:
03598          if (LocalHead) fprintf (SUMA_STDERR, "%s: Adding to ROIstrokelist...\n", FuncName);
03599          dlist_ins_next(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), (void *)ROIA->ROId);
03600          break;
03601       case SAP_Undo:
03602          if (LocalHead) fprintf (SUMA_STDERR, "%s: Removing from ROIstrokelist...\n", FuncName);
03603          dlist_remove(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), &eldata);
03604          
03605 
03606          break;
03607       default:
03608          fprintf (SUMA_STDERR, "Error %s: Should not be here.\n", FuncName);
03609          break;
03610    }
03611    
03612    SUMA_RETURN(SAR_Succeed);
03613 }
03614 
03615 
03616 
03617 
03618 
03619 
03620 
03621 
03622 
03623 void SUMA_DestroyROIActionData (void *data)
03624 {  
03625    static char FuncName[]={"SUMA_DestroyROIActionData"};
03626    SUMA_Boolean LocalHead = NOPE;
03627    SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
03628    
03629    SUMA_ENTRY;
03630    
03631    ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
03632    
03633    if (!ROIA) SUMA_RETURNe;
03634    
03635    if (ROIA->ROId) { 
03636       SUMA_FreeROIDatum ((void *)ROIA->ROId);
03637       ROIA->ROId = NULL;
03638    }
03639    
03640    ROIA->DrawnROI = NULL; 
03641    SUMA_free(ROIA);
03642    
03643    SUMA_RETURNe;
03644 }
03645 
03646 
03647 
03648 
03649 
03650 
03651 
03652 void SUMA_SetLight0 (char *s, void *data)
03653 {
03654    static char FuncName[]={"SUMA_SetLight0"};
03655    DList *list=NULL;
03656    SUMA_EngineData *ED = NULL;
03657    SUMA_SurfaceViewer *sv = NULL;
03658    float fv3[3];
03659    SUMA_Boolean LocalHead = NOPE; 
03660 
03661    SUMA_ENTRY;
03662 
03663    if (!s) SUMA_RETURNe;
03664 
03665    sv = (SUMA_SurfaceViewer *)data;
03666 
03667    
03668    if (SUMA_StringToNum (s, fv3, 3) != 3) { 
03669       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
03670       SUMA_RETURNe;
03671    }
03672 
03673    
03674    if (!list) list = SUMA_CreateList();
03675    ED = SUMA_InitializeEngineListData (SE_SetLight0Pos);
03676    if (!SUMA_RegisterEngineListCommand (  list, ED, 
03677                                           SEF_fv3, (void *)fv3, 
03678                                           SES_Suma, (void *)sv, NOPE, 
03679                                           SEI_Tail, NULL )) {
03680       fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
03681       SUMA_RETURNe;
03682    }
03683    
03684    SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
03685 
03686    if (!SUMA_Engine (&list)) {
03687       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
03688    }
03689 
03690    SUMA_RETURNe;
03691 }
03692 
03693 
03694 
03695 
03696 
03697 void SUMA_SetNumForeSmoothing (char *s, void *data)
03698 {
03699    static char FuncName[]={"SUMA_SetNumForeSmoothing"};
03700    DList *list=NULL;
03701    SUMA_EngineData *ED = NULL;
03702    SUMA_SurfaceViewer *sv = NULL;
03703    float fv3[3];
03704    SUMA_Boolean LocalHead = NOPE; 
03705 
03706    SUMA_ENTRY;
03707 
03708    if (!s) SUMA_RETURNe;
03709 
03710    sv = (SUMA_SurfaceViewer *)data;
03711 
03712    
03713    if (SUMA_StringToNum (s, fv3, 1) != 1) { 
03714       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
03715       SUMA_RETURNe;
03716    }
03717 
03718    
03719   
03720    if ((int)fv3[0] < 0) {
03721       SUMA_SLP_Err("Only positive integer\nvalues are valid.\n"); 
03722       SUMA_RETURNe;
03723    } 
03724    SUMAg_CF->X->NumForeSmoothing = (int)fv3[0];
03725    
03726    
03727    SUMA_SetAllRemixFlag(SUMAg_SVv, SUMAg_N_SVv);
03728    
03729    
03730    if (!list) list = SUMA_CreateList();
03731    SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay_AllVisible, SES_Suma, sv);
03732    if (!SUMA_Engine (&list)) {
03733       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
03734    }
03735 
03736    SUMA_RETURNe;
03737    
03738 }
03739 
03740 
03741 
03742 
03743 
03744 
03745 
03746 void SUMA_LookAtCoordinates (char *s, void *data)
03747 {
03748    static char FuncName[]={"SUMA_LookAtCoordinates"};
03749    DList *list=NULL;
03750    SUMA_EngineData *ED = NULL;
03751    SUMA_SurfaceViewer *sv = NULL;
03752    float fv3[3];
03753    SUMA_Boolean LocalHead = NOPE; 
03754 
03755    SUMA_ENTRY;
03756 
03757    if (!s) SUMA_RETURNe;
03758 
03759    sv = (SUMA_SurfaceViewer *)data;
03760 
03761    
03762    if (SUMA_StringToNum (s, fv3, 3) != 3) { 
03763       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
03764       SUMA_RETURNe;
03765    }
03766 
03767    
03768    if (!list) list = SUMA_CreateList();
03769    ED = SUMA_InitializeEngineListData (SE_SetLookAt);
03770    if (!SUMA_RegisterEngineListCommand (  list, ED, 
03771                                           SEF_fv3, (void *)fv3, 
03772                                           SES_Suma, (void *)sv, NOPE, 
03773                                           SEI_Head, NULL )) {
03774       fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
03775       SUMA_RETURNe;
03776    }
03777    if (!SUMA_Engine (&list)) {
03778       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
03779    }
03780 
03781    SUMA_RETURNe;
03782 }
03783 
03784 
03785 
03786 
03787 
03788 
03789 
03790 void SUMA_JumpIndex (char *s, void *data)
03791 {
03792    static char FuncName[]={"SUMA_JumpIndex"};
03793    DList *list=NULL;
03794    SUMA_EngineData *ED = NULL;
03795    SUMA_SurfaceViewer *sv = NULL;
03796    SUMA_SurfaceObject *SO= NULL;
03797    float fv3[3];
03798    int it, iv3[3];
03799    SUMA_Boolean LocalHead = NOPE; 
03800 
03801    SUMA_ENTRY;
03802 
03803    if (!s) SUMA_RETURNe;
03804 
03805    sv = (SUMA_SurfaceViewer *)data;
03806 
03807    
03808    if (SUMA_StringToNum (s, fv3, 1) != 1) { 
03809       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
03810       SUMA_RETURNe;
03811    }
03812    
03813    
03814    it = (int) fv3[0];
03815    if (!list) list = SUMA_CreateList ();
03816    ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
03817    if (!SUMA_RegisterEngineListCommand (  list, ED, 
03818                                           SEF_i, (void*)(&it),
03819                                           SES_Suma, (void *)sv, NOPE,
03820                                           SEI_Head, NULL)) {
03821       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
03822       SUMA_RETURNe;                                      
03823    } 
03824 
03825 
03826    
03827    SO = (SUMA_SurfaceObject *)SUMAg_DOv[sv->Focus_SO_ID].OP;
03828    ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
03829    if (!SUMA_RegisterEngineListCommand (  list, ED, 
03830                                           SEF_fv3, (void*)&(SO->NodeList[3*it]),
03831                                           SES_Suma, (void *)sv, NOPE,
03832                                           SEI_Head, NULL)) {
03833       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
03834       SUMA_RETURNe;                                          
03835    } 
03836 
03837    
03838    iv3[0] = SUMA_findSO_inDOv(SO->idcode_str, SUMAg_DOv, SUMAg_N_DOv);
03839    iv3[1] = it;
03840    ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
03841    if (!SUMA_RegisterEngineListCommand (  list, ED, 
03842                                           SEF_iv3, (void*)iv3,
03843                                           SES_Suma, (void *)sv, NOPE,
03844                                           SEI_Head, NULL)) {
03845       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
03846       SUMA_RETURNe;
03847    }   
03848    
03849    
03850    if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
03851       if (LocalHead) fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
03852       
03853       SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list, SE_SetAfniCrossHair, SES_Suma, sv);
03854    }
03855 
03856    
03857    if (!SUMA_Engine (&list)) {
03858       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
03859       SUMA_RETURNe;
03860    }
03861 
03862    
03863 
03864 
03865    if (!list) list = SUMA_CreateList();
03866    ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
03867    if (!SUMA_RegisterEngineListCommand (  list, ED, 
03868                                           SEF_iv3, (void*)iv3,
03869                                           SES_Suma, (void *)sv, NOPE,
03870                                           SEI_Tail, NULL)) {
03871       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
03872       SUMA_RETURNe;
03873    }
03874 
03875    
03876    if (!SUMA_Engine (&list)) {
03877       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
03878       SUMA_RETURNe;
03879    }
03880 
03881    
03882    sv->ResetGLStateVariables = YUP;
03883    SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA); 
03884    
03885    SUMA_RETURNe;
03886 
03887 }  
03888 
03889 
03890 
03891 
03892 
03893 
03894 
03895 
03896 
03897 
03898 void SUMA_JumpXYZ (char *s, void *data)
03899 {
03900    static char FuncName[]={"SUMA_JumpXYZ"};
03901    DList *list=NULL;
03902    SUMA_EngineData *ED = NULL;
03903    SUMA_SurfaceViewer *sv = NULL;
03904    float fv3[3];
03905    SUMA_Boolean LocalHead = NOPE; 
03906 
03907    SUMA_ENTRY;
03908 
03909    if (!s) SUMA_RETURNe;
03910 
03911    sv = (SUMA_SurfaceViewer *)data;
03912 
03913    
03914    if (SUMA_StringToNum (s, fv3, 3) != 3) { 
03915       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
03916       SUMA_RETURNe;
03917    }
03918    
03919    
03920    if (!list) list = SUMA_CreateList ();
03921    ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
03922    if (!SUMA_RegisterEngineListCommand (  list, ED, 
03923                                           SEF_fv3, (void*)fv3,
03924                                           SES_Suma, (void *)sv, NOPE,
03925                                           SEI_Head, NULL)) {
03926       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
03927       SUMA_RETURNe;                                      
03928    }
03929    
03930    
03931    if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
03932       if (LocalHead) fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
03933       
03934       SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list, SE_SetAfniCrossHair, SES_Suma, sv);
03935    }
03936 
03937    
03938    if (!SUMA_Engine (&list)) {
03939       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
03940       SUMA_RETURNe;
03941    }
03942 
03943    
03944 
03945 
03946    
03947    if (!list) list = SUMA_CreateList();
03948    ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
03949    if (!SUMA_RegisterEngineListCommand (  list, ED, 
03950                                           SEF_Empty, NULL,
03951                                           SES_Suma, (void *)sv, NOPE,
03952                                           SEI_Tail, NULL)) {
03953       SUMA_SLP_Err("Failed to register element");
03954       SUMA_RETURNe;
03955    }
03956 
03957    
03958    if (!SUMA_Engine (&list)) {
03959       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
03960       SUMA_RETURNe;
03961    }
03962 
03963    
03964    
03965    sv->ResetGLStateVariables = YUP;
03966    SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);   
03967    
03968    SUMA_RETURNe;  
03969 }
03970 
03971 
03972 
03973 
03974 
03975 
03976 
03977 
03978 
03979 void SUMA_JumpFocusNode (char *s, void *data)
03980 {
03981    static char FuncName[]={"SUMA_JumpFocusNode"};
03982    DList *list=NULL;
03983    SUMA_EngineData *ED = NULL;
03984    SUMA_SurfaceViewer *sv = NULL;
03985    float fv3[3];
03986    int it;
03987    SUMA_Boolean LocalHead = NOPE; 
03988 
03989    SUMA_ENTRY;
03990 
03991    if (!s) SUMA_RETURNe;
03992 
03993    sv = (SUMA_SurfaceViewer *)data;
03994 
03995    
03996    if (SUMA_StringToNum (s, fv3, 1) != 1) { 
03997       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
03998       SUMA_RETURNe;
03999    }
04000    
04001 
04002    
04003    it = (int) fv3[0];
04004    if (!list) list = SUMA_CreateList ();
04005    ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
04006    if (!SUMA_RegisterEngineListCommand (  list, ED, 
04007                                           SEF_i, (void*)(&it),
04008                                           SES_Suma, (void *)sv, NOPE,
04009                                           SEI_Head, NULL)) {
04010       SUMA_SLP_Err("Failed to register element");
04011       SUMA_RETURNe;                                      
04012    } 
04013    
04014    
04015    if (!SUMA_Engine (&list)) {
04016       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
04017       SUMA_RETURNe;
04018    }
04019    
04020    
04021    sv->ResetGLStateVariables = YUP;
04022    SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);   
04023    
04024    SUMA_RETURNe;  
04025 
04026 }
04027 
04028 
04029 
04030 
04031 
04032 
04033 
04034 void SUMA_JumpFocusFace (char *s, void *data)
04035 {
04036    static char FuncName[]={"SUMA_JumpFocusFace"};
04037    DList *list=NULL;
04038    SUMA_EngineData *ED = NULL;
04039    SUMA_SurfaceViewer *sv = NULL;
04040    float fv3[3];
04041    int it;
04042    SUMA_Boolean LocalHead = NOPE; 
04043 
04044    SUMA_ENTRY;
04045 
04046    if (!s) SUMA_RETURNe;
04047 
04048    sv = (SUMA_SurfaceViewer *)data;
04049 
04050    
04051    if (SUMA_StringToNum (s, fv3, 1) != 1) { 
04052       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
04053       SUMA_RETURNe;
04054    }
04055    
04056    
04057    
04058    
04059    it = (int) fv3[0];
04060    if (!list) list = SUMA_CreateList ();
04061    ED = SUMA_InitializeEngineListData (SE_SetSelectedFaceSet);
04062    if (!SUMA_RegisterEngineListCommand (  list, ED, 
04063                                           SEF_i, (void*)&it,
04064                                           SES_Suma, (void *)sv, NOPE,
04065                                           SEI_Head, NULL)) {
04066       fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
04067       SUMA_RETURNe;                                      
04068    }
04069                
04070    
04071    if (!SUMA_Engine (&list)) {
04072       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
04073       SUMA_RETURNe;
04074    }
04075    
04076    
04077    sv->ResetGLStateVariables = YUP;
04078    SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);   
04079    
04080    SUMA_RETURNe;  
04081 
04082 }
04083 
04084 
04085 
04086 
04087 
04088 
04089 
04090 
04091 
04092 
04093 void SUMA_HighlightBox (char *s, void *data)
04094 {
04095    static char FuncName[]={"SUMA_HighlightBox"};
04096    DList *list=NULL;
04097    SUMA_EngineData *ED = NULL;
04098    SUMA_SurfaceViewer *sv = NULL;
04099    float fv15[15];
04100    int it;
04101    SUMA_Boolean LocalHead = NOPE; 
04102 
04103    SUMA_ENTRY;
04104 
04105    if (!s) SUMA_RETURNe;
04106 
04107    sv = (SUMA_SurfaceViewer *)data;
04108 
04109    
04110    if (SUMA_StringToNum (s, fv15, 6) != 6) { 
04111       XBell (XtDisplay (sv->X->TOPLEVEL), 50);
04112       SUMA_RETURNe;
04113    }
04114    
04115    
04116    if (!list) list = SUMA_CreateList(); 
04117    ED = SUMA_InitializeEngineListData (SE_HighlightNodes);
04118    if (!SUMA_RegisterEngineListCommand (     list, ED, 
04119                                              SEF_fv15, (void*)fv15,
04120                                              SES_Suma, (void *)sv, NOPE,
04121                                              SEI_Head, NULL)) {
04122          fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
04123          SUMA_RETURNe;                                      
04124    }
04125 
04126    SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
04127 
04128    if (!SUMA_Engine (&list)) {
04129       fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
04130    }
04131 
04132    
04133    SUMA_RETURNe;  
04134 
04135 }