1 #include "SUMA_suma.h"
2 #include "SUMA_plot.h"
3 #include "SUMA_clippingPlanes.h"
4
5 #define SUMA_ALTHELL ( (Kev.state & Mod1Mask) || \
6 (Kev.state & Mod2Mask) || \
7 (Kev.state & SUMA_APPLE_AltOptMask) )
8
9 /*!
10 Return the code for the key that is specified in keyin
11 */
SUMA_KeyPress(char * keyin,char * keynameback)12 int SUMA_KeyPress(char *keyin, char *keynameback)
13 {
14 static char FuncName[]={"SUMA_KeyPress"};
15 int nk=0,i=0,nc=0;
16 char keyname[100];
17 char *key=NULL, c='\0';
18 SUMA_Boolean LocalHead = NOPE;
19
20 SUMA_ENTRY;
21
22 if (keynameback) keynameback[0]='\0';
23 keyname[0]='\0';
24
25 if (!keyin) SUMA_RETURN(XK_VoidSymbol);
26 nc = strlen(keyin);
27 if (nc<=0) SUMA_RETURN(XK_VoidSymbol);
28
29 key = SUMA_append_string("+",keyin); /* add a + to simplify parsing */
30
31 nc = strlen(key);
32 SUMA_LHv("Key now '%s'\n", key);
33
34 /* find the last + */
35 i = nc-2; /* skip last char, might itself be + */
36 while (i >= 0 && key[i] != '+') { --i; } ++i; /* reposition past last + */
37
38 /* copy the rest into keyname */
39 nk=0;
40 while (i<nc && nk < 10) {
41 keyname[nk] = key[i];
42 ++i;
43 ++nk;
44 }
45 keyname[nk] = '\0';
46 if (nk > 10 || nk == 0) {
47 SUMA_S_Errv("What kind of key is %s!!!\n", key);
48 SUMA_RETURN(XK_VoidSymbol);
49 }
50 SUMA_LHv("Keyname now '%s'\n", keyname);
51 if (keynameback) sprintf(keynameback,"%s", keyname);
52
53 if (nk == 1) { /* the simple case, add them as needed */
54 c = keyname[0];
55 SUMA_LHv("c now '%c'\n", c);
56 switch(c) {
57 case '0':
58 SUMA_RETURN(XK_0);
59 case '1':
60 SUMA_RETURN(XK_1);
61 case '2':
62 SUMA_RETURN(XK_2);
63 case '3':
64 SUMA_RETURN(XK_3);
65 case '4':
66 SUMA_RETURN(XK_4);
67 case '5':
68 SUMA_RETURN(XK_5);
69 case '6':
70 SUMA_RETURN(XK_6);
71 case '7':
72 SUMA_RETURN(XK_7);
73 case '8':
74 SUMA_RETURN(XK_8);
75 case '9':
76 SUMA_RETURN(XK_9);
77 case 'a':
78 SUMA_RETURN(XK_a);
79 case 'A':
80 SUMA_RETURN(XK_A);
81 case 'b':
82 SUMA_RETURN(XK_b);
83 case 'B':
84 SUMA_RETURN(XK_B);
85 case 'C':
86 SUMA_RETURN(XK_C);
87 case 'c':
88 SUMA_RETURN(XK_c);
89 case 'd':
90 SUMA_RETURN(XK_d);
91 case 'D':
92 SUMA_RETURN(XK_D);
93 case 'f':
94 SUMA_RETURN(XK_f);
95 case 'F':
96 SUMA_RETURN(XK_F);
97 case 'g':
98 SUMA_RETURN(XK_g);
99 case 'G':
100 SUMA_RETURN(XK_G);
101 case 'h':
102 SUMA_RETURN(XK_h);
103 case 'H':
104 SUMA_RETURN(XK_H);
105 case 'j':
106 SUMA_RETURN(XK_j);
107 case 'J':
108 SUMA_RETURN(XK_J);
109 case 'l':
110 SUMA_RETURN(XK_l);
111 case 'L':
112 SUMA_RETURN(XK_L);
113 case 'm':
114 SUMA_RETURN(XK_m);
115 case 'M':
116 SUMA_RETURN(XK_M);
117 case 'n':
118 SUMA_RETURN(XK_n);
119 case 'N':
120 SUMA_RETURN(XK_N);
121 case 'o':
122 SUMA_RETURN(XK_o);
123 case 'O':
124 SUMA_RETURN(XK_O);
125 case 'p':
126 SUMA_RETURN(XK_p);
127 case 'P':
128 SUMA_RETURN(XK_P);
129 case 'r':
130 SUMA_RETURN(XK_r);
131 case 'R':
132 SUMA_RETURN(XK_R);
133 case 's':
134 SUMA_RETURN(XK_s);
135 case 'S':
136 SUMA_RETURN(XK_S);
137 case 't':
138 SUMA_RETURN(XK_t);
139 case 'T':
140 SUMA_RETURN(XK_T);
141 case 'u':
142 SUMA_RETURN(XK_u);
143 case 'U':
144 SUMA_RETURN(XK_U);
145 case 'w':
146 SUMA_RETURN(XK_w);
147 case 'W':
148 SUMA_RETURN(XK_W);
149 case 'z':
150 SUMA_RETURN(XK_z);
151 case 'Z':
152 SUMA_RETURN(XK_Z);
153 case '[':
154 SUMA_RETURN(XK_bracketleft);
155 case ']':
156 SUMA_RETURN(XK_bracketright);
157 case '.':
158 if (keynameback) sprintf(keynameback,"period");
159 SUMA_RETURN(XK_period);
160 case -15:
161 if (keynameback) sprintf(keynameback,"home");
162 SUMA_RETURN(XK_Home);
163 case ' ':
164 if (keynameback) sprintf(keynameback,"space");
165 SUMA_RETURN(XK_space);
166 case 27:
167 if (keynameback) sprintf(keynameback,"escape");
168 SUMA_RETURN(XK_Escape);
169 case '+':
170 SUMA_RETURN(XK_plus);
171 case '-':
172 SUMA_RETURN(XK_minus);
173 case '=':
174 SUMA_RETURN(XK_equal);
175 case '/':
176 SUMA_RETURN(XK_slash);
177 case '*':
178 SUMA_RETURN(XK_asterisk);
179 case '@':
180 SUMA_RETURN(XK_at);
181 case '(':
182 SUMA_RETURN(XK_parenleft);
183 case ',':
184 if (keynameback) sprintf(keynameback,"comma");
185 SUMA_RETURN(XK_comma);
186 default:
187 SUMA_S_Errv("Key '%c' not yet supported, complain to author.\n", c);
188 SUMA_RETURN(XK_VoidSymbol);
189 }
190 } else {
191 if (SUMA_iswordsame_ci(keyname,"up") == 1) SUMA_RETURN(XK_Up);
192 if (SUMA_iswordsame_ci(keyname,"down") == 1) SUMA_RETURN(XK_Down);
193 if (SUMA_iswordsame_ci(keyname,"left") == 1) SUMA_RETURN(XK_Left);
194 if (SUMA_iswordsame_ci(keyname,"right") == 1) SUMA_RETURN(XK_Right);
195 if (SUMA_iswordsame_ci(keyname,"space") == 1) SUMA_RETURN(XK_space);
196 if (SUMA_iswordsame_ci(keyname,"period") == 1) SUMA_RETURN(XK_period);
197 if (SUMA_iswordsame_ci(keyname,"comma") == 1) SUMA_RETURN(XK_comma);
198 if (SUMA_iswordsame_ci(keyname,"escape") == 1) SUMA_RETURN(XK_Escape);
199 if (SUMA_iswordsame_ci(keyname,"home") == 1) SUMA_RETURN(XK_Home);
200 if (SUMA_iswordsame_ci(keyname,"+") == 1) SUMA_RETURN(XK_plus);
201 if (SUMA_iswordsame_ci(keyname,"-") == 1) SUMA_RETURN(XK_minus);
202 if (SUMA_iswordsame_ci(keyname,"=") == 1) SUMA_RETURN(XK_equal);
203 if (SUMA_iswordsame_ci(keyname,"f1") == 1) SUMA_RETURN(XK_F1);
204 if (SUMA_iswordsame_ci(keyname,"f2") == 1) SUMA_RETURN(XK_F2);
205 if (SUMA_iswordsame_ci(keyname,"f3") == 1) SUMA_RETURN(XK_F3);
206 if (SUMA_iswordsame_ci(keyname,"f4") == 1) SUMA_RETURN(XK_F4);
207 if (SUMA_iswordsame_ci(keyname,"f5") == 1) SUMA_RETURN(XK_F5);
208 if (SUMA_iswordsame_ci(keyname,"f6") == 1) SUMA_RETURN(XK_F6);
209 if (SUMA_iswordsame_ci(keyname,"f7") == 1) SUMA_RETURN(XK_F7);
210 if (SUMA_iswordsame_ci(keyname,"f8") == 1) SUMA_RETURN(XK_F8);
211 if (SUMA_iswordsame_ci(keyname,"f9") == 1) SUMA_RETURN(XK_F9);
212 if (SUMA_iswordsame_ci(keyname,"f10") == 1) SUMA_RETURN(XK_F10);
213 if (SUMA_iswordsame_ci(keyname,"f11") == 1) SUMA_RETURN(XK_F11);
214 if (SUMA_iswordsame_ci(keyname,"f12") == 1) SUMA_RETURN(XK_F12);
215 if (SUMA_iswordsame_ci(keyname,"f13") == 1) SUMA_RETURN(XK_F13);
216
217 SUMA_S_Errv("Key '%s' not yet supported, complain to author.\n", keyname);
218 SUMA_RETURN(XK_VoidSymbol);
219 }
220 SUMA_RETURN(XK_VoidSymbol);
221 }
222
223 #define SUMA_KEY_COMMON { \
224 if (!sv || !key) { \
225 SUMA_S_Err("Null input"); \
226 SUMA_RETURN(0); \
227 } \
228 if (!(nc = strlen(key))) { \
229 SUMA_S_Err("Empty key"); \
230 SUMA_RETURN(0); \
231 } \
232 \
233 SUMA_LHv("Have %s, nc=%d\n", key, nc); \
234 if ((k = SUMA_KeyPress(key, keyname)) == XK_VoidSymbol) { \
235 SUMA_S_Errv("KeyPress for %s could not be obtained.\n", key); \
236 SUMA_RETURN(0); \
237 } \
238 SUMA_LHv("Have keyname = %s\n", keyname); \
239 if (SUMA_iswordsame_ci(keyname,tk) != 1) { \
240 SUMA_S_Errv("Expecting %s (or lower case version), got %s\n", \
241 tk, keyname ); \
242 SUMA_RETURN(0); \
243 } \
244 }
245
246 #define SUMA_KEY_SWITCH { \
247 /* Check for key switching */ \
248 if (sv->State && strstr(sv->State, "GMATRIX")==sv->State) { \
249 if (SUMA_SHIFT_KEY(key)) { \
250 strncpy(skeyi, key, 63); skeyi[64]='\0'; \
251 SUMA_wordswap_ci(skeyi, "shift", "", skey); \
252 } else \
253 snprintf(skey,63,"shift%s",key); \
254 key = skey; \
255 } \
256 }
257
258
259 #if 0 /* a template to use for various keys , replace CHAR by upper case char and cHaR by lower case*/
260 int SUMA_CHAR_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
261 {
262 static char FuncName[]={"SUMA_CHAR_Key"};
263 char tk[]={"CHAR"}, keyname[100];
264 int k, nc;
265 SUMA_Boolean LocalHead = NOPE;
266
267 SUMA_ENTRY;
268
269 SUMA_KEY_COMMON;
270
271 /* do the work */
272 switch (k) {
273 case XK_CHAR:
274 break;
275 case XK_cHaR:
276 break;
277 default:
278 SUMA_S_Err("Il ne faut pas ci dessous");
279 SUMA_RETURN(0);
280 break;
281 }
282
283 SUMA_RETURN(1);
284 }
285 #endif
286
SUMA_parenleft_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode,Widget w,XtPointer clientData,XtPointer callData)287 int SUMA_parenleft_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode,
288 Widget w, XtPointer clientData, XtPointer callData)
289 {
290 static char FuncName[]={"SUMA_parenleft_Key"};
291 char tk[]={"("}, keyname[100];
292 int k, nc, i;
293 char stmp[200];
294 SUMA_Boolean LocalHead = NOPE;
295 GLfloat *glar_ColorList = NULL;
296
297 SUMA_ENTRY;
298
299 // fprintf(stderr, "%s\n", FuncName);
300
301 SUMA_KEY_COMMON;
302
303 // do the work
304 switch (k) {
305 case XK_parenleft:
306 if (SUMAg_CF->Dev) {
307 SUMA_SurfaceObject *SO;
308 SUMA_COLOR_MAP *CM;
309 SUMA_SCALE_TO_MAP_OPT * OptScl;
310 int MapType;
311 SUMA_COLOR_SCALED_VECT * SV;
312 float IntRange[2], *Vsort;
313 float * attr_sm;
314 float *Cx = NULL;
315
316 fprintf(SUMA_STDOUT, "%s: Calculating convexity ...\n", FuncName);
317 if ((SO = SUMA_SV_Focus_SO(sv))) {
318 Cx = (float *)SUMA_GetCx(SO->idcode_str,
319 SUMAg_CF->DsetList, 0);
320 if (Cx) {
321 SUMA_S_Err("Cx must be null prior to new assignment");
322 break;
323 }
324 Cx = SUMA_Convexity ( SO->NodeList, SO->N_Node,
325 SO->NodeNormList, SO->FN, NULL);
326 if (Cx == NULL) {
327 fprintf(stderr,"Error %s: Failed in SUMA_Convexity\n",
328 FuncName);
329 break;
330 }
331 /* smooth estimate twice */
332 attr_sm = SUMA_SmoothAttr_Neighb (Cx, SO->N_Node, NULL,
333 SO->FN, 1, NULL, 1);
334 if (attr_sm == NULL) {
335 fprintf(stderr,
336 "Error %s: Failed in SUMA_SmoothAttr_Neighb\n",
337 FuncName);
338 break;
339 }
340 Cx = SUMA_SmoothAttr_Neighb (attr_sm, SO->N_Node, Cx,
341 SO->FN, 1, NULL, 1);
342 if (attr_sm) SUMA_free(attr_sm);
343
344 fprintf( SUMA_STDOUT,
345 "%s: Use SUMA_ScaleToMap to colorize Conv.txt "
346 "and display it on surface.\n", FuncName);
347 CM = SUMA_FindNamedColMap ("ngray20");
348 if (CM == NULL) {
349 fprintf (SUMA_STDERR,
350 "Error %s: Could not get standard colormap.\n",
351 FuncName);
352 exit (1);
353 }
354
355 /* get the options for creating the scaled color mapping */
356 OptScl = SUMA_ScaleToMapOptInit();
357 if (!OptScl) {
358 SUMA_S_Err("Could not get scaling option structure.");
359 exit (1);
360 }
361
362 /* work the options a bit */
363 OptScl->ApplyClip = YUP;
364 IntRange[0] = 5; IntRange[1] = 95; /* percentile clip range*/
365 Vsort = SUMA_PercRange (Cx, NULL, SO->N_Node,
366 IntRange, IntRange, NULL);
367 OptScl->IntRange[0] = IntRange[0];
368 OptScl->IntRange[1] = IntRange[1];
369
370 OptScl->BrightFact = 0.4;
371
372 /* map the values in Cx to the colormap */
373 /* allocate space for the result */
374 SV = SUMA_Create_ColorScaledVect(SO->N_Node, 0);
375 if (!SV) {
376 fprintf (SUMA_STDERR,
377 "Error %s: Could not allocate for SV.\n",
378 FuncName);
379 exit(1);
380 }
381
382 /* finally ! */
383 /*fprintf ( SUMA_STDERR,"%s: 1st color in map %f %f %f\n",
384 FuncName,
385 CM->M[0][0], CM->M[0][1],CM->M[0][2]);*/
386 if (!SUMA_ScaleToMap (Cx, SO->N_Node, Vsort[0],
387 Vsort[SO->N_Node-1], CM, OptScl, SV)) {
388 fprintf (SUMA_STDERR,
389 "Error %s: Failed in SUMA_ScaleToMap.\n",
390 FuncName);
391 exit(1);
392 }
393
394 /* Now place SV in the color array */
395 glar_ColorList = SUMA_GetColorList (sv, SO->idcode_str);
396 if (!glar_ColorList) {
397 SUMA_S_Err("NULL glar_ColorList. BAD.");
398 break;
399 }
400 SUMA_RGBvec_2_GLCOLAR4(SV->cV, glar_ColorList, SO->N_Node);
401
402 /* free */
403 if (Vsort) SUMA_free(Vsort);
404 if (OptScl) SUMA_free(OptScl);
405 if (SV) SUMA_Free_ColorScaledVect (SV);
406 if (Cx) {
407 SUMA_free(Cx);
408 Cx = NULL;
409 }
410
411 fprintf(SUMA_STDOUT, "%s: Convexity mapping done ...\n",
412 FuncName);
413 SUMA_postRedisplay(w, clientData, callData);
414 }
415 }
416 break;
417 default:
418 SUMA_S_Err("Il ne faut pas etre la");
419 SUMA_RETURN(0);
420 break;
421 }
422
423 SUMA_RETURN(1);
424 }
425
SUMA_at_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)426 int SUMA_at_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
427 {
428 static char FuncName[]={"SUMA_at_Key"};
429 char tk[]={"@"}, keyname[100];
430 int k, nc, i;
431 char stmp[200];
432 SUMA_Boolean LocalHead = NOPE;
433
434 SUMA_ENTRY;
435
436 // fprintf(stderr, "%s\n", FuncName);
437
438 SUMA_KEY_COMMON;
439
440 // do the work
441 switch (k) {
442 case XK_at:
443 if (SUMAg_CF->Dev) {
444 SUMA_SurfaceObject *SO=NULL;
445 /* calculate the curvature */
446 fprintf(SUMA_STDOUT,
447 "%s: Calculating surface curvature ...\n", FuncName);
448 if ((SO = SUMA_SV_Focus_SO(sv))){
449 if (!SO->PolyArea) {
450 fprintf(SUMA_STDOUT,
451 "%s: Computing required mesh area.\n", FuncName);
452 if (!SUMA_SurfaceMetrics (SO, "PolyArea", NULL)) {
453 fprintf (SUMA_STDERR,
454 "Error %s: Failed in SUMA_SurfaceMetrics.\n",
455 FuncName);
456 break;
457 }
458 }
459 SO->SC = SUMA_Surface_Curvature (SO->NodeList, SO->N_Node,
460 SO->NodeNormList, SO->PolyArea,
461 SO->N_FaceSet, SO->FN, SO->EL, "Curvs_c.txt", 1);
462 if (SO->SC == NULL) {
463 fprintf( stderr,
464 "Error %s: Failed in SUMA_Surface_Curvature\n",
465 FuncName);
466 break;
467 }
468 }
469 }
470 break;
471 default:
472 SUMA_S_Err("Il ne faut pas etre la");
473 SUMA_RETURN(0);
474 break;
475 }
476
477 SUMA_RETURN(1);
478 }
479
SUMA_asterisk_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)480 int SUMA_asterisk_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
481 {
482 static char FuncName[]={"SUMA_asterisk_Key"};
483 char tk[]={"*"}, keyname[100];
484 int k, nc, i;
485 char stmp[200];
486 SUMA_Boolean LocalHead = NOPE;
487
488 SUMA_ENTRY;
489
490 // fprintf(stderr, "%s\n", FuncName);
491
492 SUMA_KEY_COMMON;
493
494 // do the work
495 switch (k) {
496 case XK_slash:
497 case XK_asterisk:
498 {
499 char stmp[100];
500 sprintf(stmp, "%d", SUMAg_CF->X->NumFinalSmoothing);
501 SUMAg_CF->X->N_FinalSmooth_prmpt =
502 SUMA_CreatePromptDialogStruct (SUMA_OK_APPLY_CLEAR_CANCEL,
503 "Final color smoothing iterations",
504 stmp,
505 sv->X->TOPLEVEL, YUP,
506 SUMA_APPLY_BUTTON,
507 SUMA_SetNumFinalSmoothing, (void *)sv,
508 NULL, NULL,
509 NULL, NULL,
510 SUMA_CleanNumString, (void*)1,
511 SUMAg_CF->X->N_FinalSmooth_prmpt);
512
513 SUMAg_CF->X->N_FinalSmooth_prmpt =
514 SUMA_CreatePromptDialog("Final color smoothing iterations",
515 SUMAg_CF->X->N_FinalSmooth_prmpt);
516 }
517 break;
518 default:
519 SUMA_S_Err("Il ne faut pas etre la");
520 SUMA_RETURN(0);
521 break;
522 }
523
524 SUMA_RETURN(1);
525 }
526
SUMA_slash_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)527 int SUMA_slash_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
528 {
529 static char FuncName[]={"SUMA_slash_Key"};
530 char tk[]={"/"}, keyname[100];
531 int k, nc, i;
532 char stmp[200];
533 SUMA_Boolean LocalHead = NOPE;
534
535 SUMA_ENTRY;
536
537 // fprintf(stderr, "%s\n", FuncName);
538
539 SUMA_KEY_COMMON;
540
541 // do the work
542 switch (k) {
543 case XK_slash:
544 if (!list) list = SUMA_CreateList();
545 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Home, SES_Suma, sv);
546 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_FOVreset, SES_Suma, sv);
547 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
548 if (!SUMA_Engine (&list)) {
549 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
550 }
551 break;
552 default:
553 SUMA_S_Err("Il ne faut pas etre la");
554 SUMA_RETURN(0);
555 break;
556 }
557
558 SUMA_RETURN(1);
559 }
560
SUMA_home_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)561 int SUMA_home_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
562 {
563 static char FuncName[]={"SUMA_home_Key"};
564 char tk[]={"home"}, keyname[100];
565 int k, nc, i;
566 char stmp[200];
567 SUMA_Boolean LocalHead = NOPE;
568
569 SUMA_ENTRY;
570
571 // fprintf(stderr, "%s\n", FuncName);
572
573 SUMA_KEY_COMMON;
574
575 // do the work
576 switch (k) {
577 case XK_Home:
578 if (!list) list = SUMA_CreateList();
579 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Home, SES_Suma, sv);
580 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_FOVreset, SES_Suma, sv);
581 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
582 if (!SUMA_Engine (&list)) {
583 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
584 }
585 break;
586 default:
587 SUMA_S_Err("Il ne faut pas etre la");
588 SUMA_RETURN(0);
589 break;
590 }
591
592 SUMA_RETURN(1);
593 }
594
SUMA_plus_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)595 int SUMA_plus_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
596 {
597 static char FuncName[]={"SUMA_plus_Key"};
598 char tk[]={"+"}, keyname[100];
599 int k, nc;
600 char stmp[200];
601 SUMA_Boolean LocalHead = NOPE;
602
603 SUMA_ENTRY;
604
605 // fprintf(stderr, "%s\n", FuncName);
606
607 SUMA_KEY_COMMON;
608
609 /* do the work */
610 switch (k) {
611 case XK_plus:
612 if (clippingPlaneMode && scrollInc < 999999){
613 scrollInc *= 2.0;
614 tiltInc *= 2.0;
615 sv->clippingPlaneIncrement = scrollInc;
616 SUMA_UpdateViewerTitle(sv);
617 }
618 break;
619 default:
620 SUMA_S_Err("Il ne faut pas etre la");
621 SUMA_RETURN(0);
622 break;
623 }
624
625 SUMA_RETURN(1);
626 }
627
SUMA_minus_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)628 int SUMA_minus_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
629 {
630 static char FuncName[]={"SUMA_minus_Key"};
631 char tk[]={"-"}, keyname[100];
632 int k, nc;
633 char stmp[200];
634 SUMA_Boolean LocalHead = NOPE;
635
636 SUMA_ENTRY;
637
638 // fprintf(stderr, "%s\n", FuncName);
639
640 SUMA_KEY_COMMON;
641
642 /* do the work */
643 switch (k) {
644 case XK_minus:
645 if (clippingPlaneMode){
646 scrollInc /= 2.0;
647 tiltInc /= 2.0;
648 sv->clippingPlaneIncrement = scrollInc;
649 SUMA_UpdateViewerTitle(sv);
650 }
651 break;
652 default:
653 SUMA_S_Err("Il ne faut pas etre la");
654 SUMA_RETURN(0);
655 break;
656 }
657
658 SUMA_RETURN(1);
659 }
660
SUMA_equal_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)661 int SUMA_equal_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
662 {
663 static char FuncName[]={"SUMA_equal_Key"};
664 char tk[]={"="}, keyname[100];
665 int k, nc;
666 char stmp[200];
667 SUMA_Boolean LocalHead = NOPE;
668
669 SUMA_ENTRY;
670
671 SUMA_KEY_COMMON;
672
673 /* do the work */
674 switch (k) {
675 case XK_equal:
676 if (clippingPlaneMode){
677 scrollInc = 1.0;
678 tiltInc = 1.0;
679 sv->clippingPlaneIncrement = scrollInc;
680 SUMA_UpdateViewerTitle(sv);
681 }
682 break;
683 default:
684 SUMA_S_Err("Il ne faut pas etre la");
685 SUMA_RETURN(0);
686 break;
687 }
688
689 SUMA_RETURN(1);
690 }
691
692
693 static int Nwarn_bracket = 0;
694
SUMA_bracketleft_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)695 int SUMA_bracketleft_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
696 {
697 static char FuncName[]={"SUMA_bracketleft_Key"};
698 char tk[]={"["}, keyname[100];
699 int k, nc;
700 char stmp[200];
701 SUMA_Boolean LocalHead = NOPE;
702
703 SUMA_ENTRY;
704
705 // fprintf(stderr, "%s\n", FuncName);
706
707 SUMA_KEY_COMMON;
708
709 /* do the work */
710 switch (k) {
711 case XK_bracketleft:
712 /* getting rid of some warnings that happen with normal use */
713 Nwarn_bracket = 1; /* warning always in terminal, no message to window */
714 /* toggle showing left hemispheres */
715 sv->ShowLeft = !sv->ShowLeft;
716 /* do the axis setup */
717 SUMA_WorldAxisStandard (sv->WAx, sv);
718 SUMA_UpdateViewerTitle(sv);
719 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
720 if (sv->ShowLeft) {
721 sprintf(stmp,"Showing Left side%s",
722 Nwarn_bracket ?
723 "":"\nFurther notices for '[' or ']' keys will be echoed in the shell");
724 } else {
725 sprintf(stmp,"Hiding Left side%s",
726 Nwarn_bracket > 1 ?
727 "":"\nFurther notices for '[' or ']' keys will be echoed in the shell");
728 }
729 if (!Nwarn_bracket && callmode &&
730 strcmp(callmode, "interactive") == 0) {
731 SUMA_SLP_Note("%s",stmp);
732 } else { SUMA_S_Note("%s",stmp); }
733 /* ++Nwarn_bracket;*/
734 break;
735 default:
736 SUMA_S_Err("Il ne faut pas etre la");
737 SUMA_RETURN(0);
738 break;
739 }
740
741 SUMA_RETURN(1);
742 }
743
SUMA_bracketright_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)744 int SUMA_bracketright_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
745 {
746 static char FuncName[]={"SUMA_bracketright_Key"};
747 char tk[]={"]"}, keyname[100];
748 int k, nc;
749 char stmp[200];
750 SUMA_Boolean LocalHead = NOPE;
751
752 SUMA_ENTRY;
753
754 // fprintf(stderr, "%s\n", FuncName);
755
756 SUMA_KEY_COMMON;
757
758 /* do the work */
759 switch (k) {
760 case XK_bracketright:
761 /* getting rid of some warnings that happen with normal use */
762 Nwarn_bracket = 1; /* warning always in terminal, no message to window */
763 /* toggle showing left hemispheres */
764 sv->ShowRight = !sv->ShowRight;
765 /* do the axis setup */
766 SUMA_WorldAxisStandard (sv->WAx, sv);
767 SUMA_UpdateViewerTitle(sv);
768 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
769 if (sv->ShowRight) {
770 sprintf(stmp,"Showing Right side%s",
771 Nwarn_bracket ?
772 "":"\nFurther notices for '[' or ']' key will be in the shell");
773 } else {
774 sprintf(stmp,"Hiding right side%s",
775 Nwarn_bracket ?
776 "":"\nFurther notices for '[' or ']' key will be in the shell");
777 }
778 if (!Nwarn_bracket && callmode &&
779 strcmp(callmode, "interactive") == 0) {
780 SUMA_SLP_Note("%s",stmp);
781 } else { SUMA_S_Note("%s",stmp); }
782 /* ++Nwarn_bracket;*/
783 break;
784 default:
785 SUMA_S_Err("Il ne faut pas etre la");
786 SUMA_RETURN(0);
787 break;
788 }
789
790 SUMA_RETURN(1);
791 }
792
SUMA_escape_key(SUMA_SurfaceViewer * sv,char * key,char * callmode,Widget w,XtPointer clientData,XtPointer callData)793 int SUMA_escape_key(SUMA_SurfaceViewer *sv, char *key, char *callmode,
794 Widget w, XtPointer clientData, XtPointer callData)
795 {
796 static char FuncName[]={"SUMA_escape_key"};
797 char tk[]={"escape"}, keyname[100];
798 int k, nc;
799 int nxtstateID=-1, curstateID = -1;
800 int origState = -1, dov_ID = -1;
801 SUMA_SurfaceObject *SO = NULL, *SOmap = NULL;
802 SUMA_Boolean LocalHead = NOPE;
803
804 SUMA_ENTRY;
805
806 fprintf(stderr, "%s\n", FuncName);
807
808
809 SUMA_KEY_COMMON;
810
811 origState = sv->iState;
812
813 /* do the work */
814 switch (k) {
815 case XK_Escape:// there's more:
816 // XK_BackSpace XK_Tab XK_Linefeed XK_Return XK_Delete
817 // control mask and escape is grabbed by gnome window manager ....
818 if (SUMA_SHIFT_KEY(key)){// kill all
819
820 fprintf(stderr, "Shift key \n", FuncName);
821 if( SUMAg_CF->X->WarnClose) {
822 if (SUMA_ForceUser_YesNo(sv->X->TOPLEVEL,
823 "Close All Viewers?", SUMA_YES,
824 SWP_DONT_CARE) != SUMA_YES) {
825 break;
826 }
827 }
828 XtCloseDisplay( SUMAg_CF->X->DPY_controller1 ) ;
829 exit(0);
830 }else {
831 fprintf(stderr, "No shift key \n", FuncName);
832 if( SUMAg_CF->X->WarnClose) {
833 #ifdef DARWIN
834 if (SUMA_ForceUser_YesNo(sv->X->TOPLEVEL,
835 "Close This Viewer?\n"
836 "OS-X users: If answering YES,\n"
837 "this prompt should not lie \n"
838 "over viewer to be closed.\n"
839 "Blame Bill Gates for this bug.",
840 SUMA_YES, SWP_TOP_RIGHT) != SUMA_YES) {
841 break;
842 }
843 #else
844 if (SUMA_ForceUser_YesNo(sv->X->TOPLEVEL,
845 "Close This Viewer?", SUMA_YES,
846 SWP_DONT_CARE) != SUMA_YES) {
847 break;
848 }
849 #endif
850 }
851 SUMA_ButtClose_pushed (w, clientData, callData);
852 }
853 break;
854 default:
855 SUMA_S_Err("Il ne faut pas etre la");
856 SUMA_RETURN(0);
857 break;
858 }
859
860 SUMA_RETURN(1);
861 }
862
SUMA_space_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)863 int SUMA_space_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
864 {
865 static char FuncName[]={"SUMA_space_Key"};
866 char tk[]={"SPACE"}, keyname[100];
867 int k, nc;
868 int nxtstateID=-1, curstateID = -1;
869 int origState = -1, dov_ID = -1;
870 SUMA_SurfaceObject *SO = NULL, *SOmap = NULL;
871 SUMA_Boolean LocalHead = NOPE;
872
873 SUMA_ENTRY;
874
875 // fprintf(stderr, "%s\n", FuncName);
876
877
878 SUMA_KEY_COMMON;
879
880 origState = sv->iState;
881
882 /* do the work */
883 switch (k) {
884 case XK_space:
885 /* toggle between state containing mapping reference
886 of SO in focus and other view */
887
888 /* make sure switching is OK */
889 curstateID = SUMA_WhichState(sv->State, sv, sv->CurGroupName);
890 if ((SO = SUMA_SV_Focus_SO(sv))) { /* have something to work with */
891 if (SUMA_isLocalDomainParent (SO)) {
892 /* get the last non mappable state in SV */
893 if (sv->LastNonMapStateID < 0) {
894 /* not recorded, complain and quit */
895 fprintf(SUMA_STDERR,
896 "Warning %s: Nothing defined to toggle with yet.\n",
897 FuncName);
898 break;
899 }
900
901 if (LocalHead)
902 fprintf (SUMA_STDERR,
903 "%s: surface is inherrently mappable, "
904 "switching to last non mappable state %d.\n",
905 FuncName, sv->LastNonMapStateID);
906
907 if (!SUMA_SwitchState ( SUMAg_DOv, SUMAg_N_DOv, sv,
908 sv->LastNonMapStateID, sv->CurGroupName)) {
909 fprintf( SUMA_STDERR,
910 "Error %s: Failed in SUMA_SwitchState.\n", FuncName);
911 break;
912 }
913
914 } else if (!((SO->LocalDomainParentID) )) {
915 fprintf(stderr, "Warning SUMA_space_Key: No default parent for surface object!\n");
916 } else {/* that's a non mappable, go to state containing reference */
917 if (LocalHead)
918 fprintf (SUMA_STDERR,
919 "%s: surface is not inherrently mappable, "
920 "searching for mapping reference and its state.\n",
921 FuncName);
922
923 /* find SO that is mappable reference & get its state ID*/
924 fprintf(stderr, "SO=%p\n", SO);
925 fprintf(stderr, "SO->LocalDomainParentID=%s\n", SO->LocalDomainParentID);
926 fprintf(stderr, "SUMAg_DOv=%p\n", SUMAg_DOv);
927 fprintf(stderr, "SUMAg_N_DOv=%d\n", SUMAg_N_DOv);
928 dov_ID = SUMA_findSO_inDOv(SO->LocalDomainParentID, SUMAg_DOv,
929 SUMAg_N_DOv);
930 fprintf(stderr, "Okk 2\n");
931 SOmap = (SUMA_SurfaceObject *)SUMAg_DOv[dov_ID].OP;
932 nxtstateID = SUMA_WhichState(SOmap->State, sv, sv->CurGroupName);
933
934 if (nxtstateID < 0) {
935 fprintf (SUMA_STDERR,
936 "%s: Failed in SUMA_findSO_inDOv "
937 "This should not happen.\n", FuncName);
938 break;
939 }
940
941 if (LocalHead)
942 fprintf (SUMA_STDERR,
943 "%s: Found mapping reference in viewer state %d.\n",
944 FuncName, nxtstateID);
945
946 /* store this location */
947 sv->LastNonMapStateID = curstateID;
948
949 /* go there */
950 if (!SUMA_SwitchState ( SUMAg_DOv, SUMAg_N_DOv, sv,
951 nxtstateID, sv->CurGroupName)) {
952 fprintf( SUMA_STDERR,
953 "Error %s: Failed in SUMA_SwitchState.\n",
954 FuncName);
955 break;
956 }
957 }
958
959 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
960 } else {
961 SUMA_LH("No surfaces in this state, space bar ignored");
962 }
963 break;
964 default:
965 SUMA_S_Err("Il ne faut pas etre la");
966 SUMA_RETURN(0);
967 break;
968 }
969
970 SUMA_RETURN(1);
971 }
972
SUMA_comma_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)973 int SUMA_comma_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
974 {
975 static char FuncName[]={"SUMA_comma_Key"};
976 char tk[]={"COMMA"}, keyname[100], stmp[256];
977 int k, nc, ii;
978 int nxtstateID=-1, curstateID = -1;
979 int origState = -1;
980 char *note=NULL;
981 DList *list=NULL;
982 SUMA_Boolean LocalHead = NOPE;
983
984 SUMA_ENTRY;
985
986 // fprintf(stderr, "%s\n", FuncName);
987
988 SUMA_KEY_COMMON;
989
990 origState = sv->iState;
991
992 /* do the work */
993 switch (k) {
994 case XK_comma:
995 /* switch state, back one */
996 if (sv->N_VSv < 2) break;
997
998 curstateID = SUMA_WhichState (sv->State, sv, sv->CurGroupName);
999 if (curstateID < 0) {
1000 SUMA_SL_Err("Current State not found.\n"
1001 "Should not happen here.");
1002 SUMA_RETURN(0);
1003 }
1004
1005 if (SUMAg_N_SVv > 1) {
1006 ii = SUMA_WhichViewerInMomentum (SUMAg_SVv, SUMAg_N_SVv, sv);
1007 if (ii >= 0) {
1008 sprintf (stmp, "You cannot switch states while other viewers\n"
1009 "(like viewer %c) in momentum mode.\n", ii+65);
1010 SUMA_RegisterMessage (SUMAg_CF->MessageList,
1011 stmp, FuncName, SMT_Error, SMA_LogAndPopup);
1012 SUMA_RETURN(0);
1013 }
1014 }
1015
1016 do {
1017 if (LocalHead && nxtstateID > -1) {
1018 note = SUMA_append_string("Skipping state ",sv->State);
1019 note = SUMA_append_replace_string(note,
1020 ".\nNo surfaces visible.", "", 1);
1021 SUMA_SLP_Note("%s",note);
1022 SUMA_free(note); note = NULL;
1023 }
1024
1025 /*fprintf(SUMA_STDERR,"%s: Current viewing state is %s ...\n",
1026 FuncName, sv->State);*/
1027 /* toggle to the next view state */
1028 nxtstateID = SUMA_PrevState(sv);
1029 if (nxtstateID == curstateID) break;
1030 if (nxtstateID < 0) {
1031 fprintf(SUMA_STDERR,
1032 "Error %s: Failed in SUMA_PrevState.\n", FuncName);
1033 break;
1034 }
1035 fprintf( SUMA_STDERR,"%s: Switching from %s to %s viewing state.\n",
1036 FuncName, sv->State, sv->VSv[nxtstateID].Name);
1037
1038 if (!SUMA_SwitchState ( SUMAg_DOv, SUMAg_N_DOv, sv,
1039 nxtstateID, sv->CurGroupName)) {
1040 fprintf( SUMA_STDERR,
1041 "Error %s: Failed in SUMA_SwitchState.\n", FuncName);
1042 break;
1043 }
1044
1045 /* find out if there are any surfaces that will be rendered */
1046
1047 } while (!SUMA_Selectable_ADOs (sv, SUMAg_DOv, NULL) &&
1048 sv->iState != origState);
1049
1050 /* register a call to redisplay
1051 (you also need to copy the color data,
1052 in case the next surface is of the same family)*/
1053 if (!list) list = SUMA_CreateList();
1054 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
1055 if (!SUMA_Engine (&list)) {
1056 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
1057 }
1058
1059 /* update titles */
1060 SUMA_UpdateViewerTitle(sv);
1061 break;
1062 default:
1063 SUMA_S_Err("Il ne faut pas etre la");
1064 SUMA_RETURN(0);
1065 break;
1066 }
1067
1068 SUMA_RETURN(1);
1069 }
1070
SUMA_period_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1071 int SUMA_period_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1072 {
1073 static char FuncName[]={"SUMA_period_Key"};
1074 char tk[]={"PERIOD"}, keyname[100], stmp[256];
1075 int k, nc, ii;
1076 int nxtstateID=-1, curstateID = -1;
1077 int origState = -1;
1078 char *note=NULL;
1079 DList *list=NULL;
1080 SUMA_Boolean LocalHead = NOPE;
1081
1082 SUMA_ENTRY;
1083
1084 // fprintf(stderr, "%s\n", FuncName);
1085
1086 SUMA_KEY_COMMON;
1087
1088 origState = sv->iState;
1089
1090 /* do the work */
1091 switch (k) {
1092 case XK_period:
1093 /* switch state, forward one */
1094 if (sv->N_VSv < 2) break;
1095
1096 curstateID = SUMA_WhichState (sv->State, sv, sv->CurGroupName);
1097 if (curstateID < 0) {
1098 SUMA_SL_Err("Current State not found.\n"
1099 "Should not happen here.");
1100 SUMA_RETURN(0);
1101 }
1102
1103 if (SUMAg_N_SVv > 1) {
1104 ii = SUMA_WhichViewerInMomentum (SUMAg_SVv, SUMAg_N_SVv, sv);
1105 if (ii >= 0) {
1106 sprintf (stmp, "You cannot switch states while other viewers\n"
1107 "(like viewer %c) are in momentum mode.\n", ii+65);
1108 SUMA_RegisterMessage (SUMAg_CF->MessageList,
1109 stmp, FuncName, SMT_Error, SMA_LogAndPopup);
1110 SUMA_RETURN(0);
1111 }
1112 }
1113
1114 do {
1115 if (LocalHead && nxtstateID > -1) {
1116 note = SUMA_append_string("Skipping state ",sv->State);
1117 note = SUMA_append_replace_string(note,
1118 ".\nNo surfaces visible.", "", 1);
1119 SUMA_SLP_Note("%s",note);
1120 SUMA_free(note); note = NULL;
1121 }
1122
1123 if (LocalHead)
1124 fprintf(SUMA_STDERR,"%s: Current viewing state is %s ...\n",
1125 FuncName, sv->State);
1126
1127 /* toggle to the next view state */
1128 nxtstateID = SUMA_NextState(sv);
1129 if (nxtstateID == curstateID) break;
1130 if (nxtstateID < 0) {
1131 fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_NextState.\n",
1132 FuncName);
1133 break;
1134 }
1135
1136 fprintf( SUMA_STDERR,
1137 "%s: Switching from %s to %s viewing state.\n",
1138 FuncName, sv->State, sv->VSv[nxtstateID].Name);
1139
1140 if (!SUMA_SwitchState ( SUMAg_DOv, SUMAg_N_DOv, sv,
1141 nxtstateID, sv->CurGroupName)) {
1142 fprintf( SUMA_STDERR,
1143 "Error %s: Failed in SUMA_SwitchState.\n", FuncName);
1144 break;
1145 }
1146 SUMA_SET_AS_NEEDED_2D_VIEW_ANGLE(sv);
1147
1148 } while (!SUMA_Selectable_ADOs(sv, SUMAg_DOv, NULL) &&
1149 sv->iState != origState);
1150 /* register a call to redisplay
1151 (you also need to copy the color data, in case the next surface
1152 is of the same family)*/
1153 if (!list) list = SUMA_CreateList();
1154 SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_Redisplay,
1155 SES_Suma, sv);
1156 if (!SUMA_Engine (&list)) {
1157 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n",
1158 FuncName);
1159 }
1160
1161 /* update titles */
1162 SUMA_UpdateViewerTitle(sv);
1163 break;
1164 default:
1165 SUMA_S_Err("Il ne faut pas etre la");
1166 SUMA_RETURN(0);
1167 break;
1168 }
1169
1170 SUMA_RETURN(1);
1171 }
1172
SUMA_F1_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1173 int SUMA_F1_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1174 {
1175 static char FuncName[]={"SUMA_F1_Key"};
1176 char tk[]={"F1"}, keyname[100];
1177 int k, nc;
1178 SUMA_Boolean LocalHead = NOPE;
1179
1180 SUMA_ENTRY;
1181
1182 // fprintf(stderr, "%s\n", FuncName);
1183
1184 SUMA_KEY_COMMON;
1185
1186 /* do the work */
1187 switch (k) {
1188 case XK_F1:
1189 sv->ShowEyeAxis = !sv->ShowEyeAxis;
1190 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
1191 break;
1192 default:
1193 SUMA_S_Err("Il ne faut pas etre la");
1194 SUMA_RETURN(0);
1195 break;
1196 }
1197
1198 SUMA_RETURN(1);
1199 }
1200
SUMA_F2_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1201 int SUMA_F2_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1202 {
1203 static char FuncName[]={"SUMA_F2_Key"};
1204 char tk[]={"F2"}, keyname[100];
1205 int k, nc;
1206 SUMA_Boolean LocalHead = NOPE;
1207
1208 SUMA_ENTRY;
1209
1210 // fprintf(stderr, "%s\n", FuncName);
1211
1212 SUMA_KEY_COMMON;
1213
1214 /* do the work */
1215 switch (k) {
1216 case XK_F2:
1217 {
1218 int *do_id, n_do_id;
1219 ++sv->ShowWorldAxis;
1220 sv->ShowWorldAxis = sv->ShowWorldAxis % SUMA_N_WAX_OPTIONS;
1221 sv->ShowMeshAxis = 0;
1222 /* used to be = !sv->ShowMeshAxis; ,
1223 Turned off Oct 15 04 , in favor or WorldAxis */
1224 do_id = SUMA_GetDO_Type(SUMAg_DOv, SUMAg_N_DOv, SO_type, &n_do_id);
1225 if (n_do_id) {
1226 while (n_do_id) {
1227 ((SUMA_SurfaceObject *)
1228 SUMAg_DOv[do_id[n_do_id-1]].OP)->ShowMeshAxis =
1229 sv->ShowMeshAxis;
1230 --n_do_id;
1231 }
1232 SUMA_free(do_id);
1233 }
1234 }
1235 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
1236 break;
1237 default:
1238 SUMA_S_Err("Il ne faut pas etre la haut");
1239 SUMA_RETURN(0);
1240 break;
1241 }
1242
1243 SUMA_RETURN(1);
1244 }
1245
SUMA_F3_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1246 int SUMA_F3_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1247 {
1248 static char FuncName[]={"SUMA_F3_Key"};
1249 char tk[]={"F3"}, keyname[100];
1250 int k, nc;
1251 SUMA_EngineData *ED = NULL;
1252 DList *list = NULL;
1253 SUMA_Boolean LocalHead = NOPE;
1254
1255 SUMA_ENTRY;
1256
1257 // fprintf(stderr, "%s\n", FuncName);
1258
1259 SUMA_KEY_COMMON;
1260
1261 /* do the work */
1262 switch (k) {
1263 case XK_F3:
1264 if (!list) list = SUMA_CreateList();
1265 SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_ToggleCrossHair,
1266 SES_Suma, sv);
1267 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
1268 if (!SUMA_Engine (&list)) {
1269 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
1270 }
1271 break;
1272 default:
1273 SUMA_S_Err("Il ne faut pas etre over here");
1274 SUMA_RETURN(0);
1275 break;
1276 }
1277
1278 SUMA_RETURN(1);
1279 }
1280
SUMA_F4_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1281 int SUMA_F4_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1282 {
1283 static char FuncName[]={"SUMA_F4_Key"};
1284 char tk[]={"F4"}, keyname[100];
1285 int k, nc;
1286 SUMA_EngineData *ED = NULL;
1287 DList *list = NULL;
1288 DListElmt *NextElm= NULL;
1289 SUMA_Boolean LocalHead = NOPE;
1290
1291 SUMA_ENTRY;
1292
1293 // fprintf(stderr, "%s\n", FuncName);
1294
1295 SUMA_KEY_COMMON;
1296
1297 /* do the work */
1298 switch (k) {
1299 case XK_F4:
1300 if (!list) list = SUMA_CreateList();
1301 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_ToggleShowSelectedNode,
1302 SES_Suma, sv);
1303 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
1304 if (!SUMA_Engine (&list)) {
1305 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
1306 }
1307 break;
1308 default:
1309 SUMA_S_Err("Il ne faut pas etre over dort");
1310 SUMA_RETURN(0);
1311 break;
1312 }
1313
1314 SUMA_RETURN(1);
1315 }
1316
SUMA_F5_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1317 int SUMA_F5_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1318 {
1319 static char FuncName[]={"SUMA_F5_Key"};
1320 char tk[]={"F5"}, keyname[100];
1321 int k, nc;
1322 SUMA_EngineData *ED = NULL;
1323 DList *list = NULL;
1324 DListElmt *NextElm= NULL;
1325 SUMA_Boolean LocalHead = NOPE;
1326
1327 SUMA_ENTRY;
1328
1329 // fprintf(stderr, "%s\n", FuncName);
1330
1331 SUMA_KEY_COMMON;
1332
1333 /* do the work */
1334 switch (k) {
1335 case XK_F5:
1336 if (!list) list = SUMA_CreateList();
1337 SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_ToggleShowSelectedFaceSet,
1338 SES_Suma, sv);
1339 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
1340 if (!SUMA_Engine (&list)) {
1341 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
1342 }
1343 break;
1344 default:
1345 SUMA_S_Err("Il ne faut pas etre over dort");
1346 SUMA_RETURN(0);
1347 break;
1348 }
1349
1350 SUMA_RETURN(1);
1351 }
1352
SUMA_F6_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1353 int SUMA_F6_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1354 {
1355 static char FuncName[]={"SUMA_F6_Key"};
1356 char tk[]={"F6"}, keyname[100];
1357 int k, nc;
1358 SUMA_EngineData *ED = NULL;
1359 DList *list = NULL;
1360 DListElmt *NextElm= NULL;
1361 SUMA_Boolean LocalHead = NOPE;
1362
1363 SUMA_ENTRY;
1364
1365 // fprintf(stderr, "%s\n", FuncName);
1366
1367 SUMA_KEY_COMMON;
1368
1369 /* do the work */
1370 switch (k) {
1371 case XK_F6:
1372 sv->clear_color[0] = 1 - sv->clear_color[0];
1373 sv->clear_color[1] = 1 - sv->clear_color[1];
1374 sv->clear_color[2] = 1 - sv->clear_color[2];
1375
1376 SUMA_UpdateCrossHairNodeLabelField(sv);
1377 if (!list) list = SUMA_CreateList();
1378 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
1379 if (!SUMA_Engine (&list)) {
1380 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
1381 }
1382 break;
1383 default:
1384 SUMA_S_Err("Il ne faut pas etre over dere");
1385 SUMA_RETURN(0);
1386 break;
1387 }
1388
1389 SUMA_RETURN(1);
1390 }
SUMA_F7_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1391 int SUMA_F7_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1392 {
1393 static char FuncName[]={"SUMA_F7_Key"};
1394 char tk[]={"F7"}, keyname[100];
1395 int k, nc;
1396 SUMA_EngineData *ED = NULL;
1397 DList *list = NULL;
1398 DListElmt *NextElm= NULL;
1399 SUMA_Boolean LocalHead = NOPE;
1400
1401 SUMA_ENTRY;
1402
1403 // fprintf(stderr, "%s\n", FuncName);
1404
1405 SUMA_KEY_COMMON;
1406
1407 /* do the work */
1408 switch (k) {
1409 case XK_F7:
1410 ++SUMAg_CF->ColMixMode;
1411 if (SUMAg_CF->ColMixMode >= SUMA_MAX_MODES) {
1412 SUMAg_CF->ColMixMode = SUMA_ORIG_MIX_MODE;
1413 }
1414 {
1415 char stmp[200];
1416 sprintf(stmp,"Using %s color mixing mode.",
1417 SUMA_ColMixModeString(SUMAg_CF->ColMixMode));
1418 if (callmode && strcmp(callmode, "interactive") == 0) {
1419 SUMA_SLP_Note("%s",stmp); }
1420 else { SUMA_S_Note("%s",stmp); }
1421 }
1422
1423 SUMA_SetAllRemixFlag (SUMAg_SVv, SUMAg_N_SVv);
1424
1425 if (!list) list = SUMA_CreateList();
1426 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay_AllVisible,
1427 SES_Suma, NULL);
1428 if (!SUMA_Engine (&list)) {
1429 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
1430 }
1431 break;
1432 default:
1433 SUMA_S_Err("Il ne faut pas etre over yonder");
1434 SUMA_RETURN(0);
1435 break;
1436 }
1437
1438 SUMA_RETURN(1);
1439 }
1440
SUMA_F8_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1441 int SUMA_F8_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1442 {
1443 static char FuncName[]={"SUMA_F8_Key"};
1444 char tk[]={"F8"}, keyname[100];
1445 int k, nc;
1446 SUMA_EngineData *ED = NULL;
1447 DList *list = NULL;
1448 DListElmt *NextElm= NULL;
1449 SUMA_Boolean LocalHead = NOPE;
1450
1451 SUMA_ENTRY;
1452
1453 // fprintf(stderr, "%s\n", FuncName);
1454
1455 SUMA_KEY_COMMON;
1456
1457 /* do the work */
1458 switch (k) {
1459 case XK_F8:
1460 sv->ortho = !sv->ortho;
1461 {
1462 static int inote = 0;
1463 char stmp[200];
1464 if (sv->ortho) {
1465 sprintf(stmp,"Using orthographic projection viewing");
1466 sv->FOV[sv->iState] = sv->FOV[sv->iState] / 2.0;
1467 } else {
1468 sprintf(stmp,"Using perspective viewing");
1469 sv->FOV[sv->iState] = sv->FOV[sv->iState] * 2.0;
1470 }
1471 ++inote;
1472 if (callmode && strcmp(callmode, "interactive") == 0 && inote < 3) {
1473 SUMA_SLP_Note("%s",stmp); }
1474 else { SUMA_S_Note("%s",stmp); }
1475 }
1476
1477 SUMA_SET_GL_PROJECTION(sv, sv->ortho);
1478 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
1479 break;
1480 default:
1481 SUMA_S_Err("Il ne faut pas etre over yonder");
1482 SUMA_RETURN(0);
1483 break;
1484 }
1485
1486 SUMA_RETURN(1);
1487 }
1488
SUMA_F9_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1489 int SUMA_F9_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1490 {
1491 static char FuncName[]={"SUMA_F9_Key"};
1492 char tk[]={"F9"}, keyname[100];
1493 int k, nc;
1494 SUMA_EngineData *ED = NULL;
1495 DList *list = NULL;
1496 DListElmt *NextElm= NULL;
1497 static int inote = 0;
1498 SUMA_Boolean LocalHead = NOPE;
1499
1500 SUMA_ENTRY;
1501
1502 // fprintf(stderr, "%s\n", FuncName);
1503
1504 SUMA_KEY_COMMON;
1505
1506 /* do the work */
1507 switch (k) {
1508 case XK_F9:
1509 sv->ShowLabelAtXhair = !sv->ShowLabelAtXhair;
1510 SUMA_UpdateCrossHairNodeLabelField(sv);
1511 {
1512 char stmp[200];
1513 if (sv->ShowLabelAtXhair) {
1514 sprintf(stmp,"Showing Label At Xhair");
1515 } else {
1516 sprintf(stmp,"Hiding Label At Xhair");
1517 }
1518 if (callmode && strcmp(callmode, "interactive") == 0 && inote < 2) {
1519 SUMA_SLP_Note("%s",stmp); ++inote;}
1520 else { SUMA_S_Note("%s",stmp); }
1521 }
1522 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
1523 break;
1524 default:
1525 SUMA_S_Err("Il ne faut pas etre hawn");
1526 SUMA_RETURN(0);
1527 break;
1528 }
1529
1530 SUMA_RETURN(1);
1531 }
1532
SUMA_F10_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode,char * strgval)1533 int SUMA_F10_Key(SUMA_SurfaceViewer *sv,char *key, char *callmode, char *strgval)
1534 {
1535 static char FuncName[]={"SUMA_F10_Key"};
1536 char tk[]={"F10"}, keyname[100];
1537 int k, nc;
1538 SUMA_EngineData *ED = NULL;
1539 DList *list = NULL;
1540 DListElmt *NextElm= NULL;
1541 static int inote = 0;
1542 SUMA_Boolean LocalHead = NOPE;
1543
1544 SUMA_ENTRY;
1545
1546 // fprintf(stderr, "%s\n", FuncName);
1547
1548 SUMA_KEY_COMMON;
1549
1550 /* do the work */
1551 switch (k) {
1552 case XK_F10:
1553 if (sv->PryAx == 2) sv->PryAx = 3;
1554 else if (sv->PryAx == 3) sv->PryAx = 2;
1555 else {
1556 SUMA_S_Err("Bad PryAx of %d. Reverting to 3", sv->PryAx);
1557 sv->PryAx = 3;
1558 }
1559 {
1560 char stmp[200];
1561 if (sv->PryAx == 3) {
1562 sprintf(stmp,"Prying about Z axis");
1563 } else {
1564 sprintf(stmp,"Prying about Y axis");
1565 }
1566 if (callmode && strcmp(callmode, "interactive") == 0 && inote < 2) {
1567 SUMA_SLP_Note("%s",stmp); ++inote;}
1568 else { SUMA_S_Note("%s",stmp); }
1569 }
1570 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
1571 break;
1572 default:
1573 SUMA_S_Err("Il ne faut pas etre la dessous");
1574 SUMA_RETURN(0);
1575 break;
1576 }
1577
1578 SUMA_RETURN(1);
1579 }
1580
SUMA_F11_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode,char * strgval)1581 int SUMA_F11_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode,
1582 char *strgval)
1583 {
1584 static char FuncName[]={"SUMA_F11_Key"};
1585 char tk[]={"F11"}, keyname[100];
1586 int k, nc;
1587 SUMA_EngineData *ED = NULL;
1588 DList *list = NULL;
1589 DListElmt *NextElm= NULL;
1590 static int inote = 0;
1591 SUMA_Boolean LocalHead = NOPE;
1592
1593 SUMA_ENTRY;
1594
1595 // fprintf(stderr, "%s\n", FuncName);
1596
1597 SUMA_KEY_COMMON;
1598
1599 /* do the work */
1600 switch (k) {
1601 case XK_F11: {
1602 if ( (callmode && strcmp(callmode, "interactive") == 0) ||
1603 !strgval /* why not? this way the
1604 Driver can pop the interactive window */) {
1605 sv->X->SetRenderOrder_prmpt = SUMA_CreatePromptDialogStruct(
1606 SUMA_OK_APPLY_CLEAR_CANCEL,
1607 "Set Object Display Order:\n"
1608 "(e.g. VSG for: Volume, Surface, Graph)):",
1609 "VSG",
1610 sv->X->TOPLEVEL, YUP,
1611 SUMA_APPLY_BUTTON,
1612 SUMA_SV_SetRenderOrder, (void *)sv,
1613 NULL, NULL,
1614 NULL, NULL,
1615 SUMA_VerifyRenderOrder, NULL,
1616 sv->X->SetRenderOrder_prmpt);
1617
1618 sv->X->SetRenderOrder_prmpt = SUMA_CreatePromptDialog(
1619 sv->X->Title, sv->X->SetRenderOrder_prmpt);
1620 } else {
1621 if (!strgval) {
1622 SUMA_S_Err("Have NULL string");
1623 SUMA_RETURN(0);
1624 }
1625 SUMA_SV_SetRenderOrder(strgval, (void *)sv);
1626 }
1627 break; }
1628 default:
1629 SUMA_S_Err("Il ne faut pas etre hawn");
1630 SUMA_RETURN(0);
1631 break;
1632 }
1633
1634 SUMA_RETURN(1);
1635 }
1636
SUMA_F12_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1637 int SUMA_F12_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1638 {
1639 static char FuncName[]={"SUMA_F12_Key"};
1640 char tk[]={"F12"}, keyname[100];
1641 int k, nc;
1642 SUMA_EngineData *ED = NULL;
1643 DList *list = NULL;
1644 DListElmt *NextElm= NULL;
1645 static int inote = 0;
1646 SUMA_Boolean LocalHead = NOPE;
1647
1648 SUMA_ENTRY;
1649
1650 // fprintf(stderr, "%s\n", FuncName);
1651
1652 SUMA_KEY_COMMON;
1653
1654 /* do the work */
1655 switch (k) {
1656 case XK_F12:
1657 {
1658 /* time display speed */
1659 int i, nd = 20, N_vis, *Vis_IDs=NULL, NodeTot, FaceTot;
1660 GLfloat buf;
1661 float delta_t;
1662 SUMA_SurfaceObject *SO=NULL;
1663 struct timeval tti;
1664 char stmp[500], fnameout[]={"__SUMA.speedtest.txt"};
1665 SUMA_STRING *SS = NULL;
1666 FILE *fout=NULL;
1667
1668 if (callmode && !strcmp(callmode, "drivesuma")) {
1669 fout = fopen(fnameout,"w");
1670 }
1671 SS = SUMA_StringAppend (NULL, NULL);
1672
1673 buf = sv->light0_position[2];
1674 if (callmode && strcmp(callmode, "interactive") == 0) {
1675 SUMA_SLP_Note ("Timing Display speed\n"
1676 "(20 displays): \n");
1677 } else {
1678 SUMA_S_Note("Timing Display speed\n"
1679 "(20 displays): \n");
1680 }
1681 if (fout) fprintf(fout, "Timing Display speed (20 displays):\n");
1682
1683 SUMA_etime (&tti, 0);
1684 for (i=0; i< nd-1; ++i) {
1685 fprintf (SUMA_STDOUT,"%d\t", i); fflush (SUMA_STDOUT);
1686 sv->light0_position[2] *= -1;
1687 glLightfv(GL_LIGHT0, GL_POSITION, sv->light0_position);
1688 /* direct call to display */
1689 SUMA_display(sv, SUMAg_DOv);
1690 /* wait for display */
1691 glFinish();
1692 }
1693 fprintf (SUMA_STDOUT,"\n");
1694 delta_t = SUMA_etime (&tti, 1);
1695 sv->light0_position[2] = buf;
1696 glLightfv(GL_LIGHT0, GL_POSITION, sv->light0_position);
1697 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
1698 sprintf (stmp,
1699 "Elapsed time: %f seconds.\n%.2f displays/second.\n",
1700 delta_t, nd/delta_t);
1701 SS = SUMA_StringAppend (SS, stmp);
1702
1703 /* Estimate how many nodes and triangles were rendered */
1704 Vis_IDs = (int *)SUMA_malloc(sizeof(int)*SUMAg_N_DOv);
1705 N_vis = SUMA_VisibleSOs (sv, SUMAg_DOv, Vis_IDs, 0);
1706 NodeTot = 0;
1707 FaceTot = 0;
1708 for (i=0; i<N_vis;++i) {
1709 SO = (SUMA_SurfaceObject *)SUMAg_DOv[Vis_IDs[i]].OP;
1710 FaceTot += SO->N_FaceSet;
1711 NodeTot += SO->N_Node;
1712 }
1713 if (N_vis) {
1714 sprintf (stmp, "In Polymode %d, rendered \n"
1715 "%.2f Ktri/sec %.2f Kpnt/sec.\n",
1716 sv->PolyMode,
1717 (float)FaceTot / 1000.0 / delta_t ,
1718 (float)NodeTot / 1000.0 / delta_t );
1719 SS = SUMA_StringAppend (SS, stmp);
1720 }
1721
1722 if (callmode && strcmp(callmode, "interactive") == 0) {
1723 SUMA_SLP_Note("%s",SS->s);
1724 } else {
1725 SUMA_S_Note("%s",SS->s);
1726 }
1727
1728 if (fout) {
1729 fprintf(fout, "%s\n", SS->s);
1730 SUMA_S_Note("Timing results written to file: %s", fnameout);
1731 fclose(fout);
1732 }
1733
1734 if (Vis_IDs) SUMA_free(Vis_IDs);
1735 SUMA_free(SS->s);
1736 SUMA_free(SS);
1737 }
1738 break;
1739 default:
1740 SUMA_S_Err("Il ne faut pas etre hawn");
1741 SUMA_RETURN(0);
1742 break;
1743 }
1744
1745 SUMA_RETURN(1);
1746 }
1747
SUMA_F13_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1748 int SUMA_F13_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1749 {
1750 static char FuncName[]={"SUMA_F13_Key"};
1751 char tk[]={"F13"}, keyname[100];
1752 int k, nc;
1753 SUMA_EngineData *ED = NULL;
1754 DList *list = NULL;
1755 DListElmt *NextElm= NULL;
1756 static int inote = 0;
1757 SUMA_Boolean LocalHead = NOPE;
1758
1759 SUMA_ENTRY;
1760
1761 // fprintf(stderr, "%s\n", FuncName);
1762
1763 SUMA_KEY_COMMON;
1764
1765 /* do the work */
1766 switch (k) {
1767 case XK_F13:
1768 {
1769 if (SUMAg_CF->Dev) {
1770 DList *striplist=NULL;
1771 float Eq[4];
1772 int *Vis_IDs, N_vis;
1773 SUMA_SurfaceObject *SO=NULL;
1774 Vis_IDs = (int *)SUMA_malloc(sizeof(int)*SUMAg_N_DOv);
1775 N_vis = SUMA_VisibleSOs (sv, SUMAg_DOv, Vis_IDs, 0);
1776 if (N_vis) {
1777 SO = (SUMA_SurfaceObject *)SUMAg_DOv[Vis_IDs[0]].OP;
1778 /* Axial plane */
1779 Eq[0] = Eq[1] = 0.0; Eq[2] = 1.0; Eq[3] = -SO->Center[2];
1780 SUMA_S_Warnv("Kill me!\nEq:[%f %f %f %f], step: %f\n",
1781 Eq[0], Eq[1], Eq[2], Eq[3], SO->EL->AvgLe);
1782 striplist = SUMA_SliceAlongPlane(SO, Eq, SO->EL->AvgLe);
1783 SUMA_display_edge_striplist(striplist, &(SUMAg_SVv[0]), SO,
1784 "ShowConnectedPoints");
1785 SUMA_FREE_DLIST(striplist);
1786 }
1787 if (Vis_IDs) SUMA_free(Vis_IDs);
1788 }
1789 }
1790 break;
1791 default:
1792 SUMA_S_Err("Il ne faut pas etre la");
1793 SUMA_RETURN(0);
1794 break;
1795 }
1796
1797 SUMA_RETURN(1);
1798 }
1799
1800
SUMA_Numeral_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1801 int SUMA_Numeral_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1802 {
1803 static char FuncName[]={"SUMA_Numeral_Key"};
1804 char tk[]={"0"}, keyname[100];
1805 int k, nc, i, isv;
1806 SUMA_EngineData *ED = NULL;
1807 DList *list = NULL;
1808 DListElmt *NextElm= NULL;
1809 SUMA_Boolean LocalHead = NOPE;
1810 Widget w = NULL;
1811 XKeyEvent Kev;
1812 static previouslySelectedPlane;
1813
1814 SUMA_ENTRY;
1815
1816 SUMA_GLXAREA_WIDGET2SV(w, sv, isv);
1817
1818 k = SUMA_KeyPress(key, NULL);
1819
1820 // Verbose output
1821 if (clippingPlaneMode && SUMAg_CF->clippingPlaneVerbose){
1822 switch (k){
1823 case 0x0030:
1824 fprintf(stderr, "### Reset clipping planes\n");
1825 break;
1826 case 0x0037:
1827 fprintf(stderr, "### Toggle all active clipping planes on/off\n");
1828 break;
1829 case 0x0038:
1830 case 0x0039:
1831 fprintf(stderr, "WARNING: No clipping plane %d\n", k-0x0030);
1832 break;
1833 default:
1834 fprintf(stderr, "### %s clipping plane %d\n",
1835 (SUMA_CTRL_KEY(key))? "Select" : "Toggle", k-0x0030);
1836 }
1837 }
1838
1839 /* do the work */
1840 switch (k) {
1841 case XK_0:
1842 if (clippingPlaneMode){
1843 clipPlaneTransform(0,0,0,0,0, 0, 1);
1844 resetClippingPlanes = 1;
1845 for (i=0; i<SUMAg_CF->N_ClipPlanes; ++i){
1846 active[i] = (i>0);
1847 clipPlaneTransform(0,0,0,0,i, 1, 0);
1848 }
1849 clipPlaneTransform(0,0,0,0,0, 0, 0); // Select clipping plane 1
1850 lightenActiveClipPlaneSquare(0); // Lighten plane 1 to show it's selected
1851
1852 // Required to lighten plane mode in DriveSuma mode but not in interactive mode
1853 clipPlaneTransform(0,0,0,0,0, 0, 0); // Select clipping plane 1
1854 lightenActiveClipPlaneSquare(0); // Lighten plane 1 to show it's selected
1855 }
1856 break;
1857 case XK_1:
1858 if (clippingPlaneMode){
1859 if (SUMA_CTRL_KEY(key)){
1860 clipPlaneTransform(0,0,0,0,0, 0, 0); // Select clipping plane 1
1861 lightenActiveClipPlaneSquare(0);
1862 darkenInactiveClipPlaneSquares(0);
1863 } else if (SUMAg_CF->N_ClipPlanes>=1){ // Toggle plane 1 off/on
1864 clipPlaneTransform(0,0,0,0,0, 1, 0);
1865 previouslyActive[0] = active[0];
1866 clipPlaneTransform(0,0,0,0,0, 0, 0);
1867 lightenActiveClipPlaneSquare(0);
1868 darkenInactiveClipPlaneSquares(0);
1869 }
1870 activeClipPlanes = activeClippingPlanes();
1871 locallySelectedPlane = 0;
1872 }
1873 break;
1874 case XK_2:
1875 if (clippingPlaneMode){
1876 if (SUMA_CTRL_KEY(key)){ // Select clipping plane 2
1877 clipPlaneTransform(0,0,0,0,1, 0, 0);
1878 lightenActiveClipPlaneSquare(1);
1879 darkenInactiveClipPlaneSquares(1);
1880 } else { // Toggle plane 2 off/on
1881 clipPlaneTransform(0,0,0,0,1, 1, 0);
1882 previouslyActive[1] = active[1];
1883 clipPlaneTransform(0,0,0,0,1, 0, 0);
1884 lightenActiveClipPlaneSquare(1);
1885 darkenInactiveClipPlaneSquares(1);
1886 }
1887 activeClipPlanes = activeClippingPlanes();
1888 locallySelectedPlane = 1;
1889 }
1890 break;
1891 case XK_3:
1892 if (clippingPlaneMode){
1893 if (SUMA_CTRL_KEY(key)){ // Select clipping plane 3
1894 clipPlaneTransform(0,0,0,0,2, 0, 0);
1895 lightenActiveClipPlaneSquare(2);
1896 darkenInactiveClipPlaneSquares(2);
1897 } else { // Toggle plane 3 off/on
1898 clipPlaneTransform(0,0,0,0,2, 1, 0);
1899 previouslyActive[2] = active[2];
1900 clipPlaneTransform(0,0,0,0,2, 0, 0);
1901 lightenActiveClipPlaneSquare(2);
1902 darkenInactiveClipPlaneSquares(2);
1903 }
1904 activeClipPlanes = activeClippingPlanes();
1905 locallySelectedPlane = 2;
1906 }
1907 break;
1908 case XK_4:
1909 if (clippingPlaneMode){
1910 if (SUMA_CTRL_KEY(key)){
1911 clipPlaneTransform(0,0,0,0,3, 0, 0);
1912 lightenActiveClipPlaneSquare(3);
1913 darkenInactiveClipPlaneSquares(3);
1914 } else { // Toggle plane 4 off/on
1915 clipPlaneTransform(0,0,0,0,3, 1, 0);
1916 previouslyActive[3] = active[3];
1917 clipPlaneTransform(0,0,0,0,3, 0, 0);
1918 lightenActiveClipPlaneSquare(3);
1919 darkenInactiveClipPlaneSquares(3);
1920 }
1921 activeClipPlanes = activeClippingPlanes();
1922 locallySelectedPlane = 3;
1923 }
1924 break;
1925 case XK_5:
1926 if (clippingPlaneMode){
1927 if (SUMA_CTRL_KEY(key)){ // Select clipping plane 5
1928 clipPlaneTransform(0,0,0,0,4, 0, 0);
1929 lightenActiveClipPlaneSquare(4);
1930 darkenInactiveClipPlaneSquares(4);
1931 } else { // Toggle plane 4 off/on
1932 clipPlaneTransform(0,0,0,0,4, 1, 0);
1933 previouslyActive[4] = active[4];
1934 clipPlaneTransform(0,0,0,0,4, 0, 0);
1935 lightenActiveClipPlaneSquare(4);
1936 darkenInactiveClipPlaneSquares(4);
1937 }
1938 activeClipPlanes = activeClippingPlanes();
1939 locallySelectedPlane = 4;
1940 }
1941 break;
1942 case XK_6:
1943 if (clippingPlaneMode){
1944 if (SUMA_CTRL_KEY(key)){ // Select clipping plane 6
1945 clipPlaneTransform(0,0,0,0,5, 0, 0);
1946 lightenActiveClipPlaneSquare(5);
1947 darkenInactiveClipPlaneSquares(5);
1948 } else { // Toggle plane 6 off/on
1949 clipPlaneTransform(0,0,0,0,5, 1, 0);
1950 previouslyActive[5] = active[5];
1951 clipPlaneTransform(0,0,0,0,5, 0, 0);
1952 lightenActiveClipPlaneSquare(5);
1953 darkenInactiveClipPlaneSquares(5);
1954 }
1955 activeClipPlanes = activeClippingPlanes();
1956 locallySelectedPlane = 5;
1957 }
1958 break;
1959 case XK_7:
1960 if (clippingPlaneMode){
1961 if (SUMA_CTRL_KEY(key)){
1962 // Place-holder for ctrl-7
1963 } else {
1964 activeClipPlanes = activeClippingPlanes();
1965 if (activeClipPlanes>0){
1966 previouslySelectedPlane = selectedPlane;
1967 for (i=0; i<SUMAg_CF->N_ClipPlanes; ++i){
1968 previouslyActive[i] = active[i];
1969 active[i] = 1;
1970 clipPlaneTransform(0,0,0,0,i, 0, 0);
1971 clipPlaneTransform(0,0,0,0,i, 1, 0);
1972 clipIdentificationPlane[i]->Show = 0;
1973 }
1974 } else {
1975 for (i=0; i<SUMAg_CF->N_ClipPlanes; ++i){
1976 if (previouslyActive[i]){
1977 active[i] = 0;
1978 clipPlaneTransform(0,0,0,0,i, 1, 0);
1979 clipPlaneTransform(0,0,0,0,i, 0, 0);
1980 }
1981 }
1982 selectedPlane = previouslySelectedPlane;
1983 clipPlaneTransform(0,0,0,0,selectedPlane, 0, 0);
1984 }
1985 }
1986 }
1987 break;
1988 case XK_8:
1989 if (!clippingPlaneMode && sv->X->TOPLEVEL) {
1990 char stmp[100];
1991 sprintf(stmp, "%d", SUMAg_CF->X->NumForeSmoothing);
1992 if (!(SUMAg_CF->X->N_ForeSmooth_prmpt =
1993 SUMA_CreatePromptDialogStruct (SUMA_OK_APPLY_CLEAR_CANCEL,
1994 "Foreground smoothing iterations",
1995 stmp,
1996 sv->X->TOPLEVEL, YUP,
1997 SUMA_APPLY_BUTTON,
1998 SUMA_SetNumForeSmoothing, (void *)sv,
1999 NULL, NULL,
2000 NULL, NULL,
2001 SUMA_CleanNumString, (void*)1,
2002 SUMAg_CF->X->N_ForeSmooth_prmpt))){
2003 SUMA_S_Err("Failure to create prompt dialog structure");
2004 SUMA_RETURN(0);
2005 }
2006
2007 SUMAg_CF->X->N_ForeSmooth_prmpt =
2008 SUMA_CreatePromptDialog("Foreground smoothing iterations",
2009 SUMAg_CF->X->N_ForeSmooth_prmpt);
2010 }
2011 break;
2012 default:
2013 SUMA_S_Err("Il ne faut pas ci dessous");
2014 SUMA_RETURN(0);
2015 break;
2016 }
2017
2018 SUMA_RETURN(1);
2019 }
2020
SUMA_SetShownLocalRemixFlagTemp(SUMA_SurfaceViewer * sv)2021 SUMA_Boolean SUMA_SetShownLocalRemixFlagTemp (SUMA_SurfaceViewer *sv)
2022 {
2023 static char FuncName[]={"SUMA_SetShownLocalRemixFlag"};
2024 int k;
2025
2026 SUMA_ENTRY;
2027
2028 // for (k=1; k < sv->N_ColList; ++k)
2029 for (k=0; k < sv->N_ColList; ++k) /*
2030 if (!strstr(sv->ColList[k]->idcode_str, "ClipSquare") &&
2031 !strstr(sv->ColList[k]->idcode_str, "axisObject")) */{
2032 /**/
2033 fprintf(stderr, "sv->ColList[k]->idcode_str = %s\n", sv->ColList[k]->idcode_str);
2034 /**/
2035 sv->ColList[k]->Remix = YUP;
2036 }
2037
2038 SUMA_RETURN (YUP);
2039 }
2040
2041
SUMA_A_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2042 int SUMA_A_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2043 {
2044 static char FuncName[]={"SUMA_A_Key"};
2045 char tk[]={"A"}, keyname[100];
2046 int k, nc;
2047 SUMA_EngineData *ED = NULL;
2048 DList *list = NULL;
2049 DListElmt *NextElm= NULL;
2050 SUMA_Boolean LocalHead = NOPE;
2051 XKeyEvent Kev;
2052 Widget w = NULL;
2053
2054 SUMA_ENTRY;
2055
2056 SUMA_KEY_COMMON;
2057
2058 /* do the work */
2059 switch (k) {
2060 case XK_A:
2061 if ((SUMA_CTRL_KEY(key))){
2062
2063 } else {
2064
2065 }
2066 break;
2067 case XK_a:
2068 if (clippingPlaneMode){
2069 if (!axisObject) makeAxisObject(w, sv);
2070 axisObject->ShowMeshAxis = !(axisObject->ShowMeshAxis);
2071 /*
2072 clipIdentificationPlane[0]->ShowMeshAxis =
2073 !(clipIdentificationPlane[0]->ShowMeshAxis);
2074 */
2075 SUMA_postRedisplay(w, NULL, NULL); // Refresh window
2076 } else {
2077 /* toggle background attenuation */
2078 if (sv->Back_Modfact) {
2079 fprintf (SUMA_STDOUT,
2080 "%s: Modulation by background intensity OFF.\n", FuncName);
2081 sv->Back_Modfact = 0;
2082 } else {
2083 fprintf (SUMA_STDOUT,
2084 "%s: Modulation by background intensity ON.\n", FuncName);
2085 sv->Back_Modfact = SUMA_BACKGROUND_MODULATION_FACTOR;
2086 }
2087
2088 if (SUMAg_CF->clippingPlaneVerbose && SUMAg_CF->clippingPlaneVerbosityLevel>1)
2089 fprintf(stderr, "### SUMA_A_Key: sv->N_ColList = %d\n", sv->N_ColList);
2090
2091 /* set the remix flag */
2092 if (!SUMA_SetShownLocalRemixFlagTemp (sv)) {
2093 // if (!SUMA_SetShownLocalRemixFlag (sv)) {
2094 fprintf (SUMA_STDERR,
2095 "Error %s: Failed in SUMA_SetShownLocalRemixFlag.\n",
2096 FuncName);
2097 break;
2098 }
2099
2100 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
2101 }
2102 break;
2103 default:
2104 SUMA_S_Err("Il ne faut pas ci dessous");
2105 SUMA_RETURN(0);
2106 break;
2107 }
2108
2109 SUMA_RETURN(1);
2110 }
2111
SUMA_B_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2112 int SUMA_B_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2113 {
2114 static char FuncName[]={"SUMA_B_Key"};
2115 char tk[]={"B"}, keyname[100];
2116 int k, nc;
2117 SUMA_EngineData *ED = NULL;
2118 DList *list = NULL;
2119 DListElmt *NextElm= NULL;
2120 SUMA_Boolean LocalHead = NOPE;
2121
2122 SUMA_ENTRY;
2123
2124 fprintf(stderr, "key = %s\n", key);
2125
2126 SUMA_KEY_COMMON;
2127
2128 /* do the work */
2129 switch (k) {
2130 case XK_B:
2131 if ((SUMA_CTRL_KEY(key))){
2132 if (SUMAg_CF->Dev ) {
2133 sv->Blend_Mode = (sv->Blend_Mode+1)%SUMA_N_BLEND_MODES;
2134 switch (sv->Blend_Mode) {
2135 case SUMA_NO_BLEND:
2136 glDisable(GL_BLEND);
2137 if (callmode && strcmp(callmode, "interactive") == 0) {
2138 SUMA_SLP_Note ("Blending disabled."); }
2139 else { SUMA_S_Note ("Blending disabled."); }
2140 break;
2141 case SUMA_BLEND1:
2142 glEnable (GL_BLEND);
2143 glBlendFunc(GL_ONE,GL_SRC_ALPHA);
2144 if (callmode && strcmp(callmode, "interactive") == 0) {
2145 SUMA_SLP_Note ("Blending mode1."); }
2146 else { SUMA_S_Note ("Blending mode1."); }
2147 break;
2148 case SUMA_BLEND2:
2149 glEnable (GL_BLEND);
2150 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
2151 if (callmode && strcmp(callmode, "interactive") == 0) {
2152 SUMA_SLP_Note ("Blending mode2.");}
2153 else { SUMA_S_Note ("Blending mode2."); }
2154 break;
2155 default:
2156 SUMA_SL_Err ("Should not be here");
2157 break;
2158 }
2159 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
2160 }
2161 } else {
2162 sv->BF_Cull = (sv->BF_Cull+1)%3;
2163 if (callmode && strcmp(callmode, "interactive") == 0) {
2164 SUMA_CullOption(sv, "Apply");}
2165 else { SUMA_CullOption(sv, "Restore");}
2166 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
2167 }
2168 break;
2169 case XK_b:
2170 /* Show/hide the background */
2171 if (!list) list = SUMA_CreateList();
2172 ED = SUMA_InitializeEngineListData (SE_ToggleBackground);
2173 if (!SUMA_RegisterEngineListCommand ( list, ED,
2174 SEF_Empty, NULL,
2175 SES_Suma, (void *)sv, NOPE,
2176 SEI_Head, NULL)) {
2177 fprintf (SUMA_STDERR,
2178 "Error %s: Failed to register command.\n", FuncName);
2179 }
2180
2181 ED = SUMA_InitializeEngineListData (SE_Redisplay);
2182 if (!SUMA_RegisterEngineListCommand ( list, ED,
2183 SEF_Empty, NULL,
2184 SES_Suma, (void *)sv, NOPE,
2185 SEI_Head, NULL)) {
2186 fprintf (SUMA_STDERR,
2187 "Error %s: Failed to register command.\n", FuncName);
2188 }
2189
2190 if (!SUMA_Engine (&list)) {
2191 fprintf(SUMA_STDERR, "Error SUMA_input: SUMA_Engine call failed.\n");
2192 }
2193 break;
2194 default:
2195 SUMA_S_Err("Il ne faut pas ci dessous");
2196 SUMA_RETURN(0);
2197 break;
2198 }
2199
2200 SUMA_RETURN(1);
2201 }
2202
2203
SUMA_C_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2204 int SUMA_C_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2205 {
2206 static char FuncName[]={"SUMA_C_Key"};
2207 char tk[]={"C"}, keyname[100];
2208 int k, nc, planeIndex=0, locallySelectedPlane=0, isv;
2209 SUMA_EngineData *ED = NULL;
2210 DList *list = NULL;
2211 DListElmt *NextElm= NULL;
2212 SUMA_Boolean LocalHead = NOPE;
2213 Widget w = NULL;
2214
2215 SUMA_ENTRY;
2216
2217 SUMA_KEY_COMMON;
2218
2219 /* do the work */
2220 switch (k) {
2221 case XK_C:
2222
2223 if ((SUMA_ALT_KEY(key) || SUMA_APPLE_KEY(key))){
2224
2225 if (clippingPlaneMode){
2226
2227 if (resetClippingPlanes){
2228 SUMAg_CF->N_ClipPlanes = 1;
2229 resetClippingPlanes=0;
2230 }
2231 // This sets up a new clip plane (independent of the dialog box. If called with
2232 // the dialog box, two clipping planes result.) The new plane is automatically
2233 // assigned a label which is its 1-based index
2234 if ((SUMA_CTRL_KEY(key))){ // Ctrl-Shift-alt-C (clip plane box
2235
2236 for (planeIndex=0; planeIndex<6; ++planeIndex){
2237 sprintf(SUMAg_CF->ClipPlanesLabels[SUMAg_CF->N_ClipPlanes], "%d", SUMAg_CF->N_ClipPlanes+1);
2238 clipPlaneTransform(0,0,0,0,SUMAg_CF->N_ClipPlanes, 0, 0);
2239 }
2240 }
2241 activeClipPlanes = activeClippingPlanes();
2242 }
2243 } else if (SUMA_CTRL_KEY(key)){
2244 if (SUMAg_CF->clippingPlaneVerbose && SUMAg_CF->clippingPlaneVerbosityLevel>1)
2245 fprintf(stderr, "### SUMA_C_Key: toggleClippingPlaneMode\n");
2246 toggleClippingPlaneMode(sv, w, &locallySelectedPlane);
2247 if (SUMAg_CF->clippingPlaneVerbose && SUMAg_CF->clippingPlaneVerbosityLevel>1)
2248 fprintf(stderr, "### axisObject = %d\n", axisObject);
2249 if (!axisObject) makeAxisObject(w, sv);
2250 }else if (clippingPlaneMode) {
2251
2252 SUMA_GLXAREA_WIDGET2SV(w, sv, isv);
2253
2254 // Toggle clip plane identification mode
2255 clipPlaneIdentificationMode = !clipPlaneIdentificationMode;
2256
2257 if (SUMAg_CF->clippingPlaneVerbose) fprintf(stderr, "### Clipping plane squares %s\n",
2258 clipPlaneIdentificationMode? "on" : "off");
2259
2260 for (planeIndex=0; planeIndex<SUMAg_CF->N_ClipPlanes; ++planeIndex){
2261 if (clipPlaneIdentificationMode){
2262 if (active[planeIndex]) clipIdentificationPlane[planeIndex]->Show = 1;
2263 } else {
2264 clipIdentificationPlane[planeIndex]->Show = 0;
2265 }
2266 }
2267
2268 SUMA_postRedisplay(w, NULL, NULL); // Refresh window
2269 } else if (SUMAg_CF->Dev && SUMA_CTRL_KEY(key)){
2270
2271 SUMAg_CF->X->Clip_prmpt =
2272 SUMA_CreatePromptDialogStruct (SUMA_OK_APPLY_CLEAR_CANCEL,
2273 "Enter screen clip plane parameters (a,b,c,d)",
2274 "A: 0,0,1,0",
2275 sv->X->TOPLEVEL, YUP,
2276 SUMA_APPLY_BUTTON,
2277 SUMA_SetScreenClip, (void *)sv,
2278 NULL, NULL,
2279 NULL, NULL,
2280 NULL, NULL,
2281 SUMAg_CF->X->Clip_prmpt);
2282
2283 SUMAg_CF->X->Clip_prmpt =
2284 SUMA_CreatePromptDialog(
2285 "Enter screen clip plane parameters (a,b,c,d)",
2286 SUMAg_CF->X->Clip_prmpt);
2287 }
2288 break;
2289 case XK_c:
2290 {
2291 SUMA_SurfaceObject *SO=NULL;
2292 if ((SO = SUMA_SV_Focus_SO(sv))) {
2293 if (!list) list = SUMA_CreateList();
2294 ED = SUMA_InitializeEngineListData (SE_OpenColFileSelection);
2295 if (!(NextElm = SUMA_RegisterEngineListCommand ( list, ED,
2296 SEF_vp, (void *)SO,
2297 SES_Suma, (void *)sv, NOPE,
2298 SEI_Head, NULL))) {
2299 SUMA_S_Err("Failed to register command.");
2300 }
2301
2302 if (!SUMA_RegisterEngineListCommand ( list, ED,
2303 SEF_ip, sv->X->TOPLEVEL,
2304 SES_Suma, (void *)sv, NOPE,
2305 SEI_In, NextElm)) {
2306 SUMA_S_Err("Failed to register command.");
2307 }
2308
2309 if (!SUMA_Engine (&list)) {
2310 fprintf(SUMA_STDERR,
2311 "Error %s: SUMA_Engine call failed.\n", FuncName);
2312 }
2313 }
2314 }
2315
2316 break;
2317 default:
2318 SUMA_S_Err("Il ne faut pas ci dessous");
2319 SUMA_RETURN(0);
2320 break;
2321 }
2322
2323 SUMA_RETURN(1);
2324 }
2325
2326
SUMA_D_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2327 int SUMA_D_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2328 {
2329 static char FuncName[]={"SUMA_D_Key"};
2330 SUMA_LIST_WIDGET *LW=NULL;
2331 char tk[]={"D"}, keyname[100];
2332 int k, nc, inode = 0, N_ts = 0, ChildOverInd=-1,loc[2], ii = 0;
2333 float ftop = 0.1, fbot = 0.01, fs=0.0, fstep=0.0, *fv=NULL;
2334 int normalize = 1, polort = 2;
2335 SUMA_EngineData *ED = NULL;
2336 SUMA_DSET *dot=NULL;
2337 SUMA_DSET *in_dset = NULL;
2338 SUMA_SurfaceObject *SO=NULL;
2339 SUMA_OVERLAYS *Sover=NULL, *child=NULL;
2340 SUMA_DSET *inc_dset=NULL;
2341 SUMA_SurfaceObject *SOC=NULL;
2342 DList *list = NULL;
2343 DListElmt *el= NULL;
2344 double *ts = NULL, TR=0.0;
2345 NI_group *ngr = NULL;
2346 NI_element *nel=NULL, *dotopts=NULL;
2347 SUMA_XFORM *xf=NULL;
2348 SUMA_CALLBACK *cb=NULL;
2349 char stmp[SUMA_MAX_NAME_LENGTH]={""};
2350 SUMA_Boolean LocalHead = NOPE;
2351
2352 SUMA_ENTRY;
2353
2354 // fprintf(stderr, "%s\n", FuncName);
2355
2356 SUMA_KEY_COMMON;
2357
2358 /* do the work */
2359 switch (k) {
2360 case XK_D:
2361 if ((SUMA_CTRL_KEY(key))){
2362 } else {
2363 SUMA_LH("The dotthing");
2364 /* DO the dot thing */
2365 if (!(SO = SUMA_SV_Focus_SO(sv))) {
2366 if (callmode && strcmp(callmode, "interactive") == 0) {
2367 SUMA_SLP_Err("No surface in focus.\nCannot dot.");
2368 } else {
2369 SUMA_S_Err("No surface in focus.\nCannot dot.");
2370 }
2371 SUMA_RETURN(0);
2372 }
2373 if ( !SO || !SO->SurfCont ||
2374 !SO->SurfCont->curColPlane ||
2375 !SO->SurfCont->curColPlane->dset_link) {
2376 SUMA_SL_Err("Nothing to dot");
2377 SUMA_RETURN(0);
2378 }
2379 Sover = SO->SurfCont->curColPlane;
2380 in_dset = SO->SurfCont->curColPlane->dset_link;
2381 inode = SO->SelectedNode;
2382 if (inode < 0) {
2383 if (callmode && strcmp(callmode, "interactive") == 0) {
2384 SUMA_SLP_Warn("No selected node.\nNothing to dot.");
2385 }else{
2386 SUMA_S_Warn("No selected node.\nNothing to dot.");
2387 }
2388 SUMA_RETURN(1);
2389 }
2390 if (SDSET_VECNUM(in_dset) < 3) {
2391 if (callmode && strcmp(callmode, "interactive") == 0) {
2392 SUMA_SLP_Warn( "Need more than 3 values per node.\n"
2393 "Nothing to dot.");
2394 }else{
2395 SUMA_S_Warn("Need more than 3 values per node.\n"
2396 "Nothing to dot.");
2397 }
2398 SUMA_RETURN(1);
2399 }
2400
2401
2402 if ((xf = SUMA_Find_XformByParent("Dot", SDSET_ID(in_dset), NULL))) {
2403 /* xform exists already, just flip toggle of all callbacks
2404 that claim it as a creator*/
2405 SUMA_SetXformActive(xf, -1*xf->active, 0);
2406
2407 if (callmode && strcmp(callmode, "interactive") == 0) {
2408 if (xf->active > 0) {
2409 SUMA_SLP_Note("Dot product callback active");
2410 } else {
2411 SUMA_SLP_Note("Dot product callback inactive");
2412 }
2413 }else {
2414 if (xf->active > 0) {
2415 SUMA_S_Note("Dot product callback active");
2416 } else {
2417 SUMA_S_Note("Dot product callback inactive");
2418 }
2419 }
2420
2421 SUMA_RETURN(1);
2422 } else { /* New Xform */
2423 /* We need to add a dot product transform to
2424 the dataset */
2425 SUMA_LH("Afresh: Adding Dot Xform");
2426 xf = SUMA_NewXform("Dot",
2427 SDSET_ID(in_dset), SO->LocalDomainParentID);
2428
2429 /* Any matching contralateral dset and a matching surface ?*/
2430 inc_dset = SUMA_Contralateral_dset(in_dset, SO, &SOC);
2431 if (inc_dset) {
2432 SUMA_LHv("Found contralateral dset %s (%s)\n",
2433 SDSET_LABEL(inc_dset), SDSET_FILENAME(inc_dset));
2434 if (!(SUMA_AddXformParent(xf,
2435 SDSET_ID(inc_dset), SOC->LocalDomainParentID))) {
2436 SUMA_S_Err("Failed to add parent");
2437 SUMA_RETURN(0);
2438 }
2439 } else {
2440 SUMA_S_Note("No contralateral dset ");
2441 }
2442 /* Initialize dot product options. You'll have to redo this
2443 unfortunately below... */
2444 if (!(SUMA_is_TimeSeries_dset(in_dset, &TR))) {
2445 TR = 0.0;
2446 }
2447 SUMA_SPECT_AXIS(TR, SDSET_VECNUM(in_dset), fs, ftop, fstep);
2448 dotopts = SUMA_set_dotopts(NULL, SDSET_VECNUM(in_dset),
2449 0.1, fbot,
2450 normalize, 1,
2451 polort, NULL);
2452
2453
2454 SUMA_LH("Get dot product time series");
2455
2456 if (!(fv = (float*)SUMA_GetDsetAllNodeValsInCols2(in_dset,
2457 NULL, 0,
2458 inode, SO->N_Node-1,
2459 &N_ts,
2460 SUMA_float))) {
2461 SUMA_S_Err("Failed to extract time series.");
2462 SUMA_RETURN(0);
2463 }
2464 if (!(ts = SUMA_DotPreProcessTimeSeries(fv, N_ts,
2465 (float)TR, dotopts))) {
2466 SUMA_S_Err("Failed to preprocess time series.");
2467 SUMA_RETURN(0);
2468 }
2469 SUMA_free(fv); fv=NULL;
2470
2471 for (ii=0; ii<xf->N_parents; ++ii) {
2472 dot = NULL; /* You'll need a new dset with each pass */
2473 if (!SUMA_is_ID_4_DSET(xf->parents[ii], &in_dset)) {
2474 /* This is a convoluted way to get in_dset,
2475 since in_dset is known from a few lines above.
2476 But it is meant to demo how to work with
2477 multiple parents in xf in general */
2478 SUMA_S_Err("You've really done it this time!");
2479 SUMA_RETURN(0);
2480 }
2481 if (!SUMA_is_ID_4_SO(xf->parents_domain[ii], &SO)) {
2482 /* This is a convoluted way to get SO...*/
2483 SUMA_S_Err("You've really really done it this time!");
2484 SUMA_RETURN(0);
2485 }
2486 SUMA_LHv("Creating dot for %d/%d %s\n",
2487 ii, xf->N_parents, SDSET_FILENAME(in_dset));
2488 if (!(SUMA_dot_product(in_dset, ts,
2489 &dot,
2490 dotopts))) {
2491 SUMA_S_Err("Failed to create dot product");
2492 SUMA_RETURN(0);
2493 }
2494
2495 /* Assign domain parent fields */
2496 NI_set_attribute(dot->ngr,"domain_parent_idcode",
2497 NI_get_attribute(in_dset->ngr,
2498 "domain_parent_idcode"));
2499 NI_set_attribute(dot->ngr,"geometry_parent_idcode",
2500 NI_get_attribute(in_dset->ngr,
2501 "geometry_parent_idcode"));
2502
2503 SUMA_LHv( "Insert (%s/%s)in DsetList\n",
2504 SDSET_LABEL(dot), SDSET_ID(dot) );
2505 /* no replacement allowed
2506 I don't think it's necessary*/
2507 if (!SUMA_InsertDsetPointer (&dot, SUMAg_CF->DsetList, 0)) {
2508 SUMA_S_Errv("Failed to insert pointer for %s\n",
2509 SDSET_LABEL(dot));
2510 SUMA_RETURN(0);
2511 }
2512
2513 /* Add child to Xform */
2514 if (!SUMA_AddXformChild(xf,SDSET_ID(dot))) {
2515 SUMA_S_Err("Failed to add child");
2516 SUMA_RETURN(0);
2517 }
2518
2519 SUMA_LH("Create its overlay (child)");
2520 if (!(SDSET_LABEL(dot))) SUMA_LabelDset(dot,NULL);
2521 sprintf(stmp, "overlay.%s", SDSET_ID(dot));
2522 child = SUMA_CreateOverlayPointer (
2523 stmp, dot, SO->idcode_str, NULL);
2524 if (!child) {
2525 fprintf (SUMA_STDERR,
2526 "Error %s: Failed in CreateOverlayPointer.\n" ,
2527 FuncName);
2528 SUMA_RETURN (0);
2529 }
2530 SUMA_LH("Add overlay to SO");
2531 /* Add this plane to SO->Overlays */
2532 if (!SUMA_AddNewPlane ( (SUMA_ALL_DO *)SO, child,
2533 SUMAg_DOv, SUMAg_N_DOv, 0)) {
2534 SUMA_SL_Crit("Failed in SUMA_AddNewPlane");
2535 SUMA_FreeOverlayPointer(child);
2536 SUMA_RETURN (0);
2537 }
2538
2539 ChildOverInd = SO->N_Overlays-1;
2540 /* set the opacity, index column and the range */
2541 child->GlobalOpacity = YUP;
2542 child->ShowMode = SW_SurfCont_DsetViewCol;
2543 child->OptScl->BrightFact = 0.8;
2544
2545 child->OptScl->find = 0;
2546 child->OptScl->tind = 0;
2547 child->OptScl->bind = 0;
2548 child->OptScl->UseThr = 1; /* turn on threshold use */
2549 child->SymIrange = 1; /* Use symmetric range */
2550 child->OptScl->AutoIntRange = 0; /* Do not update range */
2551
2552 /* Leave it to the -0.5, 0.5 range below, it works better
2553 SUMA_GetDsetColRange(dot, 0, child->OptScl->IntRange, loc);
2554 */
2555
2556 SO->SurfCont->curColPlane = child;
2557
2558 /* update the Dset frame */
2559 if (ChildOverInd >= 0)
2560 SUMA_InitializeColPlaneShell((SUMA_ALL_DO *)SO,
2561 SO->Overlays[ChildOverInd]);
2562 SUMA_UPDATE_ALL_NODE_GUI_FIELDS((SUMA_ALL_DO *)SO);
2563 child->OptScl->IntRange[0] = -0.5; /* set the range */
2564 child->OptScl->IntRange[1] = 0.5;
2565 SUMA_INSERT_CELL_VALUE(SO->SurfCont->SetRangeTable, 1, 1,
2566 child->OptScl->IntRange[0]);
2567 SUMA_INSERT_CELL_VALUE(SO->SurfCont->SetRangeTable, 1, 2,
2568 child->OptScl->IntRange[1]);
2569
2570 SUMA_LH("Colorize plane");
2571 SUMA_ColorizePlane(child);
2572
2573 /* remix-redisplay for surface */
2574 if (!SUMA_Remixedisplay ((SUMA_ALL_DO*)SO)) {
2575 SUMA_RETURN(0);
2576 }
2577
2578 SUMA_LH("Refreshing Dset list");
2579 /*update the list widget if open */
2580 LW = SO->SurfCont->SwitchDsetlst;
2581 if (LW) {
2582 if (!LW->isShaded) SUMA_RefreshDsetList ((SUMA_ALL_DO *)SO);
2583 }
2584
2585 if (LocalHead)
2586 fprintf (SUMA_STDERR,
2587 "%s: Updating Dset frame, OverInd=%d\n",
2588 FuncName, ChildOverInd);
2589
2590 } /* For each parent */
2591
2592 /* done with ts */
2593 SUMA_free(ts); ts = NULL;
2594
2595 /* add the dotoptions to the transform options group */
2596 NI_add_to_group(xf->XformOpts, dotopts);
2597
2598 /* activate xform */
2599 SUMA_SetXformActive(xf, 1, 0);
2600
2601
2602 SUMA_LH("Add Callback ");
2603 /* generic parts */
2604 cb = SUMA_NewCallback( "SUMA_dot_product_CB",
2605 SUMA_NEW_NODE_ACTIVATE_EVENT,
2606 SUMA_dot_product_CB,
2607 xf->children[0],
2608 xf->parents_domain[0],
2609 xf->idcode_str);
2610
2611
2612 /* add extra children */
2613 for (ii=1; ii<xf->N_children; ++ii) {
2614 if (!SUMA_AddCallbackParent(cb, xf->children[ii],
2615 xf->parents_domain[ii])) {
2616 SUMA_S_Err("Failed to add parent");
2617 SUMA_RETURN(0);
2618 }
2619 }
2620
2621 /* fill the callback function's input parameters */
2622 /* The time series datasets */
2623 nel = NI_new_data_element("AFNI_atr", 1);
2624 NI_set_attribute(nel, "atr_name", "ts_dsets_idcode");
2625 NI_add_column_stride(nel, NI_STRING, NULL,1);
2626 for (ii=0; ii<xf->N_parents; ++ii) {
2627 if (!SUMA_AddColAtt_CompString( nel, ii,
2628 xf->parents[ii], SUMA_NI_CSS, 0)){
2629 SUMA_S_Err("Failed to add ts_dsets_idcode");
2630 SUMA_RETURN(0);
2631 }
2632 }
2633 NI_add_to_group(cb->FunctionInput, nel);
2634
2635 /* the output datasets */
2636 nel = NI_new_data_element("AFNI_atr", 1);
2637 NI_set_attribute(nel, "atr_name", "dot_dsets_idcode");
2638 NI_add_column_stride(nel, NI_STRING, NULL,1);
2639 for (ii=0; ii<xf->N_children; ++ii) {
2640 if (!SUMA_AddColAtt_CompString( nel, ii,
2641 xf->children[ii], SUMA_NI_CSS, 0)){
2642 SUMA_S_Err("Failed to add dot_dsets_idcode");
2643 SUMA_RETURN(0);
2644 }
2645 }
2646 NI_add_to_group(cb->FunctionInput, nel);
2647
2648 /* Node is from surface SO, but there is no point
2649 in setting this now because the computations
2650 have been done already. Set all sources for
2651 getting the time series to nothing, for the
2652 record.*/
2653 /* ts can be specified via node selection events and parents */
2654 SUMA_FlushCallbackEventParameters (cb);
2655
2656 /* or ts can be explicitly set
2657 again, the existence of ts_vec is not necessary,
2658 but to illustrate options ...*/
2659 nel = NI_new_data_element("callback.data",0);
2660 NI_set_attribute(nel, "data_type", "ts_vec");
2661 NI_add_to_group(cb->FunctionInput, nel);
2662
2663 /* set callback to be active, but not pending */
2664 cb->active = 1;
2665 SUMA_SetCallbackPending(cb, 0, SES_Empty);
2666 if (callmode && strcmp(callmode, "interactive") == 0) {
2667 SUMA_SLP_Note("Dot product callback active"); } else {
2668 SUMA_S_Note("Dot product callback active");
2669 }
2670
2671 if (LocalHead) {
2672 SUMA_Show_Xforms(SUMAg_CF->xforms, SUMA_STDERR, 1);
2673 SUMA_Show_Callbacks(SUMAg_CF->callbacks, SUMA_STDERR, 1);
2674 }
2675
2676 /* initialize interface (no callbacks willget triggered)*/
2677 SUMA_InitializeXformInterface (xf);
2678
2679 } /* New Xform */
2680
2681 }
2682 break;
2683 case XK_d:
2684 if ((SUMA_CTRL_KEY(key))){
2685 /* Interactively it is handled by the mnemonic
2686 But if it gets here, the Driver may be driving it */
2687 /* opens draw ROI controller */
2688 if (!SUMA_OpenDrawROIController(NULL)) {
2689 SUMA_S_Err("Failed to open controller");
2690 }
2691 } else {
2692 if (SUMAg_CF->Dev ) {
2693 SUMA_Show_DOv(SUMAg_DOv, SUMAg_N_DOv, stdout);
2694 }
2695 }
2696
2697
2698 break;
2699 default:
2700 SUMA_S_Err("Il ne faut pas ci dessous");
2701 SUMA_RETURN(0);
2702 break;
2703 }
2704
2705 SUMA_RETURN(1);
2706 }
2707
SUMA_F_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2708 int SUMA_F_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2709 {
2710 static char FuncName[]={"SUMA_F_Key"};
2711 char tk[]={"F"}, keyname[100];
2712 int k=0, nc=-1;
2713 int inode = -1;
2714 SUMA_DSET *Dset = NULL;
2715 SUMA_ALL_DO *ado=NULL;
2716 SUMA_OVERLAYS *Sover=NULL;
2717 SUMA_X_SurfCont *SurfCont=NULL;
2718 char stmp[100]={"\0"};
2719 SUMA_Boolean LocalHead = NOPE;
2720 // static DList *list = NULL;
2721
2722 SUMA_ENTRY;
2723
2724 SUMA_KEY_COMMON;
2725
2726 /* do the work */
2727 switch (k) {
2728 case XK_F:
2729 /* flip light position */
2730 if (!list) list = SUMA_CreateList();
2731 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_FlipLight0Pos,
2732 SES_Suma, sv);
2733 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
2734
2735 if (!SUMA_Engine (&list)) {
2736 fprintf(stderr, "Error SUMA_input: SUMA_Engine call failed.\n");
2737 }
2738 break;
2739
2740 case XK_f:
2741 if (clippingPlaneMode && (SUMA_CTRL_KEY(key))){
2742 clipPlaneTransform(0,0,0,1,-1, 0, 0); // PDL: Flip clipping plane
2743 } else {
2744 /* Show/hide the foreground */
2745 if (!list) list = SUMA_CreateList();
2746 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_ToggleForeground,
2747 SES_Suma, sv);
2748 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
2749
2750 if (!SUMA_Engine (&list)) {
2751 fprintf(stderr, "Error SUMA_input: SUMA_Engine call failed.\n");
2752 }
2753 }
2754 break;
2755 }
2756 SUMA_RETURN(1);
2757 }
2758
SUMA_G_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2759 int SUMA_G_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2760 {
2761 static char FuncName[]={"SUMA_G_Key"};
2762 char tk[]={"G"}, keyname[100];
2763 int k=0, nc=-1;
2764 int inode = -1;
2765 SUMA_DSET *Dset = NULL;
2766 SUMA_ALL_DO *ado=NULL;
2767 SUMA_OVERLAYS *Sover=NULL;
2768 SUMA_X_SurfCont *SurfCont=NULL;
2769 char stmp[100]={"\0"};
2770 SUMA_Boolean LocalHead = NOPE;
2771
2772 SUMA_ENTRY;
2773
2774 SUMA_KEY_COMMON;
2775
2776 if (!(ado = SUMA_SV_Focus_ADO(sv))) {
2777 if (callmode && strcmp(callmode, "interactive") == 0) {
2778 SUMA_SLP_Err("No surface in focus.\nCannot graph.");
2779 } else {
2780 SUMA_S_Err("No surface in focus.\nCannot graph.");
2781 }
2782 SUMA_RETURN(0);
2783 }
2784 if ( !ado || !(SurfCont = SUMA_ADO_Cont(ado)) ||
2785 !(Sover = SUMA_ADO_CurColPlane(ado)) ||
2786 !(Dset = Sover->dset_link)) {
2787 SUMA_SL_Err("Nothing to graph");
2788 SUMA_RETURN(0);
2789 }
2790 inode = SUMA_ADO_SelectedDatum(ado, NULL, NULL);
2791 if (inode < 0) {
2792 if (callmode && strcmp(callmode, "interactive") == 0) {
2793 SUMA_SLP_Warn("No selected node.\nNothing to graph.");
2794 }else{
2795 SUMA_S_Warn("No selected node.\nNothing to graph.");
2796 }
2797 SUMA_RETURN(1);
2798 }
2799 if (SDSET_VECNUM(Dset) < 2) {
2800 if (callmode && strcmp(callmode, "interactive") == 0) {
2801 SUMA_SLP_Warn("One or no value per node.\nNothing to graph.");
2802 }else{
2803 SUMA_S_Warn("One or no value per node.\nNothing to graph.");
2804 }
2805 SUMA_RETURN(1);
2806 }
2807 /* do the work */
2808 switch (k) {
2809 case XK_g:
2810 if ((SUMA_CTRL_KEY(key))) {
2811 } else {
2812 SUMA_OverlayGraphAtNode(Sover, ado, inode);
2813 }
2814 break;
2815 case XK_G:
2816 if (SUMAg_CF->Dev ) {
2817 #ifdef SUMA_USE_AFNI_GRAPH
2818 /* an attempt at using AFNI's graphing interface */
2819 SUMA_Afni_Graph(Sover, SO);
2820 #endif
2821 }
2822 break;
2823 default:
2824 SUMA_S_Err("Il ne faut pas etre ici");
2825 SUMA_RETURN(0);
2826 break;
2827 }
2828 SUMA_RETURN(1);
2829 }
2830
SUMA_H_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2831 int SUMA_H_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2832 {
2833 static char FuncName[]={"SUMA_H_Key"};
2834 char tk[]={"H"}, keyname[100];
2835 int k=0, nc=-1;
2836 int inode = -1;
2837 SUMA_DSET *Dset = NULL;
2838 SUMA_ALL_DO *ado=NULL;
2839 SUMA_OVERLAYS *Sover=NULL;
2840 SUMA_X_SurfCont *SurfCont=NULL;
2841 char stmp[100]={"\0"};
2842 SUMA_Boolean LocalHead = NOPE;
2843
2844 SUMA_ENTRY;
2845
2846 SUMA_KEY_COMMON;
2847
2848 switch (k) {
2849 case XK_H:
2850 sv->X->HighlightBox_prmpt =
2851 SUMA_CreatePromptDialogStruct(SUMA_OK_APPLY_CLEAR_CANCEL,
2852 "Enter XYZ of box's center\n"
2853 "followed by it's size (6 values)",
2854 "",
2855 sv->X->TOPLEVEL, YUP,
2856 SUMA_APPLY_BUTTON,
2857 SUMA_HighlightBox, (void *)sv,
2858 NULL, NULL,
2859 NULL, NULL,
2860 SUMA_CleanNumString, (void*)6,
2861 sv->X->HighlightBox_prmpt);
2862
2863 sv->X->HighlightBox_prmpt = SUMA_CreatePromptDialog(sv->X->Title,
2864 sv->X->HighlightBox_prmpt);
2865
2866 break;
2867
2868 case XK_h:
2869 if (SUMA_CTRL_KEY(key)){
2870 if (!list) list = SUMA_CreateList();
2871 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Help, SES_Suma, NULL);
2872 if (!SUMA_Engine (&list)) {
2873 fprintf( stderr,
2874 "Error %s: SUMA_Engine call failed.\n", FuncName);
2875 }
2876 }else{
2877 if (SUMAg_CF->Dev) {
2878 SUMA_SLP_Note("Please use ctrl+h for help.\n"
2879 "h alone will be reassigned\n"
2880 "in future versions.");
2881 }
2882 }
2883 break;
2884 }
2885 SUMA_RETURN(1);
2886 }
2887
SUMA_J_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode,char * strgval)2888 int SUMA_J_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode, char *strgval)
2889 {
2890 static char FuncName[]={"SUMA_J_Key"};
2891 char tk[]={"J"}, keyname[100];
2892 int k=0, nc=-1;
2893 int inode = -1;
2894 SUMA_DSET *Dset = NULL;
2895 SUMA_ALL_DO *ado=NULL;
2896 SUMA_OVERLAYS *Sover=NULL;
2897 char stmp[100]={"\0"};
2898 SUMA_Boolean LocalHead = NOPE;
2899
2900 SUMA_ENTRY;
2901
2902 // fprintf(stderr, "%s\n", FuncName);
2903
2904 SUMA_KEY_COMMON;
2905
2906
2907 if (!(ado = SUMA_SV_Focus_ADO(sv))) {
2908 if (callmode && strcmp(callmode, "interactive") == 0) {
2909 SUMA_SLP_Err("No object in focus.\nCannot Jump.");
2910 } else {
2911 SUMA_S_Err("No object in focus.\nCannot Jump.");
2912 }
2913 SUMA_RETURN(0);
2914 }
2915 /* do the work */
2916 switch (k) {
2917 case XK_j:
2918 if ( (callmode && strcmp(callmode, "interactive") == 0) ||
2919 !strgval /* why not? this way the
2920 Driver can pop the interactive window */) {
2921 if (SUMA_CTRL_KEY(key)){
2922 sv->X->JumpXYZ_prmpt = SUMA_CreatePromptDialogStruct(
2923 SUMA_OK_APPLY_CLEAR_CANCEL,
2924 "Enter XYZ to send the cross hair to:",
2925 "",
2926 sv->X->TOPLEVEL, YUP,
2927 SUMA_APPLY_BUTTON,
2928 SUMA_JumpXYZ, (void *)sv,
2929 NULL, NULL,
2930 NULL, NULL,
2931 SUMA_CleanNumString, (void*)3,
2932 sv->X->JumpXYZ_prmpt);
2933 sv->X->JumpXYZ_prmpt = SUMA_CreatePromptDialog(
2934 sv->X->Title, sv->X->JumpXYZ_prmpt);
2935
2936 } else if (SUMA_AALT_KEY(key)){
2937 sv->X->JumpFocusNode_prmpt = SUMA_CreatePromptDialogStruct(
2938 SUMA_OK_APPLY_CLEAR_CANCEL,
2939 "Enter index of focus node\n"
2940 "Prepend/append L/R for hemiisphere selection\n"
2941 "Cross hair's XYZ will not be affected:",
2942 "",
2943 sv->X->TOPLEVEL, YUP,
2944 SUMA_APPLY_BUTTON,
2945 SUMA_JumpFocusNode, (void *)sv,
2946 NULL, NULL,
2947 NULL, NULL,
2948 SUMA_CleanNumStringSide, (void*)1, sv->X->JumpFocusNode_prmpt);
2949
2950 sv->X->JumpFocusNode_prmpt = SUMA_CreatePromptDialog(
2951 sv->X->Title, sv->X->JumpFocusNode_prmpt);
2952
2953 } else {
2954 sv->X->JumpIndex_prmpt = SUMA_CreatePromptDialogStruct(
2955 SUMA_OK_APPLY_CLEAR_CANCEL,
2956 "Enter index of node to send the cross hair to:\n"
2957 "(prepend/append L/R for specifying hemisphere):",
2958 "",
2959 sv->X->TOPLEVEL, YUP,
2960 SUMA_APPLY_BUTTON,
2961 SUMA_JumpIndex, (void *)sv,
2962 NULL, NULL,
2963 NULL, NULL,
2964 SUMA_CleanNumStringSide, (void*)1,
2965 sv->X->JumpIndex_prmpt);
2966
2967 sv->X->JumpIndex_prmpt = SUMA_CreatePromptDialog(
2968 sv->X->Title, sv->X->JumpIndex_prmpt);
2969 }
2970 } else {
2971 if (!strgval) {
2972 SUMA_S_Err("Have NULL string");
2973 SUMA_RETURN(0);
2974 }
2975 if (SUMA_CTRL_KEY(key)){
2976 SUMA_JumpXYZ(strgval, (void *)sv);
2977 } else if (SUMA_AALT_KEY(key)){
2978 SUMA_JumpFocusNode(strgval, (void *)sv);
2979 } else {
2980 SUMA_JumpIndex(strgval, (void *)sv);
2981 }
2982 }
2983
2984 break;
2985 case XK_J:
2986 if ( (callmode && strcmp(callmode, "interactive") == 0) ||
2987 !strgval) {
2988 sv->X->JumpFocusFace_prmpt = SUMA_CreatePromptDialogStruct (
2989 SUMA_OK_APPLY_CLEAR_CANCEL,
2990 "Enter index of FaceSet\nto highlight (this viewer only):",
2991 "",
2992 sv->X->TOPLEVEL, YUP,
2993 SUMA_APPLY_BUTTON,
2994 SUMA_JumpFocusFace, (void *)sv,
2995 NULL, NULL,
2996 NULL, NULL,
2997 SUMA_CleanNumString, (void*)1,
2998 sv->X->JumpFocusFace_prmpt);
2999
3000 sv->X->JumpFocusFace_prmpt = SUMA_CreatePromptDialog(
3001 sv->X->Title, sv->X->JumpFocusFace_prmpt);
3002 } else {
3003 if (!strgval) {
3004 SUMA_S_Err("Have NULL string");
3005 SUMA_RETURN(0);
3006 }
3007 SUMA_JumpFocusFace( strgval, (void *)sv);
3008 }
3009 break;
3010 default:
3011 SUMA_S_Err("Il ne faut pas etre ici");
3012 SUMA_RETURN(0);
3013 break;
3014 }
3015 SUMA_RETURN(1);
3016 }
3017
SUMA_L_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode,char * strgval)3018 int SUMA_L_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode, char *strgval)
3019 {
3020 static char FuncName[]={"SUMA_L_Key"};
3021 char tk[]={"L"}, keyname[100];
3022 int k, nc;
3023 SUMA_EngineData *ED = NULL;
3024 DList *list = NULL;
3025 DListElmt *NextElm= NULL;
3026 SUMA_Boolean LocalHead = NOPE;
3027
3028 SUMA_ENTRY;
3029
3030 // fprintf(stderr, "%s\n", FuncName);
3031
3032 SUMA_KEY_COMMON;
3033 if (strgval) {
3034 SUMA_S_Warn("strgval (%s) not implemented for L_Key yet. \n"
3035 "Complain to author if you want it.\n", strgval);
3036 }
3037 /* do the work */
3038 switch (k) {
3039 case XK_l:
3040 if ((SUMA_CTRL_KEY(key))){
3041 #if 0 /* Not of much use */
3042 if (SUMAg_CF->Dev) {
3043 if (!list) list = SUMA_CreateList();
3044 ED = SUMA_InitializeEngineListData (SE_ToggleLockAllCrossHair);
3045 if (!SUMA_RegisterEngineListCommand ( list, ED,
3046 SEF_Empty, NULL,
3047 SES_Suma, (void *)sv, NOPE,
3048 SEI_Head, NULL )) {
3049 fprintf( SUMA_STDERR,
3050 "Error %s: Failed to register command\n",
3051 FuncName);
3052 break;
3053 }
3054 if (!SUMA_Engine (&list)) {
3055 fprintf( stderr,
3056 "Error %s: SUMA_Engine call failed.\n", FuncName);
3057 }
3058 }
3059 #else
3060 GLfloat light0_color[] = { SUMA_LIGHT0_COLOR_INIT};
3061 /* dim the lights */
3062 sv->dim_spe = sv->dim_spe * 0.8;
3063 if (sv->dim_spe < 0.1) sv->dim_spe = 1.0;
3064 sv->dim_dif = sv->dim_dif * 0.8;
3065 if (sv->dim_dif < 0.1) sv->dim_dif = 1.0;
3066 sv->dim_amb = sv->dim_amb * 0.8;
3067 if (sv->dim_amb < 0.1) sv->dim_amb = 1.0;
3068 sv->dim_emi = sv->dim_emi * 0.8;
3069 if (sv->dim_emi < 0.1) sv->dim_emi = 1.0;
3070 fprintf(SUMA_STDERR,
3071 "%s: light dim factor now %.3f\n",
3072 FuncName, sv->dim_spe);
3073 /*fprintf(SUMA_STDERR,"%s: light dim factor now %.3f\n"
3074 "%f %f %f %f\n",
3075 FuncName, sv->dim_spe,
3076 sv->light0_color[0], sv->light0_color[1],
3077 sv->light0_color[2], sv->light0_color[3]);
3078 */
3079 light0_color[0] = sv->light0_color[0]*sv->dim_spe;
3080 light0_color[1] = sv->light0_color[1]*sv->dim_spe;
3081 light0_color[2] = sv->light0_color[2]*sv->dim_spe;
3082 light0_color[3] = sv->light0_color[3]*sv->dim_spe;
3083 glLightfv(GL_LIGHT0, GL_SPECULAR, light0_color);
3084 light0_color[0] = sv->light0_color[0]*sv->dim_dif;
3085 light0_color[1] = sv->light0_color[1]*sv->dim_dif;
3086 light0_color[2] = sv->light0_color[2]*sv->dim_dif;
3087 light0_color[3] = sv->light0_color[3]*sv->dim_dif;
3088 glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_color);
3089 light0_color[0] = sv->lmodel_ambient[0]*sv->dim_amb;
3090 light0_color[1] = sv->lmodel_ambient[1]*sv->dim_amb;
3091 light0_color[2] = sv->lmodel_ambient[2]*sv->dim_amb;
3092 light0_color[3] = sv->lmodel_ambient[3]*sv->dim_amb;
3093 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, sv->lmodel_ambient);
3094 if (!list) list = SUMA_CreateList();
3095 SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_Redisplay,
3096 SES_Suma, sv);
3097
3098 if (!SUMA_Engine (&list)) {
3099 fprintf(stderr,
3100 "Error SUMA_input: SUMA_Engine call failed.\n");
3101 }
3102 #endif
3103 } else if ((SUMA_AALT_KEY(key))){ /* alt + l */
3104 /* register cross hair XYZ with ED */
3105 if (!list) list = SUMA_CreateList();
3106 ED = SUMA_InitializeEngineListData (SE_SetLookAt);
3107 if (!SUMA_RegisterEngineListCommand ( list, ED,
3108 SEF_fv3, (void *)sv->Ch->c,
3109 SES_Suma, (void *)sv, NOPE,
3110 SEI_Head, NULL )) {
3111 fprintf( SUMA_STDERR,
3112 "Error %s: Failed to register command\n", FuncName);
3113 SUMA_RETURN(0);
3114 }
3115 if (!SUMA_Engine (&list)) {
3116 fprintf(stderr,
3117 "Error %s: SUMA_Engine call failed.\n", FuncName);
3118 }
3119 } else {
3120 sv->X->LookAt_prmpt = SUMA_CreatePromptDialogStruct(
3121 SUMA_OK_APPLY_CLEAR_CANCEL,
3122 "X,Y,Z coordinates to look at:",
3123 "0,0,0",
3124 sv->X->TOPLEVEL, YUP,
3125 SUMA_APPLY_BUTTON,
3126 SUMA_LookAtCoordinates, (void *)sv,
3127 NULL, NULL,
3128 NULL, NULL,
3129 SUMA_CleanNumString, (void*)3,
3130 sv->X->LookAt_prmpt);
3131
3132 sv->X->LookAt_prmpt = SUMA_CreatePromptDialog(sv->X->Title,
3133 sv->X->LookAt_prmpt);
3134
3135 }
3136 break;
3137 case XK_L:
3138 if ((SUMA_CTRL_KEY(key))){
3139 GLfloat light0_color[] = { SUMA_LIGHT0_COLOR_INIT};
3140 /* brighten the lights */
3141 sv->dim_spe = sv->dim_spe / 0.8;
3142 if (sv->dim_spe > 1) sv->dim_spe = 0.1;
3143 sv->dim_dif = sv->dim_dif / 0.8;
3144 if (sv->dim_dif > 1) sv->dim_dif = 0.1;
3145 sv->dim_amb = sv->dim_amb / 0.8;
3146 if (sv->dim_amb > 1) sv->dim_amb = 0.1;
3147 sv->dim_emi = sv->dim_emi / 0.8;
3148 if (sv->dim_emi > 1) sv->dim_emi = 0.1;
3149 fprintf(SUMA_STDERR,
3150 "%s: light dim factor now %.3f\n",
3151 FuncName, sv->dim_spe);
3152 /*fprintf(SUMA_STDERR,"%s: light dim factor now %.3f\n"
3153 "%f %f %f %f\n",
3154 FuncName, sv->dim_spe,
3155 sv->light0_color[0], sv->light0_color[1],
3156 sv->light0_color[2], sv->light0_color[3]);
3157 */
3158 light0_color[0] = sv->light0_color[0]*sv->dim_spe;
3159 light0_color[1] = sv->light0_color[1]*sv->dim_spe;
3160 light0_color[2] = sv->light0_color[2]*sv->dim_spe;
3161 light0_color[3] = sv->light0_color[3]*sv->dim_spe;
3162 glLightfv(GL_LIGHT0, GL_SPECULAR, light0_color);
3163 light0_color[0] = sv->light0_color[0]*sv->dim_dif;
3164 light0_color[1] = sv->light0_color[1]*sv->dim_dif;
3165 light0_color[2] = sv->light0_color[2]*sv->dim_dif;
3166 light0_color[3] = sv->light0_color[3]*sv->dim_dif;
3167 glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_color);
3168 light0_color[0] = sv->lmodel_ambient[0]*sv->dim_amb;
3169 light0_color[1] = sv->lmodel_ambient[1]*sv->dim_amb;
3170 light0_color[2] = sv->lmodel_ambient[2]*sv->dim_amb;
3171 light0_color[3] = sv->lmodel_ambient[3]*sv->dim_amb;
3172 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, sv->lmodel_ambient);
3173 if (!list) list = SUMA_CreateList();
3174 SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_Redisplay,
3175 SES_Suma, sv);
3176
3177 if (!SUMA_Engine (&list)) {
3178 fprintf(stderr,
3179 "Error SUMA_input: SUMA_Engine call failed.\n");
3180 }
3181 } else if ((SUMA_AALT_KEY(key))){
3182
3183 } else {
3184 SUMA_PROMPT_DIALOG_STRUCT *prmpt;
3185 prmpt = SUMA_CreatePromptDialogStruct (
3186 SUMA_OK_APPLY_CLEAR_CANCEL,
3187 "X,Y,Z coordinates of light0:",
3188 "",
3189 sv->X->TOPLEVEL, NOPE,
3190 SUMA_APPLY_BUTTON,
3191 SUMA_SetLight0, (void *)sv,
3192 NULL, NULL,
3193 NULL, NULL,
3194 SUMA_CleanNumString, (void*)3,
3195 NULL);
3196
3197 prmpt = SUMA_CreatePromptDialog(sv->X->Title, prmpt);
3198 }
3199
3200 break;
3201 default:
3202 SUMA_S_Err("Il ne faut pas etre ici");
3203 SUMA_RETURN(0);
3204 break;
3205 }
3206
3207 SUMA_RETURN(1);
3208 }
3209
SUMA_M_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)3210 int SUMA_M_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
3211 {
3212 static char FuncName[]={"SUMA_M_Key"};
3213 char tk[]={"M"}, keyname[100];
3214 int k, nc;
3215 SUMA_Boolean LocalHead = NOPE;
3216
3217 SUMA_ENTRY;
3218
3219 // fprintf(stderr, "%s\n", FuncName);
3220
3221 SUMA_KEY_COMMON;
3222
3223 /* do the work */
3224 switch (k) {
3225 case XK_m:
3226 if ((SUMA_CTRL_KEY(key))) {
3227 SUMA_SurfaceObject *SO;
3228 float fv3[3];
3229 int it;
3230 fprintf(SUMA_STDOUT, "%s: Enter shift in mm [RAI] "
3231 "to apply to all mappable surfaces in DOv.\n",
3232 FuncName);
3233 it = SUMA_ReadNumStdin (fv3, 3);
3234 if (it > 0 && it < 3) {
3235 fprintf(SUMA_STDERR,"Error %s: read %d values, expected 3.\n",
3236 FuncName, it);
3237 SUMA_RETURN(0);
3238 }else if (it < 0) {
3239 fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ReadNumStdin.\n",
3240 FuncName);
3241 SUMA_RETURN(0);
3242 }else if (it == 0) {
3243 fprintf(SUMA_STDERR,"%s: Nothing read.\n", FuncName);
3244 SUMA_RETURN(0);
3245 }
3246
3247 for (it = 0; it < SUMAg_N_DOv; ++it) {
3248 if (SUMA_isSO_G (SUMAg_DOv[it], sv->CurGroupName)) {
3249 SO = (SUMA_SurfaceObject *)SUMAg_DOv[it].OP;
3250 if (SUMA_isLocalDomainParent(SO)) {
3251 int imax, ii;
3252 /* add the shift */
3253 fprintf (SUMA_STDERR,
3254 "%s: Shifting %s by %f %f %f mm RAI.\n",
3255 FuncName, SO->Label, fv3[0], fv3[1], fv3[2]);
3256 ii = 0;
3257 imax = 3 * SO->N_Node;
3258 while (ii < imax) {
3259 SO->NodeList[ii] += fv3[0]; ++ii;
3260 SO->NodeList[ii] += fv3[1]; ++ii;
3261 SO->NodeList[ii] += fv3[2]; ++ii;
3262 }
3263 }
3264 }
3265 }
3266
3267 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
3268 } else {
3269 sv->GVS[sv->StdView].ApplyMomentum =
3270 !sv->GVS[sv->StdView].ApplyMomentum;
3271 SUMA_UpdateViewerTitle(sv);
3272 if (sv->GVS[sv->StdView].ApplyMomentum) {
3273 sv->X->MOMENTUMID = XtAppAddTimeOut(
3274 SUMAg_CF->X->App, 1,
3275 SUMA_momentum,
3276 (XtPointer) sv->X->GLXAREA);
3277 /* wait till user initiates turning */
3278 sv->GVS[sv->StdView].spinDeltaX = 0;
3279 sv->GVS[sv->StdView].spinDeltaY = 0;
3280 sv->GVS[sv->StdView].translateDeltaX = 0;
3281 sv->GVS[sv->StdView].translateDeltaY = 0;
3282 } else {
3283 if (sv->X->MOMENTUMID) {
3284 XtRemoveTimeOut(sv->X->MOMENTUMID);
3285 sv->X->MOMENTUMID = 0;
3286 }
3287 }
3288 }
3289 break;
3290 case XK_M:
3291 if (SUMA_CTRL_KEY(key) && (SUMA_ALT_KEY(key) || SUMA_APPLE_KEY(key)) ) {
3292 #ifdef ALLOW_MCW_MALLOC
3293 /* write memtrace results to disk */
3294 if (!mcw_malloc_enabled()) {
3295 if (callmode && strcmp(callmode, "interactive") == 0) {
3296 SUMA_SLP_Warn("Memory tracing\n"
3297 "is not enabled.\n"
3298 "Use Help-->MemTrace.");
3299 } else {
3300 SUMA_S_Warn("Memory tracing\n"
3301 "is not enabled.\n"
3302 "Use Help-->MemTrace.");
3303 }
3304 SUMA_RETURN(0);
3305 } else {
3306 if (callmode && strcmp(callmode, "interactive") == 0) {
3307 SUMA_SLP_Note("Dumping memory tracing\n"
3308 "to latest ./malldump.???\n"
3309 "file (if possible).");
3310 } else {
3311 SUMA_S_Note("Dumping memory tracing\n"
3312 "to latest ./malldump.???\n"
3313 "file (if possible).");
3314 }
3315 mcw_malloc_dump_sort(1);
3316 }
3317 #else
3318 if (callmode && strcmp(callmode, "interactive") == 0) {
3319 SUMA_SLP_Warn("Sorry, memory tracing\n"
3320 "was not enabled at compile.\n"
3321 "time. You are out of luck\n"
3322 "if using SUN.");
3323 } else {
3324 SUMA_S_Warn("Sorry, memory tracing\n"
3325 "was not enabled at compile.\n"
3326 "time. You are out of luck\n"
3327 "if using SUN.");
3328 }
3329 SUMA_RETURN(0);
3330 #endif
3331 }
3332 break;
3333 default:
3334 SUMA_S_Err("Il ne faut pas etre ici");
3335 SUMA_RETURN(0);
3336 break;
3337 }
3338
3339 SUMA_RETURN(1);
3340 }
3341
SUMA_N_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)3342 int SUMA_N_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
3343 {
3344 static char FuncName[]={"SUMA_N_Key"};
3345 char tk[]={"N"}, keyname[100];
3346 int k, nc, it;
3347 float fv15[15];
3348 SUMA_EngineData *ED = NULL;
3349 DList *list = NULL;
3350 DListElmt *NextElm= NULL;
3351 SUMA_Boolean LocalHead = NOPE;
3352
3353 SUMA_ENTRY;
3354
3355 // fprintf(stderr, "%s\n", FuncName);
3356
3357 SUMA_KEY_COMMON;
3358
3359 /* do the work */
3360 switch (k) {
3361 case XK_N:
3362 break;
3363 case XK_n:
3364 if (SUMA_CTRL_KEY(key)) {
3365 SUMA_LH("Opening a new controller...");
3366 /* open a new controller */
3367 if (!SUMA_X_SurfaceViewer_Create ()) {
3368 SUMA_S_Err("Failed in SUMA_X_SurfaceViewer_Create.");
3369 SUMA_RETURN(0);
3370 }
3371 } else {
3372 fprintf(stdout,"BAD IDEA Enter XYZ of center followed by size of Box (enter nothing to cancel):\n");
3373 it = SUMA_ReadNumStdin (fv15, 6);
3374 if (it > 0 && it < 6) {
3375 fprintf(SUMA_STDERR,"Error %s: read %d values, expected 6.\n", FuncName, it);
3376 SUMA_RETURN(0);
3377 }else if (it < 0) {
3378 fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ReadNumStdin.\n", FuncName);
3379 SUMA_RETURN(0);
3380 }else if (it == 0) {
3381 SUMA_RETURN(0);
3382 }
3383
3384 fprintf (SUMA_STDOUT, "Parsed Input:\n\tCenter %f, %f, %f.\n\tBox Size %f, %f, %f\n", \
3385 fv15[0], fv15[1],fv15[2],\
3386 fv15[3], fv15[4],fv15[5]);
3387
3388 /* register fv15 with ED */
3389 if (!list) list = SUMA_CreateList ();
3390 ED = SUMA_InitializeEngineListData (SE_GetNearestNode);
3391 if (!SUMA_RegisterEngineListCommand ( list, ED,
3392 SEF_fv15, (void *)fv15,
3393 SES_Suma, (void *)sv, NOPE,
3394 SEI_Head, NULL )) {
3395 fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
3396 break;
3397 }
3398
3399 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
3400 if (!SUMA_Engine (&list)) {
3401 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
3402 }
3403 }
3404 break;
3405 default:
3406 SUMA_S_Err("Il ne faut pas etre ici");
3407 SUMA_RETURN(0);
3408 break;
3409 }
3410
3411 SUMA_RETURN(1);
3412 }
3413
3414 /*!
3415 Execute commands when O or o is pressed
3416 */
SUMA_O_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)3417 int SUMA_O_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
3418 {
3419 static char FuncName[]={"SUMA_O_Key"};
3420 char tk[]={"O"}, keyname[100];
3421 int k, nc;
3422 int N_SOlist, SOlist[SUMA_MAX_DISPLAYABLE_OBJECTS];
3423 SUMA_ALL_DO *ado=NULL;
3424 SUMA_SurfaceObject *SO = NULL;
3425
3426 SUMA_Boolean LocalHead = NOPE;
3427
3428 SUMA_ENTRY;
3429
3430 // fprintf(stderr, "%s\n", FuncName);
3431
3432 SUMA_KEY_COMMON;
3433
3434 /* do the work */
3435 switch (k) {
3436 case XK_O:
3437 if ((SUMA_APPLE_KEY(key) || SUMA_ALT_KEY(key))) {
3438
3439 } else if (SUMA_CTRL_KEY(key)) {
3440 if ((ado = SUMA_SV_Focus_ADO(sv))) {
3441 SUMA_Set_ADO_TransMode(ado, sv->TransMode,
3442 SUMAg_CF->TransModeStep, 1);
3443 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
3444 }
3445 } else {
3446 sv->TransMode = ((sv->TransMode-SUMAg_CF->TransModeStep) %
3447 (STM_N_TransModes-2));
3448 if (sv->TransMode <= STM_ViewerDefault) sv->TransMode = STM_16;
3449
3450 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
3451 }
3452 break;
3453 case XK_o:
3454 if ((SUMA_APPLE_KEY(key) || SUMA_ALT_KEY(key))) {
3455 sv->X->SetRot_prmpt = SUMA_CreatePromptDialogStruct (
3456 SUMA_OK_APPLY_CLEAR_CANCEL, "Center of Rotation X,Y,Z:",
3457 "0,0,0",
3458 sv->X->TOPLEVEL, YUP,
3459 SUMA_APPLY_BUTTON,
3460 SUMA_SetRotCenter, (void *)sv,
3461 NULL, NULL,
3462 NULL, NULL,
3463 NULL, NULL,
3464 sv->X->SetRot_prmpt);
3465
3466 sv->X->SetRot_prmpt = SUMA_CreatePromptDialog(sv->X->Title,
3467 sv->X->SetRot_prmpt);
3468 } else if (SUMA_CTRL_KEY(key)) {
3469 if ((ado = SUMA_SV_Focus_ADO(sv))) {
3470 SUMA_Set_ADO_TransMode(ado, sv->TransMode,
3471 -SUMAg_CF->TransModeStep, 1);
3472 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
3473 }
3474 } else {
3475 sv->TransMode = ((sv->TransMode+SUMAg_CF->TransModeStep) %
3476 (STM_N_TransModes-2));
3477 if (sv->TransMode <= STM_ViewerDefault) sv->TransMode = STM_0;
3478
3479 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
3480 }
3481 break;
3482 default:
3483 SUMA_S_Err("Il ne faut pas etre ici");
3484 SUMA_RETURN(0);
3485 break;
3486 }
3487
3488 SUMA_RETURN(1);
3489 }
3490
3491 /*!
3492 Execute commands when P or p is pressed
3493 */
SUMA_P_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)3494 int SUMA_P_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
3495 {
3496 static char FuncName[]={"SUMA_P_Key"};
3497 char tk[]={"P"}, keyname[100], msg[100];
3498 int k, nc;
3499 int N_SOlist, SOlist[SUMA_MAX_DISPLAYABLE_OBJECTS];
3500 SUMA_SurfaceObject *SO = NULL;
3501 SUMA_ALL_DO *ado=NULL;
3502 SUMA_Boolean LocalHead = NOPE;
3503
3504 SUMA_ENTRY;
3505
3506 // fprintf(stderr, "%s\n", FuncName);
3507
3508 SUMA_KEY_COMMON;
3509
3510 /* do the work */
3511 switch (k) {
3512 case XK_P:
3513 if ((SUMA_APPLE_KEY(key) || SUMA_ALT_KEY(key))) {
3514 } else if (SUMA_CTRL_KEY(key)) {
3515
3516 } else {
3517 sv->PolyMode = SRM_Fill;
3518 N_SOlist = SUMA_RegisteredSOs(sv, SUMAg_DOv, SOlist);
3519 for (k=0; k<N_SOlist; ++k) {
3520 SO = (SUMA_SurfaceObject *)(SUMAg_DOv[SOlist[k]].OP);
3521 SO->PolyMode = SRM_ViewerDefault;
3522 SO->Show = YUP;
3523 }
3524 SUMA_SET_GL_RENDER_MODE(sv->PolyMode);
3525 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
3526 SUMA_SLP_Note("All surfaces displayed as solids");
3527 }
3528 break;
3529 case XK_p:
3530 if ((SUMA_APPLE_KEY(key) || SUMA_ALT_KEY(key))) {
3531 sv->DO_DrawMask = ((sv->DO_DrawMask+1) % SDODM_N_DO_DrawMasks);
3532 snprintf(msg,100*sizeof(char),"DO DrawMask now set to: %s",
3533 SUMA_DO_DrawMaskCode2Name_human(sv->DO_DrawMask));
3534 if (callmode && strcmp(callmode, "interactive") == 0) {
3535 SUMA_SLP_Note ("%s",msg);
3536 } else { SUMA_S_Note ("%s",msg); }
3537 } else if (SUMA_CTRL_KEY(key)) {
3538 if ((ado = SUMA_SV_Focus_ADO(sv))) {
3539 SUMA_Set_ADO_RenderMode(ado, sv->PolyMode, -1, 1);
3540 }
3541 } else {
3542 sv->PolyMode = ((sv->PolyMode+1) % SRM_N_RenderModes);
3543 if (sv->PolyMode <= SRM_ViewerDefault) sv->PolyMode = SRM_Fill;
3544
3545 SUMA_SET_GL_RENDER_MODE(sv->PolyMode);
3546 }
3547 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
3548 break;
3549 default:
3550 SUMA_S_Err("Il ne faut pas etre ici");
3551 SUMA_RETURN(0);
3552 break;
3553 }
3554
3555 SUMA_RETURN(1);
3556 }
3557
3558 /*!
3559 Execute commands when R or r is pressed
3560 */
SUMA_R_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)3561 int SUMA_R_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
3562 {
3563 static char FuncName[]={"SUMA_R_Key"};
3564 char tk[]={"R"}, keyname[100], msg[100];
3565 int k, nc, ii, jj, mm;
3566 SUMA_Boolean LocalHead = NOPE;
3567
3568 SUMA_ENTRY;
3569
3570 // fprintf(stderr, "%s\n", FuncName);
3571
3572 SUMA_KEY_COMMON;
3573
3574 /* do the work */
3575 switch (k) {
3576 case XK_r:
3577 if ((SUMA_APPLE_KEY(key) || SUMA_ALT_KEY(key))) {
3578 SUMAg_CF->SUMA_SnapshotOverSampling =
3579 (SUMAg_CF->SUMA_SnapshotOverSampling +1)%5;
3580 if (SUMAg_CF->SUMA_SnapshotOverSampling == 0)
3581 SUMAg_CF->SUMA_SnapshotOverSampling = 1;
3582 {
3583 sprintf(msg,"Oversampling now set to %d",
3584 SUMAg_CF->SUMA_SnapshotOverSampling);
3585 if (callmode && strcmp(callmode, "interactive") == 0) {
3586 SUMA_SLP_Note ("%s",msg);
3587 } else { SUMA_S_Note ("%s",msg); }
3588 }
3589 } else if (SUMA_CTRL_KEY(key)) {
3590 #if 0
3591 sv->X->SetRot_prmpt = SUMA_CreatePromptDialogStruct (
3592 SUMA_OK_APPLY_CLEAR_CANCEL, "Center of Rotation X,Y,Z:",
3593 "0,0,0",
3594 sv->X->TOPLEVEL, YUP,
3595 SUMA_APPLY_BUTTON,
3596 SUMA_SetRotCenter, (void *)sv,
3597 NULL, NULL,
3598 NULL, NULL,
3599 NULL, NULL,
3600 sv->X->SetRot_prmpt);
3601
3602 sv->X->SetRot_prmpt = SUMA_CreatePromptDialog(sv->X->Title,
3603 sv->X->SetRot_prmpt);
3604 #else
3605 /* save image to disk */
3606 SUMA_SnapToDisk(sv,1, 0);
3607 #endif
3608 } else {
3609 GLvoid *pixels=NULL;
3610 double rat;
3611 int oareah=-1,oareaw=-1, owindh=-1, owindw=-1;
3612 /* Control for GL_MAX_VIEWPORT_DIMS */
3613 if (SUMAg_CF->SUMA_SnapshotOverSampling > 1) {
3614 glGetIntegerv(GL_MAX_VIEWPORT_DIMS,&k);
3615 mm = SUMA_MAX_PAIR(
3616 SUMAg_CF->SUMA_SnapshotOverSampling*sv->X->aHEIGHT,
3617 SUMAg_CF->SUMA_SnapshotOverSampling*sv->X->aWIDTH);
3618 if (mm > k) { /* too big, find best new dimesnions */
3619 rat = (double)mm/(double)k;
3620 /*window shrinking factor to allow for stitching*/
3621 SUMA_S_Notev( "%d/%d (H/W) Too big for oversampling\n"
3622 " reducing resolution by %f.\n",
3623 sv->X->aHEIGHT, sv->X->aWIDTH, rat);
3624 /* store original size */
3625 oareaw = sv->X->aWIDTH; oareah = sv->X->aHEIGHT;
3626 owindw = sv->wWindWidth; owindh = sv->wWindHeight;
3627 sv->X->aHEIGHT =
3628 (int)((double)sv->X->aHEIGHT/rat)-1;
3629 sv->X->aWIDTH =
3630 (int)((double)sv->X->aWIDTH/rat)-1;
3631 SUMA_SV_WindDims_From_DrawAreaDims(sv);
3632 SUMA_WidgetResize (sv->X->TOPLEVEL ,
3633 sv->wWindWidth, sv->wWindHeight);
3634 sv->rdc = SUMA_RDC_X_RESIZE;
3635 glViewport( 0, 0,
3636 sv->X->aWIDTH, sv->X->aHEIGHT);
3637 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
3638 } else {
3639 SUMA_S_Note("Size OK");
3640 }
3641 }
3642 /* turn off checking for duplicates */
3643 for (jj=0; jj<SUMAg_CF->SUMA_SnapshotOverSampling; ++jj) {
3644 for (ii=0; ii<SUMAg_CF->SUMA_SnapshotOverSampling; ++ii) {
3645 if (SUMAg_CF->SUMA_SnapshotOverSampling > 1) {
3646 glGetIntegerv(GL_MAX_VIEWPORT_DIMS,&k);
3647 if (ii==0 && jj == 0) {
3648 SUMA_S_Notev( "Resampling factor of %d\n"
3649 "If using this feature, the\n"
3650 " sequence of %d images is saved\n"
3651 " temporarily to disk and '2dcat'\n"
3652 " is then used to put the images together.\n"
3653 "(Have ViewPort GL_MAX_VIEWPORT_DIMS of %d\n"
3654 " and max dims needed of %d.)\n",
3655 SUMAg_CF->SUMA_SnapshotOverSampling,
3656 SUMAg_CF->SUMA_SnapshotOverSampling *
3657 SUMAg_CF->SUMA_SnapshotOverSampling,
3658 k,
3659 SUMA_MAX_PAIR( SUMAg_CF->SUMA_SnapshotOverSampling *
3660 sv->X->aHEIGHT,
3661 SUMAg_CF->SUMA_SnapshotOverSampling*sv->X->aWIDTH) );
3662 } else {
3663 /* sometimes you have repeated black areas when
3664 oversampling, allow that after very first 'tant' */
3665 SNAP_OkDuplicates();
3666 }
3667 /* start from top left, move to right then go down
3668 one row (Row Major, starting on top left ) */
3669 glViewport(-ii*sv->X->aWIDTH,
3670 -(SUMAg_CF->SUMA_SnapshotOverSampling - jj - 1) *
3671 sv->X->aHEIGHT,
3672 SUMAg_CF->SUMA_SnapshotOverSampling*sv->X->aWIDTH,
3673 SUMAg_CF->SUMA_SnapshotOverSampling *
3674 sv->X->aHEIGHT);
3675 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
3676 #if 0 /* problem should be fixed by SUMA_grabRenderedPixels
3677 Throw section out if no new problems arise.
3678 Search for KILL_DOUBLE_RENDERING to locate
3679 other chunks for removal
3680 ZSS Feb 2012 */
3681 if (1) {
3682 /* seems to fix an problem with snapping the older
3683 image... at least on mac
3684 None of glFlush(); glFinish();glXWaitGL();glXWaitX();
3685 or NI_sleep did the trick
3686 Perhaps the wrong buffer is being grabbed?
3687 Check SUMA_grabPixels ...
3688 ZSS Feb 2012.
3689 Yes it was, SUMA_grabRenderedPixels does the trick.
3690 ZSS Feb the next morning 2012 */
3691 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
3692 }
3693 #endif
3694 } else {
3695 #if 0 /* Search for KILL_DOUBLE_RENDERING to locate
3696 other chunks for removal
3697 ZSS Feb 2012 */
3698 /* ZSS Nov 20 2009
3699 If you do not redisplay here, you could strange cases of
3700 snapping the previous frame as reported by Colm Connolly.
3701
3702 1. suma -spec N27_both_tlrc.spec -sv TT_N27+tlrc. &
3703 2. press F2 five times to cycle through the various axes
3704 from none to all and back to none.
3705 3. press r to record
3706
3707 The first image recorded has axes present even though none
3708 are present in the viewer. Pressing r again produces an
3709 image with no axes as expected.
3710
3711 Actually, it seems this happens in many other cases, F1, F6,
3712 change state, etc.
3713
3714 This seems to be the same problem reported by Chunmao W.
3715 a while back.
3716 Same happens with R option.
3717
3718 Problem only happens under DARWIN it seems.
3719
3720 I do not know why the call to SUMA_handleRedisplay does the
3721 trick. Perhaps it is a buffer reading problem in double
3722 buffer rendering. The fix is ugly, especially in continuous
3723 record mode (see SUMA_display function in 'if(csv->record)'
3724 block), but it works.
3725 */
3726 #ifdef DARWIN
3727 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
3728 #endif
3729 #endif
3730 }
3731 pixels = SUMA_grabRenderedPixels(sv, 3,
3732 sv->X->aWIDTH, sv->X->aHEIGHT, 0);
3733 if (pixels) {
3734 ISQ_snapsave (sv->X->aWIDTH, -sv->X->aHEIGHT,
3735 (unsigned char *)pixels, sv->X->GLXAREA );
3736 SUMA_free(pixels);
3737 }else {
3738 if (callmode && strcmp(callmode, "interactive") == 0) {
3739 SUMA_SLP_Err("Failed to record image.");
3740 } else { SUMA_S_Err("Failed to record image.");}
3741 }
3742 }
3743 }
3744 if (SUMAg_CF->SUMA_SnapshotOverSampling > 1) {
3745 /* Now return the window to its previous size */
3746 if (owindw > 0) {
3747 sv->wWindHeight = owindh;
3748 sv->X->aHEIGHT = oareah;
3749 sv->wWindWidth = owindw;
3750 sv->X->aWIDTH = oareaw;
3751 SUMA_WidgetResize (sv->X->TOPLEVEL , owindw, owindh);
3752 }
3753 sv->rdc = SUMA_RDC_X_RESIZE;
3754 glViewport( 0, 0,
3755 sv->X->aWIDTH, sv->X->aHEIGHT);
3756 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
3757 }
3758 if (SUMAg_CF->NoDuplicatesInRecorder) SNAP_NoDuplicates();
3759 else SNAP_OkDuplicates();
3760 if (SUMAg_CF->SUMA_SnapshotOverSampling > 1) {
3761 /* record the image to make life easy on user */
3762 sprintf(msg,"Writing resultant image\n"
3763 " to HighRes_Suma_tmp.ppm ...");
3764 if (callmode && strcmp(callmode, "interactive") == 0) {
3765 SUMA_SLP_Note ("%s",msg);
3766 } else { SUMA_S_Note ("%s",msg); }
3767 ISQ_snap_png_rng("HighRes_Photo___tmp",
3768 -(SUMAg_CF->SUMA_SnapshotOverSampling *
3769 SUMAg_CF->SUMA_SnapshotOverSampling),
3770 0);
3771 /* use explicit tcsh to avoid sh syntax 25 Apr 2017 [rickr] */
3772 system( "tcsh -c 'rm -f HighRes_Suma_tmp* >& /dev/null' ; "
3773 "2dcat -prefix HighRes_Suma_tmp HighRes_Photo___tmp* ; "
3774 "rm -f HighRes_Photo___tmp*");
3775 }
3776 }
3777 break;
3778 case XK_R:
3779 if (SUMA_CTRL_KEY(key)) {
3780 char sbuf[256];
3781 sv->Record = !sv->Record;
3782 if (sv->Record) sv->Record = 2;
3783 if (sv->Record) {
3784 SUMA_VALIDATE_RECORD_PATH(SUMAg_CF->autorecord);
3785 snprintf(sbuf,256*sizeof(char),
3786 "Disk Recording ON to: %s%s*",
3787 SUMAg_CF->autorecord->Path,
3788 SUMAg_CF->autorecord->FileName_NoExt);
3789 if (callmode && strcmp(callmode, "interactive") == 0) {
3790 SUMA_SLP_Note ("%s",sbuf); }
3791 else { SUMA_S_Note ("%s",sbuf); }
3792 } else {
3793 snprintf(sbuf,256*sizeof(char),
3794 "Disk Recording OFF. Results in: %s%s*",
3795 SUMAg_CF->autorecord->Path,
3796 SUMAg_CF->autorecord->FileName_NoExt);
3797 if (callmode && strcmp(callmode, "interactive") == 0) {
3798 SUMA_SLP_Note ("%s",sbuf); }
3799 else { SUMA_S_Note ("%s",sbuf);}
3800 }
3801 SUMA_UpdateViewerTitle(sv);
3802 } else {
3803 sv->Record = !sv->Record;
3804 if (sv->Record) {
3805 if (callmode && strcmp(callmode, "interactive") == 0) {
3806 SUMA_SLP_Note ("Recording ON"); }
3807 else { SUMA_S_Note ("Recording ON"); }
3808 } else {
3809 if (callmode && strcmp(callmode, "interactive") == 0) {
3810 SUMA_SLP_Note ("Recording OFF"); }
3811 else { SUMA_S_Note ("Recording OFF");}
3812 }
3813 SUMA_UpdateViewerTitle(sv);
3814 }
3815 break;
3816 default:
3817 SUMA_S_Err("Il ne faut pas etre ici");
3818 SUMA_RETURN(0);
3819 break;
3820 }
3821
3822 SUMA_RETURN(1);
3823 }
3824
SUMA_S_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)3825 int SUMA_S_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
3826 {
3827 static char FuncName[]={"SUMA_S_Key"};
3828 char tk[]={"S"}, keyname[100];
3829 int k, nc;
3830 SUMA_EngineData *ED = NULL;
3831 DList *list = NULL;
3832 DListElmt *NextElm= NULL;
3833 SUMA_Boolean LocalHead = NOPE;
3834
3835 SUMA_ENTRY;
3836
3837 SUMA_KEY_COMMON;
3838
3839 switch (k) {
3840 case XK_S:
3841 if (clippingPlaneMode){
3842 clipPlaneTransform(0, 0, -scrollInc, 0,-1, 0, 0); // Scroll outward
3843 } else if (SUMAg_CF->Dev) {
3844 int *do_id, n_do_id;
3845 do_id = SUMA_GetDO_Type(SUMAg_DOv, SUMAg_N_DOv,
3846 SO_type, &n_do_id);
3847 if (n_do_id) {
3848 while (n_do_id) {
3849 SUMA_Print_Surface_Object(
3850 (SUMA_SurfaceObject *)SUMAg_DOv[do_id[n_do_id-1]].OP,
3851 stdout);
3852 --n_do_id;
3853 }
3854 SUMA_free(do_id);
3855 }
3856 }
3857 break;
3858
3859 case XK_s:
3860 if (clippingPlaneMode){
3861 clipPlaneTransform(0, 0, scrollInc, 0,-1, 0, 0); // Scroll inward
3862 } else if ((SUMA_ALT_KEY(key)) && (SUMA_CTRL_KEY(key)) ){ // alt-ctrl-s
3863 if (!list) list = SUMA_CreateList();
3864 ED = SUMA_InitializeEngineListData (SE_LoadSegDO);
3865 if (!SUMA_RegisterEngineListCommand ( list, ED,
3866 SEF_ip, sv->X->TOPLEVEL,
3867 SES_Suma, (void *)sv, NOPE,
3868 SEI_Head, NULL)) {
3869 fprintf (SUMA_STDERR,
3870 "Error %s: Failed to register command.\n", FuncName);
3871 }
3872 if (!SUMA_Engine (&list)) {
3873 fprintf( SUMA_STDERR,
3874 "Error %s: SUMA_Engine call failed.\n",
3875 FuncName);
3876 }
3877
3878 } else if (SUMA_ALT_KEY(key)){
3879 /* swap buttons 1 and 3 */
3880 SUMAg_CF->SwapButtons_1_3 = !SUMAg_CF->SwapButtons_1_3;
3881 if (SUMAg_CF->SwapButtons_1_3) {
3882 fprintf (SUMA_STDOUT,
3883 "%s: Buttons 1 and 3 are swapped.\n", FuncName);
3884 } else {
3885 fprintf (SUMA_STDOUT,
3886 "%s: Default functions for buttons 1 and 3.\n",
3887 FuncName);
3888 }
3889 }
3890
3891 break;
3892 }
3893
3894 SUMA_RETURN(1);
3895 }
3896
SUMA_T_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)3897 int SUMA_T_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
3898 {
3899 static char FuncName[]={"SUMA_T_Key"};
3900 char tk[]={"T"}, keyname[100];
3901 int k, nc;
3902 SUMA_EngineData *ED = NULL;
3903 DList *list = NULL;
3904 DListElmt *NextElm= NULL;
3905 SUMA_Boolean LocalHead = NOPE;
3906
3907 SUMA_ENTRY;
3908
3909 // fprintf(stderr, "%s\n", FuncName);
3910
3911 SUMA_KEY_COMMON;
3912
3913 /* do the work */
3914 switch (k) {
3915 case XK_T:
3916 if (!list) list = SUMA_CreateList();
3917 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list,
3918 SE_StartListening, SES_Suma, sv);
3919
3920 if (!SUMA_Engine (&list)) {
3921 fprintf(SUMA_STDERR,
3922 "Error %s: SUMA_Engine call failed.\n", FuncName);
3923 }
3924 break;
3925 case XK_t:
3926 if ((SUMA_CTRL_KEY(key))){
3927 if (callmode && strcmp(callmode, "interactive") == 0) {
3928 SUMA_SLP_Note("Forcing a resend of Surfaces to Afni...");}
3929 else { SUMA_S_Note("Forcing a resend of Surfaces to Afni..."); }
3930 if (!list) list = SUMA_CreateList();
3931 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list,
3932 SE_SetForceAfniSurf, SES_Suma, sv);
3933
3934 if (!SUMA_Engine (&list)) {
3935 fprintf(SUMA_STDERR,
3936 "Error %s: SUMA_Engine call failed.\n", FuncName);
3937 }
3938 } else {
3939 if (!list) list = SUMA_CreateList();
3940 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list,
3941 SE_ToggleConnected, SES_Suma, sv);
3942
3943 if (!SUMA_Engine (&list)) {
3944 fprintf(SUMA_STDERR,
3945 "Error %s: SUMA_Engine call failed.\n", FuncName);
3946 }
3947 }
3948 break;
3949 default:
3950 SUMA_S_Err("Il ne faut pas ci dessous");
3951 SUMA_RETURN(0);
3952 break;
3953 }
3954
3955 SUMA_RETURN(1);
3956 }
3957
3958 /*!
3959 Execute commands when U or u is pressed
3960 */
SUMA_U_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)3961 int SUMA_U_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
3962 {
3963 static char FuncName[]={"SUMA_U_Key"};
3964 char tk[]={"U"}, keyname[100], msg[100];
3965 int k, nc, ii, jj, mm;
3966 SUMA_Boolean LocalHead = NOPE;
3967
3968 SUMA_ENTRY;
3969
3970 // fprintf(stderr, "%s\n", FuncName);
3971
3972 SUMA_KEY_COMMON;
3973
3974 /* do the work */
3975 switch (k) {
3976 case XK_u:
3977 if ((SUMA_APPLE_KEY(key) || SUMA_ALT_KEY(key))) {
3978 SUMA_LH("Nothing here");
3979 } else if (SUMA_CTRL_KEY(key)) {
3980 SUMA_viewSumaCont(1);
3981 } else {
3982 SUMA_LH("Keeping it real");
3983 }
3984 break;
3985 case XK_U:
3986 if (SUMA_CTRL_KEY(key)) {
3987
3988 } else {
3989
3990 }
3991 break;
3992 default:
3993 SUMA_S_Err("Il ne faut pas etre ici non plus");
3994 SUMA_RETURN(0);
3995 break;
3996 }
3997
3998 SUMA_RETURN(1);
3999 }
4000
4001
SUMA_free_Save_List_El(void * selu)4002 void SUMA_free_Save_List_El(void *selu) {
4003 SUMA_SAVE_LIST_EL *sel=(SUMA_SAVE_LIST_EL *)selu;
4004 if (sel) {
4005 if (sel->identifier) SUMA_free(sel->identifier);
4006 if (sel->prefix) SUMA_free(sel->prefix);
4007 if (sel->type) SUMA_free(sel->type);
4008 SUMA_free(sel);
4009 }
4010 return;
4011 }
4012
SUMA_Add_to_SaveList(DList ** SLp,char * type,char * identifier,char * prefix)4013 int SUMA_Add_to_SaveList(DList **SLp, char *type,
4014 char *identifier, char *prefix)
4015 {
4016 static char FuncName[]={"SUMA_Add_to_SaveList"};
4017 DList *SL=NULL;
4018 DListElmt *el= NULL;
4019 SUMA_SAVE_LIST_EL *sel=NULL;
4020 SUMA_Boolean LocalHead = NOPE;
4021
4022 SUMA_ENTRY;
4023
4024 // fprintf(stderr, "%s\n", FuncName);
4025
4026 if (!SLp || !type || !identifier || !prefix) SUMA_RETURN(0);
4027 SL = *SLp;
4028 if (!SL) {
4029 SL = (DList*)SUMA_malloc(sizeof(DList));
4030 dlist_init(SL, SUMA_free_Save_List_El);
4031 }
4032 SUMA_LH("Searching for possible identifier >%s<",
4033 identifier?identifier:"NULL");
4034 /* first make sure identifier is not there already */
4035 el = dlist_head(SL);
4036 while (el && identifier) {
4037 if ((sel = (SUMA_SAVE_LIST_EL *)el->data)) {
4038 if (sel->identifier &&
4039 !strcmp(sel->identifier, identifier)) {
4040 /* found, replace */
4041 SUMA_free(sel->identifier);
4042 sel->identifier = SUMA_copy_string(identifier);
4043 identifier = NULL;
4044 SUMA_free(sel->prefix);
4045 sel->prefix = SUMA_copy_string(prefix);
4046 prefix = NULL;
4047 SUMA_free(sel->type);
4048 sel->type = SUMA_copy_string(type);
4049 type = NULL;
4050 }
4051 }
4052 el = dlist_next(el);
4053 }
4054 if (identifier) { /* a new one, should add it */
4055 sel = (SUMA_SAVE_LIST_EL *)SUMA_calloc(1,sizeof(SUMA_SAVE_LIST_EL));
4056 sel->identifier = SUMA_copy_string(identifier);
4057 sel->prefix = SUMA_copy_string(prefix);
4058 sel->type = SUMA_copy_string(type);
4059 dlist_ins_next(SL, dlist_tail(SL), (void *)sel);
4060 }
4061
4062 if (LocalHead) {
4063 SUMA_Show_SaveList(SL, "SaveList now:\n");
4064 }
4065
4066 *SLp = SL;
4067 SUMA_RETURN(1);
4068 }
4069
SUMA_Show_SaveList(DList * SL,char * head)4070 void SUMA_Show_SaveList(DList *SL, char *head)
4071 {
4072 static char FuncName[]={"SUMA_Show_SaveList"};
4073 FILE *out=NULL;
4074 DListElmt *el= NULL;
4075 SUMA_SAVE_LIST_EL *sel=NULL;
4076 int cnt = 0;
4077
4078 SUMA_ENTRY;
4079
4080 // fprintf(stderr, "%s\n", FuncName);
4081
4082 if (!out) out = stderr;
4083 if (head) { fprintf(out, "%s", head); }
4084 if (!SL) { fprintf(out,"NULL SaveList\n"); SUMA_RETURNe; }
4085
4086 el = dlist_head(SL);
4087 cnt = 0;
4088 while (el) {
4089 if ((sel = (SUMA_SAVE_LIST_EL *)el->data)) {
4090 fprintf(out," %d: id>%s<, prefix>%s<, type>%s<\n",
4091 cnt, sel->identifier, sel->prefix, sel->type);
4092 } else {
4093 fprintf(out," %d: NULL sel\n", cnt);
4094 }
4095 el = dlist_next(el);
4096 fprintf(out,"\n");
4097 }
4098
4099 SUMA_RETURNe;
4100 }
4101
SUMA_SaveSaveListElement(SUMA_SAVE_LIST_EL * sel)4102 int SUMA_SaveSaveListElement(SUMA_SAVE_LIST_EL *sel)
4103 {
4104 static char FuncName[]={"SUMA_SaveSaveListElement"};
4105 SUMA_DSET *dset=NULL;
4106 char *oname=NULL, *idtype=NULL;
4107 int nid=0;
4108 SUMA_ENTRY;
4109
4110 // fprintf(stderr, "%s\n", FuncName);
4111
4112 if (!sel || !sel->identifier || !sel->prefix || !sel->type) SUMA_RETURN(0);
4113
4114 if (!strcmp(sel->type,"sdset")) {
4115 idtype="label:"; nid = strlen(idtype);
4116 if (!strncmp(idtype, sel->identifier, nid)) {
4117 if (!(dset = SUMA_FindDset2_s(sel->identifier+nid,
4118 SUMAg_CF->DsetList, "label"))) {
4119 SUMA_S_Errv("Failed to find dset labeled %s\n", sel->identifier+nid);
4120 SUMA_RETURN(0);
4121 }
4122 goto SAVEDSET;
4123 }
4124 idtype="filename:"; nid = strlen(idtype);
4125 if (!strncmp(idtype, sel->identifier, nid)) {
4126 if (!(dset = SUMA_FindDset2_s(sel->identifier+nid,
4127 SUMAg_CF->DsetList, "filename"))) {
4128 SUMA_S_Errv("Failed to find dset with filename %s\n",
4129 sel->identifier+nid);
4130 SUMA_RETURN(0);
4131 }
4132 goto SAVEDSET;
4133 }
4134 idtype="self_idcode:"; nid = strlen(idtype);
4135 if (!strncmp(idtype, sel->identifier, nid)) {
4136 if (!(dset = SUMA_FindDset2_s(sel->identifier+nid,
4137 SUMAg_CF->DsetList, "self_idcode"))) {
4138 SUMA_S_Errv("Failed to find dset with idcode %s\n",
4139 sel->identifier+nid);
4140 SUMA_RETURN(0);
4141 }
4142 goto SAVEDSET;
4143 }
4144 /* last hurrah */
4145 if (!(dset = SUMA_FindDset2_s(sel->identifier,
4146 SUMAg_CF->DsetList, NULL))) {
4147 SUMA_S_Errv("Failed to find dset with identifier %s\n",
4148 sel->identifier);
4149 SUMA_RETURN(0);
4150 }
4151 goto SAVEDSET;
4152
4153 SAVEDSET:
4154 if (!dset) SUMA_RETURN(0);
4155 oname = SUMA_WriteDset_PreserveID(sel->prefix, dset,
4156 SUMA_NO_DSET_FORMAT, 1,0);
4157 SUMA_S_Notev("Wrote: %s\n", oname);
4158 if (oname) SUMA_free(oname);
4159 } else {
4160 SUMA_S_Errv("Not setup for type %s yet\n", sel->type);
4161 SUMA_RETURN(0);
4162 }
4163 SUMA_RETURN(1);
4164 }
4165
SUMA_W_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)4166 int SUMA_W_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
4167 {
4168 static char FuncName[]={"SUMA_W_Key"};
4169 char tk[]={"W"}, keyname[100];
4170 int k, nc;
4171 SUMA_EngineData *ED = NULL;
4172 SUMA_SurfaceObject *SO;
4173 DList *list = NULL;
4174 DListElmt *el= NULL;
4175 char *lbls=NULL;
4176 SUMA_SAVE_LIST_EL *sel=NULL;
4177 SUMA_Boolean LocalHead = NOPE;
4178
4179 SUMA_ENTRY;
4180
4181 // fprintf(stderr, "%s\n", FuncName);
4182
4183 SUMA_KEY_COMMON;
4184
4185 /* do the work */
4186 switch (k) {
4187 case XK_W:
4188 if ((SUMA_CTRL_KEY(key))){
4189 if (!SUMAg_CF->SaveList || !dlist_size(SUMAg_CF->SaveList)) {
4190 SUMA_S_Note("Nothing in SaveList");
4191 SUMA_RETURN(1);
4192 }
4193 while((el = dlist_head(SUMAg_CF->SaveList))) {
4194 sel = (SUMA_SAVE_LIST_EL *)el->data;
4195 if (sel->identifier) {
4196 if (!(SUMA_SaveSaveListElement(sel))) {
4197 SUMA_S_Warnv("Failed to save %s %s\n",
4198 sel->identifier, sel->prefix)
4199 }
4200 }
4201 dlist_remove(SUMAg_CF->SaveList, el, (void *)(&sel));
4202 }
4203 } else {
4204 if ((SO=SUMA_SV_Focus_SO(sv))) {
4205 if (!list) list = SUMA_CreateList();
4206 ED = SUMA_InitializeEngineListData (SE_SaveSOFileSelection);
4207 if (!(el = SUMA_RegisterEngineListCommand ( list, ED,
4208 SEF_vp, (void *)SO,
4209 SES_Suma, (void *)sv, NOPE,
4210 SEI_Head, NULL))) {
4211 fprintf (SUMA_STDERR,
4212 "Error %s: Failed to register command.\n",
4213 FuncName);
4214 }
4215
4216 if (!SUMA_RegisterEngineListCommand ( list, ED,
4217 SEF_ip, sv->X->TOPLEVEL,
4218 SES_Suma, (void *)sv, NOPE,
4219 SEI_In, el)) {
4220 fprintf (SUMA_STDERR,
4221 "Error %s: Failed to register command.\n",
4222 FuncName);
4223 }
4224
4225 if (!SUMA_Engine (&list)) {
4226 fprintf( SUMA_STDERR,
4227 "Error %s: SUMA_Engine call failed.\n", FuncName);
4228 }
4229 }
4230 }
4231 break;
4232
4233 case XK_w:
4234 if (clippingPlaneMode){
4235 // Save clipping planes to file
4236 char stmp[PATH_MAX+512];
4237 char cwd[PATH_MAX], outputFileName[PATH_MAX+400];
4238 time_t t = time(NULL);
4239 struct tm tm = *localtime(&t);
4240 if (!(getcwd(cwd, sizeof(cwd)))) {
4241 perror("Error getting current working directory");
4242 SUMA_RETURN(0);
4243 }
4244 sprintf(outputFileName, "%s/clippingPlane%d%d%d-%d%d.niml.vvs",
4245 cwd, tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
4246 tm.tm_hour, tm.tm_min);
4247 sprintf(stmp, "%s", outputFileName);
4248 sv->X->SetRenderOrder_prmpt = NULL;
4249 sv->X->SetRenderOrder_prmpt = SUMA_CreatePromptDialogStruct(
4250 SUMA_OK_APPLY_CLEAR_CANCEL,
4251 "Please select output filename:\n"
4252 "(default is shown)):",
4253 stmp,
4254 sv->X->TOPLEVEL, YUP,
4255 SUMA_APPLY_BUTTON,
4256 writeClippingPlanes, (void *)sv,
4257 NULL, NULL,
4258 NULL, NULL,
4259 SUMA_VerifyRenderOrder, (void *)outputFileName,
4260 sv->X->SetRenderOrder_prmpt);
4261
4262 sv->X->SetRenderOrder_prmpt->VerifyFunction = NULL;
4263 sv->X->SetRenderOrder_prmpt = SUMA_CreatePromptDialog(
4264 sv->X->Title, sv->X->SetRenderOrder_prmpt);
4265
4266 sv->X->SetRenderOrder_prmpt = NULL;
4267 }
4268 break;
4269 default:
4270 SUMA_S_Err("Il ne faut pas ci dessous");
4271 SUMA_RETURN(0);
4272 break;
4273 }
4274
4275 SUMA_RETURN(1);
4276 }
4277
4278 /*!
4279 Execute commands when Z or z is pressed
4280 */
SUMA_Z_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)4281 int SUMA_Z_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
4282 {
4283 static char FuncName[]={"SUMA_Z_Key"};
4284 char tk[]={"Z"}, keyname[100], msg[100];
4285 int k, nc, ii, jj, mm;
4286 SUMA_Boolean LocalHead = NOPE;
4287
4288 SUMA_ENTRY;
4289
4290 // fprintf(stderr, "%s\n", FuncName);
4291
4292 SUMA_KEY_COMMON;
4293
4294 /* do the work */
4295 switch (k) {
4296 case XK_Z:
4297 sv->FOV[sv->iState] /= (1+sv->KeyZoomGain);
4298 if (sv->FOV[sv->iState] < FOV_MIN) {
4299 SUMA_BEEP; sv->FOV[sv->iState] = FOV_MIN;
4300 }
4301
4302 /* Now update the zoom compensation variable */
4303 if (sv->ZoomCompensate) {
4304 sv->ZoomCompensate = sv->FOV[sv->iState] / SUMA_sv_auto_fov(sv);
4305 if (sv->ZoomCompensate > 1) sv->ZoomCompensate = 1.0;
4306 /* weird stuff at zc_fac higher that 1.5 */
4307 else if (sv->ZoomCompensate < 0.005) sv->ZoomCompensate = 0.005;
4308 }
4309 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
4310 break;
4311
4312 case XK_z:
4313 sv->FOV[sv->iState] /= (1-sv->KeyZoomGain);
4314 if (sv->ortho) {
4315 if (sv->FOV[sv->iState] > FOV_MAX/2.0) {
4316 SUMA_BEEP; sv->FOV[sv->iState] = FOV_MAX/2.0; }
4317 } else {
4318 if (sv->FOV[sv->iState] > FOV_MAX) {
4319 SUMA_BEEP; sv->FOV[sv->iState] = FOV_MAX; }
4320 }
4321 /*fprintf(stderr,"Zoom out %f\n", sv->FOV[sv->iState]);*/
4322 /* Now update the zoom compensation variable */
4323 if (sv->ZoomCompensate) {
4324 sv->ZoomCompensate = sv->FOV[sv->iState] / SUMA_sv_auto_fov(sv);
4325 if (sv->ZoomCompensate > 1) sv->ZoomCompensate = 1.0;
4326 /* weird stuff at zc_fac higher that 1.5 */
4327 else if (sv->ZoomCompensate < 0.005) sv->ZoomCompensate = 0.005;
4328 /* weird stuff cause by integer spin variables!
4329 Proper way to handle all this is with float position
4330 storage and no recalculation of zc_fac except at zooming.*/
4331 }
4332 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
4333 break;
4334
4335 default:
4336 SUMA_S_Err("Il ne faut pas etre la");
4337 SUMA_RETURN(0);
4338 break;
4339 }
4340 SUMA_RETURN(1);
4341 }
4342
SUMA_Up_Key(SUMA_SurfaceViewer * sv,char * key,char * caller)4343 int SUMA_Up_Key(SUMA_SurfaceViewer *sv, char *key, char *caller)
4344 {
4345 static char FuncName[]={"SUMA_Up_Key"};
4346 char tk[]={"Up"}, keyname[100], skey[65], skeyi[65];
4347 int k, nc, ii, inode = -1;
4348 float ArrowDeltaRot = 0.05;
4349 /* The larger the value, the bigger the rotation increment */
4350 Widget w = NULL;
4351 double dd[3] = {0.0, -1.0, 0.0}; /* up */
4352 SUMA_SurfaceObject *SO=NULL;
4353 SUMA_Boolean LocalHead = NOPE;
4354
4355 SUMA_ENTRY;
4356
4357 // fprintf(stderr, "%s\n", FuncName);
4358
4359 SUMA_KEY_COMMON;
4360
4361 SUMA_KEY_SWITCH;
4362
4363 w = sv->X->GLXAREA;
4364 /* do the work */
4365 switch (k) {
4366 // PDL: Rotate clipping plane if available and ctrl key down
4367 case XK_Up:
4368 if (clippingPlaneMode && SUMA_ALT_KEY(key) && SUMAg_CF->N_ClipPlanes > 0){
4369 clipPlaneTransform(tiltInc, 0, 0, 0, -1, 0, 0);
4370 } else if ((SUMA_CTRL_KEY(key) && SUMA_SHIFT_KEY(key))) {
4371 float a[3];
4372 /* Posterior view ctrl+shift+up*/
4373 /* From top view, rotate by 90 degrees about x axis */
4374 a[0] = 1.0; a[1] = 0.0; a[2] = 0.0;
4375 axis_to_quat(a, SUMA_PI/2, sv->GVS[sv->StdView].currentQuat);
4376 SUMA_postRedisplay(w, NULL, NULL);
4377 }else if (SUMA_SHIFT_KEY(key)) {
4378 /*fprintf (SUMA_STDERR,"%s: Shift up\n", FuncName);*/
4379 sv->GVS[sv->StdView].translateVec[1] +=
4380 (GLfloat)sv->GVS[sv->StdView].ArrowtranslateDeltaY /
4381 (float)sv->X->aHEIGHT*sv->GVS[sv->StdView].TranslateGain;
4382 SUMA_postRedisplay(w, NULL, NULL);
4383 }else if (SUMA_CTRL_KEY(key)){
4384 /*fprintf (SUMA_STDERR,"%s: Control Up\n", FuncName);*/
4385 /* Top view ctrl+up*/
4386 float a[3];
4387 /* Default top view, rotate by nothing */
4388 a[0] = 1.0; a[1] = 0.0; a[2] = 0.0;
4389 axis_to_quat(a, 0, sv->GVS[sv->StdView].currentQuat);
4390 SUMA_postRedisplay(w, NULL, NULL);
4391 }else if (SUMA_AALT_KEY(key)) {
4392 SUMA_LH("alt down");
4393 if ((SO = SUMA_SV_Focus_SO(sv))) {
4394 if (SO->SelectedNode < 0 ||
4395 !SO->FN) SUMA_RETURN(1); /* nothing to do */
4396 inode = SO->SelectedNode;
4397 {
4398 inode =
4399 SUMA_NodeNeighborAlongScreenDirection(sv, SO, inode, dd);
4400 if (inode == -2) {
4401 SUMA_S_Err("Failed in"
4402 " SUMA_NodeNeighborAlongScreenDirection");
4403 SUMA_RETURN(0);
4404 } else if (inode == -1) {
4405 SUMA_LH("No good direction, get out");
4406 SUMA_BEEP;
4407 break;
4408 } else {
4409 SUMA_LHv("Next node should be %d\n", inode);
4410 }
4411 }
4412 /* Now set the new selected node */
4413 if (inode >= 0 && inode != SO->SelectedNode) {
4414 char stmp[64]; /* use Jump callback,
4415 the easy route */
4416 sprintf(stmp,"%d", inode);
4417 SUMA_JumpIndex (stmp, (void *)sv);
4418 }
4419 }
4420 } else {
4421 if (LocalHead)
4422 fprintf (SUMA_STDERR,"%s: Vanilla kind.\n", FuncName);
4423 trackball_Phi(sv->GVS[sv->StdView].deltaQuat,
4424 0.0, -ArrowDeltaRot, /* first point */
4425 0.0, ArrowDeltaRot, /* ending x,y */
4426 sv->ArrowRotationAngle);
4427 if (LocalHead) {
4428 fprintf(stdout,"\ncurrentQuat\n");
4429 for (ii=0; ii<4; ++ii) {
4430 fprintf( stdout,"%f\t",
4431 sv->GVS[sv->StdView].currentQuat[ii]);
4432 }
4433 fprintf(stdout,"\n");
4434 fprintf(stdout,"\ndeltaQuat\n");
4435 for (ii=0; ii<4; ++ii) {
4436 fprintf(stdout,"%f\t", sv->GVS[sv->StdView].deltaQuat[ii]);
4437 }
4438 fprintf(stdout,"\n");
4439 }
4440 add_quats ( sv->GVS[sv->StdView].deltaQuat,
4441 sv->GVS[sv->StdView].currentQuat,
4442 sv->GVS[sv->StdView].currentQuat);
4443 if (LocalHead) {
4444 fprintf(stdout,"\nnewQuat\n");
4445 for (ii=0; ii<4; ++ii) {
4446 fprintf( stdout,"%f\t",
4447 sv->GVS[sv->StdView].currentQuat[ii]);
4448 }
4449 fprintf(stdout,"\n");
4450 }
4451 sv->GVS[sv->StdView].spinDeltaX = 0;
4452 sv->GVS[sv->StdView].spinDeltaY =
4453 2.0*ArrowDeltaRot*sv->X->aHEIGHT;
4454 SUMA_postRedisplay(w, NULL, NULL);
4455 }
4456
4457 break;
4458
4459 break;
4460 default:
4461 SUMA_S_Err("Il ne faut pas etre ici");
4462 SUMA_RETURN(0);
4463 break;
4464 }
4465
4466 SUMA_RETURN(1);
4467 }
SUMA_Down_Key(SUMA_SurfaceViewer * sv,char * key,char * caller)4468 int SUMA_Down_Key(SUMA_SurfaceViewer *sv, char *key, char *caller)
4469 {
4470 static char FuncName[]={"SUMA_Down_Key"};
4471 char tk[]={"Down"}, keyname[100], skey[65], skeyi[65];
4472 int k, nc, ii, inode=-1;
4473 float ArrowDeltaRot = 0.05;
4474 /* The larger the value, the bigger the rotation increment */
4475 Widget w = NULL;
4476 double dd[3] = {0.0, 1.0, 0.0}; /* down */
4477 SUMA_SurfaceObject *SO=NULL;
4478 SUMA_Boolean LocalHead = NOPE;
4479
4480 SUMA_ENTRY;
4481
4482 // fprintf(stderr, "%s\n", FuncName);
4483
4484 SUMA_KEY_COMMON;
4485
4486 SUMA_KEY_SWITCH;
4487
4488 w = sv->X->GLXAREA;
4489 /* do the work */
4490 switch (k) {
4491 case XK_Down:
4492 // PDL: Rotate clipping plane if available and ctrl key down
4493 case XK_Up:
4494 if (clippingPlaneMode && SUMA_ALT_KEY(key) && SUMAg_CF->N_ClipPlanes > 0){
4495 clipPlaneTransform(-tiltInc, 0, 0, 0, -1, 0, 0);
4496 } else if ((SUMA_CTRL_KEY(key) && SUMA_SHIFT_KEY(key))) {
4497 float a[3], cQ[4], dQ[4];
4498 /* Posterior view ctrl+shift+down*/
4499 /* From top view, first rotate by 90 degrees about x axis */
4500 a[0] = 1.0; a[1] = 0.0; a[2] = 0.0;
4501 axis_to_quat(a, SUMA_PI/2, cQ);
4502 /* then rotate by 180 degrees about y axis */
4503 a[0] = 0.0; a[1] = 1.0; a[2] = 0.0;
4504 axis_to_quat(a, SUMA_PI, dQ);
4505 /*add rotation */
4506 add_quats (dQ, cQ, sv->GVS[sv->StdView].currentQuat);
4507 SUMA_postRedisplay(w, NULL, NULL);
4508 }else if (SUMA_SHIFT_KEY(key)) {
4509 /*fprintf (SUMA_STDERR,"%s: Shift down\n", FuncName);*/
4510 /*sv->GVS[sv->StdView].translateVec[0] += 0;*/
4511 sv->GVS[sv->StdView].translateVec[1] -=
4512 (GLfloat)sv->GVS[sv->StdView].ArrowtranslateDeltaY /
4513 (float)sv->X->aHEIGHT*sv->GVS[sv->StdView].TranslateGain;
4514 SUMA_postRedisplay(w, NULL, NULL);
4515 }else if (SUMA_CTRL_KEY(key)){
4516 /*fprintf (SUMA_STDERR,"%s: Control down\n", FuncName);*/
4517 /* Inferior view ctrl+down*/
4518 float a[3];
4519 /* From top view, rotate by 180 degrees about y axis */
4520 a[0] = 0.0; a[1] = 1.0; a[2] = 0.0;
4521 axis_to_quat(a, SUMA_PI, sv->GVS[sv->StdView].currentQuat);
4522 SUMA_postRedisplay(w, NULL, NULL);
4523 }else if (SUMA_AALT_KEY(key)) {
4524 SUMA_LH("alt down");
4525 if ((SO = SUMA_SV_Focus_SO(sv))) {
4526 if (SO->SelectedNode < 0 ||
4527 !SO->FN) SUMA_RETURN(1); /* nothing to do */
4528 inode = SO->SelectedNode;
4529 {
4530 inode =
4531 SUMA_NodeNeighborAlongScreenDirection(sv, SO, inode, dd);
4532 if (inode == -2) {
4533 SUMA_S_Err("Failed in"
4534 " SUMA_NodeNeighborAlongScreenDirection");
4535 SUMA_RETURN(0);
4536 } else if (inode == -1) {
4537 SUMA_LH("No good direction, get out");
4538 SUMA_BEEP;
4539 break;
4540 } else {
4541 SUMA_LHv("Next node should be %d\n", inode);
4542 }
4543 }
4544 /* Now set the new selected node */
4545 if (inode >= 0 && inode != SO->SelectedNode) {
4546 char stmp[64]; /* use Jump callback,
4547 the easy route */
4548 sprintf(stmp,"%d", inode);
4549 SUMA_JumpIndex (stmp, (void *)sv);
4550 }
4551 }
4552 }else {
4553 /*fprintf (SUMA_STDERR,"%s: Vanilla kind.\n", FuncName);*/
4554 trackball_Phi(sv->GVS[sv->StdView].deltaQuat,
4555 0.0, ArrowDeltaRot, /* first point */
4556 0.0, -ArrowDeltaRot, /* ending x,y */
4557 sv->ArrowRotationAngle);
4558 /*fprintf(stdout,"\ncurrentQuat\n");
4559 for (i=0; i<4; ++i) {
4560 fprintf(stdout,"%f\t", sv->GVS[sv->StdView].currentQuat[i]);}
4561 fprintf(stdout,"\n");
4562 fprintf(stdout,"\ndeltaQuat\n");for (i=0; i<4; ++i) {
4563 fprintf(stdout,"%f\t", sv->GVS[sv->StdView].deltaQuat[i]);}
4564 fprintf(stdout,"\n"); */
4565 add_quats (sv->GVS[sv->StdView].deltaQuat,
4566 sv->GVS[sv->StdView].currentQuat,
4567 sv->GVS[sv->StdView].currentQuat);
4568 /*fprintf(stdout,"\nnewQuat\n");
4569 for (i=0; i<4; ++i) {
4570 fprintf(stdout,"%f\t", sv->GVS[sv->StdView].currentQuat[i]);}
4571 fprintf(stdout,"\n");*/
4572 sv->GVS[sv->StdView].spinDeltaX = 0;
4573 sv->GVS[sv->StdView].spinDeltaY =
4574 -2.0*ArrowDeltaRot*sv->X->aHEIGHT;
4575 SUMA_postRedisplay(w, NULL, NULL);
4576 }
4577
4578 break;
4579
4580 break;
4581 default:
4582 SUMA_S_Err("Il ne faut pas etre ici");
4583 SUMA_RETURN(0);
4584 break;
4585 }
4586
4587
4588 SUMA_RETURN(1);
4589 }
SUMA_Left_Key(SUMA_SurfaceViewer * sv,char * key,char * caller)4590 int SUMA_Left_Key(SUMA_SurfaceViewer *sv, char *key, char *caller)
4591 {
4592 static char FuncName[]={"SUMA_Left_Key"};
4593 char tk[]={"Left"}, keyname[100], skey[65], skeyi[65];
4594 int k, nc, ii, jj, inode = -1, bkey = 0;
4595 float ArrowDeltaRot = 0.05;
4596 /* The larger the value, the bigger the rotation increment */
4597 Widget w = NULL;
4598 double dd[3] = {-1.0, 0.0, 0.0}; /* left */
4599 SUMA_SurfaceObject *SO=NULL;
4600 SUMA_Boolean LocalHead = NOPE;
4601
4602 SUMA_ENTRY;
4603
4604 // fprintf(stderr, "%s\n", FuncName);
4605
4606 SUMA_KEY_COMMON;
4607
4608 SUMA_KEY_SWITCH;
4609
4610 w = sv->X->GLXAREA;
4611 /* do the work */
4612 switch (k) {
4613 case XK_Left:
4614 // PDL: Rotate clipping plane if available and ctrl key down
4615 if (clippingPlaneMode && SUMA_ALT_KEY(key)){
4616 clipPlaneTransform(0, -tiltInc, 0, 0, -1, 0, 0);
4617 } else if ((SUMA_CTRL_KEY(key) && SUMA_SHIFT_KEY(key))) {
4618 float a[3], cQ[4];
4619 /* rotate about Z axis CCW */
4620 a[0] = 0.0; a[1] = 0.0; a[2] = 1.0;
4621 axis_to_quat(a, -sv->ArrowRotationAngle, cQ);
4622 /*add rotation */
4623 add_quats ( cQ,
4624 sv->GVS[sv->StdView].currentQuat,
4625 sv->GVS[sv->StdView].currentQuat);
4626 sv->GVS[sv->StdView].spinDeltaX = 0;
4627 sv->GVS[sv->StdView].spinDeltaY = 0;
4628 SUMA_postRedisplay(w, NULL, NULL);
4629 }else if (SUMA_SHIFT_KEY(key)) {
4630 /*fprintf (SUMA_STDERR,"%s: Shift down\n", FuncName);*/
4631 sv->GVS[sv->StdView].translateVec[0] -=
4632 (GLfloat)sv->GVS[sv->StdView].ArrowtranslateDeltaX /
4633 (float)sv->X->aWIDTH*sv->GVS[sv->StdView].TranslateGain;
4634 /*sv->GVS[sv->StdView].translateVec[1] -= 0;*/
4635 SUMA_postRedisplay(w, NULL, NULL);
4636 }else if (SUMA_CTRL_KEY(key)){
4637 float a[3], cQ[4], dQ[4];
4638 /* From top view, rotate about x 90 degrees.*/
4639 a[0] = 1.0; a[1] = 0.0; a[2] = 0.0;
4640 axis_to_quat(a, SUMA_PI/2.0, cQ);
4641 /* then rotate about y 90 degrees */
4642 a[0] = 0.0; a[1] = 1.0; a[2] = 0.0;
4643 axis_to_quat(a, SUMA_PI/2.0, dQ);
4644 /*add and apply rotation*/
4645 add_quats (dQ, cQ, sv->GVS[sv->StdView].currentQuat);
4646 SUMA_postRedisplay(w, NULL, NULL);
4647 }else if (SUMA_AALT_KEY(key)) {
4648 SUMA_LH("alt down");
4649 if ((SO = SUMA_SV_Focus_SO(sv))) {
4650 if (SO->SelectedNode < 0 ||
4651 !SO->FN) SUMA_RETURN(1); /* nothing to do */
4652 inode = SO->SelectedNode;
4653 {
4654 inode =
4655 SUMA_NodeNeighborAlongScreenDirection(sv, SO, inode, dd);
4656 if (inode == -2) {
4657 SUMA_S_Err("Failed in"
4658 " SUMA_NodeNeighborAlongScreenDirection");
4659 SUMA_RETURN(0);
4660 } else if (inode == -1) {
4661 SUMA_LH("No good direction, get out");
4662 SUMA_BEEP;
4663 break;
4664 } else {
4665 SUMA_LHv("Next node should be %d\n", inode);
4666 }
4667 }
4668 /* Now set the new selected node */
4669 if (inode >= 0 && inode != SO->SelectedNode) {
4670 char stmp[64]; /* use Jump callback,
4671 the easy route */
4672 sprintf(stmp,"%d", inode);
4673 SUMA_JumpIndex (stmp, (void *)sv);
4674 }
4675 }
4676 }else {
4677 /*fprintf (SUMA_STDERR,"%s: Vanilla kind.\n", FuncName);*/
4678 trackball_Phi(sv->GVS[sv->StdView].deltaQuat,
4679 ArrowDeltaRot, 0.0, /* first point */
4680 -ArrowDeltaRot, 0.0, /* ending x,y */
4681 sv->ArrowRotationAngle);
4682 add_quats ( sv->GVS[sv->StdView].deltaQuat,
4683 sv->GVS[sv->StdView].currentQuat,
4684 sv->GVS[sv->StdView].currentQuat);
4685 sv->GVS[sv->StdView].spinDeltaX =
4686 -2.0*ArrowDeltaRot*sv->X->aWIDTH;
4687 sv->GVS[sv->StdView].spinDeltaY = 0;
4688 SUMA_postRedisplay(w, NULL, NULL);
4689 }
4690
4691 break;
4692
4693 break;
4694 default:
4695 SUMA_S_Err("Il ne faut pas etre ici");
4696 SUMA_RETURN(0);
4697 break;
4698 }
4699
4700
4701 SUMA_RETURN(1);
4702 }
SUMA_Right_Key(SUMA_SurfaceViewer * sv,char * key,char * caller)4703 int SUMA_Right_Key(SUMA_SurfaceViewer *sv, char *key, char *caller)
4704 {
4705 static char FuncName[]={"SUMA_Right_Key"};
4706 char tk[]={"Right"}, keyname[100], skey[65], skeyi[65];
4707 int k, nc, ii, inode=-1;
4708 float ArrowDeltaRot = 0.05;
4709 /* The larger the value, the bigger the rotation increment */
4710 Widget w = NULL;
4711 double dd[3] = {1.0, 0.0, 0.0}; /* right */
4712 SUMA_SurfaceObject *SO=NULL;
4713 SUMA_Boolean LocalHead = NOPE;
4714
4715 SUMA_ENTRY;
4716
4717 // fprintf(stderr, "%s\n", FuncName);
4718
4719 SUMA_KEY_COMMON;
4720
4721 SUMA_KEY_SWITCH;
4722
4723 w = sv->X->GLXAREA;
4724 /* do the work */
4725 switch (k) {
4726 case XK_Right:
4727 // PDL: Rotate clipping plane if available and ctrl key down
4728 if (clippingPlaneMode && SUMA_ALT_KEY(key) && SUMAg_CF->N_ClipPlanes > 0){
4729 clipPlaneTransform(0, tiltInc, 0, 0, -1, 0, 0);
4730 } else if ((SUMA_CTRL_KEY(key) && SUMA_SHIFT_KEY(key))) {
4731 float a[3], cQ[4];
4732 /* rotate about Z axis CCW */
4733 a[0] = 0.0; a[1] = 0.0; a[2] = 1.0;
4734 axis_to_quat(a, sv->ArrowRotationAngle, cQ);
4735 /*add rotation */
4736 add_quats ( cQ,
4737 sv->GVS[sv->StdView].currentQuat,
4738 sv->GVS[sv->StdView].currentQuat);
4739 sv->GVS[sv->StdView].spinDeltaX = 0;
4740 sv->GVS[sv->StdView].spinDeltaY = 0;
4741 SUMA_postRedisplay(w, NULL, NULL);
4742 }else if (SUMA_SHIFT_KEY(key)) {
4743 /*fprintf (SUMA_STDERR,"%s: Shift down\n", FuncName);*/
4744 sv->GVS[sv->StdView].translateVec[0] +=
4745 (GLfloat)sv->GVS[sv->StdView].ArrowtranslateDeltaX /
4746 (float)sv->X->aWIDTH*sv->GVS[sv->StdView].TranslateGain;
4747 /*sv->GVS[sv->StdView].translateVec[1] -= 0;*/
4748 SUMA_postRedisplay(w, NULL, NULL);
4749 }else if (SUMA_CTRL_KEY(key)){
4750 float a[3], cQ[4], dQ[4];
4751 /* From top view, rotate about x 90 degrees */
4752 a[0] = 1.0; a[1] = 0.0; a[2] = 0.0;
4753 axis_to_quat(a, SUMA_PI/2.0, cQ);
4754 /* then rotate about y -90 degrees */
4755 a[0] = 0.0; a[1] = 1.0;
4756 axis_to_quat(a, -SUMA_PI/2.0, dQ);
4757 /*add and apply rotation*/
4758 add_quats (dQ, cQ, sv->GVS[sv->StdView].currentQuat);
4759 SUMA_postRedisplay(w, NULL, NULL);
4760 }else if (SUMA_AALT_KEY(key)) {
4761 SUMA_LH("alt down");
4762 if ((SO = SUMA_SV_Focus_SO(sv))) {
4763 if (SO->SelectedNode < 0 ||
4764 !SO->FN) SUMA_RETURN(1); /* nothing to do */
4765 inode = SO->SelectedNode;
4766 {
4767 inode =
4768 SUMA_NodeNeighborAlongScreenDirection(sv, SO, inode, dd);
4769 if (inode == -2) {
4770 SUMA_S_Err("Failed in"
4771 " SUMA_NodeNeighborAlongScreenDirection");
4772 SUMA_RETURN(0);
4773 } else if (inode == -1) {
4774 SUMA_LH("No good direction, get out");
4775 SUMA_BEEP;
4776 break;
4777 } else {
4778 SUMA_LHv("Next node should be %d\n", inode);
4779 }
4780 }
4781 /* Now set the new selected node */
4782 if (inode >= 0 && inode != SO->SelectedNode) {
4783 char stmp[64]; /* use Jump callback,
4784 the easy route */
4785 sprintf(stmp,"%d", inode);
4786 SUMA_JumpIndex (stmp, (void *)sv);
4787 }
4788 }
4789 }else {
4790 /*fprintf (SUMA_STDERR,"%s: Vanilla kind.\n", FuncName);*/
4791 trackball_Phi(sv->GVS[sv->StdView].deltaQuat,
4792 -ArrowDeltaRot, 0.0, /* first point */
4793 ArrowDeltaRot, 0.0, /* ending x,y */
4794 sv->ArrowRotationAngle);
4795 add_quats (sv->GVS[sv->StdView].deltaQuat,
4796 sv->GVS[sv->StdView].currentQuat,
4797 sv->GVS[sv->StdView].currentQuat);
4798 sv->GVS[sv->StdView].spinDeltaX = 2.0*ArrowDeltaRot*sv->X->aWIDTH;
4799 sv->GVS[sv->StdView].spinDeltaY = 0;
4800 SUMA_postRedisplay(w, NULL, NULL);
4801 }
4802
4803 break;
4804
4805 break;
4806 default:
4807 SUMA_S_Err("Il ne faut pas etre ici");
4808 SUMA_RETURN(0);
4809 break;
4810 }
4811
4812
4813 SUMA_RETURN(1);
4814 }
4815
SUMA_Butts2String(SUMA_EVENT * ev)4816 char *SUMA_Butts2String(SUMA_EVENT *ev)
4817 {
4818 static char ccs[10][32];
4819 static int icall=0;
4820 char *cc;
4821 int nb=0, mot;
4822
4823 ++icall; if (icall>9) icall=0;
4824 cc = (char *)ccs[icall]; cc[0]='\0';
4825
4826 if (ev->b1) {cc[nb++]='1'; cc[nb++]='&'; mot = 0;}
4827 if (ev->b2) {cc[nb++]='2'; cc[nb++]='&'; mot = 0;}
4828 if (ev->b3) {cc[nb++]='3'; cc[nb++]='&'; mot = 0;}
4829 if (ev->b4) {cc[nb++]='4'; cc[nb++]='&'; mot = 0;}
4830 if (ev->b5) {cc[nb++]='5'; cc[nb++]='&'; mot = 0;}
4831 if (ev->b6) {cc[nb++]='6'; cc[nb++]='&'; mot = 0;}
4832 if (ev->b7) {cc[nb++]='6'; cc[nb++]='&'; mot = 0;}
4833 if (ev->b1m) {cc[nb++]='1'; cc[nb++]='&'; mot = 1;}
4834 if (ev->b2m) {cc[nb++]='2'; cc[nb++]='&'; mot = 1;}
4835 if (ev->b3m) {cc[nb++]='3'; cc[nb++]='&'; mot = 1;}
4836 if (ev->b4m) {cc[nb++]='4'; cc[nb++]='&'; mot = 1;}
4837 if (ev->b5m) {cc[nb++]='5'; cc[nb++]='&'; mot = 1;}
4838
4839 if (nb>1) nb = nb-1; /* Get rid of last & */
4840 cc[nb] = '\0';
4841 return(cc);
4842 }
4843
SUMA_KeyType2String(int kt)4844 char *SUMA_KeyType2String(int kt)
4845 {
4846 switch(kt) {
4847 case KeyPress:
4848 return("key");
4849 case ButtonRelease:
4850 return("release");
4851 case ButtonPress:
4852 return("press");
4853 case MotionNotify:
4854 return("motion");
4855 default:
4856 return("UNKNOWN");
4857 }
4858 }
4859
SUMA_ShowEvent(SUMA_EVENT * ev,int opt,char * pre)4860 void SUMA_ShowEvent(SUMA_EVENT *ev, int opt, char *pre)
4861 {
4862 static char FuncName[]={"SUMA_ShowEvent"};
4863 static int icall=0;
4864 char *s = NULL;
4865 SUMA_STRING *SS = NULL;
4866 FILE *out = stderr;
4867
4868 SUMA_ENTRY;
4869
4870 // fprintf(stderr, "%s\n", FuncName);
4871
4872 SS = SUMA_StringAppend(NULL, NULL);
4873
4874 if (pre) SUMA_StringAppend(SS,pre);
4875 if (!ev) {
4876 SUMA_StringAppend(SS,"NULL ev\n"); goto OUT;
4877 }
4878 ++icall;
4879 if (!opt) {
4880 SUMA_StringAppend_va(SS,"Event Struct (set %d, callid %d)\n"
4881 " ktype %d kstate %d transl %s\n"
4882 " keysym %d mtype %d mstate %d\n"
4883 " bButton %d mButton %d\n"
4884 " bTime %ld mTime %ld\n"
4885 " mX %d mY %d bX %d bY %d\n"
4886 " mDelta %d, mDeltaX %d, mDeltaY %d\n"
4887 " shift %d control %d mod1 %d mod2 %d mod3 %d mod4 %d mod5 %d\n"
4888 " ApplAltOpt %d DoubleClick %d\n"
4889 " b1 %d b2 %d b3 %d b4 %d b5 %d b6 %d b7 %d\n"
4890 " b1m %d b2m %d b3m %d b4m %d b5m %d\n",
4891 ev->set, icall,
4892 ev->ktype, ev->kstate, ev->transl,
4893 ev->keysym, ev->mtype, ev->mstate,
4894 ev->bButton, ev->mButton,
4895 ev->bTime, ev->mTime,
4896 ev->mX, ev->mY, ev->bX, ev->bY,
4897 ev->mDelta, ev->mDeltaX, ev->mDeltaY,
4898 ev->Shift, ev->Control, ev->Mod1, ev->Mod2, ev->Mod3, ev->Mod4, ev->Mod5,
4899 ev->AppleAltOpt, ev->DoubleClick,
4900 ev->b1, ev->b2, ev->b3, ev->b4, ev->b5, ev->b6, ev->b7,
4901 ev->b1m, ev->b2m, ev->b3m, ev->b4m, ev->b5m);
4902 } else {
4903 /* More readable mode */
4904 SUMA_StringAppend_va(SS,"Input Event %d: %s \n",
4905 icall, ev->set ? "":"WARNING Event Struct Not Set!" );
4906 if (ev->ktype == KeyPress) {
4907 SUMA_StringAppend_va(SS,"%s: char>>%s<< sym>>%d<< ",
4908 SUMA_KeyType2String(ev->ktype),
4909 ev->transl, (int)ev->keysym);
4910 } else {
4911 SUMA_StringAppend_va(SS,"Mouse %s %s%s: ",
4912 SUMA_Butts2String(ev),
4913 SUMA_KeyType2String(ev->ktype),
4914 ev->DoubleClick ? " double click":"");
4915 if (ev->b1) SUMA_StringAppend_va(SS,"b1 ",ev->b1);
4916 if (ev->b2) SUMA_StringAppend_va(SS,"b2 ",ev->b2);
4917 if (ev->b3) SUMA_StringAppend_va(SS,"b3 ",ev->b3);
4918 if (ev->b4) SUMA_StringAppend_va(SS,"b4 ",ev->b4);
4919 if (ev->b5) SUMA_StringAppend_va(SS,"b5 ",ev->b5);
4920 if (ev->b6) SUMA_StringAppend_va(SS,"b6 ",ev->b6);
4921 if (ev->b7) SUMA_StringAppend_va(SS,"b7 ",ev->b7);
4922 if (ev->b1m) SUMA_StringAppend_va(SS,"m1 ",ev->b1m);
4923 if (ev->b2m) SUMA_StringAppend_va(SS,"m2 ",ev->b2m);
4924 if (ev->b3m) SUMA_StringAppend_va(SS,"m3 ",ev->b3m);
4925 if (ev->b4m) SUMA_StringAppend_va(SS,"m4 ",ev->b4m);
4926 if (ev->b5m) SUMA_StringAppend_va(SS,"m5 ",ev->b5m);
4927 }
4928 if (ev->Shift) {
4929 SUMA_StringAppend_va(SS,"Shift ");
4930 }
4931 if (ev->Control){
4932 SUMA_StringAppend_va(SS,"Control ");
4933 }
4934 if (ev->Mod1){
4935 SUMA_StringAppend_va(SS,"alt ");
4936 }
4937 if (ev->Mod2){
4938 SUMA_StringAppend_va(SS,"Mod2 (command on mac) ");
4939 }
4940 if (ev->Mod3){
4941 SUMA_StringAppend_va(SS,"Mod3 ");
4942 }
4943 if (ev->Mod4){
4944 SUMA_StringAppend_va(SS,"Mod4 ");
4945 }
4946 if (ev->Mod5){
4947 SUMA_StringAppend_va(SS,"Mod5 ");
4948 }
4949 if (ev->Mod2){
4950 SUMA_StringAppend_va(SS,"Mod2 ");
4951 }
4952 if (ev->AppleAltOpt){
4953 SUMA_StringAppend_va(SS,"Apple Alt/Opt ");
4954 }
4955 SUMA_StringAppend_va(SS,"k/mstate [%d/%d]\n\n", ev->kstate, ev->mstate);
4956 }
4957 OUT:
4958 SUMA_SS2S(SS,s);
4959
4960 fprintf(out,"%s",s);
4961
4962 SUMA_ifree(s);
4963
4964 SUMA_RETURNe;
4965 }
4966
4967 #ifdef DARWIN
4968 #define evALT ((ev->Mod1 || ev->Mod2 || ev->AppleAltOpt))
4969 #else
4970 #define evALT ((ev->Mod1))
4971 #endif
SUMA_ShftCont_Event(SUMA_EVENT * ev)4972 int SUMA_ShftCont_Event(SUMA_EVENT *ev)
4973 {
4974 if (!ev) ev = SUMAg_CF->lev;
4975 if (!ev || !ev->set) return(0);
4976 if (ev->Shift && ev->Control && !evALT) return(1);
4977 return(0);
4978 }
SUMA_Cont_Event(SUMA_EVENT * ev)4979 int SUMA_Cont_Event(SUMA_EVENT *ev)
4980 {
4981 if (!ev) ev = SUMAg_CF->lev;
4982 if (!ev || !ev->set) return(0);
4983 if (!ev->Shift && ev->Control && !evALT) return(1);
4984 return(0);
4985 }
SUMA_Shft_Event(SUMA_EVENT * ev)4986 int SUMA_Shft_Event(SUMA_EVENT *ev)
4987 {
4988 if (!ev) ev = SUMAg_CF->lev;
4989 if (!ev || !ev->set) return(0);
4990 if (ev->Shift && !ev->Control && !evALT) return(1);
4991 return(0);
4992 }
SUMA_ShftContAlt_Event(SUMA_EVENT * ev)4993 int SUMA_ShftContAlt_Event(SUMA_EVENT *ev)
4994 {
4995 if (!ev) ev = SUMAg_CF->lev;
4996 if (!ev || !ev->set) return(0);
4997 if (ev->Shift && ev->Control && evALT ) return(1);
4998 return(0);
4999 }
SUMA_ContAlt_Event(SUMA_EVENT * ev)5000 int SUMA_ContAlt_Event(SUMA_EVENT *ev)
5001 {
5002 if (!ev) ev = SUMAg_CF->lev;
5003 if (!ev || !ev->set) return(0);
5004 if (!ev->Shift && ev->Control && evALT ) return(1);
5005 return(0);
5006 }
SUMA_ShftAlt_Event(SUMA_EVENT * ev)5007 int SUMA_ShftAlt_Event(SUMA_EVENT *ev)
5008 {
5009 if (!ev) ev = SUMAg_CF->lev;
5010 if (!ev || !ev->set) return(0);
5011 if (ev->Shift && !ev->Control && evALT ) return(1);
5012 return(0);
5013 }
SUMA_Alt_Event(SUMA_EVENT * ev)5014 int SUMA_Alt_Event(SUMA_EVENT *ev)
5015 {
5016 if (!ev) ev = SUMAg_CF->lev;
5017 if (!ev || !ev->set) return(0);
5018 if (!ev->Shift && !ev->Control && evALT) return(1);
5019 return(0);
5020 }
SUMA_Plain_Event(SUMA_EVENT * ev)5021 int SUMA_Plain_Event(SUMA_EVENT *ev)
5022 {
5023 if (!ev) ev = SUMAg_CF->lev;
5024 if (!ev || !ev->set) return(0);
5025 if (!ev->Shift && !ev->Control && !evALT) return(1);
5026 return(0);
5027 }
5028
5029 /*! Get a record of events.
5030 Contents based on logic used in SUMA_input()
5031 Ideally, all should be done here and SUMA_input()
5032 should use the results of this call. But we're not
5033 there yet....
5034 Once I start using this one call, then the logic
5035 can be revisited at varied points in there.
5036 */
SUMA_RecordEvent(XEvent * event,SUMA_EVENT * ev)5037 SUMA_EVENT *SUMA_RecordEvent( XEvent *event,
5038 SUMA_EVENT *ev)
5039 {
5040 static char FuncName[]={"SUMA_RecordEvent"};
5041 XKeyEvent Kev;
5042 XButtonEvent Bev;
5043 XMotionEvent Mev;
5044 static SUMA_EVENT lev;
5045 SUMA_Boolean LocalHead = NOPE;
5046
5047 SUMA_ENTRY;
5048
5049 // fprintf(stderr, "%s\n", FuncName);
5050
5051 if (!event) {
5052 SUMA_S_Err("Null event");
5053 if (ev) memset(ev, 0, sizeof(SUMA_EVENT));
5054 SUMA_RETURN(ev);
5055 }
5056
5057 if (!ev) {
5058 if (!(ev = SUMAg_CF->lev)) {
5059 memset(&lev, 0, sizeof(SUMA_EVENT));
5060 SUMAg_CF->lev = (SUMA_EVENT *)SUMA_malloc(1*sizeof(SUMA_EVENT));
5061 }
5062 ev = SUMAg_CF->lev;
5063 }
5064 if (!ev) SUMA_RETURN(NULL);
5065 memset(ev, 0, sizeof(SUMA_EVENT));
5066
5067 Kev = *(XKeyEvent *) &event->xkey; /* RickR's suggestion to comply with
5068 ANSI C, no type casting of structures July 04*/
5069 Bev = *(XButtonEvent *) &event->xbutton;
5070 Mev = *(XMotionEvent *) &event->xmotion;
5071
5072 ev->set = 1;
5073 /* The copied parameters */
5074 ev->ktype = Kev.type;
5075 ev->kstate = Kev.state;
5076 ev->mtype = Mev.type;
5077 ev->mstate = Mev.state;
5078 ev->bTime = Bev.time;
5079 ev->mTime = Mev.time;
5080 ev->bButton = Bev.button;
5081 ev->mButton = 0; /* Not sure this one was all that necessary */
5082 ev->mX = Mev.x;
5083 ev->mY = Mev.y;
5084 ev->bX = Bev.x;
5085 ev->bY = Bev.y;
5086
5087 /* The inferred parameters */
5088 if ((Kev.state & ShiftMask) || (Bev.state & ShiftMask)) ev->Shift = 1;
5089 if ((Kev.state & ControlMask) || (Bev.state & ControlMask)) ev->Control = 1;
5090 if (Kev.state & Mod1Mask) ev->Mod1 = 1;
5091 if (Kev.state & Mod2Mask) ev->Mod2 = 1;
5092 if (Kev.state & Mod3Mask) ev->Mod3 = 1;
5093 if (Kev.state & Mod4Mask) ev->Mod4 = 1;
5094 if (Kev.state & Mod5Mask) ev->Mod5 = 1;
5095 if (Kev.state & SUMA_APPLE_AltOptMask) ev->AppleAltOpt = 1;
5096
5097 switch(ev->ktype) {
5098 case KeyPress:
5099 ev->transl[0] = ev->transl[15] = '\0';
5100 XLookupString( (XKeyEvent *)event, ev->transl, 14,
5101 &ev->keysym, NULL);
5102 break;
5103 break;
5104 case ButtonPress:
5105 if (Bev.state & Button1Mask) ev->b1 = 1;
5106 if (Bev.state & Button2Mask) ev->b2 = 1;
5107 if (Bev.state & Button3Mask) ev->b3 = 1;
5108 if (Bev.state & Button4Mask) ev->b4 = 1;
5109 if (Bev.state & Button5Mask) ev->b5 = 1;
5110 if (ev->bButton == 6) ev->b6 = 1; /* on macs Button6 not in X.h */
5111 if (ev->bButton == 7) ev->b7 = 1; /* on macs Button7 not in X.h */
5112
5113 switch (ev->bButton) {
5114 case Button1:
5115 case Button2:
5116 case Button3:
5117 case Button4:
5118 case Button5:
5119 case 6:
5120 case 7:
5121 default:
5122 SUMA_LH("ButtonPress %d not known", ev->bButton);
5123 break;
5124 }
5125
5126 /* trap for double click */
5127 if (Bev.time - lev.bTime < SUMA_DOUBLE_CLICK_MAX_DELAY) {
5128 ev->DoubleClick = YUP;
5129 } else {
5130 ev->DoubleClick = NOPE;
5131 }
5132
5133 if ( SUMAg_CF->SwapButtons_1_3 ||
5134 (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
5135 int kk=ev->b1;
5136 ev->b1 = ev->b3;
5137 ev->b3 = kk;
5138 }
5139
5140 break;
5141 case ButtonRelease:
5142 ev->mTime = 0;
5143 if (Bev.state & Button1Mask) ev->b1 = 1;
5144 if (Bev.state & Button2Mask) ev->b2 = 1;
5145 if (Bev.state & Button3Mask) ev->b3 = 1;
5146 if (Bev.state & Button4Mask) ev->b4 = 1;
5147 if (Bev.state & Button5Mask) ev->b5 = 1;
5148 if (ev->bButton == 6) ev->b6 = 1; /* on macs Button6 not in X.h */
5149 if (ev->bButton == 7) ev->b7 = 1; /* on macs Button7 not in X.h */
5150
5151 if (SUMAg_CF->SwapButtons_1_3 ||
5152 (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
5153 int kk=ev->b1;
5154 ev->b1 = ev->b3;
5155 ev->b3 = kk;
5156 }
5157 break;
5158
5159 case MotionNotify:
5160 if (Mev.state & Button1MotionMask) ev->b1m = 1;
5161 if (Mev.state & Button2MotionMask) ev->b2m = 1;
5162 if (Mev.state & Button3MotionMask) ev->b3m = 1;
5163 if (Mev.state & Button4MotionMask) ev->b4m = 1;
5164 if (Mev.state & Button5MotionMask) ev->b5m = 1;
5165 if (Mev.state) { SUMA_LH(" Something mot\n"); }
5166
5167 /* The conditions and new assignments of mButton
5168 below is stupid. But I won't touch it until I
5169 have to. Reassignments should be to b1m, b2m, etc.
5170 mButton should not be touched.
5171 Also, there should be no need for these numerous
5172 conditions. If swapping is needed, b1m and b3m
5173 values should be swaped. Things like SUMA_Button_12_Motion
5174 should be made into functions that return an answer
5175 based on ev's contents */
5176 if ( SUMAg_CF->SwapButtons_1_3 ||
5177 (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
5178 if (((Mev.state & Button3MotionMask) &&
5179 (Mev.state & Button2MotionMask))
5180 || ((Mev.state & Button2MotionMask) && (Mev.state & ShiftMask))) {
5181 int kk=ev->b1m;
5182 ev->b1m = ev->b3m;
5183 ev->b3m = kk;
5184 ev->mButton = SUMA_Button_12_Motion;
5185 } else if(Mev.state & Button3MotionMask) {
5186 ev->mButton = SUMA_Button_1_Motion;
5187 int kk=ev->b1m;
5188 ev->b1m = ev->b3m;
5189 ev->b3m = kk;
5190 }else if(Mev.state & Button2MotionMask) {
5191 ev->mButton = SUMA_Button_2_Motion;
5192 }else if(Mev.state & Button1MotionMask) {
5193
5194 ev->mButton = SUMA_Button_3_Motion;
5195 }else {
5196 break;
5197 }
5198 } else {
5199 if (((Mev.state & Button1MotionMask) &&
5200 (Mev.state & Button2MotionMask))
5201 || ((Mev.state & Button2MotionMask) && (Mev.state & ShiftMask))) {
5202 ev->mButton = SUMA_Button_12_Motion;
5203 } else if(Mev.state & Button1MotionMask) {
5204 ev->mButton = SUMA_Button_1_Motion;
5205 }else if(Mev.state & Button2MotionMask) {
5206 ev->mButton = SUMA_Button_2_Motion;
5207 } else if(Mev.state & Button3MotionMask) {
5208 ev->mButton = SUMA_Button_3_Motion;
5209 }else {
5210 break;
5211 }
5212 }
5213 switch (ev->mButton) {
5214 case SUMA_Button_12_Motion:
5215 case SUMA_Button_2_Shift_Motion:
5216 if (ev->mTime) {
5217 ev->mDelta = Mev.time - lev.mTime;
5218 ev->mDeltaX = Mev.x - lev.mX;
5219 ev->mDeltaY = Mev.y - lev.mY;
5220 } else {
5221 ev->mDelta = 0;
5222 ev->mDeltaX = 0;
5223 ev->mDeltaY = 0;
5224 }
5225 break;
5226 case SUMA_Button_2_Motion:
5227 break;
5228 case SUMA_Button_3_Motion:
5229 break;
5230 }
5231
5232 }
5233 if (LocalHead) {
5234 SUMA_ShowEvent(ev, 0, "EventRecord:\n");
5235 SUMA_ShowEvent(ev, 1, "EventRecord:\n");
5236 } else if (SUMAg_CF->Echo_KeyPress) {
5237 SUMA_ShowEvent(ev, 1, "EventRecord:\n");
5238 }
5239
5240 /* keep local copy of last event */
5241 memcpy(&lev, ev, sizeof(SUMA_EVENT));
5242
5243 SUMA_RETURN(ev);
5244 }
5245
5246 /*! Mouse and Keyboard input handler function for SUMA's viewer
5247 START shifting to SUMA_RecordEvent() and its helper functions
5248 like SUMA_Alt_Event(), etc.
5249 You should also split SUMA_input() into SUMA_input_Xevent()
5250 and SUMA_input_eng(). Where SUMA_input_Xevent() just sets
5251 SUMAg_CF->lev and SUMA_input_eng() works entirely off of
5252 SUMAg_CF->lev . This way you would be able to completely
5253 drive SUMA_input_eng() without any mouse movement/X structs
5254 etc. All you need is to manipulate the content of lev.
5255 */
SUMA_input(Widget w,XtPointer clientData,XtPointer callData)5256 void SUMA_input(Widget w, XtPointer clientData, XtPointer callData)
5257 {
5258 static char FuncName[]= {"SUMA_input"};
5259 GLwDrawingAreaCallbackStruct *cd;
5260 char buffer[10], cbuf = '\0', cbuf2='\0';
5261 KeySym keysym;
5262 int xls=-1, ntot, id = 0, ND, ip, NP;
5263 SUMA_EngineData *ED = NULL;
5264 char CommString[SUMA_MAX_COMMAND_LENGTH];
5265 char s[SUMA_MAX_STRING_LENGTH], sfield[100], sdestination[100];
5266 static char ssource[]={"suma"};
5267 char modifierBuf[32];
5268 int it, ii, iv3[3], hit = 0, SwasHit = 0;
5269 float **fm, fv3[3], fv15[15];
5270 XKeyEvent Kev;
5271 XButtonEvent Bev;
5272 XMotionEvent Mev;
5273 int isv;
5274 SUMA_SurfaceViewer *sv, *svi = NULL;
5275 GLfloat *glar_ColorList = NULL;
5276 static Time B1time = 0, M1time=0, M1delta=0;
5277 static int pButton, mButton, rButton;
5278 SUMA_Boolean ROI_mode;
5279 static SUMA_Boolean DoubleClick = NOPE;
5280 DListElmt *NextElm= NULL;
5281 float bevx, bevy, mevx, mevy, wwid, whei, zc_fac, mvx_fac, mvy_fac;
5282 static int mvxlast, mvylast, mvdeltax, mvdeltay;
5283 SUMA_PROMPT_DIALOG_STRUCT *prmpt=NULL; /* Use this only to create prompt
5284 that are not to be preserved */
5285 SUMA_Boolean LocalHead = NOPE; /* local debugging messages */
5286 int i, planeIndex;
5287 static int locallySelectedPlane = 0;
5288 SUMA_ENTRY;
5289 static DList *list = NULL;
5290
5291
5292 /* get the callData pointer */
5293 cd = (GLwDrawingAreaCallbackStruct *) callData;
5294
5295 /* find out who's calling, only GLXAREA calls this function */
5296 SUMA_GLXAREA_WIDGET2SV(w, sv, isv);
5297 if (isv < 0) {
5298 fprintf (SUMA_STDERR,
5299 "Error %s: Failed in macro SUMA_GLXAREA_WIDGET2SV.\n", FuncName);
5300 SUMA_RETURNe;
5301 }
5302 SUMA_LH("A call from SUMA_SurfaceViewer[%d], Pointer %p\n", isv, sv);
5303
5304 /* ******** ABOUT EVENT HANDLING ************** */
5305 /* Eventually you should use the structure
5306 created by RecordEvent to decide on what was clicked
5307 and how. While a little less efficient than
5308 what is done below, RecordEvent will eventually
5309 be considerably more flexible, and easier to debug.
5310 But for now, so that visible progress can be made,
5311 I will leave button processing and queries below
5312 as is, and try to make the switch gradually */
5313
5314 SUMAg_CF->lev = SUMA_RecordEvent( cd->event, SUMAg_CF->lev);
5315
5316 Kev = *(XKeyEvent *) &cd->event->xkey; /* RickR's suggestion to comply with
5317 ANSI C, no type casting of structures July 04*/
5318 Bev = *(XButtonEvent *) &cd->event->xbutton;
5319 Mev = *(XMotionEvent *) &cd->event->xmotion;
5320
5321 /* a sample keypresses */
5322 if (SUMAg_CF->Echo_KeyPress) {
5323 if (Kev.type == KeyPress) {
5324 buffer[0] = '\0';
5325 xls = XLookupString((XKeyEvent *) cd->event, buffer, 8, &keysym, NULL);
5326 fprintf (SUMA_STDERR,"%s KeyPress char>>%s<< sym>>%d<< ",
5327 FuncName, buffer, (int)keysym);
5328 } else {
5329 fprintf (SUMA_STDERR,"%s Mouse Action: ", FuncName);
5330 }
5331 if (Kev.state & ShiftMask) {
5332 fprintf (SUMA_STDERR,"Shift ");
5333 }
5334 if (Kev.state & ControlMask){
5335 fprintf (SUMA_STDERR,"Control ");
5336 }
5337 if (Kev.state & Mod1Mask){
5338 fprintf (SUMA_STDERR,"alt ");
5339 }
5340 if (Kev.state & Mod2Mask){
5341 fprintf (SUMA_STDERR,"Mod2 (command on mac) ");
5342 }
5343 if (Kev.state & Mod3Mask){
5344 fprintf (SUMA_STDERR,"Mod3 ");
5345 }
5346 if (Kev.state & Mod4Mask){
5347 fprintf (SUMA_STDERR,"Mod4 ");
5348 }
5349 if (Kev.state & Mod5Mask){
5350 fprintf (SUMA_STDERR,"Mod5 ");
5351 }
5352 if (Kev.state & SUMA_APPLE_AltOptMask){
5353 fprintf (SUMA_STDERR,"Apple Alt/Opt ");
5354 }
5355 fprintf (SUMA_STDERR,"State %d\n\n", Kev.state);
5356 }
5357
5358 switch (Kev.type) { /* switch event type */
5359 case KeyPress:
5360 {
5361 if (xls < 0) {
5362 /* avoid double call in case SUMAg_CF->Echo_KeyPress called already */
5363 xls = XLookupString((XKeyEvent *) cd->event, buffer, 8, &keysym, NULL);
5364 }
5365 // fprintf(stderr, "***** keysym = %ld\n", keysym);
5366
5367 // Modifier
5368 sprintf(modifierBuf, "\0");
5369 if (SUMA_ALTHELL) strcat(modifierBuf, "Alt+");
5370 if ((Kev.state & ControlMask)) strcat(modifierBuf, "Ctrl+");
5371
5372 /* XK_* are found in keysymdef.h */
5373 switch (keysym) { /* keysym */
5374 case XK_bracketleft: /* The left bracket */
5375 if (!SUMA_bracketleft_Key(sv, "[", "interactive")) {
5376 SUMA_S_Err("Failed in key func.");
5377 }
5378 break;
5379
5380 case XK_bracketright: /* The right bracket */
5381 if (!SUMA_bracketright_Key(sv, "]", "interactive")) {
5382 SUMA_S_Err("Failed in key func.");
5383 }
5384 break;
5385
5386 case XK_slash:
5387 if (Kev.state & ControlMask){
5388 if (!SUMA_slash_Key(sv, "Ctrl+/", "interactive")) {
5389 SUMA_S_Err("Failed in key func.");
5390 }
5391 } else {
5392 if (!SUMA_slash_Key(sv, "/", "interactive")) {
5393 SUMA_S_Err("Failed in key func.");
5394 }
5395 }
5396 break;
5397
5398 case XK_space: /* The spacebar. */
5399 if (!SUMA_space_Key(sv, "SPACE", "interactive")) {
5400 SUMA_S_Err("Failed in key func.");
5401 }
5402 break;
5403
5404 case XK_Escape:
5405 if (Kev.state & ShiftMask){
5406 if (!SUMA_escape_key(sv, "Shift+escape", "interactive",
5407 w, clientData, callData)) {
5408 SUMA_S_Err("Failed in key func.");
5409 }
5410 } else {
5411 if (!SUMA_escape_key(sv, "escape", "interactive",
5412 w, clientData, callData)) {
5413 SUMA_S_Err("Failed in key func.");
5414 }
5415 }
5416 break;
5417
5418 case XK_A:
5419 if (!SUMA_A_Key(sv, "Shift+A", "interactive")) {
5420 SUMA_S_Err("Failed in key func.");
5421 }
5422 break;
5423
5424 case XK_a:
5425 if (!SUMA_A_Key(sv, "a", "interactive")) {
5426 SUMA_S_Err("Failed in key func.");
5427 }
5428 break;
5429
5430 case XK_B:
5431 if (( Kev.state & ControlMask)){
5432 if (SUMAg_CF->Dev ) {
5433 if (!SUMA_B_Key(sv, "Shift+ctrl+B", "interactive")) {
5434 SUMA_S_Err("Failed in key func.");
5435 }
5436 }
5437 } else {
5438 if (!SUMA_B_Key(sv, "Shift+B", "interactive")) {
5439 SUMA_S_Err("Failed in key func.");
5440 }
5441 }
5442 break;
5443
5444 case XK_b:
5445 if (!SUMA_B_Key(sv, "b", "interactive")) {
5446 SUMA_S_Err("Failed in key func.");
5447 }
5448 break;
5449
5450 case XK_C:
5451 if ((SUMA_ALTHELL)){
5452 if ((Kev.state & ControlMask)){ // Ctrl-Shift-alt-C (clip plane box
5453 if (!SUMA_C_Key(sv, "Shift+Ctrl+Alt+C", "interactive")) {
5454 SUMA_S_Err("Failed in key func.");
5455 }
5456 }else {
5457 if (!SUMA_C_Key(sv, "Shift+Alt+C", "interactive")) {
5458 SUMA_S_Err("Failed in key func.");
5459 }
5460 }
5461 } else if ((Kev.state & ControlMask)){
5462 if (!SUMA_C_Key(sv, "Shift+Ctrl+C", "interactive")) {
5463 SUMA_S_Err("Failed in key func.");
5464 }
5465 } else {
5466 if (!SUMA_C_Key(sv, "Shift+C", "interactive")) {
5467 SUMA_S_Err("Failed in key func.");
5468 }
5469 }
5470 break;
5471
5472 case XK_c:
5473 if (!SUMA_C_Key(sv, "c", "interactive")) {
5474 SUMA_S_Err("Failed in key func.");
5475 }
5476 break;
5477
5478 case XK_D:
5479 if (1) {
5480 if (SUMA_ALTHELL){
5481 /* Mod1Mask is alt in linux, Mod2Mask is the apple on mac*/
5482 } else {
5483 if (!SUMA_D_Key(sv,"D", "interactive")) {
5484 SUMA_S_Err("Failed in key func.");
5485 }
5486 }
5487 }
5488 break;
5489
5490 case XK_d:
5491 if (SUMAg_CF->Dev) {
5492 if (SUMA_ALTHELL){
5493 /* Mod1Mask is alt in linux, Mod2Mask is the apple on mac*/
5494 } else {
5495 if (!SUMA_D_Key(sv,"d", "interactive")) {
5496 SUMA_S_Err("Failed in key func.");
5497 }
5498 }
5499 }
5500 break;
5501
5502 case XK_e:
5503 case XK_dead_acute: /* that is alt/option+e on macs
5504 XK_dead_acute is 0xfe51 or decimal 65105 */
5505 if (SUMAg_CF->Dev) {
5506 if (SUMA_ALTHELL){ /* Mod1Mask is alt in linux,
5507 Mod2Mask is the apple on mac*/
5508 SUMA_GL_ERRS;
5509 }
5510 }
5511 break;
5512
5513 case XK_F:
5514 if (!SUMA_F_Key(sv, "Shift+F", "interactive")) {
5515 SUMA_S_Err("Failed in key func.");
5516 }
5517 break;
5518
5519 case XK_f:
5520 if ((Kev.state & ControlMask)){
5521 if (!SUMA_F_Key(sv, "Ctrl+f", "interactive")) {
5522 SUMA_S_Err("Failed in key func.");
5523 }
5524 } else {
5525 if (!SUMA_F_Key(sv, "f", "interactive")) {
5526 SUMA_S_Err("Failed in key func.");
5527 }
5528 }
5529 break;
5530
5531 case XK_g:
5532 if (Kev.state & ControlMask){
5533 if (SUMAg_CF->Dev) {
5534 if (!SUMA_G_Key(sv, "ctrl+g", "interactive")) {
5535 SUMA_S_Err("Failed in key func.");
5536 }
5537 }
5538 } else {
5539 if (!SUMA_G_Key(sv, "g", "interactive")) {
5540 SUMA_S_Err("Failed in key func.");
5541 }
5542 }
5543 break;
5544
5545 case XK_H:
5546 if (!SUMA_H_Key(sv, "Shift+H", "interactive")) {
5547 SUMA_S_Err("Failed in key func.");
5548 }
5549 break;
5550
5551 case XK_h:
5552 if (Kev.state & ControlMask){
5553 if (!SUMA_H_Key(sv, "ctrl+h", "interactive")) {
5554 SUMA_S_Err("Failed in key func.");
5555 }
5556 } else {
5557 if (!SUMA_H_Key(sv, "h", "interactive")) {
5558 SUMA_S_Err("Failed in key func.");
5559 }
5560 }
5561 break;
5562
5563 case XK_j:
5564 if (Kev.state & ControlMask){
5565 if (!SUMA_J_Key(sv, "ctrl+j", "interactive", NULL)) {
5566 SUMA_S_Err("Failed in key func.");
5567 }
5568 } else if (SUMA_ALTHELL){
5569 if (!SUMA_J_Key(sv, "alt+j", "interactive", NULL)) {
5570 SUMA_S_Err("Failed in key func.");
5571 }
5572 } else {
5573 if (!SUMA_J_Key(sv, "j", "interactive", NULL)) {
5574 SUMA_S_Err("Failed in key func.");
5575 }
5576 }
5577 break;
5578
5579 case XK_J:
5580 if (!SUMA_J_Key(sv, "J", "interactive", NULL)) {
5581 SUMA_S_Err("Failed in key func.");
5582 }
5583 break;
5584
5585 case XK_l:
5586 if (Kev.state & ControlMask){
5587 if (!SUMA_L_Key(sv, "ctrl+l", "interactive", NULL)) {
5588 SUMA_S_Err("Failed in key func.");
5589 }
5590 } else if (SUMA_ALTHELL){
5591 if (!SUMA_L_Key(sv, "alt+l", "interactive", NULL)) {
5592 SUMA_S_Err("Failed in key func.");
5593 }
5594 } else {
5595 if (!SUMA_L_Key(sv, "l", "interactive", NULL)) {
5596 SUMA_S_Err("Failed in key func.");
5597 }
5598 }
5599 break;
5600
5601 case XK_L:
5602 if (Kev.state & ControlMask){
5603 if (!SUMA_L_Key(sv, "ctrl+L", "interactive", NULL)) {
5604 SUMA_S_Err("Failed in key func.");
5605 }
5606 } else if (SUMA_ALTHELL){
5607 if (!SUMA_L_Key(sv, "alt+L", "interactive", NULL)) {
5608 SUMA_S_Err("Failed in key func.");
5609 }
5610 } else {
5611 if (!SUMA_L_Key(sv, "L", "interactive", NULL)) {
5612 SUMA_S_Err("Failed in key func.");
5613 }
5614 }
5615 break;
5616
5617 case XK_M:
5618 if ((SUMA_ALTHELL) && (Kev.state & ControlMask) ){
5619 if (!SUMA_M_Key(sv, "alt+ctrl+M", "interactive")) {
5620 SUMA_S_Err("Failed in key func.");
5621 }
5622 }
5623 break;
5624
5625 case XK_m:
5626 if (Kev.state & ControlMask){
5627 if (SUMAg_CF->Dev) {
5628 if (!SUMA_M_Key(sv, "ctrl+m", "interactive")) {
5629 SUMA_S_Err("Failed in key func.");
5630 }
5631 }
5632 } else {
5633 if (!SUMA_M_Key(sv, "m", "interactive")) {
5634 SUMA_S_Err("Failed in key func.");
5635 }
5636 }
5637 break;
5638
5639 case XK_N:
5640 if (!SUMA_N_Key(sv, "Shift+N", "interactive")) {
5641 SUMA_S_Err("Failed in key func.");
5642 }
5643 break;
5644
5645 case XK_n:
5646 // if (clippingPlaneMode){
5647 if (Kev.state & ControlMask){
5648 SUMA_LH("Going to N_Key");
5649 if (!SUMA_N_Key(sv, "ctrl+n", "interactive")) {
5650 SUMA_S_Err("Failed in key func.");
5651 }
5652 }else {
5653 if (SUMAg_CF->Dev) {
5654 if (!SUMA_N_Key(sv, "n", "interactive")) {
5655 SUMA_S_Err("Failed in key func.");
5656 }
5657 }
5658 }
5659 break;
5660 case XK_o:
5661 if (SUMA_ALTHELL) {
5662 if (!SUMA_O_Key(sv, "alt+o", "interactive")) {
5663 SUMA_S_Err("Failed in key func.");
5664 }
5665 } else if (Kev.state & ControlMask){
5666 if (!SUMA_O_Key(sv, "ctrl+o", "interactive")) {
5667 SUMA_S_Err("Failed in key func.");
5668 }
5669 } else {
5670 if (!SUMA_O_Key(sv, "o", "interactive")) {
5671 SUMA_S_Err("Failed in key func.");
5672 }
5673 }
5674 break;
5675 case XK_O:
5676 if (SUMA_ALTHELL) {
5677 if (!SUMA_O_Key(sv, "alt+O", "interactive")) {
5678 SUMA_S_Err("Failed in key func.");
5679 }
5680 } else if (Kev.state & ControlMask){
5681 if (!SUMA_O_Key(sv, "ctrl+O", "interactive")) {
5682 SUMA_S_Err("Failed in key func.");
5683 }
5684 } else {
5685 if (!SUMA_O_Key(sv, "O", "interactive")) {
5686 SUMA_S_Err("Failed in key func.");
5687 }
5688 }
5689 break;
5690 case XK_p:
5691 if (Kev.state & ControlMask){
5692 if (!SUMA_P_Key(sv, "ctrl+p", "interactive")) {
5693 SUMA_S_Err("Failed in key func.");
5694 }
5695 } else {
5696 if (!SUMA_P_Key(sv, "p", "interactive")) {
5697 SUMA_S_Err("Failed in key func.");
5698 }
5699 }
5700 break;
5701
5702 case XK_P:
5703 if (!SUMA_P_Key(sv, "P", "interactive")) {
5704 SUMA_S_Err("Failed in key func.");
5705 }
5706 break;
5707
5708 case XK_r:
5709 if (SUMA_ALTHELL) {
5710 if (!SUMA_R_Key(sv, "alt+r", "interactive")) {
5711 SUMA_S_Err("Failed in key func.");
5712 }
5713 } else if (Kev.state & ControlMask){
5714 if (!SUMA_R_Key(sv, "ctrl+r", "interactive")) {
5715 SUMA_S_Err("Failed in key func.");
5716 }
5717 } else {
5718 if (!SUMA_R_Key(sv, "r", "interactive")) {
5719 SUMA_S_Err("Failed in key func.");
5720 }
5721 }
5722 break;
5723
5724 case XK_R:
5725 if (Kev.state & ControlMask){
5726 if (!SUMA_R_Key(sv, "ctrl+R", "interactive")) {
5727 SUMA_S_Err("Failed in key func.");
5728 }
5729 } else {
5730 if (!SUMA_R_Key(sv, "R", "interactive")) {
5731 SUMA_S_Err("Failed in key func.");
5732 }
5733 }
5734 break;
5735
5736 case XK_S:
5737 if (!SUMA_S_Key(sv, "Shift+S", "interactive")) {
5738 SUMA_S_Err("Failed in key func.");
5739 }
5740 break;
5741
5742 case XK_s:
5743 if ((SUMA_ALTHELL) && (Kev.state & ControlMask) ){
5744 if (!SUMA_S_Key(sv, "Alt+Ctrl+s", "interactive")) {
5745 SUMA_S_Err("Failed in key func.");
5746 }
5747 } else if (SUMA_ALTHELL){
5748 if (!SUMA_S_Key(sv, "Alt+s", "interactive")) {
5749 SUMA_S_Err("Failed in key func.");
5750 }
5751 } else if (!SUMA_S_Key(sv, "s", "interactive")) {
5752 SUMA_S_Err("Failed in key func.");
5753 }
5754 break;
5755
5756 case XK_t:
5757 if ((Kev.state & ControlMask)){
5758 if (!SUMA_T_Key(sv, "ctrl+t", "interactive")) {
5759 SUMA_S_Err("Failed in key func.");
5760 }
5761 } else {
5762 if (!SUMA_T_Key(sv, "t", "interactive")) {
5763 SUMA_S_Err("Failed in key func.");
5764 }
5765 }
5766 break;
5767
5768 case XK_T:
5769 if (!SUMA_T_Key(sv, "T", "interactive")) {
5770 SUMA_S_Err("Failed in key func.");
5771 }
5772 break;
5773
5774 case XK_u:
5775 if (!SUMA_U_Key(sv, "u", "interactive")) {
5776 SUMA_S_Err("Failed in key func.");
5777 }
5778 break;
5779 case XK_U:
5780 if (!SUMA_U_Key(sv, "U", "interactive")) {
5781 SUMA_S_Err("Failed in key func.");
5782 }
5783 break;
5784 case XK_v:
5785 #if 0
5786 /*** No longer in use, Jan 03 2004 */
5787 if (SUMAg_CF->Dev) {
5788 SUMA_Show_SurfaceViewer_Struct (sv, stdout, 0);
5789 }
5790 #endif
5791 break;
5792
5793 case XK_W:
5794 if ((Kev.state & ControlMask)){
5795 if (!SUMA_W_Key(sv, "Shift+ctrl+W", "interactive")) {
5796 SUMA_S_Err("Failed in key func.");
5797 }
5798 } else {
5799 if (!SUMA_W_Key(sv, "Shift+W", "interactive")) {
5800 SUMA_S_Err("Failed in key func.");
5801 }
5802 }
5803 break;
5804
5805 case XK_w:
5806 if (!SUMA_W_Key(sv, "w", "interactive")) {
5807 SUMA_S_Err("Failed in key func.");
5808 }
5809 break;
5810
5811 case XK_Z:
5812 if (!SUMA_Z_Key(sv, "Z", "interactive")) {
5813 SUMA_S_Err("Failed in key func.");
5814 }
5815 break;
5816
5817 case XK_z:
5818 if (!SUMA_Z_Key(sv, "z", "interactive")) {
5819 SUMA_S_Err("Failed in key func.");
5820 }
5821 break;
5822
5823 // ctrl-<number> keys, where number in [1,6] select the clipping plane by index
5824 case XK_1:
5825 strcat(modifierBuf, "1");
5826 if (!SUMA_Numeral_Key(sv, modifierBuf, "drivesuma")) {
5827 SUMA_S_Err("Failed in Key function.");
5828 }
5829 break;
5830 case XK_2:
5831 strcat(modifierBuf, "2");
5832 if (!SUMA_Numeral_Key(sv, modifierBuf, "drivesuma")) {
5833 SUMA_S_Err("Failed in Key function.");
5834 }
5835 break;
5836 case XK_3:
5837 strcat(modifierBuf, "3");
5838 if (!SUMA_Numeral_Key(sv, modifierBuf, "drivesuma")) {
5839 SUMA_S_Err("Failed in Key function.");
5840 }
5841 break;
5842 case XK_4:
5843 strcat(modifierBuf, "4");
5844 if (!SUMA_Numeral_Key(sv, modifierBuf, "drivesuma")) {
5845 SUMA_S_Err("Failed in Key function.");
5846 }
5847 break;
5848 case XK_5:
5849 strcat(modifierBuf, "5");
5850 if (!SUMA_Numeral_Key(sv, modifierBuf, "drivesuma")) {
5851 SUMA_S_Err("Failed in Key function.");
5852 }
5853 break;
5854 case XK_6:
5855 strcat(modifierBuf, "6");
5856 if (!SUMA_Numeral_Key(sv, modifierBuf, "drivesuma")) {
5857 SUMA_S_Err("Failed in Key function.");
5858 }
5859 break;
5860 case XK_7:
5861 strcat(modifierBuf, "7");
5862 if (!SUMA_Numeral_Key(sv, modifierBuf, "drivesuma")) {
5863 SUMA_S_Err("Failed in Key function.");
5864 }
5865 break;
5866 case XK_8:
5867 strcat(modifierBuf, "8");
5868 if (!SUMA_Numeral_Key(sv, modifierBuf, "drivesuma")) {
5869 SUMA_S_Err("Failed in Key function.");
5870 }
5871 break;
5872
5873 case XK_0: // Zero key
5874 strcat(modifierBuf, "0");
5875 if (!SUMA_Numeral_Key(sv, modifierBuf, "drivesuma")) {
5876 SUMA_S_Err("Failed in Key function.");
5877 }
5878 break;
5879
5880 case XK_asterisk:
5881 if (!SUMA_asterisk_Key(sv, "*", "drivesuma")) {
5882 SUMA_S_Err("Failed in Key function.");
5883 }
5884 break;
5885
5886 case XK_at:
5887 if (!SUMA_at_Key(sv, "@", "drivesuma")) {
5888 SUMA_S_Err("Failed in Key function.");
5889 }
5890 break;
5891
5892 case XK_parenleft:
5893 if (!SUMA_parenleft_Key(sv, "(", "drivesuma", w, clientData, callData)) {
5894 SUMA_S_Err("Failed in Key function.");
5895 }
5896 break;
5897
5898 case XK_comma:
5899 if (!SUMA_comma_Key(sv, "comma", "interactive")) {
5900 SUMA_S_Err("Failed in key func.");
5901 }
5902 break;
5903
5904 case XK_period:
5905 if (!SUMA_period_Key(sv, "period", "interactive")) {
5906 SUMA_S_Err("Failed in key func.");
5907 }
5908 break;
5909
5910 case XK_F1: /* F1 */
5911 /*printf("F1\n");*/
5912 if (!SUMA_F1_Key(sv, "F1", "interactive")) {
5913 SUMA_S_Err("Failed in key func.");
5914 }
5915 break;
5916
5917 case XK_F2:
5918 /*printf("F2\n");*/
5919 if (!SUMA_F2_Key(sv, "F2", "interactive")) {
5920 SUMA_S_Err("Failed in key func.");
5921 }
5922 break;
5923
5924 case XK_F3: /* F3 */
5925 if (!SUMA_F3_Key(sv, "F3", "interactive")) {
5926 SUMA_S_Err("Failed in key func.");
5927 }
5928 break;
5929
5930 case XK_F4: /* F4 */
5931 if (!SUMA_F4_Key(sv, "F4", "interactive")) {
5932 SUMA_S_Err("Failed in key func.");
5933 }
5934 break;
5935
5936 case XK_F5: /* F5 */
5937 if (!SUMA_F5_Key(sv, "F5", "interactive")) {
5938 SUMA_S_Err("Failed in key func.");
5939 }
5940 break;
5941
5942 case XK_F6: /*F6 */
5943 if (!SUMA_F6_Key(sv, "F6", "interactive")) {
5944 SUMA_S_Err("Failed in key func.");
5945 }
5946 break;
5947
5948 case XK_F7: /*F7 */
5949 if (!SUMA_F7_Key(sv, "F7", "interactive")) {
5950 SUMA_S_Err("Failed in key func.");
5951 }
5952 break;
5953
5954 case XK_F8: /*F8 */
5955 if (!SUMA_F8_Key(sv, "F8", "interactive")) {
5956 SUMA_S_Err("Failed in key func.");
5957 }
5958 break;
5959
5960 case XK_F9: /*F9 */
5961 if (!SUMA_F9_Key(sv, "F9", "interactive")) {
5962 SUMA_S_Err("Failed in key func.");
5963 }
5964 break;
5965
5966 case XK_F10: /*F10 */
5967 if (!SUMA_F10_Key(sv, "F10", "interactive", NULL)) {
5968 SUMA_S_Err("Failed in key func.");
5969 }
5970 break;
5971 case XK_F11: /* F11 */
5972 if (!SUMA_F11_Key(sv, "F11", "interactive", NULL)) {
5973 SUMA_S_Err("Failed in key func.");
5974 }
5975 break;
5976 case XK_F12: /* F12 */
5977 if (!SUMA_F12_Key(sv, "F12", "interactive")) {
5978 SUMA_S_Err("Failed in key func.");
5979 }
5980 break;
5981 case XK_F13:
5982 if (!SUMA_F13_Key(sv, "F12", "interactive")) {
5983 SUMA_S_Err("Failed in key func.");
5984 }
5985 break;
5986 case XK_Home:
5987 if (!SUMA_home_Key(sv, "home", "interactive")) {
5988 SUMA_S_Err("Failed in key func.");
5989 }
5990 break;
5991
5992 case XK_plus:
5993 if (!SUMA_plus_Key(sv, "+", "interactive")) {
5994 SUMA_S_Err("Failed in key func.");
5995 }
5996 break;
5997
5998 case XK_minus:
5999 if (!SUMA_minus_Key(sv, "-", "interactive")) {
6000 SUMA_S_Err("Failed in key func.");
6001 }
6002 break;
6003
6004 case XK_equal:
6005 if (!SUMA_equal_Key(sv, "=", "interactive")) {
6006 SUMA_S_Err("Failed in key func.");
6007 }
6008 break;
6009
6010 case XK_Left: /*KEY_LEFT:*/
6011 {
6012 if (clippingPlaneMode && SUMA_ALTHELL){
6013 if (!SUMA_Left_Key(sv, "Alt+left", "interactive")) {
6014 SUMA_S_Err("Error in key func.");
6015 break;
6016 }
6017 // clipPlaneTransform(0, -tiltInc, 0, 0, -1, 0, 0);
6018 } else if ((Kev.state & ControlMask) && (Kev.state & ShiftMask)) {
6019 if (!SUMA_Left_Key(sv, "ctrl+shift+left", "interactive")) {
6020 SUMA_S_Err("Error in key func.");
6021 break;
6022 }
6023 }else if (Kev.state & ShiftMask) {
6024 if (!SUMA_Left_Key(sv, "shift+left", "interactive")) {
6025 SUMA_S_Err("Error in key func.");
6026 break;
6027 }
6028 }else if (Kev.state & ControlMask){
6029 if (!SUMA_Left_Key(sv, "ctrl+left", "interactive")) {
6030 SUMA_S_Err("Error in key func.");
6031 break;
6032 }
6033 }else if (SUMA_ALTHELL) {
6034 if ((Kev.state & ControlMask)) {
6035 if (!SUMA_Left_Key(sv, "alt+ctrl+left", "interactive")) {
6036 SUMA_S_Err("Error in key func.");
6037 break;
6038 }
6039 } else if ((Kev.state & ShiftMask)) {
6040 if (!SUMA_Left_Key(sv, "alt+shift+left", "interactive")) {
6041 SUMA_S_Err("Error in key func.");
6042 break;
6043 }
6044 }
6045 else if (!SUMA_Left_Key(sv, "alt+left", "interactive")) {
6046 SUMA_S_Err("Error in key func.");
6047 break;
6048 }
6049 }else {
6050 if (!SUMA_Left_Key(sv, "left", "interactive")) {
6051 SUMA_S_Err("Error in key func.");
6052 break;
6053 }
6054 }
6055 }
6056 break;
6057
6058 case XK_Right: /*KEY_RIGHT: */
6059 if ((Kev.state & ControlMask) && (Kev.state & ShiftMask)) {
6060 if (!SUMA_Right_Key(sv, "ctrl+shift+right", "interactive")) {
6061 SUMA_S_Err("Error in key func.");
6062 break;
6063 }
6064 }else if (Kev.state & ShiftMask) {
6065 if (!SUMA_Right_Key(sv, "shift+right", "interactive")) {
6066 SUMA_S_Err("Error in key func.");
6067 break;
6068 }
6069 }else if (Kev.state & ControlMask){
6070 if (!SUMA_Right_Key(sv, "ctrl+right", "interactive")) {
6071 SUMA_S_Err("Error in key func.");
6072 break;
6073 }
6074 }else if (SUMA_ALTHELL) {
6075 if (!SUMA_Right_Key(sv, "alt+right", "interactive")) {
6076 SUMA_S_Err("Error in key func.");
6077 break;
6078 }
6079 }else {
6080 if (!SUMA_Right_Key(sv, "right", "interactive")) {
6081 SUMA_S_Err("Error in key func.");
6082 break;
6083 }
6084 }
6085 break;
6086
6087 case XK_Down: /*KEY_DOWN*/
6088 if ((Kev.state & ControlMask) && (Kev.state & ShiftMask)) {
6089 if (!SUMA_Down_Key(sv, "ctrl+shift+down", "interactive")) {
6090 SUMA_S_Err("Error in key func.");
6091 break;
6092 }
6093 }else if (Kev.state & ShiftMask) {
6094 if (!SUMA_Down_Key(sv, "shift+down", "interactive")) {
6095 SUMA_S_Err("Error in key func.");
6096 break;
6097 }
6098 }else if (Kev.state & ControlMask){
6099 if (!SUMA_Down_Key(sv, "ctrl+down", "interactive")) {
6100 SUMA_S_Err("Error in key func.");
6101 break;
6102 }
6103 }else if (SUMA_ALTHELL) {
6104 if (!SUMA_Down_Key(sv, "alt+down", "interactive")) {
6105 SUMA_S_Err("Error in key func.");
6106 break;
6107 }
6108 }else {
6109 if (!SUMA_Down_Key(sv, "down", "interactive")) {
6110 SUMA_S_Err("Error in key func.");
6111 break;
6112 }
6113 }
6114
6115 break;
6116
6117 case XK_Up: /*KEY_UP*/
6118 if ((Kev.state & ControlMask) && (Kev.state & ShiftMask)) {
6119 if (!SUMA_Up_Key(sv, "ctrl+shift+up", "interactive")) {
6120 SUMA_S_Err("Error in key func.");
6121 break;
6122 }
6123 }else if (Kev.state & ShiftMask) {
6124 if (!SUMA_Up_Key(sv, "shift+up", "interactive")) {
6125 SUMA_S_Err("Error in key func.");
6126 break;
6127 }
6128 }else if (Kev.state & ControlMask){
6129 if (!SUMA_Up_Key(sv, "ctrl+up", "interactive")) {
6130 SUMA_S_Err("Error in key func.");
6131 break;
6132 }
6133 }else if (SUMA_ALTHELL) {
6134 if (!SUMA_Up_Key(sv, "alt+up", "interactive")) {
6135 SUMA_S_Err("Error in key func.");
6136 break;
6137 }
6138 }else {
6139 if (!SUMA_Up_Key(sv, "up", "interactive")) {
6140 SUMA_S_Err("Error in key func.");
6141 break;
6142 }
6143 }
6144 break;
6145 default:
6146 break;
6147
6148 } /* keysym */
6149 } // KeyPress
6150 break;
6151 case KeyRelease:
6152 {
6153 switch (keysym) { /* keysym */
6154 case XK_Control_L:
6155 case XK_Control_R:
6156 break;
6157 } // keysym
6158 }
6159 break;
6160
6161 case ButtonPress:
6162 SUMAg_CF->X->ButtonDown=1;
6163 pButton = Bev.button; // PDL: Has value 4 if scrollwheel scrolled forward and value 5 if scrollwheel scrolled back
6164 SUMA_LHv("In ButtonPress Button %d, %d @ x,y=%d,%d\n",
6165 pButton, SUMAg_CF->X->ButtonDown, Bev.x, Bev.y);
6166 if ( SUMAg_CF->SwapButtons_1_3 ||
6167 (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
6168 if (pButton == Button1) pButton = Button3;
6169 else if (pButton == Button3) pButton = Button1;
6170 }
6171 if (SUMAg_CF->Echo_KeyPress) {
6172 fprintf (SUMA_STDERR,"Button Press: %d (%d,%d,%d,%d,%d)\n"
6173 , pButton, Button1, Button2, Button3, Button4,
6174 Button5);
6175 }
6176
6177 /* trap for double click */
6178 if (Bev.time - B1time < SUMA_DOUBLE_CLICK_MAX_DELAY) {
6179 if (LocalHead) fprintf(SUMA_STDERR, "%s: Double click.\n", FuncName);
6180 DoubleClick = YUP;
6181 } else {
6182 DoubleClick = NOPE;
6183 }
6184
6185
6186 if (strstr(sv->State, "GMATRIX")==sv->State) {
6187 /* For graph in matrix representation swap buttons 1 and 2 */
6188 switch (pButton) {
6189 case Button1:
6190 pButton = Button2;
6191 break;
6192 case Button2:
6193 pButton = Button1;
6194 break;
6195 }
6196 }
6197
6198
6199 B1time = Bev.time;
6200 M1time = 0;
6201 switch (pButton) { /* switch type of button Press */
6202 case Button1:
6203 if (Bev.state & Button2Mask) {
6204 /* setup initial zooming conditions */
6205 /*fprintf(SUMA_STDERR,"%s: Button 1 &2 down. New\n", FuncName); */
6206 sv->GVS[sv->StdView].zoomBegin = (float)Bev.y;
6207 sv->GVS[sv->StdView].zoomDelta = 0;
6208 }else {
6209 bevx=(float)Bev.x; bevy = (float)Bev.y;
6210 /*fprintf(SUMA_STDERR,"%s: Button 1 down. New\n", FuncName);*/
6211 /* setup initial spinning conditions */
6212 sv->GVS[sv->StdView].spinBeginX = bevx;
6213 sv->GVS[sv->StdView].spinBeginY = bevy;
6214 sv->GVS[sv->StdView].spinDeltaX = 0;
6215 sv->GVS[sv->StdView].spinDeltaY = 0;
6216 /* check to see if other viewers need to be notified */
6217 ii = SUMA_WhichSV(sv, SUMAg_SVv, SUMAg_N_SVv);
6218 if (SUMAg_CF->ViewLocked[ii]) {
6219 for (it=0; it < SUMAg_N_SVv; ++it) {
6220 svi = &SUMAg_SVv[it];
6221 if (it != ii && SUMAg_CF->ViewLocked[it]) {
6222 svi->GVS[svi->StdView].spinBeginX = bevx;
6223 svi->GVS[svi->StdView].spinBeginY = bevy;
6224 svi->GVS[svi->StdView].spinDeltaX = 0;
6225 svi->GVS[svi->StdView].spinDeltaY = 0;
6226 }
6227 }
6228 }
6229 if (DoubleClick) {
6230 if (Kev.state & ControlMask) SUMA_ResetPrying(sv);
6231 else {
6232 SUMA_HOME_QUAT(sv->StdView,
6233 sv->GVS[sv->StdView].currentQuat);
6234 SUMA_postRedisplay(w, NULL, NULL);
6235 }
6236 }
6237 }
6238 break;
6239 case Button4:
6240 case 6: /* This is shift and wheel on mac, Button6 is not in X.h ! */
6241 // PDL: Ctrl-scroll forward
6242 if (clippingPlaneMode && pButton==4 && SUMA_ALTHELL && SUMAg_CF->N_ClipPlanes > 0){
6243 clipPlaneTransform(0, 0, -scrollInc, 0,-1, 0, 0);
6244 } else {
6245
6246 if (pButton==6 || Bev.state & ShiftMask) {
6247 SUMA_ALL_DO *ado=NULL;
6248 char variant[2];
6249 #if 0
6250 int ii;
6251 SUMA_VolumeObject *VO=NULL;
6252 for (ii=0; ii<SUMAg_N_DOv; ++ii) {
6253 if (SUMA_isVO(SUMAg_DOv[ii])) {
6254 VO = (SUMA_VolumeObject *)(SUMAg_DOv[ii].OP);
6255 if (VO->SelectedCutPlane >= 0) {
6256 SUMA_LHv("Moving cut plane %d\n",
6257 VO->SelectedCutPlane);
6258 if (!SUMA_MoveCutplane(VO, VO->SelectedCutPlane, 1.0)) {
6259 SUMA_SLP_Err("Bad");
6260 }
6261 }
6262 /* JB: only allow cutplane from 1st volume object,
6263 otherwise remove 'break' */
6264 break;
6265 }
6266 }
6267 SUMA_postRedisplay(w, NULL, NULL);
6268 #else
6269 if ((ado = SUMA_SV_Focus_ADO(sv))) {
6270 switch (ado->do_type) {
6271 case VO_type: {
6272 float incr = 1.0;
6273 SUMA_VolumeObject *vo=(SUMA_VolumeObject *)ado;
6274 SUMA_VOL_SAUX *VSaux = SUMA_ADO_VSaux(ado);
6275 if (VSaux && VSaux->PR) {
6276 if (SUMA_dset_gui_slice_from_tex_slice_d(vo->VE, 0,
6277 VSaux->PR->dAltSel+SUMA_VOL_SLC_EQ0,
6278 0, variant, NULL) >=0 ){
6279 SUMA_set_slice(ado, variant, &incr,
6280 "increment", 0);
6281 }
6282 }
6283 SUMA_postRedisplay(w, NULL, NULL);
6284 break; }
6285 default:
6286 SUMA_LH("Nothing here for types %s\n",
6287 ADO_TNAME(ado));
6288 break;
6289 }
6290 }
6291 #endif
6292 } else if (pButton==6 || Bev.state & ControlMask) {
6293 SUMA_ALL_DO *ado=NULL;
6294 SUMA_X_SurfCont *SurfCont;
6295 if (MASK_MANIP_MODE(sv)) {
6296 ado = SUMA_whichADOg(sv->MouseMode_ado_idcode_str);
6297 if (ado && ado->do_type == MASK_type) {
6298 SUMA_MaskDO *mdo = (SUMA_MaskDO *)ado;
6299 float fv[3];
6300 int irow=-1;
6301 {
6302 fv[0] = mdo->hdim[0]-(0.2*mdo->init_hdim[0]);
6303 fv[1] = mdo->hdim[1]-(0.2*mdo->init_hdim[1]);
6304 fv[2] = mdo->hdim[2]-(0.2*mdo->init_hdim[2]);
6305 if (fv[0] < 0 || fv[1] < 0 || fv[2] < 0) {
6306 SUMA_BEEP;
6307 break;
6308 }
6309 SUMA_MDO_New_Dim(mdo, fv);
6310 }
6311 if ((SurfCont=SUMA_ADO_Cont(ado))) {
6312 irow = SUMA_ObjectID_Row(SurfCont->MaskTable,
6313 ADO_ID(ado));
6314 if (irow >= 0) {
6315 SUMA_InitMasksTable_row(SurfCont,mdo, irow);
6316 }
6317 }
6318 SUMA_NEW_MASKSTATE();
6319 /* enough for now */
6320 goto REDISP;
6321 }
6322 } else if ((ado = SUMA_SV_Focus_ADO(sv)) &&
6323 ado->do_type == GRAPH_LINK_type &&
6324 !strcmp(SUMA_ADO_variant(ado),"GMATRIX")) {
6325 SUMA_OVERLAYS *Sover = NULL;
6326 SUMA_LH("Going forward one sub-brick");
6327 Sover = SUMA_ADO_CurColPlane(ado);
6328 SUMA_SwitchColPlaneIntensity( ado, Sover,
6329 SUMA_FORWARD_ONE_SUBBRICK, 1);
6330 /* redisplay done in function above ... */
6331 SUMA_RETURNe;
6332 }
6333 } else {
6334 if (!SUMA_Z_Key(sv, "z", "interactive")) {
6335 SUMA_S_Err("Failed in key func.");
6336 }
6337 }
6338 }
6339 break;
6340 case Button5:
6341 case 7: /* This is shift and wheel on mac, Button7 is not in X.h ! */
6342 // PDL: Ctrl-scroll backward
6343 if (clippingPlaneMode && pButton==5 && SUMA_ALTHELL && SUMAg_CF->N_ClipPlanes > 0){
6344 clipPlaneTransform(0, 0, scrollInc, 0,-1, 0, 0);
6345 } else {
6346
6347 if (pButton==7 || Bev.state & ShiftMask) {
6348 SUMA_ALL_DO *ado=NULL;
6349 char variant[2];
6350 #if 0
6351 int ii;
6352 SUMA_VolumeObject *VO=NULL;
6353 for (ii=0; ii<SUMAg_N_DOv; ++ii) {
6354 if (SUMA_isVO(SUMAg_DOv[ii])) {
6355 VO = (SUMA_VolumeObject *)(SUMAg_DOv[ii].OP);
6356 if (VO->SelectedCutPlane >= 0) {
6357 SUMA_LHv("Moving cut plane %d\n",
6358 VO->SelectedCutPlane);
6359 if (!SUMA_MoveCutplane(VO, VO->SelectedCutPlane, -1.0)) {
6360 SUMA_SLP_Err("Bad");
6361 }
6362 }
6363 /* JB: only allow cutplane from 1st volume object,
6364 otherwise remove 'break' */
6365 break;
6366 }
6367 }
6368 SUMA_postRedisplay(w, NULL, NULL);
6369 #else
6370 if ((ado = SUMA_SV_Focus_ADO(sv))) {
6371 switch (ado->do_type) {
6372 case VO_type: {
6373 float incr = -1.0;
6374 SUMA_VolumeObject *vo=(SUMA_VolumeObject *)ado;
6375 SUMA_VOL_SAUX *VSaux = SUMA_ADO_VSaux(ado);
6376 if (VSaux && VSaux->PR) {
6377 if (SUMA_dset_gui_slice_from_tex_slice_d(vo->VE, 0,
6378 VSaux->PR->dAltSel+SUMA_VOL_SLC_EQ0,
6379 0, variant, NULL) >=0 ){
6380 SUMA_set_slice(ado, variant, &incr,
6381 "increment", 0);
6382 }
6383 }
6384 SUMA_postRedisplay(w, NULL, NULL);
6385 break; }
6386 default:
6387 SUMA_LH("Nothing here for types %s\n",
6388 ADO_TNAME(ado));
6389 break;
6390 }
6391 }
6392 #endif
6393 } else if (pButton==7 || Bev.state & ControlMask) {
6394 SUMA_ALL_DO *ado=NULL;
6395 SUMA_X_SurfCont *SurfCont;
6396 if (MASK_MANIP_MODE(sv)) {
6397 ado = SUMA_whichADOg(sv->MouseMode_ado_idcode_str);
6398 if (ado && ado->do_type == MASK_type) {
6399 SUMA_MaskDO *mdo = (SUMA_MaskDO *)ado;
6400 float fv[3];
6401 int irow=-1;
6402 {
6403 fv[0] = mdo->hdim[0]+(0.2*mdo->init_hdim[0]);
6404 fv[1] = mdo->hdim[1]+(0.2*mdo->init_hdim[1]);
6405 fv[2] = mdo->hdim[2]+(0.2*mdo->init_hdim[2]);
6406 SUMA_MDO_New_Dim(mdo, fv);
6407 }
6408 if ((SurfCont=SUMA_ADO_Cont(ado))) {
6409 irow = SUMA_ObjectID_Row(SurfCont->MaskTable,
6410 ADO_ID(ado));
6411 if (irow >= 0) {
6412 SUMA_InitMasksTable_row(SurfCont,mdo, irow);
6413 }
6414 }
6415 SUMA_NEW_MASKSTATE();
6416 /* enough for now */
6417 goto REDISP;
6418 }
6419 } else if ((ado = SUMA_SV_Focus_ADO(sv)) &&
6420 ado->do_type == GRAPH_LINK_type &&
6421 !strcmp(SUMA_ADO_variant(ado),"GMATRIX")) {
6422 SUMA_OVERLAYS *Sover = NULL;
6423 SUMA_LH("Switching overlay back one");
6424 Sover = SUMA_ADO_CurColPlane(ado);
6425 SUMA_SwitchColPlaneIntensity( ado, Sover,
6426 SUMA_BACK_ONE_SUBBRICK, 1);
6427 /* redisplay done in function above ... */
6428 SUMA_RETURNe;
6429 }
6430 } else {
6431 if (!SUMA_Z_Key(sv, "Z", "interactive")) {
6432 SUMA_S_Err("Failed in key func.");
6433 }
6434 }
6435 }
6436 break;
6437
6438 case Button2:
6439 if (Bev.state & ShiftMask) {
6440 /* setup initial zooming conditions */
6441 /*fprintf(SUMA_STDERR,"%s: Button 2 & Shift\n", FuncName); */
6442 sv->GVS[sv->StdView].zoomBegin = (float)Bev.y;
6443 sv->GVS[sv->StdView].zoomDelta = 0;
6444 } else {
6445 /*fprintf(stdout,"Button 2 down, plain jane\n");*/
6446 /* setup initial translation conditions */
6447 bevx = (float)Bev.x; bevy = (float)Bev.y;
6448 sv->GVS[sv->StdView].translateBeginX = bevx;;
6449 sv->GVS[sv->StdView].translateBeginY = bevy;
6450 sv->GVS[sv->StdView].translateDeltaX = 0.0;
6451 sv->GVS[sv->StdView].translateDeltaY = 0.0;
6452 }
6453 break;
6454
6455 case Button3: {
6456 SUMA_LHv("Button 3 down plain jane, "
6457 "viewer #%d : X=%f, Y = %f\n",
6458 SUMA_WhichSV(sv, SUMAg_SVv, SUMAg_N_SVv),
6459 (float)Bev.x, (float)Bev.y);
6460
6461 /* Clear any pre-existing selection */
6462 if (!SUMA_Add_To_PickResult_List(sv, NULL, "TERSUM", NULL)) {
6463 SUMA_S_Err("Failed to clear selections");
6464 break;
6465 }
6466
6467 /* Bev.state does work in the line below,
6468 unlike Mev.state further down.
6469 Using Kev.state anyway because it works in both cases */
6470 if ((Kev.state & ShiftMask) && (Kev.state & ControlMask)) {
6471 SUMA_LH("Allowing callbacks");
6472 SUMAg_CF->HoldClickCallbacks = 0;
6473 } else {
6474 SUMA_LH("Holding back callbacks");
6475 SUMAg_CF->HoldClickCallbacks = 1;
6476 }
6477
6478 /* are we in ROI drawing mode ? */
6479 if ( SUMAg_CF->ROI_mode
6480 && SUMA_SV_Focus_SO(sv) && !(Bev.state & ShiftMask)) {
6481 /* ROI drawing mode */
6482 ROI_mode = YUP;
6483 } else {
6484 ROI_mode = NOPE;
6485
6486 }
6487
6488 if (!(Kev.state & ShiftMask) && (Kev.state & ControlMask)) {
6489 SUMA_LH("Yoking intensity to node selection");
6490 SUMAg_CF->YokeIntToNode = 1;
6491 } else {
6492 SUMA_LH("Holding back yoking");
6493 SUMAg_CF->YokeIntToNode = 0;
6494 }
6495
6496 SUMA_LH("Get the selection line, bitte");
6497 if (!SUMA_GetSelectionLine ( sv, (int)Bev.x, (int)Bev.y,
6498 sv->Pick0, sv->Pick1, 0,
6499 NULL, NULL, NULL)) {
6500 fprintf (SUMA_STDERR,
6501 "Error %s: Failed in SUMA_GetSelectionLine.\n",
6502 FuncName);
6503 break;
6504 }
6505
6506 if (DoubleClick && !ROI_mode){/*See if you are selecting masks */
6507 SUMA_ALL_DO *mado=NULL, *ado=NULL;
6508 SUMA_GRAPH_SAUX *GSaux=NULL;
6509 /* you do not want to waist time doing double calculations if
6510 the user clicks twice by mistake */
6511 /* make sure no viewer, other than the one clicked in is in
6512 momentum mode */
6513 if (SUMAg_N_SVv > 1) {
6514 ii = SUMA_WhichViewerInMomentum (SUMAg_SVv,
6515 SUMAg_N_SVv, NULL);
6516 if (ii >= 0) {
6517 sprintf (s, "You cannot select or draw while viewers\n"
6518 "(like viewer %c) are in momentum mode.\n",
6519 ii+65);
6520 SUMA_RegisterMessage (SUMAg_CF->MessageList,
6521 s, FuncName, SMT_Error,
6522 SMA_LogAndPopup);
6523 SUMA_RETURNe;
6524 }
6525 }
6526
6527 /* Any hits for masks? */
6528 hit = SUMA_ComputeLineMaskIntersect (sv, SUMAg_DOv, 0, &mado);
6529 if (hit < 0) {
6530 SUMA_S_Err("Failed in SUMA_ComputeLineMaskIntersect.");
6531 } else if (hit > 0) {
6532 SUMA_LH("Mask was double clicked");
6533 if (!MASK_MANIP_MODE(sv)) {
6534 SUMA_S_Note("Turning on mask manip mode");
6535 if (!SUMA_SetMouseMode(sv,SUMA_MASK_MANIP_MMODE,
6536 (void *)(ADO_ID(mado)))) {
6537 SUMA_S_Warn("Mask manip mode could not be set");
6538 }
6539 } else {
6540 SUMA_S_Note("Turning off mask manip mode");
6541 if (!SUMA_SetMouseMode(sv,SUMA_MASK_MANIP_MMODE,NULL)) {
6542 SUMA_S_Warn("Mask manip mode could not be set");
6543 }
6544 }
6545 /* Not much else to do */
6546 goto REDISP;
6547 } else if (MASK_MANIP_MODE(sv)) { /* turn it off */
6548 SUMA_S_Note("Turning off mask manip mode");
6549 if (!SUMA_SetMouseMode(sv,SUMA_MASK_MANIP_MMODE,NULL)) {
6550 SUMA_S_Warn("Mask manip mode could not be set");
6551 }
6552 /* Not much else to do */
6553 goto REDISP;
6554 } else if ((ado = SUMA_SV_Focus_ADO(sv)) &&
6555 ado->do_type == GRAPH_LINK_type &&
6556 (GSaux = SUMA_ADO_GSaux(ado)) &&
6557 GSaux->PR && GSaux->PR->datum_index == -1 &&
6558 GSaux->PR->iAltSel[SUMA_ENODE_0] != -1 &&
6559 GSaux->IgnoreSelection == 0) {
6560 /* turn off node selection to allow all connections
6561 to be visible. Execute only if we have a graph
6562 in focus (in 3D drawing) and a point is selected
6563 and selection is not being ignored*/
6564 SUMA_LH("Ignoring selection for graph display");
6565 GSaux->IgnoreSelection = 1;
6566 SUMA_FlushPickBufferForDO(ado);
6567 goto REDISP;
6568 }
6569 SUMA_LH("No mask hit, and no selection needs ignoring");
6570 }
6571
6572 if (!DoubleClick) {
6573 /* you do not want to waist time doing double calculations if
6574 the user clicks twice by mistake */
6575 /* make sure no viewer, other than the one clicked in is in
6576 momentum mode */
6577 if (SUMAg_N_SVv > 1) {
6578 ii = SUMA_WhichViewerInMomentum (SUMAg_SVv,
6579 SUMAg_N_SVv, NULL);
6580 if (ii >= 0) {
6581 sprintf (s, "You cannot select or draw while viewers\n"
6582 "(like viewer %c) are in momentum mode.\n",
6583 ii+65);
6584 SUMA_RegisterMessage (SUMAg_CF->MessageList,
6585 s, FuncName, SMT_Error,
6586 SMA_LogAndPopup);
6587 SUMA_RETURNe;
6588 }
6589 }
6590
6591 #if 0
6592 /* Try this if you are having OpenGLStateReset problems at
6593 node selection time. It is inefficient, but helps point
6594 to the problem.
6595 Look at recent updates to SE_Redisplay*All* for the more
6596 appropriate fix */
6597 SUMA_S_Note("Blunt fix:");
6598 SUMA_OpenGLStateReset(SUMAg_DOv, SUMAg_N_DOv, sv);
6599 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
6600 #endif
6601
6602 /* perform the intersection calcluation and mark the surface */
6603 SUMA_LHv("Finding hit: %d %d,\n"
6604 "Pick0: %f %f %f, Pick1: %f %f %f\n",
6605 (int)Bev.x, (int)Bev.y,
6606 sv->Pick0[0], sv->Pick0[1], sv->Pick0[2],
6607 sv->Pick1[0], sv->Pick1[1], sv->Pick1[2]);
6608
6609
6610 if (1) {
6611 hit = SUMA_ComputeLineDOsIntersect (sv, SUMAg_DOv, 0, NULL);
6612 if ( (Kev.state & ShiftMask) &&
6613 !(Kev.state & ControlMask) &&
6614 !SUMA_ALTHELL && !SUMAg_CF->ROI_mode){
6615 /* Show me the click buffer */
6616 SUMA_MarkPickInBuffer4(sv, 1, NULL);
6617 }
6618 if (hit < 0) {
6619 SUMA_S_Err("Failed in SUMA_ComputeLineDOsIntersect.");
6620 }
6621 }
6622
6623 if (1) {
6624 SUMA_LH("Trying for volume intersections");
6625 hit = SUMA_ComputeLineVOslicesIntersect(sv, SUMAg_DOv,
6626 0, NULL);
6627 if (hit < 0) {
6628 fprintf( SUMA_STDERR,
6629 "Error %s: "
6630 "Failed in SUMA_MarkLineVOslicesIntersect.\n",
6631 FuncName);
6632 }
6633 }
6634
6635 if (1) {
6636 SUMA_LH("Trying for volume VR intersections");
6637 hit = SUMA_ComputeLineVOvrIntersect(sv, SUMAg_DOv,
6638 0, NULL);
6639 if (hit < 0) {
6640 fprintf( SUMA_STDERR,
6641 "Error %s: "
6642 "Failed in SUMA_MarkLineVOvrIntersect.\n",
6643 FuncName);
6644 }
6645 }
6646 #if 0
6647 if (SUMA_ALTHELL ||
6648 SUMA_VisibleSOs(sv, SUMAg_DOv, NULL, 0) == 0) {
6649 SUMA_LH("Trying for cutplanes");
6650 hit = SUMA_MarkLineCutplaneIntersect (sv, SUMAg_DOv, 0);
6651 if (hit < 0) {
6652 fprintf( SUMA_STDERR,
6653 "Error %s: "
6654 "Failed in SUMA_MarkLineCutplaneIntersect.\n",
6655 FuncName);
6656 }
6657 }
6658 #endif
6659
6660 SUMA_LH("Checking on registered surfaces");
6661 SwasHit = 0;
6662
6663 ii = SUMA_RegisteredSOs(sv, SUMAg_DOv, NULL);
6664
6665 if (ii == 0) { /* no surfaces, break */
6666 SUMA_LH("No registrants");
6667
6668 } else {
6669 /* have surfaces, find hits */
6670 hit = SUMA_ComputeLineSurfaceIntersect (sv, SUMAg_DOv, 0, NULL);
6671
6672 if (hit < 0) {
6673 SUMA_S_Err("Failed in SUMA_ComputeLineSurfaceIntersect.");
6674 } else if (hit > 0) SwasHit = 1;
6675
6676 }
6677
6678 }
6679
6680
6681 if (ROI_mode && (SwasHit || DoubleClick)) {
6682 /* keep track of mouse motion in window */
6683 if (!SUMA_CreateBrushStroke (sv)) {
6684 SUMA_RegisterMessage (SUMAg_CF->MessageList,
6685 "Failed to create BrushStroke.",
6686 FuncName,
6687 SMT_Error, SMA_LogAndPopup);
6688 SUMA_RETURNe;
6689
6690 }
6691
6692 SUMA_AddToBrushStroke (sv, (int)Bev.x, (int)Bev.y, sv->Pick0,
6693 sv->Pick1, YUP);
6694 }
6695
6696 ASSESS:
6697 SUMA_LH("Assessment %d", dlist_size(sv->SelAdo));
6698 SUMA_ALL_DO *ado = SUMA_SV_Focus_ADO(sv);
6699 if (!(SUMA_ADO_Saux(ado))){
6700 SUMA_S_Err("NULL Saux!!!, don't let that happen");
6701 SUMA_RETURNe;
6702 }
6703 if (dlist_size(sv->SelAdo)) {
6704 if (!SUMA_Process_Selected_ADO(sv,SUMA_ALTHELL)) {
6705 SUMA_S_Err("Failed to process selected ados");
6706 goto OUT;
6707 }
6708
6709 SUMA_LH("Calling redisplay");
6710 /* redisplay */
6711 sv->ResetGLStateVariables = YUP;
6712 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
6713 }
6714 goto OUT;
6715
6716 REDISP:
6717 SUMA_LH("Calling redisplay without assessment");
6718 sv->ResetGLStateVariables = YUP;
6719 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
6720 goto OUT;
6721
6722 OUT:
6723 /* reset hold on xforms */
6724 SUMAg_CF->HoldClickCallbacks = 0;
6725 break; }
6726 } /* switch type of button Press */
6727 break;
6728
6729 case ButtonRelease:
6730 SUMAg_CF->X->ButtonDown=0;
6731 M1time = 0;
6732 rButton = Bev.button;
6733 SUMA_LHv("In ButtonRelease Button %d %d @ x,y=%d,%d\n",
6734 rButton, SUMAg_CF->X->ButtonDown, Bev.x, Bev.y);
6735 if (SUMAg_CF->Echo_KeyPress) {
6736 fprintf (SUMA_STDERR,"Button Release: %d (%d,%d,%d,%d,%d)\n"
6737 , rButton, Button1, Button2, Button3, Button4,
6738 Button5);
6739 }
6740
6741 if (SUMAg_CF->SwapButtons_1_3 ||
6742 (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
6743 if (rButton == Button1) rButton = Button3;
6744 else if (rButton == Button3) rButton = Button1;
6745 }
6746
6747 if (strstr(sv->State, "GMATRIX")==sv->State) {
6748 /* For graph in matrix representation swap buttons 1 and 2 */
6749 switch (rButton) {
6750 case Button1:
6751 rButton = Button2;
6752 break;
6753 case Button2:
6754 rButton = Button1;
6755 break;
6756 }
6757 }
6758
6759
6760 switch (rButton) { /* switch type of button Press */
6761 case Button3:
6762 if (LocalHead)
6763 fprintf(SUMA_STDERR,"%s: In ButtonRelease3\n", FuncName);
6764
6765 if (SUMAg_CF->ROI_mode) {
6766 SUMA_DRAWN_ROI *DrawnROI = NULL;
6767 SUMA_BRUSH_STROKE_ACTION BsA=SUMA_BSA_Undefined;
6768
6769 if (sv->BS) {
6770 /* Process the brush stroke*/
6771 if (DoubleClick) BsA = SUMA_BSA_JoinEnds;
6772 else BsA = SUMA_BSA_AppendStrokeOrFill;
6773 if (!(DrawnROI = SUMA_ProcessBrushStroke (sv, BsA))) {
6774 if (LocalHead)
6775 fprintf (SUMA_STDERR,
6776 "%s: NULL DrawnROI returned.\n", FuncName);
6777 SUMA_ClearBrushStroke (sv);
6778 break;
6779 }
6780
6781 /* Showme the DrawnROI */
6782 if (LocalHead) SUMA_ShowDrawnROI (DrawnROI, NULL, NOPE);
6783
6784 /* do smething with the BrushStroke, then wipe it clean,
6785 OK to show even if empty*/
6786 if (LocalHead) SUMA_ShowBrushStroke (sv, NULL);
6787
6788 /* SUMA_DrawBrushStroke (sv, YUP); */
6789 SUMA_ClearBrushStroke (sv);
6790
6791 /* redisplay all others */
6792 if (!list) list = SUMA_CreateList ();
6793 SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list,
6794 SE_RedisplayNow_AllOtherVisible, SES_SumaWidget, sv);
6795 SUMA_Engine (&list);
6796
6797 /* redisplay .
6798 DO NOT REDISPLAY WITH SE_Redisplay_AllVisible or
6799 you will have GL state synchronization problems */
6800 sv->ResetGLStateVariables = YUP;
6801 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
6802
6803 }/* if sv->BS */
6804 } /* if SUMAg_CF->ROImode */
6805
6806 if (sv->Focus_DO_ID > 0){/* Get surface controller page in sync */
6807 if (!SUMA_IS_CONTPAGE_ON_TOP(SUMAg_CF->X->AllMaskCont)) {
6808 /* Switch only if 'sticky' mask controller page
6809 is not on top */
6810 SUMA_ALL_DO *ado = SUMA_SV_Focus_ADO(sv);
6811 if (ado) {
6812 SUMA_LHv("Will call Init for %s if %d\n",
6813 SUMA_ADO_Label(ado),
6814 SUMA_isADO_Cont_Realized(ado));
6815 if (SUMA_isADO_Cont_Realized(ado))
6816 SUMA_Init_SurfCont_SurfParam(ado);
6817 }
6818 } else {
6819 if (!SUMA_InitMasksTable(SUMAg_CF->X->AllMaskCont)) {
6820 SUMA_S_Err("Failed to initialize mask table");
6821 }
6822 }
6823 }
6824 break;
6825 case Button1:
6826 SUMA_LH("In Button 1 release\n");
6827 if (sv->GVS[sv->StdView].vLHpry0[0] !=
6828 sv->GVS[sv->StdView].vLHpry[0] ||
6829 sv->GVS[sv->StdView].vLHpry0[1] !=
6830 sv->GVS[sv->StdView].vLHpry[1] ||
6831 sv->GVS[sv->StdView].vLHpry0[2] !=
6832 sv->GVS[sv->StdView].vLHpry[2] ){
6833 /* update the normals just now, this would not be needed if
6834 SUMA_ApplyPrying has set recompute_normals = 1*/
6835 SUMA_RecomputeNormsPrying(sv);
6836 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
6837 }
6838 sv->GVS[sv->StdView].vLHpry0[0] = sv->GVS[sv->StdView].vLHpry[0];
6839 sv->GVS[sv->StdView].vLHpry0[1] = sv->GVS[sv->StdView].vLHpry[1];
6840 sv->GVS[sv->StdView].vLHpry0[2] = sv->GVS[sv->StdView].vLHpry[2];
6841 break;
6842 } /* switch type of button Press */
6843 break;
6844
6845 case MotionNotify:
6846 if (LocalHead) {
6847 fprintf(stdout,"In MotionNotify\n");
6848 if (Mev.state & Button1MotionMask) fprintf(stdout," B1 mot\n");
6849 else if (Mev.state & Button2MotionMask) fprintf(stdout," B2 mot\n");
6850 else if (Mev.state & Button3MotionMask) fprintf(stdout," B3 mot\n");
6851 else if (Mev.state & Button4MotionMask) fprintf(stdout," B4 mot\n");
6852 else if (Mev.state & Button5MotionMask) fprintf(stdout," B5 mot\n");
6853 else fprintf(stdout," Something mot, button %d\n", Bev.button);
6854 }
6855 if (SUMAg_CF->Echo_KeyPress) {
6856 if (Mev.state & Button1MotionMask)
6857 fprintf(SUMA_STDERR," B1 mot\n");
6858 else if (Mev.state & Button2MotionMask)
6859 fprintf(SUMA_STDERR," B2 mot\n");
6860 else if (Mev.state & Button3MotionMask)
6861 fprintf(SUMA_STDERR," B3 mot\n");
6862 else if (Mev.state & Button4MotionMask)
6863 fprintf(SUMA_STDERR," B4 mot\n");
6864 else if (Mev.state & Button5MotionMask)
6865 fprintf(SUMA_STDERR," B5 mot\n");
6866 else if (Mev.state) fprintf(SUMA_STDERR,
6867 " Something mot, button %d\n", Bev.button);
6868 }
6869
6870 if ( SUMAg_CF->SwapButtons_1_3 ||
6871 (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
6872 if (((Mev.state & Button3MotionMask) && (Mev.state & Button2MotionMask))
6873 || ((Mev.state & Button2MotionMask) && (Mev.state & ShiftMask))) {
6874 mButton = SUMA_Button_12_Motion;
6875 } else if(Mev.state & Button3MotionMask) {
6876 mButton = SUMA_Button_1_Motion;
6877 }else if(Mev.state & Button2MotionMask) {
6878 mButton = SUMA_Button_2_Motion;
6879 }else if(Mev.state & Button1MotionMask) {
6880 mButton = SUMA_Button_3_Motion;
6881 }else {
6882 break;
6883 }
6884 } else {
6885 if (((Mev.state & Button1MotionMask) && (Mev.state & Button2MotionMask))
6886 || ((Mev.state & Button2MotionMask) && (Mev.state & ShiftMask))) {
6887 mButton = SUMA_Button_12_Motion;
6888 } else if(Mev.state & Button1MotionMask) {
6889 mButton = SUMA_Button_1_Motion;
6890 }else if(Mev.state & Button2MotionMask) {
6891 mButton = SUMA_Button_2_Motion;
6892 } else if(Mev.state & Button3MotionMask) {
6893 mButton = SUMA_Button_3_Motion;
6894 }else {
6895 break;
6896 }
6897 }
6898
6899 if (strstr(sv->State, "GMATRIX")==sv->State) {
6900 /* For graph in matrix representation swap buttons 1 and 2 */
6901 SUMA_LH("In graph matrix, swapping 1/2 motion");
6902 switch (mButton) {
6903 case SUMA_Button_1_Motion:
6904 mButton = SUMA_Button_2_Motion;
6905 break;
6906 case SUMA_Button_2_Motion:
6907 mButton = SUMA_Button_1_Motion;
6908 break;
6909 }
6910 }
6911
6912 switch (mButton) {
6913 case SUMA_Button_12_Motion:
6914 case SUMA_Button_2_Shift_Motion:
6915 /*fprintf(SUMA_STDERR,"%s: In motion, Butt1 & Butt2\n", FuncName);*/
6916 sv->GVS[sv->StdView].zoomDelta = 1.0 +
6917 (float)((int)Mev.y -
6918 sv->GVS[sv->StdView].zoomBegin)/MOUSE_ZOOM_FACT;
6919 if (sv->GVS[sv->StdView].zoomDelta > 2.0)
6920 sv->GVS[sv->StdView].zoomDelta = 2.0;
6921 else if (sv->GVS[sv->StdView].zoomDelta < 0.5)
6922 sv->GVS[sv->StdView].zoomDelta = 0.5;
6923 sv->FOV[sv->iState] /= sv->GVS[sv->StdView].zoomDelta;
6924 if (sv->FOV[sv->iState] < FOV_MIN) sv->FOV[sv->iState] = FOV_MIN;
6925 else if (sv->FOV[sv->iState] > FOV_MAX)
6926 sv->FOV[sv->iState] = FOV_MAX;
6927 sv->GVS[sv->StdView].zoomBegin = (float)(int)Mev.y;
6928 /*fprintf(stdout, "FOV zoom Delta = %f=n",
6929 sv->GVS[sv->StdView].zoomDelta);*/
6930 /* Now update the zoom compensation variable */
6931 if (sv->ZoomCompensate) {
6932 sv->ZoomCompensate = sqrt(sv->FOV[sv->iState] /
6933 SUMA_sv_auto_fov(sv));
6934 /* slow down compensation, with sqrt*/
6935 if (sv->ZoomCompensate > 1)
6936 sv->ZoomCompensate = 1.0;
6937 /* no need to compensate at low zooms */
6938 else if (sv->ZoomCompensate < 0.05)
6939 sv->ZoomCompensate = 0.05; /* no need to go lower */
6940 }
6941 ii = SUMA_WhichSV (sv, SUMAg_SVv, SUMAg_N_SVv);
6942 SUMA_postRedisplay(w, clientData, callData);
6943 break;
6944
6945 case SUMA_Button_1_Motion:
6946 /* fprintf(SUMA_STDERR,"%s: In motion, Butt1 \n", FuncName); */
6947 mevx = (float)Mev.x;
6948 mevy = (float)Mev.y;
6949 wwid = (float)sv->X->aWIDTH;
6950 whei = (float)sv->X->aHEIGHT;
6951 /* spinning mode */
6952 if (sv->ZoomCompensate) {
6953 zc_fac = sv->ZoomCompensate;
6954 }else {
6955 zc_fac = 1.0;
6956 }
6957 sv->GVS[sv->StdView].spinDeltaX =
6958 (mevx - sv->GVS[sv->StdView].spinBeginX);
6959 sv->GVS[sv->StdView].spinDeltaY =
6960 (mevy - sv->GVS[sv->StdView].spinBeginY);
6961 if (M1time) {
6962 M1delta = Mev.time - M1time;
6963 mvdeltax = Mev.x - mvxlast;
6964 mvdeltay = Mev.y - mvylast;
6965 } else {
6966 M1delta = 0;
6967 mvdeltax = 0;
6968 mvdeltay = 0;
6969 }
6970 M1time = Mev.time;
6971 mvxlast= Mev.x;
6972 mvylast= Mev.y;
6973
6974 /* compute move rate in pixels per milliseconds,
6975 You could use this to add a gain on the amount of rotation,
6976 but before you could use those factors, you'll need to scale
6977 the results to something appropriate */
6978 mvx_fac = ((SUMA_ABS((float)mvdeltax)/(M1delta+0.01)));
6979 mvy_fac = ((SUMA_ABS((float)mvdeltay)/(M1delta+0.01)));
6980
6981 #if 0
6982 fprintf(stdout,"\n"
6983 "spinBeginX %f \n"
6984 "spinBeginY %f \n"
6985 "spinDeltaX %f \n"
6986 "spinDeltaY %f \n"
6987 "X->aWIDTH %d \n"
6988 "X->aHEIGHT %d\n"
6989 "ZoomCompensate %f\n"
6990 "mv[xy]last [%d %d]\n"
6991 "mvdelta[xy]last [%d %d]\n"
6992 "MoveRatePixelsPerms [%f %f]\n"
6993 ,
6994 sv->GVS[sv->StdView].spinBeginX,
6995 sv->GVS[sv->StdView].spinBeginY,
6996 sv->GVS[sv->StdView].spinDeltaX,
6997 sv->GVS[sv->StdView].spinDeltaY,
6998 sv->X->aWIDTH, sv->X->aHEIGHT, sv->ZoomCompensate,
6999 mvxlast, mvylast,
7000 mvdeltax, mvdeltay,
7001 mvx_fac, mvy_fac
7002 );
7003 #else
7004 /* fprintf(stdout,"%f %f; ", mvx_fac, mvy_fac); */
7005 #endif
7006 /* do not use movement rate before you scale it properly */
7007 mvx_fac = mvy_fac = 1.0;
7008 if (sv->GVS[sv->StdView].spinDeltaX ||
7009 sv->GVS[sv->StdView].spinDeltaY){
7010 if (SUMA_Shft_Event(SUMAg_CF->lev)) {
7011 float a[3], cQ[4];
7012 /* rotate about Z axis */
7013 a[0] = 0.0; a[1] = 0.0; a[2] = 1.0;
7014 axis_to_quat(a,
7015 -SUMA_SIGN(mvdeltax)*sqrt(SUMA_ABS(mvdeltax))*
7016 sv->ArrowRotationAngle,
7017 cQ);
7018 /*add rotation */
7019 add_quats ( cQ,
7020 sv->GVS[sv->StdView].currentQuat,
7021 sv->GVS[sv->StdView].currentQuat);
7022 } else if (SUMA_Cont_Event(SUMAg_CF->lev)) {
7023 float val[3];
7024 val[0] = sv->GVS[sv->StdView].spinDeltaX;
7025 val[1] = sv->GVS[sv->StdView].spinDeltaY;
7026 val[2] = 0.0;
7027 SUMA_ApplyPrying(sv, val, "mouse", 0);
7028 /* update normals at release */
7029 } else if (SUMA_Plain_Event(SUMAg_CF->lev)){
7030 trackball( sv->GVS[sv->StdView].deltaQuat,
7031 (2*sv->GVS[sv->StdView].spinBeginX - wwid) /
7032 wwid*zc_fac*mvx_fac,
7033 (whei - 2*sv->GVS[sv->StdView].spinBeginY) /
7034 whei*zc_fac*mvy_fac,
7035 (2*mevx - wwid)/wwid*zc_fac*mvx_fac,
7036 (whei - 2*mevy)/whei*zc_fac*mvy_fac);
7037 /* comput the increment Quat */
7038 sv->GVS[sv->StdView].spinBeginX = mevx;
7039 sv->GVS[sv->StdView].spinBeginY = mevy;
7040 add_quats ( sv->GVS[sv->StdView].deltaQuat,
7041 sv->GVS[sv->StdView].currentQuat,
7042 sv->GVS[sv->StdView].currentQuat);
7043 } else {
7044 SUMA_LH("Not ready for event flavor");
7045 break;
7046 }
7047 ii = SUMA_WhichSV(sv, SUMAg_SVv, SUMAg_N_SVv);
7048 if (ii < 0) {
7049 fprintf (SUMA_STDERR,
7050 "Error %s: Failed to find index of sv.\n", FuncName);
7051 break;
7052 }
7053 if (!SUMAg_CF->ViewLocked[ii]) { /* No locking,
7054 just redisplay current viewer */
7055 SUMA_postRedisplay(w, clientData, callData);
7056 } else { /* locking, update and redisplay those locked */
7057 DList *list = NULL;
7058 SUMA_EngineData *ED = NULL;
7059 SUMA_STANDARD_VIEWS ed_sv, ed_svi;
7060 /* redisplay current viewer immediately */
7061 list = SUMA_CreateList ();
7062 ED = SUMA_InitializeEngineListData (SE_RedisplayNow);
7063 SUMA_RegisterEngineListCommand (list, ED,
7064 SEF_Empty, NULL,
7065 SES_Suma, (void *)sv, NOPE,
7066 SEI_Head, NULL);
7067 ed_sv = SUMA_BestStandardView(sv, SUMAg_DOv, SUMAg_N_DOv);
7068 for (it=0; it < SUMAg_N_SVv; ++it) {
7069 svi = &SUMAg_SVv[it];
7070 ed_svi = SUMA_BestStandardView(svi, SUMAg_DOv, SUMAg_N_DOv);
7071 if ( it != ii &&
7072 SUMAg_CF->ViewLocked[it] && ed_svi == ed_sv) {
7073 /* copy quaternions */
7074 svi->GVS[svi->StdView].spinBeginX =
7075 sv->GVS[sv->StdView].spinBeginX;
7076 svi->GVS[svi->StdView].spinBeginY =
7077 sv->GVS[sv->StdView].spinBeginY;
7078 SUMA_COPY_VEC( sv->GVS[sv->StdView].deltaQuat,
7079 svi->GVS[svi->StdView].deltaQuat,
7080 4, float, float);
7081 SUMA_COPY_VEC( sv->GVS[sv->StdView].currentQuat,
7082 svi->GVS[svi->StdView].currentQuat,
7083 4, float, float);
7084
7085 /* add a redisplay now */
7086 ED = SUMA_InitializeEngineListData (SE_RedisplayNow);
7087 SUMA_RegisterEngineListCommand ( list, ED,
7088 SEF_Empty, NULL,
7089 SES_Suma, (void *)svi, NOPE,
7090 SEI_Head, NULL);
7091 }
7092 }
7093 if (!SUMA_Engine (&list)) {
7094 fprintf (SUMA_STDERR,
7095 "Error %s: Failed calling SUMA_Engine.\n",
7096 FuncName);
7097 break;
7098 }
7099 }
7100 }
7101
7102 break;
7103
7104 case SUMA_Button_2_Motion:
7105 mevx = (float)Mev.x; mevy = (float)Mev.y;
7106 SUMA_LHv("In motion, Butt2 %f, %f\n", mevx , mevy);
7107 if (sv->ZoomCompensate) {
7108 zc_fac = sv->ZoomCompensate;
7109 }else {
7110 zc_fac = 1.0;
7111 }
7112 if ((Kev.state & ShiftMask)){
7113
7114 } else {
7115 sv->GVS[sv->StdView].translateDeltaX =
7116 (mevx - sv->GVS[sv->StdView].translateBeginX) /
7117 (float)sv->X->aWIDTH*sv->GVS[sv->StdView].TranslateGain;
7118 sv->GVS[sv->StdView].translateDeltaY =
7119 -(mevy - sv->GVS[sv->StdView].translateBeginY) /
7120 (float)sv->X->aHEIGHT*sv->GVS[sv->StdView].TranslateGain;
7121
7122 if ( sv->GVS[sv->StdView].translateDeltaX ||
7123 sv->GVS[sv->StdView].translateDeltaY){
7124 sv->GVS[sv->StdView].translateVec[0] +=
7125 (GLfloat)sv->GVS[sv->StdView].translateDeltaX * zc_fac;
7126 sv->GVS[sv->StdView].translateVec[1] +=
7127 (GLfloat)sv->GVS[sv->StdView].translateDeltaY * zc_fac;
7128 sv->GVS[sv->StdView].translateBeginX = mevx;
7129 sv->GVS[sv->StdView].translateBeginY = mevy;
7130 SUMA_postRedisplay(w, clientData, callData);
7131 }
7132 }
7133 break;
7134
7135 case SUMA_Button_3_Motion: {
7136 SUMA_ALL_DO *lado=NULL;
7137 SUMA_DO_Types lado_type=NOT_SET_type;
7138
7139 if (sv->LastSel_ado_idcode_str) {
7140 lado = SUMA_whichADOg(sv->LastSel_ado_idcode_str);
7141 if (lado) lado_type = lado->do_type;
7142 }
7143
7144 SUMA_LH("In button 3 motion, lado=%s", ADO_LABEL(lado));
7145
7146 /* Clear any pre-existing selection */
7147 if (!SUMA_Add_To_PickResult_List(sv, NULL, "TERSUM", NULL)) {
7148 SUMA_S_Err("Failed to clear selections");
7149 break;
7150 }
7151
7152 if (SUMAg_CF->ROI_mode && SUMA_SV_Focus_SO(sv) && sv->BS) {
7153 /* ROI drawing mode */
7154 ii = SUMA_RegisteredSOs(sv, SUMAg_DOv, NULL);
7155 if (ii == 0) { /* no surfaces, break */
7156 break;
7157 }
7158
7159
7160 if (!SUMA_GetSelectionLine(sv,
7161 (int)Mev.x, (int)Mev.y, sv->Pick0, sv->Pick1,
7162 0, NULL, NULL, NULL)) {
7163 fprintf (SUMA_STDERR, "Error %s: Failed in "
7164 "SUMA_GetSelectionLine.\n", FuncName);
7165 break;
7166 }
7167
7168 if (!SUMA_AddToBrushStroke (sv, (int)Mev.x, (int)Mev.y,
7169 sv->Pick0, sv->Pick1, YUP)) {
7170 SUMA_RegisterMessage (SUMAg_CF->MessageList,
7171 "Failed to add to BrushStroke.",
7172 FuncName,
7173 SMT_Error, SMA_LogAndPopup);
7174 break;
7175 }
7176 } else {
7177 /* Mev.state does not work in the line below */
7178 if ((Kev.state & ShiftMask) && (Kev.state & ControlMask) ) {
7179 SUMA_LH("Allowing callbacks");
7180 SUMAg_CF->HoldClickCallbacks = 0;
7181 } else {
7182 SUMA_LH("Holding back callbacks");
7183 SUMAg_CF->HoldClickCallbacks = 1;
7184 }
7185
7186 if (SUMAg_N_SVv > 1) {
7187 ii = SUMA_WhichViewerInMomentum (SUMAg_SVv,
7188 SUMAg_N_SVv, NULL);
7189 if (ii >= 0) {
7190 sprintf (s, "You cannot select or draw while viewers\n"
7191 "(like viewer %c) are in momentum mode.\n",
7192 ii+65);
7193 SUMA_RegisterMessage (SUMAg_CF->MessageList,
7194 s, FuncName, SMT_Error,
7195 SMA_LogAndPopup);
7196 SUMA_RETURNe;
7197 }
7198 }
7199
7200 if (!(Kev.state & ShiftMask) && (Kev.state & ControlMask) ) {
7201 SUMA_LH("Yoking intensity to node selection");
7202 SUMAg_CF->YokeIntToNode = 1;
7203 } else {
7204 SUMA_LH("Holding back callbacks");
7205 SUMAg_CF->YokeIntToNode = 0;
7206 }
7207
7208 #if 0
7209 /* Try this if you are having OpenGLStateReset problems at
7210 node selection time. It is inefficient, but helps point
7211 to the problem.
7212 Look at recent updates to SE_Redisplay*All* for the more
7213 appropriate fix */
7214 SUMA_S_Note("Blunt fix:");
7215 SUMA_OpenGLStateReset(SUMAg_DOv, SUMAg_N_DOv, sv);
7216 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
7217 #endif
7218
7219 if (!SUMA_GetSelectionLine ( sv, (int)Mev.x, (int)Mev.y,
7220 sv->Pick0, sv->Pick1, 0,
7221 NULL, NULL, NULL)) {
7222 fprintf (SUMA_STDERR,
7223 "Error %s: Failed in SUMA_GetSelectionLine.\n",
7224 FuncName);
7225 break;
7226 }
7227
7228 if (lado_type == NOT_SET_type ||
7229 lado_type == MASK_type) {
7230 if (!MASK_MANIP_MODE(sv)) { /* You don't want these if
7231 you're moving them! */
7232 SUMA_LH("Mask picking");
7233 hit = SUMA_ComputeLineMaskIntersect (sv, SUMAg_DOv, 0, NULL);
7234 if (hit < 0) {
7235 SUMA_S_Err("Failed in SUMA_ComputeLineMaskIntersect.");
7236 }
7237 }
7238 }
7239
7240 if (lado_type == NOT_SET_type ||
7241 lado_type == TRACT_type || lado_type == GRAPH_LINK_type) {
7242 if (1) {
7243 SUMA_LH("Tract picking");
7244 hit = SUMA_ComputeLineDOsIntersect (sv, SUMAg_DOv, 0, NULL);
7245 if (hit < 0) {
7246 SUMA_S_Err("Failed in SUMA_ComputeLineDOsIntersect.");
7247 }
7248 }
7249 }
7250
7251 if (lado_type == NOT_SET_type ||
7252 lado_type == VO_type) {
7253 if (1) {
7254 SUMA_LH("Trying for volume intersections");
7255 hit = SUMA_ComputeLineVOslicesIntersect(sv, SUMAg_DOv,
7256 0, NULL);
7257 if (hit < 0) {
7258 fprintf( SUMA_STDERR,
7259 "Error %s: "
7260 "Failed in SUMA_MarkLineVOslicesIntersect.\n",
7261 FuncName);
7262 }
7263 }
7264 if (1) {
7265 SUMA_LH("Trying for volume rendering intersections");
7266 hit = SUMA_ComputeLineVOvrIntersect(sv, SUMAg_DOv,
7267 0, NULL);
7268 if (hit < 0) {
7269 fprintf( SUMA_STDERR,
7270 "Error %s: "
7271 "Failed in SUMA_MarkLineVOvrIntersect.\n",
7272 FuncName);
7273 }
7274 }
7275 }
7276
7277 if ((lado_type == NOT_SET_type ||
7278 lado_type == SO_type)) {
7279 ii = SUMA_RegisteredSOs(sv, SUMAg_DOv, NULL);
7280 if (ii > 0) { /* some surfaces, try */
7281 /* perform the intersection calcluation and mark the surface */
7282 hit = SUMA_ComputeLineSurfaceIntersect (sv, SUMAg_DOv,
7283 1, NULL);
7284 if (hit < 0) {
7285 fprintf( SUMA_STDERR,
7286 "Error %s: "
7287 "Failed in SUMA_ComputeLineSurfaceIntersect.\n",
7288 FuncName);
7289 break;
7290 }
7291 }
7292 }
7293
7294 ASSESS_MOTION:
7295 SUMA_LH("Assessment");
7296 if (dlist_size(sv->SelAdo)) {
7297 if (!SUMA_Process_Selected_ADO(sv, SUMA_ALTHELL)) {
7298 SUMA_S_Err("Failed to process selected ado");
7299 SUMA_RETURNe;
7300 }
7301
7302 /* redisplay */
7303 sv->ResetGLStateVariables = YUP;
7304 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
7305 }
7306 OUT_MOTION:
7307 /* reset hold on xforms */
7308 SUMAg_CF->HoldClickCallbacks = 0;
7309 }
7310
7311 break; }
7312 }
7313
7314
7315 break;
7316 }
7317
7318 /* switch event type */
7319
7320 SUMA_RETURNe;
7321 }
7322
7323 /*!
7324 SUMA_momentum(XtPointer clientData, XtIntervalId *id);
7325
7326 client data contains the widget responsible for the call to SUMA_momentum
7327 */
SUMA_momentum(XtPointer clientData,XtIntervalId * id)7328 void SUMA_momentum(XtPointer clientData, XtIntervalId *id)
7329 {
7330 static char FuncName[]={"SUMA_momentum"};
7331 static int ReDisp;
7332 Widget w = NULL;
7333 int isv;
7334 SUMA_SurfaceViewer *sv;
7335
7336 SUMA_ENTRY;
7337
7338 // fprintf(stderr, "%s\n", FuncName);
7339
7340 /* the widget is passed as client data */
7341 w = (Widget)clientData;
7342
7343 /* find out which Surface viewer the widget belongs to */
7344 SUMA_ANY_WIDGET2SV((Widget)clientData, sv, isv);
7345 if (isv < 0) {
7346 SUMA_S_Err("Failed in macro SUMA_ANY_WIDGET2SV.");
7347 SUMA_RETURNe;
7348 }
7349
7350
7351 ReDisp = 0;
7352 if ( ((sv->GVS[sv->StdView].spinDeltaX*sv->GVS[sv->StdView].spinDeltaX) >
7353 sv->GVS[sv->StdView].MinIdleDelta ) ||
7354 ((sv->GVS[sv->StdView].spinDeltaY*sv->GVS[sv->StdView].spinDeltaY) >
7355 sv->GVS[sv->StdView].MinIdleDelta ) )
7356 { /* rotate if SUMA_momentum is enabled and spinDeltaX or spinDeltaY
7357 are larger than the minimum set */
7358 /*fprintf(stdout,"SUMA_momentum: spinDeltaX %f spinDeltaY %f\n",
7359 sv->GVS[sv->StdView].spinDeltaX,
7360 sv->GVS[sv->StdView].spinDeltaY);*/
7361 add_quats ( sv->GVS[sv->StdView].deltaQuat,
7362 sv->GVS[sv->StdView].currentQuat,
7363 sv->GVS[sv->StdView].currentQuat);
7364 ReDisp = 1;
7365 }
7366 if ( ((sv->GVS[sv->StdView].translateDeltaX*
7367 sv->GVS[sv->StdView].translateDeltaX) >
7368 sv->GVS[sv->StdView].MinIdleDelta ) ||
7369 ((sv->GVS[sv->StdView].translateDeltaY*
7370 sv->GVS[sv->StdView].translateDeltaY) >
7371 sv->GVS[sv->StdView].MinIdleDelta ) )
7372 { /* translate */
7373 sv->GVS[sv->StdView].translateVec[0] +=
7374 (GLfloat)sv->GVS[sv->StdView].translateDeltaX;
7375 sv->GVS[sv->StdView].translateVec[1] +=
7376 (GLfloat)sv->GVS[sv->StdView].translateDeltaY;
7377 ReDisp = 1;
7378 }
7379 if (ReDisp) {
7380 /*fprintf(stdout,"Momentum Redisplay\n");*/
7381 SUMA_postRedisplay(w, NULL, NULL);
7382 }
7383 sv->X->MOMENTUMID = XtAppAddTimeOut(SUMAg_CF->X->App, 1,
7384 SUMA_momentum, (XtPointer) w);
7385
7386 SUMA_RETURNe;
7387 }
7388
7389 /*
7390 Show the buffer used to pick displayable objects (DOs) with color id
7391 The function adds a cross hair (4 white pixels) around the selection
7392 point and displays the image in AFNI's viewer (InViewer == 1) and/or
7393 save the image to an image file if OnDisk is not NULL.
7394 Set OnDisk to something like PickBuff.ppm so that you get the exact
7395 pixels rendered in the output. Consecutive images are numbered with
7396 a time stamp.
7397
7398 Note that the 4th chanel (alpha) is not shown or written to disk at
7399 the moment.
7400 */
SUMA_MarkPickInBuffer4(SUMA_SurfaceViewer * sv,int InViewer,char * OnDisk)7401 SUMA_Boolean SUMA_MarkPickInBuffer4(SUMA_SurfaceViewer *sv, int InViewer,
7402 char *OnDisk)
7403 {
7404 static char FuncName[]={"SUMA_MarkPickInBuffer4"};
7405 int n4, n3, n, p0[5],p1[5],p2[5],p3[5], i;
7406 SUMA_Boolean LocalHead = NOPE;
7407
7408 SUMA_ENTRY;
7409
7410 // fprintf(stderr, "%s\n", FuncName);
7411 if (!InViewer && !OnDisk) {
7412 SUMA_S_Err("Nothing to do here");
7413 SUMA_RETURN(NOPE);
7414 }
7415 if (!sv->pickrenpix4) {
7416 SUMA_S_Err("Empty buffer array");
7417 SUMA_RETURN(NOPE);
7418 }
7419 p0[0] = -1; /* to hold index of pixel being marked */
7420 p1[0] = -1;
7421 p2[0] = -1;
7422 p3[0] = -1;
7423
7424 n4 = sv->PickPix[1]*sv->X->aWIDTH + sv->PickPix[0];
7425 n4 = 4*n4;
7426 SUMA_LHv("User pixel selection from whole buffer:"
7427 " at %d %d is: %d %d %d %d\n",
7428 sv->PickPix[0], sv->PickPix[1],
7429 sv->pickrenpix4[n4] , sv->pickrenpix4[n4+1],
7430 sv->pickrenpix4[n4+2] , sv->pickrenpix4[n4+3]);
7431 if (sv->PickPix[1] > 0) {
7432 n4 = (sv->PickPix[1]-1)*sv->X->aWIDTH + sv->PickPix[0];
7433 n4 = 4*n4;
7434 p0[0] = n4; p0[1] = sv->pickrenpix4[n4 ]; p0[2] = sv->pickrenpix4[n4+1];
7435 p0[3] = sv->pickrenpix4[n4+2]; p0[4] = sv->pickrenpix4[n4+3];
7436 sv->pickrenpix4[n4] = sv->pickrenpix4[n4+1] =
7437 sv->pickrenpix4[n4+2] = sv->pickrenpix4[n4+3] = 255;
7438 }
7439 if (sv->PickPix[0] > 0) {
7440 n4 = sv->PickPix[1]*sv->X->aWIDTH + sv->PickPix[0]-1;
7441 n4 = 4*n4;
7442 p1[0] = n4; p1[1] = sv->pickrenpix4[n4 ]; p1[2] = sv->pickrenpix4[n4+1];
7443 p1[3] = sv->pickrenpix4[n4+2]; p1[4] = sv->pickrenpix4[n4+3];
7444 sv->pickrenpix4[n4] = sv->pickrenpix4[n4+1] =
7445 sv->pickrenpix4[n4+2] = sv->pickrenpix4[n4+3] = 255;
7446 }
7447 if (sv->PickPix[1] < (sv->X->aHEIGHT-1)) {
7448 n4 = (sv->PickPix[1]+1)*sv->X->aWIDTH + sv->PickPix[0];
7449 n4 = 4*n4;
7450 p2[0] = n4; p2[1] = sv->pickrenpix4[n4 ]; p2[2] = sv->pickrenpix4[n4+1];
7451 p2[3] = sv->pickrenpix4[n4+2]; p2[4] = sv->pickrenpix4[n4+3];
7452 sv->pickrenpix4[n4] = sv->pickrenpix4[n4+1] =
7453 sv->pickrenpix4[n4+2] = sv->pickrenpix4[n4+3] = 255;
7454 }
7455 if (sv->PickPix[0] < (sv->X->aWIDTH-1)) {
7456 n4 = sv->PickPix[1]*sv->X->aWIDTH + sv->PickPix[0]+1;
7457 n4 = 4*n4;
7458 p3[0] = n4; p3[1] = sv->pickrenpix4[n4 ]; p3[2] = sv->pickrenpix4[n4+1];
7459 p3[3] = sv->pickrenpix4[n4+2]; p3[4] = sv->pickrenpix4[n4+3];
7460 sv->pickrenpix4[n4] = sv->pickrenpix4[n4+1] =
7461 sv->pickrenpix4[n4+2] = sv->pickrenpix4[n4+3] = 255;
7462 }
7463 if (InViewer) { /* show me the money in the interactive viewer */
7464 GLubyte *pp3 = (GLubyte *)SUMA_calloc(sv->X->aWIDTH*sv->X->aHEIGHT*3,
7465 sizeof(GLubyte));
7466 for (n3=0,n=0; n<sv->X->aWIDTH*sv->X->aHEIGHT; ++n) {
7467 n4=4*n;
7468 pp3[n3++]= sv->pickrenpix4[n4++];
7469 pp3[n3++]= sv->pickrenpix4[n4++];
7470 pp3[n3++]= sv->pickrenpix4[n4++]; n4++;
7471 }
7472 ISQ_snapsave(sv->X->aWIDTH, -sv->X->aHEIGHT,
7473 (unsigned char *)pp3, sv->X->GLXAREA );
7474 SUMA_ifree(pp3);
7475 }
7476 if (OnDisk) {
7477 if (!SUMA_PixelsToDisk(sv, sv->X->aWIDTH, -sv->X->aHEIGHT,
7478 (GLvoid *)sv->pickrenpix4, 4, 1, OnDisk, 1, 0)) {
7479 SUMA_S_Err("Failed to write pix to disk");
7480 }
7481 }
7482 /* now put things back where you found them */
7483 if (p0[0] >= 0) {
7484 for (i=0; i<4; ++i) sv->pickrenpix4[p0[0]+i] = p0[1+i];
7485 }
7486 if (p1[0] >= 0) {
7487 for (i=0; i<4; ++i) sv->pickrenpix4[p1[0]+i] = p1[1+i];
7488 }
7489 if (p2[0] >= 0) {
7490 for (i=0; i<4; ++i) sv->pickrenpix4[p2[0]+i] = p2[1+i];
7491 }
7492 if (p3[0] >= 0) {
7493 for (i=0; i<4; ++i) sv->pickrenpix4[p3[0]+i] = p3[1+i];
7494 }
7495
7496 SUMA_RETURN(YUP);
7497 }
7498
7499 /*
7500 Function to return the color in the stored rendering buffer.
7501 checking is done at the pick location first, then in progressively
7502 larger neighborhoods
7503
7504 When first called, the search begins at pixel *i, *j. If nothing
7505 is found, the search proceeds within the layer limit and the first
7506 non-blank find is returned in pixhit. *i and *j are set to the newly
7507 picked location
7508
7509 i is along the width, j along the height
7510 */
SUMA_GetColidInPickBuffer4(GLubyte * pix,int Ni,int Nj,int * ii,int * ji,int maxlay,GLubyte * colid)7511 SUMA_Boolean SUMA_GetColidInPickBuffer4(GLubyte *pix, int Ni, int Nj,
7512 int *ii, int *ji,
7513 int maxlay, GLubyte *colid)
7514 {
7515 static char FuncName[]={"SUMA_GetColidInPickBuffer4"};
7516 int i0, j0, i, j, n4, k;
7517 int poff[(1+2*2)*(1+2*2)][2] = {
7518 {0,0}, {-1,0}, {-1,-1}, {0,-1}, {-1,-1}, {1,1},/*A..F*/
7519 {-2,0}, {-2,1}, {-2,-2}, {-1,-2}, {0,-2}, {-2,1},/*G..L*/
7520 {1,-1}, {0,1}, {1,0}, {-2,2}, {1,-2}, {-1,2},/*M..R*/
7521 {2,-2}, {2,-1},{0,2}, {2,0},{1,2},{2,1},{2,2} }/*S..Y*/;
7522
7523 SUMA_ENTRY;
7524
7525 // fprintf(stderr, "%s\n", FuncName);
7526
7527 if (!pix || !ii || !ji || *ii <0 || *ii >= Ni || *ji<0 || *ji>Nj) {
7528 SUMA_S_Err("Bad input");
7529 SUMA_RETURN(NOPE);
7530 }
7531 if (maxlay < 0) maxlay = 0;
7532 if (maxlay > 2) {
7533 SUMA_S_Warn("Not ready for more than two layers");
7534 maxlay = 2;
7535 }
7536
7537 i = *ii; j = *ji;
7538 n4 = 4*(i+j*Ni);
7539 if (pix[n4] || pix[n4+1] || pix[n4+2] || pix[n4+3]) {
7540 memcpy(colid, pix+n4, 4*sizeof(GLubyte));
7541 SUMA_RETURN(YUP);
7542 }
7543
7544 if (maxlay == 0) SUMA_RETURN(NOPE);
7545
7546 /* search in order shown on page 235 of labbook NIH-6
7547 The idea is to follow a search pattern based on the shape
7548 of the cursor pointing up and slightly left
7549 Actually maxlay == 1 is not quite honored here */
7550 i0 = *ii; j0 = *ji;
7551 k=1;
7552 while (k<25) {
7553 if ((i=i0+poff[k][0]) >=0 && i<Ni &&
7554 (j=j0+poff[k][0]) >=0 && j<Nj) {
7555 n4 = 4*(i+j*Ni);
7556 if (pix[n4] || pix[n4+1] || pix[n4+2] || pix[n4+3]) {
7557 memcpy(colid, pix+n4, 4*sizeof(GLubyte));
7558 *ii=i; *ji=j;
7559 SUMA_RETURN(YUP);
7560 }
7561 }
7562 ++k;
7563 }
7564 /* if nothing is found, and users want more layers, start searching in
7565 squarish patterns from layer 3 onwards, someday */
7566
7567 SUMA_RETURN(NOPE);
7568 }
7569
7570 /* if action == 0: Free saved DO picking buffer in pickrenpix4
7571 1: Recreate pickrenpix4 regardless of whether or
7572 not the new pickrenpix4 is expected to change
7573 2: Recreate pickrenpix4 only if deemed necessary
7574 */
SUMA_PickBuffer(SUMA_SurfaceViewer * sv,int action,SUMA_DO * dov)7575 SUMA_Boolean SUMA_PickBuffer(SUMA_SurfaceViewer *sv, int action, SUMA_DO *dov)
7576 {
7577 static char FuncName[]={"SUMA_PickBuffer"};
7578 int Flush = 0;
7579 SUMA_Boolean LocalHead = NOPE;
7580
7581 SUMA_ENTRY;
7582
7583 // fprintf(stderr, "%s\n", FuncName);
7584
7585 if (!sv) {
7586 SUMA_S_Err("Null sv!");
7587 SUMA_RETURN(NOPE);
7588 }
7589
7590 if ( action == 0 || /* flush only */
7591 action == 1 /* Recreate regardless */ ) {
7592 /* flush needed */
7593 SUMA_LH("Flushing pickrenpix4");
7594 Flush = 1;
7595 } else if (action == 2) { /* recreate if needed */
7596 if ( MASK_MANIP_MODE(sv) ||
7597 SUMA_DiffGeomViewStruct(sv->GVS[sv->StdView],
7598 sv->GVS_last_PickMode[sv->StdView], 1) ||
7599 sv->FOV[sv->iState] != sv->FOV_last_PickMode[sv->iState]) {
7600 SUMA_LH("Have a changed GVS or FOV, flushing pickrenpix4");
7601 Flush = 1;
7602 } else {
7603 SUMA_LH("GVS and FOV still the same");
7604 }
7605 } else {
7606 SUMA_S_Errv("Bad action value %d\n", action);
7607 SUMA_RETURN(NOPE);
7608 }
7609
7610 if (Flush) {
7611 SUMA_LHv("Flushing, action %d\n", action);
7612 if (sv->pickrenpix4) SUMA_free(sv->pickrenpix4);
7613 sv->pickrenpix4 = NULL;
7614 }
7615
7616 if (action == 0) SUMA_RETURN(YUP);
7617
7618 /* recreate if no pickrenpix4 */
7619 if (!sv->pickrenpix4) {
7620 /* record GVS and FOV states*/
7621 SUMA_CopyGeomViewStruct(&(sv->GVS[sv->StdView]),
7622 &(sv->GVS_last_PickMode[sv->StdView]));
7623 sv->FOV_last_PickMode[sv->iState] = sv->FOV[sv->iState];
7624
7625 sv->DO_PickMode = 1;
7626 SUMA_display(sv, dov);
7627 if (!(sv->pickrenpix4 =
7628 SUMA_grabPixels(4, sv->X->aWIDTH, sv->X->aHEIGHT))) {
7629 SUMA_S_Err("Failed to grab pixels");
7630 }
7631 sv->DO_PickMode = 0;
7632 }
7633 SUMA_RETURN(YUP);
7634 }
7635
SUMA_ADO_Flush_Pick_Buffer(SUMA_ALL_DO * ado,SUMA_SurfaceViewer * sv)7636 SUMA_Boolean SUMA_ADO_Flush_Pick_Buffer(SUMA_ALL_DO *ado, SUMA_SurfaceViewer *sv)
7637 {
7638 static char FuncName[]={"SUMA_ADO_Flush_Pick_Buffer"};
7639 int ii;
7640 SUMA_ENTRY;
7641
7642 // fprintf(stderr, "%s\n", FuncName);
7643
7644 if (!ado) SUMA_RETURN(NOPE);
7645 if (sv) {
7646 if (SUMA_ADO_isRegistered(sv, ado)) {
7647 SUMA_PickBuffer(sv, 0, NULL);
7648 }
7649 } else { /* Do it for all */
7650 for (ii=0; ii<SUMAg_N_SVv; ++ii) {
7651 sv = &(SUMAg_SVv[ii]);
7652 if (SUMA_ADO_isRegistered(sv, ado)) {
7653 SUMA_PickBuffer(sv, 0, NULL);
7654 }
7655 }
7656 }
7657
7658 SUMA_RETURN(YUP);
7659 }
7660
7661 /* What was picked on a frame SO ?
7662 See SUMA_Surface_Of_NIDO_Matrix() for how surface coordinates
7663 translate to matrix pixels and eventually matrix cells.
7664 See also SUMA_GDSET_edgeij_to_GMATRIX_XYZ() and SUMA_DrawGraphDO_GMATRIX()
7665 */
SUMA_WhatWasPicked_FrameSO(SUMA_SurfaceViewer * sv,int ido)7666 SUMA_PICK_RESULT *SUMA_WhatWasPicked_FrameSO(SUMA_SurfaceViewer *sv, int ido)
7667 {
7668 static char FuncName[]={"SUMA_WhatWasPicked_FrameSO"};
7669 float P0[3], P1[3];
7670 int N[3], IIm[3], ii, jj, i, *ui=NULL, *uj=NULL, si=-1, G[3], B[3], M[3];
7671 SUMA_ALL_DO *ado=NULL;
7672 SUMA_DSET *dset=NULL;
7673 SUMA_PICK_RESULT *PR = NULL;
7674 SUMA_SurfaceObject *SO=NULL;
7675 SUMA_GRAPH_SAUX *GSaux = NULL;
7676 SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL;
7677 double Aff[4][4], I[3], V[12], X[3], GB[3];
7678 SUMA_Boolean LocalHead = NOPE;
7679
7680 SUMA_ENTRY;
7681
7682 // fprintf(stderr, "%s\n", FuncName);
7683
7684 if (!sv ) {
7685 SUMA_S_Err("NULL input");
7686 SUMA_RETURN(PR);
7687 }
7688
7689 if (!iDO_isGLDO(ido) || !iDO_is_variant(ido,"GMATRIX")) {
7690 /* No frame SOs in this DO, not an error just keep looking */
7691 SUMA_LH("Not a DO with a FrameSO, go on");
7692 SUMA_RETURN(PR);
7693 }
7694
7695 SUMA_LHv("Pick Query for FrameSO on sv %p, ido %d\n", sv, ido);
7696 if (iDO_is_variant(ido,"GMATRIX") &&
7697 (GSaux = iDO_GSaux(ido))) {
7698 SO=GSaux->FrameSO;
7699 }
7700 if (!SO) {
7701 SUMA_S_Errv("No FrameSO on %s\n", iDO_label(ido));
7702 SUMA_RETURN(PR);
7703 }
7704 NI_GET_DOUBLEv(GSaux->nido->ngr, "dicom_real_to_ijk", V, 12, LocalHead);
7705 if (!NI_GOT) {
7706 SUMA_S_Err("No dicom_real_to_ijk");
7707 SUMA_RETURN(PR);
7708 }
7709 V12_TO_AFF44(Aff, V);
7710
7711 NI_GET_INTv(GSaux->nido->ngr, "Nijk", N, 3, LocalHead);
7712 if (!NI_GOT) {
7713 SUMA_S_Err("No Nijk");
7714 SUMA_RETURN(PR);
7715 }
7716
7717 /* total num of pixels per value */
7718 NI_GET_INTv(GSaux->nido->ngr, "PixCount", M, 3, LocalHead);
7719 NI_GET_INTv(GSaux->nido->ngr, "PixPerVal", G, 3, LocalHead);
7720 NI_GET_INTv(GSaux->nido->ngr, "BorWid", B, 3, LocalHead);
7721 GB[0] = G[0]+B[0];
7722 GB[1] = G[1]+B[1];
7723 GB[2] = G[2]+B[2];
7724
7725 SUMA_COPY_VEC(sv->Pick0, P0, 3, GLdouble, float);
7726 SUMA_COPY_VEC(sv->Pick1, P1, 3, GLdouble, float);
7727 if (!(MTI = SUMA_MT_intersect_triangle(P0, P1,
7728 SO->NodeList, SO->N_Node,
7729 SO->FaceSetList, SO->N_FaceSet, NULL, 0))){
7730 SUMA_S_Err("SUMA_MT_intersect_triangle failed.");
7731 SUMA_RETURN(PR);
7732 }
7733
7734 if (MTI->N_hits < 1) {
7735 SUMA_LH("No hits");
7736 SUMA_RETURN(PR);
7737 }
7738
7739 ui = uj = NULL;
7740 if (iDO_isGLDO(ido)) {
7741 if (!(dset = SUMA_find_GLDO_Dset((SUMA_GraphLinkDO*)SUMAg_DOv[ido].OP))) {
7742 SUMA_S_Err("No dset for GLDO?");
7743 SUMA_RETURN(PR);
7744 }
7745 GSaux->IgnoreSelection = 0; /* Selection being made on matrix
7746 representation of graph.
7747 turn off IgnoreSelection */
7748 switch (dset->Aux->matrix_shape) {
7749 case MAT_FULL:
7750 case MAT_TRI:
7751 case MAT_TRI_DIAG:
7752 SUMA_LH("Direct indexing between edge points and matrix row/col");
7753 break;
7754 case MAT_SPARSE:
7755 if (!dset->inel) {
7756 SUMA_S_Err("Don't have inel, badly shaped dataset");
7757 SUMA_RETURN(PR);
7758 }
7759 if ( !(ui = SUMA_GetUniqueIndicesVec(dset,1)) ||
7760 !(uj = SUMA_GetUniqueIndicesVec(dset,2)) ) {
7761 SUMA_S_Err("Failed to get unique indices");
7762 SUMA_RETURN(PR);
7763 }
7764 break;
7765 default:
7766 SUMA_S_Err("Rats");
7767 SUMA_RETURN(PR);
7768 break;
7769 }
7770 }
7771
7772
7773 PR = SUMA_New_Pick_Result(PR);
7774 PR->ado_idcode_str = SUMA_replace_string(PR->ado_idcode_str,iDO_idcode(ido));
7775 ado = SUMA_whichADOg(PR->ado_idcode_str);
7776 PR->primitive = SUMA_replace_string(PR->primitive, "none yet");
7777 PR->primitive_index = -1;
7778 PR->PickXYZ[0] = MTI->P[0];
7779 PR->PickXYZ[1] = MTI->P[1];
7780 PR->PickXYZ[2] = MTI->P[2];
7781 sv->Focus_DO_ID = ido;
7782
7783 PR->datum_index = -1;
7784 for (i=0; i<SUMA_N_IALTSEL_TYPES; ++i) PR->iAltSel[i] = -1;
7785 for (i=0; i<SUMA_N_DALTSEL_TYPES; ++i) PR->dAltSel[i] = 0.0;
7786 AFF44_MULT_I(I, Aff, MTI->P);
7787
7788 SUMA_LHv("Hit on Frame SO, triangle %d %f %f %f, M=[%d %d]\n"
7789 " Pixel hit: %.2f %.2f %.2f\n",
7790 MTI->ifacemin, MTI->P[0], MTI->P[1], MTI->P[2], M[0], M[1],
7791 I[0], I[1], I[2]);
7792
7793 for (i=0; i<3; ++i) {
7794 /* I[i] = I[i]/GB[i]; Account for per value gain and
7795 background thickness */
7796 /* Round I to get matrix pixel coordinates*/
7797 I[i] = SUMA_ROUND(I[i]);
7798 if (I[i] < 0) IIm[i] = -1;
7799 else if (I[i] >= GB[i]*N[i]) IIm[i] = -1;
7800 else IIm[i] = (int)(I[i]/GB[i]); /* Undo gain to get back to matrix grid */
7801 }
7802
7803 if (ui) { /* sparse hell */
7804 if (IIm[0]>=0) ii = ui[IIm[0]];
7805 else ii = -1;
7806 if (IIm[1]>=0) jj = uj[IIm[1]];
7807 else jj = -1;
7808 } else {
7809 ii = IIm[0]; jj=IIm[1];
7810 }
7811
7812 SUMA_LHv("In face %d X=[%f %f %f]dicom, GB=[%d %d] \n"
7813 " If=[%f %f %f], Im=[%d %d %d], ii,jj=[%d %d]\n",
7814 MTI->ifacemin, MTI->P[0], MTI->P[1], MTI->P[2],
7815 (int)GB[0], (int)GB[1],
7816 I[0], I[1], I[2], IIm[0], IIm[1], IIm[2], ii, jj);
7817
7818 switch (MTI->ifacemin) {
7819 case 0:
7820 case 1:
7821 /* in matrix */
7822 PR->primitive = SUMA_replace_string(PR->primitive, "segments");
7823 if (!ui && ii >= 0 && jj >= 0) {
7824 PR->datum_index = PR->primitive_index = ii+jj*N[0];
7825 } else { /* sparse */
7826 if (ii < 0 || jj < 0) {
7827 PR->datum_index = PR->primitive_index = -1;
7828 } else if (!SUMA_GDSET_PointsToSegIndex(dset, ii, jj, &si)) {
7829 SUMA_S_Errv("Failed to find segment for %d %d\n", ii, jj);
7830 if (LocalHead) SUMA_DUMP_TRACE("Now what?");
7831 PR->datum_index = PR->primitive_index = -1;
7832 } else {
7833 PR->datum_index = PR->primitive_index = si;
7834 }
7835 }
7836 if (MTI->ifacemin == 1) {
7837 PR->iAltSel[SUMA_ENODE_0] = ii;
7838 PR->iAltSel[SUMA_ENODE_1] = jj;
7839 } else {
7840 PR->iAltSel[SUMA_ENODE_0] = jj;
7841 PR->iAltSel[SUMA_ENODE_1] = ii;
7842 }
7843 break;
7844 case 2:
7845 case 3:
7846 /* top edge*/
7847 PR->primitive = SUMA_replace_string(PR->primitive, "balls");
7848 PR->iAltSel[SUMA_ENODE_0] = jj;
7849 PR->iAltSel[SUMA_ENODE_1] = -1;
7850 break;
7851 case 4:
7852 case 5:
7853 /* right edge*/
7854 PR->primitive = SUMA_replace_string(PR->primitive, "balls");
7855 PR->iAltSel[SUMA_ENODE_0] = ii;
7856 PR->iAltSel[SUMA_ENODE_1] = -1;
7857 break;
7858 case 6:
7859 case 7:
7860 /* bottom edge*/
7861 PR->primitive = SUMA_replace_string(PR->primitive, "balls");
7862 PR->iAltSel[SUMA_ENODE_0] = jj;
7863 PR->iAltSel[SUMA_ENODE_1] = -1;
7864 break;
7865 case 8:
7866 case 9:
7867 /* left edge*/
7868 PR->primitive = SUMA_replace_string(PR->primitive, "balls");
7869 PR->iAltSel[SUMA_ENODE_0] = ii;
7870 PR->iAltSel[SUMA_ENODE_1] = -1;
7871 break;
7872 default:
7873 SUMA_S_Errv("Faceset %d???\n", MTI->ifacemin);
7874 SUMA_RETURN(PR);
7875 }
7876
7877 MTI = SUMA_Free_MT_intersect_triangle(MTI);
7878
7879 SUMA_RETURN(PR);
7880 }
7881
7882 /*!
7883 \brief find the closest location on a bundle to a point
7884 on the screen.
7885
7886 p (void *) One bundle
7887 ptype (char): Type of bundle. 'N' --> p is a NI_element *
7888 'B' --> p is a TAYLOR_BUNDLE *
7889 Tmask (int): if not < 0 then only consider intersections in
7890 tract Tmask of the bundle.
7891 sv (SUMA_SurfaceViewer *) The viewer
7892 scpx (float *) The pixel location in screen coordinates.
7893 If NULL, form it from sv->PickPix;
7894 crude (int) if (0) then use crude search, return closest point
7895 not bothering with where along the segment
7896 between the two closest points you are
7897 1 a fine search, locating where between
7898 the two closest points one clicked
7899 tmin (int *) Will contain the index of the tract that was
7900 hit within the bundle (-1 for no cigar)
7901 pmin (int *) Will contain the index of the closest point
7902 to the hit in tract tmin
7903 fmin (float *) Will contain the fraction between pmin and
7904 pmin+1 where intersection occurred
7905 mindist (float *) Distance from closest location on tract
7906 \ret YUP all good, NOPE nothing found or bad input
7907 */
7908
SUMA_Bundle_Pick_Intersect(void * p,char ptype,int Tmask,SUMA_SurfaceViewer * sv,float * scpxu,int crude,int * tmin,int * pmin,float * frmin,float * mindistu)7909 SUMA_Boolean SUMA_Bundle_Pick_Intersect(void *p, char ptype, int Tmask,
7910 SUMA_SurfaceViewer *sv, float *scpxu, int crude,
7911 int *tmin, int *pmin, float *frmin, float *mindistu)
7912 {
7913 static char FuncName[]={"SUMA_Bundle_Pick_Intersect"};
7914 int nn, nnmin, mmmin, mm, nn_max, nn_min;
7915 float *scrxyz = NULL, dx, dy, dxy2=0.0, fmin, scpx[3];
7916 float mindist2, mindist, *A, *B;
7917 double P[3], f = 0.0;
7918 NI_element *nelitp=NULL;
7919 TAYLOR_BUNDLE *tb = NULL;
7920 TAYLOR_TRACT *ttn=NULL;
7921
7922 SUMA_ENTRY;
7923
7924 // fprintf(stderr, "%s\n", FuncName);
7925
7926 if (tmin) *tmin = -1;
7927 if (pmin) *pmin = -1;
7928 if (frmin) *frmin = -1.0;
7929 if (mindistu) *mindistu = -1.0;
7930
7931 if (!p || !sv) SUMA_RETURN(NOPE);
7932
7933 nn_min = 0;
7934 if (ptype == 'N') { /* NI_element */
7935 nelitp = (NI_element *)p;
7936 nn_max = nelitp->vec_len;
7937 } else if (ptype == 'B') { /* Taylor Bundle */
7938 tb = (TAYLOR_BUNDLE *)p;
7939 if (Tmask < 0) {
7940 nn_max = tb->N_tracts;
7941 } else {
7942 if (Tmask < tb->N_tracts) {
7943 nn_min = Tmask;
7944 nn_max = nn_min+1;
7945 } else {
7946 SUMA_S_Err("Tmask (%d) exceeds number of tracts (%d) in bundle",
7947 Tmask, tb->N_tracts);
7948 SUMA_RETURN(NOPE);
7949 }
7950 }
7951 } else {
7952 SUMA_RETURN(NOPE);
7953 }
7954
7955 nnmin=-1; mmmin=-1; mindist=mindist2=1000; fmin=1.0;
7956 if (scpxu) {
7957 scpx[0] = scpxu[0]; scpx[1] = scpxu[1]; scpx[2] = scpxu[2];
7958 } else {
7959 GLint viewport[4];
7960 glGetIntegerv(GL_VIEWPORT, viewport);
7961 /* screen pick coordinate in screen coords */
7962 scpx[0] = sv->PickPix[0];
7963 scpx[1] = viewport[3]-sv->PickPix[1]-1;
7964 scpx[2] = 0.0;
7965 }
7966
7967 for (nn=nn_min; nn<nn_max; ++nn) {
7968 if (nelitp) {
7969 ttn = (TAYLOR_TRACT *)(nelitp->vec[0])+nn;
7970 } else {
7971 ttn = tb->tracts+nn;
7972 }
7973 scrxyz = (float *)SUMA_calloc(ttn->N_pts3, sizeof(float));
7974 memcpy(scrxyz, ttn->pts, (ttn->N_pts3)*sizeof(float));
7975 /* tranform bundle points to screen space*/
7976 if (!SUMA_World2ScreenCoordsF(sv, ttn->N_pts3/3,
7977 ttn->pts, scrxyz, NULL,
7978 YUP, YUP)) {
7979 SUMA_S_Err("Failed to get screen coords");
7980 SUMA_RETURN(NOPE);
7981 }
7982 /* Now search for the closest point of bundle to the click
7983 The depth is ignored, in the hope that a simple closest
7984 search is enough. Otherwise we need to add a heuristic
7985 for the cost of depth */
7986 if (crude) {
7987 /* For finer tracing, you should project scpx onto the
7988 segment between the 1st and 2 points forming a segment,
7989 much like what is done in SUMA_PROJECT_C_ONTO_AB below
7990 The finer tracing is needed for crass paths. However
7991 for real bundles, on high-res data this might be
7992 overkill */
7993 mm=0;
7994 while (mm < ttn->N_pts3) {
7995 if ( ((dx = SUMA_ABS(scrxyz[mm ]-scpx[0])) < mindist) &&
7996 ((dy = SUMA_ABS(scrxyz[mm+1]-scpx[1])) < mindist) ){ if ((dxy2 = dx*dx+dy*dy) < mindist2) {
7997 mindist2 = dxy2;
7998 mindist = sqrtf(mindist2);
7999 nnmin=nn; mmmin=mm/3; fmin = 0.0;
8000 }
8001 }
8002 mm += 3;
8003 }
8004 } else {
8005 mm=0;
8006 while (mm < ttn->N_pts3-3) {
8007 A = scrxyz+mm;
8008 B = scrxyz+mm+3;
8009 SUMA_PROJECT_C_ONTO_AB(scpx, A, B, P, f);
8010 if ( (f > -0.2 && f < 1.2) &&
8011 ((dx = SUMA_ABS(P[0]-scpx[0])) < mindist) &&
8012 ((dy = SUMA_ABS(P[1]-scpx[1])) < mindist) ){ if ((dxy2 = dx*dx+dy*dy) < mindist2) {
8013 mindist2 = dxy2;
8014 mindist = sqrtf(mindist2);
8015 nnmin=nn; mmmin=mm/3; fmin=f;
8016 }
8017 }
8018 mm += 3;
8019 }
8020 }
8021 SUMA_ifree(scrxyz);
8022 }
8023
8024 if (tmin) *tmin=nnmin;
8025 if (pmin) *pmin=mmmin;
8026 if (frmin) *frmin=fmin;
8027 if (mindistu) *mindistu = mindist;
8028
8029 SUMA_RETURN(YUP);
8030 }
8031
8032 /* Find the object that was picked, pointer copy to found object is
8033 returned in ucodf and should not be freed by calling function*/
SUMA_WhatWasPicked(SUMA_SurfaceViewer * sv,GLubyte * colid,SUMA_COLID_OFFSET_DATUM ** ucodf,int ipick,int jpick,SUMA_PICK_RESULT * PR)8034 SUMA_PICK_RESULT *SUMA_WhatWasPicked(SUMA_SurfaceViewer *sv, GLubyte *colid,
8035 SUMA_COLID_OFFSET_DATUM **ucodf,
8036 int ipick, int jpick,
8037 SUMA_PICK_RESULT *PR)
8038 {
8039 static char FuncName[]={"SUMA_WhatWasPicked"};
8040 DListElmt *el=NULL;
8041 SUMA_COLID_OFFSET_DATUM *cod=NULL, *codf=NULL;
8042 long int n4;
8043 int iii;
8044 double f = 0.0;
8045 SUMA_ALL_DO *ado=NULL;
8046 SUMA_DUMB_DO DDO;
8047 SUMA_Boolean LocalHead = NOPE;
8048
8049 SUMA_ENTRY;
8050
8051 // fprintf(stderr, "%s\n", FuncName);
8052
8053 if (ucodf) *ucodf=codf;
8054 PR = SUMA_New_Pick_Result(PR);
8055 if (!sv || !colid) {
8056 SUMA_S_Err("NULL input");
8057 SUMA_RETURN(PR);
8058 }
8059 if (!sv->pick_colid_list || !dlist_size(sv->pick_colid_list)) {
8060 SUMA_S_Err("NULL or Empty pick_colid_list");
8061 SUMA_RETURN(PR);
8062 }
8063 if (LocalHead) SUMA_Show_Pick_Colid_List(sv->pick_colid_list, SUMA_STDERR);
8064 SUMA_COLID_RGBA2N(colid[0], colid[1], colid[2], colid[3], n4);
8065 do {
8066 if (!el) el = dlist_head(sv->pick_colid_list);
8067 else el = dlist_next(el);
8068 cod = (SUMA_COLID_OFFSET_DATUM *)el->data;
8069 if (n4>= cod->i0 && n4<= cod->i1) { /* we're in this object */
8070 codf = cod;
8071 }
8072 } while (!codf && el != dlist_tail(sv->pick_colid_list));
8073
8074 if (!codf) SUMA_RETURN(PR);
8075 if (ucodf) *ucodf=codf;
8076
8077 /* Compute get more info about intersection */
8078 if (codf) {
8079 NI_element *nelitp=NULL;
8080 float *fv=NULL;
8081 double xyzw[9], scl[9], U[3], P[3], C[3], *dv=NULL;
8082 int i0, i1, ir, datum_index;
8083 SUMA_ALL_DO *ado=NULL;
8084 SUMA_DSET *dset=NULL;
8085 GLint viewport[4];
8086 SUMA_GRAPH_SAUX *GSaux = NULL;
8087
8088 glGetIntegerv(GL_VIEWPORT, viewport);
8089 PR->ado_idcode_str = SUMA_replace_string(PR->ado_idcode_str,
8090 codf->ref_idcode_str);
8091 PR->primitive = SUMA_replace_string(PR->primitive, codf->primitive);
8092 PR->primitive_index = (n4-codf->i0);
8093 for (i0=0; i0<SUMA_N_IALTSEL_TYPES; ++i0) PR->iAltSel[i0] = -1;
8094 for (i0=0; i0<SUMA_N_DALTSEL_TYPES; ++i0) PR->dAltSel[i0] = 0.0;
8095 PR->datum_index = -1;
8096 ado = SUMA_whichADOg(PR->ado_idcode_str);
8097 switch (codf->ref_do_type) {
8098 case GRAPH_LINK_type: {
8099 dset = SUMA_find_GLDO_Dset((SUMA_GraphLinkDO*)ado);
8100 DDO.err = 1; SUMA_Load_Dumb_DO(ado, &DDO);
8101 if (DDO.err) {
8102 if (DDO.err==1) {
8103 SUMA_SL_Err("Object's parent graph set not found.");
8104 } else if (DDO.err==2) {
8105 SUMA_SL_Err("Could not fill DDO");
8106 } else {
8107 SUMA_SL_Err("Weird error.");
8108 }
8109 SUMA_RETURN (PR);
8110 }
8111 if (!DDO.NodeList) {
8112 SUMA_S_Err("SDO is node based but could not get a NodeList");
8113 SUMA_RETURN (PR);
8114 }
8115 if (!(GSaux = SDSET_GSAUX(dset))) {
8116 SUMA_S_Err("No GSaux");
8117 SUMA_RETURN(PR);
8118 }
8119 GSaux->IgnoreSelection = 0; /*reset ignore selection flag */
8120 if (SUMA_is_ADO_Datum_Primitive(ado, codf)) {
8121 datum_index = SUMA_GDSET_EdgeRow_To_Index(dset,
8122 PR->primitive_index);
8123 if (!(SUMA_GDSET_SegIndexToPoints(dset, datum_index,
8124 &i0, &i1, NULL))) {
8125 SUMA_RETURN(PR);
8126 }
8127 nelitp = NULL;
8128 if (GSaux->ShowBundles &&
8129 (nelitp = SUMA_GDSET_Edge_Bundle(dset, GSaux,
8130 datum_index, -1))) {
8131 #if 1 /* more unified version, older, valid one below */
8132 int nn=0, mm=0, nnmin=-1, mmmin=-1, mmmin3=-1;
8133 float scpx[3], *A, *B;
8134 float mindist, dist, distatmin, seglen;
8135 float fmin;
8136 TAYLOR_TRACT *ttn=NULL;
8137
8138 SUMA_LHv("Clicked on a bundle representation of edge %d.\n",
8139 datum_index);
8140 /* screen pick coordinate in screen coords */
8141 scpx[0] = sv->PickPix[0];
8142 scpx[1] = viewport[3]-sv->PickPix[1]-1;
8143 scpx[2] = 0.0;
8144 /* find the closest point to where we clicked on the bundle */
8145 if (!SUMA_Bundle_Pick_Intersect(nelitp, 'N', -1, sv, scpx, 0,
8146 &nnmin, &mmmin,
8147 &fmin, &mindist)) {
8148 SUMA_LH("No bunlde intersection");
8149 }
8150 mmmin3 = 3*mmmin;
8151 if (nnmin > -1) {
8152 ttn = (TAYLOR_TRACT *)(nelitp->vec[0])+nnmin;
8153 if (fmin != 0.0f) {
8154 PR->PickXYZ[0]=ttn->pts[mmmin3+0]+
8155 fmin*(ttn->pts[mmmin3+3]-ttn->pts[mmmin3]);
8156 PR->PickXYZ[1]=ttn->pts[mmmin3+1]+
8157 fmin*(ttn->pts[mmmin3+4]-ttn->pts[mmmin3+1]);
8158 PR->PickXYZ[2]=ttn->pts[mmmin3+2]+
8159 fmin*(ttn->pts[mmmin3+5]-ttn->pts[mmmin3+2]);
8160 /* where along the tract? */
8161 mm=0; dist=0.0; distatmin=19999.9;
8162 while (mm < ttn->N_pts3-3) {
8163 A = ttn->pts+mm;
8164 B = ttn->pts+mm+3;
8165 seglen = sqrtf((B[0]-A[0])*(B[0]-A[0])+
8166 (B[1]-A[1])*(B[1]-A[1])+
8167 (B[2]-A[2])*(B[2]-A[2]));
8168 if (mm==mmmin3) {
8169 distatmin = dist + fmin*seglen;
8170 }
8171 dist +=seglen;
8172 mm += 3;
8173 }
8174 /* Which is the closest node? */
8175 f = distatmin/dist;
8176 if (f <= 0.5) {
8177 PR->iAltSel[SUMA_ENODE_0] = i0;
8178 PR->iAltSel[SUMA_ENODE_0] = i1;
8179 if (SUMA_ABS(f)> 0.01) {/* not too close to edge */
8180 PR->datum_index = datum_index;
8181 } else PR->datum_index = -1;
8182 } else {
8183 SUMA_LHv("++half way, look for opp. edge [%d %d]\n",
8184 i1, i0);
8185 PR->iAltSel[SUMA_ENODE_0] = i1;
8186 PR->iAltSel[SUMA_ENODE_1] = i0;
8187
8188 if (SUMA_ABS(1.0-f) > 0.01){/*not too close to edge*/
8189 /* does edge [i1, i0] exist? If so take it*/
8190 if (SUMA_GDSET_PointsToSegIndex(dset,i1,i0,&ir)) {
8191 SUMA_LHv("Switching primitve to edge %d\n", ir);
8192 PR->datum_index = ir;
8193 } else { /* leave old hit, no opposite edge */
8194 PR->datum_index = datum_index;
8195 }
8196 } else PR->datum_index = -1;
8197 }
8198 } else { /* from the quick search, no fmin used*/
8199 PR->PickXYZ[0]=ttn->pts[mmmin3+0];
8200 PR->PickXYZ[1]=ttn->pts[mmmin3+1];
8201 PR->PickXYZ[2]=ttn->pts[mmmin3+2];
8202 }
8203 } else {
8204 PR->PickXYZ[0] = PR->PickXYZ[1] = PR->PickXYZ[2]=0.0;
8205 }
8206 SUMA_LHv("Closest distance of %f, tract %d, point %d, f=%f\n"
8207 "at world [%f %f %f]\n",
8208 mindist, nnmin, mmmin, fmin,
8209 PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2]);
8210 #else
8211 int nn=0, mm=0, nnmin=-1, mmmin=-1;
8212 float *scrxyz = NULL, scpx[3], *A, *B;
8213 float mindist, mindist2, dist, distatmin, seglen;
8214 float dx, dy, dxy2=0.0, fmin;
8215 TAYLOR_TRACT *ttn=NULL;
8216
8217 SUMA_LHv("Clicked on a bundle representation of edge %d.\n",
8218 datum_index);
8219 /* screen pick coordinate in screen coords */
8220 scpx[0] = sv->PickPix[0];
8221 scpx[1] = viewport[3]-sv->PickPix[1]-1;
8222 scpx[2] = 0.0;
8223 /* find the closest point to where we clicked on the bundle */
8224 nnmin=-1; mmmin=-1; mindist=mindist2=1000; fmin=1.0;
8225 for (nn=0; nn<nelitp->vec_len; ++nn) {
8226 ttn = (TAYLOR_TRACT *)(nelitp->vec[0])+nn;
8227 scrxyz = (float *)SUMA_calloc(ttn->N_pts3, sizeof(float));
8228 memcpy(scrxyz, ttn->pts, (ttn->N_pts3)*sizeof(float));
8229 /* tranform bundle points to screen space*/
8230 if (!SUMA_World2ScreenCoordsF(sv, ttn->N_pts3/3,
8231 ttn->pts, scrxyz, NULL,
8232 YUP, YUP)) {
8233 SUMA_S_Err("Failed to get screen coords");
8234 SUMA_RETURN(PR);
8235 }
8236 /* Now search for the closest point of bundle to the click
8237 The depth is ignored, in the hope that a simple closest
8238 search is enough. Otherwise we need to add a heuristic
8239 for the cost of depth */
8240 #ifdef CRUDE_SEARCH
8241 /* For finer tracing, you should project scpx onto the
8242 segment between the 1st and 2 points forming a segment,
8243 much like what is done in SUMA_PROJECT_C_ONTO_AB below
8244 The finer tracing is needed for crass paths. However
8245 for real bundles, on high-res data this might be
8246 overkill */
8247 mm=0;
8248 while (mm < ttn->N_pts3) {
8249 if ( ((dx = SUMA_ABS(scrxyz[mm ]-scpx[0])) < mindist) &&
8250 ((dy = SUMA_ABS(scrxyz[mm+1]-scpx[1])) < mindist) ){ if ((dxy2 = dx*dx+dy*dy) < mindist2) {
8251 mindist2 = dxy2;
8252 mindist = sqrtf(mindist2);
8253 nnmin=nn; mmmin=mm; fmin = 0.0;
8254 }
8255 }
8256 mm += 3;
8257 }
8258 #else
8259 mm=0;
8260 while (mm < ttn->N_pts3-3) {
8261 A = scrxyz+mm;
8262 B = scrxyz+mm+3;
8263 SUMA_PROJECT_C_ONTO_AB(scpx, A, B, P, f);
8264 if ( ((dx = SUMA_ABS(P[0]-scpx[0])) < mindist) &&
8265 ((dy = SUMA_ABS(P[1]-scpx[1])) < mindist) ){ if ((dxy2 = dx*dx+dy*dy) < mindist2) {
8266 mindist2 = dxy2;
8267 mindist = sqrtf(mindist2);
8268 nnmin=nn; mmmin=mm; fmin=f;
8269 }
8270 }
8271 mm += 3;
8272 }
8273 #endif
8274 SUMA_ifree(scrxyz);
8275 }
8276 if (nnmin > -1) {
8277 ttn = (TAYLOR_TRACT *)(nelitp->vec[0])+nnmin;
8278 if (fmin != 0.0f) {
8279 PR->PickXYZ[0]=ttn->pts[mmmin+0]+
8280 fmin*(ttn->pts[mmmin+3]-ttn->pts[mmmin]);
8281 PR->PickXYZ[1]=ttn->pts[mmmin+1]+
8282 fmin*(ttn->pts[mmmin+4]-ttn->pts[mmmin+1]);
8283 PR->PickXYZ[2]=ttn->pts[mmmin+2]+
8284 fmin*(ttn->pts[mmmin+5]-ttn->pts[mmmin+2]);
8285 /* where along the tract? */
8286 mm=0; dist=0.0; distatmin=19999.9;
8287 while (mm < ttn->N_pts3-3) {
8288 A = ttn->pts+mm;
8289 B = ttn->pts+mm+3;
8290 seglen = sqrtf((B[0]-A[0])*(B[0]-A[0])+
8291 (B[1]-A[1])*(B[1]-A[1])+
8292 (B[2]-A[2])*(B[2]-A[2]));
8293 if (mm==mmmin) {
8294 distatmin = dist + fmin*seglen;
8295 }
8296 dist +=seglen;
8297 mm += 3;
8298 }
8299 /* Which is the closest node? */
8300 f = distatmin/dist;
8301 if (f <= 0.5) {
8302 PR->iAltSel[SUMA_ENODE_0] = i0;
8303 PR->iAltSel[SUMA_ENODE_1] = i1;
8304
8305 if (SUMA_ABS(f)> 0.01) {/* not too close to edge */
8306 PR->datum_index = datum_index;
8307 } else PR->datum_index = -1;
8308 } else {
8309 SUMA_LHv("++half way, look for opp. edge [%d %d]\n",
8310 i1, i0);
8311 PR->iAltSel[SUMA_ENODE_0] = i1;
8312 PR->iAltSel[SUMA_ENODE_1] = i0;
8313 if (SUMA_ABS(1.0-f) > 0.01){/*not too close to edge*/
8314 /* does edge [i1, i0] exist? If so take it*/
8315 if (SUMA_GDSET_PointsToSegIndex(dset,i1,i0,&ir)) {
8316 SUMA_LHv("Switching primitve to edge %d\n", ir);
8317 PR->datum_index = ir;
8318 } else { /* leave old hit, no opposite edge */
8319 PR->datum_index = datum_index;
8320 }
8321 } else PR->datum_index = -1;
8322 }
8323 } else { /* from the quick search, no fmin used*/
8324 PR->PickXYZ[0]=ttn->pts[mmmin+0];
8325 PR->PickXYZ[1]=ttn->pts[mmmin+1];
8326 PR->PickXYZ[2]=ttn->pts[mmmin+2];
8327 }
8328 } else {
8329 PR->PickXYZ[0] = PR->PickXYZ[1] = PR->PickXYZ[2]=0.0;
8330 }
8331 SUMA_LHv("Closest distance of %f, tract %d, point %d, f=%f\n"
8332 "at world [%f %f %f]\n",
8333 mindist, nnmin, mmmin, fmin,
8334 PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2]);
8335
8336 #endif
8337 } else {
8338 SUMA_LHv("Segment %d is formed by points %d and %d\n",
8339 datum_index, i0, i1);
8340 fv = SUMA_GDSET_NodeXYZ(dset, i0, SUMA_ADO_variant(ado), NULL);
8341 xyzw[0] = fv[0]; xyzw[1] = fv[1]; xyzw[2] = fv[2];
8342 fv = SUMA_GDSET_NodeXYZ(dset, i1, SUMA_ADO_variant(ado), NULL);
8343 xyzw[3] = fv[0]; xyzw[4] = fv[1]; xyzw[5] = fv[2];
8344 xyzw[6] = (sv->Pick0[0]+sv->Pick1[0])/2.0;
8345 xyzw[7] = (sv->Pick0[1]+sv->Pick1[1])/2.0;
8346 xyzw[8] = (sv->Pick0[2]+sv->Pick1[2])/2.0;
8347
8348 if (!SUMA_World2ScreenCoords(sv, 3,xyzw,scl, NULL, YUP, YUP)) {
8349 SUMA_S_Err("Failed to get screen coords");
8350 SUMA_RETURN(PR);
8351 }
8352 /* Project click point onto line by two nodes */
8353 C[0] = sv->PickPix[0];
8354 C[1] = viewport[3]-sv->PickPix[1]-1;
8355 C[2] = 0;
8356 dv = scl+3; /* point B */
8357 SUMA_PROJECT_C_ONTO_AB(C, scl, dv, P, f);
8358 /* Project point click onto segment */
8359 SUMA_LHv(
8360 "User click locations: %d %d Norm(%f %f)\n"
8361 "sv PickPix: %d %d (screen/mouse y:%d)\n"
8362 "world: near[%f %f %f] far[%f %f %f]\n"
8363 "Edge %d formed by nodes %d [%f %f %f], %d [%f %f %f]\n"
8364 "Nodes projected to screen: [%f %f %f], [%f %f %f]\n"
8365 "Projection of click point screen edge: [%f %f %f], f = %f\n"
8366 ,ipick, jpick,
8367 ipick/(double)viewport[2], jpick/(double)viewport[3],
8368 sv->PickPix[0], sv->PickPix[1], viewport[3]-jpick-1,
8369 sv->Pick0[0], sv->Pick0[1], sv->Pick0[2],
8370 sv->Pick1[0], sv->Pick1[1], sv->Pick1[2],
8371 datum_index, i0, xyzw[0], xyzw[1], xyzw[2],
8372 i1, xyzw[3], xyzw[4], xyzw[5],
8373 scl[0], scl[1], scl[2], scl[3], scl[4], scl[5],
8374 P[0], P[1], P[2], f);
8375
8376 /* Record the intersection location */
8377 PR->PickXYZ[0]=xyzw[0]+f*(xyzw[3]-xyzw[0]);
8378 PR->PickXYZ[1]=xyzw[1]+f*(xyzw[4]-xyzw[1]);
8379 PR->PickXYZ[2]=xyzw[2]+f*(xyzw[5]-xyzw[2]);
8380
8381 /* Which is the closest node? */
8382 if (f <= 0.5) {
8383 PR->iAltSel[SUMA_ENODE_0] = i0;
8384 PR->iAltSel[SUMA_ENODE_1] = i1;
8385 if (SUMA_ABS(f)> 0.01) {/* not too close to edge */
8386 PR->datum_index = datum_index;
8387 } else PR->datum_index = -1;
8388 } else {
8389 SUMA_LHv("++half way, looking for opp. edge [%d %d]\n",
8390 i1, i0);
8391 PR->iAltSel[SUMA_ENODE_0] = i1;
8392 PR->iAltSel[SUMA_ENODE_1] = i0;
8393 if (SUMA_ABS(1.0-f) > 0.01) { /* not too close to edge */
8394 /* does edge [i1, i0] exist? If so take it*/
8395 if (SUMA_GDSET_PointsToSegIndex(dset, i1, i0, &ir)) {
8396 SUMA_LHv("Switching primitve to edge %d\n", ir);
8397 PR->datum_index = ir;
8398 } else { /* leave old hit, no opposite edge */
8399 PR->datum_index = datum_index;
8400 }
8401 } else PR->datum_index = -1;
8402 }
8403 }
8404 } else { /* picked a node, no data on it*/
8405 PR->iAltSel[SUMA_ENODE_0] =
8406 SUMA_GDSET_Index_To_NodeIndex(dset, PR->primitive_index);
8407 PR->iAltSel[SUMA_ENODE_1] = -1;
8408 PR->datum_index = -1;
8409 fv = SUMA_GDSET_NodeXYZ(dset, PR->iAltSel[SUMA_ENODE_0],
8410 SUMA_ADO_variant(ado), NULL);
8411 PR->PickXYZ[0]=fv[0]; PR->PickXYZ[1]=fv[1]; PR->PickXYZ[2]=fv[2];
8412 }
8413 break; }
8414 case GDSET_type:
8415 SUMA_S_Err("I don't expect graph dsets to be picked directly");
8416 break;
8417 case CDOM_type:
8418 SUMA_S_Err("CIFTI not picked on buffer");
8419 break;
8420 case VO_type:
8421 SUMA_S_Err("VOs not picked on buffer....");
8422 break;
8423 case MASK_type:
8424 SUMA_S_Err("Masks not picked on buffer....");
8425 break;
8426 case TRACT_type:
8427 {
8428 SUMA_TractDO *tdo=(SUMA_TractDO *)ado;
8429 int nn=0, mm=0, nnmin=-1, mmmin=-1, mmmin3=-1, oki=0, it=0, ib=0;
8430 float *scrxyz = NULL;
8431 float mindist, dist;
8432 float fmin;
8433 TAYLOR_TRACT *ttn=NULL;
8434 TAYLOR_BUNDLE *tb=NULL;
8435
8436 oki = 0;
8437 if (!strcmp(PR->primitive,"bundles")) {
8438 ib = PR->primitive_index;
8439 SUMA_LHv("Seeking bundle %d/%d\n",
8440 (int)PR->primitive_index, tdo->net->N_tbv);
8441 tb = TDO_BUNDLE(tdo, PR->primitive_index);
8442 if (!(oki=SUMA_Bundle_Pick_Intersect(tb, 'B', -1, sv, NULL, 0,
8443 &nnmin, &mmmin, &fmin, &mindist))) {
8444 SUMA_LH("No bunlde intersection");
8445 }
8446 } else if (!strcmp(PR->primitive,"tracts")) {
8447 SUMA_LHv("Seeking tract %d/%d\n",
8448 (int)PR->primitive_index, TDO_N_TRACTS(tdo));
8449 if (Network_1T_to_TB(tdo->net,
8450 (int)PR->primitive_index, &it, &ib, NULL, NULL) < 0) {
8451 SUMA_S_Err("Failed to resolve tract index");
8452 } else {
8453 tb = TDO_BUNDLE(tdo, ib);
8454 if (!(oki=SUMA_Bundle_Pick_Intersect(tb, 'B', it, sv, NULL, 0,
8455 &nnmin, &mmmin, &fmin, &mindist))) {
8456 SUMA_LH("No tract intersection");
8457 }
8458 }
8459 }
8460 if (oki) {
8461 if (nnmin > -1) {
8462 mmmin3=3*mmmin;
8463 ttn = tb->tracts+nnmin;
8464 if (fmin != 0.0f) {
8465 PR->PickXYZ[0]=ttn->pts[mmmin3+0]+
8466 fmin*(ttn->pts[mmmin3+3]-ttn->pts[mmmin3]);
8467 PR->PickXYZ[1]=ttn->pts[mmmin3+1]+
8468 fmin*(ttn->pts[mmmin3+4]-ttn->pts[mmmin3+1]);
8469 PR->PickXYZ[2]=ttn->pts[mmmin3+2]+
8470 fmin*(ttn->pts[mmmin3+5]-ttn->pts[mmmin3+2]);
8471 } else {
8472 /* from the quick search, no fmin used*/
8473 PR->PickXYZ[0]=ttn->pts[mmmin3+0];
8474 PR->PickXYZ[1]=ttn->pts[mmmin3+1];
8475 PR->PickXYZ[2]=ttn->pts[mmmin3+2];
8476 }
8477 PR->iAltSel[SUMA_TRC_PNT] = mmmin;
8478 PR->iAltSel[SUMA_BUN_TRC] = nnmin;
8479 PR->iAltSel[SUMA_NET_BUN] = ib;
8480 PR->datum_index = Network_PTB_to_1P(tdo->net,
8481 PR->iAltSel[SUMA_TRC_PNT],
8482 PR->iAltSel[SUMA_BUN_TRC],
8483 PR->iAltSel[SUMA_NET_BUN]);
8484 PR->iAltSel[SUMA_NET_TRC] = Network_TB_to_1T(tdo->net,
8485 PR->iAltSel[SUMA_BUN_TRC],
8486 PR->iAltSel[SUMA_NET_BUN]);
8487 SUMA_LHv("Bundle %ld intersected, tract %ld, "
8488 "point %ld, tract in net %ld. \n"
8489 "Point NetID: %ld\n"
8490 "XYZ[%.3f %.3f %.3f], fmin=%f\n",
8491 PR->iAltSel[SUMA_NET_BUN],
8492 PR->iAltSel[SUMA_BUN_TRC],
8493 PR->iAltSel[SUMA_TRC_PNT],
8494 PR->iAltSel[SUMA_NET_TRC], PR->datum_index,
8495 PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2], fmin);
8496
8497 #if 0 /* Just to debug reverse lookup */
8498 if (Network_1P_to_PTB(tdo->net, PR->datum_index,
8499 &mmmin, &nnmin, &nn, NULL) < 0) {
8500 SUMA_S_Err("Failed in reverse lookup test");
8501 } else {
8502 SUMA_LHv("Inverse lookup: %ld --> P %d, T %d, B %d\n",
8503 PR->datum_index, mmmin, nnmin, nn);
8504 }
8505 #endif
8506 }
8507 }
8508 f = fmin;
8509 break; }
8510 default:
8511 SUMA_S_Warnv("Not ready to get location for %s\n",
8512 SUMA_ObjectTypeCode2ObjectTypeName(codf->ref_do_type));
8513 break;
8514 }
8515 }
8516
8517 /* report */
8518 if (codf) {
8519 SUMA_S_Notev("\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n"
8520 "DO pick: colid (%ld=[%d %d %d %d]) \n"
8521 " is in <%s, %s, %s>, f=%1.3f\n"
8522 " datum = %ld, iAltSel = [",
8523 n4, colid[0], colid[1], colid[2], colid[3],
8524 cod->Label, cod->variant, cod->primitive, f,
8525 PR->datum_index);
8526 for (iii=0; iii<SUMA_N_IALTSEL_TYPES; ++iii)
8527 fprintf(SUMA_STDOUT, "%ld, ", PR->iAltSel[iii]);
8528 fprintf(SUMA_STDOUT, "]\n dAltSel = [");
8529 for (iii=0; iii<SUMA_N_DALTSEL_TYPES; ++iii)
8530 fprintf(SUMA_STDOUT, "%.3f, ", PR->dAltSel[iii]);
8531 fprintf(SUMA_STDOUT, "]\n"
8532 "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
8533 }
8534
8535 SUMA_RETURN(PR);
8536 }
8537
SUMA_New_Pick_Result(SUMA_PICK_RESULT * PR)8538 SUMA_PICK_RESULT *SUMA_New_Pick_Result(SUMA_PICK_RESULT *PR)
8539 {
8540 static char FuncName[]={"SUMA_New_Pick_Result"};
8541
8542 // fprintf(stderr, "%s\n", FuncName);
8543 int i;
8544 if (!PR) {
8545 PR = (SUMA_PICK_RESULT *)SUMA_calloc(1,sizeof(SUMA_PICK_RESULT));
8546 }
8547 PR->primitive_index = -1;
8548 PR->datum_index = -1;
8549 for (i=0; i<SUMA_N_IALTSEL_TYPES; ++i) PR->iAltSel[i] = -1;
8550 for (i=0; i<SUMA_N_DALTSEL_TYPES; ++i) PR->dAltSel[i] = 0.0;
8551 SUMA_ifree(PR->primitive);
8552 SUMA_ifree(PR->ado_idcode_str);
8553 /* Imprint with event structure */
8554 PR->evr = (SUMA_EVENT *)malloc(sizeof(SUMA_EVENT));
8555 if (SUMAg_CF->lev) memcpy(PR->evr, SUMAg_CF->lev, sizeof(SUMA_EVENT));
8556 else memset(PR->evr, 0, sizeof(SUMA_EVENT));
8557 /* SUMA_ShowEvent(PR->evr, 0, "From New Pick Result\n"); */
8558 return(PR);
8559 }
8560
SUMA_free_PickResult(SUMA_PICK_RESULT * PR)8561 SUMA_PICK_RESULT *SUMA_free_PickResult(SUMA_PICK_RESULT *PR)
8562 {
8563 static char FuncName[]={"SUMA_free_PickResult"};
8564 SUMA_ENTRY;
8565
8566 if (!PR) SUMA_RETURN(PR);
8567
8568 if (SUMAg_CF->clippingPlaneVerbose && SUMAg_CF->clippingPlaneVerbosityLevel>1)
8569 fprintf(stderr, "### SUMA_free_PickResult: Free PR->primitive\n");
8570 if (PR->primitive) SUMA_ifree(PR->primitive);
8571 if (SUMAg_CF->clippingPlaneVerbose && SUMAg_CF->clippingPlaneVerbosityLevel>1)
8572 fprintf(stderr, "### SUMA_free_PickResult: Free PR->ado_idcode_str\n");
8573 if (PR->ado_idcode_str) SUMA_ifree(PR->ado_idcode_str);
8574 if (SUMAg_CF->clippingPlaneVerbose && SUMAg_CF->clippingPlaneVerbosityLevel>1)
8575 fprintf(stderr, "### SUMA_free_PickResult: Free PR->dset_idcode_str\n");
8576 if (PR->dset_idcode_str){
8577 SUMA_ifree(PR->dset_idcode_str);
8578 if (SUMAg_CF->clippingPlaneVerbose && SUMAg_CF->clippingPlaneVerbosityLevel>1)
8579 fprintf(stderr, "### SUMA_free_PickResult: Free PR->evr\n");
8580 if (PR->evr) SUMA_ifree(PR->evr);
8581 }
8582
8583 SUMA_free(PR);
8584
8585 SUMA_RETURN(NULL);
8586 }
8587
SUMA_ADO_StorePickResult(SUMA_ALL_DO * ado,SUMA_PICK_RESULT ** PRP)8588 SUMA_Boolean SUMA_ADO_StorePickResult(SUMA_ALL_DO *ado, SUMA_PICK_RESULT **PRP)
8589 {
8590 static char FuncName[]={"SUMA_ADO_StorePickResult"};
8591
8592 SUMA_ENTRY;
8593
8594 // fprintf(stderr, "%s\n", FuncName);
8595
8596 if (!PRP || !*PRP) SUMA_RETURN(NOPE);
8597
8598 switch (ado->do_type) {
8599 case SO_type: {
8600 SUMA_SURF_SAUX *Saux = SUMA_ADO_SSaux(ado);
8601 if (!Saux){
8602 SUMA_S_Err("NULL Saux!!!, don't let that happen");
8603 SUMA_RETURN(NOPE);
8604 }
8605 if (SUMAg_CF->clippingPlaneVerbose && SUMAg_CF->clippingPlaneVerbosityLevel>1)
8606 fprintf(stderr, "### SUMA_free_PickResult\n");
8607 SUMA_free_PickResult(Saux->PR);
8608 Saux->PR = *PRP; *PRP = NULL;
8609 SUMA_RETURN(YUP);
8610 break; }
8611 case CDOM_type: {
8612 SUMA_CIFTI_SAUX *Saux = SUMA_ADO_CSaux(ado);
8613 SUMA_free_PickResult(Saux->PR);
8614 Saux->PR = *PRP; *PRP = NULL;
8615 SUMA_RETURN(YUP);
8616 break; }
8617 case GDSET_type: {
8618 SUMA_DSET *dset=(SUMA_DSET *)ado;
8619 SUMA_GRAPH_SAUX *Saux = SDSET_GSAUX(dset);
8620 /* Is the selection type changed? If so, then
8621 you need to flush the pick buffer */
8622
8623 if (Saux->PR) {
8624 if ( (Saux->PR->datum_index * (*PRP)->datum_index < 0) ||
8625 ((*PRP)->datum_index == -1 &&
8626 (Saux->PR->iAltSel[SUMA_ENODE_0] !=
8627 (*PRP)->iAltSel[SUMA_ENODE_0])) ) {
8628 /* Going from edge selection to node selection, in general
8629 But there is no need to get picky */
8630 SUMA_FlushPickBufferForDO((SUMA_ALL_DO *)SUMA_find_Dset_GLDO(dset,
8631 "G3D",NULL));
8632 }
8633 }
8634 SUMA_free_PickResult(Saux->PR);
8635 Saux->PR = *PRP; *PRP = NULL;
8636 SUMA_RETURN(YUP);
8637 break; }
8638 case GRAPH_LINK_type:
8639 SUMA_RETURN(SUMA_ADO_StorePickResult(
8640 (SUMA_ALL_DO*)SUMA_find_GLDO_Dset(
8641 (SUMA_GraphLinkDO*)ado),PRP));
8642 break;
8643 case TRACT_type: {
8644 SUMA_TRACT_SAUX *Saux = SUMA_ADO_TSaux(ado);
8645 SUMA_free_PickResult(Saux->PR);
8646 Saux->PR = *PRP; *PRP = NULL;
8647 SUMA_RETURN(YUP);
8648 break; }
8649 case MASK_type: {
8650 SUMA_MASK_SAUX *Saux = SUMA_ADO_MSaux(ado);
8651 if (Saux) {
8652 SUMA_free_PickResult(Saux->PR);
8653 Saux->PR = *PRP; *PRP = NULL;
8654 } else {
8655 SUMA_S_Err("NULL Saux!!!, don't let that happen");
8656 SUMA_RETURN(NOPE);
8657 }
8658 SUMA_RETURN(YUP);
8659 break; }
8660 case VO_type: {
8661 SUMA_VOL_SAUX *Saux = SUMA_ADO_VSaux(ado);
8662 if (!(*PRP)->primitive) {
8663 SUMA_S_Err("NULL primitve not acceptable for VOs");
8664 break;
8665 }
8666 if (!strcmp((*PRP)->primitive,"voxel")) {
8667 SUMA_free_PickResult(Saux->PR);
8668 Saux->PR = *PRP; *PRP = NULL;
8669 SUMA_RETURN(YUP);
8670 } else if (!strcmp((*PRP)->primitive,"cutplane")) {
8671 SUMA_free_PickResult(Saux->PRc);
8672 Saux->PRc = *PRP; *PRP = NULL;
8673 SUMA_RETURN(YUP);
8674 } else {
8675 SUMA_S_Err("Bad primitive %s for VO", (*PRP)->primitive);
8676 SUMA_DUMP_TRACE("Who dunit?");
8677 }
8678 break; }
8679 default:
8680 SUMA_S_Errv("Note ready for type %s\n", ADO_TNAME(ado));
8681 break;
8682 }
8683 SUMA_RETURN(NOPE);
8684 }
8685
SUMA_ADO_GetPickResult(SUMA_ALL_DO * ado,char * primitive)8686 SUMA_PICK_RESULT * SUMA_ADO_GetPickResult(SUMA_ALL_DO *ado, char *primitive)
8687 {
8688 static char FuncName[]={"SUMA_ADO_GetPickResult"};
8689 SUMA_PICK_RESULT *PR=NULL;
8690
8691 SUMA_ENTRY;
8692
8693 // fprintf(stderr, "%s\n", FuncName);
8694
8695 if (!ado) SUMA_RETURN(NULL);
8696 if (!primitive) primitive = "none";
8697
8698 switch (ado->do_type) {
8699 case SO_type:{
8700 SUMA_SURF_SAUX *Saux = SUMA_ADO_SSaux(ado);
8701 SUMA_RETURN(Saux->PR);
8702 break; }
8703 case CDOM_type: {
8704 SUMA_CIFTI_SAUX *Saux = SUMA_ADO_CSaux(ado);
8705 SUMA_RETURN(Saux->PR);
8706 break; }
8707 case GDSET_type: {
8708 SUMA_DSET *dset=(SUMA_DSET *)ado;
8709 SUMA_GRAPH_SAUX *Saux = SDSET_GSAUX(dset);
8710 SUMA_RETURN(Saux->PR);
8711 break; }
8712 case GRAPH_LINK_type:
8713 SUMA_RETURN(SUMA_ADO_GetPickResult(
8714 (SUMA_ALL_DO*)SUMA_find_GLDO_Dset((SUMA_GraphLinkDO*)ado),primitive));
8715 break;
8716 case TRACT_type: {
8717 SUMA_TRACT_SAUX *Saux = SUMA_ADO_TSaux(ado);
8718 SUMA_RETURN(Saux->PR);
8719 break; }
8720 case MASK_type: {
8721 SUMA_MASK_SAUX *Saux = SUMA_ADO_MSaux(ado);
8722 SUMA_RETURN(Saux->PR);
8723 break; }
8724 case VO_type: {
8725 SUMA_VOL_SAUX *Saux = SUMA_ADO_VSaux(ado);
8726 if (!strcmp(primitive,"voxel")) SUMA_RETURN(Saux->PR);
8727 else if (!strcmp(primitive,"cutplane")) SUMA_RETURN(Saux->PRc);
8728 else {
8729 SUMA_S_Err("Bad primitive %s for VO", primitive);
8730 }
8731 break; }
8732 default:
8733 SUMA_S_Errv("Note ready for type %s\n", ADO_TNAME(ado));
8734 break;
8735 }
8736 SUMA_RETURN(NOPE);
8737 }
8738
8739
8740 /*!
8741 */
SUMA_Show_Pick_Colid_List(DList * pick_colid_list,FILE * fout)8742 void SUMA_Show_Pick_Colid_List(DList *pick_colid_list, FILE *fout)
8743 {
8744 static char FuncName[]={"SUMA_Show_Pick_Colid_List"};
8745 char *s = NULL;
8746
8747 SUMA_ENTRY;
8748
8749 // fprintf(stderr, "%s\n", FuncName);
8750 if (!fout) fout = SUMA_STDOUT;
8751
8752 s = SUMA_Pick_Colid_List_Info(pick_colid_list);
8753 fprintf(fout, "%s", s);
8754 SUMA_ifree(s);
8755
8756 SUMA_RETURNe;
8757 }
8758
SUMA_Pick_Colid_List_Info(DList * pick_colid_list)8759 char *SUMA_Pick_Colid_List_Info (DList *pick_colid_list)
8760 {
8761 static char FuncName[]={"SUMA_Pick_Colid_List_Info"};
8762 char *s = NULL;
8763 SUMA_STRING *SS = NULL;
8764 SUMA_SurfaceObject *SO=NULL;
8765 SUMA_DO_Types do_type;
8766 void *vv=NULL;
8767 SUMA_DSET *dset=NULL;
8768 DListElmt *el=NULL;
8769 SUMA_ALL_DO *ado=NULL;
8770 SUMA_COLID_OFFSET_DATUM *cod=NULL;
8771
8772 SUMA_ENTRY;
8773
8774 // fprintf(stderr, "%s\n", FuncName);
8775
8776 SS = SUMA_StringAppend(NULL, NULL);
8777
8778 if (!pick_colid_list) {
8779 SS = SUMA_StringAppend(SS,"NULL pick_colid_list"); goto CLEAN_RETURN;
8780 }
8781 if (!dlist_size(pick_colid_list)) {
8782 SS = SUMA_StringAppend(SS,"Empty pick_colid_list"); goto CLEAN_RETURN;
8783 }
8784 SS = SUMA_StringAppend_va(SS,"DO Pick List of %d elements\n",
8785 dlist_size(pick_colid_list));
8786 do {
8787 if (!el) el = dlist_head(pick_colid_list);
8788 else el = dlist_next(el);
8789 if (!el || !el->data) {
8790 SS = SUMA_StringAppend(SS, " NULL element!");
8791 } else {
8792 cod = (SUMA_COLID_OFFSET_DATUM *)el->data;
8793 SS = SUMA_StringAppend_va(SS," DO %s, Primitive %s, [%ld to %ld]\n",
8794 cod->Label, cod->primitive,
8795 cod->i0, cod->i1);
8796 vv = SUMA_Picked_reference_object(cod, &do_type);
8797 switch (do_type) {
8798 case MD_DSET_type:
8799 dset = (SUMA_DSET *)vv;
8800 SS = SUMA_StringAppend_va(SS,
8801 " Reference object is a %s dataset labeled %s "
8802 "(reference type %s)\n",
8803 "Multi Domain",
8804 SDSET_LABEL(dset),
8805 SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
8806 break;
8807 case ANY_DSET_type:
8808 case GDSET_type:
8809 dset = (SUMA_DSET *)vv;
8810 SS = SUMA_StringAppend_va(SS,
8811 " Reference object is a %s dataset labeled %s "
8812 "(reference type %s)\n",
8813 SUMA_isCIFTIDset(dset) ? "CIFTI" :
8814 (SUMA_isGraphDset(dset) ? "Graph":"Surface-based"),
8815 SDSET_LABEL(dset),
8816 SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
8817 break;
8818 case SO_type:
8819 SO = (SUMA_SurfaceObject *)vv;
8820 SS = SUMA_StringAppend_va(SS,
8821 " Reference object is a surface labeled %s "
8822 "(reference type %s)\n",
8823 SO->Label,
8824 SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
8825 break;
8826 case GRAPH_LINK_type:
8827 ado = (SUMA_ALL_DO *)vv;
8828 SS = SUMA_StringAppend_va(SS,
8829 " Reference object is a graph link labeled %s "
8830 "(reference type %s)\n",
8831 SUMA_ADO_Label(ado),
8832 SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
8833 break;
8834 case TRACT_type:
8835 SS = SUMA_StringAppend_va(SS,
8836 " Reference object is a tract object labeled %s "
8837 "(reference type %s)\n",
8838 SUMA_ADO_Label(ado),
8839 SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
8840 break;
8841 case CDOM_type:
8842 SS = SUMA_StringAppend_va(SS,
8843 " Reference object is a CIFTI DO labeled %s "
8844 "(reference type %s)\n",
8845 SUMA_ADO_Label(ado),
8846 SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
8847 break;
8848 case MASK_type:
8849 SS = SUMA_StringAppend_va(SS,
8850 " Reference object is a mask object labeled %s "
8851 "(reference type %s)\n",
8852 SUMA_ADO_Label(ado),
8853 SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
8854 break;
8855 default:
8856 SS = SUMA_StringAppend_va(SS,
8857 " Parent, not surface or dset.\n");
8858 break;
8859 }
8860 }
8861 } while (el != dlist_tail(pick_colid_list));
8862
8863 CLEAN_RETURN:
8864 SUMA_SS2S(SS,s);
8865
8866 SUMA_RETURN(s);
8867 }
8868
SUMA_MarkLineDOsIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode)8869 int SUMA_MarkLineDOsIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
8870 int IgnoreSameNode)
8871 {
8872 static char FuncName[]={"SUMA_MarkLineDOsIntersect"};
8873
8874 SUMA_PICK_RESULT *PR = NULL;
8875 SUMA_ALL_DO *ado = NULL;
8876 int ans;
8877
8878 SUMA_ENTRY;
8879
8880 // fprintf(stderr, "%s\n", FuncName);
8881 SUMA_S_Warn("Do not call me anymore."
8882 "Go via SUMA_ComputeLineDOsIntersect. "
8883 "This is left here for testing purposes");
8884 ans = SUMA_ComputeLineDOsIntersect(sv, dov, IgnoreSameNode, &ado);
8885 if (ans <= 0) {
8886 SUMA_RETURN(ans);
8887 }
8888 /* just for temporary testing, get PR back from list and apply it */
8889 PR = SUMA_Get_From_PickResult_List(sv, ado, NULL);
8890 ans = SUMA_Apply_PR(sv, &PR);
8891
8892 SUMA_RETURN(ans);
8893 }
8894
8895 /*!
8896 Determines the intersection between pickline and displayable objects
8897 */
SUMA_ComputeLineDOsIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode,SUMA_ALL_DO ** pado)8898 int SUMA_ComputeLineDOsIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
8899 int IgnoreSameNode, SUMA_ALL_DO **pado)
8900 {
8901 static char FuncName[]={"SUMA_ComputeLineDOsIntersect"};
8902 int i, j, *MembDOs=NULL, N_MembDOs;
8903 SUMA_DO_Types ttv[12];
8904 SUMA_PICK_RESULT *hit=NULL;
8905 GLubyte colans[4];
8906 SUMA_COLID_OFFSET_DATUM *codf=NULL;
8907 SUMA_ALL_DO *ado=NULL;
8908 SUMA_EngineData *ED = NULL;
8909 DList *list = NULL;
8910 DListElmt *SetNodeElem = NULL, *Location=NULL;
8911 SUMA_SurfaceObject *SO = NULL;
8912 SUMA_Boolean NodeIgnored = NOPE;
8913 SUMA_Boolean LocalHead = NOPE;
8914
8915 SUMA_ENTRY;
8916
8917 // fprintf(stderr, "%s\n", FuncName);
8918
8919 if (!sv || !dov) SUMA_RETURN(-1);
8920
8921 SUMA_LH("DO pickin");
8922
8923 if (sv->PickPix[0] < 0 || sv->PickPix[1] < 0 ||
8924 sv->PickPix[0] >= sv->X->aWIDTH || sv->PickPix[1] >= sv->X->aHEIGHT) {
8925 /* This happens when you select and drag outside of the viewing area
8926 Don't return in error */
8927 SUMA_LHv("Bad PickPix=[%d %d] for viewport %d %d\n",
8928 sv->PickPix[0], sv->PickPix[1], sv->X->aWIDTH, sv->X->aHEIGHT);
8929 SUMA_RETURN(0);
8930 }
8931
8932 /* Any pickable DO, other than brain surfaces, that does not require
8933 pick buffer picking? */
8934 ttv[0] = GRAPH_LINK_type; ttv[1] = NOT_SET_type;
8935 MembDOs = SUMA_ViewState_Membs(&(sv->VSv[sv->iState]), ttv, &N_MembDOs);
8936 for (i=0; i<N_MembDOs; ++i) {
8937 if ((hit = SUMA_WhatWasPicked_FrameSO(sv, MembDOs[i]))) {
8938 if ( hit->datum_index < 0 && (
8939 ( hit->iAltSel[SUMA_ENODE_0]>=0 &&
8940 hit->iAltSel[SUMA_ENODE_1]>=0)) ) {
8941 /* You have selected a point pair that has no edge defined.
8942 This can happen when you click on an empty cell in the matrix */
8943 hit = SUMA_free_PickResult(hit);
8944 } else {
8945 /* got something, leave.
8946 Perhaps in the future will need to go through
8947 all stack (slices) and pick the best one ... */
8948 ado = iDO_ADO(MembDOs[i]);
8949 if (pado) *pado = ado;
8950 break;
8951 }
8952 }
8953 }
8954 SUMA_ifree(MembDOs);
8955
8956 if (!hit) { /* nothing found above, go for pick buffer */
8957 if (!SUMA_PickBuffer(sv, 2, dov)) { /* refresh the buffer only if needed */
8958 SUMA_S_Err("Failed to refresh buffer");
8959 SUMA_RETURN(-1);
8960 }
8961
8962 if (!sv->pickrenpix4) {
8963 SUMA_S_Err("Could not form pickrenpix4, should this be an error?");
8964 SUMA_RETURN(-1);
8965 }
8966 if (!sv->pick_colid_list || !dlist_size(sv->pick_colid_list)) {
8967 SUMA_LH("No such pickable objects");
8968 } else {
8969 /* get pixel at click */
8970 i = sv->PickPix[0]; j = sv->PickPix[1];
8971 if (SUMA_GetColidInPickBuffer4(sv->pickrenpix4,
8972 sv->X->aWIDTH, sv->X->aHEIGHT,
8973 &i, &j, 2, colans)) {
8974 if (LocalHead) {
8975 /* Just for debugging, draw the crosshair point */
8976 SUMA_MarkPickInBuffer4(sv, 1, NULL);
8977 SUMA_LHv("User pixel selection: \n"
8978 " closest hit to click at %d %d was from %d %d\n"
8979 " colid = %d %d %d %d \n",
8980 sv->PickPix[0], sv->PickPix[1], i, j,
8981 colans[0] , colans[1],
8982 colans[2] , colans[3]);
8983 }
8984 /* so what was that you touched. Note hit is never
8985 returned as null. */
8986 hit = SUMA_WhatWasPicked(sv, colans, &codf, i, j, NULL);
8987 if (!hit || !hit->ado_idcode_str) {
8988 SUMA_LH("Not hit found.");
8989 } else {
8990 if (!(ado = iDO_ADO(SUMA_Picked_DO_ID(codf)))) {
8991 SUMA_S_Err("Could not locate object in codf (%s) /hit (%s)!",
8992 codf->ref_idcode_str, hit->ado_idcode_str);
8993 SUMA_free_PickResult(hit); hit = NULL;
8994 } else {
8995 if (pado) *pado = ado;
8996 }
8997 }
8998 } else {
8999 SUMA_LH("There is no there there\n");
9000 hit = NULL;
9001 }
9002 }
9003 }
9004
9005 if (hit && ado) {
9006 SUMA_LH("Adding hit to list");
9007 if (!SUMA_Add_To_PickResult_List(sv, ado, NULL, &hit)) {
9008 SUMA_S_Err("Failed to add selected ado");
9009 SUMA_RETURN(-1);
9010 }
9011 SUMA_RETURN(1);
9012 } else SUMA_RETURN(0);
9013 }
9014
SUMA_Apply_PR_DO(SUMA_SurfaceViewer * sv,SUMA_ALL_DO * ado,SUMA_PICK_RESULT ** PRi)9015 int SUMA_Apply_PR_DO(SUMA_SurfaceViewer *sv, SUMA_ALL_DO *ado,
9016 SUMA_PICK_RESULT **PRi)
9017 {
9018 static char FuncName[]={"SUMA_Apply_PR_DO"};
9019 DList *list = NULL;
9020 DListElmt *SetNodeElem = NULL, *Location=NULL;
9021 SUMA_Boolean NodeIgnored = NOPE;
9022 SUMA_PICK_RESULT *PR;
9023 int NP=0, ip=0, it=-1, id = 0, iv3[3], iv15[15];
9024 SUMA_EngineData *ED = NULL;
9025 SUMA_Boolean LocalHead = NOPE;
9026
9027 SUMA_ENTRY;
9028
9029 // fprintf(stderr, "%s\n", FuncName);
9030 SUMA_LH("Here");
9031 if (!sv || !ado || !PRi || !*PRi) { SUMA_S_Err("Niente"); SUMA_RETURN(-1); }
9032
9033 PR = *PRi; /* keep local copy */
9034 /* Store the PR in ado, hide it from return potential */
9035 SUMA_ADO_StorePickResult(ado, PRi);
9036
9037 SUMA_LHv("Hit object type %s, label %s\n",
9038 SUMA_ObjectTypeCode2ObjectTypeName(ado->do_type),
9039 SUMA_ADO_Label(ado));
9040
9041 sv->Focus_DO_ID = ADO_iDO(ado);
9042 SUMA_UpdateViewerTitle(sv);
9043
9044 /* if the surface controller is open, update it */
9045 if (SUMA_isADO_Cont_Realized(ado))
9046 SUMA_Init_SurfCont_SurfParam(ado);
9047
9048 /* print nodes about the pick */
9049 switch (ado->do_type) {
9050 case TRACT_type:
9051 fprintf(SUMA_STDOUT, "\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
9052 fprintf(SUMA_STDOUT, "Selected network %s (Focus_DO_ID # %d).\n"
9053 "Point %ld, (Bundle %ld, Tract %ld, Point %ld)\n",
9054 ADO_LABEL(ado), sv->Focus_DO_ID, PR->datum_index,
9055 PR->iAltSel[SUMA_NET_BUN], PR->iAltSel[SUMA_BUN_TRC],
9056 PR->iAltSel[SUMA_TRC_PNT]);
9057 fprintf(SUMA_STDOUT, "Seletion coordinates:\n");
9058 fprintf(SUMA_STDOUT, "%f, %f, %f\n",
9059 PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2]);
9060 fprintf(SUMA_STDOUT, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
9061 break;
9062 case MASK_type:
9063 fprintf(SUMA_STDOUT, "\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
9064 fprintf(SUMA_STDOUT, "Selected mask %s (Focus_DO_ID # %d).\n",
9065 ADO_LABEL(ado), sv->Focus_DO_ID);
9066 fprintf(SUMA_STDOUT, "Seletion coordinates:\n");
9067 fprintf(SUMA_STDOUT, "%f, %f, %f\n",
9068 PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2]);
9069 fprintf(SUMA_STDOUT, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
9070 break;
9071 case GRAPH_LINK_type:
9072 fprintf(SUMA_STDOUT, "\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
9073 fprintf(SUMA_STDOUT, "Selected Graph Dset %s (Focus_DO_ID # %d).\n"
9074 "Edge %ld, (P0 %ld, P1 %ld)\n",
9075 ADO_LABEL(ado), sv->Focus_DO_ID, PR->datum_index,
9076 PR->iAltSel[SUMA_ENODE_0], PR->iAltSel[SUMA_ENODE_1]);
9077 fprintf(SUMA_STDOUT, "Seletion coordinates:\n");
9078 fprintf(SUMA_STDOUT, "%f, %f, %f\n",
9079 PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2]);
9080 fprintf(SUMA_STDOUT, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
9081 break;
9082 default:
9083 SUMA_S_Err("Not yet set to report on %s", ADO_LABEL(ado));
9084 break;
9085 }
9086
9087 /* Based on what you selected, update controller */
9088 /* Set the Nodeselection at the closest node */
9089 if (PR->datum_index >= 0 ||
9090 (PR->datum_index == -1 &&
9091 PR->iAltSel[SUMA_ENODE_0] >= 0 &&
9092 PR->iAltSel[SUMA_ENODE_1] == -1) ) {
9093 /* 2nd condition is when only edge node is selected.
9094 We insist on PR->iAltSel[SUMA_ENODE_1] == -1 otherwise
9095 we would have picked a cell in the matrix for which
9096 there is no data, hence we have ENODE_0, and ENODE_1,
9097 but datum_index = -1 */
9098 it = (int)PR->datum_index;
9099 if (!list) list = SUMA_CreateList();
9100 if (PR->ignore_same_datum &&
9101 SUMA_ADO_SelectedDatum(ado, NULL, NULL) == it) {
9102 SUMA_LHv("Ignoring identical datum selection %d on object %s\n",
9103 SUMA_ADO_SelectedDatum(ado, NULL, NULL), SUMA_ADO_Label(ado));
9104 NodeIgnored = YUP;
9105 } else {
9106 ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
9107 SetNodeElem = SUMA_RegisterEngineListCommand ( list, ED,
9108 SEF_i, (void*)&it,
9109 SES_Suma, (void *)sv, NOPE,
9110 SEI_Head, NULL);
9111 if (!SetNodeElem) {
9112 fprintf( SUMA_STDERR,
9113 "Error %s: Failed to register SetNodeElem\n", FuncName);
9114 SUMA_RETURN (-1);
9115 } else {
9116 SUMA_RegisterEngineListCommand ( list, ED,
9117 SEF_ngr, NULL,
9118 SES_Suma, (void *)sv, NOPE,
9119 SEI_In, SetNodeElem);
9120 }
9121 switch (ado->do_type) {
9122 case TRACT_type:
9123 iv15[SUMA_NET_BUN] = (int)PR->iAltSel[SUMA_NET_BUN];
9124 iv15[SUMA_BUN_TRC] = (int)PR->iAltSel[SUMA_BUN_TRC];
9125 iv15[SUMA_TRC_PNT] = (int)PR->iAltSel[SUMA_TRC_PNT];
9126 iv15[SUMA_NET_TRC] = (int)PR->iAltSel[SUMA_NET_TRC];
9127 SUMA_RegisterEngineListCommand ( list, ED,
9128 SEF_iv15, (void *)iv15,
9129 SES_Suma, (void *)sv, NOPE,
9130 SEI_In, SetNodeElem);
9131 break;
9132 case SO_type:
9133 case VO_type:
9134 /* handled in separate function */
9135 break;
9136 default:
9137 SUMA_LH("No aux set here for type %s of %s\n",
9138 ADO_TNAME(ado), SUMA_ADO_Label(ado));
9139 break;
9140 }
9141
9142 }
9143 }
9144
9145
9146 /* Set the selected edge node (cunningly in recycled selected face set) */
9147 it = PR->iAltSel[SUMA_ENODE_0];
9148 if (!list) list = SUMA_CreateList();
9149 ED = SUMA_InitializeEngineListData (SE_SetSelectedFaceSet);
9150 if (!SUMA_RegisterEngineListCommand ( list, ED,
9151 SEF_i, (void*)&it,
9152 SES_Suma, (void *)sv, NOPE,
9153 SEI_Head, NULL)) {
9154 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9155 SUMA_RETURN (-1);
9156 }
9157
9158 /* Now set the cross hair position at the intersection*/
9159 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
9160 if (!(Location = SUMA_RegisterEngineListCommand ( list, ED,
9161 SEF_fv3, (void*)PR->PickXYZ,
9162 SES_Suma, (void *)sv, NOPE,
9163 SEI_Head, NULL))) {
9164 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9165 SUMA_RETURN (-1);
9166 }
9167 /* and add the ado with this location, needed for VisX business*/
9168 SUMA_RegisterEngineListCommand ( list, ED,
9169 SEF_vp, (void *)ado,
9170 SES_Suma, (void *)sv, NOPE,
9171 SEI_In, Location);
9172 /* attach the cross hair to the selected ado */
9173 iv3[0] = SUMA_whichDO(PR->ado_idcode_str, SUMAg_DOv, SUMAg_N_DOv);
9174 iv3[1] = PR->datum_index;
9175 iv3[2] = PR->iAltSel[SUMA_ENODE_0];
9176 ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
9177 if (!SUMA_RegisterEngineListCommand ( list, ED,
9178 SEF_iv3, (void*)iv3,
9179 SES_Suma, (void *)sv, NOPE,
9180 SEI_Head, NULL)) {
9181 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9182 SUMA_RETURN (-1);
9183 }
9184
9185 /* check to see if AFNI needs to be notified */
9186 /* Need to deal with SUMA_TO_MATLAB_STREAM_INDEX too
9187 Same for remaining occurrence of SUMA_AFNI_STREAM_INDEX*/
9188 if ( ( SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] &&
9189 sv->LinkAfniCrossHair ) ||
9190 ( SUMAg_CF->Connected_v[SUMA_HALLO_SUMA_LINE]) ||
9191 ( SUMAg_CF->Connected_v[SUMA_INSTA_TRACT_LINE]) ) {
9192 if (LocalHead)
9193 fprintf(SUMA_STDERR,
9194 "%s: Notifying Afni of CrossHair XYZ\n", FuncName);
9195 /* register a call to SetAfniCrossHair */
9196 if (!list) list = SUMA_CreateList();
9197 it = SUMA_ShftCont_Event(PR->evr);
9198 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
9199 if (!SUMA_RegisterEngineListCommand ( list, ED,
9200 SEF_i, (void*)&it,
9201 SES_Suma, (void *)sv, NOPE,
9202 SEI_Tail, NULL)) {
9203 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9204 SUMA_RETURN (-1);
9205 }
9206 if (MASK_MANIP_MODE(sv) && SUMAg_CF->Dev) {
9207 SUMA_ALL_DO *ado = SUMA_whichADOg(sv->MouseMode_ado_idcode_str);
9208 DListElmt *Location=NULL;
9209 SUMA_LH("Might be telling afni about mask...");
9210 if (ado && ado->do_type == MASK_type) {
9211 SUMA_MaskDO *mdo = (SUMA_MaskDO *)ado;
9212 ED = SUMA_InitializeEngineListData (SE_SetAfniMask);
9213 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
9214 SEF_fv3, (void*)mdo->cen,
9215 SES_Suma, (void *)sv, NOPE,
9216 SEI_Tail, NULL))) {
9217 SUMA_S_Err("Failed to register element\n");
9218 SUMA_RETURN (-1);
9219 }
9220 SUMA_RegisterEngineListCommand ( list, ED,
9221 SEF_s, (void *)(ADO_ID(ado)),
9222 SES_Suma, (void *)sv, NOPE,
9223 SEI_In, Location);
9224 }
9225 }
9226
9227 if (!SUMA_Engine (&list)) {
9228 fprintf( SUMA_STDERR,
9229 "Error %s: SUMA_Engine call failed.\n", FuncName);
9230 SUMA_RETURN (-1);
9231 }
9232 }else {
9233 if (LocalHead)
9234 fprintf(SUMA_STDERR,"%s: No Notification to AFNI.\n", FuncName);
9235 }
9236
9237 /* now put in a request for locking cross hair but you must do
9238 this after the node selection has been executed
9239 NOTE: You do not always have SetNodeElem because the list might
9240 get emptied in the call to AFNI notification.
9241 You should just put the next call at the end of the list.*/
9242 if (!list) list = SUMA_CreateList();
9243 ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
9244 if (!SUMA_RegisterEngineListCommand ( list, ED,
9245 SEF_iv3, (void*)iv3,
9246 SES_Suma, (void *)sv, NOPE,
9247 SEI_Tail, NULL)) {
9248 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9249 SUMA_RETURN (-1);
9250 }
9251 if (!SUMA_Engine (&list)) {
9252 fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
9253 SUMA_RETURN (-1);
9254 }
9255
9256 SUMA_RETURN(1);
9257 }
9258
SUMA_Apply_PR(SUMA_SurfaceViewer * sv,SUMA_PICK_RESULT ** PR)9259 int SUMA_Apply_PR(SUMA_SurfaceViewer *sv, SUMA_PICK_RESULT **PR)
9260 {
9261 static char FuncName[]={"SUMA_Apply_PR"};
9262 SUMA_ALL_DO *ado=NULL, *ado_pick=NULL;
9263 float *xyz=NULL;
9264 SUMA_Boolean LocalHead = NOPE;
9265
9266 SUMA_ENTRY;
9267
9268 // fprintf(stderr, "%s\n", FuncName);
9269
9270 if (!sv || !PR || !*PR) {
9271 SUMA_S_Err("NULL input %p %p %p", sv, PR, *PR);
9272 SUMA_DUMP_TRACE("PR application");
9273 SUMA_RETURN(-1);
9274 }
9275 if (MASK_MANIP_MODE(sv)) {
9276 ado_pick = SUMA_whichADOg((*PR)->ado_idcode_str);
9277 SUMA_LH("Mask Manip Mode, moving to %f %f %f per ado %s\n",
9278 (*PR)->PickXYZ[0], (*PR)->PickXYZ[1], (*PR)->PickXYZ[2],
9279 ADO_LABEL(ado_pick));
9280 SUMA_ifree(sv->LastSel_ado_idcode_str);
9281 sv->LastSel_ado_idcode_str = SUMA_copy_string((*PR)->ado_idcode_str);
9282 /* Just move the selected mask */
9283 if (!(ado = SUMA_whichADOg(sv->MouseMode_ado_idcode_str))) {
9284 SUMA_S_Err("Yikes, got not ado for MouseMode_ado_idcode_str %s",
9285 sv->MouseMode_ado_idcode_str?sv->MouseMode_ado_idcode_str:"NULL");
9286 SUMA_RETURN(-1);
9287 }
9288 if (ado->do_type != MASK_type) {
9289 SUMA_S_Err("Bad ID for mouse mode value");
9290 SUMA_RETURN(-1);
9291 }
9292 /* Set the parent as the ado_pick */
9293 SUMA_MDO_New_parent((SUMA_MaskDO *)ado, (*PR)->ado_idcode_str,
9294 (*PR)->datum_index);
9295
9296 if (ado_pick->do_type == SO_type) {
9297 SUMA_SurfaceObject *SO = (SUMA_SurfaceObject *)ado_pick;
9298 /* PickXYZ might be under VisX */
9299 xyz = SO->NodeList+SO->NodeDim* (*PR)->datum_index;
9300 SUMA_MDO_New_Doppel((SUMA_MaskDO *)ado, (*PR)->PickXYZ);
9301 } else {
9302 xyz = (*PR)->PickXYZ;
9303 SUMA_MDO_New_Doppel((SUMA_MaskDO *)ado, NULL);
9304 }
9305 if (LocalHead) SUMA_DUMP_TRACE("Box motion");
9306 SUMA_NEW_MASKSTATE();
9307 SUMA_MDO_New_Cen((SUMA_MaskDO *)ado, xyz);
9308 }
9309
9310 {
9311 ado = SUMA_whichADOg((*PR)->ado_idcode_str);
9312 SUMA_ifree(sv->LastSel_ado_idcode_str);
9313 sv->LastSel_ado_idcode_str = SUMA_copy_string((*PR)->ado_idcode_str);
9314 switch (ado->do_type) {
9315 case SO_type:
9316 SUMA_RETURN(SUMA_Apply_PR_SO(sv, (SUMA_SurfaceObject *)ado, PR));
9317 break;
9318 case VO_type:
9319 SUMA_RETURN(SUMA_Apply_PR_VO(sv, (SUMA_VolumeObject *)ado, PR));
9320 break;
9321 case GRAPH_LINK_type:
9322 SUMA_RETURN(SUMA_Apply_PR_DO(sv, ado, PR));
9323 break;
9324 case TRACT_type:
9325 SUMA_RETURN(SUMA_Apply_PR_DO(sv, ado, PR));
9326 break;
9327 case MASK_type:
9328 SUMA_RETURN(SUMA_Apply_PR_DO(sv, ado, PR));
9329 break;
9330 default:
9331 SUMA_S_Err("Not yet implemented for %s", ADO_TNAME(ado));
9332 SUMA_RETURN(-1);
9333 break;
9334 }
9335 }
9336 SUMA_RETURN(-1);
9337 }
9338
SUMA_MarkLineMaskIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode)9339 int SUMA_MarkLineMaskIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
9340 int IgnoreSameNode)
9341 {/* determine intersection */
9342 static char FuncName[]={"SUMA_MarkLineMaskIntersect"};
9343 SUMA_PICK_RESULT *PR = NULL;
9344 SUMA_ALL_DO *ado = NULL;
9345 int ans;
9346
9347 SUMA_ENTRY;
9348
9349 // fprintf(stderr, "%s\n", FuncName);
9350 SUMA_S_Warn("Do not call me anymore. Follow the new selection logic");
9351 ans = SUMA_ComputeLineMaskIntersect(sv, dov, IgnoreSameNode, &ado);
9352 if (ans <= 0) {
9353 SUMA_RETURN(ans);
9354 }
9355 /* just for temporary testing, get PR back from list and apply it */
9356 PR = SUMA_Get_From_PickResult_List(sv, ado, NULL);
9357 ans = SUMA_Apply_PR(sv, &PR);
9358 SUMA_RETURN(ans);
9359 }
9360
SUMA_ComputeLineMaskIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode,SUMA_ALL_DO ** pado)9361 int SUMA_ComputeLineMaskIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
9362 int IgnoreSameNode, SUMA_ALL_DO **pado)
9363 {/* determine intersection */
9364 static char FuncName[]={"SUMA_ComputeLineMaskIntersect"};
9365 float P0f[3], P1f[3];
9366 int NP;
9367 SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL, *MTIi = NULL;
9368 float delta_t_tmp, dmin;
9369 struct timeval tt_tmp;
9370 SUMA_ALL_DO *ado=NULL;
9371 int ip, it, id, ii, N_MDOlist,
9372 MDOlist[SUMA_MAX_DISPLAYABLE_OBJECTS], imin;
9373 char sfield[100], sdestination[100], CommString[SUMA_MAX_COMMAND_LENGTH];
9374 SUMA_MaskDO *MDO = NULL;
9375 SUMA_Boolean LocalHead = NOPE;
9376
9377 SUMA_ENTRY;
9378
9379 // fprintf(stderr, "%s\n", FuncName);
9380
9381 P0f[0] = sv->Pick0[0];
9382 P0f[1] = sv->Pick0[1];
9383 P0f[2] = sv->Pick0[2];
9384 P1f[0] = sv->Pick1[0];
9385 P1f[1] = sv->Pick1[1];
9386 P1f[2] = sv->Pick1[2];
9387
9388 N_MDOlist = SUMA_VisibleMDOs(sv, dov, MDOlist);
9389 if (LocalHead) {
9390 SUMA_LH("%d visible MDOs", N_MDOlist);
9391 for (ii=0; ii < N_MDOlist; ++ii) {
9392 ado = (SUMA_ALL_DO *)dov[MDOlist[ii]].OP;
9393 fprintf(SUMA_STDERR,"%d: object %d in DOv, label %s, type %s\n",
9394 ii, MDOlist[ii], ADO_LABEL(ado), ADO_TNAME(ado));
9395 }
9396 }
9397 imin = -1;
9398 dmin = 10000000.0;
9399 for (ii=0; ii < N_MDOlist; ++ii) { /* find the closest intersection */
9400 if (LocalHead)
9401 fprintf (SUMA_STDERR,
9402 "%s: working %d/%d shown masks ...\n",
9403 FuncName, ii, N_MDOlist);
9404 MDO = (SUMA_MaskDO *)dov[MDOlist[ii]].OP;
9405 if (!MDO_IS_SURF(MDO) && !MDO_IS_BOX(MDO) && !MDO_IS_SPH(MDO)) {
9406 fprintf(SUMA_STDERR,
9407 "Error %s: "
9408 "Not ready to handle such MDO (%s) intersections on %s\n",
9409 FuncName, MDO->mtype, ADO_LABEL((SUMA_ALL_DO *)MDO));
9410 } if (!MDO->SO) {
9411 SUMA_S_Err("No SO buster on %s", ADO_LABEL((SUMA_ALL_DO *)MDO));
9412 } else {
9413 /* Here we're doing the intersection the lazy way, via the SO,
9414 although this can be done a lot faster in other ways for box and
9415 sphere, speed is not an issue here */
9416 SUMA_etime (&tt_tmp, 0);
9417 MTIi = SUMA_MT_intersect_triangle(P0f, P1f, MDO->SO->NodeList,
9418 MDO->SO->N_Node, MDO->SO->FaceSetList,
9419 MDO->SO->N_FaceSet, NULL, 0);
9420
9421 delta_t_tmp = SUMA_etime (&tt_tmp, 1);
9422 SUMA_LH("Intersection took %f seconds with %s.\n",
9423 delta_t_tmp,
9424 ADO_LABEL((SUMA_ALL_DO *)dov[MDOlist[ii]].OP));
9425
9426 if (MTIi == NULL) {
9427 fprintf(SUMA_STDERR,
9428 "Error %s: SUMA_MT_intersect_triangle failed.\n", FuncName);
9429 SUMA_RETURN (-1);
9430 }
9431
9432 if (MTIi->N_hits) {
9433 /* decide on the closest surface to the clicking point */
9434 if (MTIi->t[MTIi->ifacemin] < dmin) {
9435 if (LocalHead)
9436 fprintf (SUMA_STDERR, "%s: A minimum for surface %d.\n",
9437 FuncName, ii);
9438 dmin = MTIi->t[MTIi->ifacemin];
9439 imin = MDOlist[ii];
9440 MTI = MTIi;
9441 }else {
9442 /* not good, toss it away */
9443 SUMA_LH("ii=%d not any closer (%f vs %f). freeing MTIi...\n",
9444 ii,MTIi->t[MTIi->ifacemin], dmin);
9445 MTIi = SUMA_Free_MT_intersect_triangle(MTIi);
9446 }
9447 }else {
9448 /* not good, toss it away */
9449 if (LocalHead)
9450 fprintf (SUMA_STDERR,
9451 "%s: ii=%d freeing MTIi no hits...\n", FuncName, ii);
9452 MTIi = SUMA_Free_MT_intersect_triangle(MTIi);
9453 }
9454 }
9455 }
9456
9457 if (LocalHead)
9458 fprintf (SUMA_STDERR,
9459 "%s: Closest surface is indexed %d in DOv.\n", FuncName, imin);
9460
9461 if (imin >= 0) {
9462 SUMA_PICK_RESULT *PR;
9463 SUMA_ALL_DO *ado;
9464 if (!(ado = iDO_ADO(imin))) {
9465 SUMA_S_Err("NULL ado at this point? imin = %d", imin);
9466 SUMA_RETURN(-1);
9467 }
9468 PR = SUMA_New_Pick_Result(NULL);
9469 if (pado) *pado = ado; /* user want answer back */
9470 PR->ado_idcode_str = SUMA_copy_string(ADO_ID(ado));
9471 PR->datum_index = MTI->inodemin;
9472 PR->ignore_same_datum = IgnoreSameNode;
9473 PR->iAltSel[SUMA_SURF_TRI] = MTI->ifacemin;
9474 SUMA_COPY_VEC(MTI->P, PR->PickXYZ, 3, float, float);
9475 /* Add selection result to stack */
9476 if (!SUMA_Add_To_PickResult_List(sv, ado, NULL, &PR)) {
9477 SUMA_S_Err("Failed to add selected ado");
9478 SUMA_RETURN(-1);
9479 }
9480 }
9481
9482 /* clear MTI */
9483 if (MTI) {
9484 MTI = SUMA_Free_MT_intersect_triangle(MTI);
9485 }
9486
9487 if (imin >=0) SUMA_RETURN(1);
9488 else SUMA_RETURN(0);
9489 }
9490
9491
SUMA_MarkLineSurfaceIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode)9492 int SUMA_MarkLineSurfaceIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
9493 int IgnoreSameNode)
9494 {
9495 static char FuncName[]={"SUMA_MarkLineSurfaceIntersect"};
9496 SUMA_PICK_RESULT *PR = NULL;
9497 SUMA_ALL_DO *ado = NULL;
9498 int ans;
9499
9500 SUMA_ENTRY;
9501
9502 // fprintf(stderr, "%s\n", FuncName);
9503 SUMA_S_Warn("Do not call me anymore."
9504 "Go via SUMA_ComputeLineSurfaceIntersect. "
9505 "This is left here for testing purposes");
9506 ans = SUMA_ComputeLineSurfaceIntersect(sv, dov, IgnoreSameNode, &ado);
9507 if (ans <= 0) {
9508 SUMA_RETURN(ans);
9509 }
9510 /* just for temporary testing, get PR back from list and apply it */
9511 PR = SUMA_Get_From_PickResult_List(sv, ado, NULL);
9512 ans = SUMA_Apply_PR(sv, &PR);
9513
9514 SUMA_RETURN(ans);
9515 }
9516
9517 /*!
9518 Determines the intersection between ]sv->Pick0 sv->Pick1[ and SO
9519 Highlights the intersected faceset, node and updates cross hair location
9520 This used to be part of Button3's code in SUMA_input
9521 ans = SUMA_ComputeLineSurfaceIntersect (sv, dov);
9522 \param sv (SUMA_SurfaceViewer *) surface viewer pointer
9523 \param dov (SUMA_DO *) displayable object vector pointer
9524 \param IgnoreSameNode (int) 1 do nothing if node already selected
9525 0 don't care if it was already selected
9526 \param pado (SUMA_ALL_DO **) If not NULL, *pado will contain a copy
9527 of an ADO pointer to the intersected
9528 object, if any.
9529 \ret ans (int) -1 error, 0 no hit, hit
9530
9531 Note that this function will register whatever surfaces get hit in the
9532 selections list with a call to SUMA_Add_To_PickResult_List()
9533
9534 also requires SUMAg_DOv and SUMAg_N_DOv
9535 */
SUMA_ComputeLineSurfaceIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode,SUMA_ALL_DO ** pado)9536 int SUMA_ComputeLineSurfaceIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
9537 int IgnoreSameNode, SUMA_ALL_DO **pado)
9538 {/* determine intersection */
9539 static char FuncName[]={"SUMA_ComputeLineSurfaceIntersect"};
9540 float P0f[3], P1f[3];
9541 int NP;
9542 SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL, *MTIi = NULL;
9543 float delta_t_tmp, dmin;
9544 struct timeval tt_tmp;
9545 int ip, it, id, ii, N_SOlist,
9546 SOlist[SUMA_MAX_DISPLAYABLE_OBJECTS], imin;
9547 char sfield[100], sdestination[100], CommString[SUMA_MAX_COMMAND_LENGTH];
9548 SUMA_SurfaceObject *SO = NULL;
9549 SUMA_Boolean LocalHead = NOPE;
9550
9551 SUMA_ENTRY;
9552
9553 // fprintf(stderr, "%s\n", FuncName);
9554
9555 P0f[0] = sv->Pick0[0];
9556 P0f[1] = sv->Pick0[1];
9557 P0f[2] = sv->Pick0[2];
9558 P1f[0] = sv->Pick1[0];
9559 P1f[1] = sv->Pick1[1];
9560 P1f[2] = sv->Pick1[2];
9561
9562 N_SOlist = SUMA_VisibleSOs(sv, dov, SOlist, 0);
9563 imin = -1;
9564 dmin = 10000000.0;
9565
9566 for (ii=0; ii < N_SOlist; ++ii) { /* find the closest intersection */
9567 if (LocalHead)
9568 fprintf (SUMA_STDERR,
9569 "%s: working %d/%d shown surfaces ...\n",
9570 FuncName, ii, N_SOlist);
9571 SO = (SUMA_SurfaceObject *)dov[SOlist[ii]].OP;
9572 SUMA_VisX_Pointers4Display(SO, 1); /* using coordinates as displayed */
9573 if (SO->FaceSetDim != 3) {
9574 fprintf(SUMA_STDERR,
9575 "Error %s: "
9576 "SUMA_MT_intersect_triangle only works for triangular meshes.\n",
9577 FuncName);
9578 } else {
9579
9580 SUMA_etime (&tt_tmp, 0);
9581
9582 MTIi = SUMA_MT_intersect_triangle(P0f, P1f, SO->NodeList, SO->N_Node,
9583 SO->FaceSetList, SO->N_FaceSet, NULL, 0);
9584
9585 delta_t_tmp = SUMA_etime (&tt_tmp, 1);
9586 if (LocalHead)
9587 fprintf (SUMA_STDERR,
9588 "Local Debug %s: Intersection took %f seconds.\n",
9589 FuncName, delta_t_tmp);
9590
9591 if (MTIi == NULL) {
9592 fprintf(SUMA_STDERR,
9593 "Error %s: SUMA_MT_intersect_triangle failed.\n", FuncName);
9594 SUMA_RETURN (-1);
9595 }
9596
9597 if (MTIi->N_hits) {
9598 /* decide on the closest surface to the clicking point */
9599 if (MTIi->t[MTIi->ifacemin] < dmin) {
9600 if (LocalHead)
9601 fprintf (SUMA_STDERR, "%s: A minimum for surface %d.\n",
9602 FuncName, ii);
9603 dmin = MTIi->t[MTIi->ifacemin];
9604 imin = SOlist[ii];
9605 MTI = MTIi;
9606 }else {
9607 /* not good, toss it away */
9608 if (LocalHead)
9609 fprintf (SUMA_STDERR,
9610 "%s: ii=%d freeing MTIi...\n", FuncName, ii);
9611 MTIi = SUMA_Free_MT_intersect_triangle(MTIi);
9612 }
9613 }else {
9614 /* not good, toss it away */
9615 if (LocalHead)
9616 fprintf (SUMA_STDERR,
9617 "%s: ii=%d freeing MTIi no hits...\n", FuncName, ii);
9618 MTIi = SUMA_Free_MT_intersect_triangle(MTIi);
9619 }
9620 }
9621 SUMA_VisX_Pointers4Display(SO, 0); /* put things back young man */
9622 }
9623
9624 if (LocalHead)
9625 fprintf (SUMA_STDERR,
9626 "%s: Closest surface is indexed %d in DOv.\n", FuncName, imin);
9627
9628 if (imin >= 0) {
9629 SUMA_PICK_RESULT *PR;
9630 SUMA_ALL_DO *ado;
9631 if (!(ado = iDO_ADO(imin))) {
9632 SUMA_S_Err("NULL ado at this point?");
9633 SUMA_RETURN(-1);
9634 }
9635 PR = SUMA_New_Pick_Result(NULL);
9636 if (pado) *pado = ado; /* user want answer back */
9637 PR->ado_idcode_str = SUMA_copy_string(ADO_ID(ado));
9638 PR->datum_index = MTI->inodemin;
9639 PR->ignore_same_datum = IgnoreSameNode;
9640 PR->iAltSel[SUMA_SURF_TRI] = MTI->ifacemin;
9641 SUMA_COPY_VEC(MTI->P, PR->PickXYZ, 3, float, float);
9642 /* Add selection result to stack. NB. This increments sv->SelAdo->size
9643 PR has the surface details. */
9644 if (!SUMA_Add_To_PickResult_List(sv, ado, NULL, &PR)) {
9645 SUMA_S_Err("Failed to add selected ado");
9646 SUMA_RETURN(-1);
9647 }
9648 }
9649
9650 /* clear MTI */
9651 if (MTI) {
9652 MTI = SUMA_Free_MT_intersect_triangle(MTI);
9653 }
9654
9655 if (imin >=0) SUMA_RETURN(1);
9656 else SUMA_RETURN(0);
9657 }
9658
SUMA_Apply_PR_SO(SUMA_SurfaceViewer * sv,SUMA_SurfaceObject * SO,SUMA_PICK_RESULT ** PRi)9659 int SUMA_Apply_PR_SO(SUMA_SurfaceViewer *sv, SUMA_SurfaceObject *SO,
9660 SUMA_PICK_RESULT **PRi)
9661 {
9662 static char FuncName[]={"SUMA_Apply_PR_SO"};
9663 SUMA_ALL_DO *ado=NULL;
9664 DList *list = NULL;
9665 DListElmt *SetNodeElem = NULL, *Location=NULL;
9666 SUMA_Boolean NodeIgnored = NOPE;
9667 SUMA_PICK_RESULT *PR;
9668 int NP=0, ip=0, it=0, id = 0, iv3[3];
9669 SUMA_EngineData *ED = NULL;
9670 SUMA_Boolean LocalHead = NOPE;
9671
9672 SUMA_ENTRY;
9673
9674 if (strstr(SO->Label, "clippingPlaneIdentificationSquare_")){
9675 fprintf(stderr, "Clipping plane identification squares may not be selected.\n");
9676 return (0);
9677 }
9678
9679 // fprintf(stderr, "%s\n", FuncName);
9680
9681 if (!sv || !SO || !PRi || !*PRi) { SUMA_S_Err("Niente"); SUMA_RETURN(-1); }
9682
9683 /* Mark intersection Facsets */
9684 ado = (SUMA_ALL_DO *)SO;
9685
9686 PR = *PRi; /* Keep local copy */
9687 /* Store the PR in ado, hide it from return potential */
9688 SUMA_ADO_StorePickResult(ado, PRi);
9689
9690
9691 sv->Focus_DO_ID = ADO_iDO(ado);
9692 SUMA_UpdateViewerTitle(sv);
9693
9694 NP = SO->FaceSetDim;
9695 ip = NP * PR->iAltSel[SUMA_SURF_TRI];
9696
9697
9698 /* if the surface controller is open, update it */
9699 if (SUMA_isADO_Cont_Realized(ado))
9700 SUMA_Init_SurfCont_SurfParam(ado);
9701
9702 /* print nodes about the closets faceset*/
9703 fprintf(SUMA_STDOUT, "\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
9704 fprintf(SUMA_STDOUT, "Selected surface %s (Focus_DO_ID # %d).\n"
9705 "FaceSet %ld, Closest Node %ld\n",
9706 SO->Label, sv->Focus_DO_ID, PR->iAltSel[SUMA_SURF_TRI],
9707 PR->datum_index);
9708 fprintf(SUMA_STDOUT, "Nodes forming closest FaceSet:\n");
9709 fprintf(SUMA_STDOUT, "%d, %d, %d\n",
9710 SO->FaceSetList[ip], SO->FaceSetList[ip+1],SO->FaceSetList[ip+2]);
9711
9712 fprintf (SUMA_STDOUT,"Coordinates of Nodes forming closest FaceSet:\n");
9713 for (it=0; it < 3; ++it) {
9714
9715 id = SO->NodeDim * SO->FaceSetList[ip+it];
9716 fprintf(SUMA_STDOUT, "%f, %f, %f\n", SO->NodeList[id],
9717 SO->NodeList[id+1],
9718 SO->NodeList[id+2]);
9719 }
9720 fprintf(SUMA_STDOUT, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
9721
9722 /* Set the Nodeselection at the closest node */
9723 it = PR->datum_index;
9724 if (!list) list = SUMA_CreateList();
9725 if (PR->ignore_same_datum && SO->SelectedNode == PR->datum_index) {
9726 SUMA_LHv("Ignoring identical node selection %d on surface %s\n",
9727 SO->SelectedNode, SO->Label);
9728 NodeIgnored = YUP;
9729 } else {
9730 ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
9731 SetNodeElem = SUMA_RegisterEngineListCommand ( list, ED,
9732 SEF_i, (void*)&it,
9733 SES_Suma, (void *)sv, NOPE,
9734 SEI_Head, NULL);
9735 if (!SetNodeElem) {
9736 fprintf( SUMA_STDERR,
9737 "Error %s: Failed to register SetNodeElem\n", FuncName);
9738 SUMA_RETURN (-1);
9739 } else {
9740 SUMA_RegisterEngineListCommand ( list, ED,
9741 SEF_ngr, NULL,
9742 SES_Suma, (void *)sv, NOPE,
9743 SEI_In, SetNodeElem);
9744 }
9745 }
9746
9747
9748 /* Set the FaceSetselection */
9749 it = PR->iAltSel[SUMA_SURF_TRI];
9750 ED = SUMA_InitializeEngineListData (SE_SetSelectedFaceSet);
9751 if (!SUMA_RegisterEngineListCommand ( list, ED,
9752 SEF_i, (void*)&it,
9753 SES_Suma, (void *)sv, NOPE,
9754 SEI_Head, NULL)) {
9755 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9756 SUMA_RETURN (-1);
9757 }
9758
9759 /* Now set the cross hair position at the intersection*/
9760 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
9761 if (!(Location = SUMA_RegisterEngineListCommand ( list, ED,
9762 SEF_fv3, (void*)PR->PickXYZ,
9763 SES_Suma, (void *)sv, NOPE,
9764 SEI_Head, NULL))) {
9765 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9766 SUMA_RETURN (-1);
9767 }
9768 /* and add the SO with this location, needed for VisX business*/
9769 SUMA_RegisterEngineListCommand ( list, ED,
9770 SEF_vp, (void *)SO,
9771 SES_Suma, (void *)sv, NOPE,
9772 SEI_In, Location);
9773
9774 /* attach the cross hair to the selected surface */
9775 iv3[0] = SUMA_findSO_inDOv(SO->idcode_str, SUMAg_DOv, SUMAg_N_DOv);
9776 iv3[1] = PR->datum_index;
9777 iv3[2] = PR->iAltSel[SUMA_SURF_TRI];
9778 ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
9779 if (!SUMA_RegisterEngineListCommand ( list, ED,
9780 SEF_iv3, (void*)iv3,
9781 SES_Suma, (void *)sv, NOPE,
9782 SEI_Head, NULL)) {
9783 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9784 SUMA_RETURN (-1);
9785 }
9786
9787 /* check to see if AFNI needs to be notified */
9788 /* Need to deal with SUMA_TO_MATLAB_STREAM_INDEX too
9789 Same for remaining occurrence of SUMA_AFNI_STREAM_INDEX*/
9790 if ( ( SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] &&
9791 sv->LinkAfniCrossHair ) ||
9792 ( SUMAg_CF->Connected_v[SUMA_HALLO_SUMA_LINE]) ||
9793 ( SUMAg_CF->Connected_v[SUMA_INSTA_TRACT_LINE]) ) {
9794 if (LocalHead)
9795 fprintf(SUMA_STDERR,
9796 "%s: Notifying Afni of CrossHair XYZ\n", FuncName);
9797 /* register a call to SetAfniCrossHair */
9798 if (!list) list = SUMA_CreateList();
9799 it = SUMA_ShftCont_Event(PR->evr);
9800 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
9801 if (!SUMA_RegisterEngineListCommand ( list, ED,
9802 SEF_i, (void*)&it,
9803 SES_Suma, (void *)sv, NOPE,
9804 SEI_Tail, NULL)) {
9805 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9806 SUMA_RETURN (-1);
9807 }
9808 if (MASK_MANIP_MODE(sv) && SUMAg_CF->Dev) {
9809 SUMA_ALL_DO *ado = SUMA_whichADOg(sv->MouseMode_ado_idcode_str);
9810 if (ado && ado->do_type == MASK_type) {
9811 SUMA_MaskDO *mdo = (SUMA_MaskDO *)ado;
9812 ED = SUMA_InitializeEngineListData (SE_SetAfniMask);
9813 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
9814 SEF_fv3, (void*)mdo->cen,
9815 SES_Suma, (void *)sv, NOPE,
9816 SEI_Tail, NULL))) {
9817 SUMA_S_Err("Failed to register element\n");
9818 SUMA_RETURN (-1);
9819 }
9820 SUMA_RegisterEngineListCommand ( list, ED,
9821 SEF_s, (void *)(ADO_ID(ado)),
9822 SES_Suma, (void *)sv, NOPE,
9823 SEI_In, Location);
9824 }
9825 }
9826 if (!SUMA_Engine (&list)) {
9827 fprintf( SUMA_STDERR,
9828 "Error %s: SUMA_Engine call failed.\n", FuncName);
9829 SUMA_RETURN (-1);
9830 }
9831 }else {
9832 if (LocalHead)
9833 fprintf(SUMA_STDERR,"%s: No Notification to AFNI.\n", FuncName);
9834 }
9835
9836 /* put in a request for GICOR if need be */
9837 if ( !NodeIgnored &&
9838 SUMAg_CF->Connected_v[SUMA_GICORR_LINE] &&
9839 SUMAg_CF->giset && !SUMAg_CF->HoldClickCallbacks) {
9840 if (LocalHead)
9841 fprintf(SUMA_STDERR,
9842 "%s: Notifying GICOR of node selection\n", FuncName);
9843 /* register a call to SetGICORnode */
9844 if (!list) list = SUMA_CreateList();
9845 SUMA_REGISTER_TAIL_COMMAND_NO_DATA( list, SE_SetGICORnode,
9846 SES_Suma, sv);
9847 if (!SUMA_Engine (&list)) {
9848 fprintf( SUMA_STDERR,
9849 "Error %s: SUMA_Engine call failed.\n", FuncName);
9850 SUMA_RETURN (-1);
9851 }
9852 }else {
9853 if (LocalHead)
9854 fprintf(SUMA_STDERR,"%s: No Notification to GICOR.\n", FuncName);
9855 }
9856 /* now put in a request for locking cross hair but you must do
9857 this after the node selection has been executed
9858 NOTE: You do not always have SetNodeElem because the list might
9859 get emptied in the call to AFNI notification.
9860 You should just put the next call at the end of the list.*/
9861 SUMA_LH("Cross hair locking");
9862 if (!list) list = SUMA_CreateList();
9863 ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
9864 if (!SUMA_RegisterEngineListCommand ( list, ED,
9865 SEF_iv3, (void*)iv3,
9866 SES_Suma, (void *)sv, NOPE,
9867 SEI_Tail, NULL)) {
9868 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9869 SUMA_RETURN (-1);
9870 }
9871
9872 SUMA_LH("Cross hair locking Engine call");
9873 if (!SUMA_Engine (&list)) {
9874 fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
9875 SUMA_RETURN (-1);
9876 }
9877 SUMA_LH("Returning");
9878 SUMA_RETURN (1); /* OK */
9879 }/* determine intersection */
9880
SUMA_MarkLineCutplaneIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode)9881 int SUMA_MarkLineCutplaneIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
9882 int IgnoreSameNode)
9883 {/* determine intersection */
9884 static char FuncName[]={"SUMA_MarkLineCutplaneIntersect"};
9885 float P0f[3], P1f[3];
9886 int NP;
9887 SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL, *MTIi = NULL;
9888 float delta_t_tmp, dmin;
9889 struct timeval tt_tmp;
9890 int ip, it, id, iv3[3], ii, N_SOlist,
9891 SOlist[SUMA_MAX_DISPLAYABLE_OBJECTS], imin;
9892 char sfield[100], sdestination[100], CommString[SUMA_MAX_COMMAND_LENGTH];
9893 SUMA_EngineData *ED = NULL;
9894 DList *list = NULL;
9895 DListElmt *SetNodeElem = NULL, *Location=NULL;
9896 SUMA_SurfaceObject *SO = NULL;
9897 SUMA_SurfaceObject **SOv = NULL;
9898 SUMA_VolumeObject *VO=NULL;
9899 SUMA_Boolean NodeIgnored = NOPE;
9900 SUMA_Boolean LocalHead = NOPE;
9901
9902 SUMA_ENTRY;
9903
9904 // fprintf(stderr, "%s\n", FuncName);
9905
9906 P0f[0] = sv->Pick0[0];
9907 P0f[1] = sv->Pick0[1];
9908 P0f[2] = sv->Pick0[2];
9909 P1f[0] = sv->Pick1[0];
9910 P1f[1] = sv->Pick1[1];
9911 P1f[2] = sv->Pick1[2];
9912
9913 SUMA_LH("Getting array of pointers to clip plane surfaces");
9914 if (!(SOv = SUMA_TextureClipPlaneSurfaces(&N_SOlist))) {
9915 SUMA_LH("No clip plane surfaces");
9916 SUMA_RETURN(0);
9917 }
9918 imin = -1;
9919 dmin = 10000000.0;
9920 for (ii=0; ii < N_SOlist; ++ii) { /* find the closest intersection */
9921 if (LocalHead)
9922 fprintf (SUMA_STDERR,
9923 "%s: working %d/%d clip plane ...\n",
9924 FuncName, ii, N_SOlist);
9925 SO = SOv[ii];
9926 if (SO->FaceSetDim != 3) {
9927 fprintf(SUMA_STDERR,
9928 "Error %s: "
9929 "SUMA_MT_intersect_triangle only works for triangular meshes.\n",
9930 FuncName);
9931 } else {
9932
9933 SUMA_etime (&tt_tmp, 0);
9934 SUMA_LH("About to call intersection function");
9935
9936 MTIi = SUMA_MT_intersect_triangle(P0f, P1f, SO->NodeList, SO->N_Node,
9937 SO->FaceSetList, SO->N_FaceSet, NULL, 0);
9938
9939 delta_t_tmp = SUMA_etime (&tt_tmp, 1);
9940 if (LocalHead)
9941 fprintf (SUMA_STDERR,
9942 "Local Debug %s: Intersection took %f seconds.\n",
9943 FuncName, delta_t_tmp);
9944
9945 if (MTIi == NULL) {
9946 fprintf(SUMA_STDERR,
9947 "Error %s: SUMA_MT_intersect_triangle failed.\n", FuncName);
9948 SUMA_RETURN (-1);
9949 }
9950
9951 if (MTIi->N_hits) {
9952 /* decide on the closest surface to the clicking point */
9953 if (MTIi->t[MTIi->ifacemin] < dmin) {
9954 if (LocalHead)
9955 fprintf (SUMA_STDERR, "%s: A minimum for surface %d.\n",
9956 FuncName, ii);
9957 dmin = MTIi->t[MTIi->ifacemin];
9958 imin = ii;
9959 MTI = MTIi;
9960 }else {
9961 /* not good, toss it away */
9962 if (LocalHead)
9963 fprintf (SUMA_STDERR,
9964 "%s: ii=%d freeing MTIi...\n", FuncName, ii);
9965 MTIi = SUMA_Free_MT_intersect_triangle(MTIi);
9966 }
9967 }else {
9968 /* not good, toss it away */
9969 if (LocalHead)
9970 fprintf (SUMA_STDERR,
9971 "%s: ii=%d freeing MTIi no hits...\n", FuncName, ii);
9972 MTIi = SUMA_Free_MT_intersect_triangle(MTIi);
9973 }
9974 }
9975 }
9976
9977 if (LocalHead)
9978 fprintf (SUMA_STDERR,
9979 "%s: Closest surface is indexed %d in cutplane surfaces.\n",
9980 FuncName, imin);
9981
9982 /* Mark intersection Facsets */
9983 if (imin >= 0) {
9984 SUMA_ALL_DO *ado=NULL;
9985 if (!(VO = SUMA_VolumeObjectOfClipPlaneSurface(SO))) {
9986 SUMA_S_Err("Failed to find volume object for clipped surface");
9987 SUMA_RETURN(-1);
9988 }
9989 VO->SelectedCutPlane = imin;
9990 SUMA_S_Warn("NEED TO IMPLEMENT PR THING HERE, THEN PASS IT BELOW");
9991 ado = (SUMA_ALL_DO *)VO;
9992 if (!SUMA_Add_To_PickResult_List(sv, ado, "cutplane", NULL)) {
9993 SUMA_S_Err("Failed to add selected ado");
9994 SUMA_RETURN(-1);
9995 }
9996 /* Now set this volume as the focus DO */
9997 sv->Focus_DO_ID =
9998 SUMA_findVO_inDOv(SUMA_ADO_idcode(ado), SUMAg_DOv, SUMAg_N_DOv);
9999
10000 /* if the surface controller is open, update it */
10001 if (SUMA_isADO_Cont_Realized(ado))
10002 SUMA_Init_SurfCont_SurfParam(ado);
10003
10004 SUMA_UpdateViewerTitle(sv);
10005
10006 /* if the surface controller is open, update it */
10007 if (SUMA_isADO_Cont_Realized(ado))
10008 SUMA_Init_SurfCont_SurfParam(ado);
10009
10010
10011 ip = SO->FaceSetDim * MTI->ifacemin;
10012 SUMA_S_Note("Have to decide on what to do here,\n"
10013 "see equivalent section in SUMA_MarkLineSurfaceIntersect");
10014 SUMA_S_Warn("Weird, coords all zero");
10015 /* print nodes about the closets faceset*/
10016 fprintf(SUMA_STDOUT, "\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
10017 fprintf(SUMA_STDOUT, "Selected cutplane surface %d .\n"
10018 "FaceSet %d, Closest Node %d\n",
10019 imin, MTI->ifacemin, MTI->inodemin);
10020 fprintf(SUMA_STDOUT, "Nodes forming closest FaceSet:\n");
10021 fprintf(SUMA_STDOUT, "%d, %d, %d\n", \
10022 SO->FaceSetList[ip], SO->FaceSetList[ip+1],SO->FaceSetList[ip+2]);
10023
10024 fprintf (SUMA_STDOUT,"Coordinates of Nodes forming closest FaceSet:\n"
10025 "SO->NodeDim = %d \n", SO->NodeDim);
10026 for (it=0; it < 3; ++it) {
10027
10028 id = SO->NodeDim * SO->FaceSetList[ip+it];
10029 fprintf(SUMA_STDOUT, "%f, %f, %f\n", SO->NodeList[id],
10030 SO->NodeList[id+1],
10031 SO->NodeList[id+2]);
10032 }
10033 fprintf(SUMA_STDOUT, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
10034
10035
10036
10037 /* Now set the cross hair position at the intersection*/
10038 if (!list) list = SUMA_CreateList();
10039 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
10040 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
10041 SEF_fv3, (void*)MTI->P,
10042 SES_Suma, (void *)sv, NOPE,
10043 SEI_Head, NULL))) {
10044 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
10045 SUMA_RETURN (-1);
10046 }
10047 /* and add the SO with this location, needed for VisX business*/
10048 SUMA_RegisterEngineListCommand ( list, ED,
10049 SEF_vp, (void *)SO,
10050 SES_Suma, (void *)sv, NOPE,
10051 SEI_In, Location);
10052
10053 if (!SUMA_Engine (&list)) {
10054 fprintf( SUMA_STDERR,
10055 "Error %s: SUMA_Engine call failed.\n", FuncName);
10056 SUMA_RETURN (-1);
10057 }
10058 /* check to see if AFNI needs to be notified */
10059 /* Need to deal with SUMA_TO_MATLAB_STREAM_INDEX too
10060 Same for remaining occurrence of SUMA_AFNI_STREAM_INDEX*/
10061 if ( SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] &&
10062 sv->LinkAfniCrossHair) {
10063 if (LocalHead)
10064 fprintf(SUMA_STDERR,
10065 "%s: Notifying Afni of CrossHair XYZ\n", FuncName);
10066 /* register a call to SetAfniCrossHair */
10067 if (!list) list = SUMA_CreateList();
10068 it = 0; /* Might want someday: SUMA_ShftCont_Event(PR->evr); */
10069 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
10070 if (!SUMA_RegisterEngineListCommand ( list, ED,
10071 SEF_i, (void*)&it,
10072 SES_Suma, (void *)sv, NOPE,
10073 SEI_Tail, NULL)) {
10074 SUMA_S_Err("Failed to register element\n");
10075 SUMA_RETURN (-1);
10076 }
10077 if (!SUMA_Engine (&list)) {
10078 fprintf( SUMA_STDERR,
10079 "Error %s: SUMA_Engine call failed.\n", FuncName);
10080 SUMA_RETURN (-1);
10081 }
10082 }else {
10083 if (LocalHead)
10084 fprintf(SUMA_STDERR,"%s: No Notification to AFNI.\n", FuncName);
10085 }
10086
10087 /* put in a request for GICOR if need be */
10088 if ( !NodeIgnored &&
10089 SUMAg_CF->Connected_v[SUMA_GICORR_LINE] &&
10090 SUMAg_CF->giset && !SUMAg_CF->HoldClickCallbacks) {
10091 if (LocalHead)
10092 fprintf(SUMA_STDERR,
10093 "%s: Notifying GICOR of node selection\n", FuncName);
10094 /* register a call to SetGICORnode */
10095 if (!list) list = SUMA_CreateList();
10096 SUMA_REGISTER_TAIL_COMMAND_NO_DATA( list, SE_SetGICORnode,
10097 SES_Suma, sv);
10098 if (!SUMA_Engine (&list)) {
10099 fprintf( SUMA_STDERR,
10100 "Error %s: SUMA_Engine call failed.\n", FuncName);
10101 SUMA_RETURN (-1);
10102 }
10103 }else {
10104 if (LocalHead)
10105 fprintf(SUMA_STDERR,"%s: No Notification to GICOR.\n", FuncName);
10106 }
10107
10108
10109
10110 }
10111 /* clear MTI */
10112 if (MTI) {
10113 MTI = SUMA_Free_MT_intersect_triangle(MTI);
10114 }
10115
10116 SUMA_free(SOv); SOv = NULL;
10117
10118 if (imin >= 0) {
10119 SUMA_RETURN (1); /* hit */
10120 } else {
10121 SUMA_RETURN (0); /* no hit */
10122 }
10123 }/* determine intersection with cutplanes*/
10124
SUMA_MarkLineVOslicesIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode)10125 int SUMA_MarkLineVOslicesIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
10126 int IgnoreSameNode)
10127 {/* determine intersection */
10128 static char FuncName[]={"SUMA_MarkLineVOslicesIntersect"};
10129 SUMA_PICK_RESULT *PR = NULL;
10130 SUMA_ALL_DO *ado = NULL;
10131 int ans;
10132
10133 SUMA_ENTRY;
10134
10135 // fprintf(stderr, "%s\n", FuncName);
10136 SUMA_S_Warn("Do not call me anymore. Follow the new selection logic");
10137 ans = SUMA_ComputeLineVOslicesIntersect(sv, dov, IgnoreSameNode, &ado);
10138 if (ans <= 0) {
10139 SUMA_RETURN(ans);
10140 }
10141 /* just for temporary testing, get PR back from list and apply it */
10142 PR = SUMA_Get_From_PickResult_List(sv, ado, NULL);
10143 ans = SUMA_Apply_PR(sv, &PR);
10144 SUMA_RETURN(ans);
10145 }
10146
10147 #if 0
10148 /* BEFORE you start using this MACRO everywhere, including with the,
10149 other ThrMode values, make sure you write a function version of it
10150 which can be used as a sanity check. For now, this seems OK */
10151 #define SUMA_VAL_MEETS_THRESH(val, ThreshRange, ThrMode) (\
10152 ((ThrMode) == SUMA_LESS_THAN && (val) >= ThreshRange[0])?1: \
10153 (((ThrMode) == SUMA_ABS_LESS_THAN && ( (val) >= ThreshRange[0] || \
10154 (val) <= -ThreshRange[0]))?1:0) )
10155 #endif
SUMA_Val_Meets_Thresh(float val,double * ThreshRange,SUMA_THRESH_MODE ThrMode)10156 byte SUMA_Val_Meets_Thresh(float val, double *ThreshRange,
10157 SUMA_THRESH_MODE ThrMode)
10158 {
10159 static char FuncName[]={"SUMA_Val_Meets_Thresh"};
10160
10161 // fprintf(stderr, "%s\n", FuncName);
10162 switch(ThrMode){
10163 case SUMA_LESS_THAN:
10164 return((val >= ThreshRange[0]));
10165 break;
10166 case SUMA_ABS_LESS_THAN:
10167 return((val >= ThreshRange[0]) || (val <= -ThreshRange[0]));
10168 break;
10169 case SUMA_THRESH_OUTSIDE_RANGE:
10170 return((val < ThreshRange[0]) || (val > ThreshRange[1]));
10171 break;
10172 case SUMA_THRESH_INSIDE_RANGE:
10173 return((val >= ThreshRange[0]) && (val <= ThreshRange[1]));
10174 break;
10175 case SUMA_NO_THRESH:
10176 return(1);
10177 default:
10178 SUMA_S_Warn("Bad thresh mode %d", ThrMode);
10179 return(1);
10180 break;
10181 }
10182 SUMA_S_Warn("Should not be here %d", ThrMode);
10183 return(1);
10184 }
10185
10186 /*
10187 This function is almost identical to SUMA_ComputeLineVOvrIntersect()
10188 They could be merged quite readily but for some reason this feels
10189 cleaner to me.
10190 Make sure that any change here is mirrored verbatim (to the degree possible)
10191 in SUMA_ComputeLineVOvrIntersect() .
10192
10193 Consider merging SUMA_ComputeLineVOvrIntersect() into
10194 SUMA_ComputeLineVOslicesIntersect() in the future if maintenance is a problem
10195 */
SUMA_ComputeLineVOslicesIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode,SUMA_ALL_DO ** pado)10196 int SUMA_ComputeLineVOslicesIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
10197 int IgnoreSameNode, SUMA_ALL_DO **pado)
10198 {/* determine intersection */
10199 static char FuncName[]={"SUMA_ComputeLineVOslicesIntersect"};
10200 float P0f[3], P1f[3], pinter[3], I[3];
10201 int NP, N_Hit, okinten=0;
10202 float delta_t_tmp, dmin, val;
10203 struct timeval tt_tmp;
10204 int ip, it, id, ii, imin, I1d, Irw, Hit, ive, icolplane, indef=-1;
10205 int *MembDOs=NULL, N_MembDOs, UseAlphaTresh=1;
10206 float valpha=0.0;
10207 SUMA_DO_Types ttv[12];
10208 char sfield[100], sdestination[100], CommString[SUMA_MAX_COMMAND_LENGTH];
10209 SUMA_VolumeObject *VO=NULL;
10210 SUMA_Boolean NodeIgnored = NOPE;
10211 SUMA_RENDERED_SLICE *rslc;
10212 SUMA_ALL_DO *ado = NULL;
10213 SUMA_DSET *dset = NULL;
10214 SUMA_OVERLAYS *colplane=NULL;
10215 SUMA_VOL_SAUX *VSaux = NULL;
10216 SUMA_PICK_RESULT *PR=NULL;
10217 DListElmt *el=NULL;
10218 SUMA_Boolean LocalHead = NOPE;
10219
10220 SUMA_ENTRY;
10221
10222 // fprintf(stderr, "%s\n", FuncName);
10223
10224 P0f[0] = sv->Pick0[0];
10225 P0f[1] = sv->Pick0[1];
10226 P0f[2] = sv->Pick0[2];
10227 P1f[0] = sv->Pick1[0];
10228 P1f[1] = sv->Pick1[1];
10229 P1f[2] = sv->Pick1[2];
10230
10231 ttv[0] = VO_type; ttv[1] = NOT_SET_type;
10232 MembDOs = SUMA_ViewState_Membs(&(sv->VSv[sv->iState]), ttv, &N_MembDOs);
10233 SUMA_LHv("Searching for hit: %f %f %f --> %f %f %f\n",
10234 P0f[0], P0f[1], P0f[2], P1f[0], P1f[1], P1f[2]);
10235 N_Hit = 0;
10236 for (ii=0; ii<N_MembDOs; ++ii) {
10237 {
10238 VO = (SUMA_VolumeObject *)(dov[MembDOs[ii]].OP);
10239 ado = (SUMA_ALL_DO *)VO;
10240 if (!(VSaux = SUMA_ADO_VSaux(ado))) continue;
10241 SUMA_LH("%d slices on %s", dlist_size(VSaux->slcl), ADO_LABEL(ado));
10242 if (!dlist_size(VSaux->slcl)) continue;
10243 /* now compute intersection from the top down */
10244 Hit = 0;
10245 el = NULL;
10246 do {
10247 if (!el) el = dlist_head(VSaux->slcl);
10248 else el = dlist_next(el);
10249 rslc = (SUMA_RENDERED_SLICE *)el->data;
10250 /* does line intersect this plane? */
10251 SUMA_SEGMENT_PLANE_INTERSECT(P0f, P1f, rslc->Eq, Hit, pinter);
10252 if (Hit) {/* is the intersection point in the volume? */
10253 Hit = 0; /* demote, real hit decided on below */
10254 ive = 0;
10255 while (VO->VE && VO->VE[ive]) {
10256 AFF44_MULT_I(I, VO->VE[ive]->X2I, pinter);
10257 SUMA_LH("On %s: Inter at X=[%f %f %f] --> ijk=[%f %f %f]",
10258 SUMA_VE_Headname(VO->VE, ive),
10259 pinter[0], pinter[1], pinter[2], I[0], I[1], I[2]);
10260 I[0] = (int)I[0]; I[1] = (int)I[1]; I[2] = (int)I[2];
10261 if (I[0] >= 0.0f && I[1] >= 0.0f && I[2] >= 0.0f &&
10262 I[0] < VO->VE[ive]->Ni && I[1] < VO->VE[ive]->Nj &&
10263 I[2] < VO->VE[ive]->Nk) {
10264 dset = SUMA_VE_dset(VO->VE, ive);
10265 colplane = SUMA_Fetch_OverlayPointerByDset(
10266 (SUMA_ALL_DO *)VO, dset, &icolplane);
10267 /* here you check on the value at I in the dataset */
10268 I1d = I[2]*VO->VE[ive]->Ni*VO->VE[ive]->Nj +
10269 I[1]*VO->VE[ive]->Ni+I[0];
10270 Irw = SUMA_GetNodeRow_FromNodeIndex_eng(dset, I1d,-1);
10271 if (!colplane->V) {
10272 SUMA_S_Err("Need SUMA_GetDsetValInCol to get vals");
10273 SUMA_RETURN(NOPE);
10274 } else {
10275 val = colplane->V[Irw];
10276 }
10277 SUMA_LH("Have intersection on ive %d inside VE %s\n"
10278 "IJK [%d %d %d], I1d=%d, Irw=%d, \n"
10279 "val %f, thr [%f %f]\n",
10280 ive, SUMA_VE_Headname(VO->VE, ive),
10281 (int)I[0], (int)I[1], (int)I[2],
10282 I1d, Irw, val,
10283 colplane->OptScl->ThreshRange[0],
10284 colplane->OptScl->ThreshRange[1]);
10285
10286 /* Do we meet intensity thresholds? */
10287 okinten = 0;
10288 if ( SUMA_Val_Meets_Thresh(val,
10289 colplane->OptScl->ThreshRange,
10290 colplane->OptScl->ThrMode ) &&
10291 (val != 0.0f || !colplane->OptScl->MaskZero)) {
10292 okinten = 1;
10293 }
10294
10295 indef = -1;
10296 UseAlphaTresh = 1;/* control from interface someday */
10297 valpha = 2.0; /* no masking */
10298 if (UseAlphaTresh && okinten && colplane->ColAlpha) {
10299 /* Also mask if value is below alpha thresh
10300 This is a slow search... So you may not want
10301 to use it all the time.
10302 Problem is finding the row of the voxel in
10303 NodeDef, and that's too slow for a big
10304 volume to be run repeatedly...Would
10305 be easier if I had a function to recompute
10306 a voxel's alpha, rather than search for it
10307 in ColAlpha. Oh, well, someday I guess. For
10308 now we search*/
10309 if ((indef=SUMA_GetSortedNodeOverInd(colplane, I1d))>=0){
10310 valpha = colplane->ColAlpha[indef]/255.0;
10311 }
10312 }
10313
10314 if ( okinten && (valpha > colplane->AlphaThresh) ) {
10315 SUMA_LH("FOUND IT, on VE %s, IJK [%d %d %d], val %f,"
10316 "thresh[%f %f], UseAlphaTresh = %d, "
10317 "valpha=%f, ColAlphaThresh=%f\n",
10318 SUMA_VE_Headname(VO->VE, ive),
10319 (int)I[0], (int)I[1], (int)I[2], val,
10320 colplane->OptScl->ThreshRange[0],
10321 colplane->OptScl->ThreshRange[1],
10322 UseAlphaTresh,
10323 valpha, colplane->AlphaThresh*255);
10324 PR = SUMA_New_Pick_Result(NULL);
10325 PR->ado_idcode_str = SUMA_replace_string(
10326 PR->ado_idcode_str, ADO_ID(ado));
10327 if (pado) *pado = ado; /* user wants it */
10328 PR->primitive = SUMA_replace_string(
10329 PR->primitive,"voxel");
10330 PR->primitive_index = -1;
10331 PR->PickXYZ[0] = pinter[0];
10332 PR->PickXYZ[1] = pinter[1];
10333 PR->PickXYZ[2] = pinter[2];
10334 PR->ignore_same_datum = IgnoreSameNode;
10335 PR->datum_index = I1d;
10336 PR->iAltSel[SUMA_VOL_I] = I[0];
10337 PR->iAltSel[SUMA_VOL_J] = I[1];
10338 PR->iAltSel[SUMA_VOL_K] = I[2];
10339 PR->iAltSel[SUMA_VOL_IJK] = I1d;
10340 PR->iAltSel[SUMA_VOL_SLC_NUM] = rslc->slc_num;
10341 PR->iAltSel[SUMA_VOL_SLC_VARIANT] =
10342 (int)SUMA_SlcVariantToCode(rslc->variant);
10343 PR->dAltSel[SUMA_VOL_SLC_EQ0] = rslc->Eq[0];
10344 PR->dAltSel[SUMA_VOL_SLC_EQ1] = rslc->Eq[1];
10345 PR->dAltSel[SUMA_VOL_SLC_EQ2] = rslc->Eq[2];
10346 PR->dAltSel[SUMA_VOL_SLC_EQ3] = rslc->Eq[3];
10347 PR->dset_idcode_str = SUMA_replace_string(
10348 PR->dset_idcode_str, SDSET_ID(dset));
10349 if (!SUMA_Add_To_PickResult_List(sv, ado,
10350 "voxel", &PR)) {
10351 SUMA_S_Err("Failed to add selected ado");
10352 SUMA_RETURN(0);
10353 }
10354 Hit = 1;
10355 ++N_Hit;
10356 /* You could leave at the first hit IF:
10357 you only have one direction of slices in the
10358 entire stack, AND if they are properly
10359 ordered for rendering.
10360 Should speed be an issue you can check for
10361 this condition and bolt with the line below */
10362 /* goto GOT_IT; */
10363 }
10364 }
10365 ++ive;
10366 }
10367 }
10368 SUMA_LH("el now %p,\n"
10369 "tail = %p, N_Hit = %d",
10370 el, dlist_tail(VSaux->slcl), N_Hit);
10371 } while(el != dlist_tail(VSaux->slcl));
10372 }
10373 }
10374
10375
10376 GOT_IT:
10377 SUMA_RETURN(N_Hit);
10378 }/* determine intersection with slices of VO*/
10379
10380 /*
10381 This function is almost identical to SUMA_ComputeLineVOslicesIntersect()
10382 They could be merged quite readily but for some reason this feels
10383 cleaner to me.
10384 Make sure that any change here is mirrored verbatim (to the degree possible)
10385 in SUMA_ComputeLineVOslicesIntersect() .
10386
10387 Consider merging SUMA_ComputeLineVOvrIntersect() into
10388 SUMA_ComputeLineVOslicesIntersect() in the future if maintenance is a problem
10389
10390
10391 */
SUMA_ComputeLineVOvrIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode,SUMA_ALL_DO ** pado)10392 int SUMA_ComputeLineVOvrIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
10393 int IgnoreSameNode, SUMA_ALL_DO **pado)
10394 {/* determine intersection */
10395 static char FuncName[]={"SUMA_ComputeLineVOvrIntersect"};
10396 float P0f[3], P1f[3], pinter[3], I[3];
10397 int NP, N_Hit, okinten=0;
10398 float delta_t_tmp, dmin, val;
10399 struct timeval tt_tmp;
10400 int ip, it, id, ii, imin, I1d, Irw, Hit, ive, icolplane, indef=-1;
10401 int *MembDOs=NULL, N_MembDOs, UseAlphaTresh=1;
10402 float valpha=0.0;
10403 SUMA_DO_Types ttv[12];
10404 char sfield[100], sdestination[100], CommString[SUMA_MAX_COMMAND_LENGTH];
10405 SUMA_VolumeObject *VO=NULL;
10406 SUMA_Boolean NodeIgnored = NOPE;
10407 SUMA_RENDERED_SLICE *rslc;
10408 SUMA_ALL_DO *ado = NULL;
10409 SUMA_DSET *dset = NULL;
10410 SUMA_OVERLAYS *colplane=NULL;
10411 SUMA_VOL_SAUX *VSaux = NULL;
10412 SUMA_PICK_RESULT *PR=NULL;
10413 DListElmt *el=NULL;
10414 SUMA_Boolean LocalHead = NOPE;
10415
10416 SUMA_ENTRY;
10417
10418 // fprintf(stderr, "%s\n", FuncName);
10419
10420 P0f[0] = sv->Pick0[0];
10421 P0f[1] = sv->Pick0[1];
10422 P0f[2] = sv->Pick0[2];
10423 P1f[0] = sv->Pick1[0];
10424 P1f[1] = sv->Pick1[1];
10425 P1f[2] = sv->Pick1[2];
10426
10427 ttv[0] = VO_type; ttv[1] = NOT_SET_type;
10428 MembDOs = SUMA_ViewState_Membs(&(sv->VSv[sv->iState]), ttv, &N_MembDOs);
10429 SUMA_LHv("Searching for hit: %f %f %f --> %f %f %f\n",
10430 P0f[0], P0f[1], P0f[2], P1f[0], P1f[1], P1f[2]);
10431 N_Hit = 0;
10432 for (ii=0; ii<N_MembDOs; ++ii) {
10433 {
10434 VO = (SUMA_VolumeObject *)(dov[MembDOs[ii]].OP);
10435 ado = (SUMA_ALL_DO *)VO;
10436 if (!(VSaux = SUMA_ADO_VSaux(ado))) continue;
10437 SUMA_LH("%d VR slices on %s, show=%d, VrSelect=%d",
10438 dlist_size(VSaux->vrslcl),
10439 ADO_LABEL(ado), VSaux->ShowVrSlc,
10440 VSaux->VrSelect);
10441 if (!VSaux->ShowVrSlc || !VSaux->VrSelect) continue;
10442 if (!dlist_size(VSaux->vrslcl)) continue;
10443 /* now compute intersection from the top down */
10444 Hit = 0;
10445 el = NULL;
10446 do {
10447 if (!el) el = dlist_head(VSaux->vrslcl);
10448 else el = dlist_next(el);
10449 rslc = (SUMA_RENDERED_SLICE *)el->data;
10450 /* does line intersect this plane? */
10451 SUMA_SEGMENT_PLANE_INTERSECT(P0f, P1f, rslc->Eq, Hit, pinter);
10452 if (Hit) {/* is the intersection point in the volume? */
10453 Hit = 0; /* demote, real hit decided on below */
10454 ive = 0;
10455 while (VO->VE && VO->VE[ive]) {
10456 AFF44_MULT_I(I, VO->VE[ive]->X2I, pinter);
10457 SUMA_LH("On %s: Inter at X=[%f %f %f] --> ijk=[%f %f %f]",
10458 SUMA_VE_Headname(VO->VE, ive),
10459 pinter[0], pinter[1], pinter[2], I[0], I[1], I[2]);
10460 I[0] = (int)I[0]; I[1] = (int)I[1]; I[2] = (int)I[2];
10461 if (I[0] >= 0.0f && I[1] >= 0.0f && I[2] >= 0.0f &&
10462 I[0] < VO->VE[ive]->Ni && I[1] < VO->VE[ive]->Nj &&
10463 I[2] < VO->VE[ive]->Nk) {
10464 dset = SUMA_VE_dset(VO->VE, ive);
10465 colplane = SUMA_Fetch_OverlayPointerByDset(
10466 (SUMA_ALL_DO *)VO, dset, &icolplane);
10467 /* here you check on the value at I in the dataset */
10468 I1d = I[2]*VO->VE[ive]->Ni*VO->VE[ive]->Nj +
10469 I[1]*VO->VE[ive]->Ni+I[0];
10470 Irw = SUMA_GetNodeRow_FromNodeIndex_eng(dset, I1d,-1);
10471 if (!colplane->V) {
10472 SUMA_S_Err("Need SUMA_GetDsetValInCol to get vals");
10473 SUMA_RETURN(NOPE);
10474 } else {
10475 val = colplane->V[Irw];
10476 }
10477 SUMA_LH("Have intersection on ive %d inside VE %s\n"
10478 "IJK [%d %d %d], I1d=%d, Irw=%d, \n"
10479 "val %f, thr [%f %f]\n",
10480 ive, SUMA_VE_Headname(VO->VE, ive),
10481 (int)I[0], (int)I[1], (int)I[2],
10482 I1d, Irw, val,
10483 colplane->OptScl->ThreshRange[0],
10484 colplane->OptScl->ThreshRange[1]);
10485
10486 /* Do we meet intensity thresholds? */
10487 okinten = 0;
10488 if ( SUMA_Val_Meets_Thresh(val,
10489 colplane->OptScl->ThreshRange,
10490 colplane->OptScl->ThrMode ) &&
10491 (val != 0.0f || !colplane->OptScl->MaskZero)) {
10492 okinten = 1;
10493 }
10494
10495 indef = -1;
10496 UseAlphaTresh = 1;/* control from interface someday */
10497 valpha = 2.0; /* no masking */
10498 if (UseAlphaTresh && okinten && colplane->ColAlpha) {
10499 /* Also mask if value is below alpha thresh
10500 This is a slow search... So you may not want
10501 to use it all the time.
10502 Problem is finding the row of the voxel in
10503 NodeDef, and that's too slow for a big
10504 volume to be run repeatedly...Would
10505 be easier if I had a function to recompute
10506 a voxel's alpha, rather than search for it
10507 in ColAlpha. Oh, well, someday I guess. For
10508 now we search*/
10509 if ((indef=SUMA_GetSortedNodeOverInd(colplane, I1d))>=0){
10510 valpha = colplane->ColAlpha[indef]/255.0;
10511 }
10512 }
10513
10514 if ( okinten && (valpha > colplane->AlphaThresh) ) {
10515 SUMA_LH("FOUND IT, on VE %s, IJK [%d %d %d], val %f,"
10516 "thresh[%f %f], UseAlphaTresh = %d, "
10517 "valpha=%f, ColAlphaThresh=%f\n",
10518 SUMA_VE_Headname(VO->VE, ive),
10519 (int)I[0], (int)I[1], (int)I[2], val,
10520 colplane->OptScl->ThreshRange[0],
10521 colplane->OptScl->ThreshRange[1],
10522 UseAlphaTresh,
10523 valpha, colplane->AlphaThresh*255);
10524 PR = SUMA_New_Pick_Result(NULL);
10525 PR->ado_idcode_str = SUMA_replace_string(
10526 PR->ado_idcode_str, ADO_ID(ado));
10527 if (pado) *pado = ado; /* user wants it */
10528 PR->primitive = SUMA_replace_string(
10529 PR->primitive,"voxel");
10530 PR->primitive_index = -1;
10531 PR->PickXYZ[0] = pinter[0];
10532 PR->PickXYZ[1] = pinter[1];
10533 PR->PickXYZ[2] = pinter[2];
10534 PR->ignore_same_datum = IgnoreSameNode;
10535 PR->datum_index = I1d;
10536 PR->iAltSel[SUMA_VOL_I] = I[0];
10537 PR->iAltSel[SUMA_VOL_J] = I[1];
10538 PR->iAltSel[SUMA_VOL_K] = I[2];
10539 PR->iAltSel[SUMA_VOL_IJK] = I1d;
10540 PR->iAltSel[SUMA_VOL_SLC_NUM] = rslc->slc_num;
10541 PR->iAltSel[SUMA_VOL_SLC_VARIANT] =
10542 (int)SUMA_SlcVariantToCode(rslc->variant);
10543 PR->dAltSel[SUMA_VOL_SLC_EQ0] = rslc->Eq[0];
10544 PR->dAltSel[SUMA_VOL_SLC_EQ1] = rslc->Eq[1];
10545 PR->dAltSel[SUMA_VOL_SLC_EQ2] = rslc->Eq[2];
10546 PR->dAltSel[SUMA_VOL_SLC_EQ3] = rslc->Eq[3];
10547 PR->dset_idcode_str = SUMA_replace_string(
10548 PR->dset_idcode_str, SDSET_ID(dset));
10549 if (!SUMA_Add_To_PickResult_List(sv, ado,
10550 "voxel", &PR)) {
10551 SUMA_S_Err("Failed to add selected ado");
10552 SUMA_RETURN(0);
10553 }
10554 Hit = 1;
10555 ++N_Hit;
10556 /* You could leave at the first hit IF:
10557 you only have one direction of slices in the
10558 entire stack, AND if they are properly
10559 ordered for rendering.
10560 Should speed be an issue you can check for
10561 this condition and bolt with the line below */
10562 /* goto GOT_IT; */
10563 }
10564 }
10565 ++ive;
10566 }
10567 }
10568 SUMA_LH("el now %p,\n"
10569 "tail = %p, N_Hit = %d",
10570 el, dlist_tail(VSaux->vrslcl), N_Hit);
10571 } while(el != dlist_tail(VSaux->vrslcl));
10572 }
10573 }
10574
10575
10576 GOT_IT:
10577 SUMA_RETURN(N_Hit);
10578 }/* determine intersection with 3D rendering of VO*/
10579
SUMA_Apply_PR_VO(SUMA_SurfaceViewer * sv,SUMA_VolumeObject * VO,SUMA_PICK_RESULT ** PRi)10580 int SUMA_Apply_PR_VO(SUMA_SurfaceViewer *sv, SUMA_VolumeObject *VO,
10581 SUMA_PICK_RESULT **PRi)
10582 {
10583 static char FuncName[]={"SUMA_Apply_PR_VO"};
10584 SUMA_ALL_DO *ado=NULL;
10585 int iv3[3], iv15[15];
10586 float fv15[15];
10587 DList *list = NULL;
10588 SUMA_Boolean NodeIgnored = NOPE;
10589 SUMA_PICK_RESULT *PR;
10590 SUMA_EngineData *ED = NULL;
10591 SUMA_DSET *dset=NULL;
10592 DListElmt *Location=NULL, *el=NULL, *SetNodeElem = NULL;
10593 SUMA_Boolean LocalHead = NOPE;
10594
10595 SUMA_ENTRY;
10596
10597 // fprintf(stderr, "%s\n", FuncName);
10598
10599 SUMA_LH("Here");
10600 if (!sv || !VO || !PRi || !*PRi) { SUMA_S_Err("Niente"); SUMA_RETURN(-1); }
10601
10602 /* Mark intersection Facsets */
10603 ado = (SUMA_ALL_DO *)VO;
10604
10605 PR = *PRi; /* Keep local copy */
10606 /* Store the PR in ado, hide it from return potential */
10607 SUMA_ADO_StorePickResult(ado, PRi);
10608
10609 if (!(dset = SUMA_FindDset_s(PR->dset_idcode_str, SUMAg_CF->DsetList))) {
10610 SUMA_S_Err("NULL dset?");
10611 SUMA_RETURN(0);
10612 }
10613
10614 sv->Focus_DO_ID = ADO_iDO(ado);
10615 SUMA_UpdateViewerTitle(sv);
10616
10617 /* if the surface controller is open, update it */
10618 if (SUMA_isADO_Cont_Realized(ado))
10619 SUMA_Init_SurfCont_SurfParam(ado);
10620
10621 fprintf(SUMA_STDOUT, "\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
10622 fprintf(SUMA_STDOUT, "Selected voxel RAI [%.3f %.3f %.3f]mm \n"
10623 " IJK [%ld %ld %ld] on volume %s.\n",
10624 PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2],
10625 PR->iAltSel[SUMA_VOL_I], PR->iAltSel[SUMA_VOL_J], PR->iAltSel[SUMA_VOL_K],
10626 SDSET_FILENAME(dset));
10627 fprintf(SUMA_STDOUT, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
10628
10629
10630 /* Set the voxel selection */
10631 if (!list) list = SUMA_CreateList();
10632 if (PR->ignore_same_datum &&
10633 SUMA_ADO_SelectedDatum(ado, NULL, NULL) == PR->datum_index) {
10634 SUMA_LHv("Ignoring identical voxel selection %d on volume %s\n",
10635 SUMA_ADO_SelectedDatum(ado, NULL, NULL), SUMA_ADO_Label(ado));
10636 NodeIgnored = YUP;
10637 } else {
10638 ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
10639 SetNodeElem = SUMA_RegisterEngineListCommand ( list, ED,
10640 SEF_i, (void*)&PR->datum_index,
10641 SES_Suma, (void *)sv, NOPE,
10642 SEI_Head, NULL);
10643 if (!SetNodeElem) {
10644 fprintf( SUMA_STDERR,
10645 "Error %s: Failed to register SetNodeElem\n", FuncName);
10646 SUMA_RETURN (-1);
10647 } else {
10648 SUMA_RegisterEngineListCommand ( list, ED,
10649 SEF_ngr, NULL,
10650 SES_Suma, (void *)sv, NOPE,
10651 SEI_In, SetNodeElem);
10652 }
10653
10654 iv15[SUMA_VOL_I] = (int)PR->iAltSel[SUMA_VOL_I];
10655 iv15[SUMA_VOL_J] = (int)PR->iAltSel[SUMA_VOL_J];
10656 iv15[SUMA_VOL_K] = (int)PR->iAltSel[SUMA_VOL_K];
10657 iv15[SUMA_VOL_IJK] = (int)PR->iAltSel[SUMA_VOL_IJK];
10658
10659 fv15[SUMA_VOL_SLC_EQ0] = (float)PR->dAltSel[SUMA_VOL_SLC_EQ0];
10660 fv15[SUMA_VOL_SLC_EQ1] = (float)PR->dAltSel[SUMA_VOL_SLC_EQ1];
10661 fv15[SUMA_VOL_SLC_EQ2] = (float)PR->dAltSel[SUMA_VOL_SLC_EQ2];
10662 fv15[SUMA_VOL_SLC_EQ3] = (float)PR->dAltSel[SUMA_VOL_SLC_EQ3];
10663
10664 SUMA_RegisterEngineListCommand ( list, ED,
10665 SEF_iv15, (void *)iv15,
10666 SES_Suma, (void *)sv, NOPE,
10667 SEI_In, SetNodeElem);
10668 SUMA_RegisterEngineListCommand ( list, ED,
10669 SEF_fv15, (void *)fv15,
10670 SES_Suma, (void *)sv, NOPE,
10671 SEI_In, SetNodeElem);
10672 }
10673
10674
10675 /* Now set the cross hair position at the selected node*/
10676 if (!list) list = SUMA_CreateList();
10677 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
10678 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
10679 SEF_fv3, (void*)PR->PickXYZ,
10680 SES_Suma, (void *)sv, NOPE,
10681 SEI_Head, NULL))) {
10682 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
10683 SUMA_RETURN(-1);
10684 }
10685 /* and add the object with this location */
10686 SUMA_RegisterEngineListCommand ( list, ED,
10687 SEF_vp, (void *)dset,
10688 SES_Suma, (void *)sv, NOPE,
10689 SEI_In, Location);
10690
10691 /* attach the cross hair to the selected object
10692 Note that binding here is to voxel of dset */
10693 iv3[0] = ADO_iDO(ado);
10694 iv3[1] = PR->iAltSel[SUMA_VOL_IJK];
10695 iv3[2] = -1;
10696
10697 ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
10698 if (!SUMA_RegisterEngineListCommand ( list, ED,
10699 SEF_iv3, (void*)iv3,
10700 SES_Suma, (void *)sv, NOPE,
10701 SEI_Head, NULL)) {
10702 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
10703 SUMA_RETURN(-1);
10704 }
10705
10706 /* call with the list */
10707 if (!SUMA_Engine (&list)) {
10708 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
10709 SUMA_RETURN(-1);
10710 }
10711
10712 /* check to see if AFNI needs to be notified */
10713 if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] &&
10714 sv->LinkAfniCrossHair) {
10715 int it;
10716 SUMA_LH("Notifying Afni of CrossHair XYZ");
10717 /* register a call to SetAfniCrossHair */
10718 if (!list) list = SUMA_CreateList();
10719 it = SUMA_ShftCont_Event(PR->evr);
10720 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
10721 if (!SUMA_RegisterEngineListCommand ( list, ED,
10722 SEF_i, (void*)&it,
10723 SES_Suma, (void *)sv, NOPE,
10724 SEI_Tail, NULL)) {
10725 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
10726 SUMA_RETURN (-1);
10727 }
10728 if (MASK_MANIP_MODE(sv) && SUMAg_CF->Dev) {
10729 SUMA_ALL_DO *ado = SUMA_whichADOg(sv->MouseMode_ado_idcode_str);
10730 DListElmt *Location=NULL;
10731 if (ado && ado->do_type == MASK_type) {
10732 SUMA_MaskDO *mdo = (SUMA_MaskDO *)ado;
10733 ED = SUMA_InitializeEngineListData (SE_SetAfniMask);
10734 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
10735 SEF_fv3, (void*)mdo->cen,
10736 SES_Suma, (void *)sv, NOPE,
10737 SEI_Tail, NULL))) {
10738 SUMA_S_Err("Failed to register element\n");
10739 SUMA_RETURN (-1);
10740 }
10741 SUMA_RegisterEngineListCommand ( list, ED,
10742 SEF_s, (void *)(ADO_ID(ado)),
10743 SES_Suma, (void *)sv, NOPE,
10744 SEI_In, Location);
10745 }
10746 }
10747 if (!SUMA_Engine (&list)) {
10748 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
10749 SUMA_RETURN(-1);
10750 }
10751 }
10752
10753 SUMA_RETURN(1);
10754 }
10755
10756 /*!
10757 \brief Show the contents of a brush stroke
10758 SUMA_ShowBrushStroke (sv, Out);
10759
10760 */
SUMA_ShowBrushStroke(SUMA_SurfaceViewer * sv,FILE * out)10761 void SUMA_ShowBrushStroke (SUMA_SurfaceViewer *sv, FILE *out)
10762 {
10763 static char FuncName[]={"SUMA_ShowBrushStroke"};
10764 int i, k, N=0;
10765 SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
10766 DListElmt *Next_Elm = NULL;
10767
10768 SUMA_ENTRY;
10769
10770 // fprintf(stderr, "%s\n", FuncName);
10771
10772 if (!out) out = SUMA_STDERR;
10773
10774 if (!sv->BS) {
10775 fprintf(out, "%s: NULL sv->BS\n", FuncName);
10776 SUMA_RETURNe;
10777 }
10778
10779 N = dlist_size(sv->BS);
10780 if (!N) {
10781 fprintf(out, "%s: Empty sv->BS. (N = 0)\n", FuncName);
10782 SUMA_RETURNe;
10783 }
10784
10785 fprintf(out, "%s: Brush stroke has %d elements:\n", FuncName, N);
10786
10787 i = 0;
10788 do {
10789 if (Next_Elm==NULL) Next_Elm = dlist_head(sv->BS);
10790 else Next_Elm = Next_Elm->next;
10791 if (!Next_Elm->data) {
10792 fprintf(out, "%s: Element->data %d is NULL!\n", FuncName, i);
10793 }else {
10794 bsd = (SUMA_BRUSH_STROKE_DATUM *)Next_Elm->data;
10795 fprintf(out, "%d: (%f %f) [%.2f, %.2f, %.2f <--> %.2f, %.2f, %.2f]\t Node %d, Tri %d\n",
10796 i, bsd->x, bsd->y,
10797 bsd->NP[0], bsd->NP[1], bsd->NP[2],
10798 bsd->FP[0], bsd->FP[1], bsd->FP[2],
10799 bsd->SurfNode, bsd->SurfTri);
10800 }
10801 ++i;
10802 }while (dlist_tail(sv->BS) != Next_Elm);
10803
10804 fprintf(out, "\n");
10805
10806 SUMA_RETURNe;
10807 }
10808
10809 /*!
10810 \brief Clear the contents of sv->BS and sets it to NULL
10811
10812 SUMA_ClearBrushStroke (sv);
10813
10814
10815 \sa SUMA_CreateBrushStroke
10816 */
SUMA_ClearBrushStroke(SUMA_SurfaceViewer * sv)10817 void SUMA_ClearBrushStroke (SUMA_SurfaceViewer *sv)
10818 {
10819 static char FuncName[]={"SUMA_ClearBrushStroke"};
10820
10821 SUMA_ENTRY;
10822
10823 // fprintf(stderr, "%s\n", FuncName);
10824
10825 /* THE NEW VERSION */
10826 if (sv->BS) {
10827 SUMA_EmptyDestroyList(sv->BS);
10828 sv->BS = NULL;
10829 }
10830
10831 SUMA_RETURNe;
10832 }
10833 /*!
10834 \brief Creates the BrushStroke structure inside sv structure
10835 success = SUMA_CreateBrushStroke (sv);
10836
10837 \param sv (SUMA_SurfaceViewer *) Surface viewer structure
10838 \return YUP/NOPE
10839
10840 sv->BS must be null before this function is called.
10841 The liat and its components are then allocated for.
10842
10843 \sa SUMA_ClearBrushStroke
10844 */
SUMA_CreateBrushStroke(SUMA_SurfaceViewer * sv)10845 SUMA_Boolean SUMA_CreateBrushStroke (SUMA_SurfaceViewer *sv)
10846 {
10847 static char FuncName[]={"SUMA_CreateBrushStroke"};
10848
10849 SUMA_ENTRY;
10850
10851 // fprintf(stderr, "%s\n", FuncName);
10852
10853 /* New Version */
10854 if (sv->BS) { /* bad news, this should be NULL to begin with */
10855 SUMA_RegisterMessage (SUMAg_CF->MessageList,
10856 "Brush Stroke not NULL.", FuncName,
10857 SMT_Critical, SMA_LogAndPopup);
10858 SUMA_RETURN(NOPE);
10859
10860 }
10861 sv->BS = (DList *)SUMA_calloc(1,sizeof(DList));
10862 dlist_init(sv->BS, SUMA_FreeBSDatum);
10863
10864 SUMA_RETURN (YUP);
10865 }
10866
SUMA_CreateBSDatum(void)10867 SUMA_BRUSH_STROKE_DATUM * SUMA_CreateBSDatum(void)
10868 {
10869 static char FuncName[]={"SUMA_CreateBSDatum"};
10870 SUMA_BRUSH_STROKE_DATUM *bsd = NULL;
10871
10872 SUMA_ENTRY;
10873
10874 // fprintf(stderr, "%s\n", FuncName);
10875
10876 bsd = (SUMA_BRUSH_STROKE_DATUM *)
10877 SUMA_calloc(1,sizeof(SUMA_BRUSH_STROKE_DATUM));
10878 if (!bsd) {
10879 SUMA_RegisterMessage (SUMAg_CF->MessageList,
10880 "Failed to allocate.", FuncName,
10881 SMT_Critical, SMA_LogAndPopup);
10882 SUMA_RETURN(NULL);
10883 }
10884 /* setup defaults */
10885 bsd->x = bsd->y = 0.0;
10886 bsd->NP[0] = bsd->NP[1] = bsd->NP[2] = 0.0;
10887 bsd->FP[0] = bsd->FP[1] = bsd->FP[2] = 0.0;
10888 bsd->SurfNode = -1;
10889 bsd->SurfTri = -1;
10890 bsd->Decimated = NOPE;
10891
10892 SUMA_RETURN(bsd);
10893 }
10894
10895 /*!
10896 \brief free a brush stroke datum that is contained inside the doubly linked BS
10897 */
SUMA_FreeBSDatum(void * bsd)10898 void SUMA_FreeBSDatum (void *bsd)
10899 {
10900 static char FuncName[]={"SUMA_FreeBSDatum"};
10901
10902 SUMA_ENTRY;
10903
10904 // fprintf(stderr, "%s\n", FuncName);
10905
10906 /* nothing is allocated for inside bsd */
10907 if (bsd) SUMA_free(bsd);
10908
10909 SUMA_RETURNe;
10910 }
10911
10912
10913
10914 /*!
10915 \brief Adds, new point to the brush stroke
10916 success = SUMA_AddToBrushStroke ( sv, x, y, Show);
10917
10918 \param sv (SUMA_SurfaceViewer *) pointer to surface viewer where stroke is occuring
10919 \param x (int) X coordinate of mouse
10920 \param y (int) Y coordinate of mouse
10921 \param NP (GLdouble *) vector of XYZ coordinates of Near Plane intersection point
10922 \param FP (GLdouble *) vector of XYZ coordinates of Far Plane intersection point.
10923 \param Show (SUMA_Boolean) if YUP: Then trace is drawn as you move the mouse
10924 \return YUP/NOPE, success indicator
10925
10926 */
SUMA_AddToBrushStroke(SUMA_SurfaceViewer * sv,int x,int y,GLdouble * NP,GLdouble * FP,SUMA_Boolean Show)10927 SUMA_Boolean SUMA_AddToBrushStroke (SUMA_SurfaceViewer *sv, int x, int y, GLdouble *NP, GLdouble *FP, SUMA_Boolean Show)
10928 {
10929 static char FuncName[]={"SUMA_AddToBrushStroke"};
10930 int ip;
10931 SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
10932
10933 SUMA_ENTRY;
10934
10935 // fprintf(stderr, "%s\n", FuncName);
10936
10937 /* New version */
10938 bsd = SUMA_CreateBSDatum();
10939 bsd->x = (float)x;
10940 bsd->y = (float)y;
10941 bsd->NP[0] = NP[0]; bsd->NP[1] = NP[1]; bsd->NP[2] = NP[2];
10942 bsd->FP[0] = FP[0]; bsd->FP[1] = FP[1]; bsd->FP[2] = FP[2];
10943 dlist_ins_next (sv->BS, dlist_tail(sv->BS), (void*)bsd);
10944
10945 /* incremental draw */
10946 if (Show) SUMA_DrawBrushStroke (sv, YUP);
10947
10948 SUMA_RETURN (YUP);
10949 }
10950
10951 /*!
10952 Sets the foreground color of the drawing area
10953 */
SUMA_SetSVForegroundColor(SUMA_SurfaceViewer * sv,const char * Color)10954 void SUMA_SetSVForegroundColor (SUMA_SurfaceViewer *sv, const char *Color)
10955 {
10956 static char FuncName[]={"SUMA_SetSVForegroundColor"};
10957 XColor col, unused;
10958
10959 SUMA_ENTRY;
10960
10961 // fprintf(stderr, "%s\n", FuncName);
10962
10963 #ifdef DARWIN
10964 SUMA_S_Warn("Calling this function from OS X seems to cause trouble");
10965 #endif
10966
10967 /* using sv->X->CMAP instead of
10968 DefaultColormapOfScreen(XtScreen(sv->X->GLXAREA))
10969 is useless */
10970 if (!XAllocNamedColor (sv->X->DPY,
10971 DefaultColormapOfScreen(XtScreen(sv->X->GLXAREA)),
10972 Color, &col, &unused)) {
10973 fprintf (SUMA_STDERR,
10974 "Error %s: Can't allocate for %s color.\n", FuncName, Color);
10975 SUMA_RETURNe;
10976 }
10977 XSetForeground (sv->X->DPY, sv->X->gc, col.pixel);
10978
10979 SUMA_RETURNe;
10980 }
10981
10982 /*!
10983 \brief Draws the brushstroke
10984
10985 \param sv (SUMA_SurfaceViewer *) pointer to surface viewer structure
10986 \param incremental (SUMA_Boolean) YUP: draw a line between the last two points
10987 NOPE: draw the whole thing
10988
10989 - NB: This function used to crash when run on SGI if display is not
10990 in TrueColor mode.
10991 This happens even though the visual chosen by SUMA does not change.
10992 To put the SGI in true color mode, you need to add to /var/X11/xdm/Xservers
10993 the following: -class TrueColor -depth 24
10994 and then restart X or the system.
10995 The bug was that the graphics context (sv->X->gc) was created using the
10996 Screen's root window and not the GLX visual's window.
10997 */
SUMA_DrawBrushStroke(SUMA_SurfaceViewer * sv,SUMA_Boolean incr)10998 void SUMA_DrawBrushStroke (SUMA_SurfaceViewer *sv, SUMA_Boolean incr)
10999 {
11000 static char FuncName[]={"SUMA_DrawBrushStroke"};
11001 int i, N;
11002 DListElmt *NE=NULL, *NEn=NULL;
11003 SUMA_BRUSH_STROKE_DATUM *bsd=NULL, *bsdn = NULL;
11004
11005 SUMA_ENTRY;
11006
11007 // fprintf(stderr, "%s\n", FuncName);
11008
11009 if (!sv->BS) SUMA_RETURNe;
11010
11011 N = dlist_size(sv->BS);
11012 if (N < 2) SUMA_RETURNe;
11013
11014 if (!incr) {
11015 do {
11016 if (!NE) NE = dlist_head(sv->BS);
11017 else NE = NE->next;
11018
11019 NEn = NE->next;
11020
11021 bsd = (SUMA_BRUSH_STROKE_DATUM *)NE->data;
11022 bsdn = (SUMA_BRUSH_STROKE_DATUM *)NEn->data;
11023
11024 SUMA_DrawWindowLine( sv, (int)bsd->x, (int)bsd->y,
11025 (int)bsdn->x, (int)bsdn->y, 1);
11026 } while (NEn != dlist_tail(sv->BS));
11027
11028 } else {
11029 NEn = dlist_tail(sv->BS);
11030 NE = NEn->prev;
11031
11032 bsd = (SUMA_BRUSH_STROKE_DATUM *)NE->data;
11033 bsdn = (SUMA_BRUSH_STROKE_DATUM *)NEn->data;
11034
11035 SUMA_DrawWindowLine( sv,
11036 (int)bsd->x, (int)bsd->y,
11037 (int)bsdn->x, (int)bsdn->y, 1 );
11038
11039 }
11040 SUMA_RETURNe;
11041
11042 }
11043
11044 /*!
11045 \brief Processes the brushstroke sent from a viewer
11046
11047 */
SUMA_ProcessBrushStroke(SUMA_SurfaceViewer * sv,SUMA_BRUSH_STROKE_ACTION BsA)11048 SUMA_DRAWN_ROI * SUMA_ProcessBrushStroke
11049 (SUMA_SurfaceViewer *sv, SUMA_BRUSH_STROKE_ACTION BsA)
11050 {
11051 static char FuncName[]={"SUMA_ProcessBrushStroke"};
11052 SUMA_DRAWN_ROI *DrawnROI = NULL;
11053 SUMA_ROI_DATUM *ROIstroke = NULL, *ROIlink=NULL, *ROIfill=NULL;
11054 SUMA_SurfaceObject *SO = NULL;
11055 int ii=0, TailNode = -1, FirstSurfNode = -1, ft = -1, N_SurfNode = 0;
11056 int HeadNode = -1, *ROI_Mask=NULL, N_ROI_Mask = 0;
11057 DListElmt *El = NULL;
11058 SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
11059 char *sbuf;
11060 SUMA_ROI_ACTION_STRUCT *ROIA;
11061 DListElmt *tmpStackPos=NULL;
11062 SUMA_Boolean Shaded = NOPE, LocalHead = NOPE;
11063
11064 SUMA_ENTRY;
11065
11066 // fprintf(stderr, "%s\n", FuncName);
11067
11068 SO = SUMA_SV_Focus_SO(sv);
11069
11070 if (!SO) {
11071 fprintf (SUMA_STDERR,
11072 "%s: No surface object in focus, nothing to do.\n", FuncName);
11073 SUMA_RETURN (DrawnROI);
11074 }
11075
11076 if (!sv->BS) {
11077 fprintf (SUMA_STDERR,
11078 "%s: No Brushstroke (BS), nothing to do.\n", FuncName);
11079 SUMA_RETURN (DrawnROI);
11080 }
11081
11082 if (!SUMAg_CF->ROI_mode) {
11083 fprintf (SUMA_STDERR, "%s: Not in ROI mode, nothing to do.\n", FuncName);
11084 SUMA_RETURN (DrawnROI);
11085 }
11086
11087 /* We are in ROI mode,
11088 is there an ROI in curDrawnROI that works with the current surface ? */
11089 if (SUMAg_CF->X->DrawROI->curDrawnROI) {
11090 if ( SUMA_isdROIrelated(SUMAg_CF->X->DrawROI->curDrawnROI,
11091 (SUMA_ALL_DO *)SO) &&
11092 SUMAg_CF->X->DrawROI->curDrawnROI->DrawStatus != SUMA_ROI_Finished){
11093 if (LocalHead)
11094 fprintf (SUMA_STDERR,"%s: using currDrawnROI.\n", FuncName);
11095 DrawnROI = SUMAg_CF->X->DrawROI->curDrawnROI;
11096 }else {
11097 if (LocalHead)
11098 fprintf (SUMA_STDERR,
11099 "%s: No match between currDrawnROI and SO.\n", FuncName);
11100 DrawnROI = NULL;
11101 }
11102 }
11103 if (!DrawnROI) { /* try some more */
11104 if ((DrawnROI = SUMA_FetchROI_InCreation (SO, SUMAg_DOv, SUMAg_N_DOv))){
11105 if (LocalHead)
11106 fprintf (SUMA_STDERR,"%s: using ROI in creation.\n", FuncName);
11107 /* There is an ROI being created on this surface,
11108 initialize DrawROI window*/
11109 SUMA_InitializeDrawROIWindow(DrawnROI);
11110 } else {
11111 /* wait till later */
11112 if (LocalHead)
11113 fprintf (SUMA_STDERR,"%s: will create a new ROI.\n", FuncName);
11114 }
11115 }
11116
11117 if (!DrawnROI && BsA == SUMA_BSA_JoinEnds) {
11118 SUMA_SLP_Err ("NO ROI to close.");
11119 SUMA_RETURN (DrawnROI);
11120 }
11121
11122 if (!DrawnROI) { /* No ROI found, create one */
11123 if (LocalHead)
11124 fprintf (SUMA_STDERR,
11125 "%s: No ROI found, creating a new one.\n", FuncName);
11126 SUMA_GET_TEXT_FIELD(SUMAg_CF->X->DrawROI->ROIlbl->textfield, sbuf);
11127 DrawnROI = SUMA_AllocateDrawnROI (SO->idcode_str, SUMA_ROI_InCreation,
11128 SUMA_ROI_OpenPath,
11129 sbuf,
11130 SUMAg_CF->X->DrawROI->ROIval->value);
11131 if (!DrawnROI) {
11132 SUMA_RegisterMessage (SUMAg_CF->MessageList,
11133 "Failed to allocate for DrawnROI.", FuncName,
11134 SMT_Critical, SMA_LogAndPopup);
11135 SUMA_RETURN (NULL);
11136 }
11137
11138 /* Although ROIs are stored as DOs,
11139 they are dependent on the surfaces they are related to
11140 ROIs at this stage are node indices only (and perhaps the mesh) but the coordinates of the indices
11141 come from the surface onto which they are displayed. So when you are
11142 drawing a surface, using CreateMesh,
11143 you will search DOv for ROIs related to the surface displayed and
11144 overlay them accordingly */
11145 /* Add the ROI to DO */
11146 if (!SUMA_AddDO ( SUMAg_DOv, &SUMAg_N_DOv,
11147 (void *)DrawnROI, ROIdO_type, SUMA_WORLD)) {
11148 fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AddDO.\n", FuncName);
11149 }
11150
11151 /* is the Switch ROI window open ? */
11152 SUMA_IS_DRAW_ROI_SWITCH_ROI_SHADED(Shaded);
11153 if (!Shaded) {
11154 SUMA_cb_DrawROI_SwitchROI (
11155 NULL,
11156 (XtPointer) SUMAg_CF->X->DrawROI->SwitchROIlst,
11157 NULL);
11158 }
11159
11160
11161 } else {
11162 if (LocalHead)
11163 fprintf( SUMA_STDOUT,
11164 "%s: ROI %p fetched. Status %d.\n",
11165 FuncName, DrawnROI, DrawnROI->DrawStatus);
11166 }
11167
11168 if (BsA == SUMA_BSA_AppendStrokeOrFill) {
11169 if ( DrawnROI->Type == SUMA_ROI_ClosedPath ||
11170 DrawnROI->Type == SUMA_ROI_FilledArea)
11171 BsA = SUMA_BSA_FillArea;
11172 else if (DrawnROI->Type == SUMA_ROI_OpenPath)
11173 BsA = SUMA_BSA_AppendStroke;
11174 }
11175 if ( DrawnROI->Type == SUMA_ROI_ClosedPath &&
11176 BsA != SUMA_BSA_FillArea) {
11177 SUMA_SLP_Err ( "You can only fill a closed path.\n"
11178 "You cannot append more paths to it.");
11179 SUMA_RETURN (DrawnROI);
11180 }
11181 if ( DrawnROI->Type == SUMA_ROI_FilledArea &&
11182 BsA != SUMA_BSA_FillArea) {
11183 SUMA_SLP_Err ("You cannot add paths to a filled ROI.");
11184 SUMA_RETURN (DrawnROI);
11185 }
11186
11187 /* Good, now initialize the DrawROI widget, if needed */
11188 if (SUMAg_CF->X->DrawROI->curDrawnROI != DrawnROI) {
11189 if (!SUMA_InitializeDrawROIWindow (DrawnROI)) {
11190 SUMA_SL_Err("Failed to initialize DrawWindow.");
11191 }
11192 }
11193
11194 /* Now you must transform the brushstroke to a series of nodes
11195 (not necessarily connected)*/
11196 if (LocalHead)
11197 fprintf (SUMA_STDERR,
11198 "%s: Turning BrushStroke to NodeStroke ...\n", FuncName);
11199 if (!SUMA_BrushStrokeToNodeStroke (sv)) {
11200 SUMA_RegisterMessage (SUMAg_CF->MessageList,
11201 "Failed in SUMA_BrushStrokeToNodeStroke.", FuncName,
11202 SMT_Error, SMA_LogAndPopup);
11203 SUMA_RETURN(NULL);
11204 }
11205
11206 switch (BsA) {
11207 case SUMA_BSA_AppendStroke:
11208 /* Turn the brush stroke into a series of connected nodes */
11209 if (LocalHead)
11210 fprintf (SUMA_STDERR,
11211 "%s: Turning NodeStroke to ROIStroke ...\n", FuncName);
11212 if (!(ROIstroke = SUMA_NodeStrokeToConnectedNodes (sv))) {
11213 SUMA_RegisterMessage (SUMAg_CF->MessageList,
11214 "Failed in SUMA_NodeStrokeToConnectedNodes.",
11215 FuncName,
11216 SMT_Critical, SMA_LogAndPopup);
11217 if (ROIlink) SUMA_FreeROIDatum((void *)ROIlink);
11218 ROIlink = NULL;
11219 if (ROIstroke) SUMA_FreeROIDatum((void *)ROIstroke);
11220 ROIstroke = NULL;
11221 SUMA_RETURN(NULL);
11222 }
11223
11224 if (LocalHead)
11225 fprintf (SUMA_STDERR,
11226 "%s: Turning NodeStroke to ROIStroke . DONE.\n",
11227 FuncName);
11228 /* if this is the first element of ROI,
11229 create the first ROIdatum and get out */
11230 if (dlist_size(DrawnROI->ROIstrokelist)) {
11231 /* Not the beginning of an ROI */
11232 if (LocalHead)
11233 fprintf (SUMA_STDERR,
11234 "%s: Adding ROIstroke to previous ones ...\n",
11235 FuncName);
11236 /* make sure new brushstroke is not just one node that is
11237 the tail of the ROI*/
11238 SUMA_DRAWN_ROI_TAIL_NODE(DrawnROI,TailNode);
11239
11240 SUMA_BS_FIRST_SURF_NODE(sv->BS, FirstSurfNode, ft, El);
11241 SUMA_BS_COUNT_SURF_NODES(sv->BS, N_SurfNode);
11242 if (FirstSurfNode == TailNode && N_SurfNode == 1) {
11243 /* nothing to do here */
11244 fprintf (SUMA_STDERR,
11245 "%s: New stroke has one node that is \n"
11246 "identical to tail node. Dumping element.\n", FuncName);
11247 SUMA_RETURN(DrawnROI);
11248 }
11249
11250 /* Connect this chunk to the last open Node in ROI */
11251 if (FirstSurfNode != TailNode) {
11252 if (LocalHead)
11253 fprintf (SUMA_STDERR,
11254 "%s: linking Tail Node to New stroke.\n", FuncName);
11255
11256 ROIlink = SUMA_LinkTailNodeToNodeStroke (sv, DrawnROI);
11257 if (!ROIlink) {
11258 SUMA_SL_Err("Failed to connect Tail node to Node stroke\n"
11259 ", try again.");
11260 SUMA_RETURN(NULL);
11261 }
11262 if (LocalHead) {
11263 fprintf (SUMA_STDERR,
11264 "%s: RIOlink, before prepending:\n", FuncName);
11265 SUMA_ShowDrawnROIDatum (ROIlink, NULL, NOPE);
11266 }
11267
11268 /* connect the ROIlink with the ROIstroke */
11269 if (LocalHead) {
11270 fprintf (SUMA_STDERR,
11271 "%s: RIOstroke, before prepending:\n", FuncName);
11272 SUMA_ShowDrawnROIDatum (ROIstroke, NULL, NOPE);
11273 }
11274 if (!SUMA_PrependToROIdatum (ROIlink, ROIstroke)) {
11275 SUMA_RegisterMessage (SUMAg_CF->MessageList,
11276 "Failed to merge ROIs.", FuncName,
11277 SMT_Critical, SMA_LogAndPopup);
11278 if (ROIlink) SUMA_FreeROIDatum((void *)ROIlink);
11279 ROIlink = NULL;
11280 if (ROIstroke) SUMA_FreeROIDatum((void *)ROIstroke);
11281 ROIstroke = NULL;
11282 SUMA_RETURN(NULL);
11283 }
11284
11285 if (LocalHead) {
11286 fprintf (SUMA_STDERR,
11287 "%s: RIOstroke, after prepending:\n", FuncName);
11288 SUMA_ShowDrawnROIDatum (ROIstroke, NULL, NOPE);
11289 }
11290 /* now free ROIlink, not needed anymore */
11291 if (ROIlink) SUMA_FreeROIDatum ((void *)ROIlink); ROIlink = NULL;
11292 }
11293 }else{
11294 if (LocalHead)
11295 fprintf (SUMA_STDERR, "%s: First ROIStroke of ROI.\n", FuncName);
11296 }
11297 break;
11298 case SUMA_BSA_JoinEnds:
11299 /* Join ends here */
11300 if (DrawnROI) { /* close ROI */
11301 SUMA_DRAWN_ROI_HEAD_NODE(DrawnROI,HeadNode);
11302 SUMA_BS_FIRST_SURF_NODE(sv->BS, FirstSurfNode, ft, El);
11303 bsd = (SUMA_BRUSH_STROKE_DATUM *)El->data;
11304 if (LocalHead)
11305 fprintf( SUMA_STDERR,
11306 "%s: Trying to join node %d to node %d.\n",
11307 FuncName, FirstSurfNode, HeadNode);
11308 /* Now compute the intersection of the surface with the plane */
11309 ROIstroke = SUMA_Surf_Plane_Intersect_ROI ( SO, FirstSurfNode,
11310 HeadNode, bsd->NP);
11311
11312 if (!ROIstroke) {
11313 SUMA_SL_Err ("Failed to close path. Repeat new stroke.");
11314 SUMA_RETURN(DrawnROI);
11315 }
11316 /* what is the last node of ROIstroke ?
11317 It is possible that the returned ROIstroke
11318 was not a successful closure (a partial success), investigate*/
11319 if (LocalHead)
11320 fprintf( SUMA_STDERR,
11321 "%s: Last node of ROIstroke is %d\n",
11322 FuncName, ROIstroke->nPath[ROIstroke->N_n-1]);
11323 if (ROIstroke->nPath[ROIstroke->N_n-1] != HeadNode) {
11324 /* pretend this is not a JoinEnds exercice */
11325 BsA = SUMA_BSA_AppendStroke;
11326 SUMA_SL_Err ("Failed to close path. Continue with stroke.");
11327 SUMA_RETURN(DrawnROI);
11328 }else {
11329 /* Do not remove the last point from ROIstroke,
11330 otherwise it will make drawing a closed ROI painful */
11331 }
11332 } else {
11333 /* tremors, nothing to do */
11334 }
11335 break;
11336 case SUMA_BSA_FillArea:
11337 SUMA_BS_FIRST_SURF_NODE(sv->BS, FirstSurfNode, ft, El);
11338 if (LocalHead)
11339 fprintf (SUMA_STDERR,
11340 "%s: Should be filling from node %d\n",
11341 FuncName, FirstSurfNode);
11342
11343 /* create the mask from ROIs on this surface */
11344 switch (SUMAg_CF->ROI_FillMode) {
11345 case SUMA_ROI_FILL_TO_ALLROI:
11346 ROI_Mask = SUMA_Build_Mask_AllROI ( SUMAg_DOv, SUMAg_N_DOv,
11347 SO, NULL, &N_ROI_Mask);
11348 break;
11349 case SUMA_ROI_FILL_TO_THISROI:
11350 ROI_Mask = (int *)SUMA_calloc (SO->N_Node, sizeof(int));
11351 if (!ROI_Mask) {
11352 SUMA_SLP_Crit("Failed to allocate");
11353 SUMA_RETURN(DrawnROI);
11354 }
11355 SUMA_Build_Mask_DrawnROI (DrawnROI, ROI_Mask);
11356 break;
11357 default:
11358 SUMA_SLP_Err("No such mode.");
11359 SUMA_RETURN(DrawnROI);
11360 break;
11361 }
11362
11363 /* Now fill it up */
11364 ROIfill = SUMA_FillToMask (SO, ROI_Mask, FirstSurfNode);
11365 if (ROI_Mask) SUMA_free(ROI_Mask); ROI_Mask = NULL;
11366 if (!ROIfill) {
11367 SUMA_SLP_Err( "Failed to fill area:\n"
11368 "Perhaps seed on edge\nor nothing to fill.");
11369 SUMA_RETURN(DrawnROI);
11370 }
11371
11372 break;
11373 default:
11374 fprintf (SUMA_STDERR,
11375 "Error %s: Why are you doing this to me ?.\n", FuncName);
11376 break;
11377 }
11378
11379
11380 /* Another switch on BsA,
11381 it is possible that its value changed within this function */
11382
11383 switch (BsA) {
11384 case SUMA_BSA_AppendStroke:
11385 /* store the action */
11386 ROIstroke->action = SUMA_BSA_AppendStroke;
11387 /*now add the ROIdatum to the list of ROIs */
11388 if (LocalHead)
11389 fprintf (SUMA_STDERR,
11390 "%s: Adding ROIStroke to DrawnROI->ROIstrokelist\n",
11391 FuncName);
11392 ROIA = (SUMA_ROI_ACTION_STRUCT *)
11393 SUMA_calloc(1,sizeof(SUMA_ROI_ACTION_STRUCT));
11394 /* this structure is freed in SUMA_DestroyROIActionData */
11395 ROIA->DrawnROI = DrawnROI;
11396 ROIA->ROId = ROIstroke;
11397 tmpStackPos = SUMA_PushActionStack (
11398 DrawnROI->ActionStack,
11399 DrawnROI->StackPos, SUMA_AddToTailROIDatum,
11400 (void *)ROIA, SUMA_DestroyROIActionData);
11401 if (tmpStackPos) DrawnROI->StackPos = tmpStackPos;
11402 else {
11403 fprintf (SUMA_STDERR,
11404 "Error %s: Failed in SUMA_PushActionStack.\n", FuncName);
11405 SUMA_RETURN (DrawnROI);
11406 }
11407 if ( SUMAg_CF->X->DrawROI->WhatDist == SW_DrawROI_WhatDistTrace ||
11408 SUMAg_CF->X->DrawROI->WhatDist == SW_DrawROI_WhatDistAll)
11409 SUMA_ReportDrawnROIDatumLength( SO, ROIA->ROId, NULL,
11410 SUMAg_CF->X->DrawROI->WhatDist);
11411 break;
11412 case SUMA_BSA_JoinEnds:
11413 /* store the action */
11414 ROIstroke->action = SUMA_BSA_JoinEnds;
11415 if (LocalHead) fprintf (SUMA_STDERR, "%s: Closing path.\n", FuncName);
11416 ROIA = (SUMA_ROI_ACTION_STRUCT *)
11417 SUMA_calloc(1,sizeof(SUMA_ROI_ACTION_STRUCT));
11418 /* this structure is freed in SUMA_DestroyROIActionData */
11419 ROIA->DrawnROI = DrawnROI;
11420 ROIA->ROId = ROIstroke;
11421 tmpStackPos = SUMA_PushActionStack (
11422 DrawnROI->ActionStack, DrawnROI->StackPos,
11423 SUMA_AddToTailJunctionROIDatum,
11424 (void *)ROIA, SUMA_DestroyROIActionData);
11425 if (tmpStackPos) DrawnROI->StackPos = tmpStackPos;
11426 else {
11427 fprintf (SUMA_STDERR,
11428 "Error %s: Failed in SUMA_PushActionStack.\n", FuncName);
11429 SUMA_RETURN (DrawnROI);
11430 }
11431 if ( SUMAg_CF->X->DrawROI->WhatDist == SW_DrawROI_WhatDistTrace ||
11432 SUMAg_CF->X->DrawROI->WhatDist == SW_DrawROI_WhatDistAll)
11433 SUMA_ReportDrawnROIDatumLength( SO, ROIA->ROId, NULL,
11434 SUMAg_CF->X->DrawROI->WhatDist);
11435 break;
11436 case SUMA_BSA_FillArea:
11437 /* store the action */
11438 ROIfill->action = SUMA_BSA_FillArea;
11439 /* Now add ROIdatum to stack */
11440 ROIA = (SUMA_ROI_ACTION_STRUCT *)
11441 SUMA_calloc(1,sizeof(SUMA_ROI_ACTION_STRUCT));
11442 /* this structure is freed in SUMA_DestroyROIActionData */
11443 ROIA->DrawnROI = DrawnROI;
11444 ROIA->ROId = ROIfill;
11445 tmpStackPos = SUMA_PushActionStack (
11446 DrawnROI->ActionStack, DrawnROI->StackPos,
11447 SUMA_AddFillROIDatum,
11448 (void *)ROIA, SUMA_DestroyROIActionData);
11449 if (tmpStackPos) DrawnROI->StackPos = tmpStackPos;
11450 else {
11451 fprintf (SUMA_STDERR,
11452 "Error %s: Failed in SUMA_PushActionStack.\n", FuncName);
11453 SUMA_RETURN (DrawnROI);
11454 }
11455 break;
11456 default:
11457 fprintf (SUMA_STDERR,
11458 "Error %s: Why are you doing this to me ??.\n", FuncName);
11459 break;
11460 }
11461
11462 /* Now update the Paint job on the ROI plane */
11463 if (!SUMA_Paint_SO_ROIplanes_w (SO, SUMAg_DOv, SUMAg_N_DOv)) {
11464 SUMA_SLP_Err("Failed in SUMA_Paint_SO_ROIplanes_w.");
11465 SUMA_RETURN(DrawnROI);
11466 }
11467 if (BsA == SUMA_BSA_FillArea) { /* ZSS Sept 29 06 */
11468 SUMA_OVERLAYS *Overlay=NULL;
11469 int junk;
11470 /* If you're drawing, and have just filled an area,
11471 better pop the dset to the top so it is visible */
11472 if (!(Overlay = SUMA_Fetch_OverlayPointer((SUMA_ALL_DO *)SO,
11473 DrawnROI->ColPlaneName,
11474 &junk))) {
11475 SUMA_S_Err("Unexpected! Could not find overlay pointer");
11476 } else {
11477 /* if the current col plane is not the same as this one,
11478 do the switching please */
11479 SUMA_InitializeColPlaneShell((SUMA_ALL_DO *)SO, Overlay);
11480 SUMA_UpdateColPlaneShellAsNeeded((SUMA_ALL_DO *)SO);
11481 /* update other open
11482 ColPlaneShells */
11483 }
11484 }
11485
11486 SUMA_RETURN(DrawnROI);
11487 }
11488
11489 /*!
11490 Function that turns a brushstroke to a series of nodes on the surface.
11491
11492 No surface paths are created from one node to the next yet.
11493
11494 It is not always the case that BrushStroke->N_SurfNodes is equal
11495 to BrushStroke->N
11496 */
SUMA_BrushStrokeToNodeStroke(SUMA_SurfaceViewer * sv)11497 SUMA_Boolean SUMA_BrushStrokeToNodeStroke (SUMA_SurfaceViewer *sv)
11498 {
11499 static char FuncName[]={"SUMA_BrushStrokeToNodeStroke"};
11500 DList * NS=NULL;
11501 SUMA_SurfaceObject *SO=NULL;
11502 SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL;
11503 float delta_t_tmp;
11504 struct timeval tt_tmp;
11505 int N = -1;
11506 SUMA_Boolean LocalHead=NOPE;
11507 SUMA_BRUSH_STROKE_DATUM *bsd=NULL, *obsd=NULL;
11508 DListElmt *Elmt = NULL, *oElmt=NULL;
11509
11510 SUMA_ENTRY;
11511
11512 // fprintf(stderr, "%s\n", FuncName);
11513
11514 if (!(SO = SUMA_SV_Focus_SO(sv))) {
11515 SUMA_S_Err("No surface in focus");
11516 SUMA_RETURN(NOPE);
11517 }
11518
11519 /* ONLY WORK ON FocusSO */
11520 if (SO->FaceSetDim != 3) {
11521 SUMA_S_Err("SUMA_MT_intersect_triangle only works for triangular meshes.");
11522 SUMA_RETURN(NOPE);
11523 }
11524
11525 N = dlist_size(sv->BS);
11526 if (!N) {
11527 fprintf (SUMA_STDERR, "%s: Empty brushstroke, nothing to do.\n", FuncName);
11528 SUMA_RETURN(NOPE);
11529 }else SUMA_LHv("%d element(s) in sv->BS.\n", N);
11530
11531 /* the first node of the brushstroke is stored as the cross hair's node id,
11532 just copy it */
11533 Elmt = dlist_head(sv->BS);
11534 bsd = (SUMA_BRUSH_STROKE_DATUM *)Elmt->data;
11535
11536 bsd->SurfNode = SO->SelectedNode;
11537 bsd->SurfTri = SO->SelectedFaceSet;
11538
11539 #ifdef DISASTER_LOOP
11540 /* Now as a brute force method, do all the remaing nodes in the path.
11541 In the future, you want to downsample the path is some clever fashion */
11542 if (N > 1) {
11543 if (LocalHead) {
11544 fprintf (SUMA_STDERR, "%s: Disaster loop, hold on .\n", FuncName);
11545 SUMA_etime (&tt_tmp, 0);
11546 }
11547
11548 MTI = NULL;
11549 do {
11550 Elmt = Elmt->next;
11551 bsd = (SUMA_BRUSH_STROKE_DATUM *)Elmt->data;
11552
11553 MTI = SUMA_MT_intersect_triangle( bsd->NP, bsd->FP,
11554 SO->NodeList, SO->N_Node,
11555 SO->FaceSetList, SO->N_FaceSet,
11556 MTI,0);
11557
11558 if (!MTI) {
11559 fprintf(SUMA_STDERR,"Error %s: SUMA_MT_intersect_triangle failed.\n", FuncName);
11560 SUMA_RETURN (NOPE);
11561 }
11562
11563 if (MTI->N_hits) { /* There is a hit, store it if useful */
11564 oElmt = Elmt->prev;
11565 obsd = (SUMA_BRUSH_STROKE_DATUM *)oElmt->data;
11566 if (obsd->SurfNode != MTI->inodemin) { /* a new one, bring it on */
11567 bsd->SurfNode = MTI->inodemin;
11568 bsd->SurfTri = MTI->ifacemin;
11569 }else {
11570 /* destroy Elmt, it is redundant */
11571 if (LocalHead) fprintf (SUMA_STDERR, "%s: Removing redundant BS element.\n", FuncName);
11572 dlist_remove (sv->BS, Elmt, (void*)(&bsd));
11573 SUMA_FreeBSDatum (bsd);
11574 Elmt = oElmt;
11575 }
11576 }
11577
11578 }while (Elmt != dlist_tail(sv->BS));
11579
11580 /* free MTI */
11581 MTI = SUMA_Free_MT_intersect_triangle(MTI);
11582
11583 if (LocalHead) {
11584 delta_t_tmp = SUMA_etime (&tt_tmp, 1);
11585 if (LocalHead) fprintf (SUMA_STDERR, "Local Debug %s: Intersections took %f seconds.\n", FuncName, delta_t_tmp);
11586 }
11587
11588 }
11589 #else
11590 if (N > 1) { /* new, faster method */
11591 DListElmt *Eli=NULL, *Eln=NULL;
11592 float ip[3], d[3];
11593 int IncTri[100], N_IncTri=0, n1=-1, n2=-1, n3=-1, ni = -1,
11594 ti = -1, N_Neighb=0,DeciLevel = 0, i, j, Removed=0;
11595 int DeciReentry=0, UsedNode[3]={ 0 , 0, 0 };
11596 SUMA_BRUSH_STROKE_DATUM *bsdi=NULL, *bsdn=NULL, *bsd_deci=NULL;
11597 SUMA_Boolean DoesInters=NOPE; /* flag for Decimation mode */
11598 SUMA_Boolean TrackOscillation = YUP; /* flag to tracking
11599 algorithm oscillation */
11600 SUMA_Boolean TryBruteForce = NOPE;
11601 int *Visited = NULL;
11602
11603 if (TrackOscillation) {
11604 Visited = (int *)SUMA_calloc(SO->N_Node, sizeof(int));
11605 if (!Visited) {
11606 SUMA_SLP_Err("Failed to allocate for Visited.\n");
11607 SUMA_RETURN(NOPE);
11608 }
11609 }
11610
11611 Eli = Elmt; /* initialize current element to the
11612 very fist in the brushstroke */
11613 MTI = NULL;
11614 TryBruteForce = NOPE;
11615 do {
11616 bsdi = (SUMA_BRUSH_STROKE_DATUM *)Eli->data;
11617 n1 = bsdi->SurfNode;
11618
11619 Eln = Eli->next; /* get the next element in line */
11620 bsdn = (SUMA_BRUSH_STROKE_DATUM *)Eln->data;
11621
11622 if (LocalHead)
11623 fprintf(SUMA_STDERR,"%s: Working from node %d.\n", FuncName, n1);
11624
11625 if (!TryBruteForce) { /* try the fast method */
11626 N_Neighb = SO->FN->N_Neighb[n1];
11627 if (N_Neighb < 3) {
11628 /* nothing found */
11629 SUMA_SLP_Err ("Node has less than 3 neighbors.\n"
11630 "This method will not apply.");
11631 SUMA_RETURN(NOPE);
11632 }
11633
11634 /* does the ray formed by Eln's NP and FP hit any of
11635 the triangles incident to bsdi->SurfNode (or n1) ? */
11636 if (LocalHead)
11637 fprintf (SUMA_STDERR,
11638 "%s: Searching incident triangles:\n", FuncName);
11639 i=0;
11640 DoesInters = NOPE;
11641 while ((i < N_Neighb ) && (!DoesInters)) {
11642 n2 = SO->FN->FirstNeighb[n1][i];
11643 if ( i+1 == N_Neighb) n3 = SO->FN->FirstNeighb[n1][0];
11644 else n3 = SO->FN->FirstNeighb[n1][i+1];
11645 #if 0
11646 if (LocalHead) {
11647 fprintf (SUMA_STDERR, " %d: [%d %d %d] Tri %d\n",
11648 i, n1, n2, n3, SUMA_whichTri(SO->EL, n1, n2, n3, 1));
11649 fprintf (SUMA_STDERR, " %d: [%.2f, %.2f, %.2f]\n",
11650 n1, SO->NodeList[3*n1],
11651 SO->NodeList[3*n1+1], SO->NodeList[3*n1+2]);
11652 fprintf (SUMA_STDERR, " %d: [%.2f, %.2f, %.2f]\n",
11653 n2, SO->NodeList[3*n2],
11654 SO->NodeList[3*n2+1], SO->NodeList[3*n2+2]);
11655 fprintf (SUMA_STDERR, " %d: [%.2f, %.2f, %.2f]\n",
11656 n3, SO->NodeList[3*n3],
11657 SO->NodeList[3*n3+1], SO->NodeList[3*n3+2]);
11658 fprintf (SUMA_STDERR,
11659 " NP: [%.2f, %.2f, %.2f] FP: [%.3f, %.2f, %.2f]\n",
11660 bsdn->NP[0], bsdn->NP[1], bsdn->NP[2],
11661 bsdn->FP[0], bsdn->FP[1], bsdn->FP[2]);
11662 }
11663 #endif
11664 DoesInters = SUMA_MT_isIntersect_Triangle (bsdn->NP, bsdn->FP,
11665 &(SO->NodeList[3*n1]),
11666 &(SO->NodeList[3*n2]),
11667 &(SO->NodeList[3*n3]), ip, d, &ni);
11668 if (DoesInters) {
11669 if (ni == 0) ni = n1;
11670 else if (ni == 1) ni = n2;
11671 else ni = n3;
11672
11673 ti = SUMA_whichTri(SO->EL, n1, n2, n3, 1, 0);
11674 }
11675
11676 #if 0
11677 if (LocalHead)
11678 fprintf (SUMA_STDERR,
11679 "%s: DoesInters = %d, ni = %d\n",
11680 FuncName, DoesInters, ni);
11681 {
11682 /* for debuging */
11683 MTI = NULL;MTI =
11684 SUMA_MT_intersect_triangle( bsdn->NP, bsdn->FP,
11685 SO->NodeList, SO->N_Node,
11686 SO->FaceSetList,
11687 SO->N_FaceSet,
11688 MTI, 0);
11689 fprintf (SUMA_STDERR,
11690 "%s: Intersection would be with triangle %d, node %d\n",
11691 FuncName, MTI->ifacemin, MTI->inodemin);
11692 }
11693 #endif
11694 ++i;
11695 }
11696 if (LocalHead) fprintf (SUMA_STDERR, "\n");
11697
11698 } else { /* try brute force flag has been set*/
11699
11700 if (LocalHead) fprintf (SUMA_STDERR, "%s: Trying brute force here \n", FuncName);
11701 /* Now skip and remove decimated elements */
11702 SUMA_REMOVE_NEXT_NON_DECIMATED (sv->BS, Eli, Eln);
11703 DeciLevel = 0;
11704 DeciReentry = 0;
11705 if (!Eln) {
11706 SUMA_SL_Err ("I tried hard to figure out your trace.\nI failed, now you try again.");
11707 SUMA_RETURN(YUP);
11708 }
11709
11710 bsdn = (SUMA_BRUSH_STROKE_DATUM *)Eln->data;
11711 MTI = SUMA_MT_intersect_triangle( bsdn->NP, bsdn->FP,
11712 SO->NodeList, SO->N_Node,
11713 SO->FaceSetList, SO->N_FaceSet,
11714 MTI, 0);
11715
11716 if (!MTI) {
11717 SUMA_SL_Err ("I tried harder to figure out your trace.\nI failed, do try again.");
11718 SUMA_RETURN (YUP);
11719 }
11720
11721 if (MTI->N_hits) { /* There is a hit, store it if useful */
11722 DoesInters = YUP;
11723 if (bsdi->SurfNode != MTI->inodemin) { /* a new one, bring it on */
11724 if (LocalHead) fprintf (SUMA_STDERR, "%s: Brute Force: Found intersection at new node %d.\n", FuncName, MTI->inodemin);
11725 ni = MTI->inodemin;
11726 ti = MTI->ifacemin;
11727 }else {
11728 /* set ni to n1 and let the element be destroyed */
11729 if (LocalHead) fprintf (SUMA_STDERR, "%s: Brute Force: Found intersection at n1 = %d!.\n", FuncName, MTI->inodemin);
11730 ni = n1;
11731 }
11732 } else {
11733 /* No hits at all, get out of this business */
11734 SUMA_SL_Err ("Why are you drawing out of bounds ?");
11735 SUMA_RETURN (YUP);
11736 }
11737 /* reset the TryBruteForce flag */
11738 TryBruteForce = NOPE;
11739 }
11740
11741 if (!DoesInters) { /* no intersection found, insert an element between Eli and Eln and try again */
11742 ++DeciLevel;
11743 if (LocalHead) fprintf (SUMA_STDERR, "%s: No intersection found. Decimating, level %d.\n", FuncName, DeciLevel);
11744
11745 if (DeciLevel > 3000) { /* this condition is only here to keep things from going awry. */
11746 if (LocalHead) fprintf (SUMA_STDERR,"%s: Decimation method failed. Trying from brute force", FuncName);
11747 TryBruteForce = YUP;
11748 } else {
11749 bsd_deci = SUMA_CreateBSDatum();
11750 bsd_deci->Decimated = YUP;
11751 bsd_deci->x = (bsdi->x + bsdn->x)/2.0;
11752 bsd_deci->y = (bsdi->y + bsdn->y)/2.0;
11753 for (j=0; j < 3; ++j) bsd_deci->NP[j] = (bsdi->NP[j] + bsdn->NP[j])/2.0;
11754 for (j=0; j < 3; ++j) bsd_deci->FP[j] = (bsdi->FP[j] + bsdn->FP[j])/2.0;
11755 bsd_deci->SurfNode = -1;
11756 bsd_deci->SurfTri = -1;
11757
11758 dlist_ins_next (sv->BS, Eli, bsd_deci);
11759 }
11760 } else {
11761 /* intersection found */
11762 if (ni == n1 && !DeciLevel) {
11763 /* same node reached, not during decimation, perhaps path was too densely sampled, delete Eln */
11764 ++Removed;
11765 if (LocalHead) fprintf (SUMA_STDERR, "%s: Same node reached without decimation, deleting for the %dth time.\n",
11766 FuncName, Removed);
11767 dlist_remove(sv->BS, Eln, (void*)&bsdn);
11768 SUMA_FreeBSDatum(bsdn);
11769 } else {
11770 if (ni == n1 && DeciLevel) {
11771 /* back to the starting point during decimation */
11772 if (DeciLevel) { /* user went out of bounds or drawing over cuts in surface */
11773 #if 0
11774 /* same node reached during decimation, to hell with it, use brute force intersection: YOU PAY PRICE IN TIME MISTER*/
11775 TryBruteForce = YUP;
11776 /* cancel the find */
11777 DoesInters = NOPE;
11778 #else
11779 /* same node reached during decimation, try othernode in triangle */
11780 if (!DeciReentry) {
11781 UsedNode[0] = n1;
11782 if (LocalHead) fprintf (SUMA_STDERR, "%s: Same node reached during decimation.\n Switching to second closest node.\n", FuncName);
11783 if (d[1] < d[2]) {
11784 ni = n2;
11785 UsedNode[1] = n2;
11786 } else {
11787 ni = n3;
11788 UsedNode[1] = n3;
11789 }
11790 } else if (DeciReentry == 1){
11791 /* been there before, one last node is left */
11792 if (LocalHead) fprintf (SUMA_STDERR, "%s: Last chance!\n", FuncName);
11793 if (n2 != UsedNode[0] && n2 != UsedNode[1]) ni = n2;
11794 else if (n3 != UsedNode[0] && n3 != UsedNode[1]) ni = n3;
11795 } else {
11796 /* Decimation failed, Do intersection with entire surface */
11797 TryBruteForce = YUP;
11798 /* cancel the find */
11799 DoesInters = NOPE;
11800 }
11801 #endif
11802 ++DeciReentry;
11803 }
11804 }else {
11805 /* ni != n1 Reset DeciLevel */
11806 DeciLevel = 0;
11807 DeciReentry = 0;
11808 }
11809
11810 /* algorithm might fall into oscillatory patterns, keep track of nodes visited.
11811 It is possible that a node is visited multiple times when users go over the
11812 same region over and over and over.*/
11813 if (TrackOscillation) {
11814 ++Visited[ni];
11815 if (Visited[ni] == 9) {
11816 DoesInters = NOPE;
11817 TryBruteForce = YUP;
11818 SUMA_SL_Err ("Path tracing oscillation. Trying with brute force.");
11819 }
11820 if (Visited[ni] > 9) {
11821 SUMA_SL_Err ("Path tracing oscillation remaining. Quitting tracing.");
11822 SUMA_RETURN(YUP);
11823 }
11824 }
11825
11826 if (DoesInters) { /* it is possible that the find is cancelled */
11827 if (LocalHead) fprintf (SUMA_STDERR, "%s: Found new node.\n", FuncName);
11828 /* good, new node is useful*/
11829 bsdn->SurfNode = ni;
11830 bsdn->SurfTri = ti;
11831 /* set Eli to Eln */
11832 Eli = Eln;
11833 }
11834 }
11835 }
11836 /* repeat until you have no more element */
11837 } while (Eli != dlist_tail(sv->BS));
11838
11839 if (MTI) MTI = SUMA_Free_MT_intersect_triangle(MTI);
11840 if (TrackOscillation) {
11841 if (Visited) SUMA_free(Visited);
11842 }
11843 }/* new, faster method */
11844 #endif
11845 SUMA_RETURN(YUP);
11846 }
11847
11848
11849 /*!
11850 \brief Function to link a node on the surface to a certain node in NodeStroke
11851
11852 \param sv (SUMA_SurfaceViewer *) with a valid BrushStroke in it
11853 \param NonSurf (int) index of node on surface to connect to NinStroke
11854 \param ELinStroke (DListElmt *) sv->BS element containing in SurfNode the index of the node to connect NonSurf to
11855 \sa SUMA_LinkTailNodeToNodeStroke
11856 */
SUMA_LinkThisNodeToNodeInStroke(SUMA_SurfaceViewer * sv,int NonSurf,DListElmt * ELinStroke)11857 SUMA_ROI_DATUM *SUMA_LinkThisNodeToNodeInStroke (SUMA_SurfaceViewer *sv,
11858 int NonSurf, DListElmt *ELinStroke)
11859 {
11860 static char FuncName[]={"SUMA_LinkThisNodeToNodeInStroke"};
11861 SUMA_Boolean LocalHead = NOPE;
11862 SUMA_ROI_DATUM *ROId=NULL;
11863 SUMA_SurfaceObject *SO=NULL;
11864 int Nfrom, Nto;
11865 SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
11866
11867 SUMA_ENTRY;
11868
11869 // fprintf(stderr, "%s\n", FuncName);
11870
11871 if (!(SO = SUMA_SV_Focus_SO(sv))) {
11872 SUMA_S_Err("No SO in focus");
11873 SUMA_RETURN(NULL);
11874 }
11875
11876 Nfrom = NonSurf;
11877 bsd = (SUMA_BRUSH_STROKE_DATUM *)ELinStroke->data;
11878 Nto = bsd->SurfNode;
11879
11880 /* Now compute the intersection of the surface with the plane */
11881 ROId = SUMA_Surf_Plane_Intersect_ROI (SO, Nfrom, Nto, bsd->NP);
11882
11883 if (!ROId) {
11884 SUMA_S_Err("Failed to link tail node to first node in new stroke.\n"
11885 "Repeat new stroke.");
11886 SUMA_RETURN(NULL);
11887 }
11888
11889 SUMA_RETURN(ROId);
11890 }
11891
11892 /*!
11893 \brief Function to link a node on the surface to the first node
11894 of a NodeStroke
11895
11896 -This function returns an ROI_datum that represents the link between
11897 the last node visited and the first node of the Nodestroke
11898
11899 \sa SUMA_LinkThisNodeToNodeInStroke
11900 */
SUMA_LinkTailNodeToNodeStroke(SUMA_SurfaceViewer * sv,SUMA_DRAWN_ROI * DrawnROI)11901 SUMA_ROI_DATUM *SUMA_LinkTailNodeToNodeStroke ( SUMA_SurfaceViewer *sv,
11902 SUMA_DRAWN_ROI *DrawnROI)
11903 {
11904
11905 static char FuncName[]={"SUMA_LinkTailNodeToNodeStroke"};
11906 SUMA_ROI_DATUM *ROId=NULL;
11907 SUMA_SurfaceObject *SO=NULL;
11908 SUMA_Boolean LocalHead = NOPE;
11909 int Nfrom=-1, Nto=-1, Trito=-1;
11910 DListElmt *Elm=NULL;
11911 SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
11912
11913 SUMA_ENTRY;
11914
11915 // fprintf(stderr, "%s\n", FuncName);
11916
11917 if (!(SO = SUMA_SV_Focus_SO(sv))) {
11918 SUMA_S_Err("No SO in focus");
11919 SUMA_RETURN(NULL);
11920 }
11921
11922 /* get the equation of the plane fromed by TailNode,
11923 FirstNodeinBrushStroke and its NearPlanePoint */
11924 SUMA_DRAWN_ROI_TAIL_NODE(DrawnROI, Nfrom);
11925 if (Nfrom < 0) {
11926 fprintf (SUMA_STDERR, "Error %s: No tail node found.\n", FuncName);
11927 SUMA_RETURN(NULL);
11928 }
11929
11930 /* get the first node in the stroke */
11931 SUMA_BS_FIRST_SURF_NODE(sv->BS, Nto, Trito, Elm);
11932 if (Nto < 0 || !Elm) {
11933 SUMA_SLP_Err ("Failed in SUMA_BS_FIRST_SURF_NODE macro.");
11934 SUMA_RETURN(NULL);
11935 }
11936 bsd = (SUMA_BRUSH_STROKE_DATUM *)Elm->data;
11937
11938 /* Now compute the intersection of the surface with the plane */
11939 ROId = SUMA_Surf_Plane_Intersect_ROI (SO, Nfrom, Nto, bsd->NP);
11940
11941 if (!ROId) {
11942 SUMA_S_Err("Failed to link tail node to first node in new stroke.\n"
11943 "Repeat new stroke.");
11944 SUMA_RETURN(NULL);
11945 }
11946
11947 SUMA_RETURN(ROId);
11948 }
11949
11950
11951 /*!
11952 This function turns the NodeStroke into a datum of connected nodes
11953 */
SUMA_NodeStrokeToConnectedNodes(SUMA_SurfaceViewer * sv)11954 SUMA_ROI_DATUM *SUMA_NodeStrokeToConnectedNodes (SUMA_SurfaceViewer *sv)
11955 {
11956 static char FuncName[]={"SUMA_NodeStrokeToConnectedNodes"};
11957 SUMA_Boolean LocalHead = NOPE;
11958 SUMA_ROI_DATUM *ROId=NULL, *ROIlink = NULL;
11959 int i=0;
11960 SUMA_SurfaceObject *SO=NULL;
11961 DListElmt *Elmt = NULL, *oElmt = NULL;
11962 SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
11963
11964 SUMA_ENTRY;
11965
11966 // fprintf(stderr, "%s\n", FuncName);
11967
11968 if (!(SO = SUMA_SV_Focus_SO(sv))) {
11969 SUMA_S_Err("No SO in focus");
11970 SUMA_RETURN(NULL);
11971 }
11972
11973 ROId = SUMA_AllocROIDatum();
11974
11975 /* fill up node series here */
11976 ROId->N_n = 1;
11977 ROId->N_t = 1;
11978 ROId->nPath = (int *) SUMA_calloc (ROId->N_n, sizeof(int));
11979 ROId->tPath = (int *) SUMA_calloc (ROId->N_t, sizeof(int));
11980
11981 SUMA_BS_FIRST_SURF_NODE(sv->BS, ROId->nPath[0], ROId->tPath[0], Elmt);
11982 ROId->Type = SUMA_ROI_NodeSegment;
11983
11984 /* try filling up the rest */
11985 oElmt = Elmt;
11986 do {
11987 /* get the next element with a surfnode */
11988 SUMA_BS_NEXT_SURF_NODE(sv->BS, oElmt, Elmt);
11989
11990 if (!Elmt) {
11991 /* perhaps reached end of list without success */
11992 SUMA_S_Note("Reached EOL without finding Elmt.\n"
11993 "Not necessarily a bad thing.");
11994 SUMA_RETURN(ROId);
11995 } else {
11996 if (LocalHead) {
11997 fprintf (SUMA_STDERR, "%s: Working with element %p.\n", FuncName, Elmt);
11998 }
11999 }
12000 bsd = (SUMA_BRUSH_STROKE_DATUM *)Elmt->data;
12001 SUMA_LHv("%d %d\nWill look for edge %d %d\n",
12002 ROId->N_n, bsd->SurfNode,
12003 ROId->nPath[ROId->N_n-1], bsd->SurfNode);
12004 if (SUMA_FindEdge(SO->EL, ROId->nPath[ROId->N_n-1], bsd->SurfNode) < 0) {
12005 /* Not found, link nodes together*/
12006 SUMA_LH("Edge not found, linking together.");
12007 if (!(ROIlink = SUMA_LinkThisNodeToNodeInStroke (sv,
12008 ROId->nPath[ROId->N_n-1], Elmt))) {
12009 SUMA_SLP_Err ("Failed to connect nodes in stroke.");
12010 SUMA_RETURN (ROId);
12011 }
12012 /* merge ROIlink with ROId */
12013 SUMA_LH("Merging ROIs together.");
12014 if (!SUMA_AppendToROIdatum (ROIlink, ROId)) {
12015 SUMA_RegisterMessage (SUMAg_CF->MessageList,
12016 "Failed to merge ROIs.", FuncName,
12017 SMT_Critical, SMA_LogAndPopup);
12018 if (ROIlink) SUMA_FreeROIDatum((void *)ROIlink); ROIlink = NULL;
12019 SUMA_RETURN(ROId);
12020 }
12021 if (ROIlink) SUMA_FreeROIDatum((void *)ROIlink); ROIlink = NULL;
12022 }else {
12023 SUMA_LH("Nodes connected.");
12024 /* nodes are connected, just add to path */
12025 ++ROId->N_n;
12026 ROId->nPath = (int *) SUMA_realloc (ROId->nPath, sizeof(int)*ROId->N_n);
12027 ROId->nPath[ROId->N_n-1] = bsd->SurfNode;
12028 }
12029
12030 oElmt = Elmt;
12031 } while (Elmt != dlist_tail(sv->BS));
12032
12033 SUMA_RETURN (ROId);
12034 }
12035
12036
12037 /*!
12038 Executes an action
12039 Adds it to the action stack
12040 Update the action stack pointer
12041 DO not do StckPos = SUMA_PushActionStack (..., StackPos, ....);
12042 that is because the function might return NULL if something failed and you'd lose the current stack position for good.
12043 */
SUMA_PushActionStack(DList * ActionStack,DListElmt * StackPos,SUMA_ACTION_RESULT (* ActionFunction)(void * ActionData,SUMA_ACTION_POLARITY Pol),void * ActionData,void (* ActionDataDestructor)(void * Actiondata))12044 DListElmt * SUMA_PushActionStack (DList *ActionStack, DListElmt *StackPos,
12045 SUMA_ACTION_RESULT (*ActionFunction)(void *ActionData, SUMA_ACTION_POLARITY Pol),
12046 void *ActionData,
12047 void (*ActionDataDestructor)(void *Actiondata))
12048 {
12049 static char FuncName[]={"SUMA_PushActionStack"};
12050 SUMA_Boolean LocalHead = NOPE;
12051 SUMA_ACTION_STACK_DATA *AS_data=NULL;
12052 SUMA_ACTION_RESULT ActionResult = SAR_Undefined;
12053
12054 SUMA_ENTRY;
12055
12056 // fprintf(stderr, "%s\n", FuncName);
12057
12058 /* execute action */
12059 if (LocalHead) fprintf (SUMA_STDERR, "%s: Executing Action.\n", FuncName);
12060 ActionResult = ActionFunction (ActionData, SAP_Do);
12061 switch (ActionResult) {
12062 case SAR_Fail:
12063 SUMA_SLP_Err("Action failed.");
12064 SUMA_RETURN(NULL);
12065 break;
12066 case SAR_Succeed:
12067 break;
12068 default:
12069 SUMA_SLP_Err("Action result not understood.");
12070 SUMA_RETURN(NULL);
12071 break;
12072 }
12073
12074 /* remove all elements above the position in the stack */
12075 if (LocalHead) fprintf (SUMA_STDERR, "%s: Removing Action Stack Elements above current position.\n", FuncName);
12076 while (StackPos != dlist_tail(ActionStack)) {
12077 void *asdata=NULL;
12078
12079 dlist_remove(ActionStack, dlist_tail(ActionStack), &asdata);
12080
12081 /* now free the asdata */
12082 SUMA_FreeActionStackData(asdata);
12083 }
12084
12085 /* Pushing the action and its data onto the stack */
12086 if (LocalHead) fprintf (SUMA_STDERR, "%s: Pushing the action and its data onto the stack.\n", FuncName);
12087 AS_data = (SUMA_ACTION_STACK_DATA *)
12088 SUMA_calloc(1,sizeof(SUMA_ACTION_STACK_DATA));
12089 AS_data->ActionDataDestructor = ActionDataDestructor;
12090 AS_data->ActionFunction = ActionFunction;
12091 AS_data->ActionData = ActionData;
12092 dlist_ins_next (ActionStack, dlist_tail(ActionStack), (void*)AS_data);
12093 if (LocalHead) fprintf (SUMA_STDERR, "%s: Updating StackPos ...\n", FuncName);
12094 StackPos = dlist_tail(ActionStack);
12095
12096 SUMA_RETURN(StackPos);
12097 }
12098
12099 /*!
12100 Redo an action of the ActionStack
12101 If StackPos is NULL, it is assumed that you are at the bottom of the stack
12102 */
SUMA_RedoAction(DList * ActionStack,DListElmt * StackPos)12103 DListElmt * SUMA_RedoAction (DList *ActionStack, DListElmt *StackPos)
12104 {
12105 static char FuncName[]={"SUMA_RedoAction"};
12106 SUMA_ACTION_STACK_DATA *AS_data=NULL;
12107 SUMA_ACTION_RESULT ActionResult = SAR_Undefined;
12108 SUMA_Boolean LocalHead = NOPE;
12109
12110 SUMA_ENTRY;
12111
12112 // fprintf(stderr, "%s\n", FuncName);
12113
12114 if (!StackPos) {
12115 if (LocalHead) fprintf (SUMA_STDERR, "%s: At bottom of stack. Working up.\n", FuncName);
12116 StackPos = dlist_head(ActionStack);
12117 } else if (StackPos == dlist_tail(ActionStack)) {
12118 SUMA_SLP_Err("At top of stack, nothing to do.");
12119 SUMA_RETURN(StackPos);
12120 } else {
12121 StackPos = dlist_next(StackPos);
12122 }
12123
12124 /* execute action above StackPos again */
12125 AS_data = (SUMA_ACTION_STACK_DATA *)StackPos->data;
12126 ActionResult = AS_data->ActionFunction (AS_data->ActionData, SAP_Redo);
12127 switch (ActionResult) {
12128 case SAR_Fail:
12129 SUMA_SLP_Err("Action failed.");
12130 SUMA_RETURN(NULL);
12131 break;
12132 case SAR_Succeed:
12133 break;
12134 default:
12135 SUMA_SLP_Err("Action result not understood.");
12136 SUMA_RETURN(NULL);
12137 break;
12138 }
12139
12140 SUMA_RETURN(StackPos);
12141 }
12142 /*!
12143 Undo an action on the ActionStack
12144
12145 \returns StackNewPos = StackPos if reached the bottom of the stack.
12146 It is your job to make sure this function is not called again.
12147 = StackPos->prev if all went well
12148 =NULL if trouble
12149
12150 */
SUMA_UndoAction(DList * ActionStack,DListElmt * StackPos)12151 DListElmt * SUMA_UndoAction (DList *ActionStack, DListElmt *StackPos)
12152 {
12153 static char FuncName[]={"SUMA_UndoAction"};
12154 SUMA_ACTION_STACK_DATA *AS_data=NULL;
12155 SUMA_ACTION_RESULT ActionResult = SAR_Undefined;
12156 SUMA_Boolean LocalHead = NOPE;
12157
12158 SUMA_ENTRY;
12159
12160 // fprintf(stderr, "%s\n", FuncName);
12161
12162 if (!StackPos) {
12163 SUMA_SLP_Err("At bottom of stack.");
12164 SUMA_RETURN(StackPos);
12165 }
12166
12167 AS_data = (SUMA_ACTION_STACK_DATA *)StackPos->data;
12168
12169 /* execute reverse of action */
12170 ActionResult = AS_data->ActionFunction (AS_data->ActionData, SAP_Undo);
12171 switch (ActionResult) {
12172 case SAR_Fail:
12173 SUMA_SLP_Err("Action failed.");
12174 SUMA_RETURN(NULL);
12175 break;
12176 case SAR_Succeed:
12177 break;
12178 default:
12179 SUMA_SLP_Err("Action result not understood.");
12180 SUMA_RETURN(NULL);
12181 break;
12182 }
12183
12184 /* now move StackPos down */
12185 if (StackPos == dlist_head(ActionStack)) {
12186 /* do nothing to StackPos */
12187 } else {
12188 StackPos = dlist_prev(StackPos);
12189 }
12190
12191 SUMA_RETURN(StackPos);
12192 }
12193
12194 /*!
12195 \brief Mark an ROI as finished
12196 */
SUMA_FinishedROI(void * data,SUMA_ACTION_POLARITY Pol)12197 SUMA_ACTION_RESULT SUMA_FinishedROI (void *data, SUMA_ACTION_POLARITY Pol)
12198 {
12199 static char FuncName[]={"SUMA_FinishedROI"};
12200 SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
12201 SUMA_SurfaceObject *SOparent=NULL;
12202 SUMA_Boolean LocalHead = NOPE;
12203
12204 SUMA_ENTRY;
12205
12206 // fprintf(stderr, "%s\n", FuncName);
12207
12208 ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
12209
12210 switch (Pol) {
12211 case SAP_Do:
12212 case SAP_Redo:
12213 if (LocalHead)
12214 fprintf (SUMA_STDERR, "%s: Marking as finished...\n", FuncName);
12215 /* set the drawing status */
12216 ROIA->DrawnROI->DrawStatus = SUMA_ROI_Finished;
12217
12218 SOparent = SUMA_findSOp_inDOv(ROIA->DrawnROI->Parent_idcode_str,
12219 SUMAg_DOv, SUMAg_N_DOv);
12220 if (!SOparent) {
12221 SUMA_SLP_Warn( "Parent surface\n"
12222 "not found for ROI\n"
12223 "No contour will\n"
12224 "be determined." );
12225 SUMA_RETURN(SAR_Succeed);
12226 }else {
12227 /* calculate the contours */
12228 if (!ROIA->DrawnROI->CE) { /* must create contour */
12229 int *Nodes, N_Nodes;
12230 SUMA_Boolean Unique = NOPE;
12231
12232 SUMA_LH("Getting Contour ");
12233 N_Nodes = 0;
12234 Unique = YUP; /* Set to YUP if you have node
12235 indices listed more than once. */
12236 Nodes = SUMA_NodesInROI (ROIA->DrawnROI, &N_Nodes, Unique);
12237 if (Nodes) {
12238 ROIA->DrawnROI->CE = SUMA_GetContour (
12239 SOparent,
12240 Nodes, N_Nodes, &(ROIA->DrawnROI->N_CE),
12241 0, NULL, NULL, 1);
12242 if (!ROIA->DrawnROI->CE) { SUMA_LH("Null DrawnROI->CE"); }
12243 else { SUMA_LH("Good DrawnROI->CE"); }
12244 SUMA_free(Nodes);
12245 }
12246 }else {
12247 SUMA_SLP_Err("Unexpected Contour");
12248 SUMA_RETURN(SAR_Fail);
12249 }
12250 }
12251
12252 break;
12253 case SAP_Undo:
12254 if (LocalHead)
12255 fprintf (SUMA_STDERR, "%s: Marking as InCreation...\n", FuncName);
12256 ROIA->DrawnROI->DrawStatus = SUMA_ROI_InCreation;
12257 /* remove any contour if present */
12258 if (ROIA->DrawnROI->CE) SUMA_free(ROIA->DrawnROI->CE);
12259 ROIA->DrawnROI->CE = NULL;
12260 ROIA->DrawnROI->N_CE = -1;
12261 break;
12262 default:
12263 fprintf (SUMA_STDERR, "Error %s: Should not be here.\n", FuncName);
12264 break;
12265 }
12266
12267 SUMA_RETURN(SAR_Succeed);
12268 }
12269
12270 /*!
12271 \brief This function is like SUMA_AddToTailROIDatum, except that it also updates the type of the ROI
12272 to be a filled one. You call this function when you are adding an ROIDatum that fills a closed path
12273 \param data (void *) of SUMA_ROI_ACTION_STRUCT * containing the ROIlist and the ROIdatum
12274 \param Pol (SUMA_ACTION_POLARITY) SAP_Do, SAP_Redo, SAP_Undo
12275 */
12276
SUMA_AddFillROIDatum(void * data,SUMA_ACTION_POLARITY Pol)12277 SUMA_ACTION_RESULT SUMA_AddFillROIDatum (void *data, SUMA_ACTION_POLARITY Pol)
12278 {
12279 static char FuncName[]={"SUMA_AddFillROIDatum"};
12280 SUMA_Boolean LocalHead = NOPE;
12281 SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
12282 void *eldata=NULL;
12283 DListElmt *tail_elm=NULL;
12284 SUMA_ROI_DATUM *ROId=NULL;
12285
12286 SUMA_ENTRY;
12287
12288 // fprintf(stderr, "%s\n", FuncName);
12289
12290 ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
12291
12292 switch (Pol) {
12293 case SAP_Do:
12294 case SAP_Redo:
12295 if (LocalHead) fprintf (SUMA_STDERR, "%s: Adding to ROIstrokelist...\n", FuncName);
12296 dlist_ins_next(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), (void *)ROIA->ROId);
12297 ROIA->DrawnROI->Type = SUMA_ROI_FilledArea;
12298 break;
12299 case SAP_Undo:
12300 if (LocalHead) fprintf (SUMA_STDERR, "%s: Removing from ROIstrokelist...\n", FuncName);
12301 dlist_remove(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), &eldata);
12302 /* eldata contains the ROIdatum that has been removed from the list. It should not be freed here
12303 This structure is to remain in the stack for later usage.*/
12304 /* if the tail is a segment, then turn the ROI type to a closedpath */
12305 tail_elm = dlist_tail(ROIA->DrawnROI->ROIstrokelist);
12306 ROId = (SUMA_ROI_DATUM *)tail_elm->data;
12307 if (ROId->Type == SUMA_ROI_NodeSegment) { /* we are no longer dealing with filled ROI */
12308 ROIA->DrawnROI->Type = SUMA_ROI_ClosedPath;
12309 }
12310 break;
12311 default:
12312 fprintf (SUMA_STDERR, "Error %s: Should not be here.\n", FuncName);
12313 break;
12314 }
12315
12316 SUMA_RETURN(SAR_Succeed);
12317 }
12318
12319 /*!
12320 \brief This function is like SUMA_AddToTailROIDatum, except that it also updates the type of the ROI
12321 to be a closed one. You call this function when you are addind the last ROIDatum that closes the path
12322 \param data (void *) of SUMA_ROI_ACTION_STRUCT * containing the ROIlist and the ROIdatum
12323 \param Pol (SUMA_ACTION_POLARITY) SAP_Do, SAP_Redo, SAP_Undo
12324 */
SUMA_AddToTailJunctionROIDatum(void * data,SUMA_ACTION_POLARITY Pol)12325 SUMA_ACTION_RESULT SUMA_AddToTailJunctionROIDatum (void *data,
12326 SUMA_ACTION_POLARITY Pol)
12327 {
12328 static char FuncName[]={"SUMA_AddToTailJunctionROIDatum"};
12329 SUMA_Boolean LocalHead = NOPE;
12330 SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
12331 void *eldata=NULL;
12332
12333 SUMA_ENTRY;
12334
12335 // fprintf(stderr, "%s\n", FuncName);
12336
12337 ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
12338
12339 switch (Pol) {
12340 case SAP_Do:
12341 case SAP_Redo:
12342 if (ROIA->DrawnROI->Type == SUMA_ROI_ClosedPath) {
12343 SUMA_SLP_Err ("Trying to close a closed path!");
12344 SUMA_RETURN(SAR_Fail);
12345 }
12346 if (LocalHead) fprintf (SUMA_STDERR, "%s: Adding to ROIstrokelist...\n", FuncName);
12347 dlist_ins_next(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), (void *)ROIA->ROId);
12348 ROIA->DrawnROI->Type = SUMA_ROI_ClosedPath;
12349 break;
12350 case SAP_Undo:
12351 if (ROIA->DrawnROI->Type == SUMA_ROI_OpenPath) {
12352 SUMA_SLP_Err ("Trying to open an open path!");
12353 SUMA_RETURN(SAR_Fail);
12354 }
12355 if (LocalHead)
12356 fprintf (SUMA_STDERR, "%s: Removing from ROIstrokelist...\n",
12357 FuncName);
12358 dlist_remove(ROIA->DrawnROI->ROIstrokelist,
12359 dlist_tail(ROIA->DrawnROI->ROIstrokelist), &eldata);
12360 /* eldata contains the ROIdatum that has been removed from the list.
12361 It should not be freed here
12362 This structure is to remain in the stack for later usage.*/
12363 ROIA->DrawnROI->Type = SUMA_ROI_OpenPath;
12364 break;
12365 default:
12366 fprintf (SUMA_STDERR, "Error %s: Should not be here.\n", FuncName);
12367 break;
12368 }
12369
12370 SUMA_RETURN(SAR_Succeed);
12371 }
12372
12373
12374 /*!
12375 \brief Adds (or removes) an ROIdatum to the tail of the ROI list
12376
12377 \param data (void *) of SUMA_ROI_ACTION_STRUCT * containing the ROIlist and the ROIdatum
12378 \param Pol (SUMA_ACTION_POLARITY) SAP_Do, SAP_Redo, SAP_Undo
12379 */
SUMA_AddToTailROIDatum(void * data,SUMA_ACTION_POLARITY Pol)12380 SUMA_ACTION_RESULT SUMA_AddToTailROIDatum (void *data, SUMA_ACTION_POLARITY Pol)
12381 {
12382 static char FuncName[]={"SUMA_AddToTailROIDatum"};
12383 SUMA_Boolean LocalHead = NOPE;
12384 SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
12385 void *eldata=NULL;
12386
12387 SUMA_ENTRY;
12388
12389 // fprintf(stderr, "%s\n", FuncName);
12390
12391 ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
12392
12393 switch (Pol) {
12394 case SAP_Do:
12395 case SAP_Redo:
12396 if (LocalHead) fprintf (SUMA_STDERR, "%s: Adding to ROIstrokelist...\n", FuncName);
12397 dlist_ins_next(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), (void *)ROIA->ROId);
12398 break;
12399 case SAP_Undo:
12400 if (LocalHead) fprintf (SUMA_STDERR, "%s: Removing from ROIstrokelist...\n", FuncName);
12401 dlist_remove(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), &eldata);
12402 /* eldata contains the ROIdatum that has been removed from the list. It should not be freed here
12403 This structure is to remain in the stack for later usage.*/
12404 break;
12405 default:
12406 fprintf (SUMA_STDERR, "Error %s: Should not be here.\n", FuncName);
12407 break;
12408 }
12409
12410 SUMA_RETURN(SAR_Succeed);
12411 }
12412
12413 /*!
12414 A function to destroy the ROI action data structure.
12415
12416 \param data (void *) of SUMA_ROI_ACTION_STRUCT * containing the ROIlist and the ROIdatum
12417
12418 - Only ROIA->ROId and ROIA are freed. ROIA->DrawnROI should be freed when the DrawnROI list is destroyed.
12419 */
12420
SUMA_DestroyROIActionData(void * data)12421 void SUMA_DestroyROIActionData (void *data)
12422 {
12423 static char FuncName[]={"SUMA_DestroyROIActionData"};
12424 SUMA_Boolean LocalHead = NOPE;
12425 SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
12426
12427 SUMA_ENTRY;
12428
12429 // fprintf(stderr, "%s\n", FuncName);
12430
12431 ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
12432
12433 if (!ROIA) SUMA_RETURNe;
12434
12435 if (ROIA->ROId) { /* free the ROI datum */
12436 SUMA_FreeROIDatum ((void *)ROIA->ROId);
12437 ROIA->ROId = NULL;
12438 }
12439
12440 ROIA->DrawnROI = NULL; /* this should not be freed here, it is freed when the function for destroying DrawnROI is called */
12441 SUMA_free(ROIA);
12442
12443 SUMA_RETURNe;
12444 }
12445
12446 /*!
12447 \brief set the position of light0
12448 \param s (char *) a strng containing X, Y, Z coordinates
12449 \param data (void *) a typecast of the pointer to the surface viewer to be affected
12450
12451 */
SUMA_SetLight0(char * s,void * data)12452 void SUMA_SetLight0 (char *s, void *data)
12453 {
12454 static char FuncName[]={"SUMA_SetLight0"};
12455 DList *list=NULL;
12456 SUMA_EngineData *ED = NULL;
12457 SUMA_SurfaceViewer *sv = NULL;
12458 float fv3[3];
12459 SUMA_Boolean LocalHead = NOPE;
12460
12461 SUMA_ENTRY;
12462
12463 // fprintf(stderr, "%s\n", FuncName);
12464
12465 if (!s) SUMA_RETURNe;
12466
12467 sv = (SUMA_SurfaceViewer *)data;
12468
12469 /* parse s */
12470 if (SUMA_StringToNum (s, (void*)fv3, 3, 1) != 3) {/*problem,beep and ignore */
12471 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12472 SUMA_RETURNe;
12473 }
12474
12475 /* register fv3 with ED */
12476 if (!list) list = SUMA_CreateList();
12477 ED = SUMA_InitializeEngineListData (SE_SetLight0Pos);
12478 if (!SUMA_RegisterEngineListCommand ( list, ED,
12479 SEF_fv3, (void *)fv3,
12480 SES_Suma, (void *)sv, NOPE,
12481 SEI_Tail, NULL )) {
12482 fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
12483 SUMA_RETURNe;
12484 }
12485
12486 SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
12487
12488 if (!SUMA_Engine (&list)) {
12489 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12490 }
12491
12492 SUMA_RETURNe;
12493 }
12494
12495 /*!
12496 \brief sets the number of smoothing operations to perform on foreground colors
12497 before display
12498 */
SUMA_SetNumForeSmoothing(char * s,void * data)12499 void SUMA_SetNumForeSmoothing (char *s, void *data)
12500 {
12501 static char FuncName[]={"SUMA_SetNumForeSmoothing"};
12502 DList *list=NULL;
12503 SUMA_EngineData *ED = NULL;
12504 SUMA_SurfaceViewer *sv = NULL;
12505 float fv3[3];
12506 SUMA_Boolean LocalHead = NOPE;
12507
12508 SUMA_ENTRY;
12509
12510 // fprintf(stderr, "%s\n", FuncName);
12511
12512 if (!s) SUMA_RETURNe;
12513
12514 sv = (SUMA_SurfaceViewer *)data;
12515
12516 /* parse s */
12517 if (SUMA_StringToNum (s, (void *)fv3, 1,1) != 1) {/*problem,beep and ignore */
12518 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12519 SUMA_RETURNe;
12520 }
12521
12522 /* set sv */
12523
12524 if ((int)fv3[0] < 0) {
12525 SUMA_SLP_Err("Only positive integer\nvalues are valid.\n");
12526 SUMA_RETURNe;
12527 }
12528 SUMAg_CF->X->NumForeSmoothing = (int)fv3[0];
12529
12530 /* flag surfaces for remix */
12531 SUMA_SetAllRemixFlag(SUMAg_SVv, SUMAg_N_SVv);
12532
12533 /* register a redisplay for sv*/
12534 if (!list) list = SUMA_CreateList();
12535 SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_Redisplay_AllVisible,
12536 SES_Suma, sv);
12537 if (!SUMA_Engine (&list)) {
12538 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12539 }
12540
12541 SUMA_RETURNe;
12542
12543 }
12544
SUMA_SetNumFinalSmoothing(char * s,void * data)12545 void SUMA_SetNumFinalSmoothing (char *s, void *data)
12546 {
12547 static char FuncName[]={"SUMA_SetNumFinalSmoothing"};
12548 DList *list=NULL;
12549 SUMA_EngineData *ED = NULL;
12550 SUMA_SurfaceViewer *sv = NULL;
12551 float fv3[3];
12552 SUMA_Boolean LocalHead = NOPE;
12553
12554 SUMA_ENTRY;
12555
12556 // fprintf(stderr, "%s\n", FuncName);
12557
12558 if (!s) SUMA_RETURNe;
12559
12560 sv = (SUMA_SurfaceViewer *)data;
12561
12562 /* parse s */
12563 if (SUMA_StringToNum (s, (void *)fv3, 1,1) != 1) {/*problem,beep and ignore */
12564 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12565 SUMA_RETURNe;
12566 }
12567
12568 /* set sv */
12569
12570 if ((int)fv3[0] < 0) {
12571 SUMA_SLP_Err("Only positive integer\nvalues are valid.\n");
12572 SUMA_RETURNe;
12573 }
12574 SUMAg_CF->X->NumFinalSmoothing = (int)fv3[0];
12575
12576 /* flag surfaces for remix */
12577 SUMA_SetAllRemixFlag(SUMAg_SVv, SUMAg_N_SVv);
12578
12579 /* register a redisplay for sv*/
12580 if (!list) list = SUMA_CreateList();
12581 SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_Redisplay_AllVisible,
12582 SES_Suma, sv);
12583 if (!SUMA_Engine (&list)) {
12584 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12585 }
12586
12587 SUMA_RETURNe;
12588
12589 }
12590
12591 /*!
12592 \brief Sets the screen clipping plane
12593
12594 \param s (char *) a strng containing a,b,c,d parameters of plane equation
12595 \param data (void *) a typecast of the pointer to the surface viewer to be affected
12596
12597 */
SUMA_SetScreenClip(char * s,void * data)12598 void SUMA_SetScreenClip (char *s, void *data)
12599 {
12600 SUMA_SetClip(s,(SUMA_SurfaceViewer *)data, SUMA_SCREEN_CLIP);
12601 }
SUMA_SetObjectClip(char * s,void * data)12602 void SUMA_SetObjectClip (char *s, void *data)
12603 {
12604 SUMA_SetClip(s,(SUMA_SurfaceViewer *)data, SUMA_ALL_OBJECT_CLIP);
12605 }
12606
SUMA_SetClip(char * s,SUMA_SurfaceViewer * sv,SUMA_CLIP_PLANE_TYPES tp)12607 void SUMA_SetClip (char *s, SUMA_SurfaceViewer *sv, SUMA_CLIP_PLANE_TYPES tp)
12608 {
12609 static char FuncName[]={"SUMA_SetScreenClip"};
12610 DList *list=NULL;
12611 SUMA_EngineData *ED = NULL;
12612 float fv15[15];
12613 int npar=0;
12614 char *sn;
12615 char namebuf[24];
12616 int itmp, ii, it=0;
12617 DListElmt *NextElm= NULL;
12618 SUMA_Boolean LocalHead = NOPE;
12619
12620 SUMA_ENTRY;
12621
12622 // fprintf(stderr, "%s\n", FuncName);
12623
12624 if (!s) {
12625 SUMA_Show_Clip_Planes(SUMAg_CF, NULL);
12626 SUMA_RETURNe;
12627 }
12628
12629 /* Get the name, if any */
12630 if ((sn = strstr(s,":"))) {/* found name */
12631 if (sn - s > 7) {
12632 SUMA_SLP_Err("Plane label too long!");
12633 SUMA_RETURNe;
12634 }
12635 ii=0;
12636 while (s[ii] != ':') { namebuf[ii] = s[ii]; ++ii; }/* copy name */
12637 namebuf[ii] = '\0';
12638 itmp = 0; ++ii;
12639 while (s[ii] != '\0') { s[itmp] = s[ii]; ++ii; ++itmp; } /* copy rest */
12640 s[itmp] = '\0';
12641 /* get the equation */
12642 npar = SUMA_StringToNum (s, (void *)fv15, 4, 1);
12643 if (npar != 4 && npar != 2 && npar != 0) { /* problem, beep and ignore */
12644 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12645 SUMA_RETURNe;
12646 }
12647 if (npar == 2) { /* the z game */
12648 fv15[2] = fv15[0];
12649 fv15[3] = fv15[1];
12650 fv15[0] = 0.0;
12651 fv15[1] = 0.0;
12652 } else if (npar == 0) { /* the nothing */
12653 fv15[0] = 0.0;
12654 fv15[1] = 0.0;
12655 fv15[2] = 0.0;
12656 fv15[3] = 0.0;
12657 }
12658 }else {
12659 SUMA_SLP_Err("Must provide plane label!");
12660 SUMA_RETURNe;
12661 }
12662
12663
12664 /* register fv15 with ED */
12665 if (!list) list = SUMA_CreateList();
12666 ED = SUMA_InitializeEngineListData (SE_SetClip);
12667 if (!(NextElm = SUMA_RegisterEngineListCommand ( list, ED,
12668 SEF_fv15, (void *)fv15,
12669 SES_Suma, (void *)sv, NOPE,
12670 SEI_Head, NULL ))) {
12671 fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
12672 SUMA_RETURNe;
12673 }
12674 /* register type expected */
12675 it = (int)tp;
12676 if (!(SUMA_RegisterEngineListCommand ( list, ED,
12677 SEF_i, (void*)(&it),
12678 SES_Suma, (void *)sv, NOPE,
12679 SEI_In, NextElm ))) {
12680 fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
12681 SUMA_RETURNe;
12682 }
12683 /* register name of plane */
12684 if (!(SUMA_RegisterEngineListCommand ( list, ED,
12685 SEF_s, (void*)(namebuf),
12686 SES_Suma, (void *)sv, NOPE,
12687 SEI_In, NextElm ))) {
12688 fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
12689 SUMA_RETURNe;
12690 }
12691 if (!SUMA_Engine (&list)) {
12692 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12693 }
12694
12695 SUMA_RETURNe;
12696 }
12697
12698 /*!
12699 \brief Sets the rotation center
12700
12701 \param s (char *) a strng containing X, Y, Z coordinates
12702 \param data (void *) a typecast of the pointer to the surface viewer to
12703 be affected
12704
12705 NOTE: This is a bit ugly because there is a jump in surface location with
12706 the change in center of rotation. Something also needs updating to keep this
12707 from happening ...
12708 */
12709
SUMA_SetRotCenter(char * s,void * data)12710 void SUMA_SetRotCenter (char *s, void *data)
12711 {
12712 static char FuncName[]={"SUMA_SetRotCenter"};
12713 DList *list=NULL;
12714 SUMA_EngineData *ED = NULL;
12715 SUMA_SurfaceViewer *sv = NULL;
12716 float fv3[3];
12717 SUMA_Boolean LocalHead = NOPE;
12718
12719 SUMA_ENTRY;
12720
12721 // fprintf(stderr, "%s\n", FuncName);
12722
12723 sv = (SUMA_SurfaceViewer *)data;
12724 if (!sv) {
12725 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12726 SUMA_RETURNe;
12727 }
12728
12729 if (!s) {
12730 if (!SUMA_UpdateRotaCenter(sv, SUMAg_DOv, SUMAg_N_DOv)) {
12731 fprintf (SUMA_STDERR,
12732 "Error %s: Failed to update center of rotation", FuncName);
12733 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12734 SUMA_RETURNe;
12735 }
12736 SUMA_RETURNe;
12737 }
12738
12739 /* parse s */
12740 if (SUMA_StringToNum (s, (void*)fv3, 3,1) != 3) {/*problem, beep and ignore */
12741 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12742 SUMA_RETURNe;
12743 }
12744
12745 sv->GVS[sv->StdView].RotaCenter[0] = fv3[0];
12746 sv->GVS[sv->StdView].RotaCenter[1] = fv3[1];
12747 sv->GVS[sv->StdView].RotaCenter[2] = fv3[2];
12748
12749
12750 SUMA_RETURNe;
12751 }
12752
12753 /*!
12754 \brief rotates surface to face a certain coordinate
12755
12756 \param s (char *) a strng containing X, Y, Z coordinates
12757 \param data (void *) a typecast of the pointer to the surface viewer to be affected
12758
12759 */
SUMA_LookAtCoordinates(char * s,void * data)12760 void SUMA_LookAtCoordinates (char *s, void *data)
12761 {
12762 static char FuncName[]={"SUMA_LookAtCoordinates"};
12763 DList *list=NULL;
12764 SUMA_EngineData *ED = NULL;
12765 SUMA_SurfaceViewer *sv = NULL;
12766 float fv3[3];
12767 SUMA_Boolean LocalHead = NOPE;
12768
12769 SUMA_ENTRY;
12770
12771 // fprintf(stderr, "%s\n", FuncName);
12772
12773 if (!s) SUMA_RETURNe;
12774
12775 sv = (SUMA_SurfaceViewer *)data;
12776
12777 /* parse s */
12778 if (SUMA_StringToNum (s, (void *)fv3, 3,1) != 3) {/*problem,beep and ignore */
12779 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12780 SUMA_RETURNe;
12781 }
12782
12783 /* register fv3 with ED */
12784 if (!list) list = SUMA_CreateList();
12785 ED = SUMA_InitializeEngineListData (SE_SetLookAt);
12786 if (!SUMA_RegisterEngineListCommand ( list, ED,
12787 SEF_fv3, (void *)fv3,
12788 SES_Suma, (void *)sv, NOPE,
12789 SEI_Head, NULL )) {
12790 fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
12791 SUMA_RETURNe;
12792 }
12793 if (!SUMA_Engine (&list)) {
12794 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12795 }
12796
12797 SUMA_RETURNe;
12798 }
12799
SUMA_SV_SetRenderOrder(char * s,void * data)12800 void SUMA_SV_SetRenderOrder(char *s, void *data)
12801 {
12802 static char FuncName[]={"SUMA_SV_SetRenderOrder"};
12803 SUMA_SurfaceViewer *sv = NULL;
12804 SUMA_Boolean LocalHead = NOPE;
12805
12806 SUMA_ENTRY;
12807
12808 // fprintf(stderr, "%s\n", FuncName);
12809
12810 if (!s) SUMA_RETURNe;
12811
12812 sv = (SUMA_SurfaceViewer *)data;
12813 if (!sv) {
12814 SUMA_S_Err("Null sv");
12815 SUMA_RETURNe;
12816 }
12817
12818 sv->N_otseq = SUMA_SetObjectDisplayOrder(s, sv->otseq);
12819
12820 SUMA_RETURNe;
12821 }
12822
SUMA_JumpIndex(char * s,void * data)12823 void SUMA_JumpIndex (char *s, void *data)
12824 {
12825 static char FuncName[]={"SUMA_JumpIndex"};
12826 SUMA_SurfaceViewer *sv = NULL;
12827 SUMA_ALL_DO *ado=NULL;
12828 char *variant = NULL;
12829 SUMA_Boolean LocalHead = NOPE;
12830
12831 SUMA_ENTRY;
12832
12833 // fprintf(stderr, "%s\n", FuncName);
12834
12835 if (!s) SUMA_RETURNe;
12836
12837 sv = (SUMA_SurfaceViewer *)data;
12838 if (!(ado = SUMA_SV_Focus_ADO(sv))) {
12839 SUMA_S_Err("No ado in focus");
12840 SUMA_RETURNe;
12841 }
12842
12843 switch (ado->do_type) {
12844 case SO_type:
12845 SUMA_JumpIndex_SO (s, sv, (SUMA_SurfaceObject *)ado);
12846 break;
12847 case GDSET_type:
12848 SUMA_JumpIndex_GDSET (s, sv, (SUMA_DSET *)ado, variant);
12849 break;
12850 case CDOM_type:
12851 SUMA_JumpIndex_CO (s, sv, (SUMA_CIFTI_DO *)ado);
12852 break;
12853 case GRAPH_LINK_type: {
12854 SUMA_GraphLinkDO *gldo=(SUMA_GraphLinkDO *)ado;
12855 SUMA_DSET *dset=NULL;
12856 if (!(dset=SUMA_find_GLDO_Dset(gldo))) {
12857 SUMA_S_Errv("Failed to find dset for gldo %s!!!\n",
12858 SUMA_ADO_Label(ado));
12859 break;
12860 }
12861 SUMA_JumpIndex_GDSET (s, sv, dset, gldo->variant);
12862 break; }
12863 case TRACT_type: {
12864 SUMA_JumpIndex_TDO (s, sv, (SUMA_TractDO *)ado);
12865 break; }
12866 case MASK_type: {
12867 SUMA_JumpIndex_MDO (s, sv, (SUMA_MaskDO *)ado);
12868 break; }
12869 case VO_type: {
12870 SUMA_JumpIndex_VO (s, sv, (SUMA_VolumeObject *)ado);
12871 break; }
12872 default:
12873 SUMA_S_Errv("For %s nothing my dear\n",
12874 SUMA_ObjectTypeCode2ObjectTypeName(ado->do_type));
12875 break;
12876 }
12877 SUMA_RETURNe;
12878 }
12879
12880 /*!
12881 \brief sends the cross hair to a certain node index
12882 \param s (char *) a string containing node index
12883 \param data (void *) a typecast of the pointer to the surface
12884 viewer to be affected
12885
12886 */
SUMA_JumpIndex_SO(char * s,SUMA_SurfaceViewer * sv,SUMA_SurfaceObject * SO)12887 void SUMA_JumpIndex_SO (char *s, SUMA_SurfaceViewer *sv, SUMA_SurfaceObject *SO)
12888 {
12889 static char FuncName[]={"SUMA_JumpIndex_SO"};
12890 DList *list=NULL;
12891 SUMA_EngineData *ED = NULL;
12892 DListElmt *el=NULL, *Location=NULL;
12893 SUMA_SurfaceObject *SOc=NULL;
12894 SUMA_SO_SIDE sd=SUMA_NO_SIDE;
12895 float fv3[3];
12896 int it, iv3[3];
12897 SUMA_Boolean LocalHead = NOPE;
12898
12899 SUMA_ENTRY;
12900
12901 // fprintf(stderr, "%s\n", FuncName);
12902
12903 if (!s || !sv || !SO) SUMA_RETURNe;
12904
12905 /* HERE you should check if you have an L or R at the beginning
12906 or end of s.
12907 If you do, then first see if the side of SO (the focus surface)
12908 is the same as the letter. If it is, proceed. If it is not,
12909 try to get the contralateral surface with SUMA_Contralateral_SO
12910 then set the contralateral as the focus surface, then proceed
12911 with setting the focus node. Needs more work
12912 */
12913 /* parse s */
12914 SUMA_LHv("Parsing %s\n", s);
12915 if (SUMA_StringToNumSide(s, (void*)fv3, 1,1, &sd) != 1) {
12916 /*problem, beep and ignore */
12917 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12918 SUMA_RETURNe;
12919 }
12920
12921 /* do we have side match with Focus node? */
12922 SUMA_LHv("Side of jump is %d, SO %s side %d\n", sd, SO->Label, SO->Side);
12923 if (sd == SUMA_RIGHT || sd == SUMA_LEFT) {
12924 if ((SO->Side == SUMA_RIGHT || SO->Side == SUMA_LEFT) &&
12925 SO->Side != sd) {
12926 /* Need to swith sides */
12927 if ((SOc = SUMA_Contralateral_SO(SO, SUMAg_DOv, SUMAg_N_DOv))) {
12928 sv->Focus_DO_ID = SUMA_findSO_inDOv(SOc->idcode_str,
12929 SUMAg_DOv, SUMAg_N_DOv);
12930 SUMA_LHv("Jumping to %s (contralateral of %s)\n",
12931 SOc->Label, SO->Label);
12932 SO = SOc;
12933 } else {
12934 SUMA_S_Errv("Failed to find contralateral surface to %s\n"
12935 "Ignoring jump to node's side marker\n",
12936 SO->Label);
12937 }
12938 }
12939 }
12940
12941
12942 /* Set the Nodeselection */
12943 it = (int) fv3[0];
12944 if (!list) list = SUMA_CreateList ();
12945 ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
12946 if (!(el = SUMA_RegisterEngineListCommand ( list, ED,
12947 SEF_i, (void*)(&it),
12948 SES_Suma, (void *)sv, NOPE,
12949 SEI_Head, NULL))) {
12950 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12951 SUMA_RETURNe;
12952 } else {
12953 SUMA_RegisterEngineListCommand ( list, ED,
12954 SEF_ngr, NULL,
12955 SES_Suma, (void *)sv, NOPE,
12956 SEI_In, el);
12957 }
12958
12959
12960 /* Now set the cross hair position at the selected node*/
12961 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
12962 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
12963 SEF_fv3, (void*)&(SO->NodeList[3*it]),
12964 SES_Suma, (void *)sv, NOPE,
12965 SEI_Head, NULL))) {
12966 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12967 SUMA_RETURNe;
12968 }
12969 /* and add the SO with this location, needed for VisX business*/
12970 SUMA_RegisterEngineListCommand ( list, ED,
12971 SEF_vp, (void *)SO,
12972 SES_Suma, (void *)sv, NOPE,
12973 SEI_In, Location);
12974
12975 /* attach the cross hair to the selected surface */
12976 iv3[0] = SUMA_findSO_inDOv(SO->idcode_str, SUMAg_DOv, SUMAg_N_DOv);
12977 iv3[1] = it;
12978 iv3[2] = -1;
12979 ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
12980 if (!SUMA_RegisterEngineListCommand ( list, ED,
12981 SEF_iv3, (void*)iv3,
12982 SES_Suma, (void *)sv, NOPE,
12983 SEI_Head, NULL)) {
12984 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12985 SUMA_RETURNe;
12986 }
12987
12988 /* check to see if AFNI needs to be notified */
12989 if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
12990 if (LocalHead)
12991 fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
12992 /* register a call to SetAfniCrossHair */
12993 it = 0; /* Set to 1 if you want instacorr notice to AFNI */
12994 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
12995 if (!SUMA_RegisterEngineListCommand ( list, ED,
12996 SEF_i, (void*)&it,
12997 SES_Suma, (void *)sv, NOPE,
12998 SEI_Tail, NULL)) {
12999 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13000 SUMA_RETURNe;
13001 }
13002
13003 }
13004
13005 /* and if GICOR needs some love */
13006 if ( SUMAg_CF->Connected_v[SUMA_GICORR_LINE] &&
13007 SUMAg_CF->giset && !SUMAg_CF->HoldClickCallbacks) {
13008 if (LocalHead)
13009 fprintf(SUMA_STDERR,
13010 "%s: Notifying GICOR of node selection\n", FuncName);
13011 /* register a call to SetGICORnode */
13012 SUMA_REGISTER_TAIL_COMMAND_NO_DATA( list, SE_SetGICORnode,
13013 SES_Suma, sv);
13014 }else {
13015 SUMA_LHv("No Notification to GICOR. %d %p\n",
13016 SUMAg_CF->Connected_v[SUMA_GICORR_LINE], SUMAg_CF->giset);
13017 }
13018
13019 /* call with the list */
13020 if (!SUMA_Engine (&list)) {
13021 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13022 SUMA_RETURNe;
13023 }
13024
13025 /* now put in a request for locking cross hair but you must do this
13026 after the node selection has been executed
13027 NOTE: You do not always have SetNodeElem because the list might get emptied in
13028 the call to AFNI notification.
13029 You should just put the next call at the end of the list.*/
13030 if (!list) list = SUMA_CreateList();
13031 ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
13032 if (!SUMA_RegisterEngineListCommand ( list, ED,
13033 SEF_iv3, (void*)iv3,
13034 SES_Suma, (void *)sv, NOPE,
13035 SEI_Tail, NULL)) {
13036 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13037 SUMA_RETURNe;
13038 }
13039
13040 /* call with the list */
13041 if (!SUMA_Engine (&list)) {
13042 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13043 SUMA_RETURNe;
13044 }
13045
13046 /* redisplay curent only*/
13047 sv->ResetGLStateVariables = YUP;
13048 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
13049
13050 SUMA_RETURNe;
13051
13052 }
13053
13054 /* Jump to a certain edge on a graph dset */
SUMA_JumpIndex_GDSET(char * s,SUMA_SurfaceViewer * sv,SUMA_DSET * dset,char * variant)13055 void SUMA_JumpIndex_GDSET (char *s, SUMA_SurfaceViewer *sv,
13056 SUMA_DSET *dset, char *variant)
13057 {
13058 static char FuncName[]={"SUMA_JumpIndex_GDSET"};
13059 DList *list=NULL;
13060 DListElmt *el=NULL, *Location=NULL;
13061 SUMA_EngineData *ED = NULL;
13062 float fv3[3];
13063 int it, iv3[3];
13064 SUMA_Boolean LocalHead = NOPE;
13065
13066 SUMA_ENTRY;
13067
13068 // fprintf(stderr, "%s\n", FuncName);
13069
13070 if (!s || !sv) SUMA_RETURNe;
13071
13072 /* parse s */
13073 SUMA_LHv("Parsing %s\n", s);
13074 if (SUMA_StringToNum(s, (void*)fv3, 1,1) != 1) {
13075 /*problem, beep and ignore */
13076 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13077 SUMA_RETURNe;
13078 }
13079
13080 /* Set the Nodeselection */
13081 it = (int) fv3[0];
13082 if (!list) list = SUMA_CreateList ();
13083 ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
13084 if (!(el = SUMA_RegisterEngineListCommand ( list, ED,
13085 SEF_i, (void*)(&it),
13086 SES_Suma, (void *)sv, NOPE,
13087 SEI_Head, NULL))) {
13088 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13089 SUMA_RETURNe;
13090 } else {
13091 SUMA_RegisterEngineListCommand ( list, ED,
13092 SEF_ngr, NULL,
13093 SES_Suma, (void *)sv, NOPE,
13094 SEI_In, el);
13095 }
13096
13097
13098 /* Now set the cross hair position at the selected node*/
13099 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
13100 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
13101 SEF_fv3,
13102 (void*)(SUMA_GDSET_NodeXYZ(dset, it, variant, NULL)),
13103 SES_Suma, (void *)sv, NOPE,
13104 SEI_Head, NULL))) {
13105 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13106 SUMA_RETURNe;
13107 }
13108 /* and add the object with this location */
13109 SUMA_RegisterEngineListCommand ( list, ED,
13110 SEF_vp, (void *)dset,
13111 SES_Suma, (void *)sv, NOPE,
13112 SEI_In, Location);
13113
13114 /* attach the cross hair to the selected object
13115 Note that binding here is to edge of graph and not to a node*/
13116 SUMA_find_Dset_GLDO(dset,variant, iv3); /* this will set iv3[0] */
13117 iv3[1] = it;
13118 iv3[2] = -1;
13119 ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
13120 if (!SUMA_RegisterEngineListCommand ( list, ED,
13121 SEF_iv3, (void*)iv3,
13122 SES_Suma, (void *)sv, NOPE,
13123 SEI_Head, NULL)) {
13124 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13125 SUMA_RETURNe;
13126 }
13127
13128 /* check to see if AFNI needs to be notified */
13129 if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
13130 if (LocalHead)
13131 fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
13132 it = 0;
13133 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
13134 if (!SUMA_RegisterEngineListCommand ( list, ED,
13135 SEF_i, (void*)&it,
13136 SES_Suma, (void *)sv, NOPE,
13137 SEI_Tail, NULL)) {
13138 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13139 SUMA_RETURNe;
13140 }
13141
13142 }
13143
13144 /* call with the list */
13145 if (!SUMA_Engine (&list)) {
13146 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13147 SUMA_RETURNe;
13148 }
13149
13150 /* now put in a request for locking cross hair but you must do this
13151 after the node selection has been executed
13152 NOTE: You do not always have SetNodeElem because the list might get emptied in
13153 the call to AFNI notification.
13154 You should just put the next call at the end of the list.*/
13155 if (!list) list = SUMA_CreateList();
13156 ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
13157 if (!SUMA_RegisterEngineListCommand ( list, ED,
13158 SEF_iv3, (void*)iv3,
13159 SES_Suma, (void *)sv, NOPE,
13160 SEI_Tail, NULL)) {
13161 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13162 SUMA_RETURNe;
13163 }
13164
13165 /* call with the list */
13166 if (!SUMA_Engine (&list)) {
13167 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13168 SUMA_RETURNe;
13169 }
13170
13171 /* redisplay curent only*/
13172 sv->ResetGLStateVariables = YUP;
13173 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
13174
13175 SUMA_RETURNe;
13176
13177 }
13178
13179 /* Jump to a certain point on a tract object */
SUMA_JumpIndex_TDO(char * s,SUMA_SurfaceViewer * sv,SUMA_TractDO * tdo)13180 void SUMA_JumpIndex_TDO (char *s, SUMA_SurfaceViewer *sv,
13181 SUMA_TractDO *tdo)
13182 {
13183 static char FuncName[]={"SUMA_JumpIndex_TDO"};
13184 DList *list=NULL;
13185 SUMA_ALL_DO *ado = (SUMA_ALL_DO *)tdo;
13186 DListElmt *el=NULL, *Location=NULL;
13187 SUMA_EngineData *ED = NULL;
13188 float fv3[3];
13189 int it, iv15[15], iv3[3], nv = 0;
13190 char stmp[64];
13191 SUMA_Boolean revert_on_err = YUP;
13192 SUMA_Boolean LocalHead = NOPE;
13193
13194 SUMA_ENTRY;
13195
13196 // fprintf(stderr, "%s\n", FuncName);
13197
13198 if (!s || !sv || !tdo || !tdo->net) SUMA_RETURNe;
13199
13200 /* parse s */
13201 if ((nv = SUMA_StringToNum(s, (void*)fv3, 3,1)) != 1 &&
13202 nv != 3) {
13203 /*problem, beep and ignore */
13204 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13205 SUMA_RETURNe;
13206 }
13207 SUMA_LHv("Parsed %s to %d val(s)\n", s, nv);
13208 if (nv == 3) {/* bundle, tract, point */
13209 iv15[SUMA_NET_BUN] = (int)fv3[SUMA_NET_BUN];
13210 iv15[SUMA_BUN_TRC] = (int)fv3[SUMA_BUN_TRC];
13211 iv15[SUMA_TRC_PNT] = (int)fv3[SUMA_TRC_PNT];
13212 iv15[SUMA_NET_TRC] =
13213 Network_TB_to_1T(tdo->net, iv15[SUMA_BUN_TRC], iv15[SUMA_NET_BUN]);
13214 it = Network_PTB_to_1P(tdo->net,
13215 iv15[SUMA_TRC_PNT], iv15[SUMA_BUN_TRC], iv15[SUMA_NET_BUN]);
13216 if (it < 0) { /* no good */
13217 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13218 SUMA_LH("BTP %d %d %d could not be parsed\n",
13219 iv15[SUMA_NET_BUN], iv15[SUMA_BUN_TRC], iv15[SUMA_TRC_PNT]);
13220 if (revert_on_err) {
13221 sprintf(stmp,"%d", SUMA_ADO_SelectedDatum(ado, NULL, NULL));
13222 SUMA_JumpIndex_TDO(stmp, sv, tdo);
13223 }
13224 SUMA_RETURNe;
13225 }
13226 SUMA_LHv("Point ID %d from B%d T%d P%d (tract in net %d)\n",
13227 it, iv15[SUMA_NET_BUN], iv15[SUMA_BUN_TRC],
13228 iv15[SUMA_TRC_PNT], iv15[SUMA_NET_TRC]);
13229 } else {
13230 /* Set the point selection */
13231 it = (int) fv3[0];
13232 if (!Network_1P_to_PTB(tdo->net, it,
13233 iv15+SUMA_TRC_PNT, iv15+SUMA_BUN_TRC,
13234 iv15+SUMA_NET_BUN, iv15+SUMA_NET_TRC)) {
13235 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13236 SUMA_RETURNe;
13237 }
13238 SUMA_LHv("Point ID %d yielded B%d T%d P%d (tract in net %d) \n"
13239 " (which yields back %d)\n",
13240 it, iv15[SUMA_NET_BUN], iv15[SUMA_BUN_TRC], iv15[SUMA_TRC_PNT],
13241 iv15[SUMA_NET_TRC],
13242 Network_PTB_to_1P(tdo->net,
13243 iv15[SUMA_TRC_PNT], iv15[SUMA_BUN_TRC], iv15[SUMA_NET_BUN]));
13244 }
13245
13246 SUMA_TDO_PointXYZ(tdo, it, iv15, fv3);
13247 SUMA_LH(" Located at %f %f %f\n", fv3[0], fv3[1], fv3[2]);
13248
13249 if (!list) list = SUMA_CreateList ();
13250 ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
13251 if (!(el = SUMA_RegisterEngineListCommand ( list, ED,
13252 SEF_i, (void*)(&it),
13253 SES_Suma, (void *)sv, NOPE,
13254 SEI_Head, NULL))) {
13255 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13256 SUMA_RETURNe;
13257 } else {
13258 SUMA_RegisterEngineListCommand ( list, ED,
13259 SEF_ngr, NULL,
13260 SES_Suma, (void *)sv, NOPE,
13261 SEI_In, el);
13262 SUMA_RegisterEngineListCommand ( list, ED,
13263 SEF_iv15, (void *)iv15,
13264 SES_Suma, (void *)sv, NOPE,
13265 SEI_In, el);
13266 }
13267
13268
13269 /* Now set the cross hair position at the selected point*/
13270 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
13271 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
13272 SEF_fv3, (void*)fv3,
13273 SES_Suma, (void *)sv, NOPE,
13274 SEI_Head, NULL))) {
13275 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13276 SUMA_RETURNe;
13277 }
13278 /* and add the DO with this location, needed for VisX business*/
13279 SUMA_RegisterEngineListCommand ( list, ED,
13280 SEF_vp, (void *)tdo,
13281 SES_Suma, (void *)sv, NOPE,
13282 SEI_In, Location);
13283
13284 /* attach the cross hair to the selected object
13285 Note that binding here is to edge of graph and not to a node*/
13286 iv3[0] = SUMA_whichDO(SUMA_ADO_idcode(ado), SUMAg_DOv, SUMAg_N_DOv);
13287 iv3[1] = it;
13288 iv3[2] = -1;
13289 ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
13290 if (!SUMA_RegisterEngineListCommand ( list, ED,
13291 SEF_iv3, (void*)iv3,
13292 SES_Suma, (void *)sv, NOPE,
13293 SEI_Head, NULL)) {
13294 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13295 SUMA_RETURNe;
13296 }
13297
13298 /* check to see if AFNI needs to be notified */
13299 if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
13300 if (LocalHead)
13301 fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
13302 it = 0;
13303 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
13304 if (!SUMA_RegisterEngineListCommand ( list, ED,
13305 SEF_i, (void*)&it,
13306 SES_Suma, (void *)sv, NOPE,
13307 SEI_Tail, NULL)) {
13308 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13309 SUMA_RETURNe;
13310 }
13311
13312 }
13313
13314 /* call with the list */
13315 if (!SUMA_Engine (&list)) {
13316 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13317 SUMA_RETURNe;
13318 }
13319
13320 /* now put in a request for locking cross hair but you must do this
13321 after the node selection has been executed
13322 NOTE: You do not always have SetNodeElem because the list might get emptied in
13323 the call to AFNI notification.
13324 You should just put the next call at the end of the list.*/
13325 if (!list) list = SUMA_CreateList();
13326 ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
13327 if (!SUMA_RegisterEngineListCommand ( list, ED,
13328 SEF_iv3, (void*)iv3,
13329 SES_Suma, (void *)sv, NOPE,
13330 SEI_Tail, NULL)) {
13331 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13332 SUMA_RETURNe;
13333 }
13334
13335 /* call with the list */
13336 if (!SUMA_Engine (&list)) {
13337 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13338 SUMA_RETURNe;
13339 }
13340
13341 /* redisplay curent only*/
13342 sv->ResetGLStateVariables = YUP;
13343 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
13344
13345 SUMA_RETURNe;
13346
13347 }
13348
13349 /* Jump to a certain datum on a CIFTI object */
SUMA_JumpIndex_CO(char * s,SUMA_SurfaceViewer * sv,SUMA_CIFTI_DO * co)13350 void SUMA_JumpIndex_CO (char *s, SUMA_SurfaceViewer *sv,
13351 SUMA_CIFTI_DO *co)
13352 {
13353 static char FuncName[]={"SUMA_JumpIndex_CO"};
13354 DList *list=NULL;
13355 SUMA_ALL_DO *ado = (SUMA_ALL_DO *)co;
13356 DListElmt *el=NULL, *Location=NULL;
13357 SUMA_EngineData *ED = NULL;
13358 float fv3[3], fv15[15];
13359 int it, iv15[15], iv3[3], nv = 0, *dims=NULL;
13360 char stmp[64];
13361 SUMA_DSET *dset=NULL;
13362 SUMA_Boolean revert_on_err = YUP;
13363 SUMA_Boolean LocalHead = NOPE;
13364
13365 SUMA_ENTRY;
13366
13367 // fprintf(stderr, "%s\n", FuncName);
13368
13369 SUMA_LH("Called");
13370
13371 SUMA_S_Err("Not implemented, see SUMA_JumpIndex_VO and SUMA_JumpIndex_SO "
13372 "for inspiration. You will need to determine the domain of "
13373 "the index before jumping anyway");
13374
13375 SUMA_RETURNe;
13376 }
13377
13378 /* Jump to a certain point on a volume object */
SUMA_JumpIndex_VO(char * s,SUMA_SurfaceViewer * sv,SUMA_VolumeObject * vo)13379 void SUMA_JumpIndex_VO (char *s, SUMA_SurfaceViewer *sv,
13380 SUMA_VolumeObject *vo)
13381 {
13382 static char FuncName[]={"SUMA_JumpIndex_VO"};
13383 DList *list=NULL;
13384 SUMA_ALL_DO *ado = (SUMA_ALL_DO *)vo;
13385 DListElmt *el=NULL, *Location=NULL;
13386 SUMA_EngineData *ED = NULL;
13387 float fv3[3], fv15[15];
13388 int it, iv15[15], iv3[3], nv = 0, *dims=NULL;
13389 char stmp[64];
13390 SUMA_DSET *dset=NULL;
13391 SUMA_Boolean revert_on_err = YUP;
13392 SUMA_Boolean LocalHead = NOPE;
13393
13394 SUMA_ENTRY;
13395
13396 // fprintf(stderr, "%s\n", FuncName);
13397
13398 SUMA_LH("Called");
13399 if (!s || !sv || !vo ||
13400 !(dset = SUMA_VO_dset(vo)) ||
13401 !(dims = SUMA_GetDatasetDimensions(dset))) SUMA_RETURNe;
13402
13403 /* parse s */
13404 if ((nv = SUMA_StringToNum(s, (void*)fv3, 3,1)) != 1 &&
13405 nv != 3) {
13406 /*problem, beep and ignore */
13407 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13408 SUMA_RETURNe;
13409 }
13410 SUMA_LHv("Parsed %s to %d val(s)\n", s, nv);
13411 if (nv == 3) {/* i j k */
13412 iv15[SUMA_VOL_I] = (int)fv3[SUMA_VOL_I];
13413 iv15[SUMA_VOL_J] = (int)fv3[SUMA_VOL_J];
13414 iv15[SUMA_VOL_K] = (int)fv3[SUMA_VOL_K];
13415 if (iv15[SUMA_VOL_I] < 0 || iv15[SUMA_VOL_I] >= dims[0] ||
13416 iv15[SUMA_VOL_J] < 0 || iv15[SUMA_VOL_J] >= dims[1] ||
13417 iv15[SUMA_VOL_K] < 0 || iv15[SUMA_VOL_K] >= dims[2] ) {
13418 /* no good */
13419 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13420 SUMA_LH("IJK %d %d %d could not be parsed or out of range\n",
13421 iv15[SUMA_VOL_I], iv15[SUMA_VOL_J], iv15[SUMA_VOL_K]);
13422 if (revert_on_err) {
13423 sprintf(stmp,"%d", SUMA_ADO_SelectedDatum(ado, NULL, NULL));
13424 SUMA_JumpIndex_VO(stmp, sv, vo);
13425 }
13426 SUMA_RETURNe;
13427 }
13428
13429 iv15[SUMA_VOL_IJK] =
13430 SUMA_3D_2_1D_index(iv15[SUMA_VOL_I], iv15[SUMA_VOL_J], iv15[SUMA_VOL_K],
13431 dims[0], dims[0]*dims[1] );
13432
13433 it = iv15[SUMA_VOL_IJK];
13434
13435 SUMA_LHv("Voxel ID %d from I%d J%d K%d\n",
13436 iv15[SUMA_VOL_IJK], iv15[SUMA_VOL_I], iv15[SUMA_VOL_J],
13437 iv15[SUMA_VOL_K]);
13438 } else {
13439 /* Set the point selection */
13440 it = (int) fv3[0];
13441 if (it < 0 || it >= SDSET_NVOX(dset)) {
13442 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13443 SUMA_RETURNe;
13444 }
13445 Vox1D2Vox3D(it, dims[0], dims[0]*dims[1], (iv15+SUMA_VOL_I));
13446 SUMA_LHv("Point ID %d yielded I%d J%d K%d \n",
13447 it, iv15[SUMA_VOL_I], iv15[SUMA_VOL_J], iv15[SUMA_VOL_K]);
13448 }
13449
13450 SUMA_VO_PointXYZ(vo, it, iv15, fv3);
13451 SUMA_LH(" Located at %f %f %f\n", fv3[0], fv3[1], fv3[2]);
13452 SUMA_MARK_PLANE_NOT_SET(fv15+SUMA_VOL_SLC_EQ0); /* No cigar */
13453
13454 if (!list) list = SUMA_CreateList ();
13455 ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
13456 if (!(el = SUMA_RegisterEngineListCommand ( list, ED,
13457 SEF_i, (void*)(&it),
13458 SES_Suma, (void *)sv, NOPE,
13459 SEI_Head, NULL))) {
13460 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13461 SUMA_RETURNe;
13462 } else {
13463 SUMA_RegisterEngineListCommand ( list, ED,
13464 SEF_ngr, NULL,
13465 SES_Suma, (void *)sv, NOPE,
13466 SEI_In, el);
13467 SUMA_RegisterEngineListCommand ( list, ED,
13468 SEF_iv15, (void *)iv15,
13469 SES_Suma, (void *)sv, NOPE,
13470 SEI_In, el);
13471 SUMA_RegisterEngineListCommand ( list, ED,
13472 SEF_fv15, (void *)fv15,
13473 SES_Suma, (void *)sv, NOPE,
13474 SEI_In, el);
13475 }
13476
13477
13478 /* Now set the cross hair position at the selected point*/
13479 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
13480 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
13481 SEF_fv3, (void*)fv3,
13482 SES_Suma, (void *)sv, NOPE,
13483 SEI_Head, NULL))) {
13484 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13485 SUMA_RETURNe;
13486 }
13487 /* and add the DO with this location, needed for VisX business*/
13488 SUMA_RegisterEngineListCommand ( list, ED,
13489 SEF_vp, (void *)vo,
13490 SES_Suma, (void *)sv, NOPE,
13491 SEI_In, Location);
13492
13493 /* attach the cross hair to the selected object
13494 Note that binding here is to edge of graph and not to a node*/
13495 iv3[0] = SUMA_whichDO(SUMA_ADO_idcode(ado), SUMAg_DOv, SUMAg_N_DOv);
13496 iv3[1] = it;
13497 iv3[2] = -1;
13498 ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
13499 if (!SUMA_RegisterEngineListCommand ( list, ED,
13500 SEF_iv3, (void*)iv3,
13501 SES_Suma, (void *)sv, NOPE,
13502 SEI_Head, NULL)) {
13503 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13504 SUMA_RETURNe;
13505 }
13506
13507 /* check to see if AFNI needs to be notified */
13508 if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
13509 if (LocalHead)
13510 fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
13511 it = 0;
13512 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
13513 if (!SUMA_RegisterEngineListCommand ( list, ED,
13514 SEF_i, (void*)&it,
13515 SES_Suma, (void *)sv, NOPE,
13516 SEI_Tail, NULL)) {
13517 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13518 SUMA_RETURNe;
13519 }
13520
13521 }
13522
13523 /* call with the list */
13524 if (!SUMA_Engine (&list)) {
13525 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13526 SUMA_RETURNe;
13527 }
13528
13529 /* now put in a request for locking cross hair but you must do this
13530 after the node selection has been executed
13531 NOTE: You do not always have SetNodeElem because the list might get emptied in
13532 the call to AFNI notification.
13533 You should just put the next call at the end of the list.*/
13534 if (!list) list = SUMA_CreateList();
13535 ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
13536 if (!SUMA_RegisterEngineListCommand ( list, ED,
13537 SEF_iv3, (void*)iv3,
13538 SES_Suma, (void *)sv, NOPE,
13539 SEI_Tail, NULL)) {
13540 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13541 SUMA_RETURNe;
13542 }
13543
13544 /* call with the list */
13545 if (!SUMA_Engine (&list)) {
13546 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13547 SUMA_RETURNe;
13548 }
13549
13550 /* redisplay curent only*/
13551 sv->ResetGLStateVariables = YUP;
13552 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
13553
13554 SUMA_RETURNe;
13555
13556 }
13557
13558 /* Jump to a certain point on a mask object */
SUMA_JumpIndex_MDO(char * s,SUMA_SurfaceViewer * sv,SUMA_MaskDO * mo)13559 void SUMA_JumpIndex_MDO (char *s, SUMA_SurfaceViewer *sv, SUMA_MaskDO *mo)
13560 {
13561 static char FuncName[]={"SUMA_JumpIndex_MDO"};
13562 DList *list=NULL;
13563 SUMA_ALL_DO *ado = (SUMA_ALL_DO *)mo;
13564 DListElmt *el=NULL, *Location=NULL;
13565 SUMA_EngineData *ED = NULL;
13566 float fv3[3];
13567 int it, iv15[15], iv3[3], nv = 0, *dims=NULL;
13568 char stmp[64];
13569 SUMA_DSET *dset=NULL;
13570 SUMA_Boolean revert_on_err = YUP;
13571 SUMA_Boolean LocalHead = NOPE;
13572
13573 SUMA_ENTRY;
13574
13575 // fprintf(stderr, "%s\n", FuncName);
13576
13577 if (!s || !sv) SUMA_RETURNe;
13578
13579 SUMA_S_Err("Not ready for action");
13580 SUMA_RETURNe;
13581
13582 /* parse s */
13583 if ((nv = SUMA_StringToNum(s, (void*)fv3, 3,1)) != 1 &&
13584 nv != 3) {
13585 /*problem, beep and ignore */
13586 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13587 SUMA_RETURNe;
13588 }
13589 SUMA_LHv("Parsed %s to %d val(s)\n", s, nv);
13590 if (nv == 3) {/* i j k */
13591 iv15[SUMA_VOL_I] = (int)fv3[SUMA_VOL_I];
13592 iv15[SUMA_VOL_J] = (int)fv3[SUMA_VOL_J];
13593 iv15[SUMA_VOL_K] = (int)fv3[SUMA_VOL_K];
13594 if (iv15[SUMA_VOL_I] < 0 || iv15[SUMA_VOL_I] >= dims[0] ||
13595 iv15[SUMA_VOL_J] < 0 || iv15[SUMA_VOL_J] >= dims[1] ||
13596 iv15[SUMA_VOL_K] < 0 || iv15[SUMA_VOL_K] >= dims[2] ) {
13597 /* no good */
13598 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13599 SUMA_LH("IJK %d %d %d could not be parsed or out of range\n",
13600 iv15[SUMA_VOL_I], iv15[SUMA_VOL_J], iv15[SUMA_VOL_K]);
13601 if (revert_on_err) {
13602 sprintf(stmp,"%d", SUMA_ADO_SelectedDatum(ado, NULL, NULL));
13603 SUMA_JumpIndex_MDO(stmp, sv, mo);
13604 }
13605 SUMA_RETURNe;
13606 }
13607
13608 iv15[SUMA_VOL_IJK] =
13609 SUMA_3D_2_1D_index(iv15[SUMA_VOL_I], iv15[SUMA_VOL_J], iv15[SUMA_VOL_K],
13610 dims[0], dims[0]*dims[1] );
13611
13612
13613 SUMA_LHv("Voxel ID %d from I%d J%d K%d\n",
13614 iv15[SUMA_VOL_IJK], iv15[SUMA_VOL_I], iv15[SUMA_VOL_J],
13615 iv15[SUMA_VOL_K]);
13616 } else {
13617 /* Set the point selection */
13618 it = (int) fv3[0];
13619 if (it < 0 || it >= SDSET_NVOX(dset)) {
13620 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13621 SUMA_RETURNe;
13622 }
13623 Vox1D2Vox3D(it, dims[0], dims[0]*dims[1], (iv15+SUMA_VOL_I));
13624 SUMA_LHv("Point ID %d yielded I%d J%d K%d \n",
13625 it, iv15[SUMA_VOL_I], iv15[SUMA_VOL_J], iv15[SUMA_VOL_K]);
13626 }
13627
13628 SUMA_MDO_PointXYZ(mo, it, iv15, fv3);
13629 SUMA_LH(" Located at %f %f %f\n", fv3[0], fv3[1], fv3[2]);
13630
13631 if (!list) list = SUMA_CreateList ();
13632 ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
13633 if (!(el = SUMA_RegisterEngineListCommand ( list, ED,
13634 SEF_i, (void*)(&it),
13635 SES_Suma, (void *)sv, NOPE,
13636 SEI_Head, NULL))) {
13637 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13638 SUMA_RETURNe;
13639 } else {
13640 SUMA_RegisterEngineListCommand ( list, ED,
13641 SEF_ngr, NULL,
13642 SES_Suma, (void *)sv, NOPE,
13643 SEI_In, el);
13644 SUMA_RegisterEngineListCommand ( list, ED,
13645 SEF_iv15, (void *)iv15,
13646 SES_Suma, (void *)sv, NOPE,
13647 SEI_In, el);
13648 }
13649
13650
13651 /* Now set the cross hair position at the selected point*/
13652 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
13653 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
13654 SEF_fv3, (void*)fv3,
13655 SES_Suma, (void *)sv, NOPE,
13656 SEI_Head, NULL))) {
13657 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13658 SUMA_RETURNe;
13659 }
13660 /* and add the DO with this location, needed for VisX business*/
13661 SUMA_RegisterEngineListCommand ( list, ED,
13662 SEF_vp, (void *)mo,
13663 SES_Suma, (void *)sv, NOPE,
13664 SEI_In, Location);
13665
13666 /* attach the cross hair to the selected object
13667 Note that binding here is to edge of graph and not to a node*/
13668 iv3[0] = SUMA_whichDO(SUMA_ADO_idcode(ado), SUMAg_DOv, SUMAg_N_DOv);
13669 iv3[1] = it;
13670 iv3[2] = -1;
13671 ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
13672 if (!SUMA_RegisterEngineListCommand ( list, ED,
13673 SEF_iv3, (void*)iv3,
13674 SES_Suma, (void *)sv, NOPE,
13675 SEI_Head, NULL)) {
13676 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13677 SUMA_RETURNe;
13678 }
13679
13680 /* check to see if AFNI needs to be notified */
13681 if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
13682 if (LocalHead)
13683 fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
13684 it = 0;
13685 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
13686 if (!SUMA_RegisterEngineListCommand ( list, ED,
13687 SEF_i, (void*)&it,
13688 SES_Suma, (void *)sv, NOPE,
13689 SEI_Tail, NULL)) {
13690 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13691 SUMA_RETURNe;
13692 }
13693
13694 }
13695
13696 /* call with the list */
13697 if (!SUMA_Engine (&list)) {
13698 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13699 SUMA_RETURNe;
13700 }
13701
13702 /* now put in a request for locking cross hair but you must do this
13703 after the node selection has been executed
13704 NOTE: You do not always have SetNodeElem because the list might get emptied in
13705 the call to AFNI notification.
13706 You should just put the next call at the end of the list.*/
13707 if (!list) list = SUMA_CreateList();
13708 ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
13709 if (!SUMA_RegisterEngineListCommand ( list, ED,
13710 SEF_iv3, (void*)iv3,
13711 SES_Suma, (void *)sv, NOPE,
13712 SEI_Tail, NULL)) {
13713 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13714 SUMA_RETURNe;
13715 }
13716
13717 /* call with the list */
13718 if (!SUMA_Engine (&list)) {
13719 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13720 SUMA_RETURNe;
13721 }
13722
13723 /* redisplay curent only*/
13724 sv->ResetGLStateVariables = YUP;
13725 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
13726
13727 SUMA_RETURNe;
13728
13729 }
13730
13731 /*!
13732 \brief sends the cross hair to a certain XYZ location.
13733
13734 \param s (char *) a string containing XYZ coordinates
13735 \param data (void *) a typecast of the pointer to the surface viewer to be affected
13736
13737 - Update to AFNI is done if linked
13738 - Update to other viewers is performed IF they are XYZ locked
13739 (that can get confusing)
13740 */
SUMA_JumpXYZ(char * s,void * data)13741 void SUMA_JumpXYZ (char *s, void *data)
13742 {
13743 static char FuncName[]={"SUMA_JumpXYZ"};
13744 DList *list=NULL;
13745 DListElmt *Location=NULL;
13746 SUMA_EngineData *ED = NULL;
13747 SUMA_SurfaceViewer *sv = NULL;
13748 float fv3[3];
13749 SUMA_Boolean LocalHead = NOPE;
13750
13751 SUMA_ENTRY;
13752
13753 // fprintf(stderr, "%s\n", FuncName);
13754
13755 if (!s) SUMA_RETURNe;
13756
13757 sv = (SUMA_SurfaceViewer *)data;
13758
13759 /* parse s */
13760 if (SUMA_StringToNum (s, (void*)fv3, 3,1) != 3) {/*problem, beep and ignore */
13761 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13762 SUMA_RETURNe;
13763 }
13764
13765 /* Now set the cross hair position */
13766 if (!list) list = SUMA_CreateList ();
13767 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
13768 if (!(Location = SUMA_RegisterEngineListCommand ( list, ED,
13769 SEF_fv3, (void*)fv3,
13770 SES_Suma, (void *)sv, NOPE,
13771 SEI_Head, NULL))) {
13772 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13773 SUMA_RETURNe;
13774 }
13775 /* and add the SO with this location (not possible here), needed for VisX
13776 business*/
13777 SUMA_RegisterEngineListCommand ( list, ED,
13778 SEF_vp, NULL,
13779 SES_Suma, (void *)sv, NOPE,
13780 SEI_In, Location);
13781
13782 /* check to see if AFNI needs to be notified */
13783 if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
13784 int it;
13785 if (LocalHead)
13786 fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
13787 it = 0;
13788 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
13789 if (!SUMA_RegisterEngineListCommand ( list, ED,
13790 SEF_i, (void*)&it,
13791 SES_Suma, (void *)sv, NOPE,
13792 SEI_Tail, NULL)) {
13793 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13794 SUMA_RETURNe;
13795 }
13796
13797 }
13798
13799 /* call with the list */
13800 if (!SUMA_Engine (&list)) {
13801 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13802 SUMA_RETURNe;
13803 }
13804
13805 /* now put in a request for locking cross hair but you must
13806 do this after the node selection has been executed
13807 NOTE: You do not always have SetNodeElem because the list might
13808 get emptied in the call to AFNI notification.
13809 You should just put the next call at the end of the list.*/
13810 /* NOTE2: Only viewers that are XYZ locked will be affected */
13811 if (!list) list = SUMA_CreateList();
13812 ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
13813 if (!SUMA_RegisterEngineListCommand ( list, ED,
13814 SEF_Empty, NULL,
13815 SES_Suma, (void *)sv, NOPE,
13816 SEI_Tail, NULL)) {
13817 SUMA_SLP_Err("Failed to register element");
13818 SUMA_RETURNe;
13819 }
13820
13821 /* call with the list */
13822 if (!SUMA_Engine (&list)) {
13823 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13824 SUMA_RETURNe;
13825 }
13826
13827
13828 /* redisplay curent only*/
13829 sv->ResetGLStateVariables = YUP;
13830 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
13831
13832 SUMA_RETURNe;
13833 }
13834
13835 /*!
13836 \brief Changes the focus node without moving the cross hair
13837 \param s (char *) a string containing node index
13838 \param data (void *) a typecast of the pointer to the surface viewer to be affected
13839
13840 -actions of this function are limited to the viewer that launched it
13841 */
13842
SUMA_JumpFocusNode(char * s,void * data)13843 void SUMA_JumpFocusNode (char *s, void *data)
13844 {
13845 static char FuncName[]={"SUMA_JumpFocusNode"};
13846 DList *list=NULL;
13847 DListElmt *el=NULL;
13848 SUMA_EngineData *ED = NULL;
13849 SUMA_SurfaceViewer *sv = NULL;
13850 float fv3[3];
13851 int it;
13852 SUMA_SurfaceObject *SO=NULL, *SOc=NULL;
13853 SUMA_SO_SIDE sd=SUMA_NO_SIDE;
13854 SUMA_Boolean LocalHead = NOPE;
13855
13856 SUMA_ENTRY;
13857
13858 // fprintf(stderr, "%s\n", FuncName);
13859
13860 if (!s) SUMA_RETURNe;
13861
13862 sv = (SUMA_SurfaceViewer *)data;
13863 if (!(SO = SUMA_SV_Focus_SO(sv))) {
13864 SUMA_S_Err("No SO in focus");
13865 SUMA_RETURNe;
13866 }
13867
13868
13869 /* HERE you should check if you have an L or R at the beginning
13870 or end of s.
13871 If you do, then first see if the side of SO (the focus surface)
13872 is the same as the letter. If it is, proceed. If it is not,
13873 try to get the contralateral surface with SUMA_Contralateral_SO
13874 then set the contralateral as the focus surface, then proceed
13875 with setting the focus node. Needs more work
13876 */
13877 /* parse s */
13878 SUMA_LHv("Parsing %s\n", s);
13879 if (SUMA_StringToNumSide(s, (void*)fv3, 1,1, &sd) != 1) {
13880 /*problem, beep and ignore */
13881 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13882 SUMA_RETURNe;
13883 }
13884
13885 SUMA_LHv("Side of focus jump is %d\n", sd);
13886 /* do we have side match with Focus node? */
13887 if (sd == SUMA_RIGHT || sd == SUMA_LEFT) {
13888 if ((SO->Side == SUMA_RIGHT || SO->Side == SUMA_LEFT) &&
13889 SO->Side != sd) {
13890 /* Need to swith sides */
13891 if ((SOc = SUMA_Contralateral_SO(SO, SUMAg_DOv, SUMAg_N_DOv))) {
13892 sv->Focus_DO_ID = SUMA_findSO_inDOv(SOc->idcode_str,
13893 SUMAg_DOv, SUMAg_N_DOv);
13894 SUMA_LHv("Jumping focus only to %s (contralateral of %s)\n",
13895 SOc->Label, SO->Label);
13896 SO = SOc;
13897 } else {
13898 SUMA_S_Errv("Failed to find contralateral surface to %s\n"
13899 "Ignoring jump to node's side marker\n",
13900 SO->Label);
13901 }
13902 }
13903 }
13904 /* Set the Nodeselection */
13905 it = (int) fv3[0];
13906 if (!list) list = SUMA_CreateList ();
13907 ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
13908 if (!(el=SUMA_RegisterEngineListCommand ( list, ED,
13909 SEF_i, (void*)(&it),
13910 SES_Suma, (void *)sv, NOPE,
13911 SEI_Head, NULL))) {
13912 SUMA_SLP_Err("Failed to register element");
13913 SUMA_RETURNe;
13914 } else {
13915 SUMA_RegisterEngineListCommand ( list, ED,
13916 SEF_ngr, NULL,
13917 SES_Suma, (void *)sv, NOPE,
13918 SEI_In, el);
13919 }
13920
13921 /* call with the list */
13922 if (!SUMA_Engine (&list)) {
13923 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13924 SUMA_RETURNe;
13925 }
13926
13927 /* redisplay curent only*/
13928 sv->ResetGLStateVariables = YUP;
13929 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
13930
13931 SUMA_RETURNe;
13932
13933 }
13934
13935 /*!
13936 \brief changes the selected faceset (Focus FaceSet)
13937 \param s (char *) a string containing FaceSet index
13938 \param data (void *) a typecast of the pointer to the surface viewer to be affected
13939
13940 */
SUMA_JumpFocusFace(char * s,void * data)13941 void SUMA_JumpFocusFace (char *s, void *data)
13942 {
13943 static char FuncName[]={"SUMA_JumpFocusFace"};
13944 DList *list=NULL;
13945 SUMA_EngineData *ED = NULL;
13946 SUMA_SurfaceViewer *sv = NULL;
13947 float fv3[3];
13948 int it;
13949
13950 SUMA_ENTRY;
13951
13952 // fprintf(stderr, "%s\n", FuncName);
13953
13954 if (!s) SUMA_RETURNe;
13955
13956 sv = (SUMA_SurfaceViewer *)data;
13957
13958 /* parse s */
13959 if (SUMA_StringToNum (s, (void*)fv3, 1,1) != 1) {/*problem, beep and ignore */
13960 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
13961 SUMA_RETURNe;
13962 }
13963
13964
13965
13966 /* Set the Faceselection */
13967 it = (int) fv3[0];
13968 if (!list) list = SUMA_CreateList ();
13969 ED = SUMA_InitializeEngineListData (SE_SetSelectedFaceSet);
13970 if (!SUMA_RegisterEngineListCommand ( list, ED,
13971 SEF_i, (void*)&it,
13972 SES_Suma, (void *)sv, NOPE,
13973 SEI_Head, NULL)) {
13974 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
13975 SUMA_RETURNe;
13976 }
13977
13978 /* call with the list */
13979 if (!SUMA_Engine (&list)) {
13980 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
13981 SUMA_RETURNe;
13982 }
13983
13984 /* redisplay curent only*/
13985 sv->ResetGLStateVariables = YUP;
13986 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
13987
13988 SUMA_RETURNe;
13989
13990 }
13991
13992 /*!
13993 \brief Highlight a set of nodes within a box
13994 \param s (char *) a string containing box center followed by box size (6 values)
13995 \param data (void *) a typecast of the pointer to the surface viewer to be affected
13996
13997 - operates by coloring nodes inside box.
13998 - coloring is not permanent and modifies other colors already present
13999 - operates on current viewer only
14000 */
SUMA_HighlightBox(char * s,void * data)14001 void SUMA_HighlightBox (char *s, void *data)
14002 {
14003 static char FuncName[]={"SUMA_HighlightBox"};
14004 DList *list=NULL;
14005 SUMA_EngineData *ED = NULL;
14006 SUMA_SurfaceViewer *sv = NULL;
14007 float fv15[15];
14008
14009 SUMA_ENTRY;
14010
14011 // fprintf(stderr, "%s\n", FuncName);
14012
14013 if (!s) SUMA_RETURNe;
14014
14015 sv = (SUMA_SurfaceViewer *)data;
14016
14017 /* parse s */
14018 if (SUMA_StringToNum (s, (void*)fv15, 6,1) != 6) {
14019 /*problem, beep and ignore */
14020 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
14021 SUMA_RETURNe;
14022 }
14023
14024 /* register fv15 with ED */
14025 if (!list) list = SUMA_CreateList();
14026 ED = SUMA_InitializeEngineListData (SE_HighlightNodes);
14027 if (!SUMA_RegisterEngineListCommand ( list, ED,
14028 SEF_fv15, (void*)fv15,
14029 SES_Suma, (void *)sv, NOPE,
14030 SEI_Head, NULL)) {
14031 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
14032 SUMA_RETURNe;
14033 }
14034
14035 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
14036
14037 if (!SUMA_Engine (&list)) {
14038 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
14039 }
14040
14041
14042 SUMA_RETURNe;
14043
14044 }
14045
14046
14047 /*** Begin - Drawing colored line ***
14048
14049 void Line(Vector3 start, Vector3 end) {
14050
14051 Vector3 startPoint = start;
14052 Vector3 endPoint = end;
14053 Vector3 lineColor = {1.0, 1.0, 1.0};
14054
14055 const char *vertexShaderSource = "#version 330 core\n"
14056 "layout (location = 0) in vec3 aPos;\n"
14057 "uniform mat4 MVP;\n"
14058 "void main()\n"
14059 "{\n"
14060 " gl_Position = MVP * vec4(aPos.x, aPos.y, aPos.z, 1.0);\n"
14061 "}\0";
14062 const char *fragmentShaderSource = "#version 330 core\n"
14063 "out vec4 FragColor;\n"
14064 "uniform vec3 color;\n"
14065 "void main()\n"
14066 "{\n"
14067 " FragColor = vec4(color, 1.0f);\n"
14068 "}\n\0";
14069
14070 // vertex shader
14071 int vertexShader = glCreateShader(GL_VERTEX_SHADER);
14072 glShaderSource(vertexShader, 1, &vertexShaderSource, NULL);
14073 glCompileShader(vertexShader);
14074 // check for shader compile errors
14075
14076 // fragment shader
14077 int fragmentShader = glCreateShader(GL_FRAGMENT_SHADER);
14078 glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL);
14079 glCompileShader(fragmentShader);
14080 // check for shader compile errors
14081
14082 // link shaders
14083 shaderProgram = glCreateProgram();
14084 glAttachShader(shaderProgram, vertexShader);
14085 glAttachShader(shaderProgram, fragmentShader);
14086 glLinkProgram(shaderProgram);
14087 // check for linking errors
14088
14089 glDeleteShader(vertexShader);
14090 glDeleteShader(fragmentShader);
14091
14092 vertices = {
14093 start.x, start.y, start.z,
14094 end.x, end.y, end.z,
14095
14096 };
14097
14098 glGenVertexArrays(1, &VAO);
14099 glGenBuffers(1, &VBO);
14100 glBindVertexArray(VAO);
14101
14102 glBindBuffer(GL_ARRAY_BUFFER, VBO);
14103 glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices.data(), GL_STATIC_DRAW);
14104
14105 glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
14106 glEnableVertexAttribArray(0);
14107
14108 glBindBuffer(GL_ARRAY_BUFFER, 0);
14109 glBindVertexArray(0);
14110
14111 }
14112
14113 int setMVP(mat4 mvp) {
14114 MVP = mvp;
14115 }
14116
14117 int setColor(vec3 color) {
14118 lineColor = color;
14119 }
14120
14121 int draw() {
14122 glUseProgram(shaderProgram);
14123 glUniformMatrix4fv(glGetUniformLocation(shaderProgram, "MVP"), 1, GL_FALSE, &MVP[0][0]);
14124 glUniform3fv(glGetUniformLocation(shaderProgram, "color"), 1, &lineColor[0]);
14125
14126 glBindVertexArray(VAO);
14127 glDrawArrays(GL_LINES, 0, 2);
14128 return 0;
14129 }
14130
14131 ~Line() {
14132
14133 glDeleteVertexArrays(1, &VAO);
14134 glDeleteBuffers(1, &VBO);
14135 glDeleteProgram(shaderProgram);
14136 }
14137
14138
14139 *** End - Drawing colored line ***/
14140
DrawCube(Display * dpy,Window win)14141 void DrawCube(Display *dpy, Window win){
14142
14143 float vertCoords[] = {
14144 0.5f, 0.5f, 0.5f, //V0
14145 -0.5f, 0.5f, 0.5f, //V1
14146 -0.5f, -0.5f, 0.5f, //V2
14147 0.5f, -0.5f, 0.5f, //V3
14148 0.5f, -0.5f, -0.5f, //V4
14149 0.5f, 0.5f, -0.5f, //V5
14150 -0.5f, 0.5f, -0.5f, //V6
14151 -0.5f, -0.5f, -0.5f //V7
14152 };
14153
14154 GLubyte indices[] = {
14155 0, 1, 2, 3, // Front face
14156 5, 0, 3, 4, // Right face
14157 5, 6, 7, 4, // Back face
14158 5, 6, 1, 0, // Upper face
14159 1, 6, 7, 2, // Left face
14160 7, 4, 3, 2 // Bottom face
14161 };
14162
14163 GLubyte colors[] = {
14164 255, 0, 0, //V0
14165 0, 255, 0, //V1
14166 0, 0, 255, //V2
14167 255, 255, 0, //V3
14168 0, 255, 255, //V4
14169 255, 0, 255, //V5
14170 255, 255, 255, //V6
14171 0, 0, 0, //V7
14172 };
14173 static int angle = 0;
14174 XWindowAttributes winattr;
14175 XGetWindowAttributes( dpy, win, &winattr);
14176 glViewport(0,0,winattr.width, winattr.height);
14177
14178 glClearColor(1.0f, 1.0f, 1.0f, 0.0f);
14179 glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
14180 glColor3f(0.0f, 0.9f, 1.0f);
14181
14182 glPushMatrix();
14183 glRotatef(angle, 0.5, 1.0, 0.0);
14184
14185 #if 0
14186 glBegin(GL_TRIANGLES);
14187 glVertex3f(0.0, -0.2f, 0.5f);
14188 glVertex3f(-0.5, 0.3, 0.5f);
14189 glVertex3f(0.5, 0.6f, 0.5f);
14190 glEnd();
14191 #endif
14192 glEnableClientState(GL_VERTEX_ARRAY);
14193 glEnableClientState(GL_COLOR_ARRAY);
14194 glColorPointer(3,GL_UNSIGNED_BYTE,0,colors);
14195 glVertexPointer(3,GL_FLOAT,0,vertCoords);
14196
14197 glDrawElements(GL_QUADS,24,GL_UNSIGNED_BYTE, indices);
14198
14199 glPopMatrix();
14200
14201 glXSwapBuffers(dpy, win);
14202
14203 usleep(5000);
14204
14205 angle += 1;
14206 }
14207
makeCube()14208 void makeCube(){
14209 int i;
14210 /*
14211 Display *dpy;
14212 static int screen;
14213 Window win, root_win;
14214 XEvent event;
14215
14216 // unsigned int depth;
14217 XSetWindowAttributes attrs;
14218
14219 XWindowAttributes winattr;
14220
14221 // GLX vars
14222 GLint att[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None};
14223 XVisualInfo *visual;
14224 GLXContext glc;
14225
14226 if (!(dpy = XOpenDisplay(NULL))){
14227 fprintf(stderr, "Cannot open display\n");
14228 exit(1);
14229 }
14230
14231 screen = DefaultScreen(dpy);
14232
14233 int depth = DefaultDepth(dpy, screen);
14234
14235 root_win = RootWindow(dpy, screen); // Program crashes
14236
14237 visual = glXChooseVisual(dpy, screen, att);
14238
14239 attrs.border_pixel = BlackPixel(dpy, screen);
14240 attrs.background_pixel = WhitePixel(dpy, screen);
14241 attrs.override_redirect = True;
14242
14243 // attrs.colormap = CopyFromParent;
14244 attrs.colormap = XCreateColormap(dpy, root_win, visual->visual, AllocNone);
14245 attrs.event_mask = ExposureMask | KeyPressMask | PointerMotionMask | ButtonPress;
14246 // Note the PointerMotionMask is necessary for the MotionNotify event
14247 // to be seen
14248
14249 // Parent window
14250 win = XCreateWindow(dpy, root_win,
14251 200, 200, 500, 300,
14252 0, visual->depth, InputOutput, visual->visual,
14253 CWBackPixel | CWColormap | CWBorderPixel |
14254 CWEventMask, &attrs);
14255
14256 XMapWindow(dpy, win);
14257
14258 // Get current window
14259 Display * currentDisplay = glXGetCurrentDisplay();
14260 GLXContext currentContext = glXGetCurrentContext();
14261 Window focused;
14262 int revert_to;
14263 XGetInputFocus(currentDisplay, &focused, &revert_to);
14264
14265 glc = glXCreateContext(dpy, visual, NULL, GL_TRUE);
14266
14267 // glXMakeCurrent(dpy, win, glc);
14268 glXMakeCurrent(currentDisplay, focused, currentContext);
14269
14270 glEnable(GL_DEPTH_TEST);
14271
14272 glEnable(GL_LINE_SMOOTH); // fOR LINE formatting (Makes line thicker)
14273
14274 glEnable(GL_LINE_STIPPLE);
14275
14276 for (i=0; i<5; ++i)
14277 DrawCube(currentDisplay, focused);
14278 // DrawCube(dpy, win);
14279 */
14280 static int screen;
14281 Window win, root_win;
14282
14283 // GLX vars
14284 GLint att[] = {GLX_RGBA, GLX_DEPTH_SIZE, 24, GLX_DOUBLEBUFFER, None};
14285 XVisualInfo *visual;
14286 GLXContext glc;
14287
14288 // For pointer position
14289 Window root_return, child_return;
14290 int root_x_return, root_y_return;
14291 int win_x_return, win_y_return;
14292 unsigned int mask_return;
14293 XSetWindowAttributes attrs;
14294
14295 // Get current window
14296 Display * currentDisplay = glXGetCurrentDisplay();
14297 GLXContext currentContext = glXGetCurrentContext();
14298 Window focused;
14299 int revert_to;
14300 XGetInputFocus(currentDisplay, &focused, &revert_to);
14301
14302 screen = DefaultScreen(currentDisplay);
14303
14304 int depth = DefaultDepth(currentDisplay, screen);
14305
14306 root_win = RootWindow(currentDisplay, screen); // Program crashes
14307
14308 visual = glXChooseVisual(currentDisplay, screen, att);
14309
14310 attrs.border_pixel = BlackPixel(currentDisplay, screen);
14311 attrs.background_pixel = WhitePixel(currentDisplay, screen);
14312 attrs.override_redirect = True;
14313 attrs.colormap = XCreateColormap(currentDisplay, root_win, visual->visual, AllocNone);
14314 attrs.event_mask = ExposureMask | KeyPressMask | PointerMotionMask | ButtonPress;
14315
14316 glc = glXCreateContext(currentDisplay, visual, NULL, GL_TRUE);
14317
14318 // glXMakeCurrent(dpy, win, glc);
14319 glXMakeCurrent(currentDisplay, focused, currentContext);
14320
14321 glEnable(GL_DEPTH_TEST);
14322
14323 glEnable(GL_LINE_SMOOTH); // fOR LINE formatting (Makes line thicker)
14324
14325 glEnable(GL_LINE_STIPPLE);
14326
14327 for (i=0; i<5; ++i)
14328 DrawCube(currentDisplay, focused);
14329
14330
14331 }
14332