1 #include "SUMA_suma.h"
2 #include "SUMA_plot.h"
3
4 /*!
5 Return the code for the key that is specified in keyin
6 */
SUMA_KeyPress(char * keyin,char * keynameback)7 int SUMA_KeyPress(char *keyin, char *keynameback)
8 {
9 static char FuncName[]={"SUMA_KeyPress"};
10 int nk=0,i=0,nc=0;
11 char keyname[100];
12 char *key=NULL, c='\0';
13 SUMA_Boolean LocalHead = NOPE;
14
15 SUMA_ENTRY;
16
17 if (keynameback) keynameback[0]='\0';
18 keyname[0]='\0';
19
20 if (!keyin) SUMA_RETURN(XK_VoidSymbol);
21 nc = strlen(keyin);
22 if (nc<=0) SUMA_RETURN(XK_VoidSymbol);
23
24 key = SUMA_append_string("+",keyin); /* add a + to simplify parsing */
25
26 nc = strlen(key);
27 SUMA_LHv("Key now '%s'\n", key);
28
29 /* find the last + */
30 i = nc-2; /* skip last char, might itself be + */
31 while (i >= 0 && key[i] != '+') { --i; } ++i; /* reposition past last + */
32
33 /* copy the rest into keyname */
34 nk=0;
35 while (i<nc && nk < 10) {
36 keyname[nk] = key[i];
37 ++i;
38 ++nk;
39 }
40 keyname[nk] = '\0';
41 if (nk > 10 || nk == 0) {
42 SUMA_S_Errv("What kind of key is %s!!!\n", key);
43 SUMA_RETURN(XK_VoidSymbol);
44 }
45 SUMA_LHv("Keyname now '%s'\n", keyname);
46 if (keynameback) sprintf(keynameback,"%s", keyname);
47
48 if (nk == 1) { /* the simple case, add them as needed */
49 c = keyname[0];
50 SUMA_LHv("c now '%c'\n", c);
51 switch(c) {
52 case 'a':
53 SUMA_RETURN(XK_a);
54 case 'A':
55 SUMA_RETURN(XK_A);
56 case 'b':
57 SUMA_RETURN(XK_b);
58 case 'B':
59 SUMA_RETURN(XK_B);
60 case 'd':
61 SUMA_RETURN(XK_d);
62 case 'D':
63 SUMA_RETURN(XK_D);
64 case 'g':
65 SUMA_RETURN(XK_g);
66 case 'G':
67 SUMA_RETURN(XK_G);
68 case 'j':
69 SUMA_RETURN(XK_j);
70 case 'J':
71 SUMA_RETURN(XK_J);
72 case 'l':
73 SUMA_RETURN(XK_l);
74 case 'L':
75 SUMA_RETURN(XK_L);
76 case 'm':
77 SUMA_RETURN(XK_m);
78 case 'M':
79 SUMA_RETURN(XK_M);
80 case 'n':
81 SUMA_RETURN(XK_n);
82 case 'N':
83 SUMA_RETURN(XK_N);
84 case 'o':
85 SUMA_RETURN(XK_o);
86 case 'O':
87 SUMA_RETURN(XK_O);
88 case 'p':
89 SUMA_RETURN(XK_p);
90 case 'P':
91 SUMA_RETURN(XK_P);
92 case 'r':
93 SUMA_RETURN(XK_r);
94 case 'R':
95 SUMA_RETURN(XK_R);
96 case 't':
97 SUMA_RETURN(XK_t);
98 case 'T':
99 SUMA_RETURN(XK_T);
100 case 'u':
101 SUMA_RETURN(XK_u);
102 case 'U':
103 SUMA_RETURN(XK_U);
104 case 'w':
105 SUMA_RETURN(XK_w);
106 case 'W':
107 SUMA_RETURN(XK_W);
108 case 'z':
109 SUMA_RETURN(XK_z);
110 case 'Z':
111 SUMA_RETURN(XK_Z);
112 case '[':
113 SUMA_RETURN(XK_bracketleft);
114 case ']':
115 SUMA_RETURN(XK_bracketright);
116 case '.':
117 if (keynameback) sprintf(keynameback,"period");
118 SUMA_RETURN(XK_period);
119 case ' ':
120 if (keynameback) sprintf(keynameback,"space");
121 SUMA_RETURN(XK_space);
122 case ',':
123 if (keynameback) sprintf(keynameback,"comma");
124 SUMA_RETURN(XK_comma);
125 default:
126 SUMA_S_Errv("Key '%c' not yet supported, complain to author.\n", c);
127 SUMA_RETURN(XK_VoidSymbol);
128 }
129 } else {
130 if (SUMA_iswordsame_ci(keyname,"up") == 1) SUMA_RETURN(XK_Up);
131 if (SUMA_iswordsame_ci(keyname,"down") == 1) SUMA_RETURN(XK_Down);
132 if (SUMA_iswordsame_ci(keyname,"left") == 1) SUMA_RETURN(XK_Left);
133 if (SUMA_iswordsame_ci(keyname,"right") == 1) SUMA_RETURN(XK_Right);
134 if (SUMA_iswordsame_ci(keyname,"space") == 1) SUMA_RETURN(XK_space);
135 if (SUMA_iswordsame_ci(keyname,"period") == 1) SUMA_RETURN(XK_period);
136 if (SUMA_iswordsame_ci(keyname,"comma") == 1) SUMA_RETURN(XK_comma);
137 if (SUMA_iswordsame_ci(keyname,"f1") == 1) SUMA_RETURN(XK_F1);
138 if (SUMA_iswordsame_ci(keyname,"f2") == 1) SUMA_RETURN(XK_F2);
139 if (SUMA_iswordsame_ci(keyname,"f3") == 1) SUMA_RETURN(XK_F3);
140 if (SUMA_iswordsame_ci(keyname,"f4") == 1) SUMA_RETURN(XK_F4);
141 if (SUMA_iswordsame_ci(keyname,"f5") == 1) SUMA_RETURN(XK_F5);
142 if (SUMA_iswordsame_ci(keyname,"f6") == 1) SUMA_RETURN(XK_F6);
143 if (SUMA_iswordsame_ci(keyname,"f7") == 1) SUMA_RETURN(XK_F7);
144 if (SUMA_iswordsame_ci(keyname,"f8") == 1) SUMA_RETURN(XK_F8);
145 if (SUMA_iswordsame_ci(keyname,"f9") == 1) SUMA_RETURN(XK_F9);
146 if (SUMA_iswordsame_ci(keyname,"f10") == 1) SUMA_RETURN(XK_F10);
147 if (SUMA_iswordsame_ci(keyname,"f11") == 1) SUMA_RETURN(XK_F11);
148 if (SUMA_iswordsame_ci(keyname,"f12") == 1) SUMA_RETURN(XK_F12);
149
150 SUMA_S_Errv("Key '%s' not yet supported, complain to author.\n", keyname);
151 SUMA_RETURN(XK_VoidSymbol);
152 }
153 SUMA_RETURN(XK_VoidSymbol);
154 }
155
156 #define SUMA_KEY_COMMON { \
157 if (!sv || !key) { \
158 SUMA_S_Err("Null input"); \
159 SUMA_RETURN(0); \
160 } \
161 if (!(nc = strlen(key))) { \
162 SUMA_S_Err("Empty key"); \
163 SUMA_RETURN(0); \
164 } \
165 \
166 SUMA_LHv("Have %s, nc=%d\n", key, nc); \
167 if ((k = SUMA_KeyPress(key, keyname)) == XK_VoidSymbol) { \
168 SUMA_S_Errv("KeyPress for %s could not be obtained.\n", key); \
169 SUMA_RETURN(0); \
170 } \
171 SUMA_LHv("Have keyname = %s\n", keyname); \
172 if (SUMA_iswordsame_ci(keyname,tk) != 1) { \
173 SUMA_S_Errv("Expecting %s (or lower case version), got %s\n", \
174 tk, keyname ); \
175 SUMA_RETURN(0); \
176 } \
177 }
178
179 #define SUMA_KEY_SWITCH { \
180 /* Check for key switching */ \
181 if (sv->State && strstr(sv->State, "GMATRIX")==sv->State) { \
182 if (SUMA_SHIFT_KEY(key)) { \
183 strncpy(skeyi, key, 63); skeyi[64]='\0'; \
184 SUMA_wordswap_ci(skeyi, "shift", "", skey); \
185 } else \
186 snprintf(skey,63,"shift%s",key); \
187 key = skey; \
188 } \
189 }
190
191
192 #if 0 /* a template to use for various keys , replace CHAR by upper case char and cHaR by lower case*/
193 int SUMA_CHAR_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
194 {
195 static char FuncName[]={"SUMA_CHAR_Key"};
196 char tk[]={"CHAR"}, keyname[100];
197 int k, nc;
198 SUMA_Boolean LocalHead = NOPE;
199
200 SUMA_ENTRY;
201
202 SUMA_KEY_COMMON;
203
204 /* do the work */
205 switch (k) {
206 case XK_CHAR:
207 break;
208 case XK_cHaR:
209 break;
210 default:
211 SUMA_S_Err("Il ne faut pas ci dessous");
212 SUMA_RETURN(0);
213 break;
214 }
215
216 SUMA_RETURN(1);
217 }
218 #endif
219
220 static int Nwarn_bracket = 0;
221
SUMA_bracketleft_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)222 int SUMA_bracketleft_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
223 {
224 static char FuncName[]={"SUMA_bracketleft_Key"};
225 char tk[]={"["}, keyname[100];
226 int k, nc;
227 char stmp[200];
228 SUMA_Boolean LocalHead = NOPE;
229
230 SUMA_ENTRY;
231
232 SUMA_KEY_COMMON;
233
234 /* do the work */
235 switch (k) {
236 case XK_bracketleft:
237 /* getting rid of some warnings that happen with normal use */
238 Nwarn_bracket = 1; /* warning always in terminal, no message to window */
239 /* toggle showing left hemispheres */
240 sv->ShowLeft = !sv->ShowLeft;
241 /* do the axis setup */
242 SUMA_WorldAxisStandard (sv->WAx, sv);
243 SUMA_UpdateViewerTitle(sv);
244 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
245 if (sv->ShowLeft) {
246 sprintf(stmp,"Showing Left side%s",
247 Nwarn_bracket ?
248 "":"\nFurther notices for '[' or ']' keys will be echoed in the shell");
249 } else {
250 sprintf(stmp,"Hiding Left side%s",
251 Nwarn_bracket > 1 ?
252 "":"\nFurther notices for '[' or ']' keys will be echoed in the shell");
253 }
254 if (!Nwarn_bracket && callmode &&
255 strcmp(callmode, "interactive") == 0) {
256 SUMA_SLP_Note("%s",stmp);
257 } else { SUMA_S_Note("%s",stmp); }
258 /* ++Nwarn_bracket;*/
259 break;
260 default:
261 SUMA_S_Err("Il ne faut pas etre la");
262 SUMA_RETURN(0);
263 break;
264 }
265
266 SUMA_RETURN(1);
267 }
268
SUMA_bracketright_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)269 int SUMA_bracketright_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
270 {
271 static char FuncName[]={"SUMA_bracketright_Key"};
272 char tk[]={"]"}, keyname[100];
273 int k, nc;
274 char stmp[200];
275 SUMA_Boolean LocalHead = NOPE;
276
277 SUMA_ENTRY;
278
279 SUMA_KEY_COMMON;
280
281 /* do the work */
282 switch (k) {
283 case XK_bracketright:
284 /* getting rid of some warnings that happen with normal use */
285 Nwarn_bracket = 1; /* warning always in terminal, no message to window */
286 /* toggle showing left hemispheres */
287 sv->ShowRight = !sv->ShowRight;
288 /* do the axis setup */
289 SUMA_WorldAxisStandard (sv->WAx, sv);
290 SUMA_UpdateViewerTitle(sv);
291 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
292 if (sv->ShowRight) {
293 sprintf(stmp,"Showing Right side%s",
294 Nwarn_bracket ?
295 "":"\nFurther notices for '[' or ']' key will be in the shell");
296 } else {
297 sprintf(stmp,"Hiding right side%s",
298 Nwarn_bracket ?
299 "":"\nFurther notices for '[' or ']' key will be in the shell");
300 }
301 if (!Nwarn_bracket && callmode &&
302 strcmp(callmode, "interactive") == 0) {
303 SUMA_SLP_Note("%s",stmp);
304 } else { SUMA_S_Note("%s",stmp); }
305 /* ++Nwarn_bracket;*/
306 break;
307 default:
308 SUMA_S_Err("Il ne faut pas etre la");
309 SUMA_RETURN(0);
310 break;
311 }
312
313 SUMA_RETURN(1);
314 }
315
SUMA_space_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)316 int SUMA_space_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
317 {
318 static char FuncName[]={"SUMA_space_Key"};
319 char tk[]={"SPACE"}, keyname[100];
320 int k, nc;
321 int nxtstateID=-1, curstateID = -1;
322 int origState = -1, dov_ID = -1;
323 SUMA_SurfaceObject *SO = NULL, *SOmap = NULL;
324 SUMA_Boolean LocalHead = NOPE;
325
326 SUMA_ENTRY;
327
328
329 SUMA_KEY_COMMON;
330
331 origState = sv->iState;
332
333 /* do the work */
334 switch (k) {
335 case XK_space:
336 /* toggle between state containing mapping reference
337 of SO in focus and other view */
338
339 /* make sure switching is OK */
340 curstateID = SUMA_WhichState(sv->State, sv, sv->CurGroupName);
341 if ((SO = SUMA_SV_Focus_SO(sv))) { /* have something to work with */
342 if (SUMA_isLocalDomainParent (SO)) {
343 /* get the last non mappable state in SV */
344 if (sv->LastNonMapStateID < 0) {
345 /* not recorded, complain and quit */
346 fprintf(SUMA_STDERR,
347 "Warning %s: Nothing defined to toggle with yet.\n",
348 FuncName);
349 break;
350 }
351
352 if (LocalHead)
353 fprintf (SUMA_STDERR,
354 "%s: surface is inherrently mappable, "
355 "switching to last non mappable state %d.\n",
356 FuncName, sv->LastNonMapStateID);
357
358 if (!SUMA_SwitchState ( SUMAg_DOv, SUMAg_N_DOv, sv,
359 sv->LastNonMapStateID, sv->CurGroupName)) {
360 fprintf( SUMA_STDERR,
361 "Error %s: Failed in SUMA_SwitchState.\n", FuncName);
362 break;
363 }
364
365 } else {/* that's a non mappable, go to state containing reference */
366 if (LocalHead)
367 fprintf (SUMA_STDERR,
368 "%s: surface is not inherrently mappable, "
369 "searching for mapping reference and its state.\n",
370 FuncName);
371
372 /* find SO that is mappable reference & get its state ID*/
373 dov_ID = SUMA_findSO_inDOv(SO->LocalDomainParentID, SUMAg_DOv,
374 SUMAg_N_DOv);
375 SOmap = (SUMA_SurfaceObject *)SUMAg_DOv[dov_ID].OP;
376 nxtstateID = SUMA_WhichState(SOmap->State, sv, sv->CurGroupName);
377
378 if (nxtstateID < 0) {
379 fprintf (SUMA_STDERR,
380 "%s: Failed in SUMA_findSO_inDOv "
381 "This should not happen.\n", FuncName);
382 break;
383 }
384
385 if (LocalHead)
386 fprintf (SUMA_STDERR,
387 "%s: Found mapping reference in viewer state %d.\n",
388 FuncName, nxtstateID);
389
390 /* store this location */
391 sv->LastNonMapStateID = curstateID;
392
393 /* go there */
394 if (!SUMA_SwitchState ( SUMAg_DOv, SUMAg_N_DOv, sv,
395 nxtstateID, sv->CurGroupName)) {
396 fprintf( SUMA_STDERR,
397 "Error %s: Failed in SUMA_SwitchState.\n",
398 FuncName);
399 break;
400 }
401 }
402
403 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
404 } else {
405 SUMA_LH("No surfaces in this state, space bar ignored");
406 }
407 break;
408 default:
409 SUMA_S_Err("Il ne faut pas etre la");
410 SUMA_RETURN(0);
411 break;
412 }
413
414 SUMA_RETURN(1);
415 }
416
SUMA_comma_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)417 int SUMA_comma_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
418 {
419 static char FuncName[]={"SUMA_comma_Key"};
420 char tk[]={"COMMA"}, keyname[100], stmp[256];
421 int k, nc, ii;
422 int nxtstateID=-1, curstateID = -1;
423 int origState = -1;
424 char *note=NULL;
425 DList *list=NULL;
426 SUMA_Boolean LocalHead = NOPE;
427
428 SUMA_ENTRY;
429
430 SUMA_KEY_COMMON;
431
432 origState = sv->iState;
433
434 /* do the work */
435 switch (k) {
436 case XK_comma:
437 /* switch state, back one */
438 if (sv->N_VSv < 2) break;
439
440 curstateID = SUMA_WhichState (sv->State, sv, sv->CurGroupName);
441 if (curstateID < 0) {
442 SUMA_SL_Err("Current State not found.\n"
443 "Should not happen here.");
444 SUMA_RETURN(0);
445 }
446
447 if (SUMAg_N_SVv > 1) {
448 ii = SUMA_WhichViewerInMomentum (SUMAg_SVv, SUMAg_N_SVv, sv);
449 if (ii >= 0) {
450 sprintf (stmp, "You cannot switch states while other viewers\n"
451 "(like viewer %c) in momentum mode.\n", ii+65);
452 SUMA_RegisterMessage (SUMAg_CF->MessageList,
453 stmp, FuncName, SMT_Error, SMA_LogAndPopup);
454 SUMA_RETURN(0);
455 }
456 }
457
458 do {
459 if (LocalHead && nxtstateID > -1) {
460 note = SUMA_append_string("Skipping state ",sv->State);
461 note = SUMA_append_replace_string(note,
462 ".\nNo surfaces visible.", "", 1);
463 SUMA_SLP_Note("%s",note);
464 SUMA_free(note); note = NULL;
465 }
466
467 /*fprintf(SUMA_STDERR,"%s: Current viewing state is %s ...\n",
468 FuncName, sv->State);*/
469 /* toggle to the next view state */
470 nxtstateID = SUMA_PrevState(sv);
471 if (nxtstateID == curstateID) break;
472 if (nxtstateID < 0) {
473 fprintf(SUMA_STDERR,
474 "Error %s: Failed in SUMA_PrevState.\n", FuncName);
475 break;
476 }
477 fprintf( SUMA_STDERR,"%s: Switching from %s to %s viewing state.\n",
478 FuncName, sv->State, sv->VSv[nxtstateID].Name);
479
480 if (!SUMA_SwitchState ( SUMAg_DOv, SUMAg_N_DOv, sv,
481 nxtstateID, sv->CurGroupName)) {
482 fprintf( SUMA_STDERR,
483 "Error %s: Failed in SUMA_SwitchState.\n", FuncName);
484 break;
485 }
486
487 /* find out if there are any surfaces that will be rendered */
488
489 } while (!SUMA_Selectable_ADOs (sv, SUMAg_DOv, NULL) &&
490 sv->iState != origState);
491
492 /* register a call to redisplay
493 (you also need to copy the color data,
494 in case the next surface is of the same family)*/
495 if (!list) list = SUMA_CreateList();
496 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
497 if (!SUMA_Engine (&list)) {
498 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
499 }
500
501 /* update titles */
502 SUMA_UpdateViewerTitle(sv);
503 break;
504 default:
505 SUMA_S_Err("Il ne faut pas etre la");
506 SUMA_RETURN(0);
507 break;
508 }
509
510 SUMA_RETURN(1);
511 }
512
SUMA_period_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)513 int SUMA_period_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
514 {
515 static char FuncName[]={"SUMA_period_Key"};
516 char tk[]={"PERIOD"}, keyname[100], stmp[256];
517 int k, nc, ii;
518 int nxtstateID=-1, curstateID = -1;
519 int origState = -1;
520 char *note=NULL;
521 DList *list=NULL;
522 SUMA_Boolean LocalHead = NOPE;
523
524 SUMA_ENTRY;
525
526 SUMA_KEY_COMMON;
527
528 origState = sv->iState;
529
530 /* do the work */
531 switch (k) {
532 case XK_period:
533 /* switch state, forward one */
534 if (sv->N_VSv < 2) break;
535
536 curstateID = SUMA_WhichState (sv->State, sv, sv->CurGroupName);
537 if (curstateID < 0) {
538 SUMA_SL_Err("Current State not found.\n"
539 "Should not happen here.");
540 SUMA_RETURN(0);
541 }
542
543 if (SUMAg_N_SVv > 1) {
544 ii = SUMA_WhichViewerInMomentum (SUMAg_SVv, SUMAg_N_SVv, sv);
545 if (ii >= 0) {
546 sprintf (stmp, "You cannot switch states while other viewers\n"
547 "(like viewer %c) are in momentum mode.\n", ii+65);
548 SUMA_RegisterMessage (SUMAg_CF->MessageList,
549 stmp, FuncName, SMT_Error, SMA_LogAndPopup);
550 SUMA_RETURN(0);
551 }
552 }
553
554 do {
555 if (LocalHead && nxtstateID > -1) {
556 note = SUMA_append_string("Skipping state ",sv->State);
557 note = SUMA_append_replace_string(note,
558 ".\nNo surfaces visible.", "", 1);
559 SUMA_SLP_Note("%s",note);
560 SUMA_free(note); note = NULL;
561 }
562
563 if (LocalHead)
564 fprintf(SUMA_STDERR,"%s: Current viewing state is %s ...\n",
565 FuncName, sv->State);
566
567 /* toggle to the next view state */
568 nxtstateID = SUMA_NextState(sv);
569 if (nxtstateID == curstateID) break;
570 if (nxtstateID < 0) {
571 fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_NextState.\n",
572 FuncName);
573 break;
574 }
575
576 fprintf( SUMA_STDERR,
577 "%s: Switching from %s to %s viewing state.\n",
578 FuncName, sv->State, sv->VSv[nxtstateID].Name);
579
580 if (!SUMA_SwitchState ( SUMAg_DOv, SUMAg_N_DOv, sv,
581 nxtstateID, sv->CurGroupName)) {
582 fprintf( SUMA_STDERR,
583 "Error %s: Failed in SUMA_SwitchState.\n", FuncName);
584 break;
585 }
586 SUMA_SET_AS_NEEDED_2D_VIEW_ANGLE(sv);
587
588 } while (!SUMA_Selectable_ADOs(sv, SUMAg_DOv, NULL) &&
589 sv->iState != origState);
590 /* register a call to redisplay
591 (you also need to copy the color data, in case the next surface
592 is of the same family)*/
593 if (!list) list = SUMA_CreateList();
594 SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_Redisplay,
595 SES_Suma, sv);
596 if (!SUMA_Engine (&list)) {
597 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n",
598 FuncName);
599 }
600
601 /* update titles */
602 SUMA_UpdateViewerTitle(sv);
603 break;
604 default:
605 SUMA_S_Err("Il ne faut pas etre la");
606 SUMA_RETURN(0);
607 break;
608 }
609
610 SUMA_RETURN(1);
611 }
612
SUMA_F1_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)613 int SUMA_F1_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
614 {
615 static char FuncName[]={"SUMA_F1_Key"};
616 char tk[]={"F1"}, keyname[100];
617 int k, nc;
618 SUMA_Boolean LocalHead = NOPE;
619
620 SUMA_ENTRY;
621
622 SUMA_KEY_COMMON;
623
624 /* do the work */
625 switch (k) {
626 case XK_F1:
627 sv->ShowEyeAxis = !sv->ShowEyeAxis;
628 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
629 break;
630 default:
631 SUMA_S_Err("Il ne faut pas etre la");
632 SUMA_RETURN(0);
633 break;
634 }
635
636 SUMA_RETURN(1);
637 }
638
SUMA_F2_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)639 int SUMA_F2_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
640 {
641 static char FuncName[]={"SUMA_F2_Key"};
642 char tk[]={"F2"}, keyname[100];
643 int k, nc;
644 SUMA_Boolean LocalHead = NOPE;
645
646 SUMA_ENTRY;
647
648 SUMA_KEY_COMMON;
649
650 /* do the work */
651 switch (k) {
652 case XK_F2:
653 {
654 int *do_id, n_do_id;
655 ++sv->ShowWorldAxis;
656 sv->ShowWorldAxis = sv->ShowWorldAxis % SUMA_N_WAX_OPTIONS;
657 sv->ShowMeshAxis = 0;
658 /* used to be = !sv->ShowMeshAxis; ,
659 Turned off Oct 15 04 , in favor or WorldAxis */
660 do_id = SUMA_GetDO_Type(SUMAg_DOv, SUMAg_N_DOv, SO_type, &n_do_id);
661 if (n_do_id) {
662 while (n_do_id) {
663 ((SUMA_SurfaceObject *)
664 SUMAg_DOv[do_id[n_do_id-1]].OP)->ShowMeshAxis =
665 sv->ShowMeshAxis;
666 --n_do_id;
667 }
668 SUMA_free(do_id);
669 }
670 }
671 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
672 break;
673 default:
674 SUMA_S_Err("Il ne faut pas etre la haut");
675 SUMA_RETURN(0);
676 break;
677 }
678
679 SUMA_RETURN(1);
680 }
681
SUMA_F3_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)682 int SUMA_F3_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
683 {
684 static char FuncName[]={"SUMA_F3_Key"};
685 char tk[]={"F3"}, keyname[100];
686 int k, nc;
687 SUMA_EngineData *ED = NULL;
688 DList *list = NULL;
689 SUMA_Boolean LocalHead = NOPE;
690
691 SUMA_ENTRY;
692
693 SUMA_KEY_COMMON;
694
695 /* do the work */
696 switch (k) {
697 case XK_F3:
698 if (!list) list = SUMA_CreateList();
699 SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_ToggleCrossHair,
700 SES_Suma, sv);
701 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
702 if (!SUMA_Engine (&list)) {
703 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
704 }
705 break;
706 default:
707 SUMA_S_Err("Il ne faut pas etre over here");
708 SUMA_RETURN(0);
709 break;
710 }
711
712 SUMA_RETURN(1);
713 }
714
SUMA_F4_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)715 int SUMA_F4_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
716 {
717 static char FuncName[]={"SUMA_F4_Key"};
718 char tk[]={"F4"}, keyname[100];
719 int k, nc;
720 SUMA_EngineData *ED = NULL;
721 DList *list = NULL;
722 DListElmt *NextElm= NULL;
723 SUMA_Boolean LocalHead = NOPE;
724
725 SUMA_ENTRY;
726
727 SUMA_KEY_COMMON;
728
729 /* do the work */
730 switch (k) {
731 case XK_F4:
732 if (!list) list = SUMA_CreateList();
733 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_ToggleShowSelectedNode,
734 SES_Suma, sv);
735 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
736 if (!SUMA_Engine (&list)) {
737 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
738 }
739 break;
740 default:
741 SUMA_S_Err("Il ne faut pas etre over dort");
742 SUMA_RETURN(0);
743 break;
744 }
745
746 SUMA_RETURN(1);
747 }
748
SUMA_F5_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)749 int SUMA_F5_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
750 {
751 static char FuncName[]={"SUMA_F5_Key"};
752 char tk[]={"F5"}, keyname[100];
753 int k, nc;
754 SUMA_EngineData *ED = NULL;
755 DList *list = NULL;
756 DListElmt *NextElm= NULL;
757 SUMA_Boolean LocalHead = NOPE;
758
759 SUMA_ENTRY;
760
761 SUMA_KEY_COMMON;
762
763 /* do the work */
764 switch (k) {
765 case XK_F5:
766 if (!list) list = SUMA_CreateList();
767 SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_ToggleShowSelectedFaceSet,
768 SES_Suma, sv);
769 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
770 if (!SUMA_Engine (&list)) {
771 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
772 }
773 break;
774 default:
775 SUMA_S_Err("Il ne faut pas etre over dort");
776 SUMA_RETURN(0);
777 break;
778 }
779
780 SUMA_RETURN(1);
781 }
782
SUMA_F6_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)783 int SUMA_F6_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
784 {
785 static char FuncName[]={"SUMA_F6_Key"};
786 char tk[]={"F6"}, keyname[100];
787 int k, nc;
788 SUMA_EngineData *ED = NULL;
789 DList *list = NULL;
790 DListElmt *NextElm= NULL;
791 SUMA_Boolean LocalHead = NOPE;
792
793 SUMA_ENTRY;
794
795 SUMA_KEY_COMMON;
796
797 /* do the work */
798 switch (k) {
799 case XK_F6:
800 sv->clear_color[0] = 1 - sv->clear_color[0];
801 sv->clear_color[1] = 1 - sv->clear_color[1];
802 sv->clear_color[2] = 1 - sv->clear_color[2];
803
804 SUMA_UpdateCrossHairNodeLabelField(sv);
805 if (!list) list = SUMA_CreateList();
806 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
807 if (!SUMA_Engine (&list)) {
808 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
809 }
810 break;
811 default:
812 SUMA_S_Err("Il ne faut pas etre over dere");
813 SUMA_RETURN(0);
814 break;
815 }
816
817 SUMA_RETURN(1);
818 }
SUMA_F7_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)819 int SUMA_F7_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
820 {
821 static char FuncName[]={"SUMA_F7_Key"};
822 char tk[]={"F7"}, keyname[100];
823 int k, nc;
824 SUMA_EngineData *ED = NULL;
825 DList *list = NULL;
826 DListElmt *NextElm= NULL;
827 SUMA_Boolean LocalHead = NOPE;
828
829 SUMA_ENTRY;
830
831 SUMA_KEY_COMMON;
832
833 /* do the work */
834 switch (k) {
835 case XK_F7:
836 ++SUMAg_CF->ColMixMode;
837 if (SUMAg_CF->ColMixMode >= SUMA_MAX_MODES) {
838 SUMAg_CF->ColMixMode = SUMA_ORIG_MIX_MODE;
839 }
840 {
841 char stmp[200];
842 sprintf(stmp,"Using %s color mixing mode.",
843 SUMA_ColMixModeString(SUMAg_CF->ColMixMode));
844 if (callmode && strcmp(callmode, "interactive") == 0) {
845 SUMA_SLP_Note("%s",stmp); }
846 else { SUMA_S_Note("%s",stmp); }
847 }
848
849 SUMA_SetAllRemixFlag (SUMAg_SVv, SUMAg_N_SVv);
850
851 if (!list) list = SUMA_CreateList();
852 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay_AllVisible,
853 SES_Suma, NULL);
854 if (!SUMA_Engine (&list)) {
855 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
856 }
857 break;
858 default:
859 SUMA_S_Err("Il ne faut pas etre over yonder");
860 SUMA_RETURN(0);
861 break;
862 }
863
864 SUMA_RETURN(1);
865 }
866
SUMA_F8_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)867 int SUMA_F8_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
868 {
869 static char FuncName[]={"SUMA_F8_Key"};
870 char tk[]={"F8"}, keyname[100];
871 int k, nc;
872 SUMA_EngineData *ED = NULL;
873 DList *list = NULL;
874 DListElmt *NextElm= NULL;
875 SUMA_Boolean LocalHead = NOPE;
876
877 SUMA_ENTRY;
878
879 SUMA_KEY_COMMON;
880
881 /* do the work */
882 switch (k) {
883 case XK_F8:
884 sv->ortho = !sv->ortho;
885 {
886 static int inote = 0;
887 char stmp[200];
888 if (sv->ortho) {
889 sprintf(stmp,"Using orthographic projection viewing");
890 sv->FOV[sv->iState] = sv->FOV[sv->iState] / 2.0;
891 } else {
892 sprintf(stmp,"Using perspective viewing");
893 sv->FOV[sv->iState] = sv->FOV[sv->iState] * 2.0;
894 }
895 ++inote;
896 if (callmode && strcmp(callmode, "interactive") == 0 && inote < 3) {
897 SUMA_SLP_Note("%s",stmp); }
898 else { SUMA_S_Note("%s",stmp); }
899 }
900
901 SUMA_SET_GL_PROJECTION(sv, sv->ortho);
902 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
903 break;
904 default:
905 SUMA_S_Err("Il ne faut pas etre over yonder");
906 SUMA_RETURN(0);
907 break;
908 }
909
910 SUMA_RETURN(1);
911 }
912
SUMA_F9_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)913 int SUMA_F9_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
914 {
915 static char FuncName[]={"SUMA_F9_Key"};
916 char tk[]={"F9"}, keyname[100];
917 int k, nc;
918 SUMA_EngineData *ED = NULL;
919 DList *list = NULL;
920 DListElmt *NextElm= NULL;
921 static int inote = 0;
922 SUMA_Boolean LocalHead = NOPE;
923
924 SUMA_ENTRY;
925
926 SUMA_KEY_COMMON;
927
928 /* do the work */
929 switch (k) {
930 case XK_F9:
931 sv->ShowLabelAtXhair = !sv->ShowLabelAtXhair;
932 SUMA_UpdateCrossHairNodeLabelField(sv);
933 {
934 char stmp[200];
935 if (sv->ShowLabelAtXhair) {
936 sprintf(stmp,"Showing Label At Xhair");
937 } else {
938 sprintf(stmp,"Hiding Label At Xhair");
939 }
940 if (callmode && strcmp(callmode, "interactive") == 0 && inote < 2) {
941 SUMA_SLP_Note("%s",stmp); ++inote;}
942 else { SUMA_S_Note("%s",stmp); }
943 }
944 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
945 break;
946 default:
947 SUMA_S_Err("Il ne faut pas etre hawn");
948 SUMA_RETURN(0);
949 break;
950 }
951
952 SUMA_RETURN(1);
953 }
954
SUMA_F10_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode,char * strgval)955 int SUMA_F10_Key(SUMA_SurfaceViewer *sv,char *key, char *callmode, char *strgval)
956 {
957 static char FuncName[]={"SUMA_F10_Key"};
958 char tk[]={"F10"}, keyname[100];
959 int k, nc;
960 SUMA_EngineData *ED = NULL;
961 DList *list = NULL;
962 DListElmt *NextElm= NULL;
963 static int inote = 0;
964 SUMA_Boolean LocalHead = NOPE;
965
966 SUMA_ENTRY;
967
968 SUMA_KEY_COMMON;
969
970 /* do the work */
971 switch (k) {
972 case XK_F10:
973 if (sv->PryAx == 2) sv->PryAx = 3;
974 else if (sv->PryAx == 3) sv->PryAx = 2;
975 else {
976 SUMA_S_Err("Bad PryAx of %d. Reverting to 3", sv->PryAx);
977 sv->PryAx = 3;
978 }
979 {
980 char stmp[200];
981 if (sv->PryAx == 3) {
982 sprintf(stmp,"Prying about Z axis");
983 } else {
984 sprintf(stmp,"Prying about Y axis");
985 }
986 if (callmode && strcmp(callmode, "interactive") == 0 && inote < 2) {
987 SUMA_SLP_Note("%s",stmp); ++inote;}
988 else { SUMA_S_Note("%s",stmp); }
989 }
990 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
991 break;
992 default:
993 SUMA_S_Err("Il ne faut pas etre la dessous");
994 SUMA_RETURN(0);
995 break;
996 }
997
998 SUMA_RETURN(1);
999 }
1000
SUMA_F11_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode,char * strgval)1001 int SUMA_F11_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode,
1002 char *strgval)
1003 {
1004 static char FuncName[]={"SUMA_F11_Key"};
1005 char tk[]={"F11"}, keyname[100];
1006 int k, nc;
1007 SUMA_EngineData *ED = NULL;
1008 DList *list = NULL;
1009 DListElmt *NextElm= NULL;
1010 static int inote = 0;
1011 SUMA_Boolean LocalHead = NOPE;
1012
1013 SUMA_ENTRY;
1014
1015 SUMA_KEY_COMMON;
1016
1017 /* do the work */
1018 switch (k) {
1019 case XK_F11: {
1020 if ( (callmode && strcmp(callmode, "interactive") == 0) ||
1021 !strgval /* why not? this way the
1022 Driver can pop the interactive window */) {
1023 sv->X->SetRenderOrder_prmpt = SUMA_CreatePromptDialogStruct(
1024 SUMA_OK_APPLY_CLEAR_CANCEL,
1025 "Set Object Display Order:\n"
1026 "(e.g. VSG for: Volume, Surface, Graph)):",
1027 "VSG",
1028 sv->X->TOPLEVEL, YUP,
1029 SUMA_APPLY_BUTTON,
1030 SUMA_SV_SetRenderOrder, (void *)sv,
1031 NULL, NULL,
1032 NULL, NULL,
1033 SUMA_VerifyRenderOrder, NULL,
1034 sv->X->SetRenderOrder_prmpt);
1035
1036 sv->X->SetRenderOrder_prmpt = SUMA_CreatePromptDialog(
1037 sv->X->Title, sv->X->SetRenderOrder_prmpt);
1038 } else {
1039 if (!strgval) {
1040 SUMA_S_Err("Have NULL string");
1041 SUMA_RETURN(0);
1042 }
1043 SUMA_SV_SetRenderOrder(strgval, (void *)sv);
1044 }
1045 break; }
1046 default:
1047 SUMA_S_Err("Il ne faut pas etre hawn");
1048 SUMA_RETURN(0);
1049 break;
1050 }
1051
1052 SUMA_RETURN(1);
1053 }
1054
SUMA_F12_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1055 int SUMA_F12_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1056 {
1057 static char FuncName[]={"SUMA_F12_Key"};
1058 char tk[]={"F12"}, keyname[100];
1059 int k, nc;
1060 SUMA_EngineData *ED = NULL;
1061 DList *list = NULL;
1062 DListElmt *NextElm= NULL;
1063 static int inote = 0;
1064 SUMA_Boolean LocalHead = NOPE;
1065
1066 SUMA_ENTRY;
1067
1068 SUMA_KEY_COMMON;
1069
1070 /* do the work */
1071 switch (k) {
1072 case XK_F12:
1073 {
1074 /* time display speed */
1075 int i, nd = 20, N_vis, *Vis_IDs=NULL, NodeTot, FaceTot;
1076 GLfloat buf;
1077 float delta_t;
1078 SUMA_SurfaceObject *SO=NULL;
1079 struct timeval tti;
1080 char stmp[500], fnameout[]={"__SUMA.speedtest.txt"};
1081 SUMA_STRING *SS = NULL;
1082 FILE *fout=NULL;
1083
1084 if (callmode && !strcmp(callmode, "drivesuma")) {
1085 fout = fopen(fnameout,"w");
1086 }
1087 SS = SUMA_StringAppend (NULL, NULL);
1088
1089 buf = sv->light0_position[2];
1090 if (callmode && strcmp(callmode, "interactive") == 0) {
1091 SUMA_SLP_Note ("Timing Display speed\n"
1092 "(20 displays): \n");
1093 } else {
1094 SUMA_S_Note("Timing Display speed\n"
1095 "(20 displays): \n");
1096 }
1097 if (fout) fprintf(fout, "Timing Display speed (20 displays):\n");
1098
1099 SUMA_etime (&tti, 0);
1100 for (i=0; i< nd-1; ++i) {
1101 fprintf (SUMA_STDOUT,"%d\t", i); fflush (SUMA_STDOUT);
1102 sv->light0_position[2] *= -1;
1103 glLightfv(GL_LIGHT0, GL_POSITION, sv->light0_position);
1104 /* direct call to display */
1105 SUMA_display(sv, SUMAg_DOv);
1106 /* wait for display */
1107 glFinish();
1108 }
1109 fprintf (SUMA_STDOUT,"\n");
1110 delta_t = SUMA_etime (&tti, 1);
1111 sv->light0_position[2] = buf;
1112 glLightfv(GL_LIGHT0, GL_POSITION, sv->light0_position);
1113 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
1114 sprintf (stmp,
1115 "Elapsed time: %f seconds.\n%.2f displays/second.\n",
1116 delta_t, nd/delta_t);
1117 SS = SUMA_StringAppend (SS, stmp);
1118
1119 /* Estimate how many nodes and triangles were rendered */
1120 Vis_IDs = (int *)SUMA_malloc(sizeof(int)*SUMAg_N_DOv);
1121 N_vis = SUMA_VisibleSOs (sv, SUMAg_DOv, Vis_IDs, 0);
1122 NodeTot = 0;
1123 FaceTot = 0;
1124 for (i=0; i<N_vis;++i) {
1125 SO = (SUMA_SurfaceObject *)SUMAg_DOv[Vis_IDs[i]].OP;
1126 FaceTot += SO->N_FaceSet;
1127 NodeTot += SO->N_Node;
1128 }
1129 if (N_vis) {
1130 sprintf (stmp, "In Polymode %d, rendered \n"
1131 "%.2f Ktri/sec %.2f Kpnt/sec.\n",
1132 sv->PolyMode,
1133 (float)FaceTot / 1000.0 / delta_t ,
1134 (float)NodeTot / 1000.0 / delta_t );
1135 SS = SUMA_StringAppend (SS, stmp);
1136 }
1137
1138 if (callmode && strcmp(callmode, "interactive") == 0) {
1139 SUMA_SLP_Note("%s",SS->s);
1140 } else {
1141 SUMA_S_Note("%s",SS->s);
1142 }
1143
1144 if (fout) {
1145 fprintf(fout, "%s\n", SS->s);
1146 SUMA_S_Note("Timing results written to file: %s", fnameout);
1147 fclose(fout);
1148 }
1149
1150 if (Vis_IDs) SUMA_free(Vis_IDs);
1151 SUMA_free(SS->s);
1152 SUMA_free(SS);
1153 }
1154 break;
1155 default:
1156 SUMA_S_Err("Il ne faut pas etre hawn");
1157 SUMA_RETURN(0);
1158 break;
1159 }
1160
1161 SUMA_RETURN(1);
1162 }
1163
SUMA_A_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1164 int SUMA_A_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1165 {
1166 static char FuncName[]={"SUMA_A_Key"};
1167 char tk[]={"A"}, keyname[100];
1168 int k, nc;
1169 SUMA_EngineData *ED = NULL;
1170 DList *list = NULL;
1171 DListElmt *NextElm= NULL;
1172 SUMA_Boolean LocalHead = NOPE;
1173
1174 SUMA_ENTRY;
1175
1176 SUMA_KEY_COMMON;
1177
1178 /* do the work */
1179 switch (k) {
1180 case XK_A:
1181 if ((SUMA_CTRL_KEY(key))){
1182
1183 } else {
1184
1185 }
1186 break;
1187 case XK_a:
1188 /* toggle background attenuation */
1189 if (sv->Back_Modfact) {
1190 fprintf (SUMA_STDOUT,
1191 "%s: Modulation by background intensity OFF.\n", FuncName);
1192 sv->Back_Modfact = 0;
1193 } else {
1194 fprintf (SUMA_STDOUT,
1195 "%s: Modulation by background intensity ON.\n", FuncName);
1196 sv->Back_Modfact = SUMA_BACKGROUND_MODULATION_FACTOR;
1197 }
1198
1199 /* set the remix flag */
1200 if (!SUMA_SetShownLocalRemixFlag (sv)) {
1201 fprintf (SUMA_STDERR,
1202 "Error %s: Failed in SUMA_SetShownLocalRemixFlag.\n",
1203 FuncName);
1204 break;
1205 }
1206
1207 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
1208 break;
1209 default:
1210 SUMA_S_Err("Il ne faut pas ci dessous");
1211 SUMA_RETURN(0);
1212 break;
1213 }
1214
1215 SUMA_RETURN(1);
1216 }
1217
1218
SUMA_B_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1219 int SUMA_B_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1220 {
1221 static char FuncName[]={"SUMA_B_Key"};
1222 char tk[]={"B"}, keyname[100];
1223 int k, nc;
1224 SUMA_EngineData *ED = NULL;
1225 DList *list = NULL;
1226 DListElmt *NextElm= NULL;
1227 SUMA_Boolean LocalHead = NOPE;
1228
1229 SUMA_ENTRY;
1230
1231 SUMA_KEY_COMMON;
1232
1233 /* do the work */
1234 switch (k) {
1235 case XK_B:
1236 if ((SUMA_CTRL_KEY(key))){
1237 if (SUMAg_CF->Dev ) {
1238 sv->Blend_Mode = (sv->Blend_Mode+1)%SUMA_N_BLEND_MODES;
1239 switch (sv->Blend_Mode) {
1240 case SUMA_NO_BLEND:
1241 glDisable(GL_BLEND);
1242 if (callmode && strcmp(callmode, "interactive") == 0) {
1243 SUMA_SLP_Note ("Blending disabled."); }
1244 else { SUMA_S_Note ("Blending disabled."); }
1245 break;
1246 case SUMA_BLEND1:
1247 glEnable (GL_BLEND);
1248 glBlendFunc(GL_ONE,GL_SRC_ALPHA);
1249 if (callmode && strcmp(callmode, "interactive") == 0) {
1250 SUMA_SLP_Note ("Blending mode1."); }
1251 else { SUMA_S_Note ("Blending mode1."); }
1252 break;
1253 case SUMA_BLEND2:
1254 glEnable (GL_BLEND);
1255 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
1256 if (callmode && strcmp(callmode, "interactive") == 0) {
1257 SUMA_SLP_Note ("Blending mode2.");}
1258 else { SUMA_S_Note ("Blending mode2."); }
1259 break;
1260 default:
1261 SUMA_SL_Err ("Should not be here");
1262 break;
1263 }
1264 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
1265 }
1266 } else {
1267 sv->BF_Cull = (sv->BF_Cull+1)%3;
1268 if (callmode && strcmp(callmode, "interactive") == 0) {
1269 SUMA_CullOption(sv, "Apply");}
1270 else { SUMA_CullOption(sv, "Restore");}
1271 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
1272 }
1273 break;
1274 case XK_b:
1275 /* Show/hide the background */
1276 if (!list) list = SUMA_CreateList();
1277 ED = SUMA_InitializeEngineListData (SE_ToggleBackground);
1278 if (!SUMA_RegisterEngineListCommand ( list, ED,
1279 SEF_Empty, NULL,
1280 SES_Suma, (void *)sv, NOPE,
1281 SEI_Head, NULL)) {
1282 fprintf (SUMA_STDERR,
1283 "Error %s: Failed to register command.\n", FuncName);
1284 }
1285
1286 ED = SUMA_InitializeEngineListData (SE_Redisplay);
1287 if (!SUMA_RegisterEngineListCommand ( list, ED,
1288 SEF_Empty, NULL,
1289 SES_Suma, (void *)sv, NOPE,
1290 SEI_Head, NULL)) {
1291 fprintf (SUMA_STDERR,
1292 "Error %s: Failed to register command.\n", FuncName);
1293 }
1294
1295 if (!SUMA_Engine (&list)) {
1296 fprintf(SUMA_STDERR, "Error SUMA_input: SUMA_Engine call failed.\n");
1297 }
1298 break;
1299 default:
1300 SUMA_S_Err("Il ne faut pas ci dessous");
1301 SUMA_RETURN(0);
1302 break;
1303 }
1304
1305 SUMA_RETURN(1);
1306 }
1307
1308
1309
SUMA_D_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1310 int SUMA_D_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1311 {
1312 static char FuncName[]={"SUMA_D_Key"};
1313 SUMA_LIST_WIDGET *LW=NULL;
1314 char tk[]={"D"}, keyname[100];
1315 int k, nc, inode = 0, N_ts = 0, ChildOverInd=-1,loc[2], ii = 0;
1316 float ftop = 0.1, fbot = 0.01, fs=0.0, fstep=0.0, *fv=NULL;
1317 int normalize = 1, polort = 2;
1318 SUMA_EngineData *ED = NULL;
1319 SUMA_DSET *dot=NULL;
1320 SUMA_DSET *in_dset = NULL;
1321 SUMA_SurfaceObject *SO=NULL;
1322 SUMA_OVERLAYS *Sover=NULL, *child=NULL;
1323 SUMA_DSET *inc_dset=NULL;
1324 SUMA_SurfaceObject *SOC=NULL;
1325 DList *list = NULL;
1326 DListElmt *el= NULL;
1327 double *ts = NULL, TR=0.0;
1328 NI_group *ngr = NULL;
1329 NI_element *nel=NULL, *dotopts=NULL;
1330 SUMA_XFORM *xf=NULL;
1331 SUMA_CALLBACK *cb=NULL;
1332 char stmp[SUMA_MAX_NAME_LENGTH]={""};
1333 SUMA_Boolean LocalHead = NOPE;
1334
1335 SUMA_ENTRY;
1336
1337 SUMA_KEY_COMMON;
1338
1339 /* do the work */
1340 switch (k) {
1341 case XK_D:
1342 if ((SUMA_CTRL_KEY(key))){
1343 } else {
1344 SUMA_LH("The dotthing");
1345 /* DO the dot thing */
1346 if (!(SO = SUMA_SV_Focus_SO(sv))) {
1347 if (callmode && strcmp(callmode, "interactive") == 0) {
1348 SUMA_SLP_Err("No surface in focus.\nCannot dot.");
1349 } else {
1350 SUMA_S_Err("No surface in focus.\nCannot dot.");
1351 }
1352 SUMA_RETURN(0);
1353 }
1354 if ( !SO || !SO->SurfCont ||
1355 !SO->SurfCont->curColPlane ||
1356 !SO->SurfCont->curColPlane->dset_link) {
1357 SUMA_SL_Err("Nothing to dot");
1358 SUMA_RETURN(0);
1359 }
1360 Sover = SO->SurfCont->curColPlane;
1361 in_dset = SO->SurfCont->curColPlane->dset_link;
1362 inode = SO->SelectedNode;
1363 if (inode < 0) {
1364 if (callmode && strcmp(callmode, "interactive") == 0) {
1365 SUMA_SLP_Warn("No selected node.\nNothing to dot.");
1366 }else{
1367 SUMA_S_Warn("No selected node.\nNothing to dot.");
1368 }
1369 SUMA_RETURN(1);
1370 }
1371 if (SDSET_VECNUM(in_dset) < 3) {
1372 if (callmode && strcmp(callmode, "interactive") == 0) {
1373 SUMA_SLP_Warn( "Need more than 3 values per node.\n"
1374 "Nothing to dot.");
1375 }else{
1376 SUMA_S_Warn("Need more than 3 values per node.\n"
1377 "Nothing to dot.");
1378 }
1379 SUMA_RETURN(1);
1380 }
1381
1382
1383 if ((xf = SUMA_Find_XformByParent("Dot", SDSET_ID(in_dset), NULL))) {
1384 /* xform exists already, just flip toggle of all callbacks
1385 that claim it as a creator*/
1386 SUMA_SetXformActive(xf, -1*xf->active, 0);
1387
1388 if (callmode && strcmp(callmode, "interactive") == 0) {
1389 if (xf->active > 0) {
1390 SUMA_SLP_Note("Dot product callback active");
1391 } else {
1392 SUMA_SLP_Note("Dot product callback inactive");
1393 }
1394 }else {
1395 if (xf->active > 0) {
1396 SUMA_S_Note("Dot product callback active");
1397 } else {
1398 SUMA_S_Note("Dot product callback inactive");
1399 }
1400 }
1401
1402 SUMA_RETURN(1);
1403 } else { /* New Xform */
1404 /* We need to add a dot product transform to
1405 the dataset */
1406 SUMA_LH("Afresh: Adding Dot Xform");
1407 xf = SUMA_NewXform("Dot",
1408 SDSET_ID(in_dset), SO->LocalDomainParentID);
1409
1410 /* Any matching contralateral dset and a matching surface ?*/
1411 inc_dset = SUMA_Contralateral_dset(in_dset, SO, &SOC);
1412 if (inc_dset) {
1413 SUMA_LHv("Found contralateral dset %s (%s)\n",
1414 SDSET_LABEL(inc_dset), SDSET_FILENAME(inc_dset));
1415 if (!(SUMA_AddXformParent(xf,
1416 SDSET_ID(inc_dset), SOC->LocalDomainParentID))) {
1417 SUMA_S_Err("Failed to add parent");
1418 SUMA_RETURN(0);
1419 }
1420 } else {
1421 SUMA_S_Note("No contralateral dset ");
1422 }
1423 /* Initialize dot product options. You'll have to redo this
1424 unfortunately below... */
1425 if (!(SUMA_is_TimeSeries_dset(in_dset, &TR))) {
1426 TR = 0.0;
1427 }
1428 SUMA_SPECT_AXIS(TR, SDSET_VECNUM(in_dset), fs, ftop, fstep);
1429 dotopts = SUMA_set_dotopts(NULL, SDSET_VECNUM(in_dset),
1430 0.1, fbot,
1431 normalize, 1,
1432 polort, NULL);
1433
1434
1435 SUMA_LH("Get dot product time series");
1436
1437 if (!(fv = (float*)SUMA_GetDsetAllNodeValsInCols2(in_dset,
1438 NULL, 0,
1439 inode, SO->N_Node-1,
1440 &N_ts,
1441 SUMA_float))) {
1442 SUMA_S_Err("Failed to extract time series.");
1443 SUMA_RETURN(0);
1444 }
1445 if (!(ts = SUMA_DotPreProcessTimeSeries(fv, N_ts,
1446 (float)TR, dotopts))) {
1447 SUMA_S_Err("Failed to preprocess time series.");
1448 SUMA_RETURN(0);
1449 }
1450 SUMA_free(fv); fv=NULL;
1451
1452 for (ii=0; ii<xf->N_parents; ++ii) {
1453 dot = NULL; /* You'll need a new dset with each pass */
1454 if (!SUMA_is_ID_4_DSET(xf->parents[ii], &in_dset)) {
1455 /* This is a convoluted way to get in_dset,
1456 since in_dset is known from a few lines above.
1457 But it is meant to demo how to work with
1458 multiple parents in xf in general */
1459 SUMA_S_Err("You've really done it this time!");
1460 SUMA_RETURN(0);
1461 }
1462 if (!SUMA_is_ID_4_SO(xf->parents_domain[ii], &SO)) {
1463 /* This is a convoluted way to get SO...*/
1464 SUMA_S_Err("You've really really done it this time!");
1465 SUMA_RETURN(0);
1466 }
1467 SUMA_LHv("Creating dot for %d/%d %s\n",
1468 ii, xf->N_parents, SDSET_FILENAME(in_dset));
1469 if (!(SUMA_dot_product(in_dset, ts,
1470 &dot,
1471 dotopts))) {
1472 SUMA_S_Err("Failed to create dot product");
1473 SUMA_RETURN(0);
1474 }
1475
1476 /* Assign domain parent fields */
1477 NI_set_attribute(dot->ngr,"domain_parent_idcode",
1478 NI_get_attribute(in_dset->ngr,
1479 "domain_parent_idcode"));
1480 NI_set_attribute(dot->ngr,"geometry_parent_idcode",
1481 NI_get_attribute(in_dset->ngr,
1482 "geometry_parent_idcode"));
1483
1484 SUMA_LHv( "Insert (%s/%s)in DsetList\n",
1485 SDSET_LABEL(dot), SDSET_ID(dot) );
1486 /* no replacement allowed
1487 I don't think it's necessary*/
1488 if (!SUMA_InsertDsetPointer (&dot, SUMAg_CF->DsetList, 0)) {
1489 SUMA_S_Errv("Failed to insert pointer for %s\n",
1490 SDSET_LABEL(dot));
1491 SUMA_RETURN(0);
1492 }
1493
1494 /* Add child to Xform */
1495 if (!SUMA_AddXformChild(xf,SDSET_ID(dot))) {
1496 SUMA_S_Err("Failed to add child");
1497 SUMA_RETURN(0);
1498 }
1499
1500 SUMA_LH("Create its overlay (child)");
1501 if (!(SDSET_LABEL(dot))) SUMA_LabelDset(dot,NULL);
1502 sprintf(stmp, "overlay.%s", SDSET_ID(dot));
1503 child = SUMA_CreateOverlayPointer (
1504 stmp, dot, SO->idcode_str, NULL);
1505 if (!child) {
1506 fprintf (SUMA_STDERR,
1507 "Error %s: Failed in CreateOverlayPointer.\n" ,
1508 FuncName);
1509 SUMA_RETURN (0);
1510 }
1511 SUMA_LH("Add overlay to SO");
1512 /* Add this plane to SO->Overlays */
1513 if (!SUMA_AddNewPlane ( (SUMA_ALL_DO *)SO, child,
1514 SUMAg_DOv, SUMAg_N_DOv, 0)) {
1515 SUMA_SL_Crit("Failed in SUMA_AddNewPlane");
1516 SUMA_FreeOverlayPointer(child);
1517 SUMA_RETURN (0);
1518 }
1519
1520 ChildOverInd = SO->N_Overlays-1;
1521 /* set the opacity, index column and the range */
1522 child->GlobalOpacity = YUP;
1523 child->ShowMode = SW_SurfCont_DsetViewCol;
1524 child->OptScl->BrightFact = 0.8;
1525
1526 child->OptScl->find = 0;
1527 child->OptScl->tind = 0;
1528 child->OptScl->bind = 0;
1529 child->OptScl->UseThr = 1; /* turn on threshold use */
1530 child->SymIrange = 1; /* Use symmetric range */
1531 child->OptScl->AutoIntRange = 0; /* Do not update range */
1532
1533 /* Leave it to the -0.5, 0.5 range below, it works better
1534 SUMA_GetDsetColRange(dot, 0, child->OptScl->IntRange, loc);
1535 */
1536
1537 SO->SurfCont->curColPlane = child;
1538
1539 /* update the Dset frame */
1540 if (ChildOverInd >= 0)
1541 SUMA_InitializeColPlaneShell((SUMA_ALL_DO *)SO,
1542 SO->Overlays[ChildOverInd]);
1543 SUMA_UPDATE_ALL_NODE_GUI_FIELDS((SUMA_ALL_DO *)SO);
1544 child->OptScl->IntRange[0] = -0.5; /* set the range */
1545 child->OptScl->IntRange[1] = 0.5;
1546 SUMA_INSERT_CELL_VALUE(SO->SurfCont->SetRangeTable, 1, 1,
1547 child->OptScl->IntRange[0]);
1548 SUMA_INSERT_CELL_VALUE(SO->SurfCont->SetRangeTable, 1, 2,
1549 child->OptScl->IntRange[1]);
1550
1551 SUMA_LH("Colorize plane");
1552 SUMA_ColorizePlane(child);
1553
1554 /* remix-redisplay for surface */
1555 if (!SUMA_Remixedisplay ((SUMA_ALL_DO*)SO)) {
1556 SUMA_RETURN(0);
1557 }
1558
1559 SUMA_LH("Refreshing Dset list");
1560 /*update the list widget if open */
1561 LW = SO->SurfCont->SwitchDsetlst;
1562 if (LW) {
1563 if (!LW->isShaded) SUMA_RefreshDsetList ((SUMA_ALL_DO *)SO);
1564 }
1565
1566 if (LocalHead)
1567 fprintf (SUMA_STDERR,
1568 "%s: Updating Dset frame, OverInd=%d\n",
1569 FuncName, ChildOverInd);
1570
1571 } /* For each parent */
1572
1573 /* done with ts */
1574 SUMA_free(ts); ts = NULL;
1575
1576 /* add the dotoptions to the transform options group */
1577 NI_add_to_group(xf->XformOpts, dotopts);
1578
1579 /* activate xform */
1580 SUMA_SetXformActive(xf, 1, 0);
1581
1582
1583 SUMA_LH("Add Callback ");
1584 /* generic parts */
1585 cb = SUMA_NewCallback( "SUMA_dot_product_CB",
1586 SUMA_NEW_NODE_ACTIVATE_EVENT,
1587 SUMA_dot_product_CB,
1588 xf->children[0],
1589 xf->parents_domain[0],
1590 xf->idcode_str);
1591
1592
1593 /* add extra children */
1594 for (ii=1; ii<xf->N_children; ++ii) {
1595 if (!SUMA_AddCallbackParent(cb, xf->children[ii],
1596 xf->parents_domain[ii])) {
1597 SUMA_S_Err("Failed to add parent");
1598 SUMA_RETURN(0);
1599 }
1600 }
1601
1602 /* fill the callback function's input parameters */
1603 /* The time series datasets */
1604 nel = NI_new_data_element("AFNI_atr", 1);
1605 NI_set_attribute(nel, "atr_name", "ts_dsets_idcode");
1606 NI_add_column_stride(nel, NI_STRING, NULL,1);
1607 for (ii=0; ii<xf->N_parents; ++ii) {
1608 if (!SUMA_AddColAtt_CompString( nel, ii,
1609 xf->parents[ii], SUMA_NI_CSS, 0)){
1610 SUMA_S_Err("Failed to add ts_dsets_idcode");
1611 SUMA_RETURN(0);
1612 }
1613 }
1614 NI_add_to_group(cb->FunctionInput, nel);
1615
1616 /* the output datasets */
1617 nel = NI_new_data_element("AFNI_atr", 1);
1618 NI_set_attribute(nel, "atr_name", "dot_dsets_idcode");
1619 NI_add_column_stride(nel, NI_STRING, NULL,1);
1620 for (ii=0; ii<xf->N_children; ++ii) {
1621 if (!SUMA_AddColAtt_CompString( nel, ii,
1622 xf->children[ii], SUMA_NI_CSS, 0)){
1623 SUMA_S_Err("Failed to add dot_dsets_idcode");
1624 SUMA_RETURN(0);
1625 }
1626 }
1627 NI_add_to_group(cb->FunctionInput, nel);
1628
1629 /* Node is from surface SO, but there is no point
1630 in setting this now because the computations
1631 have been done already. Set all sources for
1632 getting the time series to nothing, for the
1633 record.*/
1634 /* ts can be specified via node selection events and parents */
1635 SUMA_FlushCallbackEventParameters (cb);
1636
1637 /* or ts can be explicitly set
1638 again, the existence of ts_vec is not necessary,
1639 but to illustrate options ...*/
1640 nel = NI_new_data_element("callback.data",0);
1641 NI_set_attribute(nel, "data_type", "ts_vec");
1642 NI_add_to_group(cb->FunctionInput, nel);
1643
1644 /* set callback to be active, but not pending */
1645 cb->active = 1;
1646 SUMA_SetCallbackPending(cb, 0, SES_Empty);
1647 if (callmode && strcmp(callmode, "interactive") == 0) {
1648 SUMA_SLP_Note("Dot product callback active"); } else {
1649 SUMA_S_Note("Dot product callback active");
1650 }
1651
1652 if (LocalHead) {
1653 SUMA_Show_Xforms(SUMAg_CF->xforms, SUMA_STDERR, 1);
1654 SUMA_Show_Callbacks(SUMAg_CF->callbacks, SUMA_STDERR, 1);
1655 }
1656
1657 /* initialize interface (no callbacks willget triggered)*/
1658 SUMA_InitializeXformInterface (xf);
1659
1660 } /* New Xform */
1661
1662 }
1663 break;
1664 case XK_d:
1665 if ((SUMA_CTRL_KEY(key))){
1666 /* Interactively it is handled by the mnemonic
1667 But if it gets here, the Driver may be driving it */
1668 /* opens draw ROI controller */
1669 if (!SUMA_OpenDrawROIController(NULL)) {
1670 SUMA_S_Err("Failed to open controller");
1671 }
1672 } else {
1673 if (SUMAg_CF->Dev ) {
1674 SUMA_Show_DOv(SUMAg_DOv, SUMAg_N_DOv, stdout);
1675 }
1676 }
1677
1678
1679 break;
1680 default:
1681 SUMA_S_Err("Il ne faut pas ci dessous");
1682 SUMA_RETURN(0);
1683 break;
1684 }
1685
1686 SUMA_RETURN(1);
1687 }
1688
SUMA_G_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)1689 int SUMA_G_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
1690 {
1691 static char FuncName[]={"SUMA_G_Key"};
1692 char tk[]={"G"}, keyname[100];
1693 int k=0, nc=-1;
1694 int inode = -1;
1695 SUMA_DSET *Dset = NULL;
1696 SUMA_ALL_DO *ado=NULL;
1697 SUMA_OVERLAYS *Sover=NULL;
1698 SUMA_X_SurfCont *SurfCont=NULL;
1699 char stmp[100]={"\0"};
1700 SUMA_Boolean LocalHead = NOPE;
1701
1702 SUMA_ENTRY;
1703
1704 SUMA_KEY_COMMON;
1705
1706 if (!(ado = SUMA_SV_Focus_ADO(sv))) {
1707 if (callmode && strcmp(callmode, "interactive") == 0) {
1708 SUMA_SLP_Err("No surface in focus.\nCannot graph.");
1709 } else {
1710 SUMA_S_Err("No surface in focus.\nCannot graph.");
1711 }
1712 SUMA_RETURN(0);
1713 }
1714 if ( !ado || !(SurfCont = SUMA_ADO_Cont(ado)) ||
1715 !(Sover = SUMA_ADO_CurColPlane(ado)) ||
1716 !(Dset = Sover->dset_link)) {
1717 SUMA_SL_Err("Nothing to graph");
1718 SUMA_RETURN(0);
1719 }
1720 inode = SUMA_ADO_SelectedDatum(ado, NULL, NULL);
1721 if (inode < 0) {
1722 if (callmode && strcmp(callmode, "interactive") == 0) {
1723 SUMA_SLP_Warn("No selected node.\nNothing to graph.");
1724 }else{
1725 SUMA_S_Warn("No selected node.\nNothing to graph.");
1726 }
1727 SUMA_RETURN(1);
1728 }
1729 if (SDSET_VECNUM(Dset) < 2) {
1730 if (callmode && strcmp(callmode, "interactive") == 0) {
1731 SUMA_SLP_Warn("One or no value per node.\nNothing to graph.");
1732 }else{
1733 SUMA_S_Warn("One or no value per node.\nNothing to graph.");
1734 }
1735 SUMA_RETURN(1);
1736 }
1737 /* do the work */
1738 switch (k) {
1739 case XK_g:
1740 if ((SUMA_CTRL_KEY(key))) {
1741 } else {
1742 SUMA_OverlayGraphAtNode(Sover, ado, inode);
1743 }
1744 break;
1745 case XK_G:
1746 if (SUMAg_CF->Dev ) {
1747 #ifdef SUMA_USE_AFNI_GRAPH
1748 /* an attempt at using AFNI's graphing interface */
1749 SUMA_Afni_Graph(Sover, SO);
1750 #endif
1751 }
1752 break;
1753 default:
1754 SUMA_S_Err("Il ne faut pas etre ici");
1755 SUMA_RETURN(0);
1756 break;
1757 }
1758 SUMA_RETURN(1);
1759 }
1760
SUMA_J_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode,char * strgval)1761 int SUMA_J_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode, char *strgval)
1762 {
1763 static char FuncName[]={"SUMA_J_Key"};
1764 char tk[]={"J"}, keyname[100];
1765 int k=0, nc=-1;
1766 int inode = -1;
1767 SUMA_DSET *Dset = NULL;
1768 SUMA_ALL_DO *ado=NULL;
1769 SUMA_OVERLAYS *Sover=NULL;
1770 char stmp[100]={"\0"};
1771 SUMA_Boolean LocalHead = NOPE;
1772
1773 SUMA_ENTRY;
1774
1775 SUMA_KEY_COMMON;
1776
1777
1778 if (!(ado = SUMA_SV_Focus_ADO(sv))) {
1779 if (callmode && strcmp(callmode, "interactive") == 0) {
1780 SUMA_SLP_Err("No object in focus.\nCannot Jump.");
1781 } else {
1782 SUMA_S_Err("No object in focus.\nCannot Jump.");
1783 }
1784 SUMA_RETURN(0);
1785 }
1786 /* do the work */
1787 switch (k) {
1788 case XK_j:
1789 if ( (callmode && strcmp(callmode, "interactive") == 0) ||
1790 !strgval /* why not? this way the
1791 Driver can pop the interactive window */) {
1792 if (SUMA_CTRL_KEY(key)){
1793 sv->X->JumpXYZ_prmpt = SUMA_CreatePromptDialogStruct(
1794 SUMA_OK_APPLY_CLEAR_CANCEL,
1795 "Enter XYZ to send the cross hair to:",
1796 "",
1797 sv->X->TOPLEVEL, YUP,
1798 SUMA_APPLY_BUTTON,
1799 SUMA_JumpXYZ, (void *)sv,
1800 NULL, NULL,
1801 NULL, NULL,
1802 SUMA_CleanNumString, (void*)3,
1803 sv->X->JumpXYZ_prmpt);
1804 sv->X->JumpXYZ_prmpt = SUMA_CreatePromptDialog(
1805 sv->X->Title, sv->X->JumpXYZ_prmpt);
1806
1807 } else if (SUMA_AALT_KEY(key)){
1808 sv->X->JumpFocusNode_prmpt = SUMA_CreatePromptDialogStruct(
1809 SUMA_OK_APPLY_CLEAR_CANCEL,
1810 "Enter index of focus node\n"
1811 "Prepend/append L/R for hemiisphere selection\n"
1812 "Cross hair's XYZ will not be affected:",
1813 "",
1814 sv->X->TOPLEVEL, YUP,
1815 SUMA_APPLY_BUTTON,
1816 SUMA_JumpFocusNode, (void *)sv,
1817 NULL, NULL,
1818 NULL, NULL,
1819 SUMA_CleanNumStringSide, (void*)1, sv->X->JumpFocusNode_prmpt);
1820
1821 sv->X->JumpFocusNode_prmpt = SUMA_CreatePromptDialog(
1822 sv->X->Title, sv->X->JumpFocusNode_prmpt);
1823
1824 } else {
1825 sv->X->JumpIndex_prmpt = SUMA_CreatePromptDialogStruct(
1826 SUMA_OK_APPLY_CLEAR_CANCEL,
1827 "Enter index of node to send the cross hair to:\n"
1828 "(prepend/append L/R for specifying hemisphere):",
1829 "",
1830 sv->X->TOPLEVEL, YUP,
1831 SUMA_APPLY_BUTTON,
1832 SUMA_JumpIndex, (void *)sv,
1833 NULL, NULL,
1834 NULL, NULL,
1835 SUMA_CleanNumStringSide, (void*)1,
1836 sv->X->JumpIndex_prmpt);
1837
1838 sv->X->JumpIndex_prmpt = SUMA_CreatePromptDialog(
1839 sv->X->Title, sv->X->JumpIndex_prmpt);
1840 }
1841 } else {
1842 if (!strgval) {
1843 SUMA_S_Err("Have NULL string");
1844 SUMA_RETURN(0);
1845 }
1846 if (SUMA_CTRL_KEY(key)){
1847 SUMA_JumpXYZ(strgval, (void *)sv);
1848 } else if (SUMA_AALT_KEY(key)){
1849 SUMA_JumpFocusNode(strgval, (void *)sv);
1850 } else {
1851 SUMA_JumpIndex(strgval, (void *)sv);
1852 }
1853 }
1854
1855 break;
1856 case XK_J:
1857 if ( (callmode && strcmp(callmode, "interactive") == 0) ||
1858 !strgval) {
1859 sv->X->JumpFocusFace_prmpt = SUMA_CreatePromptDialogStruct (
1860 SUMA_OK_APPLY_CLEAR_CANCEL,
1861 "Enter index of FaceSet\nto highlight (this viewer only):",
1862 "",
1863 sv->X->TOPLEVEL, YUP,
1864 SUMA_APPLY_BUTTON,
1865 SUMA_JumpFocusFace, (void *)sv,
1866 NULL, NULL,
1867 NULL, NULL,
1868 SUMA_CleanNumString, (void*)1,
1869 sv->X->JumpFocusFace_prmpt);
1870
1871 sv->X->JumpFocusFace_prmpt = SUMA_CreatePromptDialog(
1872 sv->X->Title, sv->X->JumpFocusFace_prmpt);
1873 } else {
1874 if (!strgval) {
1875 SUMA_S_Err("Have NULL string");
1876 SUMA_RETURN(0);
1877 }
1878 SUMA_JumpFocusFace( strgval, (void *)sv);
1879 }
1880 break;
1881 default:
1882 SUMA_S_Err("Il ne faut pas etre ici");
1883 SUMA_RETURN(0);
1884 break;
1885 }
1886 SUMA_RETURN(1);
1887 }
1888
SUMA_L_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode,char * strgval)1889 int SUMA_L_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode, char *strgval)
1890 {
1891 static char FuncName[]={"SUMA_L_Key"};
1892 char tk[]={"L"}, keyname[100];
1893 int k, nc;
1894 SUMA_EngineData *ED = NULL;
1895 DList *list = NULL;
1896 DListElmt *NextElm= NULL;
1897 SUMA_Boolean LocalHead = NOPE;
1898
1899 SUMA_ENTRY;
1900
1901 SUMA_KEY_COMMON;
1902 if (strgval) {
1903 SUMA_S_Warn("strgval (%s) not implemented for L_Key yet. \n"
1904 "Complain to author if you want it.\n", strgval);
1905 }
1906 /* do the work */
1907 switch (k) {
1908 case XK_l:
1909 if ((SUMA_CTRL_KEY(key))){
1910 #if 0 /* Not of much use */
1911 if (SUMAg_CF->Dev) {
1912 if (!list) list = SUMA_CreateList();
1913 ED = SUMA_InitializeEngineListData (SE_ToggleLockAllCrossHair);
1914 if (!SUMA_RegisterEngineListCommand ( list, ED,
1915 SEF_Empty, NULL,
1916 SES_Suma, (void *)sv, NOPE,
1917 SEI_Head, NULL )) {
1918 fprintf( SUMA_STDERR,
1919 "Error %s: Failed to register command\n",
1920 FuncName);
1921 break;
1922 }
1923 if (!SUMA_Engine (&list)) {
1924 fprintf( stderr,
1925 "Error %s: SUMA_Engine call failed.\n", FuncName);
1926 }
1927 }
1928 #else
1929 GLfloat light0_color[] = { SUMA_LIGHT0_COLOR_INIT};
1930 /* dim the lights */
1931 sv->dim_spe = sv->dim_spe * 0.8;
1932 if (sv->dim_spe < 0.1) sv->dim_spe = 1.0;
1933 sv->dim_dif = sv->dim_dif * 0.8;
1934 if (sv->dim_dif < 0.1) sv->dim_dif = 1.0;
1935 sv->dim_amb = sv->dim_amb * 0.8;
1936 if (sv->dim_amb < 0.1) sv->dim_amb = 1.0;
1937 sv->dim_emi = sv->dim_emi * 0.8;
1938 if (sv->dim_emi < 0.1) sv->dim_emi = 1.0;
1939 fprintf(SUMA_STDERR,
1940 "%s: light dim factor now %.3f\n",
1941 FuncName, sv->dim_spe);
1942 /*fprintf(SUMA_STDERR,"%s: light dim factor now %.3f\n"
1943 "%f %f %f %f\n",
1944 FuncName, sv->dim_spe,
1945 sv->light0_color[0], sv->light0_color[1],
1946 sv->light0_color[2], sv->light0_color[3]);
1947 */
1948 light0_color[0] = sv->light0_color[0]*sv->dim_spe;
1949 light0_color[1] = sv->light0_color[1]*sv->dim_spe;
1950 light0_color[2] = sv->light0_color[2]*sv->dim_spe;
1951 light0_color[3] = sv->light0_color[3]*sv->dim_spe;
1952 glLightfv(GL_LIGHT0, GL_SPECULAR, light0_color);
1953 light0_color[0] = sv->light0_color[0]*sv->dim_dif;
1954 light0_color[1] = sv->light0_color[1]*sv->dim_dif;
1955 light0_color[2] = sv->light0_color[2]*sv->dim_dif;
1956 light0_color[3] = sv->light0_color[3]*sv->dim_dif;
1957 glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_color);
1958 light0_color[0] = sv->lmodel_ambient[0]*sv->dim_amb;
1959 light0_color[1] = sv->lmodel_ambient[1]*sv->dim_amb;
1960 light0_color[2] = sv->lmodel_ambient[2]*sv->dim_amb;
1961 light0_color[3] = sv->lmodel_ambient[3]*sv->dim_amb;
1962 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, sv->lmodel_ambient);
1963 if (!list) list = SUMA_CreateList();
1964 SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_Redisplay,
1965 SES_Suma, sv);
1966
1967 if (!SUMA_Engine (&list)) {
1968 fprintf(stderr,
1969 "Error SUMA_input: SUMA_Engine call failed.\n");
1970 }
1971 #endif
1972 } else if ((SUMA_AALT_KEY(key))){ /* alt + l */
1973 /* register cross hair XYZ with ED */
1974 if (!list) list = SUMA_CreateList();
1975 ED = SUMA_InitializeEngineListData (SE_SetLookAt);
1976 if (!SUMA_RegisterEngineListCommand ( list, ED,
1977 SEF_fv3, (void *)sv->Ch->c,
1978 SES_Suma, (void *)sv, NOPE,
1979 SEI_Head, NULL )) {
1980 fprintf( SUMA_STDERR,
1981 "Error %s: Failed to register command\n", FuncName);
1982 SUMA_RETURN(0);
1983 }
1984 if (!SUMA_Engine (&list)) {
1985 fprintf(stderr,
1986 "Error %s: SUMA_Engine call failed.\n", FuncName);
1987 }
1988 } else {
1989 sv->X->LookAt_prmpt = SUMA_CreatePromptDialogStruct(
1990 SUMA_OK_APPLY_CLEAR_CANCEL,
1991 "X,Y,Z coordinates to look at:",
1992 "0,0,0",
1993 sv->X->TOPLEVEL, YUP,
1994 SUMA_APPLY_BUTTON,
1995 SUMA_LookAtCoordinates, (void *)sv,
1996 NULL, NULL,
1997 NULL, NULL,
1998 SUMA_CleanNumString, (void*)3,
1999 sv->X->LookAt_prmpt);
2000
2001 sv->X->LookAt_prmpt = SUMA_CreatePromptDialog(sv->X->Title,
2002 sv->X->LookAt_prmpt);
2003
2004 }
2005 break;
2006 case XK_L:
2007 if ((SUMA_CTRL_KEY(key))){
2008 GLfloat light0_color[] = { SUMA_LIGHT0_COLOR_INIT};
2009 /* brighten the lights */
2010 sv->dim_spe = sv->dim_spe / 0.8;
2011 if (sv->dim_spe > 1) sv->dim_spe = 0.1;
2012 sv->dim_dif = sv->dim_dif / 0.8;
2013 if (sv->dim_dif > 1) sv->dim_dif = 0.1;
2014 sv->dim_amb = sv->dim_amb / 0.8;
2015 if (sv->dim_amb > 1) sv->dim_amb = 0.1;
2016 sv->dim_emi = sv->dim_emi / 0.8;
2017 if (sv->dim_emi > 1) sv->dim_emi = 0.1;
2018 fprintf(SUMA_STDERR,
2019 "%s: light dim factor now %.3f\n",
2020 FuncName, sv->dim_spe);
2021 /*fprintf(SUMA_STDERR,"%s: light dim factor now %.3f\n"
2022 "%f %f %f %f\n",
2023 FuncName, sv->dim_spe,
2024 sv->light0_color[0], sv->light0_color[1],
2025 sv->light0_color[2], sv->light0_color[3]);
2026 */
2027 light0_color[0] = sv->light0_color[0]*sv->dim_spe;
2028 light0_color[1] = sv->light0_color[1]*sv->dim_spe;
2029 light0_color[2] = sv->light0_color[2]*sv->dim_spe;
2030 light0_color[3] = sv->light0_color[3]*sv->dim_spe;
2031 glLightfv(GL_LIGHT0, GL_SPECULAR, light0_color);
2032 light0_color[0] = sv->light0_color[0]*sv->dim_dif;
2033 light0_color[1] = sv->light0_color[1]*sv->dim_dif;
2034 light0_color[2] = sv->light0_color[2]*sv->dim_dif;
2035 light0_color[3] = sv->light0_color[3]*sv->dim_dif;
2036 glLightfv(GL_LIGHT0, GL_DIFFUSE, light0_color);
2037 light0_color[0] = sv->lmodel_ambient[0]*sv->dim_amb;
2038 light0_color[1] = sv->lmodel_ambient[1]*sv->dim_amb;
2039 light0_color[2] = sv->lmodel_ambient[2]*sv->dim_amb;
2040 light0_color[3] = sv->lmodel_ambient[3]*sv->dim_amb;
2041 glLightModelfv(GL_LIGHT_MODEL_AMBIENT, sv->lmodel_ambient);
2042 if (!list) list = SUMA_CreateList();
2043 SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_Redisplay,
2044 SES_Suma, sv);
2045
2046 if (!SUMA_Engine (&list)) {
2047 fprintf(stderr,
2048 "Error SUMA_input: SUMA_Engine call failed.\n");
2049 }
2050 } else if ((SUMA_AALT_KEY(key))){
2051
2052 } else {
2053 SUMA_PROMPT_DIALOG_STRUCT *prmpt;
2054 prmpt = SUMA_CreatePromptDialogStruct (
2055 SUMA_OK_APPLY_CLEAR_CANCEL,
2056 "X,Y,Z coordinates of light0:",
2057 "",
2058 sv->X->TOPLEVEL, NOPE,
2059 SUMA_APPLY_BUTTON,
2060 SUMA_SetLight0, (void *)sv,
2061 NULL, NULL,
2062 NULL, NULL,
2063 SUMA_CleanNumString, (void*)3,
2064 NULL);
2065
2066 prmpt = SUMA_CreatePromptDialog(sv->X->Title, prmpt);
2067 }
2068
2069 break;
2070 default:
2071 SUMA_S_Err("Il ne faut pas etre ici");
2072 SUMA_RETURN(0);
2073 break;
2074 }
2075
2076 SUMA_RETURN(1);
2077 }
2078
SUMA_M_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2079 int SUMA_M_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2080 {
2081 static char FuncName[]={"SUMA_M_Key"};
2082 char tk[]={"M"}, keyname[100];
2083 int k, nc;
2084 SUMA_Boolean LocalHead = NOPE;
2085
2086 SUMA_ENTRY;
2087
2088 SUMA_KEY_COMMON;
2089
2090 /* do the work */
2091 switch (k) {
2092 case XK_m:
2093 if ((SUMA_CTRL_KEY(key))) {
2094 SUMA_SurfaceObject *SO;
2095 float fv3[3];
2096 int it;
2097 fprintf(SUMA_STDOUT, "%s: Enter shift in mm [RAI] "
2098 "to apply to all mappable surfaces in DOv.\n",
2099 FuncName);
2100 it = SUMA_ReadNumStdin (fv3, 3);
2101 if (it > 0 && it < 3) {
2102 fprintf(SUMA_STDERR,"Error %s: read %d values, expected 3.\n",
2103 FuncName, it);
2104 SUMA_RETURN(0);
2105 }else if (it < 0) {
2106 fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ReadNumStdin.\n",
2107 FuncName);
2108 SUMA_RETURN(0);
2109 }else if (it == 0) {
2110 fprintf(SUMA_STDERR,"%s: Nothing read.\n", FuncName);
2111 SUMA_RETURN(0);
2112 }
2113
2114 for (it = 0; it < SUMAg_N_DOv; ++it) {
2115 if (SUMA_isSO_G (SUMAg_DOv[it], sv->CurGroupName)) {
2116 SO = (SUMA_SurfaceObject *)SUMAg_DOv[it].OP;
2117 if (SUMA_isLocalDomainParent(SO)) {
2118 int imax, ii;
2119 /* add the shift */
2120 fprintf (SUMA_STDERR,
2121 "%s: Shifting %s by %f %f %f mm RAI.\n",
2122 FuncName, SO->Label, fv3[0], fv3[1], fv3[2]);
2123 ii = 0;
2124 imax = 3 * SO->N_Node;
2125 while (ii < imax) {
2126 SO->NodeList[ii] += fv3[0]; ++ii;
2127 SO->NodeList[ii] += fv3[1]; ++ii;
2128 SO->NodeList[ii] += fv3[2]; ++ii;
2129 }
2130 }
2131 }
2132 }
2133
2134 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
2135 } else {
2136 sv->GVS[sv->StdView].ApplyMomentum =
2137 !sv->GVS[sv->StdView].ApplyMomentum;
2138 SUMA_UpdateViewerTitle(sv);
2139 if (sv->GVS[sv->StdView].ApplyMomentum) {
2140 sv->X->MOMENTUMID = XtAppAddTimeOut(
2141 SUMAg_CF->X->App, 1,
2142 SUMA_momentum,
2143 (XtPointer) sv->X->GLXAREA);
2144 /* wait till user initiates turning */
2145 sv->GVS[sv->StdView].spinDeltaX = 0;
2146 sv->GVS[sv->StdView].spinDeltaY = 0;
2147 sv->GVS[sv->StdView].translateDeltaX = 0;
2148 sv->GVS[sv->StdView].translateDeltaY = 0;
2149 } else {
2150 if (sv->X->MOMENTUMID) {
2151 XtRemoveTimeOut(sv->X->MOMENTUMID);
2152 sv->X->MOMENTUMID = 0;
2153 }
2154 }
2155 }
2156 break;
2157 case XK_M:
2158 if (SUMA_CTRL_KEY(key) && (SUMA_ALT_KEY(key) || SUMA_APPLE_KEY(key)) ) {
2159 #ifdef ALLOW_MCW_MALLOC
2160 /* write memtrace results to disk */
2161 if (!mcw_malloc_enabled()) {
2162 if (callmode && strcmp(callmode, "interactive") == 0) {
2163 SUMA_SLP_Warn("Memory tracing\n"
2164 "is not enabled.\n"
2165 "Use Help-->MemTrace.");
2166 } else {
2167 SUMA_S_Warn("Memory tracing\n"
2168 "is not enabled.\n"
2169 "Use Help-->MemTrace.");
2170 }
2171 SUMA_RETURN(0);
2172 } else {
2173 if (callmode && strcmp(callmode, "interactive") == 0) {
2174 SUMA_SLP_Note("Dumping memory tracing\n"
2175 "to latest ./malldump.???\n"
2176 "file (if possible).");
2177 } else {
2178 SUMA_S_Note("Dumping memory tracing\n"
2179 "to latest ./malldump.???\n"
2180 "file (if possible).");
2181 }
2182 mcw_malloc_dump_sort(1);
2183 }
2184 #else
2185 if (callmode && strcmp(callmode, "interactive") == 0) {
2186 SUMA_SLP_Warn("Sorry, memory tracing\n"
2187 "was not enabled at compile.\n"
2188 "time. You are out of luck\n"
2189 "if using SUN.");
2190 } else {
2191 SUMA_S_Warn("Sorry, memory tracing\n"
2192 "was not enabled at compile.\n"
2193 "time. You are out of luck\n"
2194 "if using SUN.");
2195 }
2196 SUMA_RETURN(0);
2197 #endif
2198 }
2199 break;
2200 default:
2201 SUMA_S_Err("Il ne faut pas etre ici");
2202 SUMA_RETURN(0);
2203 break;
2204 }
2205
2206 SUMA_RETURN(1);
2207 }
2208
SUMA_N_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2209 int SUMA_N_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2210 {
2211 static char FuncName[]={"SUMA_N_Key"};
2212 char tk[]={"N"}, keyname[100];
2213 int k, nc, it;
2214 float fv15[15];
2215 SUMA_EngineData *ED = NULL;
2216 DList *list = NULL;
2217 DListElmt *NextElm= NULL;
2218 SUMA_Boolean LocalHead = NOPE;
2219
2220 SUMA_ENTRY;
2221
2222 SUMA_KEY_COMMON;
2223
2224 /* do the work */
2225 switch (k) {
2226 case XK_N:
2227 break;
2228 case XK_n:
2229 if (SUMA_CTRL_KEY(key)) {
2230 SUMA_LH("Opening a new controller...");
2231 /* open a new controller */
2232 if (!SUMA_X_SurfaceViewer_Create ()) {
2233 SUMA_S_Err("Failed in SUMA_X_SurfaceViewer_Create.");
2234 SUMA_RETURN(0);
2235 }
2236 } else {
2237 fprintf(stdout,"BAD IDEA Enter XYZ of center followed by size of Box (enter nothing to cancel):\n");
2238 it = SUMA_ReadNumStdin (fv15, 6);
2239 if (it > 0 && it < 6) {
2240 fprintf(SUMA_STDERR,"Error %s: read %d values, expected 6.\n", FuncName, it);
2241 SUMA_RETURN(0);
2242 }else if (it < 0) {
2243 fprintf(SUMA_STDERR,"Error %s: Error in SUMA_ReadNumStdin.\n", FuncName);
2244 SUMA_RETURN(0);
2245 }else if (it == 0) {
2246 SUMA_RETURN(0);
2247 }
2248
2249 fprintf (SUMA_STDOUT, "Parsed Input:\n\tCenter %f, %f, %f.\n\tBox Size %f, %f, %f\n", \
2250 fv15[0], fv15[1],fv15[2],\
2251 fv15[3], fv15[4],fv15[5]);
2252
2253 /* register fv15 with ED */
2254 if (!list) list = SUMA_CreateList ();
2255 ED = SUMA_InitializeEngineListData (SE_GetNearestNode);
2256 if (!SUMA_RegisterEngineListCommand ( list, ED,
2257 SEF_fv15, (void *)fv15,
2258 SES_Suma, (void *)sv, NOPE,
2259 SEI_Head, NULL )) {
2260 fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
2261 break;
2262 }
2263
2264 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
2265 if (!SUMA_Engine (&list)) {
2266 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
2267 }
2268 }
2269 break;
2270 default:
2271 SUMA_S_Err("Il ne faut pas etre ici");
2272 SUMA_RETURN(0);
2273 break;
2274 }
2275
2276 SUMA_RETURN(1);
2277 }
2278
2279 /*!
2280 Execute commands when O or o is pressed
2281 */
SUMA_O_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2282 int SUMA_O_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2283 {
2284 static char FuncName[]={"SUMA_O_Key"};
2285 char tk[]={"O"}, keyname[100];
2286 int k, nc;
2287 int N_SOlist, SOlist[SUMA_MAX_DISPLAYABLE_OBJECTS];
2288 SUMA_ALL_DO *ado=NULL;
2289 SUMA_SurfaceObject *SO = NULL;
2290
2291 SUMA_Boolean LocalHead = NOPE;
2292
2293 SUMA_ENTRY;
2294
2295 SUMA_KEY_COMMON;
2296
2297 /* do the work */
2298 switch (k) {
2299 case XK_O:
2300 if ((SUMA_APPLE_KEY(key) || SUMA_ALT_KEY(key))) {
2301
2302 } else if (SUMA_CTRL_KEY(key)) {
2303 if ((ado = SUMA_SV_Focus_ADO(sv))) {
2304 SUMA_Set_ADO_TransMode(ado, sv->TransMode,
2305 SUMAg_CF->TransModeStep, 1);
2306 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
2307 }
2308 } else {
2309 sv->TransMode = ((sv->TransMode-SUMAg_CF->TransModeStep) %
2310 (STM_N_TransModes-2));
2311 if (sv->TransMode <= STM_ViewerDefault) sv->TransMode = STM_16;
2312
2313 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
2314 }
2315 break;
2316 case XK_o:
2317 if ((SUMA_APPLE_KEY(key) || SUMA_ALT_KEY(key))) {
2318 sv->X->SetRot_prmpt = SUMA_CreatePromptDialogStruct (
2319 SUMA_OK_APPLY_CLEAR_CANCEL, "Center of Rotation X,Y,Z:",
2320 "0,0,0",
2321 sv->X->TOPLEVEL, YUP,
2322 SUMA_APPLY_BUTTON,
2323 SUMA_SetRotCenter, (void *)sv,
2324 NULL, NULL,
2325 NULL, NULL,
2326 NULL, NULL,
2327 sv->X->SetRot_prmpt);
2328
2329 sv->X->SetRot_prmpt = SUMA_CreatePromptDialog(sv->X->Title,
2330 sv->X->SetRot_prmpt);
2331 } else if (SUMA_CTRL_KEY(key)) {
2332 if ((ado = SUMA_SV_Focus_ADO(sv))) {
2333 SUMA_Set_ADO_TransMode(ado, sv->TransMode,
2334 -SUMAg_CF->TransModeStep, 1);
2335 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
2336 }
2337 } else {
2338 sv->TransMode = ((sv->TransMode+SUMAg_CF->TransModeStep) %
2339 (STM_N_TransModes-2));
2340 if (sv->TransMode <= STM_ViewerDefault) sv->TransMode = STM_0;
2341
2342 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
2343 }
2344 break;
2345 default:
2346 SUMA_S_Err("Il ne faut pas etre ici");
2347 SUMA_RETURN(0);
2348 break;
2349 }
2350
2351 SUMA_RETURN(1);
2352 }
2353
2354 /*!
2355 Execute commands when P or p is pressed
2356 */
SUMA_P_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2357 int SUMA_P_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2358 {
2359 static char FuncName[]={"SUMA_P_Key"};
2360 char tk[]={"P"}, keyname[100], msg[100];
2361 int k, nc;
2362 int N_SOlist, SOlist[SUMA_MAX_DISPLAYABLE_OBJECTS];
2363 SUMA_SurfaceObject *SO = NULL;
2364 SUMA_ALL_DO *ado=NULL;
2365 SUMA_Boolean LocalHead = NOPE;
2366
2367 SUMA_ENTRY;
2368
2369 SUMA_KEY_COMMON;
2370
2371 /* do the work */
2372 switch (k) {
2373 case XK_P:
2374 if ((SUMA_APPLE_KEY(key) || SUMA_ALT_KEY(key))) {
2375 } else if (SUMA_CTRL_KEY(key)) {
2376
2377 } else {
2378 sv->PolyMode = SRM_Fill;
2379 N_SOlist = SUMA_RegisteredSOs(sv, SUMAg_DOv, SOlist);
2380 for (k=0; k<N_SOlist; ++k) {
2381 SO = (SUMA_SurfaceObject *)(SUMAg_DOv[SOlist[k]].OP);
2382 SO->PolyMode = SRM_ViewerDefault;
2383 SO->Show = YUP;
2384 }
2385 SUMA_SET_GL_RENDER_MODE(sv->PolyMode);
2386 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
2387 SUMA_SLP_Note("All surfaces displayed as solids");
2388 }
2389 break;
2390 case XK_p:
2391 if ((SUMA_APPLE_KEY(key) || SUMA_ALT_KEY(key))) {
2392 sv->DO_DrawMask = ((sv->DO_DrawMask+1) % SDODM_N_DO_DrawMasks);
2393 snprintf(msg,100*sizeof(char),"DO DrawMask now set to: %s",
2394 SUMA_DO_DrawMaskCode2Name_human(sv->DO_DrawMask));
2395 if (callmode && strcmp(callmode, "interactive") == 0) {
2396 SUMA_SLP_Note ("%s",msg);
2397 } else { SUMA_S_Note ("%s",msg); }
2398 } else if (SUMA_CTRL_KEY(key)) {
2399 if ((ado = SUMA_SV_Focus_ADO(sv))) {
2400 SUMA_Set_ADO_RenderMode(ado, sv->PolyMode, -1, 1);
2401 }
2402 } else {
2403 sv->PolyMode = ((sv->PolyMode+1) % SRM_N_RenderModes);
2404 if (sv->PolyMode <= SRM_ViewerDefault) sv->PolyMode = SRM_Fill;
2405
2406 SUMA_SET_GL_RENDER_MODE(sv->PolyMode);
2407 }
2408 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
2409 break;
2410 default:
2411 SUMA_S_Err("Il ne faut pas etre ici");
2412 SUMA_RETURN(0);
2413 break;
2414 }
2415
2416 SUMA_RETURN(1);
2417 }
2418
2419 /*!
2420 Execute commands when R or r is pressed
2421 */
SUMA_R_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2422 int SUMA_R_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2423 {
2424 static char FuncName[]={"SUMA_R_Key"};
2425 char tk[]={"R"}, keyname[100], msg[100];
2426 int k, nc, ii, jj, mm;
2427 SUMA_Boolean LocalHead = NOPE;
2428
2429 SUMA_ENTRY;
2430
2431 SUMA_KEY_COMMON;
2432
2433 /* do the work */
2434 switch (k) {
2435 case XK_r:
2436 if ((SUMA_APPLE_KEY(key) || SUMA_ALT_KEY(key))) {
2437 SUMAg_CF->SUMA_SnapshotOverSampling =
2438 (SUMAg_CF->SUMA_SnapshotOverSampling +1)%5;
2439 if (SUMAg_CF->SUMA_SnapshotOverSampling == 0)
2440 SUMAg_CF->SUMA_SnapshotOverSampling = 1;
2441 {
2442 sprintf(msg,"Oversampling now set to %d",
2443 SUMAg_CF->SUMA_SnapshotOverSampling);
2444 if (callmode && strcmp(callmode, "interactive") == 0) {
2445 SUMA_SLP_Note ("%s",msg);
2446 } else { SUMA_S_Note ("%s",msg); }
2447 }
2448 } else if (SUMA_CTRL_KEY(key)) {
2449 #if 0
2450 sv->X->SetRot_prmpt = SUMA_CreatePromptDialogStruct (
2451 SUMA_OK_APPLY_CLEAR_CANCEL, "Center of Rotation X,Y,Z:",
2452 "0,0,0",
2453 sv->X->TOPLEVEL, YUP,
2454 SUMA_APPLY_BUTTON,
2455 SUMA_SetRotCenter, (void *)sv,
2456 NULL, NULL,
2457 NULL, NULL,
2458 NULL, NULL,
2459 sv->X->SetRot_prmpt);
2460
2461 sv->X->SetRot_prmpt = SUMA_CreatePromptDialog(sv->X->Title,
2462 sv->X->SetRot_prmpt);
2463 #else
2464 /* save image to disk */
2465 SUMA_SnapToDisk(sv,1, 0);
2466 #endif
2467 } else {
2468 GLvoid *pixels=NULL;
2469 double rat;
2470 int oareah=-1,oareaw=-1, owindh=-1, owindw=-1;
2471 /* Control for GL_MAX_VIEWPORT_DIMS */
2472 if (SUMAg_CF->SUMA_SnapshotOverSampling > 1) {
2473 glGetIntegerv(GL_MAX_VIEWPORT_DIMS,&k);
2474 mm = SUMA_MAX_PAIR(
2475 SUMAg_CF->SUMA_SnapshotOverSampling*sv->X->aHEIGHT,
2476 SUMAg_CF->SUMA_SnapshotOverSampling*sv->X->aWIDTH);
2477 if (mm > k) { /* too big, find best new dimesnions */
2478 rat = (double)mm/(double)k;
2479 /*window shrinking factor to allow for stitching*/
2480 SUMA_S_Notev( "%d/%d (H/W) Too big for oversampling\n"
2481 " reducing resolution by %f.\n",
2482 sv->X->aHEIGHT, sv->X->aWIDTH, rat);
2483 /* store original size */
2484 oareaw = sv->X->aWIDTH; oareah = sv->X->aHEIGHT;
2485 owindw = sv->wWindWidth; owindh = sv->wWindHeight;
2486 sv->X->aHEIGHT =
2487 (int)((double)sv->X->aHEIGHT/rat)-1;
2488 sv->X->aWIDTH =
2489 (int)((double)sv->X->aWIDTH/rat)-1;
2490 SUMA_SV_WindDims_From_DrawAreaDims(sv);
2491 SUMA_WidgetResize (sv->X->TOPLEVEL ,
2492 sv->wWindWidth, sv->wWindHeight);
2493 sv->rdc = SUMA_RDC_X_RESIZE;
2494 glViewport( 0, 0,
2495 sv->X->aWIDTH, sv->X->aHEIGHT);
2496 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
2497 } else {
2498 SUMA_S_Note("Size OK");
2499 }
2500 }
2501 /* turn off checking for duplicates */
2502 for (jj=0; jj<SUMAg_CF->SUMA_SnapshotOverSampling; ++jj) {
2503 for (ii=0; ii<SUMAg_CF->SUMA_SnapshotOverSampling; ++ii) {
2504 if (SUMAg_CF->SUMA_SnapshotOverSampling > 1) {
2505 glGetIntegerv(GL_MAX_VIEWPORT_DIMS,&k);
2506 if (ii==0 && jj == 0) {
2507 SUMA_S_Notev( "Resampling factor of %d\n"
2508 "If using this feature, the\n"
2509 " sequence of %d images is saved\n"
2510 " temporarily to disk and '2dcat'\n"
2511 " is then used to put the images together.\n"
2512 "(Have ViewPort GL_MAX_VIEWPORT_DIMS of %d\n"
2513 " and max dims needed of %d.)\n",
2514 SUMAg_CF->SUMA_SnapshotOverSampling,
2515 SUMAg_CF->SUMA_SnapshotOverSampling *
2516 SUMAg_CF->SUMA_SnapshotOverSampling,
2517 k,
2518 SUMA_MAX_PAIR( SUMAg_CF->SUMA_SnapshotOverSampling *
2519 sv->X->aHEIGHT,
2520 SUMAg_CF->SUMA_SnapshotOverSampling*sv->X->aWIDTH) );
2521 } else {
2522 /* sometimes you have repeated black areas when
2523 oversampling, allow that after very first 'tant' */
2524 SNAP_OkDuplicates();
2525 }
2526 /* start from top left, move to right then go down
2527 one row (Row Major, starting on top left ) */
2528 glViewport(-ii*sv->X->aWIDTH,
2529 -(SUMAg_CF->SUMA_SnapshotOverSampling - jj - 1) *
2530 sv->X->aHEIGHT,
2531 SUMAg_CF->SUMA_SnapshotOverSampling*sv->X->aWIDTH,
2532 SUMAg_CF->SUMA_SnapshotOverSampling *
2533 sv->X->aHEIGHT);
2534 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
2535 #if 0 /* problem should be fixed by SUMA_grabRenderedPixels
2536 Throw section out if no new problems arise.
2537 Search for KILL_DOUBLE_RENDERING to locate
2538 other chunks for removal
2539 ZSS Feb 2012 */
2540 if (1) {
2541 /* seems to fix an problem with snapping the older
2542 image... at least on mac
2543 None of glFlush(); glFinish();glXWaitGL();glXWaitX();
2544 or NI_sleep did the trick
2545 Perhaps the wrong buffer is being grabbed?
2546 Check SUMA_grabPixels ...
2547 ZSS Feb 2012.
2548 Yes it was, SUMA_grabRenderedPixels does the trick.
2549 ZSS Feb the next morning 2012 */
2550 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
2551 }
2552 #endif
2553 } else {
2554 #if 0 /* Search for KILL_DOUBLE_RENDERING to locate
2555 other chunks for removal
2556 ZSS Feb 2012 */
2557 /* ZSS Nov 20 2009
2558 If you do not redisplay here, you could strange cases of
2559 snapping the previous frame as reported by Colm Connolly.
2560
2561 1. suma -spec N27_both_tlrc.spec -sv TT_N27+tlrc. &
2562 2. press F2 five times to cycle through the various axes
2563 from none to all and back to none.
2564 3. press r to record
2565
2566 The first image recorded has axes present even though none
2567 are present in the viewer. Pressing r again produces an
2568 image with no axes as expected.
2569
2570 Actually, it seems this happens in many other cases, F1, F6,
2571 change state, etc.
2572
2573 This seems to be the same problem reported by Chunmao W.
2574 a while back.
2575 Same happens with R option.
2576
2577 Problem only happens under DARWIN it seems.
2578
2579 I do not know why the call to SUMA_handleRedisplay does the
2580 trick. Perhaps it is a buffer reading problem in double
2581 buffer rendering. The fix is ugly, especially in continuous
2582 record mode (see SUMA_display function in 'if(csv->record)'
2583 block), but it works.
2584 */
2585 #ifdef DARWIN
2586 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
2587 #endif
2588 #endif
2589 }
2590 pixels = SUMA_grabRenderedPixels(sv, 3,
2591 sv->X->aWIDTH, sv->X->aHEIGHT, 0);
2592 if (pixels) {
2593 ISQ_snapsave (sv->X->aWIDTH, -sv->X->aHEIGHT,
2594 (unsigned char *)pixels, sv->X->GLXAREA );
2595 SUMA_free(pixels);
2596 }else {
2597 if (callmode && strcmp(callmode, "interactive") == 0) {
2598 SUMA_SLP_Err("Failed to record image.");
2599 } else { SUMA_S_Err("Failed to record image.");}
2600 }
2601 }
2602 }
2603 if (SUMAg_CF->SUMA_SnapshotOverSampling > 1) {
2604 /* Now return the window to its previous size */
2605 if (owindw > 0) {
2606 sv->wWindHeight = owindh;
2607 sv->X->aHEIGHT = oareah;
2608 sv->wWindWidth = owindw;
2609 sv->X->aWIDTH = oareaw;
2610 SUMA_WidgetResize (sv->X->TOPLEVEL , owindw, owindh);
2611 }
2612 sv->rdc = SUMA_RDC_X_RESIZE;
2613 glViewport( 0, 0,
2614 sv->X->aWIDTH, sv->X->aHEIGHT);
2615 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
2616 }
2617 if (SUMAg_CF->NoDuplicatesInRecorder) SNAP_NoDuplicates();
2618 else SNAP_OkDuplicates();
2619 if (SUMAg_CF->SUMA_SnapshotOverSampling > 1) {
2620 /* record the image to make life easy on user */
2621 sprintf(msg,"Writing resultant image\n"
2622 " to HighRes_Suma_tmp.ppm ...");
2623 if (callmode && strcmp(callmode, "interactive") == 0) {
2624 SUMA_SLP_Note ("%s",msg);
2625 } else { SUMA_S_Note ("%s",msg); }
2626 ISQ_snap_png_rng("HighRes_Photo___tmp",
2627 -(SUMAg_CF->SUMA_SnapshotOverSampling *
2628 SUMAg_CF->SUMA_SnapshotOverSampling),
2629 0);
2630 /* use explicit tcsh to avoid sh syntax 25 Apr 2017 [rickr] */
2631 system( "tcsh -c 'rm -f HighRes_Suma_tmp* >& /dev/null' ; "
2632 "2dcat -prefix HighRes_Suma_tmp HighRes_Photo___tmp* ; "
2633 "rm -f HighRes_Photo___tmp*");
2634 }
2635 }
2636 break;
2637 case XK_R:
2638 if (SUMA_CTRL_KEY(key)) {
2639 char sbuf[256];
2640 sv->Record = !sv->Record;
2641 if (sv->Record) sv->Record = 2;
2642 if (sv->Record) {
2643 SUMA_VALIDATE_RECORD_PATH(SUMAg_CF->autorecord);
2644 snprintf(sbuf,256*sizeof(char),
2645 "Disk Recording ON to: %s%s*",
2646 SUMAg_CF->autorecord->Path,
2647 SUMAg_CF->autorecord->FileName_NoExt);
2648 if (callmode && strcmp(callmode, "interactive") == 0) {
2649 SUMA_SLP_Note ("%s",sbuf); }
2650 else { SUMA_S_Note ("%s",sbuf); }
2651 } else {
2652 snprintf(sbuf,256*sizeof(char),
2653 "Disk Recording OFF. Results in: %s%s*",
2654 SUMAg_CF->autorecord->Path,
2655 SUMAg_CF->autorecord->FileName_NoExt);
2656 if (callmode && strcmp(callmode, "interactive") == 0) {
2657 SUMA_SLP_Note ("%s",sbuf); }
2658 else { SUMA_S_Note ("%s",sbuf);}
2659 }
2660 SUMA_UpdateViewerTitle(sv);
2661 } else {
2662 sv->Record = !sv->Record;
2663 if (sv->Record) {
2664 if (callmode && strcmp(callmode, "interactive") == 0) {
2665 SUMA_SLP_Note ("Recording ON"); }
2666 else { SUMA_S_Note ("Recording ON"); }
2667 } else {
2668 if (callmode && strcmp(callmode, "interactive") == 0) {
2669 SUMA_SLP_Note ("Recording OFF"); }
2670 else { SUMA_S_Note ("Recording OFF");}
2671 }
2672 SUMA_UpdateViewerTitle(sv);
2673 }
2674 break;
2675 default:
2676 SUMA_S_Err("Il ne faut pas etre ici");
2677 SUMA_RETURN(0);
2678 break;
2679 }
2680
2681 SUMA_RETURN(1);
2682 }
2683
SUMA_T_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2684 int SUMA_T_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2685 {
2686 static char FuncName[]={"SUMA_T_Key"};
2687 char tk[]={"T"}, keyname[100];
2688 int k, nc;
2689 SUMA_EngineData *ED = NULL;
2690 DList *list = NULL;
2691 DListElmt *NextElm= NULL;
2692 SUMA_Boolean LocalHead = NOPE;
2693
2694 SUMA_ENTRY;
2695
2696 SUMA_KEY_COMMON;
2697
2698 /* do the work */
2699 switch (k) {
2700 case XK_T:
2701 if (!list) list = SUMA_CreateList();
2702 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list,
2703 SE_StartListening, SES_Suma, sv);
2704
2705 if (!SUMA_Engine (&list)) {
2706 fprintf(SUMA_STDERR,
2707 "Error %s: SUMA_Engine call failed.\n", FuncName);
2708 }
2709 break;
2710 case XK_t:
2711 if ((SUMA_CTRL_KEY(key))){
2712 if (callmode && strcmp(callmode, "interactive") == 0) {
2713 SUMA_SLP_Note("Forcing a resend of Surfaces to Afni...");}
2714 else { SUMA_S_Note("Forcing a resend of Surfaces to Afni..."); }
2715 if (!list) list = SUMA_CreateList();
2716 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list,
2717 SE_SetForceAfniSurf, SES_Suma, sv);
2718
2719 if (!SUMA_Engine (&list)) {
2720 fprintf(SUMA_STDERR,
2721 "Error %s: SUMA_Engine call failed.\n", FuncName);
2722 }
2723 } else {
2724 if (!list) list = SUMA_CreateList();
2725 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list,
2726 SE_ToggleConnected, SES_Suma, sv);
2727
2728 if (!SUMA_Engine (&list)) {
2729 fprintf(SUMA_STDERR,
2730 "Error %s: SUMA_Engine call failed.\n", FuncName);
2731 }
2732 }
2733 break;
2734 default:
2735 SUMA_S_Err("Il ne faut pas ci dessous");
2736 SUMA_RETURN(0);
2737 break;
2738 }
2739
2740 SUMA_RETURN(1);
2741 }
2742
2743 /*!
2744 Execute commands when U or u is pressed
2745 */
SUMA_U_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2746 int SUMA_U_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2747 {
2748 static char FuncName[]={"SUMA_U_Key"};
2749 char tk[]={"U"}, keyname[100], msg[100];
2750 int k, nc, ii, jj, mm;
2751 SUMA_Boolean LocalHead = NOPE;
2752
2753 SUMA_ENTRY;
2754
2755 SUMA_KEY_COMMON;
2756
2757 /* do the work */
2758 switch (k) {
2759 case XK_u:
2760 if ((SUMA_APPLE_KEY(key) || SUMA_ALT_KEY(key))) {
2761 SUMA_LH("Nothing here");
2762 } else if (SUMA_CTRL_KEY(key)) {
2763 SUMA_viewSumaCont(1);
2764 } else {
2765 SUMA_LH("Keeping it real");
2766 }
2767 break;
2768 case XK_U:
2769 if (SUMA_CTRL_KEY(key)) {
2770
2771 } else {
2772
2773 }
2774 break;
2775 default:
2776 SUMA_S_Err("Il ne faut pas etre ici non plus");
2777 SUMA_RETURN(0);
2778 break;
2779 }
2780
2781 SUMA_RETURN(1);
2782 }
2783
2784
SUMA_free_Save_List_El(void * selu)2785 void SUMA_free_Save_List_El(void *selu) {
2786 SUMA_SAVE_LIST_EL *sel=(SUMA_SAVE_LIST_EL *)selu;
2787 if (sel) {
2788 if (sel->identifier) SUMA_free(sel->identifier);
2789 if (sel->prefix) SUMA_free(sel->prefix);
2790 if (sel->type) SUMA_free(sel->type);
2791 SUMA_free(sel);
2792 }
2793 return;
2794 }
2795
SUMA_Add_to_SaveList(DList ** SLp,char * type,char * identifier,char * prefix)2796 int SUMA_Add_to_SaveList(DList **SLp, char *type,
2797 char *identifier, char *prefix)
2798 {
2799 static char FuncName[]={"SUMA_Add_to_SaveList"};
2800 DList *SL=NULL;
2801 DListElmt *el= NULL;
2802 SUMA_SAVE_LIST_EL *sel=NULL;
2803 SUMA_Boolean LocalHead = NOPE;
2804
2805 SUMA_ENTRY;
2806
2807 if (!SLp || !type || !identifier || !prefix) SUMA_RETURN(0);
2808 SL = *SLp;
2809 if (!SL) {
2810 SL = (DList*)SUMA_malloc(sizeof(DList));
2811 dlist_init(SL, SUMA_free_Save_List_El);
2812 }
2813 SUMA_LH("Searching for possible identifier >%s<",
2814 identifier?identifier:"NULL");
2815 /* first make sure identifier is not there already */
2816 el = dlist_head(SL);
2817 while (el && identifier) {
2818 if ((sel = (SUMA_SAVE_LIST_EL *)el->data)) {
2819 if (sel->identifier &&
2820 !strcmp(sel->identifier, identifier)) {
2821 /* found, replace */
2822 SUMA_free(sel->identifier);
2823 sel->identifier = SUMA_copy_string(identifier);
2824 identifier = NULL;
2825 SUMA_free(sel->prefix);
2826 sel->prefix = SUMA_copy_string(prefix);
2827 prefix = NULL;
2828 SUMA_free(sel->type);
2829 sel->type = SUMA_copy_string(type);
2830 type = NULL;
2831 }
2832 }
2833 el = dlist_next(el);
2834 }
2835 if (identifier) { /* a new one, should add it */
2836 sel = (SUMA_SAVE_LIST_EL *)SUMA_calloc(1,sizeof(SUMA_SAVE_LIST_EL));
2837 sel->identifier = SUMA_copy_string(identifier);
2838 sel->prefix = SUMA_copy_string(prefix);
2839 sel->type = SUMA_copy_string(type);
2840 dlist_ins_next(SL, dlist_tail(SL), (void *)sel);
2841 }
2842
2843 if (LocalHead) {
2844 SUMA_Show_SaveList(SL, "SaveList now:\n");
2845 }
2846
2847 *SLp = SL;
2848 SUMA_RETURN(1);
2849 }
2850
SUMA_Show_SaveList(DList * SL,char * head)2851 void SUMA_Show_SaveList(DList *SL, char *head)
2852 {
2853 static char FuncName[]={"SUMA_Show_SaveList"};
2854 FILE *out=NULL;
2855 DListElmt *el= NULL;
2856 SUMA_SAVE_LIST_EL *sel=NULL;
2857 int cnt = 0;
2858
2859 SUMA_ENTRY;
2860
2861 if (!out) out = stderr;
2862 if (head) { fprintf(out, "%s", head); }
2863 if (!SL) { fprintf(out,"NULL SaveList\n"); SUMA_RETURNe; }
2864
2865 el = dlist_head(SL);
2866 cnt = 0;
2867 while (el) {
2868 if ((sel = (SUMA_SAVE_LIST_EL *)el->data)) {
2869 fprintf(out," %d: id>%s<, prefix>%s<, type>%s<\n",
2870 cnt, sel->identifier, sel->prefix, sel->type);
2871 } else {
2872 fprintf(out," %d: NULL sel\n", cnt);
2873 }
2874 el = dlist_next(el);
2875 fprintf(out,"\n");
2876 }
2877
2878 SUMA_RETURNe;
2879 }
2880
SUMA_SaveSaveListElement(SUMA_SAVE_LIST_EL * sel)2881 int SUMA_SaveSaveListElement(SUMA_SAVE_LIST_EL *sel)
2882 {
2883 static char FuncName[]={"SUMA_SaveSaveListElement"};
2884 SUMA_DSET *dset=NULL;
2885 char *oname=NULL, *idtype=NULL;
2886 int nid=0;
2887 SUMA_ENTRY;
2888
2889 if (!sel || !sel->identifier || !sel->prefix || !sel->type) SUMA_RETURN(0);
2890
2891 if (!strcmp(sel->type,"sdset")) {
2892 idtype="label:"; nid = strlen(idtype);
2893 if (!strncmp(idtype, sel->identifier, nid)) {
2894 if (!(dset = SUMA_FindDset2_s(sel->identifier+nid,
2895 SUMAg_CF->DsetList, "label"))) {
2896 SUMA_S_Errv("Failed to find dset labeled %s\n", sel->identifier+nid);
2897 SUMA_RETURN(0);
2898 }
2899 goto SAVEDSET;
2900 }
2901 idtype="filename:"; nid = strlen(idtype);
2902 if (!strncmp(idtype, sel->identifier, nid)) {
2903 if (!(dset = SUMA_FindDset2_s(sel->identifier+nid,
2904 SUMAg_CF->DsetList, "filename"))) {
2905 SUMA_S_Errv("Failed to find dset with filename %s\n",
2906 sel->identifier+nid);
2907 SUMA_RETURN(0);
2908 }
2909 goto SAVEDSET;
2910 }
2911 idtype="self_idcode:"; nid = strlen(idtype);
2912 if (!strncmp(idtype, sel->identifier, nid)) {
2913 if (!(dset = SUMA_FindDset2_s(sel->identifier+nid,
2914 SUMAg_CF->DsetList, "self_idcode"))) {
2915 SUMA_S_Errv("Failed to find dset with idcode %s\n",
2916 sel->identifier+nid);
2917 SUMA_RETURN(0);
2918 }
2919 goto SAVEDSET;
2920 }
2921 /* last hurrah */
2922 if (!(dset = SUMA_FindDset2_s(sel->identifier,
2923 SUMAg_CF->DsetList, NULL))) {
2924 SUMA_S_Errv("Failed to find dset with identifier %s\n",
2925 sel->identifier);
2926 SUMA_RETURN(0);
2927 }
2928 goto SAVEDSET;
2929
2930 SAVEDSET:
2931 if (!dset) SUMA_RETURN(0);
2932 oname = SUMA_WriteDset_PreserveID(sel->prefix, dset,
2933 SUMA_NO_DSET_FORMAT, 1,0);
2934 SUMA_S_Notev("Wrote: %s\n", oname);
2935 if (oname) SUMA_free(oname);
2936 } else {
2937 SUMA_S_Errv("Not setup for type %s yet\n", sel->type);
2938 SUMA_RETURN(0);
2939 }
2940 SUMA_RETURN(1);
2941 }
2942
SUMA_W_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)2943 int SUMA_W_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
2944 {
2945 static char FuncName[]={"SUMA_W_Key"};
2946 char tk[]={"W"}, keyname[100];
2947 int k, nc;
2948 SUMA_EngineData *ED = NULL;
2949 SUMA_SurfaceObject *SO;
2950 DList *list = NULL;
2951 DListElmt *el= NULL;
2952 char *lbls=NULL;
2953 SUMA_SAVE_LIST_EL *sel=NULL;
2954 SUMA_Boolean LocalHead = NOPE;
2955
2956 SUMA_ENTRY;
2957
2958 SUMA_KEY_COMMON;
2959
2960 /* do the work */
2961 switch (k) {
2962 case XK_W:
2963 if ((SUMA_CTRL_KEY(key))){
2964 if (!SUMAg_CF->SaveList || !dlist_size(SUMAg_CF->SaveList)) {
2965 SUMA_S_Note("Nothing in SaveList");
2966 SUMA_RETURN(1);
2967 }
2968 while((el = dlist_head(SUMAg_CF->SaveList))) {
2969 sel = (SUMA_SAVE_LIST_EL *)el->data;
2970 if (sel->identifier) {
2971 if (!(SUMA_SaveSaveListElement(sel))) {
2972 SUMA_S_Warnv("Failed to save %s %s\n",
2973 sel->identifier, sel->prefix)
2974 }
2975 }
2976 dlist_remove(SUMAg_CF->SaveList, el, (void *)(&sel));
2977 }
2978 } else {
2979 if ((SO=SUMA_SV_Focus_SO(sv))) {
2980 if (!list) list = SUMA_CreateList();
2981 ED = SUMA_InitializeEngineListData (SE_SaveSOFileSelection);
2982 if (!(el = SUMA_RegisterEngineListCommand ( list, ED,
2983 SEF_vp, (void *)SO,
2984 SES_Suma, (void *)sv, NOPE,
2985 SEI_Head, NULL))) {
2986 fprintf (SUMA_STDERR,
2987 "Error %s: Failed to register command.\n",
2988 FuncName);
2989 }
2990
2991 if (!SUMA_RegisterEngineListCommand ( list, ED,
2992 SEF_ip, sv->X->TOPLEVEL,
2993 SES_Suma, (void *)sv, NOPE,
2994 SEI_In, el)) {
2995 fprintf (SUMA_STDERR,
2996 "Error %s: Failed to register command.\n",
2997 FuncName);
2998 }
2999
3000 if (!SUMA_Engine (&list)) {
3001 fprintf( SUMA_STDERR,
3002 "Error %s: SUMA_Engine call failed.\n", FuncName);
3003 }
3004 }
3005 }
3006 break;
3007
3008 case XK_w:
3009 if (SUMAg_CF->Dev) {
3010 if ((SO=SUMA_SV_Focus_SO(sv))) {
3011 if (!SUMAg_CF->X->Whereami_TextShell) {
3012 if (!(SUMAg_CF->X->Whereami_TextShell =
3013 SUMA_CreateTextShellStruct ( SUMA_Whereami_open,
3014 NULL, NULL,
3015 SUMA_Whereami_destroyed,
3016 NULL, NULL))) {
3017 SUMA_S_Err("Failed to create TextShellStruct.");
3018 break;
3019 }
3020 }
3021 /* call the function to form labels and notify window */
3022 lbls = SUMA_GetLabelsAtSelection((SUMA_ALL_DO *)SO,
3023 SO->SelectedNode, -1);
3024 if (lbls) SUMA_free(lbls); lbls = NULL;
3025 }
3026 }
3027 break;
3028 default:
3029 SUMA_S_Err("Il ne faut pas ci dessous");
3030 SUMA_RETURN(0);
3031 break;
3032 }
3033
3034 SUMA_RETURN(1);
3035 }
3036
3037 /*!
3038 Execute commands when Z or z is pressed
3039 */
SUMA_Z_Key(SUMA_SurfaceViewer * sv,char * key,char * callmode)3040 int SUMA_Z_Key(SUMA_SurfaceViewer *sv, char *key, char *callmode)
3041 {
3042 static char FuncName[]={"SUMA_Z_Key"};
3043 char tk[]={"Z"}, keyname[100], msg[100];
3044 int k, nc, ii, jj, mm;
3045 SUMA_Boolean LocalHead = NOPE;
3046
3047 SUMA_ENTRY;
3048
3049 SUMA_KEY_COMMON;
3050
3051 /* do the work */
3052 switch (k) {
3053 case XK_Z:
3054 sv->FOV[sv->iState] /= (1+sv->KeyZoomGain);
3055 if (sv->FOV[sv->iState] < FOV_MIN) {
3056 SUMA_BEEP; sv->FOV[sv->iState] = FOV_MIN;
3057 }
3058 /*fprintf(stderr,"Zoom in %f\n", sv->FOV[sv->iState]);*/
3059 /* Now update the zoom compensation variable */
3060 if (sv->ZoomCompensate) {
3061 sv->ZoomCompensate = sv->FOV[sv->iState] / SUMA_sv_auto_fov(sv);
3062 if (sv->ZoomCompensate > 1) sv->ZoomCompensate = 1.0;
3063 /* weird stuff at zc_fac higher that 1.5 */
3064 else if (sv->ZoomCompensate < 0.005) sv->ZoomCompensate = 0.005;
3065 }
3066 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
3067 break;
3068
3069 case XK_z:
3070 sv->FOV[sv->iState] /= (1-sv->KeyZoomGain);
3071 if (sv->ortho) {
3072 if (sv->FOV[sv->iState] > FOV_MAX/2.0) {
3073 SUMA_BEEP; sv->FOV[sv->iState] = FOV_MAX/2.0; }
3074 } else {
3075 if (sv->FOV[sv->iState] > FOV_MAX) {
3076 SUMA_BEEP; sv->FOV[sv->iState] = FOV_MAX; }
3077 }
3078 /*fprintf(stderr,"Zoom out %f\n", sv->FOV[sv->iState]);*/
3079 /* Now update the zoom compensation variable */
3080 if (sv->ZoomCompensate) {
3081 sv->ZoomCompensate = sv->FOV[sv->iState] / SUMA_sv_auto_fov(sv);
3082 if (sv->ZoomCompensate > 1) sv->ZoomCompensate = 1.0;
3083 /* weird stuff at zc_fac higher that 1.5 */
3084 else if (sv->ZoomCompensate < 0.005) sv->ZoomCompensate = 0.005;
3085 /* weird stuff cause by integer spin variables!
3086 Proper way to handle all this is with float position
3087 storage and no recalculation of zc_fac except at zooming.*/
3088 }
3089 SUMA_postRedisplay(sv->X->GLXAREA, NULL, NULL);
3090 break;
3091
3092 default:
3093 SUMA_S_Err("Il ne faut pas etre la");
3094 SUMA_RETURN(0);
3095 break;
3096 }
3097 SUMA_RETURN(1);
3098 }
3099
SUMA_Up_Key(SUMA_SurfaceViewer * sv,char * key,char * caller)3100 int SUMA_Up_Key(SUMA_SurfaceViewer *sv, char *key, char *caller)
3101 {
3102 static char FuncName[]={"SUMA_Up_Key"};
3103 char tk[]={"Up"}, keyname[100], skey[65], skeyi[65];
3104 int k, nc, ii, inode = -1;
3105 float ArrowDeltaRot = 0.05;
3106 /* The larger the value, the bigger the rotation increment */
3107 Widget w;
3108 double dd[3] = {0.0, -1.0, 0.0}; /* up */
3109 SUMA_SurfaceObject *SO=NULL;
3110 SUMA_Boolean LocalHead = NOPE;
3111
3112 SUMA_ENTRY;
3113
3114 SUMA_KEY_COMMON;
3115
3116 SUMA_KEY_SWITCH;
3117
3118 w = sv->X->GLXAREA;
3119 /* do the work */
3120 switch (k) {
3121 case XK_Up:
3122 if ((SUMA_CTRL_KEY(key) && SUMA_SHIFT_KEY(key))) {
3123 float a[3];
3124 /* Posterior view ctrl+shift+up*/
3125 /* From top view, rotate by 90 degrees about x axis */
3126 a[0] = 1.0; a[1] = 0.0; a[2] = 0.0;
3127 axis_to_quat(a, SUMA_PI/2, sv->GVS[sv->StdView].currentQuat);
3128 SUMA_postRedisplay(w, NULL, NULL);
3129 }else if (SUMA_SHIFT_KEY(key)) {
3130 /*fprintf (SUMA_STDERR,"%s: Shift up\n", FuncName);*/
3131 sv->GVS[sv->StdView].translateVec[1] +=
3132 (GLfloat)sv->GVS[sv->StdView].ArrowtranslateDeltaY /
3133 (float)sv->X->aHEIGHT*sv->GVS[sv->StdView].TranslateGain;
3134 SUMA_postRedisplay(w, NULL, NULL);
3135 }else if (SUMA_CTRL_KEY(key)){
3136 /*fprintf (SUMA_STDERR,"%s: Control Up\n", FuncName);*/
3137 /* Top view ctrl+up*/
3138 float a[3];
3139 /* Default top view, rotate by nothing */
3140 a[0] = 1.0; a[1] = 0.0; a[2] = 0.0;
3141 axis_to_quat(a, 0, sv->GVS[sv->StdView].currentQuat);
3142 SUMA_postRedisplay(w, NULL, NULL);
3143 }else if (SUMA_AALT_KEY(key)) {
3144 SUMA_LH("alt down");
3145 if ((SO = SUMA_SV_Focus_SO(sv))) {
3146 if (SO->SelectedNode < 0 ||
3147 !SO->FN) SUMA_RETURN(1); /* nothing to do */
3148 inode = SO->SelectedNode;
3149 {
3150 inode =
3151 SUMA_NodeNeighborAlongScreenDirection(sv, SO, inode, dd);
3152 if (inode == -2) {
3153 SUMA_S_Err("Failed in"
3154 " SUMA_NodeNeighborAlongScreenDirection");
3155 SUMA_RETURN(0);
3156 } else if (inode == -1) {
3157 SUMA_LH("No good direction, get out");
3158 SUMA_BEEP;
3159 break;
3160 } else {
3161 SUMA_LHv("Next node should be %d\n", inode);
3162 }
3163 }
3164 /* Now set the new selected node */
3165 if (inode >= 0 && inode != SO->SelectedNode) {
3166 char stmp[64]; /* use Jump callback,
3167 the easy route */
3168 sprintf(stmp,"%d", inode);
3169 SUMA_JumpIndex (stmp, (void *)sv);
3170 }
3171 }
3172 } else {
3173 if (LocalHead)
3174 fprintf (SUMA_STDERR,"%s: Vanilla kind.\n", FuncName);
3175 trackball_Phi(sv->GVS[sv->StdView].deltaQuat,
3176 0.0, -ArrowDeltaRot, /* first point */
3177 0.0, ArrowDeltaRot, /* ending x,y */
3178 sv->ArrowRotationAngle);
3179 if (LocalHead) {
3180 fprintf(stdout,"\ncurrentQuat\n");
3181 for (ii=0; ii<4; ++ii) {
3182 fprintf( stdout,"%f\t",
3183 sv->GVS[sv->StdView].currentQuat[ii]);
3184 }
3185 fprintf(stdout,"\n");
3186 fprintf(stdout,"\ndeltaQuat\n");
3187 for (ii=0; ii<4; ++ii) {
3188 fprintf(stdout,"%f\t", sv->GVS[sv->StdView].deltaQuat[ii]);
3189 }
3190 fprintf(stdout,"\n");
3191 }
3192 add_quats ( sv->GVS[sv->StdView].deltaQuat,
3193 sv->GVS[sv->StdView].currentQuat,
3194 sv->GVS[sv->StdView].currentQuat);
3195 if (LocalHead) {
3196 fprintf(stdout,"\nnewQuat\n");
3197 for (ii=0; ii<4; ++ii) {
3198 fprintf( stdout,"%f\t",
3199 sv->GVS[sv->StdView].currentQuat[ii]);
3200 }
3201 fprintf(stdout,"\n");
3202 }
3203 sv->GVS[sv->StdView].spinDeltaX = 0;
3204 sv->GVS[sv->StdView].spinDeltaY =
3205 2.0*ArrowDeltaRot*sv->X->aHEIGHT;
3206 SUMA_postRedisplay(w, NULL, NULL);
3207
3208 }
3209
3210 break;
3211
3212 break;
3213 default:
3214 SUMA_S_Err("Il ne faut pas etre ici");
3215 SUMA_RETURN(0);
3216 break;
3217 }
3218
3219 SUMA_RETURN(1);
3220 }
SUMA_Down_Key(SUMA_SurfaceViewer * sv,char * key,char * caller)3221 int SUMA_Down_Key(SUMA_SurfaceViewer *sv, char *key, char *caller)
3222 {
3223 static char FuncName[]={"SUMA_Down_Key"};
3224 char tk[]={"Down"}, keyname[100], skey[65], skeyi[65];
3225 int k, nc, ii, inode=-1;
3226 float ArrowDeltaRot = 0.05;
3227 /* The larger the value, the bigger the rotation increment */
3228 Widget w;
3229 double dd[3] = {0.0, 1.0, 0.0}; /* down */
3230 SUMA_SurfaceObject *SO=NULL;
3231 SUMA_Boolean LocalHead = NOPE;
3232
3233 SUMA_ENTRY;
3234
3235 SUMA_KEY_COMMON;
3236
3237 SUMA_KEY_SWITCH;
3238
3239 w = sv->X->GLXAREA;
3240 /* do the work */
3241 switch (k) {
3242 case XK_Down:
3243 if ((SUMA_CTRL_KEY(key) && SUMA_SHIFT_KEY(key))) {
3244 float a[3], cQ[4], dQ[4];
3245 /* Posterior view ctrl+shift+down*/
3246 /* From top view, first rotate by 90 degrees about x axis */
3247 a[0] = 1.0; a[1] = 0.0; a[2] = 0.0;
3248 axis_to_quat(a, SUMA_PI/2, cQ);
3249 /* then rotate by 180 degrees about y axis */
3250 a[0] = 0.0; a[1] = 1.0; a[2] = 0.0;
3251 axis_to_quat(a, SUMA_PI, dQ);
3252 /*add rotation */
3253 add_quats (dQ, cQ, sv->GVS[sv->StdView].currentQuat);
3254 SUMA_postRedisplay(w, NULL, NULL);
3255 }else if (SUMA_SHIFT_KEY(key)) {
3256 /*fprintf (SUMA_STDERR,"%s: Shift down\n", FuncName);*/
3257 /*sv->GVS[sv->StdView].translateVec[0] += 0;*/
3258 sv->GVS[sv->StdView].translateVec[1] -=
3259 (GLfloat)sv->GVS[sv->StdView].ArrowtranslateDeltaY /
3260 (float)sv->X->aHEIGHT*sv->GVS[sv->StdView].TranslateGain;
3261 SUMA_postRedisplay(w, NULL, NULL);
3262 }else if (SUMA_CTRL_KEY(key)){
3263 /*fprintf (SUMA_STDERR,"%s: Control down\n", FuncName);*/
3264 /* Inferior view ctrl+down*/
3265 float a[3];
3266 /* From top view, rotate by 180 degrees about y axis */
3267 a[0] = 0.0; a[1] = 1.0; a[2] = 0.0;
3268 axis_to_quat(a, SUMA_PI, sv->GVS[sv->StdView].currentQuat);
3269 SUMA_postRedisplay(w, NULL, NULL);
3270 }else if (SUMA_AALT_KEY(key)) {
3271 SUMA_LH("alt down");
3272 if ((SO = SUMA_SV_Focus_SO(sv))) {
3273 if (SO->SelectedNode < 0 ||
3274 !SO->FN) SUMA_RETURN(1); /* nothing to do */
3275 inode = SO->SelectedNode;
3276 {
3277 inode =
3278 SUMA_NodeNeighborAlongScreenDirection(sv, SO, inode, dd);
3279 if (inode == -2) {
3280 SUMA_S_Err("Failed in"
3281 " SUMA_NodeNeighborAlongScreenDirection");
3282 SUMA_RETURN(0);
3283 } else if (inode == -1) {
3284 SUMA_LH("No good direction, get out");
3285 SUMA_BEEP;
3286 break;
3287 } else {
3288 SUMA_LHv("Next node should be %d\n", inode);
3289 }
3290 }
3291 /* Now set the new selected node */
3292 if (inode >= 0 && inode != SO->SelectedNode) {
3293 char stmp[64]; /* use Jump callback,
3294 the easy route */
3295 sprintf(stmp,"%d", inode);
3296 SUMA_JumpIndex (stmp, (void *)sv);
3297 }
3298 }
3299 }else {
3300 /*fprintf (SUMA_STDERR,"%s: Vanilla kind.\n", FuncName);*/
3301 trackball_Phi(sv->GVS[sv->StdView].deltaQuat,
3302 0.0, ArrowDeltaRot, /* first point */
3303 0.0, -ArrowDeltaRot, /* ending x,y */
3304 sv->ArrowRotationAngle);
3305 /*fprintf(stdout,"\ncurrentQuat\n");
3306 for (i=0; i<4; ++i) {
3307 fprintf(stdout,"%f\t", sv->GVS[sv->StdView].currentQuat[i]);}
3308 fprintf(stdout,"\n");
3309 fprintf(stdout,"\ndeltaQuat\n");for (i=0; i<4; ++i) {
3310 fprintf(stdout,"%f\t", sv->GVS[sv->StdView].deltaQuat[i]);}
3311 fprintf(stdout,"\n"); */
3312 add_quats (sv->GVS[sv->StdView].deltaQuat,
3313 sv->GVS[sv->StdView].currentQuat,
3314 sv->GVS[sv->StdView].currentQuat);
3315 /*fprintf(stdout,"\nnewQuat\n");
3316 for (i=0; i<4; ++i) {
3317 fprintf(stdout,"%f\t", sv->GVS[sv->StdView].currentQuat[i]);}
3318 fprintf(stdout,"\n");*/
3319 sv->GVS[sv->StdView].spinDeltaX = 0;
3320 sv->GVS[sv->StdView].spinDeltaY =
3321 -2.0*ArrowDeltaRot*sv->X->aHEIGHT;
3322 SUMA_postRedisplay(w, NULL, NULL);
3323 }
3324
3325 break;
3326
3327 break;
3328 default:
3329 SUMA_S_Err("Il ne faut pas etre ici");
3330 SUMA_RETURN(0);
3331 break;
3332 }
3333
3334
3335 SUMA_RETURN(1);
3336 }
SUMA_Left_Key(SUMA_SurfaceViewer * sv,char * key,char * caller)3337 int SUMA_Left_Key(SUMA_SurfaceViewer *sv, char *key, char *caller)
3338 {
3339 static char FuncName[]={"SUMA_Left_Key"};
3340 char tk[]={"Left"}, keyname[100], skey[65], skeyi[65];
3341 int k, nc, ii, jj, inode = -1, bkey = 0;
3342 float ArrowDeltaRot = 0.05;
3343 /* The larger the value, the bigger the rotation increment */
3344 Widget w;
3345 double dd[3] = {-1.0, 0.0, 0.0}; /* left */
3346 SUMA_SurfaceObject *SO=NULL;
3347 SUMA_Boolean LocalHead = NOPE;
3348
3349 SUMA_ENTRY;
3350
3351 SUMA_KEY_COMMON;
3352
3353 SUMA_KEY_SWITCH;
3354
3355 w = sv->X->GLXAREA;
3356 /* do the work */
3357 switch (k) {
3358 case XK_Left:
3359 if ((SUMA_CTRL_KEY(key) && SUMA_SHIFT_KEY(key))) {
3360 float a[3], cQ[4];
3361 /* rotate about Z axis CCW */
3362 a[0] = 0.0; a[1] = 0.0; a[2] = 1.0;
3363 axis_to_quat(a, -sv->ArrowRotationAngle, cQ);
3364 /*add rotation */
3365 add_quats ( cQ,
3366 sv->GVS[sv->StdView].currentQuat,
3367 sv->GVS[sv->StdView].currentQuat);
3368 sv->GVS[sv->StdView].spinDeltaX = 0;
3369 sv->GVS[sv->StdView].spinDeltaY = 0;
3370 SUMA_postRedisplay(w, NULL, NULL);
3371 }else if (SUMA_SHIFT_KEY(key)) {
3372 /*fprintf (SUMA_STDERR,"%s: Shift down\n", FuncName);*/
3373 sv->GVS[sv->StdView].translateVec[0] -=
3374 (GLfloat)sv->GVS[sv->StdView].ArrowtranslateDeltaX /
3375 (float)sv->X->aWIDTH*sv->GVS[sv->StdView].TranslateGain;
3376 /*sv->GVS[sv->StdView].translateVec[1] -= 0;*/
3377 SUMA_postRedisplay(w, NULL, NULL);
3378 }else if (SUMA_CTRL_KEY(key)){
3379 float a[3], cQ[4], dQ[4];
3380 /* From top view, rotate about x 90 degrees.*/
3381 a[0] = 1.0; a[1] = 0.0; a[2] = 0.0;
3382 axis_to_quat(a, SUMA_PI/2.0, cQ);
3383 /* then rotate about y 90 degrees */
3384 a[0] = 0.0; a[1] = 1.0; a[2] = 0.0;
3385 axis_to_quat(a, SUMA_PI/2.0, dQ);
3386 /*add and apply rotation*/
3387 add_quats (dQ, cQ, sv->GVS[sv->StdView].currentQuat);
3388 SUMA_postRedisplay(w, NULL, NULL);
3389 }else if (SUMA_AALT_KEY(key)) {
3390 SUMA_LH("alt down");
3391 if ((SO = SUMA_SV_Focus_SO(sv))) {
3392 if (SO->SelectedNode < 0 ||
3393 !SO->FN) SUMA_RETURN(1); /* nothing to do */
3394 inode = SO->SelectedNode;
3395 {
3396 inode =
3397 SUMA_NodeNeighborAlongScreenDirection(sv, SO, inode, dd);
3398 if (inode == -2) {
3399 SUMA_S_Err("Failed in"
3400 " SUMA_NodeNeighborAlongScreenDirection");
3401 SUMA_RETURN(0);
3402 } else if (inode == -1) {
3403 SUMA_LH("No good direction, get out");
3404 SUMA_BEEP;
3405 break;
3406 } else {
3407 SUMA_LHv("Next node should be %d\n", inode);
3408 }
3409 }
3410 /* Now set the new selected node */
3411 if (inode >= 0 && inode != SO->SelectedNode) {
3412 char stmp[64]; /* use Jump callback,
3413 the easy route */
3414 sprintf(stmp,"%d", inode);
3415 SUMA_JumpIndex (stmp, (void *)sv);
3416 }
3417 }
3418 }else {
3419 /*fprintf (SUMA_STDERR,"%s: Vanilla kind.\n", FuncName);*/
3420 trackball_Phi(sv->GVS[sv->StdView].deltaQuat,
3421 ArrowDeltaRot, 0.0, /* first point */
3422 -ArrowDeltaRot, 0.0, /* ending x,y */
3423 sv->ArrowRotationAngle);
3424 add_quats ( sv->GVS[sv->StdView].deltaQuat,
3425 sv->GVS[sv->StdView].currentQuat,
3426 sv->GVS[sv->StdView].currentQuat);
3427 sv->GVS[sv->StdView].spinDeltaX =
3428 -2.0*ArrowDeltaRot*sv->X->aWIDTH;
3429 sv->GVS[sv->StdView].spinDeltaY = 0;
3430 SUMA_postRedisplay(w, NULL, NULL);
3431 }
3432
3433 break;
3434
3435 break;
3436 default:
3437 SUMA_S_Err("Il ne faut pas etre ici");
3438 SUMA_RETURN(0);
3439 break;
3440 }
3441
3442
3443 SUMA_RETURN(1);
3444 }
SUMA_Right_Key(SUMA_SurfaceViewer * sv,char * key,char * caller)3445 int SUMA_Right_Key(SUMA_SurfaceViewer *sv, char *key, char *caller)
3446 {
3447 static char FuncName[]={"SUMA_Right_Key"};
3448 char tk[]={"Right"}, keyname[100], skey[65], skeyi[65];
3449 int k, nc, ii, inode=-1;
3450 float ArrowDeltaRot = 0.05;
3451 /* The larger the value, the bigger the rotation increment */
3452 Widget w;
3453 double dd[3] = {1.0, 0.0, 0.0}; /* right */
3454 SUMA_SurfaceObject *SO=NULL;
3455 SUMA_Boolean LocalHead = NOPE;
3456
3457 SUMA_ENTRY;
3458
3459 SUMA_KEY_COMMON;
3460
3461 SUMA_KEY_SWITCH;
3462
3463 w = sv->X->GLXAREA;
3464 /* do the work */
3465 switch (k) {
3466 case XK_Right:
3467 if ((SUMA_CTRL_KEY(key) && SUMA_SHIFT_KEY(key))) {
3468 float a[3], cQ[4];
3469 /* rotate about Z axis CCW */
3470 a[0] = 0.0; a[1] = 0.0; a[2] = 1.0;
3471 axis_to_quat(a, sv->ArrowRotationAngle, cQ);
3472 /*add rotation */
3473 add_quats ( cQ,
3474 sv->GVS[sv->StdView].currentQuat,
3475 sv->GVS[sv->StdView].currentQuat);
3476 sv->GVS[sv->StdView].spinDeltaX = 0;
3477 sv->GVS[sv->StdView].spinDeltaY = 0;
3478 SUMA_postRedisplay(w, NULL, NULL);
3479 }else if (SUMA_SHIFT_KEY(key)) {
3480 /*fprintf (SUMA_STDERR,"%s: Shift down\n", FuncName);*/
3481 sv->GVS[sv->StdView].translateVec[0] +=
3482 (GLfloat)sv->GVS[sv->StdView].ArrowtranslateDeltaX /
3483 (float)sv->X->aWIDTH*sv->GVS[sv->StdView].TranslateGain;
3484 /*sv->GVS[sv->StdView].translateVec[1] -= 0;*/
3485 SUMA_postRedisplay(w, NULL, NULL);
3486 }else if (SUMA_CTRL_KEY(key)){
3487 float a[3], cQ[4], dQ[4];
3488 /* From top view, rotate about x 90 degrees */
3489 a[0] = 1.0; a[1] = 0.0; a[2] = 0.0;
3490 axis_to_quat(a, SUMA_PI/2.0, cQ);
3491 /* then rotate about y -90 degrees */
3492 a[0] = 0.0; a[1] = 1.0;
3493 axis_to_quat(a, -SUMA_PI/2.0, dQ);
3494 /*add and apply rotation*/
3495 add_quats (dQ, cQ, sv->GVS[sv->StdView].currentQuat);
3496 SUMA_postRedisplay(w, NULL, NULL);
3497 }else if (SUMA_AALT_KEY(key)) {
3498 SUMA_LH("alt down");
3499 if ((SO = SUMA_SV_Focus_SO(sv))) {
3500 if (SO->SelectedNode < 0 ||
3501 !SO->FN) SUMA_RETURN(1); /* nothing to do */
3502 inode = SO->SelectedNode;
3503 {
3504 inode =
3505 SUMA_NodeNeighborAlongScreenDirection(sv, SO, inode, dd);
3506 if (inode == -2) {
3507 SUMA_S_Err("Failed in"
3508 " SUMA_NodeNeighborAlongScreenDirection");
3509 SUMA_RETURN(0);
3510 } else if (inode == -1) {
3511 SUMA_LH("No good direction, get out");
3512 SUMA_BEEP;
3513 break;
3514 } else {
3515 SUMA_LHv("Next node should be %d\n", inode);
3516 }
3517 }
3518 /* Now set the new selected node */
3519 if (inode >= 0 && inode != SO->SelectedNode) {
3520 char stmp[64]; /* use Jump callback,
3521 the easy route */
3522 sprintf(stmp,"%d", inode);
3523 SUMA_JumpIndex (stmp, (void *)sv);
3524 }
3525 }
3526 }else {
3527 /*fprintf (SUMA_STDERR,"%s: Vanilla kind.\n", FuncName);*/
3528 trackball_Phi(sv->GVS[sv->StdView].deltaQuat,
3529 -ArrowDeltaRot, 0.0, /* first point */
3530 ArrowDeltaRot, 0.0, /* ending x,y */
3531 sv->ArrowRotationAngle);
3532 add_quats (sv->GVS[sv->StdView].deltaQuat,
3533 sv->GVS[sv->StdView].currentQuat,
3534 sv->GVS[sv->StdView].currentQuat);
3535 sv->GVS[sv->StdView].spinDeltaX = 2.0*ArrowDeltaRot*sv->X->aWIDTH;
3536 sv->GVS[sv->StdView].spinDeltaY = 0;
3537 SUMA_postRedisplay(w, NULL, NULL);
3538 }
3539
3540 break;
3541
3542 break;
3543 default:
3544 SUMA_S_Err("Il ne faut pas etre ici");
3545 SUMA_RETURN(0);
3546 break;
3547 }
3548
3549
3550 SUMA_RETURN(1);
3551 }
3552
3553 #define SUMA_ALTHELL ( (Kev.state & Mod1Mask) || \
3554 (Kev.state & Mod2Mask) || \
3555 (Kev.state & SUMA_APPLE_AltOptMask) )
3556
SUMA_Butts2String(SUMA_EVENT * ev)3557 char *SUMA_Butts2String(SUMA_EVENT *ev)
3558 {
3559 static char ccs[10][32];
3560 static int icall=0;
3561 char *cc;
3562 int nb=0, mot;
3563
3564 ++icall; if (icall>9) icall=0;
3565 cc = (char *)ccs[icall]; cc[0]='\0';
3566
3567 if (ev->b1) {cc[nb++]='1'; cc[nb++]='&'; mot = 0;}
3568 if (ev->b2) {cc[nb++]='2'; cc[nb++]='&'; mot = 0;}
3569 if (ev->b3) {cc[nb++]='3'; cc[nb++]='&'; mot = 0;}
3570 if (ev->b4) {cc[nb++]='4'; cc[nb++]='&'; mot = 0;}
3571 if (ev->b5) {cc[nb++]='5'; cc[nb++]='&'; mot = 0;}
3572 if (ev->b6) {cc[nb++]='6'; cc[nb++]='&'; mot = 0;}
3573 if (ev->b7) {cc[nb++]='6'; cc[nb++]='&'; mot = 0;}
3574 if (ev->b1m) {cc[nb++]='1'; cc[nb++]='&'; mot = 1;}
3575 if (ev->b2m) {cc[nb++]='2'; cc[nb++]='&'; mot = 1;}
3576 if (ev->b3m) {cc[nb++]='3'; cc[nb++]='&'; mot = 1;}
3577 if (ev->b4m) {cc[nb++]='4'; cc[nb++]='&'; mot = 1;}
3578 if (ev->b5m) {cc[nb++]='5'; cc[nb++]='&'; mot = 1;}
3579
3580 if (nb>1) nb = nb-1; /* Get rid of last & */
3581 cc[nb] = '\0';
3582 return(cc);
3583 }
3584
SUMA_KeyType2String(int kt)3585 char *SUMA_KeyType2String(int kt)
3586 {
3587 switch(kt) {
3588 case KeyPress:
3589 return("key");
3590 case ButtonRelease:
3591 return("release");
3592 case ButtonPress:
3593 return("press");
3594 case MotionNotify:
3595 return("motion");
3596 default:
3597 return("UNKNOWN");
3598 }
3599 }
3600
SUMA_ShowEvent(SUMA_EVENT * ev,int opt,char * pre)3601 void SUMA_ShowEvent(SUMA_EVENT *ev, int opt, char *pre)
3602 {
3603 static char FuncName[]={"SUMA_ShowEvent"};
3604 static int icall=0;
3605 char *s = NULL;
3606 SUMA_STRING *SS = NULL;
3607 FILE *out = stderr;
3608
3609 SUMA_ENTRY;
3610
3611 SS = SUMA_StringAppend(NULL, NULL);
3612
3613 if (pre) SUMA_StringAppend(SS,pre);
3614 if (!ev) {
3615 SUMA_StringAppend(SS,"NULL ev\n"); goto OUT;
3616 }
3617 ++icall;
3618 if (!opt) {
3619 SUMA_StringAppend_va(SS,"Event Struct (set %d, callid %d)\n"
3620 " ktype %d kstate %d transl %s\n"
3621 " keysym %d mtype %d mstate %d\n"
3622 " bButton %d mButton %d\n"
3623 " bTime %ld mTime %ld\n"
3624 " mX %d mY %d bX %d bY %d\n"
3625 " mDelta %d, mDeltaX %d, mDeltaY %d\n"
3626 " shift %d control %d mod1 %d mod2 %d mod3 %d mod4 %d mod5 %d\n"
3627 " ApplAltOpt %d DoubleClick %d\n"
3628 " b1 %d b2 %d b3 %d b4 %d b5 %d b6 %d b7 %d\n"
3629 " b1m %d b2m %d b3m %d b4m %d b5m %d\n",
3630 ev->set, icall,
3631 ev->ktype, ev->kstate, ev->transl,
3632 ev->keysym, ev->mtype, ev->mstate,
3633 ev->bButton, ev->mButton,
3634 ev->bTime, ev->mTime,
3635 ev->mX, ev->mY, ev->bX, ev->bY,
3636 ev->mDelta, ev->mDeltaX, ev->mDeltaY,
3637 ev->Shift, ev->Control, ev->Mod1, ev->Mod2, ev->Mod3, ev->Mod4, ev->Mod5,
3638 ev->AppleAltOpt, ev->DoubleClick,
3639 ev->b1, ev->b2, ev->b3, ev->b4, ev->b5, ev->b6, ev->b7,
3640 ev->b1m, ev->b2m, ev->b3m, ev->b4m, ev->b5m);
3641 } else {
3642 /* More readable mode */
3643 SUMA_StringAppend_va(SS,"Input Event %d: %s \n",
3644 icall, ev->set ? "":"WARNING Event Struct Not Set!" );
3645 if (ev->ktype == KeyPress) {
3646 SUMA_StringAppend_va(SS,"%s: char>>%s<< sym>>%d<< ",
3647 SUMA_KeyType2String(ev->ktype),
3648 ev->transl, (int)ev->keysym);
3649 } else {
3650 SUMA_StringAppend_va(SS,"Mouse %s %s%s: ",
3651 SUMA_Butts2String(ev),
3652 SUMA_KeyType2String(ev->ktype),
3653 ev->DoubleClick ? " double click":"");
3654 if (ev->b1) SUMA_StringAppend_va(SS,"b1 ",ev->b1);
3655 if (ev->b2) SUMA_StringAppend_va(SS,"b2 ",ev->b2);
3656 if (ev->b3) SUMA_StringAppend_va(SS,"b3 ",ev->b3);
3657 if (ev->b4) SUMA_StringAppend_va(SS,"b4 ",ev->b4);
3658 if (ev->b5) SUMA_StringAppend_va(SS,"b5 ",ev->b5);
3659 if (ev->b6) SUMA_StringAppend_va(SS,"b6 ",ev->b6);
3660 if (ev->b7) SUMA_StringAppend_va(SS,"b7 ",ev->b7);
3661 if (ev->b1m) SUMA_StringAppend_va(SS,"m1 ",ev->b1m);
3662 if (ev->b2m) SUMA_StringAppend_va(SS,"m2 ",ev->b2m);
3663 if (ev->b3m) SUMA_StringAppend_va(SS,"m3 ",ev->b3m);
3664 if (ev->b4m) SUMA_StringAppend_va(SS,"m4 ",ev->b4m);
3665 if (ev->b5m) SUMA_StringAppend_va(SS,"m5 ",ev->b5m);
3666 }
3667 if (ev->Shift) {
3668 SUMA_StringAppend_va(SS,"Shift ");
3669 }
3670 if (ev->Control){
3671 SUMA_StringAppend_va(SS,"Control ");
3672 }
3673 if (ev->Mod1){
3674 SUMA_StringAppend_va(SS,"alt ");
3675 }
3676 if (ev->Mod2){
3677 SUMA_StringAppend_va(SS,"Mod2 (command on mac) ");
3678 }
3679 if (ev->Mod3){
3680 SUMA_StringAppend_va(SS,"Mod3 ");
3681 }
3682 if (ev->Mod4){
3683 SUMA_StringAppend_va(SS,"Mod4 ");
3684 }
3685 if (ev->Mod5){
3686 SUMA_StringAppend_va(SS,"Mod5 ");
3687 }
3688 if (ev->Mod2){
3689 SUMA_StringAppend_va(SS,"Mod2 ");
3690 }
3691 if (ev->AppleAltOpt){
3692 SUMA_StringAppend_va(SS,"Apple Alt/Opt ");
3693 }
3694 SUMA_StringAppend_va(SS,"k/mstate [%d/%d]\n\n", ev->kstate, ev->mstate);
3695 }
3696 OUT:
3697 SUMA_SS2S(SS,s);
3698
3699 fprintf(out,"%s",s);
3700
3701 SUMA_ifree(s);
3702
3703 SUMA_RETURNe;
3704 }
3705
3706 #ifdef DARWIN
3707 #define evALT ((ev->Mod1 || ev->Mod2 || ev->AppleAltOpt))
3708 #else
3709 #define evALT ((ev->Mod1))
3710 #endif
SUMA_ShftCont_Event(SUMA_EVENT * ev)3711 int SUMA_ShftCont_Event(SUMA_EVENT *ev)
3712 {
3713 if (!ev) ev = SUMAg_CF->lev;
3714 if (!ev || !ev->set) return(0);
3715 if (ev->Shift && ev->Control && !evALT) return(1);
3716 return(0);
3717 }
SUMA_Cont_Event(SUMA_EVENT * ev)3718 int SUMA_Cont_Event(SUMA_EVENT *ev)
3719 {
3720 if (!ev) ev = SUMAg_CF->lev;
3721 if (!ev || !ev->set) return(0);
3722 if (!ev->Shift && ev->Control && !evALT) return(1);
3723 return(0);
3724 }
SUMA_Shft_Event(SUMA_EVENT * ev)3725 int SUMA_Shft_Event(SUMA_EVENT *ev)
3726 {
3727 if (!ev) ev = SUMAg_CF->lev;
3728 if (!ev || !ev->set) return(0);
3729 if (ev->Shift && !ev->Control && !evALT) return(1);
3730 return(0);
3731 }
SUMA_ShftContAlt_Event(SUMA_EVENT * ev)3732 int SUMA_ShftContAlt_Event(SUMA_EVENT *ev)
3733 {
3734 if (!ev) ev = SUMAg_CF->lev;
3735 if (!ev || !ev->set) return(0);
3736 if (ev->Shift && ev->Control && evALT ) return(1);
3737 return(0);
3738 }
SUMA_ContAlt_Event(SUMA_EVENT * ev)3739 int SUMA_ContAlt_Event(SUMA_EVENT *ev)
3740 {
3741 if (!ev) ev = SUMAg_CF->lev;
3742 if (!ev || !ev->set) return(0);
3743 if (!ev->Shift && ev->Control && evALT ) return(1);
3744 return(0);
3745 }
SUMA_ShftAlt_Event(SUMA_EVENT * ev)3746 int SUMA_ShftAlt_Event(SUMA_EVENT *ev)
3747 {
3748 if (!ev) ev = SUMAg_CF->lev;
3749 if (!ev || !ev->set) return(0);
3750 if (ev->Shift && !ev->Control && evALT ) return(1);
3751 return(0);
3752 }
SUMA_Alt_Event(SUMA_EVENT * ev)3753 int SUMA_Alt_Event(SUMA_EVENT *ev)
3754 {
3755 if (!ev) ev = SUMAg_CF->lev;
3756 if (!ev || !ev->set) return(0);
3757 if (!ev->Shift && !ev->Control && evALT) return(1);
3758 return(0);
3759 }
SUMA_Plain_Event(SUMA_EVENT * ev)3760 int SUMA_Plain_Event(SUMA_EVENT *ev)
3761 {
3762 if (!ev) ev = SUMAg_CF->lev;
3763 if (!ev || !ev->set) return(0);
3764 if (!ev->Shift && !ev->Control && !evALT) return(1);
3765 return(0);
3766 }
3767
3768 /*! Get a record of events.
3769 Contents based on logic used in SUMA_input()
3770 Ideally, all should be done here and SUMA_input()
3771 should use the results of this call. But we're not
3772 there yet....
3773 Once I start using this one call, then the logic
3774 can be revisited at varied points in there.
3775 */
SUMA_RecordEvent(XEvent * event,SUMA_EVENT * ev)3776 SUMA_EVENT *SUMA_RecordEvent( XEvent *event,
3777 SUMA_EVENT *ev)
3778 {
3779 static char FuncName[]={"SUMA_RecordEvent"};
3780 XKeyEvent Kev;
3781 XButtonEvent Bev;
3782 XMotionEvent Mev;
3783 static SUMA_EVENT lev;
3784 SUMA_Boolean LocalHead = NOPE;
3785
3786 SUMA_ENTRY;
3787
3788 if (!event) {
3789 SUMA_S_Err("Null event");
3790 if (ev) memset(ev, 0, sizeof(SUMA_EVENT));
3791 SUMA_RETURN(ev);
3792 }
3793
3794 if (!ev) {
3795 if (!(ev = SUMAg_CF->lev)) {
3796 memset(&lev, 0, sizeof(SUMA_EVENT));
3797 SUMAg_CF->lev = (SUMA_EVENT *)SUMA_malloc(1*sizeof(SUMA_EVENT));
3798 }
3799 ev = SUMAg_CF->lev;
3800 }
3801 if (!ev) SUMA_RETURN(NULL);
3802 memset(ev, 0, sizeof(SUMA_EVENT));
3803
3804 Kev = *(XKeyEvent *) &event->xkey; /* RickR's suggestion to comply with
3805 ANSI C, no type casting of structures July 04*/
3806 Bev = *(XButtonEvent *) &event->xbutton;
3807 Mev = *(XMotionEvent *) &event->xmotion;
3808
3809 ev->set = 1;
3810 /* The copied parameters */
3811 ev->ktype = Kev.type;
3812 ev->kstate = Kev.state;
3813 ev->mtype = Mev.type;
3814 ev->mstate = Mev.state;
3815 ev->bTime = Bev.time;
3816 ev->mTime = Mev.time;
3817 ev->bButton = Bev.button;
3818 ev->mButton = 0; /* Not sure this one was all that necessary */
3819 ev->mX = Mev.x;
3820 ev->mY = Mev.y;
3821 ev->bX = Bev.x;
3822 ev->bY = Bev.y;
3823
3824 /* The inferred parameters */
3825 if ((Kev.state & ShiftMask) || (Bev.state & ShiftMask)) ev->Shift = 1;
3826 if ((Kev.state & ControlMask) || (Bev.state & ControlMask)) ev->Control = 1;
3827 if (Kev.state & Mod1Mask) ev->Mod1 = 1;
3828 if (Kev.state & Mod2Mask) ev->Mod2 = 1;
3829 if (Kev.state & Mod3Mask) ev->Mod3 = 1;
3830 if (Kev.state & Mod4Mask) ev->Mod4 = 1;
3831 if (Kev.state & Mod5Mask) ev->Mod5 = 1;
3832 if (Kev.state & SUMA_APPLE_AltOptMask) ev->AppleAltOpt = 1;
3833
3834 switch(ev->ktype) {
3835 case KeyPress:
3836 ev->transl[0] = ev->transl[15] = '\0';
3837 XLookupString( (XKeyEvent *)event, ev->transl, 14,
3838 &ev->keysym, NULL);
3839 break;
3840 break;
3841 case ButtonPress:
3842 if (Bev.state & Button1Mask) ev->b1 = 1;
3843 if (Bev.state & Button2Mask) ev->b2 = 1;
3844 if (Bev.state & Button3Mask) ev->b3 = 1;
3845 if (Bev.state & Button4Mask) ev->b4 = 1;
3846 if (Bev.state & Button5Mask) ev->b5 = 1;
3847 if (ev->bButton == 6) ev->b6 = 1; /* on macs Button6 not in X.h */
3848 if (ev->bButton == 7) ev->b7 = 1; /* on macs Button7 not in X.h */
3849
3850 switch (ev->bButton) {
3851 case Button1:
3852 case Button2:
3853 case Button3:
3854 case Button4:
3855 case Button5:
3856 case 6:
3857 case 7:
3858 default:
3859 SUMA_LH("ButtonPress %d not known", ev->bButton);
3860 break;
3861 }
3862
3863 /* trap for double click */
3864 if (Bev.time - lev.bTime < SUMA_DOUBLE_CLICK_MAX_DELAY) {
3865 ev->DoubleClick = YUP;
3866 } else {
3867 ev->DoubleClick = NOPE;
3868 }
3869
3870 if ( SUMAg_CF->SwapButtons_1_3 ||
3871 (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
3872 int kk=ev->b1;
3873 ev->b1 = ev->b3;
3874 ev->b3 = kk;
3875 }
3876
3877 break;
3878 case ButtonRelease:
3879 ev->mTime = 0;
3880 if (Bev.state & Button1Mask) ev->b1 = 1;
3881 if (Bev.state & Button2Mask) ev->b2 = 1;
3882 if (Bev.state & Button3Mask) ev->b3 = 1;
3883 if (Bev.state & Button4Mask) ev->b4 = 1;
3884 if (Bev.state & Button5Mask) ev->b5 = 1;
3885 if (ev->bButton == 6) ev->b6 = 1; /* on macs Button6 not in X.h */
3886 if (ev->bButton == 7) ev->b7 = 1; /* on macs Button7 not in X.h */
3887
3888 if (SUMAg_CF->SwapButtons_1_3 ||
3889 (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
3890 int kk=ev->b1;
3891 ev->b1 = ev->b3;
3892 ev->b3 = kk;
3893 }
3894 break;
3895
3896 case MotionNotify:
3897 if (Mev.state & Button1MotionMask) ev->b1m = 1;
3898 if (Mev.state & Button2MotionMask) ev->b2m = 1;
3899 if (Mev.state & Button3MotionMask) ev->b3m = 1;
3900 if (Mev.state & Button4MotionMask) ev->b4m = 1;
3901 if (Mev.state & Button5MotionMask) ev->b5m = 1;
3902 if (Mev.state) { SUMA_LH(" Something mot\n"); }
3903
3904 /* The conditions and new assignments of mButton
3905 below is stupid. But I won't touch it until I
3906 have to. Reassignments should be to b1m, b2m, etc.
3907 mButton should not be touched.
3908 Also, there should be no need for these numerous
3909 conditions. If swapping is needed, b1m and b3m
3910 values should be swaped. Things like SUMA_Button_12_Motion
3911 should be made into functions that return an answer
3912 based on ev's contents */
3913 if ( SUMAg_CF->SwapButtons_1_3 ||
3914 (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
3915 if (((Mev.state & Button3MotionMask) &&
3916 (Mev.state & Button2MotionMask))
3917 || ((Mev.state & Button2MotionMask) && (Mev.state & ShiftMask))) {
3918 int kk=ev->b1m;
3919 ev->b1m = ev->b3m;
3920 ev->b3m = kk;
3921 ev->mButton = SUMA_Button_12_Motion;
3922 } else if(Mev.state & Button3MotionMask) {
3923 ev->mButton = SUMA_Button_1_Motion;
3924 int kk=ev->b1m;
3925 ev->b1m = ev->b3m;
3926 ev->b3m = kk;
3927 }else if(Mev.state & Button2MotionMask) {
3928 ev->mButton = SUMA_Button_2_Motion;
3929 }else if(Mev.state & Button1MotionMask) {
3930
3931 ev->mButton = SUMA_Button_3_Motion;
3932 }else {
3933 break;
3934 }
3935 } else {
3936 if (((Mev.state & Button1MotionMask) &&
3937 (Mev.state & Button2MotionMask))
3938 || ((Mev.state & Button2MotionMask) && (Mev.state & ShiftMask))) {
3939 ev->mButton = SUMA_Button_12_Motion;
3940 } else if(Mev.state & Button1MotionMask) {
3941 ev->mButton = SUMA_Button_1_Motion;
3942 }else if(Mev.state & Button2MotionMask) {
3943 ev->mButton = SUMA_Button_2_Motion;
3944 } else if(Mev.state & Button3MotionMask) {
3945 ev->mButton = SUMA_Button_3_Motion;
3946 }else {
3947 break;
3948 }
3949 }
3950 switch (ev->mButton) {
3951 case SUMA_Button_12_Motion:
3952 case SUMA_Button_2_Shift_Motion:
3953 if (ev->mTime) {
3954 ev->mDelta = Mev.time - lev.mTime;
3955 ev->mDeltaX = Mev.x - lev.mX;
3956 ev->mDeltaY = Mev.y - lev.mY;
3957 } else {
3958 ev->mDelta = 0;
3959 ev->mDeltaX = 0;
3960 ev->mDeltaY = 0;
3961 }
3962 break;
3963 case SUMA_Button_2_Motion:
3964 break;
3965 case SUMA_Button_3_Motion:
3966 break;
3967 }
3968
3969 }
3970 if (LocalHead) {
3971 SUMA_ShowEvent(ev, 0, "EventRecord:\n");
3972 SUMA_ShowEvent(ev, 1, "EventRecord:\n");
3973 } else if (SUMAg_CF->Echo_KeyPress) {
3974 SUMA_ShowEvent(ev, 1, "EventRecord:\n");
3975 }
3976
3977 /* keep local copy of last event */
3978 memcpy(&lev, ev, sizeof(SUMA_EVENT));
3979
3980 SUMA_RETURN(ev);
3981 }
3982
3983 /*! Mouse and Keyboard input handler function for SUMA's viewer
3984 START shifting to SUMA_RecordEvent() and its helper functions
3985 like SUMA_Alt_Event(), etc.
3986 You should also split SUMA_input() into SUMA_input_Xevent()
3987 and SUMA_input_eng(). Where SUMA_input_Xevent() just sets
3988 SUMAg_CF->lev and SUMA_input_eng() works entirely off of
3989 SUMAg_CF->lev . This way you would be able to completely
3990 drive SUMA_input_eng() without any mouse movement/X structs
3991 etc. All you need is to manipulate the content of lev.
3992 */
SUMA_input(Widget w,XtPointer clientData,XtPointer callData)3993 void SUMA_input(Widget w, XtPointer clientData, XtPointer callData)
3994 {
3995 static char FuncName[]= {"SUMA_input"};
3996 GLwDrawingAreaCallbackStruct *cd;
3997 char buffer[10], cbuf = '\0', cbuf2='\0';
3998 KeySym keysym;
3999 int xls=-1, ntot, id = 0, ND, ip, NP;
4000 SUMA_EngineData *ED = NULL;
4001 char CommString[SUMA_MAX_COMMAND_LENGTH];
4002 char s[SUMA_MAX_STRING_LENGTH], sfield[100], sdestination[100];
4003 static char ssource[]={"suma"};
4004 int it, ii, iv3[3], hit = 0, SwasHit = 0;
4005 float **fm, fv3[3], fv15[15];
4006 XKeyEvent Kev;
4007 XButtonEvent Bev;
4008 XMotionEvent Mev;
4009 int isv;
4010 SUMA_SurfaceViewer *sv, *svi = NULL;
4011 GLfloat *glar_ColorList = NULL;
4012 static Time B1time = 0, M1time=0, M1delta=0;
4013 static int pButton, mButton, rButton;
4014 SUMA_Boolean ROI_mode;
4015 static SUMA_Boolean DoubleClick = NOPE;
4016 DList *list = NULL;
4017 DListElmt *NextElm= NULL;
4018 float bevx, bevy, mevx, mevy, wwid, whei, zc_fac, mvx_fac, mvy_fac;
4019 static int mvxlast, mvylast, mvdeltax, mvdeltay;
4020 SUMA_PROMPT_DIALOG_STRUCT *prmpt=NULL; /* Use this only to create prompt
4021 that are not to be preserved */
4022 SUMA_Boolean LocalHead = NOPE; /* local debugging messages */
4023
4024 SUMA_ENTRY;
4025
4026 /* get the callData pointer */
4027 cd = (GLwDrawingAreaCallbackStruct *) callData;
4028
4029 /* find out who's calling, only GLXAREA calls this function */
4030 SUMA_GLXAREA_WIDGET2SV(w, sv, isv);
4031 if (isv < 0) {
4032 fprintf (SUMA_STDERR,
4033 "Error %s: Failed in macro SUMA_GLXAREA_WIDGET2SV.\n", FuncName);
4034 SUMA_RETURNe;
4035 }
4036 SUMA_LH("A call from SUMA_SurfaceViewer[%d], Pointer %p\n", isv, sv);
4037
4038 /* ******** ABOUT EVENT HANDLING ************** */
4039 /* Eventually you should use the structure
4040 created by RecordEvent to decide on what was clicked
4041 and how. While a little less efficient than
4042 what is done below, RecordEvent will eventually
4043 be considerably more flexible, and easier to debug.
4044 But for now, so that visible progress can be made,
4045 I will leave button processing and queries below
4046 as is, and try to make the switch gradually */
4047
4048 SUMAg_CF->lev = SUMA_RecordEvent( cd->event, SUMAg_CF->lev);
4049
4050 Kev = *(XKeyEvent *) &cd->event->xkey; /* RickR's suggestion to comply with
4051 ANSI C, no type casting of structures July 04*/
4052 Bev = *(XButtonEvent *) &cd->event->xbutton;
4053 Mev = *(XMotionEvent *) &cd->event->xmotion;
4054
4055 /* a sample keypresses */
4056 if (SUMAg_CF->Echo_KeyPress) {
4057 if (Kev.type == KeyPress) {
4058 buffer[0] = '\0';
4059 xls = XLookupString((XKeyEvent *) cd->event, buffer, 8, &keysym, NULL);
4060 fprintf (SUMA_STDERR,"%s KeyPress char>>%s<< sym>>%d<< ",
4061 FuncName, buffer, (int)keysym);
4062 } else {
4063 fprintf (SUMA_STDERR,"%s Mouse Action: ", FuncName);
4064 }
4065 if (Kev.state & ShiftMask) {
4066 fprintf (SUMA_STDERR,"Shift ");
4067 }
4068 if (Kev.state & ControlMask){
4069 fprintf (SUMA_STDERR,"Control ");
4070 }
4071 if (Kev.state & Mod1Mask){
4072 fprintf (SUMA_STDERR,"alt ");
4073 }
4074 if (Kev.state & Mod2Mask){
4075 fprintf (SUMA_STDERR,"Mod2 (command on mac) ");
4076 }
4077 if (Kev.state & Mod3Mask){
4078 fprintf (SUMA_STDERR,"Mod3 ");
4079 }
4080 if (Kev.state & Mod4Mask){
4081 fprintf (SUMA_STDERR,"Mod4 ");
4082 }
4083 if (Kev.state & Mod5Mask){
4084 fprintf (SUMA_STDERR,"Mod5 ");
4085 }
4086 if (Kev.state & SUMA_APPLE_AltOptMask){
4087 fprintf (SUMA_STDERR,"Apple Alt/Opt ");
4088 }
4089 fprintf (SUMA_STDERR,"State %d\n\n", Kev.state);
4090 }
4091
4092 switch (Kev.type) { /* switch event type */
4093 case KeyPress:
4094 if (xls < 0) {
4095 /* avoid double call in case SUMAg_CF->Echo_KeyPress called already */
4096 xls = XLookupString((XKeyEvent *) cd->event, buffer, 8, &keysym, NULL);
4097 }
4098 /* XK_* are found in keysymdef.h */
4099 switch (keysym) { /* keysym */
4100 case XK_bracketleft: /* The left bracket */
4101 if (!SUMA_bracketleft_Key(sv, "[", "interactive")) {
4102 SUMA_S_Err("Failed in key func.");
4103 }
4104 break;
4105
4106 case XK_bracketright: /* The right bracket */
4107 if (!SUMA_bracketright_Key(sv, "]", "interactive")) {
4108 SUMA_S_Err("Failed in key func.");
4109 }
4110 break;
4111
4112 case XK_space: /* The spacebar. */
4113 if (!SUMA_space_Key(sv, "SPACE", "interactive")) {
4114 SUMA_S_Err("Failed in key func.");
4115 }
4116 break;
4117 /* toggle between state containing mapping reference
4118 of SO in focus and other view */
4119 {
4120 SUMA_SurfaceObject *SO = NULL, *SOmap = NULL;
4121 int curstateID = -1, nxtstateID = -1, dov_ID = -1;
4122
4123 /* make sure switching is OK */
4124 curstateID = SUMA_WhichState(sv->State, sv, sv->CurGroupName);
4125 if ((SO = SUMA_SV_Focus_SO(sv))) {
4126 if (SUMA_isLocalDomainParent (SO)) {
4127 /* get the last non mappable state in SV */
4128 if (sv->LastNonMapStateID < 0) {
4129 /* not recorded, complain and quit */
4130 SUMA_S_Warn("Nothing defined to toggle with yet.");
4131 break;
4132 }
4133
4134 SUMA_LHv("surface is inherrently mappable, "
4135 "switching to last non mappable state %d.\n",
4136 sv->LastNonMapStateID);
4137
4138 if (!SUMA_SwitchState (SUMAg_DOv, SUMAg_N_DOv, sv,
4139 sv->LastNonMapStateID, sv->CurGroupName)) {
4140 SUMA_S_Err("Failed in SUMA_SwitchState.");
4141 break;
4142 }
4143
4144 } else {/* non mappable, go to state containing reference */
4145 SUMA_LH("surface is not inherrently mappable, "
4146 "searching for mapping reference and its state.");
4147
4148 /* find SO that is mappable reference &
4149 get corresponding state ID */
4150 dov_ID = SUMA_findSO_inDOv(SO->LocalDomainParentID,
4151 SUMAg_DOv, SUMAg_N_DOv);
4152 SOmap = (SUMA_SurfaceObject *)SUMAg_DOv[dov_ID].OP;
4153 nxtstateID = SUMA_WhichState(SOmap->State, sv,
4154 sv->CurGroupName);
4155
4156 if (nxtstateID < 0) {
4157 SUMA_S_Err("Failed in SUMA_findSO_inDOv."
4158 "This should not happen.");
4159 break;
4160 }
4161
4162 SUMA_LHv("Found mapping reference in viewer state %d.\n",
4163 nxtstateID);
4164
4165 /* store this location */
4166 sv->LastNonMapStateID = curstateID;
4167
4168 /* go there */
4169 if (!SUMA_SwitchState (SUMAg_DOv, SUMAg_N_DOv, sv,
4170 nxtstateID, sv->CurGroupName)) {
4171 SUMA_S_Err("Failed in SUMA_SwitchState.");
4172 break;
4173 }
4174 }
4175 }
4176 }
4177 SUMA_postRedisplay(w, clientData, callData);
4178 break;
4179
4180 case XK_Escape: /* there's more:
4181 XK_BackSpace XK_Tab XK_Linefeed XK_Return XK_Delete */
4182 /* control mask and escape is grabbed by gnome window manager .... */
4183 if (Kev.state & ShiftMask){/* kill all */
4184 if( SUMAg_CF->X->WarnClose) {
4185 if (SUMA_ForceUser_YesNo(sv->X->TOPLEVEL,
4186 "Close All Viewers?", SUMA_YES,
4187 SWP_DONT_CARE) != SUMA_YES) {
4188 break;
4189 }
4190 }
4191 XtCloseDisplay( SUMAg_CF->X->DPY_controller1 ) ;
4192 exit(0);
4193 }else {
4194 if( SUMAg_CF->X->WarnClose) {
4195 #ifdef DARWIN
4196 if (SUMA_ForceUser_YesNo(sv->X->TOPLEVEL,
4197 "Close This Viewer?\n"
4198 "OS-X users: If answering YES,\n"
4199 "this prompt should not lie \n"
4200 "over viewer to be closed.\n"
4201 "Blame Bill Gates for this bug.",
4202 SUMA_YES, SWP_TOP_RIGHT) != SUMA_YES) {
4203 break;
4204 }
4205 #else
4206 if (SUMA_ForceUser_YesNo(sv->X->TOPLEVEL,
4207 "Close This Viewer?", SUMA_YES,
4208 SWP_DONT_CARE) != SUMA_YES) {
4209 break;
4210 }
4211 #endif
4212 }
4213 SUMA_ButtClose_pushed (w, clientData, callData);
4214 }
4215 break;
4216
4217 case XK_a:
4218 if (!SUMA_A_Key(sv, "a", "interactive")) {
4219 SUMA_S_Err("Failed in key func.");
4220 }
4221 break;
4222
4223 case XK_B:
4224 if (( Kev.state & ControlMask)){
4225 if (SUMAg_CF->Dev ) {
4226 if (!SUMA_B_Key(sv, "ctrl+B", "interactive")) {
4227 SUMA_S_Err("Failed in key func.");
4228 }
4229 }
4230 } else {
4231 if (!SUMA_B_Key(sv, "B", "interactive")) {
4232 SUMA_S_Err("Failed in key func.");
4233 }
4234 }
4235 break;
4236
4237 case XK_b:
4238 if (!SUMA_B_Key(sv, "b", "interactive")) {
4239 SUMA_S_Err("Failed in key func.");
4240 }
4241 break;
4242
4243 case XK_C:
4244 if (SUMAg_CF->Dev && (SUMA_ALTHELL)){
4245 SUMAg_CF->X->ClipObj_prmpt =
4246 SUMA_CreatePromptDialogStruct (SUMA_OK_APPLY_CLEAR_CANCEL,
4247 "Enter object clip plane parameters (a,b,c,d)",
4248 "A: 0,0,1,0",
4249 sv->X->TOPLEVEL, YUP,
4250 SUMA_APPLY_BUTTON,
4251 SUMA_SetObjectClip, (void *)sv,
4252 NULL, NULL,
4253 NULL, NULL,
4254 NULL, NULL,
4255 SUMAg_CF->X->ClipObj_prmpt);
4256
4257 SUMAg_CF->X->ClipObj_prmpt =
4258 SUMA_CreatePromptDialog(
4259 "Enter object clip plane parameters (a,b,c,d)",
4260 SUMAg_CF->X->ClipObj_prmpt);
4261 } else if (SUMAg_CF->Dev && (Kev.state & ControlMask)){
4262 SUMAg_CF->X->Clip_prmpt =
4263 SUMA_CreatePromptDialogStruct (SUMA_OK_APPLY_CLEAR_CANCEL,
4264 "Enter screen clip plane parameters (a,b,c,d)",
4265 "A: 0,0,1,0",
4266 sv->X->TOPLEVEL, YUP,
4267 SUMA_APPLY_BUTTON,
4268 SUMA_SetScreenClip, (void *)sv,
4269 NULL, NULL,
4270 NULL, NULL,
4271 NULL, NULL,
4272 SUMAg_CF->X->Clip_prmpt);
4273
4274 SUMAg_CF->X->Clip_prmpt =
4275 SUMA_CreatePromptDialog(
4276 "Enter screen clip plane parameters (a,b,c,d)",
4277 SUMAg_CF->X->Clip_prmpt);
4278 }
4279 break;
4280 case XK_c:
4281 {
4282 SUMA_SurfaceObject *SO=NULL;
4283 if ((SO = SUMA_SV_Focus_SO(sv))) {
4284 if (!list) list = SUMA_CreateList();
4285 ED = SUMA_InitializeEngineListData (SE_OpenColFileSelection);
4286 if (!(NextElm = SUMA_RegisterEngineListCommand ( list, ED,
4287 SEF_vp, (void *)SO,
4288 SES_Suma, (void *)sv, NOPE,
4289 SEI_Head, NULL))) {
4290 SUMA_S_Err("Failed to register command.");
4291 }
4292
4293 if (!SUMA_RegisterEngineListCommand ( list, ED,
4294 SEF_ip, sv->X->TOPLEVEL,
4295 SES_Suma, (void *)sv, NOPE,
4296 SEI_In, NextElm)) {
4297 SUMA_S_Err("Failed to register command.");
4298 }
4299
4300 if (!SUMA_Engine (&list)) {
4301 fprintf(SUMA_STDERR,
4302 "Error %s: SUMA_Engine call failed.\n", FuncName);
4303 }
4304 }
4305 }
4306
4307 break;
4308
4309 #if 0
4310 /* THE OLD WAY (part of it) FOR SETTING NODE COLORS DIRECTLY,
4311 Left here for documentation */
4312 /* allocate space */
4313 fm = (float **)SUMA_allocate2D (ntot/4, 4, sizeof(float));
4314 if (fm == NULL) {
4315 fprintf(stderr,
4316 "Error SUMA_input: Failed to allocate space for fm\n");
4317 SUMA_RETURNe;
4318 }
4319
4320 if (SUMA_Read_2Dfile (s, fm, 4, ntot/4) != ntot/4 ) {
4321 fprintf(stderr,
4322 "SUMA_input Error: Failed to read full matrix from %s\n",
4323 s);
4324 SUMA_RETURNe;
4325 }
4326
4327 if (!list) list = SUMA_CreateList();
4328 ED = SUMA_InitializeEngineListData (SE_SetNodeColor);
4329 ED->N_cols = 4;
4330 ED->N_rows = ntot/4;
4331 if (!SUMA_RegisterEngineListCommand ( list, ED,
4332 SEF_fm, (void*)fm,
4333 SES_Suma, (void *)sv, YUP,
4334 SEI_Head, NULL)) {
4335 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n",
4336 FuncName);
4337 break;
4338 }
4339
4340
4341 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
4342
4343 if (!SUMA_Engine (&list)) {
4344 fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n",
4345 FuncName);
4346 }
4347
4348 /* free fm since it was registered by pointer and is not
4349 automatically freed after the call to SUMA_Engine */
4350 if (fm) SUMA_free2D ((char **)fm, ntot/4);
4351 break;
4352 #endif
4353
4354 case XK_D:
4355 if (1) {
4356 if (SUMA_ALTHELL){
4357 /* Mod1Mask is alt in linux, Mod2Mask is the apple on mac*/
4358 } else {
4359 if (!SUMA_D_Key(sv,"D", "interactive")) {
4360 SUMA_S_Err("Failed in key func.");
4361 }
4362 }
4363 }
4364 break;
4365
4366 case XK_d:
4367 if (SUMAg_CF->Dev) {
4368 if (SUMA_ALTHELL){
4369 /* Mod1Mask is alt in linux, Mod2Mask is the apple on mac*/
4370 } else {
4371 if (!SUMA_D_Key(sv,"d", "interactive")) {
4372 SUMA_S_Err("Failed in key func.");
4373 }
4374 }
4375 }
4376 break;
4377
4378 case XK_e:
4379 case XK_dead_acute: /* that is alt/option+e on macs
4380 XK_dead_acute is 0xfe51 or decimal 65105 */
4381 if (SUMAg_CF->Dev) {
4382 if (SUMA_ALTHELL){ /* Mod1Mask is alt in linux,
4383 Mod2Mask is the apple on mac*/
4384 SUMA_GL_ERRS;
4385 }
4386 }
4387 break;
4388
4389 case XK_F:
4390 /* flip light position */
4391 if (!list) list = SUMA_CreateList();
4392 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_FlipLight0Pos,
4393 SES_Suma, sv);
4394 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
4395
4396 if (!SUMA_Engine (&list)) {
4397 fprintf(stderr, "Error SUMA_input: SUMA_Engine call failed.\n");
4398 }
4399 break;
4400
4401 case XK_f:
4402 /* Show/hide the foreground */
4403 if (!list) list = SUMA_CreateList();
4404 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_ToggleForeground,
4405 SES_Suma, sv);
4406 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
4407
4408 if (!SUMA_Engine (&list)) {
4409 fprintf(stderr, "Error SUMA_input: SUMA_Engine call failed.\n");
4410 }
4411 break;
4412
4413 case XK_H:
4414 sv->X->HighlightBox_prmpt =
4415 SUMA_CreatePromptDialogStruct(SUMA_OK_APPLY_CLEAR_CANCEL,
4416 "Enter XYZ of box's center\n"
4417 "followed by it's size (6 values)",
4418 "",
4419 sv->X->TOPLEVEL, YUP,
4420 SUMA_APPLY_BUTTON,
4421 SUMA_HighlightBox, (void *)sv,
4422 NULL, NULL,
4423 NULL, NULL,
4424 SUMA_CleanNumString, (void*)6,
4425 sv->X->HighlightBox_prmpt);
4426
4427 sv->X->HighlightBox_prmpt = SUMA_CreatePromptDialog(sv->X->Title,
4428 sv->X->HighlightBox_prmpt);
4429
4430 break;
4431 case XK_g:
4432 if (Kev.state & ControlMask){
4433 if (SUMAg_CF->Dev) {
4434 if (!SUMA_G_Key(sv, "ctrl+g", "interactive")) {
4435 SUMA_S_Err("Failed in key func.");
4436 }
4437 }
4438 } else {
4439 if (!SUMA_G_Key(sv, "g", "interactive")) {
4440 SUMA_S_Err("Failed in key func.");
4441 }
4442 }
4443 break;
4444 case XK_h:
4445 if (Kev.state & ControlMask){
4446 if (!list) list = SUMA_CreateList();
4447 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Help, SES_Suma, NULL);
4448 if (!SUMA_Engine (&list)) {
4449 fprintf( stderr,
4450 "Error %s: SUMA_Engine call failed.\n", FuncName);
4451 }
4452 }else{
4453 if (SUMAg_CF->Dev) {
4454 SUMA_SLP_Note("Please use ctrl+h for help.\n"
4455 "h alone will be reassigned\n"
4456 "in future versions.");
4457 }
4458 }
4459 break;
4460
4461 case XK_j:
4462 if (Kev.state & ControlMask){
4463 if (!SUMA_J_Key(sv, "ctrl+j", "interactive", NULL)) {
4464 SUMA_S_Err("Failed in key func.");
4465 }
4466 } else if (SUMA_ALTHELL){
4467 if (!SUMA_J_Key(sv, "alt+j", "interactive", NULL)) {
4468 SUMA_S_Err("Failed in key func.");
4469 }
4470 } else {
4471 if (!SUMA_J_Key(sv, "j", "interactive", NULL)) {
4472 SUMA_S_Err("Failed in key func.");
4473 }
4474 }
4475 break;
4476
4477 case XK_J:
4478 if (!SUMA_J_Key(sv, "J", "interactive", NULL)) {
4479 SUMA_S_Err("Failed in key func.");
4480 }
4481 break;
4482
4483 case XK_l:
4484 if (Kev.state & ControlMask){
4485 if (!SUMA_L_Key(sv, "ctrl+l", "interactive", NULL)) {
4486 SUMA_S_Err("Failed in key func.");
4487 }
4488 } else if (SUMA_ALTHELL){
4489 if (!SUMA_L_Key(sv, "alt+l", "interactive", NULL)) {
4490 SUMA_S_Err("Failed in key func.");
4491 }
4492 } else {
4493 if (!SUMA_L_Key(sv, "l", "interactive", NULL)) {
4494 SUMA_S_Err("Failed in key func.");
4495 }
4496 }
4497 break;
4498
4499 case XK_L:
4500 if (Kev.state & ControlMask){
4501 if (!SUMA_L_Key(sv, "ctrl+L", "interactive", NULL)) {
4502 SUMA_S_Err("Failed in key func.");
4503 }
4504 } else if (SUMA_ALTHELL){
4505 if (!SUMA_L_Key(sv, "alt+L", "interactive", NULL)) {
4506 SUMA_S_Err("Failed in key func.");
4507 }
4508 } else {
4509 if (!SUMA_L_Key(sv, "L", "interactive", NULL)) {
4510 SUMA_S_Err("Failed in key func.");
4511 }
4512 }
4513 break;
4514
4515 case XK_M:
4516 if ((SUMA_ALTHELL) && (Kev.state & ControlMask) ){
4517 if (!SUMA_M_Key(sv, "alt+ctrl+M", "interactive")) {
4518 SUMA_S_Err("Failed in key func.");
4519 }
4520 }
4521 break;
4522
4523 case XK_m:
4524 if (Kev.state & ControlMask){
4525 if (SUMAg_CF->Dev) {
4526 if (!SUMA_M_Key(sv, "ctrl+m", "interactive")) {
4527 SUMA_S_Err("Failed in key func.");
4528 }
4529 }
4530 } else {
4531 if (!SUMA_M_Key(sv, "m", "interactive")) {
4532 SUMA_S_Err("Failed in key func.");
4533 }
4534 }
4535 break;
4536
4537 case XK_n:
4538 if (Kev.state & ControlMask){
4539 SUMA_LH("Going to N_Key");
4540 if (!SUMA_N_Key(sv, "ctrl+n", "interactive")) {
4541 SUMA_S_Err("Failed in key func.");
4542 }
4543 }else {
4544 if (SUMAg_CF->Dev) {
4545 if (!SUMA_N_Key(sv, "n", "interactive")) {
4546 SUMA_S_Err("Failed in key func.");
4547 }
4548 }
4549 }
4550 break;
4551 case XK_o:
4552 if (SUMA_ALTHELL) {
4553 if (!SUMA_O_Key(sv, "alt+o", "interactive")) {
4554 SUMA_S_Err("Failed in key func.");
4555 }
4556 } else if (Kev.state & ControlMask){
4557 if (!SUMA_O_Key(sv, "ctrl+o", "interactive")) {
4558 SUMA_S_Err("Failed in key func.");
4559 }
4560 } else {
4561 if (!SUMA_O_Key(sv, "o", "interactive")) {
4562 SUMA_S_Err("Failed in key func.");
4563 }
4564 }
4565 break;
4566 case XK_O:
4567 if (SUMA_ALTHELL) {
4568 if (!SUMA_O_Key(sv, "alt+O", "interactive")) {
4569 SUMA_S_Err("Failed in key func.");
4570 }
4571 } else if (Kev.state & ControlMask){
4572 if (!SUMA_O_Key(sv, "ctrl+O", "interactive")) {
4573 SUMA_S_Err("Failed in key func.");
4574 }
4575 } else {
4576 if (!SUMA_O_Key(sv, "O", "interactive")) {
4577 SUMA_S_Err("Failed in key func.");
4578 }
4579 }
4580 break;
4581 case XK_p:
4582 if (Kev.state & ControlMask){
4583 if (!SUMA_P_Key(sv, "ctrl+p", "interactive")) {
4584 SUMA_S_Err("Failed in key func.");
4585 }
4586 } else {
4587 if (!SUMA_P_Key(sv, "p", "interactive")) {
4588 SUMA_S_Err("Failed in key func.");
4589 }
4590 }
4591 break;
4592
4593 case XK_P:
4594 if (!SUMA_P_Key(sv, "P", "interactive")) {
4595 SUMA_S_Err("Failed in key func.");
4596 }
4597 break;
4598
4599 case XK_r:
4600 if (SUMA_ALTHELL) {
4601 if (!SUMA_R_Key(sv, "alt+r", "interactive")) {
4602 SUMA_S_Err("Failed in key func.");
4603 }
4604 } else if (Kev.state & ControlMask){
4605 if (!SUMA_R_Key(sv, "ctrl+r", "interactive")) {
4606 SUMA_S_Err("Failed in key func.");
4607 }
4608 } else {
4609 if (!SUMA_R_Key(sv, "r", "interactive")) {
4610 SUMA_S_Err("Failed in key func.");
4611 }
4612 }
4613 break;
4614
4615 case XK_R:
4616 if (Kev.state & ControlMask){
4617 if (!SUMA_R_Key(sv, "ctrl+R", "interactive")) {
4618 SUMA_S_Err("Failed in key func.");
4619 }
4620 } else {
4621 if (!SUMA_R_Key(sv, "R", "interactive")) {
4622 SUMA_S_Err("Failed in key func.");
4623 }
4624 }
4625 break;
4626
4627 case XK_S:
4628 if (SUMAg_CF->Dev) {
4629 int *do_id, n_do_id;
4630 do_id = SUMA_GetDO_Type(SUMAg_DOv, SUMAg_N_DOv,
4631 SO_type, &n_do_id);
4632 if (n_do_id) {
4633 while (n_do_id) {
4634 SUMA_Print_Surface_Object(
4635 (SUMA_SurfaceObject *)SUMAg_DOv[do_id[n_do_id-1]].OP,
4636 stdout);
4637 --n_do_id;
4638 }
4639 SUMA_free(do_id);
4640 }
4641 break;
4642 }
4643
4644 case XK_s:
4645 if ((SUMA_ALTHELL) && (Kev.state & ControlMask) ){
4646 if (!list) list = SUMA_CreateList();
4647 ED = SUMA_InitializeEngineListData (SE_LoadSegDO);
4648 if (!SUMA_RegisterEngineListCommand ( list, ED,
4649 SEF_ip, sv->X->TOPLEVEL,
4650 SES_Suma, (void *)sv, NOPE,
4651 SEI_Head, NULL)) {
4652 fprintf (SUMA_STDERR,
4653 "Error %s: Failed to register command.\n", FuncName);
4654 }
4655 if (!SUMA_Engine (&list)) {
4656 fprintf( SUMA_STDERR,
4657 "Error %s: SUMA_Engine call failed.\n",
4658 FuncName);
4659 }
4660
4661 } else if (SUMA_ALTHELL){
4662 /* swap buttons 1 and 3 */
4663 SUMAg_CF->SwapButtons_1_3 = !SUMAg_CF->SwapButtons_1_3;
4664 if (SUMAg_CF->SwapButtons_1_3) {
4665 fprintf (SUMA_STDOUT,
4666 "%s: Buttons 1 and 3 are swapped.\n", FuncName);
4667 } else {
4668 fprintf (SUMA_STDOUT,
4669 "%s: Default functions for buttons 1 and 3.\n",
4670 FuncName);
4671 }
4672 } else if (SUMAg_CF->Dev) {
4673 #if 0
4674 /** Feb 03/03 No longer in use.*/
4675 for (ii=0; ii< sv->N_DO; ++ii) {
4676 if (SUMA_isSO(SUMAg_DOv[sv->RegisteredDO[ii]]))
4677 SUMA_Print_Surface_Object(
4678 (SUMA_SurfaceObject*)SUMAg_DOv[sv->RegisteredDO[ii]].OP,
4679 stdout);
4680 }
4681 #endif
4682 }
4683 break;
4684
4685 case XK_t:
4686 if ((Kev.state & ControlMask)){
4687 if (!SUMA_T_Key(sv, "ctrl+t", "interactive")) {
4688 SUMA_S_Err("Failed in key func.");
4689 }
4690 } else {
4691 if (!SUMA_T_Key(sv, "t", "interactive")) {
4692 SUMA_S_Err("Failed in key func.");
4693 }
4694 }
4695 break;
4696
4697 case XK_T:
4698 if (!SUMA_T_Key(sv, "T", "interactive")) {
4699 SUMA_S_Err("Failed in key func.");
4700 }
4701 break;
4702
4703 case XK_u:
4704 if (!SUMA_U_Key(sv, "u", "interactive")) {
4705 SUMA_S_Err("Failed in key func.");
4706 }
4707 break;
4708 case XK_U:
4709 if (!SUMA_U_Key(sv, "U", "interactive")) {
4710 SUMA_S_Err("Failed in key func.");
4711 }
4712 break;
4713 case XK_v:
4714 #if 0
4715 /*** No longer in use, Jan 03 2004 */
4716 if (SUMAg_CF->Dev) {
4717 SUMA_Show_SurfaceViewer_Struct (sv, stdout, 0);
4718 }
4719 #endif
4720 break;
4721
4722 case XK_W:
4723 if ((Kev.state & ControlMask)){
4724 if (!SUMA_W_Key(sv, "ctrl+W", "interactive")) {
4725 SUMA_S_Err("Failed in key func.");
4726 }
4727 } else {
4728 if (!SUMA_W_Key(sv, "W", "interactive")) {
4729 SUMA_S_Err("Failed in key func.");
4730 }
4731 }
4732 break;
4733
4734 case XK_w:
4735 if (!SUMA_W_Key(sv, "w", "interactive")) {
4736 SUMA_S_Err("Failed in key func.");
4737 }
4738 break;
4739
4740 break;
4741
4742 case XK_Z:
4743 if (!SUMA_Z_Key(sv, "Z", "interactive")) {
4744 SUMA_S_Err("Failed in key func.");
4745 }
4746 break;
4747
4748 case XK_z:
4749 if (!SUMA_Z_Key(sv, "z", "interactive")) {
4750 SUMA_S_Err("Failed in key func.");
4751 }
4752 break;
4753
4754 #if 0
4755 case XK_3:
4756 sv->Do_3Drender = !sv->Do_3Drender;
4757 SUMA_S_Notev("!!!!!!!!!!!!!!%d!!!!!!!\n", sv->Do_3Drender);
4758 break;
4759 #endif
4760 case XK_8:
4761 {
4762 char stmp[100];
4763 sprintf(stmp, "%d", SUMAg_CF->X->NumForeSmoothing);
4764 SUMAg_CF->X->N_ForeSmooth_prmpt =
4765 SUMA_CreatePromptDialogStruct (SUMA_OK_APPLY_CLEAR_CANCEL,
4766 "Foreground smoothing iterations",
4767 stmp,
4768 sv->X->TOPLEVEL, YUP,
4769 SUMA_APPLY_BUTTON,
4770 SUMA_SetNumForeSmoothing, (void *)sv,
4771 NULL, NULL,
4772 NULL, NULL,
4773 SUMA_CleanNumString, (void*)1,
4774 SUMAg_CF->X->N_ForeSmooth_prmpt);
4775
4776 SUMAg_CF->X->N_ForeSmooth_prmpt =
4777 SUMA_CreatePromptDialog("Foreground smoothing iterations",
4778 SUMAg_CF->X->N_ForeSmooth_prmpt);
4779 }
4780 break;
4781
4782 case XK_asterisk:
4783 {
4784 char stmp[100];
4785 sprintf(stmp, "%d", SUMAg_CF->X->NumFinalSmoothing);
4786 SUMAg_CF->X->N_FinalSmooth_prmpt =
4787 SUMA_CreatePromptDialogStruct (SUMA_OK_APPLY_CLEAR_CANCEL,
4788 "Final color smoothing iterations",
4789 stmp,
4790 sv->X->TOPLEVEL, YUP,
4791 SUMA_APPLY_BUTTON,
4792 SUMA_SetNumFinalSmoothing, (void *)sv,
4793 NULL, NULL,
4794 NULL, NULL,
4795 SUMA_CleanNumString, (void*)1, SUMAg_CF->X->N_FinalSmooth_prmpt);
4796
4797 SUMAg_CF->X->N_FinalSmooth_prmpt =
4798 SUMA_CreatePromptDialog("Final color smoothing iterations",
4799 SUMAg_CF->X->N_FinalSmooth_prmpt);
4800 }
4801 break;
4802
4803 case XK_at:
4804 if (SUMAg_CF->Dev) {
4805 SUMA_SurfaceObject *SO=NULL;
4806 /* calculate the curvature */
4807 fprintf(SUMA_STDOUT,
4808 "%s: Calculating surface curvature ...\n", FuncName);
4809 if ((SO = SUMA_SV_Focus_SO(sv))){
4810 if (!SO->PolyArea) {
4811 fprintf(SUMA_STDOUT,
4812 "%s: Computing required mesh area.\n", FuncName);
4813 if (!SUMA_SurfaceMetrics (SO, "PolyArea", NULL)) {
4814 fprintf (SUMA_STDERR,
4815 "Error %s: Failed in SUMA_SurfaceMetrics.\n",
4816 FuncName);
4817 break;
4818 }
4819 }
4820 SO->SC = SUMA_Surface_Curvature (SO->NodeList, SO->N_Node,
4821 SO->NodeNormList, SO->PolyArea,
4822 SO->N_FaceSet, SO->FN, SO->EL, "Curvs_c.txt", 1);
4823 if (SO->SC == NULL) {
4824 fprintf( stderr,
4825 "Error %s: Failed in SUMA_Surface_Curvature\n",
4826 FuncName);
4827 break;
4828 }
4829 }
4830 }
4831 break;
4832
4833 case XK_parenleft:
4834 if (SUMAg_CF->Dev) {
4835 SUMA_SurfaceObject *SO;
4836 SUMA_COLOR_MAP *CM;
4837 SUMA_SCALE_TO_MAP_OPT * OptScl;
4838 int MapType;
4839 SUMA_COLOR_SCALED_VECT * SV;
4840 float IntRange[2], *Vsort;
4841 float * attr_sm;
4842 float *Cx = NULL;
4843
4844 fprintf(SUMA_STDOUT, "%s: Calculating convexity ...\n", FuncName);
4845 if ((SO = SUMA_SV_Focus_SO(sv))) {
4846 Cx = (float *)SUMA_GetCx(SO->idcode_str,
4847 SUMAg_CF->DsetList, 0);
4848 if (Cx) {
4849 SUMA_S_Err("Cx must be null prior to new assignment");
4850 break;
4851 }
4852 Cx = SUMA_Convexity ( SO->NodeList, SO->N_Node,
4853 SO->NodeNormList, SO->FN, NULL);
4854 if (Cx == NULL) {
4855 fprintf(stderr,"Error %s: Failed in SUMA_Convexity\n",
4856 FuncName);
4857 break;
4858 }
4859 /* smooth estimate twice */
4860 attr_sm = SUMA_SmoothAttr_Neighb (Cx, SO->N_Node, NULL,
4861 SO->FN, 1, NULL, 1);
4862 if (attr_sm == NULL) {
4863 fprintf(stderr,
4864 "Error %s: Failed in SUMA_SmoothAttr_Neighb\n",
4865 FuncName);
4866 break;
4867 }
4868 Cx = SUMA_SmoothAttr_Neighb (attr_sm, SO->N_Node, Cx,
4869 SO->FN, 1, NULL, 1);
4870 if (attr_sm) SUMA_free(attr_sm);
4871
4872 fprintf( SUMA_STDOUT,
4873 "%s: Use SUMA_ScaleToMap to colorize Conv.txt "
4874 "and display it on surface.\n", FuncName);
4875 CM = SUMA_FindNamedColMap ("ngray20");
4876 if (CM == NULL) {
4877 fprintf (SUMA_STDERR,
4878 "Error %s: Could not get standard colormap.\n",
4879 FuncName);
4880 exit (1);
4881 }
4882
4883 /* get the options for creating the scaled color mapping */
4884 OptScl = SUMA_ScaleToMapOptInit();
4885 if (!OptScl) {
4886 SUMA_S_Err("Could not get scaling option structure.");
4887 exit (1);
4888 }
4889
4890 /* work the options a bit */
4891 OptScl->ApplyClip = YUP;
4892 IntRange[0] = 5; IntRange[1] = 95; /* percentile clip range*/
4893 Vsort = SUMA_PercRange (Cx, NULL, SO->N_Node,
4894 IntRange, IntRange, NULL);
4895 OptScl->IntRange[0] = IntRange[0];
4896 OptScl->IntRange[1] = IntRange[1];
4897
4898 OptScl->BrightFact = 0.4;
4899
4900 /* map the values in Cx to the colormap */
4901 /* allocate space for the result */
4902 SV = SUMA_Create_ColorScaledVect(SO->N_Node, 0);
4903 if (!SV) {
4904 fprintf (SUMA_STDERR,
4905 "Error %s: Could not allocate for SV.\n",
4906 FuncName);
4907 exit(1);
4908 }
4909
4910 /* finally ! */
4911 /*fprintf ( SUMA_STDERR,"%s: 1st color in map %f %f %f\n",
4912 FuncName,
4913 CM->M[0][0], CM->M[0][1],CM->M[0][2]);*/
4914 if (!SUMA_ScaleToMap (Cx, SO->N_Node, Vsort[0],
4915 Vsort[SO->N_Node-1], CM, OptScl, SV)) {
4916 fprintf (SUMA_STDERR,
4917 "Error %s: Failed in SUMA_ScaleToMap.\n",
4918 FuncName);
4919 exit(1);
4920 }
4921
4922 /* Now place SV in the color array */
4923 glar_ColorList = SUMA_GetColorList (sv, SO->idcode_str);
4924 if (!glar_ColorList) {
4925 SUMA_S_Err("NULL glar_ColorList. BAD.");
4926 break;
4927 }
4928 SUMA_RGBvec_2_GLCOLAR4(SV->cV, glar_ColorList, SO->N_Node);
4929
4930 /* free */
4931 if (Vsort) SUMA_free(Vsort);
4932 if (OptScl) SUMA_free(OptScl);
4933 if (SV) SUMA_Free_ColorScaledVect (SV);
4934 if (Cx) {
4935 SUMA_free(Cx);
4936 Cx = NULL;
4937 }
4938
4939 fprintf(SUMA_STDOUT, "%s: Convexity mapping done ...\n",
4940 FuncName);
4941 SUMA_postRedisplay(w, clientData, callData);
4942 }
4943 }
4944 break;
4945
4946 case XK_comma:
4947 if (!SUMA_comma_Key(sv, "comma", "interactive")) {
4948 SUMA_S_Err("Failed in key func.");
4949 }
4950 break;
4951
4952 case XK_period:
4953 if (!SUMA_period_Key(sv, "period", "interactive")) {
4954 SUMA_S_Err("Failed in key func.");
4955 }
4956 break;
4957
4958 case XK_F1: /* F1 */
4959 /*printf("F1\n");*/
4960 if (!SUMA_F1_Key(sv, "F1", "interactive")) {
4961 SUMA_S_Err("Failed in key func.");
4962 }
4963 break;
4964
4965 case XK_F2:
4966 /*printf("F2\n");*/
4967 if (!SUMA_F2_Key(sv, "F2", "interactive")) {
4968 SUMA_S_Err("Failed in key func.");
4969 }
4970 break;
4971
4972 case XK_F3: /* F3 */
4973 if (!SUMA_F3_Key(sv, "F3", "interactive")) {
4974 SUMA_S_Err("Failed in key func.");
4975 }
4976 break;
4977
4978 case XK_F4: /* F4 */
4979 if (!SUMA_F4_Key(sv, "F4", "interactive")) {
4980 SUMA_S_Err("Failed in key func.");
4981 }
4982 break;
4983
4984 case XK_F5: /* F5 */
4985 if (!SUMA_F5_Key(sv, "F5", "interactive")) {
4986 SUMA_S_Err("Failed in key func.");
4987 }
4988 break;
4989
4990 case XK_F6: /*F6 */
4991 if (!SUMA_F6_Key(sv, "F6", "interactive")) {
4992 SUMA_S_Err("Failed in key func.");
4993 }
4994 break;
4995
4996 case XK_F7: /*F7 */
4997 if (!SUMA_F7_Key(sv, "F7", "interactive")) {
4998 SUMA_S_Err("Failed in key func.");
4999 }
5000 break;
5001
5002 case XK_F8: /*F8 */
5003 if (!SUMA_F8_Key(sv, "F8", "interactive")) {
5004 SUMA_S_Err("Failed in key func.");
5005 }
5006 break;
5007
5008 case XK_F9: /*F9 */
5009 if (!SUMA_F9_Key(sv, "F9", "interactive")) {
5010 SUMA_S_Err("Failed in key func.");
5011 }
5012 break;
5013
5014 case XK_F10: /*F10 */
5015 if (!SUMA_F10_Key(sv, "F10", "interactive", NULL)) {
5016 SUMA_S_Err("Failed in key func.");
5017 }
5018 break;
5019 case XK_F11: /* F11 */
5020 if (!SUMA_F11_Key(sv, "F11", "interactive", NULL)) {
5021 SUMA_S_Err("Failed in key func.");
5022 }
5023 break;
5024 case XK_F12: /* F12 */
5025 if (!SUMA_F12_Key(sv, "F12", "interactive")) {
5026 SUMA_S_Err("Failed in key func.");
5027 }
5028 break;
5029 case XK_F13:
5030 if (SUMAg_CF->Dev) {
5031 DList *striplist=NULL;
5032 float Eq[4];
5033 int *Vis_IDs, N_vis;
5034 SUMA_SurfaceObject *SO=NULL;
5035 Vis_IDs = (int *)SUMA_malloc(sizeof(int)*SUMAg_N_DOv);
5036 N_vis = SUMA_VisibleSOs (sv, SUMAg_DOv, Vis_IDs, 0);
5037 if (N_vis) {
5038 SO = (SUMA_SurfaceObject *)SUMAg_DOv[Vis_IDs[0]].OP;
5039 /* Axial plane */
5040 Eq[0] = Eq[1] = 0.0; Eq[2] = 1.0; Eq[3] = -SO->Center[2];
5041 SUMA_S_Warnv("Kill me!\nEq:[%f %f %f %f], step: %f\n",
5042 Eq[0], Eq[1], Eq[2], Eq[3], SO->EL->AvgLe);
5043 striplist = SUMA_SliceAlongPlane(SO, Eq, SO->EL->AvgLe);
5044 SUMA_display_edge_striplist(striplist, &(SUMAg_SVv[0]), SO,
5045 "ShowConnectedPoints");
5046 SUMA_FREE_DLIST(striplist);
5047 }
5048 if (Vis_IDs) SUMA_free(Vis_IDs);
5049 }
5050 case XK_Home:
5051 /*printf("HOME\n");*/
5052 if (!list) list = SUMA_CreateList();
5053 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Home, SES_Suma, sv);
5054 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_FOVreset, SES_Suma, sv);
5055 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
5056 if (!SUMA_Engine (&list)) {
5057 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
5058 }
5059 break;
5060
5061 case XK_Left: /*KEY_LEFT:*/
5062 /*fprintf(stdout,"Left Key\n");*/
5063 if ((Kev.state & ControlMask) && (Kev.state & ShiftMask)) {
5064 if (!SUMA_Left_Key(sv, "ctrl+shift+left", "interactive")) {
5065 SUMA_S_Err("Error in key func.");
5066 break;
5067 }
5068 }else if (Kev.state & ShiftMask) {
5069 if (!SUMA_Left_Key(sv, "shift+left", "interactive")) {
5070 SUMA_S_Err("Error in key func.");
5071 break;
5072 }
5073 }else if (Kev.state & ControlMask){
5074 if (!SUMA_Left_Key(sv, "ctrl+left", "interactive")) {
5075 SUMA_S_Err("Error in key func.");
5076 break;
5077 }
5078 }else if (SUMA_ALTHELL) {
5079 if (!SUMA_Left_Key(sv, "alt+left", "interactive")) {
5080 SUMA_S_Err("Error in key func.");
5081 break;
5082 }
5083 }else {
5084 if (!SUMA_Left_Key(sv, "left", "interactive")) {
5085 SUMA_S_Err("Error in key func.");
5086 break;
5087 }
5088 }
5089
5090 break;
5091
5092 case XK_Right: /*KEY_RIGHT: */
5093 /*printf("Right Key\n");*/
5094 if ((Kev.state & ControlMask) && (Kev.state & ShiftMask)) {
5095 if (!SUMA_Right_Key(sv, "ctrl+shift+right", "interactive")) {
5096 SUMA_S_Err("Error in key func.");
5097 break;
5098 }
5099 }else if (Kev.state & ShiftMask) {
5100 if (!SUMA_Right_Key(sv, "shift+right", "interactive")) {
5101 SUMA_S_Err("Error in key func.");
5102 break;
5103 }
5104 }else if (Kev.state & ControlMask){
5105 if (!SUMA_Right_Key(sv, "ctrl+right", "interactive")) {
5106 SUMA_S_Err("Error in key func.");
5107 break;
5108 }
5109 }else if (SUMA_ALTHELL) {
5110 if (!SUMA_Right_Key(sv, "alt+right", "interactive")) {
5111 SUMA_S_Err("Error in key func.");
5112 break;
5113 }
5114 }else {
5115 if (!SUMA_Right_Key(sv, "right", "interactive")) {
5116 SUMA_S_Err("Error in key func.");
5117 break;
5118 }
5119 }
5120 break;
5121
5122 case XK_Down: /*KEY_DOWN*/
5123 /*printf("Down Key\n");*/
5124 if ((Kev.state & ControlMask) && (Kev.state & ShiftMask)) {
5125 if (!SUMA_Down_Key(sv, "ctrl+shift+down", "interactive")) {
5126 SUMA_S_Err("Error in key func.");
5127 break;
5128 }
5129 }else if (Kev.state & ShiftMask) {
5130 if (!SUMA_Down_Key(sv, "shift+down", "interactive")) {
5131 SUMA_S_Err("Error in key func.");
5132 break;
5133 }
5134 }else if (Kev.state & ControlMask){
5135 if (!SUMA_Down_Key(sv, "ctrl+down", "interactive")) {
5136 SUMA_S_Err("Error in key func.");
5137 break;
5138 }
5139 }else if (SUMA_ALTHELL) {
5140 if (!SUMA_Down_Key(sv, "alt+down", "interactive")) {
5141 SUMA_S_Err("Error in key func.");
5142 break;
5143 }
5144 }else {
5145 if (!SUMA_Down_Key(sv, "down", "interactive")) {
5146 SUMA_S_Err("Error in key func.");
5147 break;
5148 }
5149 }
5150
5151 break;
5152
5153 case XK_Up: /*KEY_UP*/
5154 /*printf("Up Key\n");*/
5155 if ((Kev.state & ControlMask) && (Kev.state & ShiftMask)) {
5156 if (!SUMA_Up_Key(sv, "ctrl+shift+up", "interactive")) {
5157 SUMA_S_Err("Error in key func.");
5158 break;
5159 }
5160 }else if (Kev.state & ShiftMask) {
5161 if (!SUMA_Up_Key(sv, "shift+up", "interactive")) {
5162 SUMA_S_Err("Error in key func.");
5163 break;
5164 }
5165 }else if (Kev.state & ControlMask){
5166 if (!SUMA_Up_Key(sv, "ctrl+up", "interactive")) {
5167 SUMA_S_Err("Error in key func.");
5168 break;
5169 }
5170 }else if (SUMA_ALTHELL) {
5171 if (!SUMA_Up_Key(sv, "alt+up", "interactive")) {
5172 SUMA_S_Err("Error in key func.");
5173 break;
5174 }
5175 }else {
5176 if (!SUMA_Up_Key(sv, "up", "interactive")) {
5177 SUMA_S_Err("Error in key func.");
5178 break;
5179 }
5180 }
5181 break;
5182 default:
5183 break;
5184
5185 } /* keysym */
5186 break;
5187
5188 case ButtonPress:
5189 SUMAg_CF->X->ButtonDown=1;
5190 pButton = Bev.button;
5191 SUMA_LHv("In ButtonPress Button %d, %d @ x,y=%d,%d\n",
5192 pButton, SUMAg_CF->X->ButtonDown, Bev.x, Bev.y);
5193 if ( SUMAg_CF->SwapButtons_1_3 ||
5194 (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
5195 if (pButton == Button1) pButton = Button3;
5196 else if (pButton == Button3) pButton = Button1;
5197 }
5198 if (SUMAg_CF->Echo_KeyPress) {
5199 fprintf (SUMA_STDERR,"Button Press: %d (%d,%d,%d,%d,%d)\n"
5200 , pButton, Button1, Button2, Button3, Button4,
5201 Button5);
5202 }
5203
5204 /* trap for double click */
5205 if (Bev.time - B1time < SUMA_DOUBLE_CLICK_MAX_DELAY) {
5206 if (LocalHead) fprintf(SUMA_STDERR, "%s: Double click.\n", FuncName);
5207 DoubleClick = YUP;
5208 } else {
5209 DoubleClick = NOPE;
5210 }
5211
5212
5213 if (strstr(sv->State, "GMATRIX")==sv->State) {
5214 /* For graph in matrix representation swap buttons 1 and 2 */
5215 switch (pButton) {
5216 case Button1:
5217 pButton = Button2;
5218 break;
5219 case Button2:
5220 pButton = Button1;
5221 break;
5222 }
5223 }
5224
5225
5226 B1time = Bev.time;
5227 M1time = 0;
5228 switch (pButton) { /* switch type of button Press */
5229 case Button1:
5230 if (Bev.state & Button2Mask) {
5231 /* setup initial zooming conditions */
5232 /*fprintf(SUMA_STDERR,"%s: Button 1 &2 down. New\n", FuncName); */
5233 sv->GVS[sv->StdView].zoomBegin = (float)Bev.y;
5234 sv->GVS[sv->StdView].zoomDelta = 0;
5235 }else {
5236 bevx=(float)Bev.x; bevy = (float)Bev.y;
5237 /*fprintf(SUMA_STDERR,"%s: Button 1 down. New\n", FuncName);*/
5238 /* setup initial spinning conditions */
5239 sv->GVS[sv->StdView].spinBeginX = bevx;
5240 sv->GVS[sv->StdView].spinBeginY = bevy;
5241 sv->GVS[sv->StdView].spinDeltaX = 0;
5242 sv->GVS[sv->StdView].spinDeltaY = 0;
5243 /* check to see if other viewers need to be notified */
5244 ii = SUMA_WhichSV(sv, SUMAg_SVv, SUMAg_N_SVv);
5245 if (SUMAg_CF->ViewLocked[ii]) {
5246 for (it=0; it < SUMAg_N_SVv; ++it) {
5247 svi = &SUMAg_SVv[it];
5248 if (it != ii && SUMAg_CF->ViewLocked[it]) {
5249 svi->GVS[svi->StdView].spinBeginX = bevx;
5250 svi->GVS[svi->StdView].spinBeginY = bevy;
5251 svi->GVS[svi->StdView].spinDeltaX = 0;
5252 svi->GVS[svi->StdView].spinDeltaY = 0;
5253 }
5254 }
5255 }
5256 if (DoubleClick) {
5257 if (Kev.state & ControlMask) SUMA_ResetPrying(sv);
5258 else {
5259 SUMA_HOME_QUAT(sv->StdView,
5260 sv->GVS[sv->StdView].currentQuat);
5261 SUMA_postRedisplay(w, NULL, NULL);
5262 }
5263 }
5264 }
5265 break;
5266 case Button4:
5267 case 6: /* This is shift and wheel on mac, Button6 is not in X.h ! */
5268 if (pButton==6 || Bev.state & ShiftMask) {
5269 SUMA_ALL_DO *ado=NULL;
5270 char variant[2];
5271 #if 0
5272 int ii;
5273 SUMA_VolumeObject *VO=NULL;
5274 for (ii=0; ii<SUMAg_N_DOv; ++ii) {
5275 if (SUMA_isVO(SUMAg_DOv[ii])) {
5276 VO = (SUMA_VolumeObject *)(SUMAg_DOv[ii].OP);
5277 if (VO->SelectedCutPlane >= 0) {
5278 SUMA_LHv("Moving cut plane %d\n",
5279 VO->SelectedCutPlane);
5280 if (!SUMA_MoveCutplane(VO, VO->SelectedCutPlane, 1.0)) {
5281 SUMA_SLP_Err("Bad");
5282 }
5283 }
5284 /* JB: only allow cutplane from 1st volume object,
5285 otherwise remove 'break' */
5286 break;
5287 }
5288 }
5289 SUMA_postRedisplay(w, NULL, NULL);
5290 #else
5291 if ((ado = SUMA_SV_Focus_ADO(sv))) {
5292 switch (ado->do_type) {
5293 case VO_type: {
5294 float incr = 1.0;
5295 SUMA_VolumeObject *vo=(SUMA_VolumeObject *)ado;
5296 SUMA_VOL_SAUX *VSaux = SUMA_ADO_VSaux(ado);
5297 if (VSaux && VSaux->PR) {
5298 if (SUMA_dset_gui_slice_from_tex_slice_d(vo->VE, 0,
5299 VSaux->PR->dAltSel+SUMA_VOL_SLC_EQ0,
5300 0, variant, NULL) >=0 ){
5301 SUMA_set_slice(ado, variant, &incr,
5302 "increment", 0);
5303 }
5304 }
5305 SUMA_postRedisplay(w, NULL, NULL);
5306 break; }
5307 default:
5308 SUMA_LH("Nothing here for types %s\n",
5309 ADO_TNAME(ado));
5310 break;
5311 }
5312 }
5313 #endif
5314 } else if (pButton==6 || Bev.state & ControlMask) {
5315 SUMA_ALL_DO *ado=NULL;
5316 SUMA_X_SurfCont *SurfCont;
5317 if (MASK_MANIP_MODE(sv)) {
5318 ado = SUMA_whichADOg(sv->MouseMode_ado_idcode_str);
5319 if (ado && ado->do_type == MASK_type) {
5320 SUMA_MaskDO *mdo = (SUMA_MaskDO *)ado;
5321 float fv[3];
5322 int irow=-1;
5323 {
5324 fv[0] = mdo->hdim[0]-(0.2*mdo->init_hdim[0]);
5325 fv[1] = mdo->hdim[1]-(0.2*mdo->init_hdim[1]);
5326 fv[2] = mdo->hdim[2]-(0.2*mdo->init_hdim[2]);
5327 if (fv[0] < 0 || fv[1] < 0 || fv[2] < 0) {
5328 SUMA_BEEP;
5329 break;
5330 }
5331 SUMA_MDO_New_Dim(mdo, fv);
5332 }
5333 if ((SurfCont=SUMA_ADO_Cont(ado))) {
5334 irow = SUMA_ObjectID_Row(SurfCont->MaskTable,
5335 ADO_ID(ado));
5336 if (irow >= 0) {
5337 SUMA_InitMasksTable_row(SurfCont,mdo, irow);
5338 }
5339 }
5340 SUMA_NEW_MASKSTATE();
5341 /* enough for now */
5342 goto REDISP;
5343 }
5344 } else if ((ado = SUMA_SV_Focus_ADO(sv)) &&
5345 ado->do_type == GRAPH_LINK_type &&
5346 !strcmp(SUMA_ADO_variant(ado),"GMATRIX")) {
5347 SUMA_OVERLAYS *Sover = NULL;
5348 SUMA_LH("Going forward one sub-brick");
5349 Sover = SUMA_ADO_CurColPlane(ado);
5350 SUMA_SwitchColPlaneIntensity( ado, Sover,
5351 SUMA_FORWARD_ONE_SUBBRICK, 1);
5352 /* redisplay done in function above ... */
5353 SUMA_RETURNe;
5354 }
5355 } else {
5356 if (!SUMA_Z_Key(sv, "z", "interactive")) {
5357 SUMA_S_Err("Failed in key func.");
5358 }
5359 }
5360 break;
5361 case Button5:
5362 case 7: /* This is shift and wheel on mac, Button7 is not in X.h ! */
5363 if (pButton==7 || Bev.state & ShiftMask) {
5364 SUMA_ALL_DO *ado=NULL;
5365 char variant[2];
5366 #if 0
5367 int ii;
5368 SUMA_VolumeObject *VO=NULL;
5369 for (ii=0; ii<SUMAg_N_DOv; ++ii) {
5370 if (SUMA_isVO(SUMAg_DOv[ii])) {
5371 VO = (SUMA_VolumeObject *)(SUMAg_DOv[ii].OP);
5372 if (VO->SelectedCutPlane >= 0) {
5373 SUMA_LHv("Moving cut plane %d\n",
5374 VO->SelectedCutPlane);
5375 if (!SUMA_MoveCutplane(VO, VO->SelectedCutPlane, -1.0)) {
5376 SUMA_SLP_Err("Bad");
5377 }
5378 }
5379 /* JB: only allow cutplane from 1st volume object,
5380 otherwise remove 'break' */
5381 break;
5382 }
5383 }
5384 SUMA_postRedisplay(w, NULL, NULL);
5385 #else
5386 if ((ado = SUMA_SV_Focus_ADO(sv))) {
5387 switch (ado->do_type) {
5388 case VO_type: {
5389 float incr = -1.0;
5390 SUMA_VolumeObject *vo=(SUMA_VolumeObject *)ado;
5391 SUMA_VOL_SAUX *VSaux = SUMA_ADO_VSaux(ado);
5392 if (VSaux && VSaux->PR) {
5393 if (SUMA_dset_gui_slice_from_tex_slice_d(vo->VE, 0,
5394 VSaux->PR->dAltSel+SUMA_VOL_SLC_EQ0,
5395 0, variant, NULL) >=0 ){
5396 SUMA_set_slice(ado, variant, &incr,
5397 "increment", 0);
5398 }
5399 }
5400 SUMA_postRedisplay(w, NULL, NULL);
5401 break; }
5402 default:
5403 SUMA_LH("Nothing here for types %s\n",
5404 ADO_TNAME(ado));
5405 break;
5406 }
5407 }
5408 #endif
5409 } else if (pButton==7 || Bev.state & ControlMask) {
5410 SUMA_ALL_DO *ado=NULL;
5411 SUMA_X_SurfCont *SurfCont;
5412 if (MASK_MANIP_MODE(sv)) {
5413 ado = SUMA_whichADOg(sv->MouseMode_ado_idcode_str);
5414 if (ado && ado->do_type == MASK_type) {
5415 SUMA_MaskDO *mdo = (SUMA_MaskDO *)ado;
5416 float fv[3];
5417 int irow=-1;
5418 {
5419 fv[0] = mdo->hdim[0]+(0.2*mdo->init_hdim[0]);
5420 fv[1] = mdo->hdim[1]+(0.2*mdo->init_hdim[1]);
5421 fv[2] = mdo->hdim[2]+(0.2*mdo->init_hdim[2]);
5422 SUMA_MDO_New_Dim(mdo, fv);
5423 }
5424 if ((SurfCont=SUMA_ADO_Cont(ado))) {
5425 irow = SUMA_ObjectID_Row(SurfCont->MaskTable,
5426 ADO_ID(ado));
5427 if (irow >= 0) {
5428 SUMA_InitMasksTable_row(SurfCont,mdo, irow);
5429 }
5430 }
5431 SUMA_NEW_MASKSTATE();
5432 /* enough for now */
5433 goto REDISP;
5434 }
5435 } else if ((ado = SUMA_SV_Focus_ADO(sv)) &&
5436 ado->do_type == GRAPH_LINK_type &&
5437 !strcmp(SUMA_ADO_variant(ado),"GMATRIX")) {
5438 SUMA_OVERLAYS *Sover = NULL;
5439 SUMA_LH("Switching overlay back one");
5440 Sover = SUMA_ADO_CurColPlane(ado);
5441 SUMA_SwitchColPlaneIntensity( ado, Sover,
5442 SUMA_BACK_ONE_SUBBRICK, 1);
5443 /* redisplay done in function above ... */
5444 SUMA_RETURNe;
5445 }
5446 } else {
5447 if (!SUMA_Z_Key(sv, "Z", "interactive")) {
5448 SUMA_S_Err("Failed in key func.");
5449 }
5450 }
5451 break;
5452
5453 case Button2:
5454 if (Bev.state & ShiftMask) {
5455 /* setup initial zooming conditions */
5456 /*fprintf(SUMA_STDERR,"%s: Button 2 & Shift\n", FuncName); */
5457 sv->GVS[sv->StdView].zoomBegin = (float)Bev.y;
5458 sv->GVS[sv->StdView].zoomDelta = 0;
5459 } else {
5460 /*fprintf(stdout,"Button 2 down, plain jane\n");*/
5461 /* setup initial translation conditions */
5462 bevx = (float)Bev.x; bevy = (float)Bev.y;
5463 sv->GVS[sv->StdView].translateBeginX = bevx;;
5464 sv->GVS[sv->StdView].translateBeginY = bevy;
5465 sv->GVS[sv->StdView].translateDeltaX = 0.0;
5466 sv->GVS[sv->StdView].translateDeltaY = 0.0;
5467 }
5468 break;
5469
5470 case Button3: {
5471 SUMA_LHv("Button 3 down plain jane, "
5472 "viewer #%d : X=%f, Y = %f\n",
5473 SUMA_WhichSV(sv, SUMAg_SVv, SUMAg_N_SVv),
5474 (float)Bev.x, (float)Bev.y);
5475
5476 /* Clear any pre-existing selection */
5477 if (!SUMA_Add_To_PickResult_List(sv, NULL, "TERSUM", NULL)) {
5478 SUMA_S_Err("Failed to clear selections");
5479 break;
5480 }
5481
5482 /* Bev.state does work in the line below,
5483 unlike Mev.state further down.
5484 Using Kev.state anyway because it works in both cases */
5485 if ((Kev.state & ShiftMask) && (Kev.state & ControlMask)) {
5486 SUMA_LH("Allowing callbacks");
5487 SUMAg_CF->HoldClickCallbacks = 0;
5488 } else {
5489 SUMA_LH("Holding back callbacks");
5490 SUMAg_CF->HoldClickCallbacks = 1;
5491 }
5492
5493 /* are we in ROI drawing mode ? */
5494 if ( SUMAg_CF->ROI_mode
5495 && SUMA_SV_Focus_SO(sv) && !(Bev.state & ShiftMask)) {
5496 /* ROI drawing mode */
5497 ROI_mode = YUP;
5498 } else {
5499 ROI_mode = NOPE;
5500
5501 }
5502
5503 if (!(Kev.state & ShiftMask) && (Kev.state & ControlMask)) {
5504 SUMA_LH("Yoking intensity to node selection");
5505 SUMAg_CF->YokeIntToNode = 1;
5506 } else {
5507 SUMA_LH("Holding back yoking");
5508 SUMAg_CF->YokeIntToNode = 0;
5509 }
5510
5511 SUMA_LH("Get the selection line, bitte");
5512 if (!SUMA_GetSelectionLine ( sv, (int)Bev.x, (int)Bev.y,
5513 sv->Pick0, sv->Pick1, 0,
5514 NULL, NULL, NULL)) {
5515 fprintf (SUMA_STDERR,
5516 "Error %s: Failed in SUMA_GetSelectionLine.\n",
5517 FuncName);
5518 break;
5519 }
5520
5521 if (DoubleClick && !ROI_mode){/*See if you are selecting masks */
5522 SUMA_ALL_DO *mado=NULL, *ado=NULL;
5523 SUMA_GRAPH_SAUX *GSaux=NULL;
5524 /* you do not want to waist time doing double calculations if
5525 the user clicks twice by mistake */
5526 /* make sure no viewer, other than the one clicked in is in
5527 momentum mode */
5528 if (SUMAg_N_SVv > 1) {
5529 ii = SUMA_WhichViewerInMomentum (SUMAg_SVv,
5530 SUMAg_N_SVv, NULL);
5531 if (ii >= 0) {
5532 sprintf (s, "You cannot select or draw while viewers\n"
5533 "(like viewer %c) are in momentum mode.\n",
5534 ii+65);
5535 SUMA_RegisterMessage (SUMAg_CF->MessageList,
5536 s, FuncName, SMT_Error,
5537 SMA_LogAndPopup);
5538 SUMA_RETURNe;
5539 }
5540 }
5541
5542 /* Any hits for masks? */
5543 hit = SUMA_ComputeLineMaskIntersect (sv, SUMAg_DOv, 0, &mado);
5544 if (hit < 0) {
5545 SUMA_S_Err("Failed in SUMA_ComputeLineMaskIntersect.");
5546 } else if (hit > 0) {
5547 SUMA_LH("Mask was double clicked");
5548 if (!MASK_MANIP_MODE(sv)) {
5549 SUMA_S_Note("Turning on mask manip mode");
5550 if (!SUMA_SetMouseMode(sv,SUMA_MASK_MANIP_MMODE,
5551 (void *)(ADO_ID(mado)))) {
5552 SUMA_S_Warn("Mask manip mode could not be set");
5553 }
5554 } else {
5555 SUMA_S_Note("Turning off mask manip mode");
5556 if (!SUMA_SetMouseMode(sv,SUMA_MASK_MANIP_MMODE,NULL)) {
5557 SUMA_S_Warn("Mask manip mode could not be set");
5558 }
5559 }
5560 /* Not much else to do */
5561 goto REDISP;
5562 } else if (MASK_MANIP_MODE(sv)) { /* turn it off */
5563 SUMA_S_Note("Turning off mask manip mode");
5564 if (!SUMA_SetMouseMode(sv,SUMA_MASK_MANIP_MMODE,NULL)) {
5565 SUMA_S_Warn("Mask manip mode could not be set");
5566 }
5567 /* Not much else to do */
5568 goto REDISP;
5569 } else if ((ado = SUMA_SV_Focus_ADO(sv)) &&
5570 ado->do_type == GRAPH_LINK_type &&
5571 (GSaux = SUMA_ADO_GSaux(ado)) &&
5572 GSaux->PR && GSaux->PR->datum_index == -1 &&
5573 GSaux->PR->iAltSel[SUMA_ENODE_0] != -1 &&
5574 GSaux->IgnoreSelection == 0) {
5575 /* turn off node selection to allow all connections
5576 to be visible. Execute only if we have a graph
5577 in focus (in 3D drawing) and a point is selected
5578 and selection is not being ignored*/
5579 SUMA_LH("Ignoring selection for graph display");
5580 GSaux->IgnoreSelection = 1;
5581 SUMA_FlushPickBufferForDO(ado);
5582 goto REDISP;
5583 }
5584 SUMA_LH("No mask hit, and no selection needs ignoring");
5585 }
5586
5587 if (!DoubleClick) {
5588 /* you do not want to waist time doing double calculations if
5589 the user clicks twice by mistake */
5590 /* make sure no viewer, other than the one clicked in is in
5591 momentum mode */
5592 if (SUMAg_N_SVv > 1) {
5593 ii = SUMA_WhichViewerInMomentum (SUMAg_SVv,
5594 SUMAg_N_SVv, NULL);
5595 if (ii >= 0) {
5596 sprintf (s, "You cannot select or draw while viewers\n"
5597 "(like viewer %c) are in momentum mode.\n",
5598 ii+65);
5599 SUMA_RegisterMessage (SUMAg_CF->MessageList,
5600 s, FuncName, SMT_Error,
5601 SMA_LogAndPopup);
5602 SUMA_RETURNe;
5603 }
5604 }
5605
5606 #if 0
5607 /* Try this if you are having OpenGLStateReset problems at
5608 node selection time. It is inefficient, but helps point
5609 to the problem.
5610 Look at recent updates to SE_Redisplay*All* for the more
5611 appropriate fix */
5612 SUMA_S_Note("Blunt fix:");
5613 SUMA_OpenGLStateReset(SUMAg_DOv, SUMAg_N_DOv, sv);
5614 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
5615 #endif
5616
5617 /* perform the intersection calcluation and mark the surface */
5618 SUMA_LHv("Finding hit: %d %d,\n"
5619 "Pick0: %f %f %f, Pick1: %f %f %f\n",
5620 (int)Bev.x, (int)Bev.y,
5621 sv->Pick0[0], sv->Pick0[1], sv->Pick0[2],
5622 sv->Pick1[0], sv->Pick1[1], sv->Pick1[2]);
5623
5624
5625 if (1) {
5626 hit = SUMA_ComputeLineDOsIntersect (sv, SUMAg_DOv, 0, NULL);
5627 if ( (Kev.state & ShiftMask) &&
5628 !(Kev.state & ControlMask) &&
5629 !SUMA_ALTHELL && !SUMAg_CF->ROI_mode){
5630 /* Show me the click buffer */
5631 SUMA_MarkPickInBuffer4(sv, 1, NULL);
5632 }
5633 if (hit < 0) {
5634 SUMA_S_Err("Failed in SUMA_ComputeLineDOsIntersect.");
5635 }
5636 }
5637
5638 if (1) {
5639 SUMA_LH("Trying for volume intersections");
5640 hit = SUMA_ComputeLineVOslicesIntersect(sv, SUMAg_DOv,
5641 0, NULL);
5642 if (hit < 0) {
5643 fprintf( SUMA_STDERR,
5644 "Error %s: "
5645 "Failed in SUMA_MarkLineVOslicesIntersect.\n",
5646 FuncName);
5647 }
5648 }
5649
5650 if (1) {
5651 SUMA_LH("Trying for volume VR intersections");
5652 hit = SUMA_ComputeLineVOvrIntersect(sv, SUMAg_DOv,
5653 0, NULL);
5654 if (hit < 0) {
5655 fprintf( SUMA_STDERR,
5656 "Error %s: "
5657 "Failed in SUMA_MarkLineVOvrIntersect.\n",
5658 FuncName);
5659 }
5660 }
5661 #if 0
5662 if (SUMA_ALTHELL ||
5663 SUMA_VisibleSOs(sv, SUMAg_DOv, NULL, 0) == 0) {
5664 SUMA_LH("Trying for cutplanes");
5665 hit = SUMA_MarkLineCutplaneIntersect (sv, SUMAg_DOv, 0);
5666 if (hit < 0) {
5667 fprintf( SUMA_STDERR,
5668 "Error %s: "
5669 "Failed in SUMA_MarkLineCutplaneIntersect.\n",
5670 FuncName);
5671 }
5672 }
5673 #endif
5674
5675 SUMA_LH("Checking on registered surfaces");
5676 SwasHit = 0;
5677 ii = SUMA_RegisteredSOs(sv, SUMAg_DOv, NULL);
5678 if (ii == 0) { /* no surfaces, break */
5679 SUMA_LH("No registrants");
5680 } else {
5681 /* have surfaces, find hits */
5682 hit = SUMA_ComputeLineSurfaceIntersect (sv, SUMAg_DOv,
5683 0, NULL);
5684 if (hit < 0) {
5685 SUMA_S_Err("Failed in SUMA_ComputeLineSurfaceIntersect.");
5686 } else if (hit > 0) SwasHit = 1;
5687
5688 }
5689
5690 }
5691
5692
5693 if (ROI_mode && (SwasHit || DoubleClick)) {
5694 /* keep track of mouse motion in window */
5695 if (!SUMA_CreateBrushStroke (sv)) {
5696 SUMA_RegisterMessage (SUMAg_CF->MessageList,
5697 "Failed to create BrushStroke.",
5698 FuncName,
5699 SMT_Error, SMA_LogAndPopup);
5700 SUMA_RETURNe;
5701
5702 }
5703
5704 SUMA_AddToBrushStroke (sv, (int)Bev.x, (int)Bev.y, sv->Pick0,
5705 sv->Pick1, YUP);
5706 }
5707
5708 ASSESS:
5709 SUMA_LH("Assessment %d", dlist_size(sv->SelAdo));
5710 if (dlist_size(sv->SelAdo)) {
5711 if (!SUMA_Process_Selected_ADO(sv,SUMA_ALTHELL)) {
5712 SUMA_S_Err("Failed to process selected ados");
5713 goto OUT;
5714 }
5715
5716 SUMA_LH("Calling redisplay");
5717 /* redisplay */
5718 sv->ResetGLStateVariables = YUP;
5719 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
5720 }
5721 goto OUT;
5722
5723 REDISP:
5724 SUMA_LH("Calling redisplay without assessment");
5725 sv->ResetGLStateVariables = YUP;
5726 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
5727 goto OUT;
5728
5729 OUT:
5730 /* reset hold on xforms */
5731 SUMAg_CF->HoldClickCallbacks = 0;
5732 break; }
5733 } /* switch type of button Press */
5734 break;
5735
5736 case ButtonRelease:
5737 SUMAg_CF->X->ButtonDown=0;
5738 M1time = 0;
5739 rButton = Bev.button;
5740 SUMA_LHv("In ButtonRelease Button %d %d @ x,y=%d,%d\n",
5741 rButton, SUMAg_CF->X->ButtonDown, Bev.x, Bev.y);
5742 if (SUMAg_CF->Echo_KeyPress) {
5743 fprintf (SUMA_STDERR,"Button Release: %d (%d,%d,%d,%d,%d)\n"
5744 , rButton, Button1, Button2, Button3, Button4,
5745 Button5);
5746 }
5747
5748 if (SUMAg_CF->SwapButtons_1_3 ||
5749 (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
5750 if (rButton == Button1) rButton = Button3;
5751 else if (rButton == Button3) rButton = Button1;
5752 }
5753
5754 if (strstr(sv->State, "GMATRIX")==sv->State) {
5755 /* For graph in matrix representation swap buttons 1 and 2 */
5756 switch (rButton) {
5757 case Button1:
5758 rButton = Button2;
5759 break;
5760 case Button2:
5761 rButton = Button1;
5762 break;
5763 }
5764 }
5765
5766
5767 switch (rButton) { /* switch type of button Press */
5768 case Button3:
5769 if (LocalHead)
5770 fprintf(SUMA_STDERR,"%s: In ButtonRelease3\n", FuncName);
5771
5772 if (SUMAg_CF->ROI_mode) {
5773 SUMA_DRAWN_ROI *DrawnROI = NULL;
5774 SUMA_BRUSH_STROKE_ACTION BsA=SUMA_BSA_Undefined;
5775
5776 if (sv->BS) {
5777 /* Process the brush stroke*/
5778 if (DoubleClick) BsA = SUMA_BSA_JoinEnds;
5779 else BsA = SUMA_BSA_AppendStrokeOrFill;
5780 if (!(DrawnROI = SUMA_ProcessBrushStroke (sv, BsA))) {
5781 if (LocalHead)
5782 fprintf (SUMA_STDERR,
5783 "%s: NULL DrawnROI returned.\n", FuncName);
5784 SUMA_ClearBrushStroke (sv);
5785 break;
5786 }
5787
5788 /* Showme the DrawnROI */
5789 if (LocalHead) SUMA_ShowDrawnROI (DrawnROI, NULL, NOPE);
5790
5791 /* do smething with the BrushStroke, then wipe it clean,
5792 OK to show even if empty*/
5793 if (LocalHead) SUMA_ShowBrushStroke (sv, NULL);
5794
5795 /* SUMA_DrawBrushStroke (sv, YUP); */
5796 SUMA_ClearBrushStroke (sv);
5797
5798 /* redisplay all others */
5799 if (!list) list = SUMA_CreateList ();
5800 SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list,
5801 SE_RedisplayNow_AllOtherVisible, SES_SumaWidget, sv);
5802 SUMA_Engine (&list);
5803
5804 /* redisplay .
5805 DO NOT REDISPLAY WITH SE_Redisplay_AllVisible or
5806 you will have GL state synchronization problems */
5807 sv->ResetGLStateVariables = YUP;
5808 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
5809
5810 }/* if sv->BS */
5811 } /* if SUMAg_CF->ROImode */
5812
5813 if (sv->Focus_DO_ID > 0){/* Get surface controller page in sync */
5814 if (!SUMA_IS_CONTPAGE_ON_TOP(SUMAg_CF->X->AllMaskCont)) {
5815 /* Switch only if 'sticky' mask controller page
5816 is not on top */
5817 SUMA_ALL_DO *ado = SUMA_SV_Focus_ADO(sv);
5818 if (ado) {
5819 SUMA_LHv("Will call Init for %s if %d\n",
5820 SUMA_ADO_Label(ado),
5821 SUMA_isADO_Cont_Realized(ado));
5822 if (SUMA_isADO_Cont_Realized(ado))
5823 SUMA_Init_SurfCont_SurfParam(ado);
5824 }
5825 } else {
5826 if (!SUMA_InitMasksTable(SUMAg_CF->X->AllMaskCont)) {
5827 SUMA_S_Err("Failed to initialize mask table");
5828 }
5829 }
5830 }
5831 break;
5832 case Button1:
5833 SUMA_LH("In Button 1 release\n");
5834 if (sv->GVS[sv->StdView].vLHpry0[0] !=
5835 sv->GVS[sv->StdView].vLHpry[0] ||
5836 sv->GVS[sv->StdView].vLHpry0[1] !=
5837 sv->GVS[sv->StdView].vLHpry[1] ||
5838 sv->GVS[sv->StdView].vLHpry0[2] !=
5839 sv->GVS[sv->StdView].vLHpry[2] ){
5840 /* update the normals just now, this would not be needed if
5841 SUMA_ApplyPrying has set recompute_normals = 1*/
5842 SUMA_RecomputeNormsPrying(sv);
5843 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
5844 }
5845 sv->GVS[sv->StdView].vLHpry0[0] = sv->GVS[sv->StdView].vLHpry[0];
5846 sv->GVS[sv->StdView].vLHpry0[1] = sv->GVS[sv->StdView].vLHpry[1];
5847 sv->GVS[sv->StdView].vLHpry0[2] = sv->GVS[sv->StdView].vLHpry[2];
5848 break;
5849 } /* switch type of button Press */
5850 break;
5851
5852 case MotionNotify:
5853 if (LocalHead) {
5854 fprintf(stdout,"In MotionNotify\n");
5855 if (Mev.state & Button1MotionMask) fprintf(stdout," B1 mot\n");
5856 else if (Mev.state & Button2MotionMask) fprintf(stdout," B2 mot\n");
5857 else if (Mev.state & Button3MotionMask) fprintf(stdout," B3 mot\n");
5858 else if (Mev.state & Button4MotionMask) fprintf(stdout," B4 mot\n");
5859 else if (Mev.state & Button5MotionMask) fprintf(stdout," B5 mot\n");
5860 else fprintf(stdout," Something mot, button %d\n", Bev.button);
5861 }
5862 if (SUMAg_CF->Echo_KeyPress) {
5863 if (Mev.state & Button1MotionMask)
5864 fprintf(SUMA_STDERR," B1 mot\n");
5865 else if (Mev.state & Button2MotionMask)
5866 fprintf(SUMA_STDERR," B2 mot\n");
5867 else if (Mev.state & Button3MotionMask)
5868 fprintf(SUMA_STDERR," B3 mot\n");
5869 else if (Mev.state & Button4MotionMask)
5870 fprintf(SUMA_STDERR," B4 mot\n");
5871 else if (Mev.state & Button5MotionMask)
5872 fprintf(SUMA_STDERR," B5 mot\n");
5873 else if (Mev.state) fprintf(SUMA_STDERR,
5874 " Something mot, button %d\n", Bev.button);
5875 }
5876
5877 if ( SUMAg_CF->SwapButtons_1_3 ||
5878 (SUMAg_CF->ROI_mode && SUMAg_CF->Pen_mode)) {
5879 if (((Mev.state & Button3MotionMask) && (Mev.state & Button2MotionMask))
5880 || ((Mev.state & Button2MotionMask) && (Mev.state & ShiftMask))) {
5881 mButton = SUMA_Button_12_Motion;
5882 } else if(Mev.state & Button3MotionMask) {
5883 mButton = SUMA_Button_1_Motion;
5884 }else if(Mev.state & Button2MotionMask) {
5885 mButton = SUMA_Button_2_Motion;
5886 }else if(Mev.state & Button1MotionMask) {
5887 mButton = SUMA_Button_3_Motion;
5888 }else {
5889 break;
5890 }
5891 } else {
5892 if (((Mev.state & Button1MotionMask) && (Mev.state & Button2MotionMask))
5893 || ((Mev.state & Button2MotionMask) && (Mev.state & ShiftMask))) {
5894 mButton = SUMA_Button_12_Motion;
5895 } else if(Mev.state & Button1MotionMask) {
5896 mButton = SUMA_Button_1_Motion;
5897 }else if(Mev.state & Button2MotionMask) {
5898 mButton = SUMA_Button_2_Motion;
5899 } else if(Mev.state & Button3MotionMask) {
5900 mButton = SUMA_Button_3_Motion;
5901 }else {
5902 break;
5903 }
5904 }
5905
5906 if (strstr(sv->State, "GMATRIX")==sv->State) {
5907 /* For graph in matrix representation swap buttons 1 and 2 */
5908 SUMA_LH("In graph matrix, swapping 1/2 motion");
5909 switch (mButton) {
5910 case SUMA_Button_1_Motion:
5911 mButton = SUMA_Button_2_Motion;
5912 break;
5913 case SUMA_Button_2_Motion:
5914 mButton = SUMA_Button_1_Motion;
5915 break;
5916 }
5917 }
5918
5919 switch (mButton) {
5920 case SUMA_Button_12_Motion:
5921 case SUMA_Button_2_Shift_Motion:
5922 /*fprintf(SUMA_STDERR,"%s: In motion, Butt1 & Butt2\n", FuncName);*/
5923 sv->GVS[sv->StdView].zoomDelta = 1.0 +
5924 (float)((int)Mev.y -
5925 sv->GVS[sv->StdView].zoomBegin)/MOUSE_ZOOM_FACT;
5926 if (sv->GVS[sv->StdView].zoomDelta > 2.0)
5927 sv->GVS[sv->StdView].zoomDelta = 2.0;
5928 else if (sv->GVS[sv->StdView].zoomDelta < 0.5)
5929 sv->GVS[sv->StdView].zoomDelta = 0.5;
5930 sv->FOV[sv->iState] /= sv->GVS[sv->StdView].zoomDelta;
5931 if (sv->FOV[sv->iState] < FOV_MIN) sv->FOV[sv->iState] = FOV_MIN;
5932 else if (sv->FOV[sv->iState] > FOV_MAX)
5933 sv->FOV[sv->iState] = FOV_MAX;
5934 sv->GVS[sv->StdView].zoomBegin = (float)(int)Mev.y;
5935 /*fprintf(stdout, "FOV zoom Delta = %f=n",
5936 sv->GVS[sv->StdView].zoomDelta);*/
5937 /* Now update the zoom compensation variable */
5938 if (sv->ZoomCompensate) {
5939 sv->ZoomCompensate = sqrt(sv->FOV[sv->iState] /
5940 SUMA_sv_auto_fov(sv));
5941 /* slow down compensation, with sqrt*/
5942 if (sv->ZoomCompensate > 1)
5943 sv->ZoomCompensate = 1.0;
5944 /* no need to compensate at low zooms */
5945 else if (sv->ZoomCompensate < 0.05)
5946 sv->ZoomCompensate = 0.05; /* no need to go lower */
5947 }
5948 ii = SUMA_WhichSV (sv, SUMAg_SVv, SUMAg_N_SVv);
5949 SUMA_postRedisplay(w, clientData, callData);
5950 break;
5951
5952 case SUMA_Button_1_Motion:
5953 /* fprintf(SUMA_STDERR,"%s: In motion, Butt1 \n", FuncName); */
5954 mevx = (float)Mev.x;
5955 mevy = (float)Mev.y;
5956 wwid = (float)sv->X->aWIDTH;
5957 whei = (float)sv->X->aHEIGHT;
5958 /* spinning mode */
5959 if (sv->ZoomCompensate) {
5960 zc_fac = sv->ZoomCompensate;
5961 }else {
5962 zc_fac = 1.0;
5963 }
5964 sv->GVS[sv->StdView].spinDeltaX =
5965 (mevx - sv->GVS[sv->StdView].spinBeginX);
5966 sv->GVS[sv->StdView].spinDeltaY =
5967 (mevy - sv->GVS[sv->StdView].spinBeginY);
5968 if (M1time) {
5969 M1delta = Mev.time - M1time;
5970 mvdeltax = Mev.x - mvxlast;
5971 mvdeltay = Mev.y - mvylast;
5972 } else {
5973 M1delta = 0;
5974 mvdeltax = 0;
5975 mvdeltay = 0;
5976 }
5977 M1time = Mev.time;
5978 mvxlast= Mev.x;
5979 mvylast= Mev.y;
5980
5981 /* compute move rate in pixels per milliseconds,
5982 You could use this to add a gain on the amount of rotation,
5983 but before you could use those factors, you'll need to scale
5984 the results to something appropriate */
5985 mvx_fac = ((SUMA_ABS((float)mvdeltax)/(M1delta+0.01)));
5986 mvy_fac = ((SUMA_ABS((float)mvdeltay)/(M1delta+0.01)));
5987
5988 #if 0
5989 fprintf(stdout,"\n"
5990 "spinBeginX %f \n"
5991 "spinBeginY %f \n"
5992 "spinDeltaX %f \n"
5993 "spinDeltaY %f \n"
5994 "X->aWIDTH %d \n"
5995 "X->aHEIGHT %d\n"
5996 "ZoomCompensate %f\n"
5997 "mv[xy]last [%d %d]\n"
5998 "mvdelta[xy]last [%d %d]\n"
5999 "MoveRatePixelsPerms [%f %f]\n"
6000 ,
6001 sv->GVS[sv->StdView].spinBeginX,
6002 sv->GVS[sv->StdView].spinBeginY,
6003 sv->GVS[sv->StdView].spinDeltaX,
6004 sv->GVS[sv->StdView].spinDeltaY,
6005 sv->X->aWIDTH, sv->X->aHEIGHT, sv->ZoomCompensate,
6006 mvxlast, mvylast,
6007 mvdeltax, mvdeltay,
6008 mvx_fac, mvy_fac
6009 );
6010 #else
6011 /* fprintf(stdout,"%f %f; ", mvx_fac, mvy_fac); */
6012 #endif
6013 /* do not use movement rate before you scale it properly */
6014 mvx_fac = mvy_fac = 1.0;
6015 if (sv->GVS[sv->StdView].spinDeltaX ||
6016 sv->GVS[sv->StdView].spinDeltaY){
6017 if (SUMA_Shft_Event(SUMAg_CF->lev)) {
6018 float a[3], cQ[4];
6019 /* rotate about Z axis */
6020 a[0] = 0.0; a[1] = 0.0; a[2] = 1.0;
6021 axis_to_quat(a,
6022 -SUMA_SIGN(mvdeltax)*sqrt(SUMA_ABS(mvdeltax))*
6023 sv->ArrowRotationAngle,
6024 cQ);
6025 /*add rotation */
6026 add_quats ( cQ,
6027 sv->GVS[sv->StdView].currentQuat,
6028 sv->GVS[sv->StdView].currentQuat);
6029 } else if (SUMA_Cont_Event(SUMAg_CF->lev)) {
6030 float val[3];
6031 val[0] = sv->GVS[sv->StdView].spinDeltaX;
6032 val[1] = sv->GVS[sv->StdView].spinDeltaY;
6033 val[2] = 0.0;
6034 SUMA_ApplyPrying(sv, val, "mouse", 0);
6035 /* update normals at release */
6036 } else if (SUMA_Plain_Event(SUMAg_CF->lev)){
6037 trackball( sv->GVS[sv->StdView].deltaQuat,
6038 (2*sv->GVS[sv->StdView].spinBeginX - wwid) /
6039 wwid*zc_fac*mvx_fac,
6040 (whei - 2*sv->GVS[sv->StdView].spinBeginY) /
6041 whei*zc_fac*mvy_fac,
6042 (2*mevx - wwid)/wwid*zc_fac*mvx_fac,
6043 (whei - 2*mevy)/whei*zc_fac*mvy_fac);
6044 /* comput the increment Quat */
6045 sv->GVS[sv->StdView].spinBeginX = mevx;
6046 sv->GVS[sv->StdView].spinBeginY = mevy;
6047 add_quats ( sv->GVS[sv->StdView].deltaQuat,
6048 sv->GVS[sv->StdView].currentQuat,
6049 sv->GVS[sv->StdView].currentQuat);
6050 } else {
6051 SUMA_LH("Not ready for event flavor");
6052 break;
6053 }
6054 ii = SUMA_WhichSV(sv, SUMAg_SVv, SUMAg_N_SVv);
6055 if (ii < 0) {
6056 fprintf (SUMA_STDERR,
6057 "Error %s: Failed to find index of sv.\n", FuncName);
6058 break;
6059 }
6060 if (!SUMAg_CF->ViewLocked[ii]) { /* No locking,
6061 just redisplay current viewer */
6062 SUMA_postRedisplay(w, clientData, callData);
6063 } else { /* locking, update and redisplay those locked */
6064 DList *list = NULL;
6065 SUMA_EngineData *ED = NULL;
6066 SUMA_STANDARD_VIEWS ed_sv, ed_svi;
6067 /* redisplay current viewer immediately */
6068 list = SUMA_CreateList ();
6069 ED = SUMA_InitializeEngineListData (SE_RedisplayNow);
6070 SUMA_RegisterEngineListCommand (list, ED,
6071 SEF_Empty, NULL,
6072 SES_Suma, (void *)sv, NOPE,
6073 SEI_Head, NULL);
6074 ed_sv = SUMA_BestStandardView(sv, SUMAg_DOv, SUMAg_N_DOv);
6075 for (it=0; it < SUMAg_N_SVv; ++it) {
6076 svi = &SUMAg_SVv[it];
6077 ed_svi = SUMA_BestStandardView(svi, SUMAg_DOv, SUMAg_N_DOv);
6078 if ( it != ii &&
6079 SUMAg_CF->ViewLocked[it] && ed_svi == ed_sv) {
6080 /* copy quaternions */
6081 svi->GVS[svi->StdView].spinBeginX =
6082 sv->GVS[sv->StdView].spinBeginX;
6083 svi->GVS[svi->StdView].spinBeginY =
6084 sv->GVS[sv->StdView].spinBeginY;
6085 SUMA_COPY_VEC( sv->GVS[sv->StdView].deltaQuat,
6086 svi->GVS[svi->StdView].deltaQuat,
6087 4, float, float);
6088 SUMA_COPY_VEC( sv->GVS[sv->StdView].currentQuat,
6089 svi->GVS[svi->StdView].currentQuat,
6090 4, float, float);
6091
6092 /* add a redisplay now */
6093 ED = SUMA_InitializeEngineListData (SE_RedisplayNow);
6094 SUMA_RegisterEngineListCommand ( list, ED,
6095 SEF_Empty, NULL,
6096 SES_Suma, (void *)svi, NOPE,
6097 SEI_Head, NULL);
6098 }
6099 }
6100 if (!SUMA_Engine (&list)) {
6101 fprintf (SUMA_STDERR,
6102 "Error %s: Failed calling SUMA_Engine.\n",
6103 FuncName);
6104 break;
6105 }
6106 }
6107 }
6108
6109 break;
6110
6111 case SUMA_Button_2_Motion:
6112 mevx = (float)Mev.x; mevy = (float)Mev.y;
6113 SUMA_LHv("In motion, Butt2 %f, %f\n", mevx , mevy);
6114 if (sv->ZoomCompensate) {
6115 zc_fac = sv->ZoomCompensate;
6116 }else {
6117 zc_fac = 1.0;
6118 }
6119 if ((Kev.state & ShiftMask)){
6120
6121 } else {
6122 sv->GVS[sv->StdView].translateDeltaX =
6123 (mevx - sv->GVS[sv->StdView].translateBeginX) /
6124 (float)sv->X->aWIDTH*sv->GVS[sv->StdView].TranslateGain;
6125 sv->GVS[sv->StdView].translateDeltaY =
6126 -(mevy - sv->GVS[sv->StdView].translateBeginY) /
6127 (float)sv->X->aHEIGHT*sv->GVS[sv->StdView].TranslateGain;
6128
6129 if ( sv->GVS[sv->StdView].translateDeltaX ||
6130 sv->GVS[sv->StdView].translateDeltaY){
6131 sv->GVS[sv->StdView].translateVec[0] +=
6132 (GLfloat)sv->GVS[sv->StdView].translateDeltaX * zc_fac;
6133 sv->GVS[sv->StdView].translateVec[1] +=
6134 (GLfloat)sv->GVS[sv->StdView].translateDeltaY * zc_fac;
6135 sv->GVS[sv->StdView].translateBeginX = mevx;
6136 sv->GVS[sv->StdView].translateBeginY = mevy;
6137 SUMA_postRedisplay(w, clientData, callData);
6138 }
6139 }
6140 break;
6141
6142 case SUMA_Button_3_Motion: {
6143 SUMA_ALL_DO *lado=NULL;
6144 SUMA_DO_Types lado_type=NOT_SET_type;
6145
6146 if (sv->LastSel_ado_idcode_str) {
6147 lado = SUMA_whichADOg(sv->LastSel_ado_idcode_str);
6148 if (lado) lado_type = lado->do_type;
6149 }
6150
6151 SUMA_LH("In button 3 motion, lado=%s", ADO_LABEL(lado));
6152
6153 /* Clear any pre-existing selection */
6154 if (!SUMA_Add_To_PickResult_List(sv, NULL, "TERSUM", NULL)) {
6155 SUMA_S_Err("Failed to clear selections");
6156 break;
6157 }
6158
6159 if (SUMAg_CF->ROI_mode && SUMA_SV_Focus_SO(sv) && sv->BS) {
6160 /* ROI drawing mode */
6161 ii = SUMA_RegisteredSOs(sv, SUMAg_DOv, NULL);
6162 if (ii == 0) { /* no surfaces, break */
6163 break;
6164 }
6165
6166
6167 if (!SUMA_GetSelectionLine(sv,
6168 (int)Mev.x, (int)Mev.y, sv->Pick0, sv->Pick1,
6169 0, NULL, NULL, NULL)) {
6170 fprintf (SUMA_STDERR, "Error %s: Failed in "
6171 "SUMA_GetSelectionLine.\n", FuncName);
6172 break;
6173 }
6174
6175 if (!SUMA_AddToBrushStroke (sv, (int)Mev.x, (int)Mev.y,
6176 sv->Pick0, sv->Pick1, YUP)) {
6177 SUMA_RegisterMessage (SUMAg_CF->MessageList,
6178 "Failed to add to BrushStroke.",
6179 FuncName,
6180 SMT_Error, SMA_LogAndPopup);
6181 break;
6182 }
6183 } else {
6184 /* Mev.state does not work in the line below */
6185 if ((Kev.state & ShiftMask) && (Kev.state & ControlMask) ) {
6186 SUMA_LH("Allowing callbacks");
6187 SUMAg_CF->HoldClickCallbacks = 0;
6188 } else {
6189 SUMA_LH("Holding back callbacks");
6190 SUMAg_CF->HoldClickCallbacks = 1;
6191 }
6192
6193 if (SUMAg_N_SVv > 1) {
6194 ii = SUMA_WhichViewerInMomentum (SUMAg_SVv,
6195 SUMAg_N_SVv, NULL);
6196 if (ii >= 0) {
6197 sprintf (s, "You cannot select or draw while viewers\n"
6198 "(like viewer %c) are in momentum mode.\n",
6199 ii+65);
6200 SUMA_RegisterMessage (SUMAg_CF->MessageList,
6201 s, FuncName, SMT_Error,
6202 SMA_LogAndPopup);
6203 SUMA_RETURNe;
6204 }
6205 }
6206
6207 if (!(Kev.state & ShiftMask) && (Kev.state & ControlMask) ) {
6208 SUMA_LH("Yoking intensity to node selection");
6209 SUMAg_CF->YokeIntToNode = 1;
6210 } else {
6211 SUMA_LH("Holding back callbacks");
6212 SUMAg_CF->YokeIntToNode = 0;
6213 }
6214
6215 #if 0
6216 /* Try this if you are having OpenGLStateReset problems at
6217 node selection time. It is inefficient, but helps point
6218 to the problem.
6219 Look at recent updates to SE_Redisplay*All* for the more
6220 appropriate fix */
6221 SUMA_S_Note("Blunt fix:");
6222 SUMA_OpenGLStateReset(SUMAg_DOv, SUMAg_N_DOv, sv);
6223 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
6224 #endif
6225
6226 if (!SUMA_GetSelectionLine ( sv, (int)Mev.x, (int)Mev.y,
6227 sv->Pick0, sv->Pick1, 0,
6228 NULL, NULL, NULL)) {
6229 fprintf (SUMA_STDERR,
6230 "Error %s: Failed in SUMA_GetSelectionLine.\n",
6231 FuncName);
6232 break;
6233 }
6234
6235 if (lado_type == NOT_SET_type ||
6236 lado_type == MASK_type) {
6237 if (!MASK_MANIP_MODE(sv)) { /* You don't want these if
6238 you're moving them! */
6239 SUMA_LH("Mask picking");
6240 hit = SUMA_ComputeLineMaskIntersect (sv, SUMAg_DOv, 0, NULL);
6241 if (hit < 0) {
6242 SUMA_S_Err("Failed in SUMA_ComputeLineMaskIntersect.");
6243 }
6244 }
6245 }
6246
6247 if (lado_type == NOT_SET_type ||
6248 lado_type == TRACT_type || lado_type == GRAPH_LINK_type) {
6249 if (1) {
6250 SUMA_LH("Tract picking");
6251 hit = SUMA_ComputeLineDOsIntersect (sv, SUMAg_DOv, 0, NULL);
6252 if (hit < 0) {
6253 SUMA_S_Err("Failed in SUMA_ComputeLineDOsIntersect.");
6254 }
6255 }
6256 }
6257
6258 if (lado_type == NOT_SET_type ||
6259 lado_type == VO_type) {
6260 if (1) {
6261 SUMA_LH("Trying for volume intersections");
6262 hit = SUMA_ComputeLineVOslicesIntersect(sv, SUMAg_DOv,
6263 0, NULL);
6264 if (hit < 0) {
6265 fprintf( SUMA_STDERR,
6266 "Error %s: "
6267 "Failed in SUMA_MarkLineVOslicesIntersect.\n",
6268 FuncName);
6269 }
6270 }
6271 if (1) {
6272 SUMA_LH("Trying for volume rendering intersections");
6273 hit = SUMA_ComputeLineVOvrIntersect(sv, SUMAg_DOv,
6274 0, NULL);
6275 if (hit < 0) {
6276 fprintf( SUMA_STDERR,
6277 "Error %s: "
6278 "Failed in SUMA_MarkLineVOvrIntersect.\n",
6279 FuncName);
6280 }
6281 }
6282 }
6283
6284 if ((lado_type == NOT_SET_type ||
6285 lado_type == SO_type)) {
6286 ii = SUMA_RegisteredSOs(sv, SUMAg_DOv, NULL);
6287 if (ii > 0) { /* some surfaces, try */
6288 /* perform the intersection calcluation and mark the surface */
6289 hit = SUMA_ComputeLineSurfaceIntersect (sv, SUMAg_DOv,
6290 1, NULL);
6291 if (hit < 0) {
6292 fprintf( SUMA_STDERR,
6293 "Error %s: "
6294 "Failed in SUMA_ComputeLineSurfaceIntersect.\n",
6295 FuncName);
6296 break;
6297 }
6298 }
6299 }
6300
6301 ASSESS_MOTION:
6302 SUMA_LH("Assessment");
6303 if (dlist_size(sv->SelAdo)) {
6304 if (!SUMA_Process_Selected_ADO(sv, SUMA_ALTHELL)) {
6305 SUMA_S_Err("Failed to process selected ado");
6306 SUMA_RETURNe;
6307 }
6308
6309 /* redisplay */
6310 sv->ResetGLStateVariables = YUP;
6311 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
6312 }
6313 OUT_MOTION:
6314 /* reset hold on xforms */
6315 SUMAg_CF->HoldClickCallbacks = 0;
6316 }
6317
6318 break; }
6319 }
6320
6321
6322 break;
6323 }/* switch event type */
6324
6325 SUMA_RETURNe;
6326 }
6327
6328 /*!
6329 SUMA_momentum(XtPointer clientData, XtIntervalId *id);
6330
6331 client data contains the widget responsible for the call to SUMA_momentum
6332 */
SUMA_momentum(XtPointer clientData,XtIntervalId * id)6333 void SUMA_momentum(XtPointer clientData, XtIntervalId *id)
6334 {
6335 static char FuncName[]={"SUMA_momentum"};
6336 static int ReDisp;
6337 Widget w;
6338 int isv;
6339 SUMA_SurfaceViewer *sv;
6340
6341 SUMA_ENTRY;
6342
6343 /* the widget is passed as client data */
6344 w = (Widget)clientData;
6345
6346 /* find out which Surface viewer the widget belongs to */
6347 SUMA_ANY_WIDGET2SV((Widget)clientData, sv, isv);
6348 if (isv < 0) {
6349 SUMA_S_Err("Failed in macro SUMA_ANY_WIDGET2SV.");
6350 SUMA_RETURNe;
6351 }
6352
6353
6354 ReDisp = 0;
6355 if ( ((sv->GVS[sv->StdView].spinDeltaX*sv->GVS[sv->StdView].spinDeltaX) >
6356 sv->GVS[sv->StdView].MinIdleDelta ) ||
6357 ((sv->GVS[sv->StdView].spinDeltaY*sv->GVS[sv->StdView].spinDeltaY) >
6358 sv->GVS[sv->StdView].MinIdleDelta ) )
6359 { /* rotate if SUMA_momentum is enabled and spinDeltaX or spinDeltaY
6360 are larger than the minimum set */
6361 /*fprintf(stdout,"SUMA_momentum: spinDeltaX %f spinDeltaY %f\n",
6362 sv->GVS[sv->StdView].spinDeltaX,
6363 sv->GVS[sv->StdView].spinDeltaY);*/
6364 add_quats ( sv->GVS[sv->StdView].deltaQuat,
6365 sv->GVS[sv->StdView].currentQuat,
6366 sv->GVS[sv->StdView].currentQuat);
6367 ReDisp = 1;
6368 }
6369 if ( ((sv->GVS[sv->StdView].translateDeltaX*
6370 sv->GVS[sv->StdView].translateDeltaX) >
6371 sv->GVS[sv->StdView].MinIdleDelta ) ||
6372 ((sv->GVS[sv->StdView].translateDeltaY*
6373 sv->GVS[sv->StdView].translateDeltaY) >
6374 sv->GVS[sv->StdView].MinIdleDelta ) )
6375 { /* translate */
6376 sv->GVS[sv->StdView].translateVec[0] +=
6377 (GLfloat)sv->GVS[sv->StdView].translateDeltaX;
6378 sv->GVS[sv->StdView].translateVec[1] +=
6379 (GLfloat)sv->GVS[sv->StdView].translateDeltaY;
6380 ReDisp = 1;
6381 }
6382 if (ReDisp) {
6383 /*fprintf(stdout,"Momentum Redisplay\n");*/
6384 SUMA_postRedisplay(w, NULL, NULL);
6385 }
6386 sv->X->MOMENTUMID = XtAppAddTimeOut(SUMAg_CF->X->App, 1,
6387 SUMA_momentum, (XtPointer) w);
6388
6389 SUMA_RETURNe;
6390 }
6391
6392 /*
6393 Show the buffer used to pick displayable objects (DOs) with color id
6394 The function adds a cross hair (4 white pixels) around the selection
6395 point and displays the image in AFNI's viewer (InViewer == 1) and/or
6396 save the image to an image file if OnDisk is not NULL.
6397 Set OnDisk to something like PickBuff.ppm so that you get the exact
6398 pixels rendered in the output. Consecutive images are numbered with
6399 a time stamp.
6400
6401 Note that the 4th chanel (alpha) is not shown or written to disk at
6402 the moment.
6403 */
SUMA_MarkPickInBuffer4(SUMA_SurfaceViewer * sv,int InViewer,char * OnDisk)6404 SUMA_Boolean SUMA_MarkPickInBuffer4(SUMA_SurfaceViewer *sv, int InViewer,
6405 char *OnDisk)
6406 {
6407 static char FuncName[]={"SUMA_MarkPickInBuffer4"};
6408 int n4, n3, n, p0[5],p1[5],p2[5],p3[5], i;
6409 SUMA_Boolean LocalHead = NOPE;
6410
6411 SUMA_ENTRY;
6412 if (!InViewer && !OnDisk) {
6413 SUMA_S_Err("Nothing to do here");
6414 SUMA_RETURN(NOPE);
6415 }
6416 if (!sv->pickrenpix4) {
6417 SUMA_S_Err("Empty buffer array");
6418 SUMA_RETURN(NOPE);
6419 }
6420 p0[0] = -1; /* to hold index of pixel being marked */
6421 p1[0] = -1;
6422 p2[0] = -1;
6423 p3[0] = -1;
6424
6425 n4 = sv->PickPix[1]*sv->X->aWIDTH + sv->PickPix[0];
6426 n4 = 4*n4;
6427 SUMA_LHv("User pixel selection from whole buffer:"
6428 " at %d %d is: %d %d %d %d\n",
6429 sv->PickPix[0], sv->PickPix[1],
6430 sv->pickrenpix4[n4] , sv->pickrenpix4[n4+1],
6431 sv->pickrenpix4[n4+2] , sv->pickrenpix4[n4+3]);
6432 if (sv->PickPix[1] > 0) {
6433 n4 = (sv->PickPix[1]-1)*sv->X->aWIDTH + sv->PickPix[0];
6434 n4 = 4*n4;
6435 p0[0] = n4; p0[1] = sv->pickrenpix4[n4 ]; p0[2] = sv->pickrenpix4[n4+1];
6436 p0[3] = sv->pickrenpix4[n4+2]; p0[4] = sv->pickrenpix4[n4+3];
6437 sv->pickrenpix4[n4] = sv->pickrenpix4[n4+1] =
6438 sv->pickrenpix4[n4+2] = sv->pickrenpix4[n4+3] = 255;
6439 }
6440 if (sv->PickPix[0] > 0) {
6441 n4 = sv->PickPix[1]*sv->X->aWIDTH + sv->PickPix[0]-1;
6442 n4 = 4*n4;
6443 p1[0] = n4; p1[1] = sv->pickrenpix4[n4 ]; p1[2] = sv->pickrenpix4[n4+1];
6444 p1[3] = sv->pickrenpix4[n4+2]; p1[4] = sv->pickrenpix4[n4+3];
6445 sv->pickrenpix4[n4] = sv->pickrenpix4[n4+1] =
6446 sv->pickrenpix4[n4+2] = sv->pickrenpix4[n4+3] = 255;
6447 }
6448 if (sv->PickPix[1] < (sv->X->aHEIGHT-1)) {
6449 n4 = (sv->PickPix[1]+1)*sv->X->aWIDTH + sv->PickPix[0];
6450 n4 = 4*n4;
6451 p2[0] = n4; p2[1] = sv->pickrenpix4[n4 ]; p2[2] = sv->pickrenpix4[n4+1];
6452 p2[3] = sv->pickrenpix4[n4+2]; p2[4] = sv->pickrenpix4[n4+3];
6453 sv->pickrenpix4[n4] = sv->pickrenpix4[n4+1] =
6454 sv->pickrenpix4[n4+2] = sv->pickrenpix4[n4+3] = 255;
6455 }
6456 if (sv->PickPix[0] < (sv->X->aWIDTH-1)) {
6457 n4 = sv->PickPix[1]*sv->X->aWIDTH + sv->PickPix[0]+1;
6458 n4 = 4*n4;
6459 p3[0] = n4; p3[1] = sv->pickrenpix4[n4 ]; p3[2] = sv->pickrenpix4[n4+1];
6460 p3[3] = sv->pickrenpix4[n4+2]; p3[4] = sv->pickrenpix4[n4+3];
6461 sv->pickrenpix4[n4] = sv->pickrenpix4[n4+1] =
6462 sv->pickrenpix4[n4+2] = sv->pickrenpix4[n4+3] = 255;
6463 }
6464 if (InViewer) { /* show me the money in the interactive viewer */
6465 GLubyte *pp3 = (GLubyte *)SUMA_calloc(sv->X->aWIDTH*sv->X->aHEIGHT*3,
6466 sizeof(GLubyte));
6467 for (n3=0,n=0; n<sv->X->aWIDTH*sv->X->aHEIGHT; ++n) {
6468 n4=4*n;
6469 pp3[n3++]= sv->pickrenpix4[n4++];
6470 pp3[n3++]= sv->pickrenpix4[n4++];
6471 pp3[n3++]= sv->pickrenpix4[n4++]; n4++;
6472 }
6473 ISQ_snapsave(sv->X->aWIDTH, -sv->X->aHEIGHT,
6474 (unsigned char *)pp3, sv->X->GLXAREA );
6475 SUMA_ifree(pp3);
6476 }
6477 if (OnDisk) {
6478 if (!SUMA_PixelsToDisk(sv, sv->X->aWIDTH, -sv->X->aHEIGHT,
6479 (GLvoid *)sv->pickrenpix4, 4, 1, OnDisk, 1, 0)) {
6480 SUMA_S_Err("Failed to write pix to disk");
6481 }
6482 }
6483 /* now put things back where you found them */
6484 if (p0[0] >= 0) {
6485 for (i=0; i<4; ++i) sv->pickrenpix4[p0[0]+i] = p0[1+i];
6486 }
6487 if (p1[0] >= 0) {
6488 for (i=0; i<4; ++i) sv->pickrenpix4[p1[0]+i] = p1[1+i];
6489 }
6490 if (p2[0] >= 0) {
6491 for (i=0; i<4; ++i) sv->pickrenpix4[p2[0]+i] = p2[1+i];
6492 }
6493 if (p3[0] >= 0) {
6494 for (i=0; i<4; ++i) sv->pickrenpix4[p3[0]+i] = p3[1+i];
6495 }
6496
6497 SUMA_RETURN(YUP);
6498 }
6499
6500 /*
6501 Function to return the color in the stored rendering buffer.
6502 checking is done at the pick location first, then in progressively
6503 larger neighborhoods
6504
6505 When first called, the search begins at pixel *i, *j. If nothing
6506 is found, the search proceeds within the layer limit and the first
6507 non-blank find is returned in pixhit. *i and *j are set to the newly
6508 picked location
6509
6510 i is along the width, j along the height
6511 */
SUMA_GetColidInPickBuffer4(GLubyte * pix,int Ni,int Nj,int * ii,int * ji,int maxlay,GLubyte * colid)6512 SUMA_Boolean SUMA_GetColidInPickBuffer4(GLubyte *pix, int Ni, int Nj,
6513 int *ii, int *ji,
6514 int maxlay, GLubyte *colid)
6515 {
6516 static char FuncName[]={"SUMA_GetColidInPickBuffer4"};
6517 int i0, j0, i, j, n4, k;
6518 int poff[(1+2*2)*(1+2*2)][2] = {
6519 {0,0}, {-1,0}, {-1,-1}, {0,-1}, {-1,-1}, {1,1},/*A..F*/
6520 {-2,0}, {-2,1}, {-2,-2}, {-1,-2}, {0,-2}, {-2,1},/*G..L*/
6521 {1,-1}, {0,1}, {1,0}, {-2,2}, {1,-2}, {-1,2},/*M..R*/
6522 {2,-2}, {2,-1},{0,2}, {2,0},{1,2},{2,1},{2,2} }/*S..Y*/;
6523
6524 SUMA_ENTRY;
6525
6526 if (!pix || !ii || !ji || *ii <0 || *ii >= Ni || *ji<0 || *ji>Nj) {
6527 SUMA_S_Err("Bad input");
6528 SUMA_RETURN(NOPE);
6529 }
6530 if (maxlay < 0) maxlay = 0;
6531 if (maxlay > 2) {
6532 SUMA_S_Warn("Not ready for more than two layers");
6533 maxlay = 2;
6534 }
6535
6536 i = *ii; j = *ji;
6537 n4 = 4*(i+j*Ni);
6538 if (pix[n4] || pix[n4+1] || pix[n4+2] || pix[n4+3]) {
6539 memcpy(colid, pix+n4, 4*sizeof(GLubyte));
6540 SUMA_RETURN(YUP);
6541 }
6542
6543 if (maxlay == 0) SUMA_RETURN(NOPE);
6544
6545 /* search in order shown on page 235 of labbook NIH-6
6546 The idea is to follow a search pattern based on the shape
6547 of the cursor pointing up and slightly left
6548 Actually maxlay == 1 is not quite honored here */
6549 i0 = *ii; j0 = *ji;
6550 k=1;
6551 while (k<25) {
6552 if ((i=i0+poff[k][0]) >=0 && i<Ni &&
6553 (j=j0+poff[k][0]) >=0 && j<Nj) {
6554 n4 = 4*(i+j*Ni);
6555 if (pix[n4] || pix[n4+1] || pix[n4+2] || pix[n4+3]) {
6556 memcpy(colid, pix+n4, 4*sizeof(GLubyte));
6557 *ii=i; *ji=j;
6558 SUMA_RETURN(YUP);
6559 }
6560 }
6561 ++k;
6562 }
6563 /* if nothing is found, and users want more layers, start searching in
6564 squarish patterns from layer 3 onwards, someday */
6565
6566 SUMA_RETURN(NOPE);
6567 }
6568
6569 /* if action == 0: Free saved DO picking buffer in pickrenpix4
6570 1: Recreate pickrenpix4 regardless of whether or
6571 not the new pickrenpix4 is expected to change
6572 2: Recreate pickrenpix4 only if deemed necessary
6573 */
SUMA_PickBuffer(SUMA_SurfaceViewer * sv,int action,SUMA_DO * dov)6574 SUMA_Boolean SUMA_PickBuffer(SUMA_SurfaceViewer *sv, int action, SUMA_DO *dov)
6575 {
6576 static char FuncName[]={"SUMA_PickBuffer"};
6577 int Flush = 0;
6578 SUMA_Boolean LocalHead = NOPE;
6579
6580 SUMA_ENTRY;
6581
6582 if (!sv) {
6583 SUMA_S_Err("Null sv!");
6584 SUMA_RETURN(NOPE);
6585 }
6586
6587 if ( action == 0 || /* flush only */
6588 action == 1 /* Recreate regardless */ ) {
6589 /* flush needed */
6590 SUMA_LH("Flushing pickrenpix4");
6591 Flush = 1;
6592 } else if (action == 2) { /* recreate if needed */
6593 if ( MASK_MANIP_MODE(sv) ||
6594 SUMA_DiffGeomViewStruct(sv->GVS[sv->StdView],
6595 sv->GVS_last_PickMode[sv->StdView], 1) ||
6596 sv->FOV[sv->iState] != sv->FOV_last_PickMode[sv->iState]) {
6597 SUMA_LH("Have a changed GVS or FOV, flushing pickrenpix4");
6598 Flush = 1;
6599 } else {
6600 SUMA_LH("GVS and FOV still the same");
6601 }
6602 } else {
6603 SUMA_S_Errv("Bad action value %d\n", action);
6604 SUMA_RETURN(NOPE);
6605 }
6606
6607 if (Flush) {
6608 SUMA_LHv("Flushing, action %d\n", action);
6609 if (sv->pickrenpix4) SUMA_free(sv->pickrenpix4);
6610 sv->pickrenpix4 = NULL;
6611 }
6612
6613 if (action == 0) SUMA_RETURN(YUP);
6614
6615 /* recreate if no pickrenpix4 */
6616 if (!sv->pickrenpix4) {
6617 /* record GVS and FOV states*/
6618 SUMA_CopyGeomViewStruct(&(sv->GVS[sv->StdView]),
6619 &(sv->GVS_last_PickMode[sv->StdView]));
6620 sv->FOV_last_PickMode[sv->iState] = sv->FOV[sv->iState];
6621
6622 sv->DO_PickMode = 1;
6623 SUMA_display(sv, dov);
6624 if (!(sv->pickrenpix4 =
6625 SUMA_grabPixels(4, sv->X->aWIDTH, sv->X->aHEIGHT))) {
6626 SUMA_S_Err("Failed to grab pixels");
6627 }
6628 sv->DO_PickMode = 0;
6629 }
6630 SUMA_RETURN(YUP);
6631 }
6632
SUMA_ADO_Flush_Pick_Buffer(SUMA_ALL_DO * ado,SUMA_SurfaceViewer * sv)6633 SUMA_Boolean SUMA_ADO_Flush_Pick_Buffer(SUMA_ALL_DO *ado, SUMA_SurfaceViewer *sv)
6634 {
6635 static char FuncName[]={"SUMA_ADO_Flush_Pick_Buffer"};
6636 int ii;
6637 SUMA_ENTRY;
6638
6639 if (!ado) SUMA_RETURN(NOPE);
6640 if (sv) {
6641 if (SUMA_ADO_isRegistered(sv, ado)) {
6642 SUMA_PickBuffer(sv, 0, NULL);
6643 }
6644 } else { /* Do it for all */
6645 for (ii=0; ii<SUMAg_N_SVv; ++ii) {
6646 sv = &(SUMAg_SVv[ii]);
6647 if (SUMA_ADO_isRegistered(sv, ado)) {
6648 SUMA_PickBuffer(sv, 0, NULL);
6649 }
6650 }
6651 }
6652
6653 SUMA_RETURN(YUP);
6654 }
6655
6656 /* What was picked on a frame SO ?
6657 See SUMA_Surface_Of_NIDO_Matrix() for how surface coordinates
6658 translate to matrix pixels and eventually matrix cells.
6659 See also SUMA_GDSET_edgeij_to_GMATRIX_XYZ() and SUMA_DrawGraphDO_GMATRIX()
6660 */
SUMA_WhatWasPicked_FrameSO(SUMA_SurfaceViewer * sv,int ido)6661 SUMA_PICK_RESULT *SUMA_WhatWasPicked_FrameSO(SUMA_SurfaceViewer *sv, int ido)
6662 {
6663 static char FuncName[]={"SUMA_WhatWasPicked_FrameSO"};
6664 float P0[3], P1[3];
6665 int N[3], IIm[3], ii, jj, i, *ui=NULL, *uj=NULL, si=-1, G[3], B[3], M[3];
6666 SUMA_ALL_DO *ado=NULL;
6667 SUMA_DSET *dset=NULL;
6668 SUMA_PICK_RESULT *PR = NULL;
6669 SUMA_SurfaceObject *SO=NULL;
6670 SUMA_GRAPH_SAUX *GSaux = NULL;
6671 SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL;
6672 double Aff[4][4], I[3], V[12], X[3], GB[3];
6673 SUMA_Boolean LocalHead = NOPE;
6674
6675 SUMA_ENTRY;
6676
6677 if (!sv ) {
6678 SUMA_S_Err("NULL input");
6679 SUMA_RETURN(PR);
6680 }
6681
6682 if (!iDO_isGLDO(ido) || !iDO_is_variant(ido,"GMATRIX")) {
6683 /* No frame SOs in this DO, not an error just keep looking */
6684 SUMA_LH("Not a DO with a FrameSO, go on");
6685 SUMA_RETURN(PR);
6686 }
6687
6688 SUMA_LHv("Pick Query for FrameSO on sv %p, ido %d\n", sv, ido);
6689 if (iDO_is_variant(ido,"GMATRIX") &&
6690 (GSaux = iDO_GSaux(ido))) {
6691 SO=GSaux->FrameSO;
6692 }
6693 if (!SO) {
6694 SUMA_S_Errv("No FrameSO on %s\n", iDO_label(ido));
6695 SUMA_RETURN(PR);
6696 }
6697 NI_GET_DOUBLEv(GSaux->nido->ngr, "dicom_real_to_ijk", V, 12, LocalHead);
6698 if (!NI_GOT) {
6699 SUMA_S_Err("No dicom_real_to_ijk");
6700 SUMA_RETURN(PR);
6701 }
6702 V12_TO_AFF44(Aff, V);
6703
6704 NI_GET_INTv(GSaux->nido->ngr, "Nijk", N, 3, LocalHead);
6705 if (!NI_GOT) {
6706 SUMA_S_Err("No Nijk");
6707 SUMA_RETURN(PR);
6708 }
6709
6710 /* total num of pixels per value */
6711 NI_GET_INTv(GSaux->nido->ngr, "PixCount", M, 3, LocalHead);
6712 NI_GET_INTv(GSaux->nido->ngr, "PixPerVal", G, 3, LocalHead);
6713 NI_GET_INTv(GSaux->nido->ngr, "BorWid", B, 3, LocalHead);
6714 GB[0] = G[0]+B[0];
6715 GB[1] = G[1]+B[1];
6716 GB[2] = G[2]+B[2];
6717
6718 SUMA_COPY_VEC(sv->Pick0, P0, 3, GLdouble, float);
6719 SUMA_COPY_VEC(sv->Pick1, P1, 3, GLdouble, float);
6720 if (!(MTI = SUMA_MT_intersect_triangle(P0, P1,
6721 SO->NodeList, SO->N_Node,
6722 SO->FaceSetList, SO->N_FaceSet, NULL, 0))){
6723 SUMA_S_Err("SUMA_MT_intersect_triangle failed.");
6724 SUMA_RETURN(PR);
6725 }
6726
6727 if (MTI->N_hits < 1) {
6728 SUMA_LH("No hits");
6729 SUMA_RETURN(PR);
6730 }
6731
6732 ui = uj = NULL;
6733 if (iDO_isGLDO(ido)) {
6734 if (!(dset = SUMA_find_GLDO_Dset((SUMA_GraphLinkDO*)SUMAg_DOv[ido].OP))) {
6735 SUMA_S_Err("No dset for GLDO?");
6736 SUMA_RETURN(PR);
6737 }
6738 GSaux->IgnoreSelection = 0; /* Selection being made on matrix
6739 representation of graph.
6740 turn off IgnoreSelection */
6741 switch (dset->Aux->matrix_shape) {
6742 case MAT_FULL:
6743 case MAT_TRI:
6744 case MAT_TRI_DIAG:
6745 SUMA_LH("Direct indexing between edge points and matrix row/col");
6746 break;
6747 case MAT_SPARSE:
6748 if (!dset->inel) {
6749 SUMA_S_Err("Don't have inel, badly shaped dataset");
6750 SUMA_RETURN(PR);
6751 }
6752 if ( !(ui = SUMA_GetUniqueIndicesVec(dset,1)) ||
6753 !(uj = SUMA_GetUniqueIndicesVec(dset,2)) ) {
6754 SUMA_S_Err("Failed to get unique indices");
6755 SUMA_RETURN(PR);
6756 }
6757 break;
6758 default:
6759 SUMA_S_Err("Rats");
6760 SUMA_RETURN(PR);
6761 break;
6762 }
6763 }
6764
6765
6766 PR = SUMA_New_Pick_Result(PR);
6767 PR->ado_idcode_str = SUMA_replace_string(PR->ado_idcode_str,iDO_idcode(ido));
6768 ado = SUMA_whichADOg(PR->ado_idcode_str);
6769 PR->primitive = SUMA_replace_string(PR->primitive, "none yet");
6770 PR->primitive_index = -1;
6771 PR->PickXYZ[0] = MTI->P[0];
6772 PR->PickXYZ[1] = MTI->P[1];
6773 PR->PickXYZ[2] = MTI->P[2];
6774 sv->Focus_DO_ID = ido;
6775
6776 PR->datum_index = -1;
6777 for (i=0; i<SUMA_N_IALTSEL_TYPES; ++i) PR->iAltSel[i] = -1;
6778 for (i=0; i<SUMA_N_DALTSEL_TYPES; ++i) PR->dAltSel[i] = 0.0;
6779 AFF44_MULT_I(I, Aff, MTI->P);
6780
6781 SUMA_LHv("Hit on Frame SO, triangle %d %f %f %f, M=[%d %d]\n"
6782 " Pixel hit: %.2f %.2f %.2f\n",
6783 MTI->ifacemin, MTI->P[0], MTI->P[1], MTI->P[2], M[0], M[1],
6784 I[0], I[1], I[2]);
6785
6786 for (i=0; i<3; ++i) {
6787 /* I[i] = I[i]/GB[i]; Account for per value gain and
6788 background thickness */
6789 /* Round I to get matrix pixel coordinates*/
6790 I[i] = SUMA_ROUND(I[i]);
6791 if (I[i] < 0) IIm[i] = -1;
6792 else if (I[i] >= GB[i]*N[i]) IIm[i] = -1;
6793 else IIm[i] = (int)(I[i]/GB[i]); /* Undo gain to get back to matrix grid */
6794 }
6795
6796 if (ui) { /* sparse hell */
6797 if (IIm[0]>=0) ii = ui[IIm[0]];
6798 else ii = -1;
6799 if (IIm[1]>=0) jj = uj[IIm[1]];
6800 else jj = -1;
6801 } else {
6802 ii = IIm[0]; jj=IIm[1];
6803 }
6804
6805 SUMA_LHv("In face %d X=[%f %f %f]dicom, GB=[%d %d] \n"
6806 " If=[%f %f %f], Im=[%d %d %d], ii,jj=[%d %d]\n",
6807 MTI->ifacemin, MTI->P[0], MTI->P[1], MTI->P[2],
6808 (int)GB[0], (int)GB[1],
6809 I[0], I[1], I[2], IIm[0], IIm[1], IIm[2], ii, jj);
6810
6811 switch (MTI->ifacemin) {
6812 case 0:
6813 case 1:
6814 /* in matrix */
6815 PR->primitive = SUMA_replace_string(PR->primitive, "segments");
6816 if (!ui && ii >= 0 && jj >= 0) {
6817 PR->datum_index = PR->primitive_index = ii+jj*N[0];
6818 } else { /* sparse */
6819 if (ii < 0 || jj < 0) {
6820 PR->datum_index = PR->primitive_index = -1;
6821 } else if (!SUMA_GDSET_PointsToSegIndex(dset, ii, jj, &si)) {
6822 SUMA_S_Errv("Failed to find segment for %d %d\n", ii, jj);
6823 if (LocalHead) SUMA_DUMP_TRACE("Now what?");
6824 PR->datum_index = PR->primitive_index = -1;
6825 } else {
6826 PR->datum_index = PR->primitive_index = si;
6827 }
6828 }
6829 if (MTI->ifacemin == 1) {
6830 PR->iAltSel[SUMA_ENODE_0] = ii;
6831 PR->iAltSel[SUMA_ENODE_1] = jj;
6832 } else {
6833 PR->iAltSel[SUMA_ENODE_0] = jj;
6834 PR->iAltSel[SUMA_ENODE_1] = ii;
6835 }
6836 break;
6837 case 2:
6838 case 3:
6839 /* top edge*/
6840 PR->primitive = SUMA_replace_string(PR->primitive, "balls");
6841 PR->iAltSel[SUMA_ENODE_0] = jj;
6842 PR->iAltSel[SUMA_ENODE_1] = -1;
6843 break;
6844 case 4:
6845 case 5:
6846 /* right edge*/
6847 PR->primitive = SUMA_replace_string(PR->primitive, "balls");
6848 PR->iAltSel[SUMA_ENODE_0] = ii;
6849 PR->iAltSel[SUMA_ENODE_1] = -1;
6850 break;
6851 case 6:
6852 case 7:
6853 /* bottom edge*/
6854 PR->primitive = SUMA_replace_string(PR->primitive, "balls");
6855 PR->iAltSel[SUMA_ENODE_0] = jj;
6856 PR->iAltSel[SUMA_ENODE_1] = -1;
6857 break;
6858 case 8:
6859 case 9:
6860 /* left edge*/
6861 PR->primitive = SUMA_replace_string(PR->primitive, "balls");
6862 PR->iAltSel[SUMA_ENODE_0] = ii;
6863 PR->iAltSel[SUMA_ENODE_1] = -1;
6864 break;
6865 default:
6866 SUMA_S_Errv("Faceset %d???\n", MTI->ifacemin);
6867 SUMA_RETURN(PR);
6868 }
6869
6870 MTI = SUMA_Free_MT_intersect_triangle(MTI);
6871
6872 SUMA_RETURN(PR);
6873 }
6874
6875 /*!
6876 \brief find the closest location on a bundle to a point
6877 on the screen.
6878
6879 p (void *) One bundle
6880 ptype (char): Type of bundle. 'N' --> p is a NI_element *
6881 'B' --> p is a TAYLOR_BUNDLE *
6882 Tmask (int): if not < 0 then only consider intersections in
6883 tract Tmask of the bundle.
6884 sv (SUMA_SurfaceViewer *) The viewer
6885 scpx (float *) The pixel location in screen coordinates.
6886 If NULL, form it from sv->PickPix;
6887 crude (int) if (0) then use crude search, return closest point
6888 not bothering with where along the segment
6889 between the two closest points you are
6890 1 a fine search, locating where between
6891 the two closest points one clicked
6892 tmin (int *) Will contain the index of the tract that was
6893 hit within the bundle (-1 for no cigar)
6894 pmin (int *) Will contain the index of the closest point
6895 to the hit in tract tmin
6896 fmin (float *) Will contain the fraction between pmin and
6897 pmin+1 where intersection occurred
6898 mindist (float *) Distance from closest location on tract
6899 \ret YUP all good, NOPE nothing found or bad input
6900 */
6901
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)6902 SUMA_Boolean SUMA_Bundle_Pick_Intersect(void *p, char ptype, int Tmask,
6903 SUMA_SurfaceViewer *sv, float *scpxu, int crude,
6904 int *tmin, int *pmin, float *frmin, float *mindistu)
6905 {
6906 static char FuncName[]={"SUMA_Bundle_Pick_Intersect"};
6907 int nn, nnmin, mmmin, mm, nn_max, nn_min;
6908 float *scrxyz = NULL, dx, dy, dxy2=0.0, fmin, scpx[3];
6909 float mindist2, mindist, *A, *B;
6910 double P[3], f = 0.0;
6911 NI_element *nelitp=NULL;
6912 TAYLOR_BUNDLE *tb = NULL;
6913 TAYLOR_TRACT *ttn=NULL;
6914
6915 SUMA_ENTRY;
6916
6917 if (tmin) *tmin = -1;
6918 if (pmin) *pmin = -1;
6919 if (frmin) *frmin = -1.0;
6920 if (mindistu) *mindistu = -1.0;
6921
6922 if (!p || !sv) SUMA_RETURN(NOPE);
6923
6924 nn_min = 0;
6925 if (ptype == 'N') { /* NI_element */
6926 nelitp = (NI_element *)p;
6927 nn_max = nelitp->vec_len;
6928 } else if (ptype == 'B') { /* Taylor Bundle */
6929 tb = (TAYLOR_BUNDLE *)p;
6930 if (Tmask < 0) {
6931 nn_max = tb->N_tracts;
6932 } else {
6933 if (Tmask < tb->N_tracts) {
6934 nn_min = Tmask;
6935 nn_max = nn_min+1;
6936 } else {
6937 SUMA_S_Err("Tmask (%d) exceeds number of tracts (%d) in bundle",
6938 Tmask, tb->N_tracts);
6939 SUMA_RETURN(NOPE);
6940 }
6941 }
6942 } else {
6943 SUMA_RETURN(NOPE);
6944 }
6945
6946 nnmin=-1; mmmin=-1; mindist=mindist2=1000; fmin=1.0;
6947 if (scpxu) {
6948 scpx[0] = scpxu[0]; scpx[1] = scpxu[1]; scpx[2] = scpxu[2];
6949 } else {
6950 GLint viewport[4];
6951 glGetIntegerv(GL_VIEWPORT, viewport);
6952 /* screen pick coordinate in screen coords */
6953 scpx[0] = sv->PickPix[0];
6954 scpx[1] = viewport[3]-sv->PickPix[1]-1;
6955 scpx[2] = 0.0;
6956 }
6957
6958 for (nn=nn_min; nn<nn_max; ++nn) {
6959 if (nelitp) {
6960 ttn = (TAYLOR_TRACT *)(nelitp->vec[0])+nn;
6961 } else {
6962 ttn = tb->tracts+nn;
6963 }
6964 scrxyz = (float *)SUMA_calloc(ttn->N_pts3, sizeof(float));
6965 memcpy(scrxyz, ttn->pts, (ttn->N_pts3)*sizeof(float));
6966 /* tranform bundle points to screen space*/
6967 if (!SUMA_World2ScreenCoordsF(sv, ttn->N_pts3/3,
6968 ttn->pts, scrxyz, NULL,
6969 YUP, YUP)) {
6970 SUMA_S_Err("Failed to get screen coords");
6971 SUMA_RETURN(NOPE);
6972 }
6973 /* Now search for the closest point of bundle to the click
6974 The depth is ignored, in the hope that a simple closest
6975 search is enough. Otherwise we need to add a heuristic
6976 for the cost of depth */
6977 if (crude) {
6978 /* For finer tracing, you should project scpx onto the
6979 segment between the 1st and 2 points forming a segment,
6980 much like what is done in SUMA_PROJECT_C_ONTO_AB below
6981 The finer tracing is needed for crass paths. However
6982 for real bundles, on high-res data this might be
6983 overkill */
6984 mm=0;
6985 while (mm < ttn->N_pts3) {
6986 if ( ((dx = SUMA_ABS(scrxyz[mm ]-scpx[0])) < mindist) &&
6987 ((dy = SUMA_ABS(scrxyz[mm+1]-scpx[1])) < mindist) ){ if ((dxy2 = dx*dx+dy*dy) < mindist2) {
6988 mindist2 = dxy2;
6989 mindist = sqrtf(mindist2);
6990 nnmin=nn; mmmin=mm/3; fmin = 0.0;
6991 }
6992 }
6993 mm += 3;
6994 }
6995 } else {
6996 mm=0;
6997 while (mm < ttn->N_pts3-3) {
6998 A = scrxyz+mm;
6999 B = scrxyz+mm+3;
7000 SUMA_PROJECT_C_ONTO_AB(scpx, A, B, P, f);
7001 if ( (f > -0.2 && f < 1.2) &&
7002 ((dx = SUMA_ABS(P[0]-scpx[0])) < mindist) &&
7003 ((dy = SUMA_ABS(P[1]-scpx[1])) < mindist) ){ if ((dxy2 = dx*dx+dy*dy) < mindist2) {
7004 mindist2 = dxy2;
7005 mindist = sqrtf(mindist2);
7006 nnmin=nn; mmmin=mm/3; fmin=f;
7007 }
7008 }
7009 mm += 3;
7010 }
7011 }
7012 SUMA_ifree(scrxyz);
7013 }
7014
7015 if (tmin) *tmin=nnmin;
7016 if (pmin) *pmin=mmmin;
7017 if (frmin) *frmin=fmin;
7018 if (mindistu) *mindistu = mindist;
7019
7020 SUMA_RETURN(YUP);
7021 }
7022
7023 /* Find the object that was picked, pointer copy to found object is
7024 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)7025 SUMA_PICK_RESULT *SUMA_WhatWasPicked(SUMA_SurfaceViewer *sv, GLubyte *colid,
7026 SUMA_COLID_OFFSET_DATUM **ucodf,
7027 int ipick, int jpick,
7028 SUMA_PICK_RESULT *PR)
7029 {
7030 static char FuncName[]={"SUMA_WhatWasPicked"};
7031 DListElmt *el=NULL;
7032 SUMA_COLID_OFFSET_DATUM *cod=NULL, *codf=NULL;
7033 long int n4;
7034 int iii;
7035 double f = 0.0;
7036 SUMA_ALL_DO *ado=NULL;
7037 SUMA_DUMB_DO DDO;
7038 SUMA_Boolean LocalHead = NOPE;
7039
7040 SUMA_ENTRY;
7041
7042 if (ucodf) *ucodf=codf;
7043 PR = SUMA_New_Pick_Result(PR);
7044 if (!sv || !colid) {
7045 SUMA_S_Err("NULL input");
7046 SUMA_RETURN(PR);
7047 }
7048 if (!sv->pick_colid_list || !dlist_size(sv->pick_colid_list)) {
7049 SUMA_S_Err("NULL or Empty pick_colid_list");
7050 SUMA_RETURN(PR);
7051 }
7052 if (LocalHead) SUMA_Show_Pick_Colid_List(sv->pick_colid_list, SUMA_STDERR);
7053 SUMA_COLID_RGBA2N(colid[0], colid[1], colid[2], colid[3], n4);
7054 do {
7055 if (!el) el = dlist_head(sv->pick_colid_list);
7056 else el = dlist_next(el);
7057 cod = (SUMA_COLID_OFFSET_DATUM *)el->data;
7058 if (n4>= cod->i0 && n4<= cod->i1) { /* we're in this object */
7059 codf = cod;
7060 }
7061 } while (!codf && el != dlist_tail(sv->pick_colid_list));
7062
7063 if (!codf) SUMA_RETURN(PR);
7064 if (ucodf) *ucodf=codf;
7065
7066 /* Compute get more info about intersection */
7067 if (codf) {
7068 NI_element *nelitp=NULL;
7069 float *fv=NULL;
7070 double xyzw[9], scl[9], U[3], P[3], C[3], *dv=NULL;
7071 int i0, i1, ir, datum_index;
7072 SUMA_ALL_DO *ado=NULL;
7073 SUMA_DSET *dset=NULL;
7074 GLint viewport[4];
7075 SUMA_GRAPH_SAUX *GSaux = NULL;
7076
7077 glGetIntegerv(GL_VIEWPORT, viewport);
7078 PR->ado_idcode_str = SUMA_replace_string(PR->ado_idcode_str,
7079 codf->ref_idcode_str);
7080 PR->primitive = SUMA_replace_string(PR->primitive, codf->primitive);
7081 PR->primitive_index = (n4-codf->i0);
7082 for (i0=0; i0<SUMA_N_IALTSEL_TYPES; ++i0) PR->iAltSel[i0] = -1;
7083 for (i0=0; i0<SUMA_N_DALTSEL_TYPES; ++i0) PR->dAltSel[i0] = 0.0;
7084 PR->datum_index = -1;
7085 ado = SUMA_whichADOg(PR->ado_idcode_str);
7086 switch (codf->ref_do_type) {
7087 case GRAPH_LINK_type: {
7088 dset = SUMA_find_GLDO_Dset((SUMA_GraphLinkDO*)ado);
7089 DDO.err = 1; SUMA_Load_Dumb_DO(ado, &DDO);
7090 if (DDO.err) {
7091 if (DDO.err==1) {
7092 SUMA_SL_Err("Object's parent graph set not found.");
7093 } else if (DDO.err==2) {
7094 SUMA_SL_Err("Could not fill DDO");
7095 } else {
7096 SUMA_SL_Err("Weird error.");
7097 }
7098 SUMA_RETURN (PR);
7099 }
7100 if (!DDO.NodeList) {
7101 SUMA_S_Err("SDO is node based but could not get a NodeList");
7102 SUMA_RETURN (PR);
7103 }
7104 if (!(GSaux = SDSET_GSAUX(dset))) {
7105 SUMA_S_Err("No GSaux");
7106 SUMA_RETURN(PR);
7107 }
7108 GSaux->IgnoreSelection = 0; /*reset ignore selection flag */
7109 if (SUMA_is_ADO_Datum_Primitive(ado, codf)) {
7110 datum_index = SUMA_GDSET_EdgeRow_To_Index(dset,
7111 PR->primitive_index);
7112 if (!(SUMA_GDSET_SegIndexToPoints(dset, datum_index,
7113 &i0, &i1, NULL))) {
7114 SUMA_RETURN(PR);
7115 }
7116 nelitp = NULL;
7117 if (GSaux->ShowBundles &&
7118 (nelitp = SUMA_GDSET_Edge_Bundle(dset, GSaux,
7119 datum_index, -1))) {
7120 #if 1 /* more unified version, older, valid one below */
7121 int nn=0, mm=0, nnmin=-1, mmmin=-1, mmmin3=-1;
7122 float scpx[3], *A, *B;
7123 float mindist, dist, distatmin, seglen;
7124 float fmin;
7125 TAYLOR_TRACT *ttn=NULL;
7126
7127 SUMA_LHv("Clicked on a bundle representation of edge %d.\n",
7128 datum_index);
7129 /* screen pick coordinate in screen coords */
7130 scpx[0] = sv->PickPix[0];
7131 scpx[1] = viewport[3]-sv->PickPix[1]-1;
7132 scpx[2] = 0.0;
7133 /* find the closest point to where we clicked on the bundle */
7134 if (!SUMA_Bundle_Pick_Intersect(nelitp, 'N', -1, sv, scpx, 0,
7135 &nnmin, &mmmin,
7136 &fmin, &mindist)) {
7137 SUMA_LH("No bunlde intersection");
7138 }
7139 mmmin3 = 3*mmmin;
7140 if (nnmin > -1) {
7141 ttn = (TAYLOR_TRACT *)(nelitp->vec[0])+nnmin;
7142 if (fmin != 0.0f) {
7143 PR->PickXYZ[0]=ttn->pts[mmmin3+0]+
7144 fmin*(ttn->pts[mmmin3+3]-ttn->pts[mmmin3]);
7145 PR->PickXYZ[1]=ttn->pts[mmmin3+1]+
7146 fmin*(ttn->pts[mmmin3+4]-ttn->pts[mmmin3+1]);
7147 PR->PickXYZ[2]=ttn->pts[mmmin3+2]+
7148 fmin*(ttn->pts[mmmin3+5]-ttn->pts[mmmin3+2]);
7149 /* where along the tract? */
7150 mm=0; dist=0.0; distatmin=19999.9;
7151 while (mm < ttn->N_pts3-3) {
7152 A = ttn->pts+mm;
7153 B = ttn->pts+mm+3;
7154 seglen = sqrtf((B[0]-A[0])*(B[0]-A[0])+
7155 (B[1]-A[1])*(B[1]-A[1])+
7156 (B[2]-A[2])*(B[2]-A[2]));
7157 if (mm==mmmin3) {
7158 distatmin = dist + fmin*seglen;
7159 }
7160 dist +=seglen;
7161 mm += 3;
7162 }
7163 /* Which is the closest node? */
7164 f = distatmin/dist;
7165 if (f <= 0.5) {
7166 PR->iAltSel[SUMA_ENODE_0] = i0;
7167 PR->iAltSel[SUMA_ENODE_0] = i1;
7168 if (SUMA_ABS(f)> 0.01) {/* not too close to edge */
7169 PR->datum_index = datum_index;
7170 } else PR->datum_index = -1;
7171 } else {
7172 SUMA_LHv("++half way, look for opp. edge [%d %d]\n",
7173 i1, i0);
7174 PR->iAltSel[SUMA_ENODE_0] = i1;
7175 PR->iAltSel[SUMA_ENODE_1] = i0;
7176
7177 if (SUMA_ABS(1.0-f) > 0.01){/*not too close to edge*/
7178 /* does edge [i1, i0] exist? If so take it*/
7179 if (SUMA_GDSET_PointsToSegIndex(dset,i1,i0,&ir)) {
7180 SUMA_LHv("Switching primitve to edge %d\n", ir);
7181 PR->datum_index = ir;
7182 } else { /* leave old hit, no opposite edge */
7183 PR->datum_index = datum_index;
7184 }
7185 } else PR->datum_index = -1;
7186 }
7187 } else { /* from the quick search, no fmin used*/
7188 PR->PickXYZ[0]=ttn->pts[mmmin3+0];
7189 PR->PickXYZ[1]=ttn->pts[mmmin3+1];
7190 PR->PickXYZ[2]=ttn->pts[mmmin3+2];
7191 }
7192 } else {
7193 PR->PickXYZ[0] = PR->PickXYZ[1] = PR->PickXYZ[2]=0.0;
7194 }
7195 SUMA_LHv("Closest distance of %f, tract %d, point %d, f=%f\n"
7196 "at world [%f %f %f]\n",
7197 mindist, nnmin, mmmin, fmin,
7198 PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2]);
7199 #else
7200 int nn=0, mm=0, nnmin=-1, mmmin=-1;
7201 float *scrxyz = NULL, scpx[3], *A, *B;
7202 float mindist, mindist2, dist, distatmin, seglen;
7203 float dx, dy, dxy2=0.0, fmin;
7204 TAYLOR_TRACT *ttn=NULL;
7205
7206 SUMA_LHv("Clicked on a bundle representation of edge %d.\n",
7207 datum_index);
7208 /* screen pick coordinate in screen coords */
7209 scpx[0] = sv->PickPix[0];
7210 scpx[1] = viewport[3]-sv->PickPix[1]-1;
7211 scpx[2] = 0.0;
7212 /* find the closest point to where we clicked on the bundle */
7213 nnmin=-1; mmmin=-1; mindist=mindist2=1000; fmin=1.0;
7214 for (nn=0; nn<nelitp->vec_len; ++nn) {
7215 ttn = (TAYLOR_TRACT *)(nelitp->vec[0])+nn;
7216 scrxyz = (float *)SUMA_calloc(ttn->N_pts3, sizeof(float));
7217 memcpy(scrxyz, ttn->pts, (ttn->N_pts3)*sizeof(float));
7218 /* tranform bundle points to screen space*/
7219 if (!SUMA_World2ScreenCoordsF(sv, ttn->N_pts3/3,
7220 ttn->pts, scrxyz, NULL,
7221 YUP, YUP)) {
7222 SUMA_S_Err("Failed to get screen coords");
7223 SUMA_RETURN(PR);
7224 }
7225 /* Now search for the closest point of bundle to the click
7226 The depth is ignored, in the hope that a simple closest
7227 search is enough. Otherwise we need to add a heuristic
7228 for the cost of depth */
7229 #ifdef CRUDE_SEARCH
7230 /* For finer tracing, you should project scpx onto the
7231 segment between the 1st and 2 points forming a segment,
7232 much like what is done in SUMA_PROJECT_C_ONTO_AB below
7233 The finer tracing is needed for crass paths. However
7234 for real bundles, on high-res data this might be
7235 overkill */
7236 mm=0;
7237 while (mm < ttn->N_pts3) {
7238 if ( ((dx = SUMA_ABS(scrxyz[mm ]-scpx[0])) < mindist) &&
7239 ((dy = SUMA_ABS(scrxyz[mm+1]-scpx[1])) < mindist) ){ if ((dxy2 = dx*dx+dy*dy) < mindist2) {
7240 mindist2 = dxy2;
7241 mindist = sqrtf(mindist2);
7242 nnmin=nn; mmmin=mm; fmin = 0.0;
7243 }
7244 }
7245 mm += 3;
7246 }
7247 #else
7248 mm=0;
7249 while (mm < ttn->N_pts3-3) {
7250 A = scrxyz+mm;
7251 B = scrxyz+mm+3;
7252 SUMA_PROJECT_C_ONTO_AB(scpx, A, B, P, f);
7253 if ( ((dx = SUMA_ABS(P[0]-scpx[0])) < mindist) &&
7254 ((dy = SUMA_ABS(P[1]-scpx[1])) < mindist) ){ if ((dxy2 = dx*dx+dy*dy) < mindist2) {
7255 mindist2 = dxy2;
7256 mindist = sqrtf(mindist2);
7257 nnmin=nn; mmmin=mm; fmin=f;
7258 }
7259 }
7260 mm += 3;
7261 }
7262 #endif
7263 SUMA_ifree(scrxyz);
7264 }
7265 if (nnmin > -1) {
7266 ttn = (TAYLOR_TRACT *)(nelitp->vec[0])+nnmin;
7267 if (fmin != 0.0f) {
7268 PR->PickXYZ[0]=ttn->pts[mmmin+0]+
7269 fmin*(ttn->pts[mmmin+3]-ttn->pts[mmmin]);
7270 PR->PickXYZ[1]=ttn->pts[mmmin+1]+
7271 fmin*(ttn->pts[mmmin+4]-ttn->pts[mmmin+1]);
7272 PR->PickXYZ[2]=ttn->pts[mmmin+2]+
7273 fmin*(ttn->pts[mmmin+5]-ttn->pts[mmmin+2]);
7274 /* where along the tract? */
7275 mm=0; dist=0.0; distatmin=19999.9;
7276 while (mm < ttn->N_pts3-3) {
7277 A = ttn->pts+mm;
7278 B = ttn->pts+mm+3;
7279 seglen = sqrtf((B[0]-A[0])*(B[0]-A[0])+
7280 (B[1]-A[1])*(B[1]-A[1])+
7281 (B[2]-A[2])*(B[2]-A[2]));
7282 if (mm==mmmin) {
7283 distatmin = dist + fmin*seglen;
7284 }
7285 dist +=seglen;
7286 mm += 3;
7287 }
7288 /* Which is the closest node? */
7289 f = distatmin/dist;
7290 if (f <= 0.5) {
7291 PR->iAltSel[SUMA_ENODE_0] = i0;
7292 PR->iAltSel[SUMA_ENODE_1] = i1;
7293
7294 if (SUMA_ABS(f)> 0.01) {/* not too close to edge */
7295 PR->datum_index = datum_index;
7296 } else PR->datum_index = -1;
7297 } else {
7298 SUMA_LHv("++half way, look for opp. edge [%d %d]\n",
7299 i1, i0);
7300 PR->iAltSel[SUMA_ENODE_0] = i1;
7301 PR->iAltSel[SUMA_ENODE_1] = i0;
7302 if (SUMA_ABS(1.0-f) > 0.01){/*not too close to edge*/
7303 /* does edge [i1, i0] exist? If so take it*/
7304 if (SUMA_GDSET_PointsToSegIndex(dset,i1,i0,&ir)) {
7305 SUMA_LHv("Switching primitve to edge %d\n", ir);
7306 PR->datum_index = ir;
7307 } else { /* leave old hit, no opposite edge */
7308 PR->datum_index = datum_index;
7309 }
7310 } else PR->datum_index = -1;
7311 }
7312 } else { /* from the quick search, no fmin used*/
7313 PR->PickXYZ[0]=ttn->pts[mmmin+0];
7314 PR->PickXYZ[1]=ttn->pts[mmmin+1];
7315 PR->PickXYZ[2]=ttn->pts[mmmin+2];
7316 }
7317 } else {
7318 PR->PickXYZ[0] = PR->PickXYZ[1] = PR->PickXYZ[2]=0.0;
7319 }
7320 SUMA_LHv("Closest distance of %f, tract %d, point %d, f=%f\n"
7321 "at world [%f %f %f]\n",
7322 mindist, nnmin, mmmin, fmin,
7323 PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2]);
7324
7325 #endif
7326 } else {
7327 SUMA_LHv("Segment %d is formed by points %d and %d\n",
7328 datum_index, i0, i1);
7329 fv = SUMA_GDSET_NodeXYZ(dset, i0, SUMA_ADO_variant(ado), NULL);
7330 xyzw[0] = fv[0]; xyzw[1] = fv[1]; xyzw[2] = fv[2];
7331 fv = SUMA_GDSET_NodeXYZ(dset, i1, SUMA_ADO_variant(ado), NULL);
7332 xyzw[3] = fv[0]; xyzw[4] = fv[1]; xyzw[5] = fv[2];
7333 xyzw[6] = (sv->Pick0[0]+sv->Pick1[0])/2.0;
7334 xyzw[7] = (sv->Pick0[1]+sv->Pick1[1])/2.0;
7335 xyzw[8] = (sv->Pick0[2]+sv->Pick1[2])/2.0;
7336
7337 if (!SUMA_World2ScreenCoords(sv, 3,xyzw,scl, NULL, YUP, YUP)) {
7338 SUMA_S_Err("Failed to get screen coords");
7339 SUMA_RETURN(PR);
7340 }
7341 /* Project click point onto line by two nodes */
7342 C[0] = sv->PickPix[0];
7343 C[1] = viewport[3]-sv->PickPix[1]-1;
7344 C[2] = 0;
7345 dv = scl+3; /* point B */
7346 SUMA_PROJECT_C_ONTO_AB(C, scl, dv, P, f);
7347 /* Project point click onto segment */
7348 SUMA_LHv(
7349 "User click locations: %d %d Norm(%f %f)\n"
7350 "sv PickPix: %d %d (screen/mouse y:%d)\n"
7351 "world: near[%f %f %f] far[%f %f %f]\n"
7352 "Edge %d formed by nodes %d [%f %f %f], %d [%f %f %f]\n"
7353 "Nodes projected to screen: [%f %f %f], [%f %f %f]\n"
7354 "Projection of click point screen edge: [%f %f %f], f = %f\n"
7355 ,ipick, jpick,
7356 ipick/(double)viewport[2], jpick/(double)viewport[3],
7357 sv->PickPix[0], sv->PickPix[1], viewport[3]-jpick-1,
7358 sv->Pick0[0], sv->Pick0[1], sv->Pick0[2],
7359 sv->Pick1[0], sv->Pick1[1], sv->Pick1[2],
7360 datum_index, i0, xyzw[0], xyzw[1], xyzw[2],
7361 i1, xyzw[3], xyzw[4], xyzw[5],
7362 scl[0], scl[1], scl[2], scl[3], scl[4], scl[5],
7363 P[0], P[1], P[2], f);
7364
7365 /* Record the intersection location */
7366 PR->PickXYZ[0]=xyzw[0]+f*(xyzw[3]-xyzw[0]);
7367 PR->PickXYZ[1]=xyzw[1]+f*(xyzw[4]-xyzw[1]);
7368 PR->PickXYZ[2]=xyzw[2]+f*(xyzw[5]-xyzw[2]);
7369
7370 /* Which is the closest node? */
7371 if (f <= 0.5) {
7372 PR->iAltSel[SUMA_ENODE_0] = i0;
7373 PR->iAltSel[SUMA_ENODE_1] = i1;
7374 if (SUMA_ABS(f)> 0.01) {/* not too close to edge */
7375 PR->datum_index = datum_index;
7376 } else PR->datum_index = -1;
7377 } else {
7378 SUMA_LHv("++half way, looking for opp. edge [%d %d]\n",
7379 i1, i0);
7380 PR->iAltSel[SUMA_ENODE_0] = i1;
7381 PR->iAltSel[SUMA_ENODE_1] = i0;
7382 if (SUMA_ABS(1.0-f) > 0.01) { /* not too close to edge */
7383 /* does edge [i1, i0] exist? If so take it*/
7384 if (SUMA_GDSET_PointsToSegIndex(dset, i1, i0, &ir)) {
7385 SUMA_LHv("Switching primitve to edge %d\n", ir);
7386 PR->datum_index = ir;
7387 } else { /* leave old hit, no opposite edge */
7388 PR->datum_index = datum_index;
7389 }
7390 } else PR->datum_index = -1;
7391 }
7392 }
7393 } else { /* picked a node, no data on it*/
7394 PR->iAltSel[SUMA_ENODE_0] =
7395 SUMA_GDSET_Index_To_NodeIndex(dset, PR->primitive_index);
7396 PR->iAltSel[SUMA_ENODE_1] = -1;
7397 PR->datum_index = -1;
7398 fv = SUMA_GDSET_NodeXYZ(dset, PR->iAltSel[SUMA_ENODE_0],
7399 SUMA_ADO_variant(ado), NULL);
7400 PR->PickXYZ[0]=fv[0]; PR->PickXYZ[1]=fv[1]; PR->PickXYZ[2]=fv[2];
7401 }
7402 break; }
7403 case GDSET_type:
7404 SUMA_S_Err("I don't expect graph dsets to be picked directly");
7405 break;
7406 case CDOM_type:
7407 SUMA_S_Err("CIFTI not picked on buffer");
7408 break;
7409 case VO_type:
7410 SUMA_S_Err("VOs not picked on buffer....");
7411 break;
7412 case MASK_type:
7413 SUMA_S_Err("Masks not picked on buffer....");
7414 break;
7415 case TRACT_type:
7416 {
7417 SUMA_TractDO *tdo=(SUMA_TractDO *)ado;
7418 int nn=0, mm=0, nnmin=-1, mmmin=-1, mmmin3=-1, oki=0, it=0, ib=0;
7419 float *scrxyz = NULL;
7420 float mindist, dist;
7421 float fmin;
7422 TAYLOR_TRACT *ttn=NULL;
7423 TAYLOR_BUNDLE *tb=NULL;
7424
7425 oki = 0;
7426 if (!strcmp(PR->primitive,"bundles")) {
7427 ib = PR->primitive_index;
7428 SUMA_LHv("Seeking bundle %d/%d\n",
7429 (int)PR->primitive_index, tdo->net->N_tbv);
7430 tb = TDO_BUNDLE(tdo, PR->primitive_index);
7431 if (!(oki=SUMA_Bundle_Pick_Intersect(tb, 'B', -1, sv, NULL, 0,
7432 &nnmin, &mmmin, &fmin, &mindist))) {
7433 SUMA_LH("No bunlde intersection");
7434 }
7435 } else if (!strcmp(PR->primitive,"tracts")) {
7436 SUMA_LHv("Seeking tract %d/%d\n",
7437 (int)PR->primitive_index, TDO_N_TRACTS(tdo));
7438 if (Network_1T_to_TB(tdo->net,
7439 (int)PR->primitive_index, &it, &ib, NULL, NULL) < 0) {
7440 SUMA_S_Err("Failed to resolve tract index");
7441 } else {
7442 tb = TDO_BUNDLE(tdo, ib);
7443 if (!(oki=SUMA_Bundle_Pick_Intersect(tb, 'B', it, sv, NULL, 0,
7444 &nnmin, &mmmin, &fmin, &mindist))) {
7445 SUMA_LH("No tract intersection");
7446 }
7447 }
7448 }
7449 if (oki) {
7450 if (nnmin > -1) {
7451 mmmin3=3*mmmin;
7452 ttn = tb->tracts+nnmin;
7453 if (fmin != 0.0f) {
7454 PR->PickXYZ[0]=ttn->pts[mmmin3+0]+
7455 fmin*(ttn->pts[mmmin3+3]-ttn->pts[mmmin3]);
7456 PR->PickXYZ[1]=ttn->pts[mmmin3+1]+
7457 fmin*(ttn->pts[mmmin3+4]-ttn->pts[mmmin3+1]);
7458 PR->PickXYZ[2]=ttn->pts[mmmin3+2]+
7459 fmin*(ttn->pts[mmmin3+5]-ttn->pts[mmmin3+2]);
7460 } else {
7461 /* from the quick search, no fmin used*/
7462 PR->PickXYZ[0]=ttn->pts[mmmin3+0];
7463 PR->PickXYZ[1]=ttn->pts[mmmin3+1];
7464 PR->PickXYZ[2]=ttn->pts[mmmin3+2];
7465 }
7466 PR->iAltSel[SUMA_TRC_PNT] = mmmin;
7467 PR->iAltSel[SUMA_BUN_TRC] = nnmin;
7468 PR->iAltSel[SUMA_NET_BUN] = ib;
7469 PR->datum_index = Network_PTB_to_1P(tdo->net,
7470 PR->iAltSel[SUMA_TRC_PNT],
7471 PR->iAltSel[SUMA_BUN_TRC],
7472 PR->iAltSel[SUMA_NET_BUN]);
7473 PR->iAltSel[SUMA_NET_TRC] = Network_TB_to_1T(tdo->net,
7474 PR->iAltSel[SUMA_BUN_TRC],
7475 PR->iAltSel[SUMA_NET_BUN]);
7476 SUMA_LHv("Bundle %ld intersected, tract %ld, "
7477 "point %ld, tract in net %ld. \n"
7478 "Point NetID: %ld\n"
7479 "XYZ[%.3f %.3f %.3f], fmin=%f\n",
7480 PR->iAltSel[SUMA_NET_BUN],
7481 PR->iAltSel[SUMA_BUN_TRC],
7482 PR->iAltSel[SUMA_TRC_PNT],
7483 PR->iAltSel[SUMA_NET_TRC], PR->datum_index,
7484 PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2], fmin);
7485
7486 #if 0 /* Just to debug reverse lookup */
7487 if (Network_1P_to_PTB(tdo->net, PR->datum_index,
7488 &mmmin, &nnmin, &nn, NULL) < 0) {
7489 SUMA_S_Err("Failed in reverse lookup test");
7490 } else {
7491 SUMA_LHv("Inverse lookup: %ld --> P %d, T %d, B %d\n",
7492 PR->datum_index, mmmin, nnmin, nn);
7493 }
7494 #endif
7495 }
7496 }
7497 f = fmin;
7498 break; }
7499 default:
7500 SUMA_S_Warnv("Not ready to get location for %s\n",
7501 SUMA_ObjectTypeCode2ObjectTypeName(codf->ref_do_type));
7502 break;
7503 }
7504 }
7505
7506 /* report */
7507 if (codf) {
7508 SUMA_S_Notev("\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n"
7509 "DO pick: colid (%ld=[%d %d %d %d]) \n"
7510 " is in <%s, %s, %s>, f=%1.3f\n"
7511 " datum = %ld, iAltSel = [",
7512 n4, colid[0], colid[1], colid[2], colid[3],
7513 cod->Label, cod->variant, cod->primitive, f,
7514 PR->datum_index);
7515 for (iii=0; iii<SUMA_N_IALTSEL_TYPES; ++iii)
7516 fprintf(SUMA_STDOUT, "%ld, ", PR->iAltSel[iii]);
7517 fprintf(SUMA_STDOUT, "]\n dAltSel = [");
7518 for (iii=0; iii<SUMA_N_DALTSEL_TYPES; ++iii)
7519 fprintf(SUMA_STDOUT, "%.3f, ", PR->dAltSel[iii]);
7520 fprintf(SUMA_STDOUT, "]\n"
7521 "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
7522 }
7523
7524 SUMA_RETURN(PR);
7525 }
7526
SUMA_New_Pick_Result(SUMA_PICK_RESULT * PR)7527 SUMA_PICK_RESULT *SUMA_New_Pick_Result(SUMA_PICK_RESULT *PR)
7528 {
7529 static char FuncName[]={"SUMA_New_Pick_Result"};
7530 int i;
7531 if (!PR) {
7532 PR = (SUMA_PICK_RESULT *)SUMA_calloc(1,sizeof(SUMA_PICK_RESULT));
7533 }
7534 PR->primitive_index = -1;
7535 PR->datum_index = -1;
7536 for (i=0; i<SUMA_N_IALTSEL_TYPES; ++i) PR->iAltSel[i] = -1;
7537 for (i=0; i<SUMA_N_DALTSEL_TYPES; ++i) PR->dAltSel[i] = 0.0;
7538 SUMA_ifree(PR->primitive);
7539 SUMA_ifree(PR->ado_idcode_str);
7540 /* Imprint with event structure */
7541 PR->evr = (SUMA_EVENT *)malloc(sizeof(SUMA_EVENT));
7542 if (SUMAg_CF->lev) memcpy(PR->evr, SUMAg_CF->lev, sizeof(SUMA_EVENT));
7543 else memset(PR->evr, 0, sizeof(SUMA_EVENT));
7544 /* SUMA_ShowEvent(PR->evr, 0, "From New Pick Result\n"); */
7545 return(PR);
7546 }
7547
SUMA_free_PickResult(SUMA_PICK_RESULT * PR)7548 SUMA_PICK_RESULT *SUMA_free_PickResult(SUMA_PICK_RESULT *PR)
7549 {
7550 static char FuncName[]={"SUMA_free_PickResult"};
7551 SUMA_ENTRY;
7552 if (!PR) SUMA_RETURN(PR);
7553 SUMA_ifree(PR->primitive);
7554 SUMA_ifree(PR->ado_idcode_str);
7555 SUMA_ifree(PR->dset_idcode_str);
7556 SUMA_ifree(PR->evr);
7557 SUMA_free(PR);
7558 SUMA_RETURN(NULL);
7559 }
7560
SUMA_ADO_StorePickResult(SUMA_ALL_DO * ado,SUMA_PICK_RESULT ** PRP)7561 SUMA_Boolean SUMA_ADO_StorePickResult(SUMA_ALL_DO *ado, SUMA_PICK_RESULT **PRP)
7562 {
7563 static char FuncName[]={"SUMA_ADO_StorePickResult"};
7564
7565 SUMA_ENTRY;
7566
7567 if (!PRP || !*PRP) SUMA_RETURN(NOPE);
7568
7569 switch (ado->do_type) {
7570 case SO_type: {
7571 SUMA_SURF_SAUX *Saux = SUMA_ADO_SSaux(ado);
7572 SUMA_free_PickResult(Saux->PR);
7573 Saux->PR = *PRP; *PRP = NULL;
7574 SUMA_RETURN(YUP);
7575 break; }
7576 case CDOM_type: {
7577 SUMA_CIFTI_SAUX *Saux = SUMA_ADO_CSaux(ado);
7578 SUMA_free_PickResult(Saux->PR);
7579 Saux->PR = *PRP; *PRP = NULL;
7580 SUMA_RETURN(YUP);
7581 break; }
7582 case GDSET_type: {
7583 SUMA_DSET *dset=(SUMA_DSET *)ado;
7584 SUMA_GRAPH_SAUX *Saux = SDSET_GSAUX(dset);
7585 /* Is the selection type changed? If so, then
7586 you need to flush the pick buffer */
7587
7588 if (Saux->PR) {
7589 if ( (Saux->PR->datum_index * (*PRP)->datum_index < 0) ||
7590 ((*PRP)->datum_index == -1 &&
7591 (Saux->PR->iAltSel[SUMA_ENODE_0] !=
7592 (*PRP)->iAltSel[SUMA_ENODE_0])) ) {
7593 /* Going from edge selection to node selection, in general
7594 But there is no need to get picky */
7595 SUMA_FlushPickBufferForDO((SUMA_ALL_DO *)SUMA_find_Dset_GLDO(dset,
7596 "G3D",NULL));
7597 }
7598 }
7599 SUMA_free_PickResult(Saux->PR);
7600 Saux->PR = *PRP; *PRP = NULL;
7601 SUMA_RETURN(YUP);
7602 break; }
7603 case GRAPH_LINK_type:
7604 SUMA_RETURN(SUMA_ADO_StorePickResult(
7605 (SUMA_ALL_DO*)SUMA_find_GLDO_Dset(
7606 (SUMA_GraphLinkDO*)ado),PRP));
7607 break;
7608 case TRACT_type: {
7609 SUMA_TRACT_SAUX *Saux = SUMA_ADO_TSaux(ado);
7610 SUMA_free_PickResult(Saux->PR);
7611 Saux->PR = *PRP; *PRP = NULL;
7612 SUMA_RETURN(YUP);
7613 break; }
7614 case MASK_type: {
7615 SUMA_MASK_SAUX *Saux = SUMA_ADO_MSaux(ado);
7616 if (Saux) {
7617 SUMA_free_PickResult(Saux->PR);
7618 Saux->PR = *PRP; *PRP = NULL;
7619 } else {
7620 SUMA_S_Err("NULL Saux!!!, don't let that happen");
7621 SUMA_RETURN(NOPE);
7622 }
7623 SUMA_RETURN(YUP);
7624 break; }
7625 case VO_type: {
7626 SUMA_VOL_SAUX *Saux = SUMA_ADO_VSaux(ado);
7627 if (!(*PRP)->primitive) {
7628 SUMA_S_Err("NULL primitve not acceptable for VOs");
7629 break;
7630 }
7631 if (!strcmp((*PRP)->primitive,"voxel")) {
7632 SUMA_free_PickResult(Saux->PR);
7633 Saux->PR = *PRP; *PRP = NULL;
7634 SUMA_RETURN(YUP);
7635 } else if (!strcmp((*PRP)->primitive,"cutplane")) {
7636 SUMA_free_PickResult(Saux->PRc);
7637 Saux->PRc = *PRP; *PRP = NULL;
7638 SUMA_RETURN(YUP);
7639 } else {
7640 SUMA_S_Err("Bad primitive %s for VO", (*PRP)->primitive);
7641 SUMA_DUMP_TRACE("Who dunit?");
7642 }
7643 break; }
7644 default:
7645 SUMA_S_Errv("Note ready for type %s\n", ADO_TNAME(ado));
7646 break;
7647 }
7648 SUMA_RETURN(NOPE);
7649 }
7650
SUMA_ADO_GetPickResult(SUMA_ALL_DO * ado,char * primitive)7651 SUMA_PICK_RESULT * SUMA_ADO_GetPickResult(SUMA_ALL_DO *ado, char *primitive)
7652 {
7653 static char FuncName[]={"SUMA_ADO_GetPickResult"};
7654 SUMA_PICK_RESULT *PR=NULL;
7655
7656 SUMA_ENTRY;
7657
7658 if (!ado) SUMA_RETURN(NULL);
7659 if (!primitive) primitive = "none";
7660
7661 switch (ado->do_type) {
7662 case SO_type:{
7663 SUMA_SURF_SAUX *Saux = SUMA_ADO_SSaux(ado);
7664 SUMA_RETURN(Saux->PR);
7665 break; }
7666 case CDOM_type: {
7667 SUMA_CIFTI_SAUX *Saux = SUMA_ADO_CSaux(ado);
7668 SUMA_RETURN(Saux->PR);
7669 break; }
7670 case GDSET_type: {
7671 SUMA_DSET *dset=(SUMA_DSET *)ado;
7672 SUMA_GRAPH_SAUX *Saux = SDSET_GSAUX(dset);
7673 SUMA_RETURN(Saux->PR);
7674 break; }
7675 case GRAPH_LINK_type:
7676 SUMA_RETURN(SUMA_ADO_GetPickResult(
7677 (SUMA_ALL_DO*)SUMA_find_GLDO_Dset((SUMA_GraphLinkDO*)ado),primitive));
7678 break;
7679 case TRACT_type: {
7680 SUMA_TRACT_SAUX *Saux = SUMA_ADO_TSaux(ado);
7681 SUMA_RETURN(Saux->PR);
7682 break; }
7683 case MASK_type: {
7684 SUMA_MASK_SAUX *Saux = SUMA_ADO_MSaux(ado);
7685 SUMA_RETURN(Saux->PR);
7686 break; }
7687 case VO_type: {
7688 SUMA_VOL_SAUX *Saux = SUMA_ADO_VSaux(ado);
7689 if (!strcmp(primitive,"voxel")) SUMA_RETURN(Saux->PR);
7690 else if (!strcmp(primitive,"cutplane")) SUMA_RETURN(Saux->PRc);
7691 else {
7692 SUMA_S_Err("Bad primitive %s for VO", primitive);
7693 }
7694 break; }
7695 default:
7696 SUMA_S_Errv("Note ready for type %s\n", ADO_TNAME(ado));
7697 break;
7698 }
7699 SUMA_RETURN(NOPE);
7700 }
7701
7702
7703 /*!
7704 */
SUMA_Show_Pick_Colid_List(DList * pick_colid_list,FILE * fout)7705 void SUMA_Show_Pick_Colid_List(DList *pick_colid_list, FILE *fout)
7706 {
7707 static char FuncName[]={"SUMA_Show_Pick_Colid_List"};
7708 char *s = NULL;
7709
7710 SUMA_ENTRY;
7711 if (!fout) fout = SUMA_STDOUT;
7712
7713 s = SUMA_Pick_Colid_List_Info(pick_colid_list);
7714 fprintf(fout, "%s", s);
7715 SUMA_ifree(s);
7716
7717 SUMA_RETURNe;
7718 }
7719
SUMA_Pick_Colid_List_Info(DList * pick_colid_list)7720 char *SUMA_Pick_Colid_List_Info (DList *pick_colid_list)
7721 {
7722 static char FuncName[]={"SUMA_Pick_Colid_List_Info"};
7723 char *s = NULL;
7724 SUMA_STRING *SS = NULL;
7725 SUMA_SurfaceObject *SO=NULL;
7726 SUMA_DO_Types do_type;
7727 void *vv=NULL;
7728 SUMA_DSET *dset=NULL;
7729 DListElmt *el=NULL;
7730 SUMA_ALL_DO *ado=NULL;
7731 SUMA_COLID_OFFSET_DATUM *cod=NULL;
7732
7733 SUMA_ENTRY;
7734
7735 SS = SUMA_StringAppend(NULL, NULL);
7736
7737 if (!pick_colid_list) {
7738 SS = SUMA_StringAppend(SS,"NULL pick_colid_list"); goto CLEAN_RETURN;
7739 }
7740 if (!dlist_size(pick_colid_list)) {
7741 SS = SUMA_StringAppend(SS,"Empty pick_colid_list"); goto CLEAN_RETURN;
7742 }
7743 SS = SUMA_StringAppend_va(SS,"DO Pick List of %d elements\n",
7744 dlist_size(pick_colid_list));
7745 do {
7746 if (!el) el = dlist_head(pick_colid_list);
7747 else el = dlist_next(el);
7748 if (!el || !el->data) {
7749 SS = SUMA_StringAppend(SS, " NULL element!");
7750 } else {
7751 cod = (SUMA_COLID_OFFSET_DATUM *)el->data;
7752 SS = SUMA_StringAppend_va(SS," DO %s, Primitive %s, [%ld to %ld]\n",
7753 cod->Label, cod->primitive,
7754 cod->i0, cod->i1);
7755 vv = SUMA_Picked_reference_object(cod, &do_type);
7756 switch (do_type) {
7757 case MD_DSET_type:
7758 dset = (SUMA_DSET *)vv;
7759 SS = SUMA_StringAppend_va(SS,
7760 " Reference object is a %s dataset labeled %s "
7761 "(reference type %s)\n",
7762 "Multi Domain",
7763 SDSET_LABEL(dset),
7764 SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
7765 break;
7766 case ANY_DSET_type:
7767 case GDSET_type:
7768 dset = (SUMA_DSET *)vv;
7769 SS = SUMA_StringAppend_va(SS,
7770 " Reference object is a %s dataset labeled %s "
7771 "(reference type %s)\n",
7772 SUMA_isCIFTIDset(dset) ? "CIFTI" :
7773 (SUMA_isGraphDset(dset) ? "Graph":"Surface-based"),
7774 SDSET_LABEL(dset),
7775 SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
7776 break;
7777 case SO_type:
7778 SO = (SUMA_SurfaceObject *)vv;
7779 SS = SUMA_StringAppend_va(SS,
7780 " Reference object is a surface labeled %s "
7781 "(reference type %s)\n",
7782 SO->Label,
7783 SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
7784 break;
7785 case GRAPH_LINK_type:
7786 ado = (SUMA_ALL_DO *)vv;
7787 SS = SUMA_StringAppend_va(SS,
7788 " Reference object is a graph link labeled %s "
7789 "(reference type %s)\n",
7790 SUMA_ADO_Label(ado),
7791 SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
7792 break;
7793 case TRACT_type:
7794 SS = SUMA_StringAppend_va(SS,
7795 " Reference object is a tract object labeled %s "
7796 "(reference type %s)\n",
7797 SUMA_ADO_Label(ado),
7798 SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
7799 break;
7800 case CDOM_type:
7801 SS = SUMA_StringAppend_va(SS,
7802 " Reference object is a CIFTI DO labeled %s "
7803 "(reference type %s)\n",
7804 SUMA_ADO_Label(ado),
7805 SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
7806 break;
7807 case MASK_type:
7808 SS = SUMA_StringAppend_va(SS,
7809 " Reference object is a mask object labeled %s "
7810 "(reference type %s)\n",
7811 SUMA_ADO_Label(ado),
7812 SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
7813 break;
7814 default:
7815 SS = SUMA_StringAppend_va(SS,
7816 " Parent, not surface or dset.\n");
7817 break;
7818 }
7819 }
7820 } while (el != dlist_tail(pick_colid_list));
7821
7822 CLEAN_RETURN:
7823 SUMA_SS2S(SS,s);
7824
7825 SUMA_RETURN(s);
7826 }
7827
SUMA_MarkLineDOsIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode)7828 int SUMA_MarkLineDOsIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
7829 int IgnoreSameNode)
7830 {
7831 static char FuncName[]={"SUMA_MarkLineDOsIntersect"};
7832
7833 SUMA_PICK_RESULT *PR = NULL;
7834 SUMA_ALL_DO *ado = NULL;
7835 int ans;
7836
7837 SUMA_ENTRY;
7838 SUMA_S_Warn("Do not call me anymore."
7839 "Go via SUMA_ComputeLineDOsIntersect. "
7840 "This is left here for testing purposes");
7841 ans = SUMA_ComputeLineDOsIntersect(sv, dov, IgnoreSameNode, &ado);
7842 if (ans <= 0) {
7843 SUMA_RETURN(ans);
7844 }
7845 /* just for temporary testing, get PR back from list and apply it */
7846 PR = SUMA_Get_From_PickResult_List(sv, ado, NULL);
7847 ans = SUMA_Apply_PR(sv, &PR);
7848
7849 SUMA_RETURN(ans);
7850 }
7851
7852 /*!
7853 Determines the intersection between pickline and displayable objects
7854 */
SUMA_ComputeLineDOsIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode,SUMA_ALL_DO ** pado)7855 int SUMA_ComputeLineDOsIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
7856 int IgnoreSameNode, SUMA_ALL_DO **pado)
7857 {
7858 static char FuncName[]={"SUMA_ComputeLineDOsIntersect"};
7859 int i, j, *MembDOs=NULL, N_MembDOs;
7860 SUMA_DO_Types ttv[12];
7861 SUMA_PICK_RESULT *hit=NULL;
7862 GLubyte colans[4];
7863 SUMA_COLID_OFFSET_DATUM *codf=NULL;
7864 SUMA_ALL_DO *ado=NULL;
7865 SUMA_EngineData *ED = NULL;
7866 DList *list = NULL;
7867 DListElmt *SetNodeElem = NULL, *Location=NULL;
7868 SUMA_SurfaceObject *SO = NULL;
7869 SUMA_Boolean NodeIgnored = NOPE;
7870 SUMA_Boolean LocalHead = NOPE;
7871
7872 SUMA_ENTRY;
7873
7874 if (!sv || !dov) SUMA_RETURN(-1);
7875
7876 SUMA_LH("DO pickin");
7877
7878 if (sv->PickPix[0] < 0 || sv->PickPix[1] < 0 ||
7879 sv->PickPix[0] >= sv->X->aWIDTH || sv->PickPix[1] >= sv->X->aHEIGHT) {
7880 /* This happens when you select and drag outside of the viewing area
7881 Don't return in error */
7882 SUMA_LHv("Bad PickPix=[%d %d] for viewport %d %d\n",
7883 sv->PickPix[0], sv->PickPix[1], sv->X->aWIDTH, sv->X->aHEIGHT);
7884 SUMA_RETURN(0);
7885 }
7886
7887 /* Any pickable DO, other than brain surfaces, that does not require
7888 pick buffer picking? */
7889 ttv[0] = GRAPH_LINK_type; ttv[1] = NOT_SET_type;
7890 MembDOs = SUMA_ViewState_Membs(&(sv->VSv[sv->iState]), ttv, &N_MembDOs);
7891 for (i=0; i<N_MembDOs; ++i) {
7892 if ((hit = SUMA_WhatWasPicked_FrameSO(sv, MembDOs[i]))) {
7893 if ( hit->datum_index < 0 && (
7894 ( hit->iAltSel[SUMA_ENODE_0]>=0 &&
7895 hit->iAltSel[SUMA_ENODE_1]>=0)) ) {
7896 /* You have selected a point pair that has no edge defined.
7897 This can happen when you click on an empty cell in the matrix */
7898 hit = SUMA_free_PickResult(hit);
7899 } else {
7900 /* got something, leave.
7901 Perhaps in the future will need to go through
7902 all stack (slices) and pick the best one ... */
7903 ado = iDO_ADO(MembDOs[i]);
7904 if (pado) *pado = ado;
7905 break;
7906 }
7907 }
7908 }
7909 SUMA_ifree(MembDOs);
7910
7911 if (!hit) { /* nothing found above, go for pick buffer */
7912 if (!SUMA_PickBuffer(sv, 2, dov)) { /* refresh the buffer only if needed */
7913 SUMA_S_Err("Failed to refresh buffer");
7914 SUMA_RETURN(-1);
7915 }
7916
7917 if (!sv->pickrenpix4) {
7918 SUMA_S_Err("Could not form pickrenpix4, should this be an error?");
7919 SUMA_RETURN(-1);
7920 }
7921 if (!sv->pick_colid_list || !dlist_size(sv->pick_colid_list)) {
7922 SUMA_LH("No such pickable objects");
7923 } else {
7924 /* get pixel at click */
7925 i = sv->PickPix[0]; j = sv->PickPix[1];
7926 if (SUMA_GetColidInPickBuffer4(sv->pickrenpix4,
7927 sv->X->aWIDTH, sv->X->aHEIGHT,
7928 &i, &j, 2, colans)) {
7929 if (LocalHead) {
7930 /* Just for debugging, draw the crosshair point */
7931 SUMA_MarkPickInBuffer4(sv, 1, NULL);
7932 SUMA_LHv("User pixel selection: \n"
7933 " closest hit to click at %d %d was from %d %d\n"
7934 " colid = %d %d %d %d \n",
7935 sv->PickPix[0], sv->PickPix[1], i, j,
7936 colans[0] , colans[1],
7937 colans[2] , colans[3]);
7938 }
7939 /* so what was that you touched. Note hit is never
7940 returned as null. */
7941 hit = SUMA_WhatWasPicked(sv, colans, &codf, i, j, NULL);
7942 if (!hit || !hit->ado_idcode_str) {
7943 SUMA_LH("Not hit found.");
7944 } else {
7945 if (!(ado = iDO_ADO(SUMA_Picked_DO_ID(codf)))) {
7946 SUMA_S_Err("Could not locate object in codf (%s) /hit (%s)!",
7947 codf->ref_idcode_str, hit->ado_idcode_str);
7948 SUMA_free_PickResult(hit); hit = NULL;
7949 } else {
7950 if (pado) *pado = ado;
7951 }
7952 }
7953 } else {
7954 SUMA_LH("There is no there there\n");
7955 hit = NULL;
7956 }
7957 }
7958 }
7959
7960 if (hit && ado) {
7961 SUMA_LH("Adding hit to list");
7962 if (!SUMA_Add_To_PickResult_List(sv, ado, NULL, &hit)) {
7963 SUMA_S_Err("Failed to add selected ado");
7964 SUMA_RETURN(-1);
7965 }
7966 SUMA_RETURN(1);
7967 } else SUMA_RETURN(0);
7968 }
7969
SUMA_Apply_PR_DO(SUMA_SurfaceViewer * sv,SUMA_ALL_DO * ado,SUMA_PICK_RESULT ** PRi)7970 int SUMA_Apply_PR_DO(SUMA_SurfaceViewer *sv, SUMA_ALL_DO *ado,
7971 SUMA_PICK_RESULT **PRi)
7972 {
7973 static char FuncName[]={"SUMA_Apply_PR_DO"};
7974 DList *list = NULL;
7975 DListElmt *SetNodeElem = NULL, *Location=NULL;
7976 SUMA_Boolean NodeIgnored = NOPE;
7977 SUMA_PICK_RESULT *PR;
7978 int NP=0, ip=0, it=-1, id = 0, iv3[3], iv15[15];
7979 SUMA_EngineData *ED = NULL;
7980 SUMA_Boolean LocalHead = NOPE;
7981
7982 SUMA_ENTRY;
7983 SUMA_LH("Here");
7984 if (!sv || !ado || !PRi || !*PRi) { SUMA_S_Err("Niente"); SUMA_RETURN(-1); }
7985
7986 PR = *PRi; /* keep local copy */
7987 /* Store the PR in ado, hide it from return potential */
7988 SUMA_ADO_StorePickResult(ado, PRi);
7989
7990 SUMA_LHv("Hit object type %s, label %s\n",
7991 SUMA_ObjectTypeCode2ObjectTypeName(ado->do_type),
7992 SUMA_ADO_Label(ado));
7993
7994 sv->Focus_DO_ID = ADO_iDO(ado);
7995 SUMA_UpdateViewerTitle(sv);
7996
7997 /* if the surface controller is open, update it */
7998 if (SUMA_isADO_Cont_Realized(ado))
7999 SUMA_Init_SurfCont_SurfParam(ado);
8000
8001 /* print nodes about the pick */
8002 switch (ado->do_type) {
8003 case TRACT_type:
8004 fprintf(SUMA_STDOUT, "\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
8005 fprintf(SUMA_STDOUT, "Selected network %s (Focus_DO_ID # %d).\n"
8006 "Point %ld, (Bundle %ld, Tract %ld, Point %ld)\n",
8007 ADO_LABEL(ado), sv->Focus_DO_ID, PR->datum_index,
8008 PR->iAltSel[SUMA_NET_BUN], PR->iAltSel[SUMA_BUN_TRC],
8009 PR->iAltSel[SUMA_TRC_PNT]);
8010 fprintf(SUMA_STDOUT, "Seletion coordinates:\n");
8011 fprintf(SUMA_STDOUT, "%f, %f, %f\n",
8012 PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2]);
8013 fprintf(SUMA_STDOUT, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
8014 break;
8015 case MASK_type:
8016 fprintf(SUMA_STDOUT, "\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
8017 fprintf(SUMA_STDOUT, "Selected mask %s (Focus_DO_ID # %d).\n",
8018 ADO_LABEL(ado), sv->Focus_DO_ID);
8019 fprintf(SUMA_STDOUT, "Seletion coordinates:\n");
8020 fprintf(SUMA_STDOUT, "%f, %f, %f\n",
8021 PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2]);
8022 fprintf(SUMA_STDOUT, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
8023 break;
8024 case GRAPH_LINK_type:
8025 fprintf(SUMA_STDOUT, "\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
8026 fprintf(SUMA_STDOUT, "Selected Graph Dset %s (Focus_DO_ID # %d).\n"
8027 "Edge %ld, (P0 %ld, P1 %ld)\n",
8028 ADO_LABEL(ado), sv->Focus_DO_ID, PR->datum_index,
8029 PR->iAltSel[SUMA_ENODE_0], PR->iAltSel[SUMA_ENODE_1]);
8030 fprintf(SUMA_STDOUT, "Seletion coordinates:\n");
8031 fprintf(SUMA_STDOUT, "%f, %f, %f\n",
8032 PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2]);
8033 fprintf(SUMA_STDOUT, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
8034 break;
8035 default:
8036 SUMA_S_Err("Not yet set to report on %s", ADO_LABEL(ado));
8037 break;
8038 }
8039
8040 /* Based on what you selected, update controller */
8041 /* Set the Nodeselection at the closest node */
8042 if (PR->datum_index >= 0 ||
8043 (PR->datum_index == -1 &&
8044 PR->iAltSel[SUMA_ENODE_0] >= 0 &&
8045 PR->iAltSel[SUMA_ENODE_1] == -1) ) {
8046 /* 2nd condition is when only edge node is selected.
8047 We insist on PR->iAltSel[SUMA_ENODE_1] == -1 otherwise
8048 we would have picked a cell in the matrix for which
8049 there is no data, hence we have ENODE_0, and ENODE_1,
8050 but datum_index = -1 */
8051 it = (int)PR->datum_index;
8052 if (!list) list = SUMA_CreateList();
8053 if (PR->ignore_same_datum &&
8054 SUMA_ADO_SelectedDatum(ado, NULL, NULL) == it) {
8055 SUMA_LHv("Ignoring identical datum selection %d on object %s\n",
8056 SUMA_ADO_SelectedDatum(ado, NULL, NULL), SUMA_ADO_Label(ado));
8057 NodeIgnored = YUP;
8058 } else {
8059 ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
8060 SetNodeElem = SUMA_RegisterEngineListCommand ( list, ED,
8061 SEF_i, (void*)&it,
8062 SES_Suma, (void *)sv, NOPE,
8063 SEI_Head, NULL);
8064 if (!SetNodeElem) {
8065 fprintf( SUMA_STDERR,
8066 "Error %s: Failed to register SetNodeElem\n", FuncName);
8067 SUMA_RETURN (-1);
8068 } else {
8069 SUMA_RegisterEngineListCommand ( list, ED,
8070 SEF_ngr, NULL,
8071 SES_Suma, (void *)sv, NOPE,
8072 SEI_In, SetNodeElem);
8073 }
8074 switch (ado->do_type) {
8075 case TRACT_type:
8076 iv15[SUMA_NET_BUN] = (int)PR->iAltSel[SUMA_NET_BUN];
8077 iv15[SUMA_BUN_TRC] = (int)PR->iAltSel[SUMA_BUN_TRC];
8078 iv15[SUMA_TRC_PNT] = (int)PR->iAltSel[SUMA_TRC_PNT];
8079 iv15[SUMA_NET_TRC] = (int)PR->iAltSel[SUMA_NET_TRC];
8080 SUMA_RegisterEngineListCommand ( list, ED,
8081 SEF_iv15, (void *)iv15,
8082 SES_Suma, (void *)sv, NOPE,
8083 SEI_In, SetNodeElem);
8084 break;
8085 case SO_type:
8086 case VO_type:
8087 /* handled in separate function */
8088 break;
8089 default:
8090 SUMA_LH("No aux set here for type %s of %s\n",
8091 ADO_TNAME(ado), SUMA_ADO_Label(ado));
8092 break;
8093 }
8094
8095 }
8096 }
8097
8098
8099 /* Set the selected edge node (cunningly in recycled selected face set) */
8100 it = PR->iAltSel[SUMA_ENODE_0];
8101 if (!list) list = SUMA_CreateList();
8102 ED = SUMA_InitializeEngineListData (SE_SetSelectedFaceSet);
8103 if (!SUMA_RegisterEngineListCommand ( list, ED,
8104 SEF_i, (void*)&it,
8105 SES_Suma, (void *)sv, NOPE,
8106 SEI_Head, NULL)) {
8107 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
8108 SUMA_RETURN (-1);
8109 }
8110
8111 /* Now set the cross hair position at the intersection*/
8112 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
8113 if (!(Location = SUMA_RegisterEngineListCommand ( list, ED,
8114 SEF_fv3, (void*)PR->PickXYZ,
8115 SES_Suma, (void *)sv, NOPE,
8116 SEI_Head, NULL))) {
8117 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
8118 SUMA_RETURN (-1);
8119 }
8120 /* and add the ado with this location, needed for VisX business*/
8121 SUMA_RegisterEngineListCommand ( list, ED,
8122 SEF_vp, (void *)ado,
8123 SES_Suma, (void *)sv, NOPE,
8124 SEI_In, Location);
8125 /* attach the cross hair to the selected ado */
8126 iv3[0] = SUMA_whichDO(PR->ado_idcode_str, SUMAg_DOv, SUMAg_N_DOv);
8127 iv3[1] = PR->datum_index;
8128 iv3[2] = PR->iAltSel[SUMA_ENODE_0];
8129 ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
8130 if (!SUMA_RegisterEngineListCommand ( list, ED,
8131 SEF_iv3, (void*)iv3,
8132 SES_Suma, (void *)sv, NOPE,
8133 SEI_Head, NULL)) {
8134 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
8135 SUMA_RETURN (-1);
8136 }
8137
8138 /* check to see if AFNI needs to be notified */
8139 /* Need to deal with SUMA_TO_MATLAB_STREAM_INDEX too
8140 Same for remaining occurrence of SUMA_AFNI_STREAM_INDEX*/
8141 if ( ( SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] &&
8142 sv->LinkAfniCrossHair ) ||
8143 ( SUMAg_CF->Connected_v[SUMA_HALLO_SUMA_LINE]) ||
8144 ( SUMAg_CF->Connected_v[SUMA_INSTA_TRACT_LINE]) ) {
8145 if (LocalHead)
8146 fprintf(SUMA_STDERR,
8147 "%s: Notifying Afni of CrossHair XYZ\n", FuncName);
8148 /* register a call to SetAfniCrossHair */
8149 if (!list) list = SUMA_CreateList();
8150 it = SUMA_ShftCont_Event(PR->evr);
8151 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
8152 if (!SUMA_RegisterEngineListCommand ( list, ED,
8153 SEF_i, (void*)&it,
8154 SES_Suma, (void *)sv, NOPE,
8155 SEI_Tail, NULL)) {
8156 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
8157 SUMA_RETURN (-1);
8158 }
8159 if (MASK_MANIP_MODE(sv) && SUMAg_CF->Dev) {
8160 SUMA_ALL_DO *ado = SUMA_whichADOg(sv->MouseMode_ado_idcode_str);
8161 DListElmt *Location=NULL;
8162 SUMA_LH("Might be telling afni about mask...");
8163 if (ado && ado->do_type == MASK_type) {
8164 SUMA_MaskDO *mdo = (SUMA_MaskDO *)ado;
8165 ED = SUMA_InitializeEngineListData (SE_SetAfniMask);
8166 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
8167 SEF_fv3, (void*)mdo->cen,
8168 SES_Suma, (void *)sv, NOPE,
8169 SEI_Tail, NULL))) {
8170 SUMA_S_Err("Failed to register element\n");
8171 SUMA_RETURN (-1);
8172 }
8173 SUMA_RegisterEngineListCommand ( list, ED,
8174 SEF_s, (void *)(ADO_ID(ado)),
8175 SES_Suma, (void *)sv, NOPE,
8176 SEI_In, Location);
8177 }
8178 }
8179
8180 if (!SUMA_Engine (&list)) {
8181 fprintf( SUMA_STDERR,
8182 "Error %s: SUMA_Engine call failed.\n", FuncName);
8183 SUMA_RETURN (-1);
8184 }
8185 }else {
8186 if (LocalHead)
8187 fprintf(SUMA_STDERR,"%s: No Notification to AFNI.\n", FuncName);
8188 }
8189
8190 /* now put in a request for locking cross hair but you must do
8191 this after the node selection has been executed
8192 NOTE: You do not always have SetNodeElem because the list might
8193 get emptied in the call to AFNI notification.
8194 You should just put the next call at the end of the list.*/
8195 if (!list) list = SUMA_CreateList();
8196 ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
8197 if (!SUMA_RegisterEngineListCommand ( list, ED,
8198 SEF_iv3, (void*)iv3,
8199 SES_Suma, (void *)sv, NOPE,
8200 SEI_Tail, NULL)) {
8201 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
8202 SUMA_RETURN (-1);
8203 }
8204 if (!SUMA_Engine (&list)) {
8205 fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
8206 SUMA_RETURN (-1);
8207 }
8208
8209 SUMA_RETURN(1);
8210 }
8211
SUMA_Apply_PR(SUMA_SurfaceViewer * sv,SUMA_PICK_RESULT ** PR)8212 int SUMA_Apply_PR(SUMA_SurfaceViewer *sv, SUMA_PICK_RESULT **PR)
8213 {
8214 static char FuncName[]={"SUMA_Apply_PR"};
8215 SUMA_ALL_DO *ado=NULL, *ado_pick=NULL;
8216 float *xyz=NULL;
8217 SUMA_Boolean LocalHead = NOPE;
8218
8219 SUMA_ENTRY;
8220
8221 if (!sv || !PR || !*PR) {
8222 SUMA_S_Err("NULL input %p %p %p", sv, PR, *PR);
8223 SUMA_DUMP_TRACE("PR application");
8224 SUMA_RETURN(-1);
8225 }
8226 if (MASK_MANIP_MODE(sv)) {
8227 ado_pick = SUMA_whichADOg((*PR)->ado_idcode_str);
8228 SUMA_LH("Mask Manip Mode, moving to %f %f %f per ado %s\n",
8229 (*PR)->PickXYZ[0], (*PR)->PickXYZ[1], (*PR)->PickXYZ[2],
8230 ADO_LABEL(ado_pick));
8231 SUMA_ifree(sv->LastSel_ado_idcode_str);
8232 sv->LastSel_ado_idcode_str = SUMA_copy_string((*PR)->ado_idcode_str);
8233 /* Just move the selected mask */
8234 if (!(ado = SUMA_whichADOg(sv->MouseMode_ado_idcode_str))) {
8235 SUMA_S_Err("Yikes, got not ado for MouseMode_ado_idcode_str %s",
8236 sv->MouseMode_ado_idcode_str?sv->MouseMode_ado_idcode_str:"NULL");
8237 SUMA_RETURN(-1);
8238 }
8239 if (ado->do_type != MASK_type) {
8240 SUMA_S_Err("Bad ID for mouse mode value");
8241 SUMA_RETURN(-1);
8242 }
8243 /* Set the parent as the ado_pick */
8244 SUMA_MDO_New_parent((SUMA_MaskDO *)ado, (*PR)->ado_idcode_str,
8245 (*PR)->datum_index);
8246
8247 if (ado_pick->do_type == SO_type) {
8248 SUMA_SurfaceObject *SO = (SUMA_SurfaceObject *)ado_pick;
8249 /* PickXYZ might be under VisX */
8250 xyz = SO->NodeList+SO->NodeDim* (*PR)->datum_index;
8251 SUMA_MDO_New_Doppel((SUMA_MaskDO *)ado, (*PR)->PickXYZ);
8252 } else {
8253 xyz = (*PR)->PickXYZ;
8254 SUMA_MDO_New_Doppel((SUMA_MaskDO *)ado, NULL);
8255 }
8256 if (LocalHead) SUMA_DUMP_TRACE("Box motion");
8257 SUMA_NEW_MASKSTATE();
8258 SUMA_MDO_New_Cen((SUMA_MaskDO *)ado, xyz);
8259 }
8260
8261 {
8262 ado = SUMA_whichADOg((*PR)->ado_idcode_str);
8263 SUMA_ifree(sv->LastSel_ado_idcode_str);
8264 sv->LastSel_ado_idcode_str = SUMA_copy_string((*PR)->ado_idcode_str);
8265 switch (ado->do_type) {
8266 case SO_type:
8267 SUMA_RETURN(SUMA_Apply_PR_SO(sv, (SUMA_SurfaceObject *)ado, PR));
8268 break;
8269 case VO_type:
8270 SUMA_RETURN(SUMA_Apply_PR_VO(sv, (SUMA_VolumeObject *)ado, PR));
8271 break;
8272 case GRAPH_LINK_type:
8273 SUMA_RETURN(SUMA_Apply_PR_DO(sv, ado, PR));
8274 break;
8275 case TRACT_type:
8276 SUMA_RETURN(SUMA_Apply_PR_DO(sv, ado, PR));
8277 break;
8278 case MASK_type:
8279 SUMA_RETURN(SUMA_Apply_PR_DO(sv, ado, PR));
8280 break;
8281 default:
8282 SUMA_S_Err("Not yet implemented for %s", ADO_TNAME(ado));
8283 SUMA_RETURN(-1);
8284 break;
8285 }
8286 }
8287 SUMA_RETURN(-1);
8288 }
8289
SUMA_MarkLineMaskIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode)8290 int SUMA_MarkLineMaskIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
8291 int IgnoreSameNode)
8292 {/* determine intersection */
8293 static char FuncName[]={"SUMA_MarkLineMaskIntersect"};
8294 SUMA_PICK_RESULT *PR = NULL;
8295 SUMA_ALL_DO *ado = NULL;
8296 int ans;
8297
8298 SUMA_ENTRY;
8299 SUMA_S_Warn("Do not call me anymore. Follow the new selection logic");
8300 ans = SUMA_ComputeLineMaskIntersect(sv, dov, IgnoreSameNode, &ado);
8301 if (ans <= 0) {
8302 SUMA_RETURN(ans);
8303 }
8304 /* just for temporary testing, get PR back from list and apply it */
8305 PR = SUMA_Get_From_PickResult_List(sv, ado, NULL);
8306 ans = SUMA_Apply_PR(sv, &PR);
8307 SUMA_RETURN(ans);
8308 }
8309
SUMA_ComputeLineMaskIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode,SUMA_ALL_DO ** pado)8310 int SUMA_ComputeLineMaskIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
8311 int IgnoreSameNode, SUMA_ALL_DO **pado)
8312 {/* determine intersection */
8313 static char FuncName[]={"SUMA_ComputeLineMaskIntersect"};
8314 float P0f[3], P1f[3];
8315 int NP;
8316 SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL, *MTIi = NULL;
8317 float delta_t_tmp, dmin;
8318 struct timeval tt_tmp;
8319 SUMA_ALL_DO *ado=NULL;
8320 int ip, it, id, ii, N_MDOlist,
8321 MDOlist[SUMA_MAX_DISPLAYABLE_OBJECTS], imin;
8322 char sfield[100], sdestination[100], CommString[SUMA_MAX_COMMAND_LENGTH];
8323 SUMA_MaskDO *MDO = NULL;
8324 SUMA_Boolean LocalHead = NOPE;
8325
8326 SUMA_ENTRY;
8327
8328 P0f[0] = sv->Pick0[0];
8329 P0f[1] = sv->Pick0[1];
8330 P0f[2] = sv->Pick0[2];
8331 P1f[0] = sv->Pick1[0];
8332 P1f[1] = sv->Pick1[1];
8333 P1f[2] = sv->Pick1[2];
8334
8335 N_MDOlist = SUMA_VisibleMDOs(sv, dov, MDOlist);
8336 if (LocalHead) {
8337 SUMA_LH("%d visible MDOs", N_MDOlist);
8338 for (ii=0; ii < N_MDOlist; ++ii) {
8339 ado = (SUMA_ALL_DO *)dov[MDOlist[ii]].OP;
8340 fprintf(SUMA_STDERR,"%d: object %d in DOv, label %s, type %s\n",
8341 ii, MDOlist[ii], ADO_LABEL(ado), ADO_TNAME(ado));
8342 }
8343 }
8344 imin = -1;
8345 dmin = 10000000.0;
8346 for (ii=0; ii < N_MDOlist; ++ii) { /* find the closest intersection */
8347 if (LocalHead)
8348 fprintf (SUMA_STDERR,
8349 "%s: working %d/%d shown masks ...\n",
8350 FuncName, ii, N_MDOlist);
8351 MDO = (SUMA_MaskDO *)dov[MDOlist[ii]].OP;
8352 if (!MDO_IS_SURF(MDO) && !MDO_IS_BOX(MDO) && !MDO_IS_SPH(MDO)) {
8353 fprintf(SUMA_STDERR,
8354 "Error %s: "
8355 "Not ready to handle such MDO (%s) intersections on %s\n",
8356 FuncName, MDO->mtype, ADO_LABEL((SUMA_ALL_DO *)MDO));
8357 } if (!MDO->SO) {
8358 SUMA_S_Err("No SO buster on %s", ADO_LABEL((SUMA_ALL_DO *)MDO));
8359 } else {
8360 /* Here we're doing the intersection the lazy way, via the SO,
8361 although this can be done a lot faster in other ways for box and
8362 sphere, speed is not an issue here */
8363 SUMA_etime (&tt_tmp, 0);
8364 MTIi = SUMA_MT_intersect_triangle(P0f, P1f, MDO->SO->NodeList,
8365 MDO->SO->N_Node, MDO->SO->FaceSetList,
8366 MDO->SO->N_FaceSet, NULL, 0);
8367
8368 delta_t_tmp = SUMA_etime (&tt_tmp, 1);
8369 SUMA_LH("Intersection took %f seconds with %s.\n",
8370 delta_t_tmp,
8371 ADO_LABEL((SUMA_ALL_DO *)dov[MDOlist[ii]].OP));
8372
8373 if (MTIi == NULL) {
8374 fprintf(SUMA_STDERR,
8375 "Error %s: SUMA_MT_intersect_triangle failed.\n", FuncName);
8376 SUMA_RETURN (-1);
8377 }
8378
8379 if (MTIi->N_hits) {
8380 /* decide on the closest surface to the clicking point */
8381 if (MTIi->t[MTIi->ifacemin] < dmin) {
8382 if (LocalHead)
8383 fprintf (SUMA_STDERR, "%s: A minimum for surface %d.\n",
8384 FuncName, ii);
8385 dmin = MTIi->t[MTIi->ifacemin];
8386 imin = MDOlist[ii];
8387 MTI = MTIi;
8388 }else {
8389 /* not good, toss it away */
8390 SUMA_LH("ii=%d not any closer (%f vs %f). freeing MTIi...\n",
8391 ii,MTIi->t[MTIi->ifacemin], dmin);
8392 MTIi = SUMA_Free_MT_intersect_triangle(MTIi);
8393 }
8394 }else {
8395 /* not good, toss it away */
8396 if (LocalHead)
8397 fprintf (SUMA_STDERR,
8398 "%s: ii=%d freeing MTIi no hits...\n", FuncName, ii);
8399 MTIi = SUMA_Free_MT_intersect_triangle(MTIi);
8400 }
8401 }
8402 }
8403
8404 if (LocalHead)
8405 fprintf (SUMA_STDERR,
8406 "%s: Closest surface is indexed %d in DOv.\n", FuncName, imin);
8407
8408 if (imin >= 0) {
8409 SUMA_PICK_RESULT *PR;
8410 SUMA_ALL_DO *ado;
8411 if (!(ado = iDO_ADO(imin))) {
8412 SUMA_S_Err("NULL ado at this point? imin = %d", imin);
8413 SUMA_RETURN(-1);
8414 }
8415 PR = SUMA_New_Pick_Result(NULL);
8416 if (pado) *pado = ado; /* user want answer back */
8417 PR->ado_idcode_str = SUMA_copy_string(ADO_ID(ado));
8418 PR->datum_index = MTI->inodemin;
8419 PR->ignore_same_datum = IgnoreSameNode;
8420 PR->iAltSel[SUMA_SURF_TRI] = MTI->ifacemin;
8421 SUMA_COPY_VEC(MTI->P, PR->PickXYZ, 3, float, float);
8422 /* Add selection result to stack */
8423 if (!SUMA_Add_To_PickResult_List(sv, ado, NULL, &PR)) {
8424 SUMA_S_Err("Failed to add selected ado");
8425 SUMA_RETURN(-1);
8426 }
8427 }
8428
8429 /* clear MTI */
8430 if (MTI) {
8431 MTI = SUMA_Free_MT_intersect_triangle(MTI);
8432 }
8433
8434 if (imin >=0) SUMA_RETURN(1);
8435 else SUMA_RETURN(0);
8436 }
8437
8438
SUMA_MarkLineSurfaceIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode)8439 int SUMA_MarkLineSurfaceIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
8440 int IgnoreSameNode)
8441 {
8442 static char FuncName[]={"SUMA_MarkLineSurfaceIntersect"};
8443 SUMA_PICK_RESULT *PR = NULL;
8444 SUMA_ALL_DO *ado = NULL;
8445 int ans;
8446
8447 SUMA_ENTRY;
8448 SUMA_S_Warn("Do not call me anymore."
8449 "Go via SUMA_ComputeLineSurfaceIntersect. "
8450 "This is left here for testing purposes");
8451 ans = SUMA_ComputeLineSurfaceIntersect(sv, dov, IgnoreSameNode, &ado);
8452 if (ans <= 0) {
8453 SUMA_RETURN(ans);
8454 }
8455 /* just for temporary testing, get PR back from list and apply it */
8456 PR = SUMA_Get_From_PickResult_List(sv, ado, NULL);
8457 ans = SUMA_Apply_PR(sv, &PR);
8458
8459 SUMA_RETURN(ans);
8460 }
8461
8462 /*!
8463 Determines the intersection between ]sv->Pick0 sv->Pick1[ and SO
8464 Highlights the intersected faceset, node and updates cross hair location
8465 This used to be part of Button3's code in SUMA_input
8466 ans = SUMA_ComputeLineSurfaceIntersect (sv, dov);
8467 \param sv (SUMA_SurfaceViewer *) surface viewer pointer
8468 \param dov (SUMA_DO *) displayable object vector pointer
8469 \param IgnoreSameNode (int) 1 do nothing if node already selected
8470 0 don't care if it was already selected
8471 \param pado (SUMA_ALL_DO **) If not NULL, *pado will contain a copy
8472 of an ADO pointer to the intersected
8473 object, if any.
8474 \ret ans (int) -1 error, 0 no hit, hit
8475
8476 Note that this function will register whatever surfaces get hit in the
8477 selections list with a call to SUMA_Add_To_PickResult_List()
8478
8479 also requires SUMAg_DOv and SUMAg_N_DOv
8480 */
SUMA_ComputeLineSurfaceIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode,SUMA_ALL_DO ** pado)8481 int SUMA_ComputeLineSurfaceIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
8482 int IgnoreSameNode, SUMA_ALL_DO **pado)
8483 {/* determine intersection */
8484 static char FuncName[]={"SUMA_ComputeLineSurfaceIntersect"};
8485 float P0f[3], P1f[3];
8486 int NP;
8487 SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL, *MTIi = NULL;
8488 float delta_t_tmp, dmin;
8489 struct timeval tt_tmp;
8490 int ip, it, id, ii, N_SOlist,
8491 SOlist[SUMA_MAX_DISPLAYABLE_OBJECTS], imin;
8492 char sfield[100], sdestination[100], CommString[SUMA_MAX_COMMAND_LENGTH];
8493 SUMA_SurfaceObject *SO = NULL;
8494 SUMA_Boolean LocalHead = NOPE;
8495
8496 SUMA_ENTRY;
8497
8498 P0f[0] = sv->Pick0[0];
8499 P0f[1] = sv->Pick0[1];
8500 P0f[2] = sv->Pick0[2];
8501 P1f[0] = sv->Pick1[0];
8502 P1f[1] = sv->Pick1[1];
8503 P1f[2] = sv->Pick1[2];
8504
8505 N_SOlist = SUMA_VisibleSOs(sv, dov, SOlist, 0);
8506 imin = -1;
8507 dmin = 10000000.0;
8508 for (ii=0; ii < N_SOlist; ++ii) { /* find the closest intersection */
8509 if (LocalHead)
8510 fprintf (SUMA_STDERR,
8511 "%s: working %d/%d shown surfaces ...\n",
8512 FuncName, ii, N_SOlist);
8513 SO = (SUMA_SurfaceObject *)dov[SOlist[ii]].OP;
8514 SUMA_VisX_Pointers4Display(SO, 1); /* using coordinates as displayed */
8515 if (SO->FaceSetDim != 3) {
8516 fprintf(SUMA_STDERR,
8517 "Error %s: "
8518 "SUMA_MT_intersect_triangle only works for triangular meshes.\n",
8519 FuncName);
8520 } else {
8521
8522 SUMA_etime (&tt_tmp, 0);
8523
8524 MTIi = SUMA_MT_intersect_triangle(P0f, P1f, SO->NodeList, SO->N_Node,
8525 SO->FaceSetList, SO->N_FaceSet, NULL, 0);
8526
8527 delta_t_tmp = SUMA_etime (&tt_tmp, 1);
8528 if (LocalHead)
8529 fprintf (SUMA_STDERR,
8530 "Local Debug %s: Intersection took %f seconds.\n",
8531 FuncName, delta_t_tmp);
8532
8533 if (MTIi == NULL) {
8534 fprintf(SUMA_STDERR,
8535 "Error %s: SUMA_MT_intersect_triangle failed.\n", FuncName);
8536 SUMA_RETURN (-1);
8537 }
8538
8539 if (MTIi->N_hits) {
8540 /* decide on the closest surface to the clicking point */
8541 if (MTIi->t[MTIi->ifacemin] < dmin) {
8542 if (LocalHead)
8543 fprintf (SUMA_STDERR, "%s: A minimum for surface %d.\n",
8544 FuncName, ii);
8545 dmin = MTIi->t[MTIi->ifacemin];
8546 imin = SOlist[ii];
8547 MTI = MTIi;
8548 }else {
8549 /* not good, toss it away */
8550 if (LocalHead)
8551 fprintf (SUMA_STDERR,
8552 "%s: ii=%d freeing MTIi...\n", FuncName, ii);
8553 MTIi = SUMA_Free_MT_intersect_triangle(MTIi);
8554 }
8555 }else {
8556 /* not good, toss it away */
8557 if (LocalHead)
8558 fprintf (SUMA_STDERR,
8559 "%s: ii=%d freeing MTIi no hits...\n", FuncName, ii);
8560 MTIi = SUMA_Free_MT_intersect_triangle(MTIi);
8561 }
8562 }
8563 SUMA_VisX_Pointers4Display(SO, 0); /* put things back young man */
8564
8565 }
8566
8567 if (LocalHead)
8568 fprintf (SUMA_STDERR,
8569 "%s: Closest surface is indexed %d in DOv.\n", FuncName, imin);
8570
8571 if (imin >= 0) {
8572 SUMA_PICK_RESULT *PR;
8573 SUMA_ALL_DO *ado;
8574 if (!(ado = iDO_ADO(imin))) {
8575 SUMA_S_Err("NULL ado at this point?");
8576 SUMA_RETURN(-1);
8577 }
8578 PR = SUMA_New_Pick_Result(NULL);
8579 if (pado) *pado = ado; /* user want answer back */
8580 PR->ado_idcode_str = SUMA_copy_string(ADO_ID(ado));
8581 PR->datum_index = MTI->inodemin;
8582 PR->ignore_same_datum = IgnoreSameNode;
8583 PR->iAltSel[SUMA_SURF_TRI] = MTI->ifacemin;
8584 SUMA_COPY_VEC(MTI->P, PR->PickXYZ, 3, float, float);
8585 /* Add selection result to stack */
8586 if (!SUMA_Add_To_PickResult_List(sv, ado, NULL, &PR)) {
8587 SUMA_S_Err("Failed to add selected ado");
8588 SUMA_RETURN(-1);
8589 }
8590 }
8591
8592 /* clear MTI */
8593 if (MTI) {
8594 MTI = SUMA_Free_MT_intersect_triangle(MTI);
8595 }
8596
8597 if (imin >=0) SUMA_RETURN(1);
8598 else SUMA_RETURN(0);
8599 }
8600
SUMA_Apply_PR_SO(SUMA_SurfaceViewer * sv,SUMA_SurfaceObject * SO,SUMA_PICK_RESULT ** PRi)8601 int SUMA_Apply_PR_SO(SUMA_SurfaceViewer *sv, SUMA_SurfaceObject *SO,
8602 SUMA_PICK_RESULT **PRi)
8603 {
8604 static char FuncName[]={"SUMA_Apply_PR_SO"};
8605 SUMA_ALL_DO *ado=NULL;
8606 DList *list = NULL;
8607 DListElmt *SetNodeElem = NULL, *Location=NULL;
8608 SUMA_Boolean NodeIgnored = NOPE;
8609 SUMA_PICK_RESULT *PR;
8610 int NP=0, ip=0, it=0, id = 0, iv3[3];
8611 SUMA_EngineData *ED = NULL;
8612 SUMA_Boolean LocalHead = NOPE;
8613
8614 SUMA_ENTRY;
8615
8616 if (!sv || !SO || !PRi || !*PRi) { SUMA_S_Err("Niente"); SUMA_RETURN(-1); }
8617
8618 /* Mark intersection Facsets */
8619 ado = (SUMA_ALL_DO *)SO;
8620
8621 PR = *PRi; /* Keep local copy */
8622 /* Store the PR in ado, hide it from return potential */
8623 SUMA_ADO_StorePickResult(ado, PRi);
8624
8625
8626 sv->Focus_DO_ID = ADO_iDO(ado);
8627 SUMA_UpdateViewerTitle(sv);
8628
8629 NP = SO->FaceSetDim;
8630 ip = NP * PR->iAltSel[SUMA_SURF_TRI];
8631
8632
8633 /* if the surface controller is open, update it */
8634 if (SUMA_isADO_Cont_Realized(ado))
8635 SUMA_Init_SurfCont_SurfParam(ado);
8636
8637 /* print nodes about the closets faceset*/
8638 fprintf(SUMA_STDOUT, "\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
8639 fprintf(SUMA_STDOUT, "Selected surface %s (Focus_DO_ID # %d).\n"
8640 "FaceSet %ld, Closest Node %ld\n",
8641 SO->Label, sv->Focus_DO_ID, PR->iAltSel[SUMA_SURF_TRI],
8642 PR->datum_index);
8643 fprintf(SUMA_STDOUT, "Nodes forming closest FaceSet:\n");
8644 fprintf(SUMA_STDOUT, "%d, %d, %d\n",
8645 SO->FaceSetList[ip], SO->FaceSetList[ip+1],SO->FaceSetList[ip+2]);
8646
8647 fprintf (SUMA_STDOUT,"Coordinates of Nodes forming closest FaceSet:\n");
8648 for (it=0; it < 3; ++it) {
8649
8650 id = SO->NodeDim * SO->FaceSetList[ip+it];
8651 fprintf(SUMA_STDOUT, "%f, %f, %f\n", SO->NodeList[id],
8652 SO->NodeList[id+1],
8653 SO->NodeList[id+2]);
8654 }
8655 fprintf(SUMA_STDOUT, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
8656
8657 /* Set the Nodeselection at the closest node */
8658 it = PR->datum_index;
8659 if (!list) list = SUMA_CreateList();
8660 if (PR->ignore_same_datum && SO->SelectedNode == PR->datum_index) {
8661 SUMA_LHv("Ignoring identical node selection %d on surface %s\n",
8662 SO->SelectedNode, SO->Label);
8663 NodeIgnored = YUP;
8664 } else {
8665 ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
8666 SetNodeElem = SUMA_RegisterEngineListCommand ( list, ED,
8667 SEF_i, (void*)&it,
8668 SES_Suma, (void *)sv, NOPE,
8669 SEI_Head, NULL);
8670 if (!SetNodeElem) {
8671 fprintf( SUMA_STDERR,
8672 "Error %s: Failed to register SetNodeElem\n", FuncName);
8673 SUMA_RETURN (-1);
8674 } else {
8675 SUMA_RegisterEngineListCommand ( list, ED,
8676 SEF_ngr, NULL,
8677 SES_Suma, (void *)sv, NOPE,
8678 SEI_In, SetNodeElem);
8679 }
8680 }
8681
8682
8683 /* Set the FaceSetselection */
8684 it = PR->iAltSel[SUMA_SURF_TRI];
8685 ED = SUMA_InitializeEngineListData (SE_SetSelectedFaceSet);
8686 if (!SUMA_RegisterEngineListCommand ( list, ED,
8687 SEF_i, (void*)&it,
8688 SES_Suma, (void *)sv, NOPE,
8689 SEI_Head, NULL)) {
8690 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
8691 SUMA_RETURN (-1);
8692 }
8693
8694 /* Now set the cross hair position at the intersection*/
8695 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
8696 if (!(Location = SUMA_RegisterEngineListCommand ( list, ED,
8697 SEF_fv3, (void*)PR->PickXYZ,
8698 SES_Suma, (void *)sv, NOPE,
8699 SEI_Head, NULL))) {
8700 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
8701 SUMA_RETURN (-1);
8702 }
8703 /* and add the SO with this location, needed for VisX business*/
8704 SUMA_RegisterEngineListCommand ( list, ED,
8705 SEF_vp, (void *)SO,
8706 SES_Suma, (void *)sv, NOPE,
8707 SEI_In, Location);
8708
8709 /* attach the cross hair to the selected surface */
8710 iv3[0] = SUMA_findSO_inDOv(SO->idcode_str, SUMAg_DOv, SUMAg_N_DOv);
8711 iv3[1] = PR->datum_index;
8712 iv3[2] = PR->iAltSel[SUMA_SURF_TRI];
8713 ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
8714 if (!SUMA_RegisterEngineListCommand ( list, ED,
8715 SEF_iv3, (void*)iv3,
8716 SES_Suma, (void *)sv, NOPE,
8717 SEI_Head, NULL)) {
8718 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
8719 SUMA_RETURN (-1);
8720 }
8721
8722 /* check to see if AFNI needs to be notified */
8723 /* Need to deal with SUMA_TO_MATLAB_STREAM_INDEX too
8724 Same for remaining occurrence of SUMA_AFNI_STREAM_INDEX*/
8725 if ( ( SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] &&
8726 sv->LinkAfniCrossHair ) ||
8727 ( SUMAg_CF->Connected_v[SUMA_HALLO_SUMA_LINE]) ||
8728 ( SUMAg_CF->Connected_v[SUMA_INSTA_TRACT_LINE]) ) {
8729 if (LocalHead)
8730 fprintf(SUMA_STDERR,
8731 "%s: Notifying Afni of CrossHair XYZ\n", FuncName);
8732 /* register a call to SetAfniCrossHair */
8733 if (!list) list = SUMA_CreateList();
8734 it = SUMA_ShftCont_Event(PR->evr);
8735 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
8736 if (!SUMA_RegisterEngineListCommand ( list, ED,
8737 SEF_i, (void*)&it,
8738 SES_Suma, (void *)sv, NOPE,
8739 SEI_Tail, NULL)) {
8740 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
8741 SUMA_RETURN (-1);
8742 }
8743 if (MASK_MANIP_MODE(sv) && SUMAg_CF->Dev) {
8744 SUMA_ALL_DO *ado = SUMA_whichADOg(sv->MouseMode_ado_idcode_str);
8745 if (ado && ado->do_type == MASK_type) {
8746 SUMA_MaskDO *mdo = (SUMA_MaskDO *)ado;
8747 ED = SUMA_InitializeEngineListData (SE_SetAfniMask);
8748 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
8749 SEF_fv3, (void*)mdo->cen,
8750 SES_Suma, (void *)sv, NOPE,
8751 SEI_Tail, NULL))) {
8752 SUMA_S_Err("Failed to register element\n");
8753 SUMA_RETURN (-1);
8754 }
8755 SUMA_RegisterEngineListCommand ( list, ED,
8756 SEF_s, (void *)(ADO_ID(ado)),
8757 SES_Suma, (void *)sv, NOPE,
8758 SEI_In, Location);
8759 }
8760 }
8761 if (!SUMA_Engine (&list)) {
8762 fprintf( SUMA_STDERR,
8763 "Error %s: SUMA_Engine call failed.\n", FuncName);
8764 SUMA_RETURN (-1);
8765 }
8766 }else {
8767 if (LocalHead)
8768 fprintf(SUMA_STDERR,"%s: No Notification to AFNI.\n", FuncName);
8769 }
8770
8771 /* put in a request for GICOR if need be */
8772 if ( !NodeIgnored &&
8773 SUMAg_CF->Connected_v[SUMA_GICORR_LINE] &&
8774 SUMAg_CF->giset && !SUMAg_CF->HoldClickCallbacks) {
8775 if (LocalHead)
8776 fprintf(SUMA_STDERR,
8777 "%s: Notifying GICOR of node selection\n", FuncName);
8778 /* register a call to SetGICORnode */
8779 if (!list) list = SUMA_CreateList();
8780 SUMA_REGISTER_TAIL_COMMAND_NO_DATA( list, SE_SetGICORnode,
8781 SES_Suma, sv);
8782 if (!SUMA_Engine (&list)) {
8783 fprintf( SUMA_STDERR,
8784 "Error %s: SUMA_Engine call failed.\n", FuncName);
8785 SUMA_RETURN (-1);
8786 }
8787 }else {
8788 if (LocalHead)
8789 fprintf(SUMA_STDERR,"%s: No Notification to GICOR.\n", FuncName);
8790 }
8791 /* now put in a request for locking cross hair but you must do
8792 this after the node selection has been executed
8793 NOTE: You do not always have SetNodeElem because the list might
8794 get emptied in the call to AFNI notification.
8795 You should just put the next call at the end of the list.*/
8796 SUMA_LH("Cross hair locking");
8797 if (!list) list = SUMA_CreateList();
8798 ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
8799 if (!SUMA_RegisterEngineListCommand ( list, ED,
8800 SEF_iv3, (void*)iv3,
8801 SES_Suma, (void *)sv, NOPE,
8802 SEI_Tail, NULL)) {
8803 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
8804 SUMA_RETURN (-1);
8805 }
8806
8807 SUMA_LH("Cross hair locking Engine call");
8808 if (!SUMA_Engine (&list)) {
8809 fprintf(SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n", FuncName);
8810 SUMA_RETURN (-1);
8811 }
8812 SUMA_LH("Returning");
8813 SUMA_RETURN (1); /* OK */
8814 }/* determine intersection */
8815
SUMA_MarkLineCutplaneIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode)8816 int SUMA_MarkLineCutplaneIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
8817 int IgnoreSameNode)
8818 {/* determine intersection */
8819 static char FuncName[]={"SUMA_MarkLineCutplaneIntersect"};
8820 float P0f[3], P1f[3];
8821 int NP;
8822 SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL, *MTIi = NULL;
8823 float delta_t_tmp, dmin;
8824 struct timeval tt_tmp;
8825 int ip, it, id, iv3[3], ii, N_SOlist,
8826 SOlist[SUMA_MAX_DISPLAYABLE_OBJECTS], imin;
8827 char sfield[100], sdestination[100], CommString[SUMA_MAX_COMMAND_LENGTH];
8828 SUMA_EngineData *ED = NULL;
8829 DList *list = NULL;
8830 DListElmt *SetNodeElem = NULL, *Location=NULL;
8831 SUMA_SurfaceObject *SO = NULL;
8832 SUMA_SurfaceObject **SOv = NULL;
8833 SUMA_VolumeObject *VO=NULL;
8834 SUMA_Boolean NodeIgnored = NOPE;
8835 SUMA_Boolean LocalHead = NOPE;
8836
8837 SUMA_ENTRY;
8838
8839 P0f[0] = sv->Pick0[0];
8840 P0f[1] = sv->Pick0[1];
8841 P0f[2] = sv->Pick0[2];
8842 P1f[0] = sv->Pick1[0];
8843 P1f[1] = sv->Pick1[1];
8844 P1f[2] = sv->Pick1[2];
8845
8846 SUMA_LH("Getting array of pointers to clip plane surfaces");
8847 if (!(SOv = SUMA_TextureClipPlaneSurfaces(&N_SOlist))) {
8848 SUMA_LH("No clip plane surfaces");
8849 SUMA_RETURN(0);
8850 }
8851 imin = -1;
8852 dmin = 10000000.0;
8853 for (ii=0; ii < N_SOlist; ++ii) { /* find the closest intersection */
8854 if (LocalHead)
8855 fprintf (SUMA_STDERR,
8856 "%s: working %d/%d clip plane ...\n",
8857 FuncName, ii, N_SOlist);
8858 SO = SOv[ii];
8859 if (SO->FaceSetDim != 3) {
8860 fprintf(SUMA_STDERR,
8861 "Error %s: "
8862 "SUMA_MT_intersect_triangle only works for triangular meshes.\n",
8863 FuncName);
8864 } else {
8865
8866 SUMA_etime (&tt_tmp, 0);
8867 SUMA_LH("About to call intersection function");
8868
8869 MTIi = SUMA_MT_intersect_triangle(P0f, P1f, SO->NodeList, SO->N_Node,
8870 SO->FaceSetList, SO->N_FaceSet, NULL, 0);
8871
8872 delta_t_tmp = SUMA_etime (&tt_tmp, 1);
8873 if (LocalHead)
8874 fprintf (SUMA_STDERR,
8875 "Local Debug %s: Intersection took %f seconds.\n",
8876 FuncName, delta_t_tmp);
8877
8878 if (MTIi == NULL) {
8879 fprintf(SUMA_STDERR,
8880 "Error %s: SUMA_MT_intersect_triangle failed.\n", FuncName);
8881 SUMA_RETURN (-1);
8882 }
8883
8884 if (MTIi->N_hits) {
8885 /* decide on the closest surface to the clicking point */
8886 if (MTIi->t[MTIi->ifacemin] < dmin) {
8887 if (LocalHead)
8888 fprintf (SUMA_STDERR, "%s: A minimum for surface %d.\n",
8889 FuncName, ii);
8890 dmin = MTIi->t[MTIi->ifacemin];
8891 imin = ii;
8892 MTI = MTIi;
8893 }else {
8894 /* not good, toss it away */
8895 if (LocalHead)
8896 fprintf (SUMA_STDERR,
8897 "%s: ii=%d freeing MTIi...\n", FuncName, ii);
8898 MTIi = SUMA_Free_MT_intersect_triangle(MTIi);
8899 }
8900 }else {
8901 /* not good, toss it away */
8902 if (LocalHead)
8903 fprintf (SUMA_STDERR,
8904 "%s: ii=%d freeing MTIi no hits...\n", FuncName, ii);
8905 MTIi = SUMA_Free_MT_intersect_triangle(MTIi);
8906 }
8907 }
8908 }
8909
8910 if (LocalHead)
8911 fprintf (SUMA_STDERR,
8912 "%s: Closest surface is indexed %d in cutplane surfaces.\n",
8913 FuncName, imin);
8914
8915 /* Mark intersection Facsets */
8916 if (imin >= 0) {
8917 SUMA_ALL_DO *ado=NULL;
8918 if (!(VO = SUMA_VolumeObjectOfClipPlaneSurface(SO))) {
8919 SUMA_S_Err("Failed to find volume object for clipped surface");
8920 SUMA_RETURN(-1);
8921 }
8922 VO->SelectedCutPlane = imin;
8923 SUMA_S_Warn("NEED TO IMPLEMENT PR THING HERE, THEN PASS IT BELOW");
8924 ado = (SUMA_ALL_DO *)VO;
8925 if (!SUMA_Add_To_PickResult_List(sv, ado, "cutplane", NULL)) {
8926 SUMA_S_Err("Failed to add selected ado");
8927 SUMA_RETURN(-1);
8928 }
8929 /* Now set this volume as the focus DO */
8930 sv->Focus_DO_ID =
8931 SUMA_findVO_inDOv(SUMA_ADO_idcode(ado), SUMAg_DOv, SUMAg_N_DOv);
8932
8933 /* if the surface controller is open, update it */
8934 if (SUMA_isADO_Cont_Realized(ado))
8935 SUMA_Init_SurfCont_SurfParam(ado);
8936
8937 SUMA_UpdateViewerTitle(sv);
8938
8939 /* if the surface controller is open, update it */
8940 if (SUMA_isADO_Cont_Realized(ado))
8941 SUMA_Init_SurfCont_SurfParam(ado);
8942
8943
8944 ip = SO->FaceSetDim * MTI->ifacemin;
8945 SUMA_S_Note("Have to decide on what to do here,\n"
8946 "see equivalent section in SUMA_MarkLineSurfaceIntersect");
8947 SUMA_S_Warn("Weird, coords all zero");
8948 /* print nodes about the closets faceset*/
8949 fprintf(SUMA_STDOUT, "\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
8950 fprintf(SUMA_STDOUT, "Selected cutplane surface %d .\n"
8951 "FaceSet %d, Closest Node %d\n",
8952 imin, MTI->ifacemin, MTI->inodemin);
8953 fprintf(SUMA_STDOUT, "Nodes forming closest FaceSet:\n");
8954 fprintf(SUMA_STDOUT, "%d, %d, %d\n", \
8955 SO->FaceSetList[ip], SO->FaceSetList[ip+1],SO->FaceSetList[ip+2]);
8956
8957 fprintf (SUMA_STDOUT,"Coordinates of Nodes forming closest FaceSet:\n"
8958 "SO->NodeDim = %d \n", SO->NodeDim);
8959 for (it=0; it < 3; ++it) {
8960
8961 id = SO->NodeDim * SO->FaceSetList[ip+it];
8962 fprintf(SUMA_STDOUT, "%f, %f, %f\n", SO->NodeList[id],
8963 SO->NodeList[id+1],
8964 SO->NodeList[id+2]);
8965 }
8966 fprintf(SUMA_STDOUT, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
8967
8968
8969
8970 /* Now set the cross hair position at the intersection*/
8971 if (!list) list = SUMA_CreateList();
8972 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
8973 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
8974 SEF_fv3, (void*)MTI->P,
8975 SES_Suma, (void *)sv, NOPE,
8976 SEI_Head, NULL))) {
8977 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
8978 SUMA_RETURN (-1);
8979 }
8980 /* and add the SO with this location, needed for VisX business*/
8981 SUMA_RegisterEngineListCommand ( list, ED,
8982 SEF_vp, (void *)SO,
8983 SES_Suma, (void *)sv, NOPE,
8984 SEI_In, Location);
8985
8986 if (!SUMA_Engine (&list)) {
8987 fprintf( SUMA_STDERR,
8988 "Error %s: SUMA_Engine call failed.\n", FuncName);
8989 SUMA_RETURN (-1);
8990 }
8991 /* check to see if AFNI needs to be notified */
8992 /* Need to deal with SUMA_TO_MATLAB_STREAM_INDEX too
8993 Same for remaining occurrence of SUMA_AFNI_STREAM_INDEX*/
8994 if ( SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] &&
8995 sv->LinkAfniCrossHair) {
8996 if (LocalHead)
8997 fprintf(SUMA_STDERR,
8998 "%s: Notifying Afni of CrossHair XYZ\n", FuncName);
8999 /* register a call to SetAfniCrossHair */
9000 if (!list) list = SUMA_CreateList();
9001 it = 0; /* Might want someday: SUMA_ShftCont_Event(PR->evr); */
9002 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
9003 if (!SUMA_RegisterEngineListCommand ( list, ED,
9004 SEF_i, (void*)&it,
9005 SES_Suma, (void *)sv, NOPE,
9006 SEI_Tail, NULL)) {
9007 SUMA_S_Err("Failed to register element\n");
9008 SUMA_RETURN (-1);
9009 }
9010 if (!SUMA_Engine (&list)) {
9011 fprintf( SUMA_STDERR,
9012 "Error %s: SUMA_Engine call failed.\n", FuncName);
9013 SUMA_RETURN (-1);
9014 }
9015 }else {
9016 if (LocalHead)
9017 fprintf(SUMA_STDERR,"%s: No Notification to AFNI.\n", FuncName);
9018 }
9019
9020 /* put in a request for GICOR if need be */
9021 if ( !NodeIgnored &&
9022 SUMAg_CF->Connected_v[SUMA_GICORR_LINE] &&
9023 SUMAg_CF->giset && !SUMAg_CF->HoldClickCallbacks) {
9024 if (LocalHead)
9025 fprintf(SUMA_STDERR,
9026 "%s: Notifying GICOR of node selection\n", FuncName);
9027 /* register a call to SetGICORnode */
9028 if (!list) list = SUMA_CreateList();
9029 SUMA_REGISTER_TAIL_COMMAND_NO_DATA( list, SE_SetGICORnode,
9030 SES_Suma, sv);
9031 if (!SUMA_Engine (&list)) {
9032 fprintf( SUMA_STDERR,
9033 "Error %s: SUMA_Engine call failed.\n", FuncName);
9034 SUMA_RETURN (-1);
9035 }
9036 }else {
9037 if (LocalHead)
9038 fprintf(SUMA_STDERR,"%s: No Notification to GICOR.\n", FuncName);
9039 }
9040
9041
9042
9043 }
9044 /* clear MTI */
9045 if (MTI) {
9046 MTI = SUMA_Free_MT_intersect_triangle(MTI);
9047 }
9048
9049 SUMA_free(SOv); SOv = NULL;
9050
9051 if (imin >= 0) {
9052 SUMA_RETURN (1); /* hit */
9053 } else {
9054 SUMA_RETURN (0); /* no hit */
9055 }
9056 }/* determine intersection with cutplanes*/
9057
SUMA_MarkLineVOslicesIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode)9058 int SUMA_MarkLineVOslicesIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
9059 int IgnoreSameNode)
9060 {/* determine intersection */
9061 static char FuncName[]={"SUMA_MarkLineVOslicesIntersect"};
9062 SUMA_PICK_RESULT *PR = NULL;
9063 SUMA_ALL_DO *ado = NULL;
9064 int ans;
9065
9066 SUMA_ENTRY;
9067 SUMA_S_Warn("Do not call me anymore. Follow the new selection logic");
9068 ans = SUMA_ComputeLineVOslicesIntersect(sv, dov, IgnoreSameNode, &ado);
9069 if (ans <= 0) {
9070 SUMA_RETURN(ans);
9071 }
9072 /* just for temporary testing, get PR back from list and apply it */
9073 PR = SUMA_Get_From_PickResult_List(sv, ado, NULL);
9074 ans = SUMA_Apply_PR(sv, &PR);
9075 SUMA_RETURN(ans);
9076 }
9077
9078 #if 0
9079 /* BEFORE you start using this MACRO everywhere, including with the,
9080 other ThrMode values, make sure you write a function version of it
9081 which can be used as a sanity check. For now, this seems OK */
9082 #define SUMA_VAL_MEETS_THRESH(val, ThreshRange, ThrMode) (\
9083 ((ThrMode) == SUMA_LESS_THAN && (val) >= ThreshRange[0])?1: \
9084 (((ThrMode) == SUMA_ABS_LESS_THAN && ( (val) >= ThreshRange[0] || \
9085 (val) <= -ThreshRange[0]))?1:0) )
9086 #endif
SUMA_Val_Meets_Thresh(float val,double * ThreshRange,SUMA_THRESH_MODE ThrMode)9087 byte SUMA_Val_Meets_Thresh(float val, double *ThreshRange,
9088 SUMA_THRESH_MODE ThrMode)
9089 {
9090 static char FuncName[]={"SUMA_Val_Meets_Thresh"};
9091 switch(ThrMode){
9092 case SUMA_LESS_THAN:
9093 return((val >= ThreshRange[0]));
9094 break;
9095 case SUMA_ABS_LESS_THAN:
9096 return((val >= ThreshRange[0]) || (val <= -ThreshRange[0]));
9097 break;
9098 case SUMA_THRESH_OUTSIDE_RANGE:
9099 return((val < ThreshRange[0]) || (val > ThreshRange[1]));
9100 break;
9101 case SUMA_THRESH_INSIDE_RANGE:
9102 return((val >= ThreshRange[0]) && (val <= ThreshRange[1]));
9103 break;
9104 case SUMA_NO_THRESH:
9105 return(1);
9106 default:
9107 SUMA_S_Warn("Bad thresh mode %d", ThrMode);
9108 return(1);
9109 break;
9110 }
9111 SUMA_S_Warn("Should not be here %d", ThrMode);
9112 return(1);
9113 }
9114
9115 /*
9116 This function is almost identical to SUMA_ComputeLineVOvrIntersect()
9117 They could be merged quite readily but for some reason this feels
9118 cleaner to me.
9119 Make sure that any change here is mirrored verbatim (to the degree possible)
9120 in SUMA_ComputeLineVOvrIntersect() .
9121
9122 Consider merging SUMA_ComputeLineVOvrIntersect() into
9123 SUMA_ComputeLineVOslicesIntersect() in the future if maintenance is a problem
9124 */
SUMA_ComputeLineVOslicesIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode,SUMA_ALL_DO ** pado)9125 int SUMA_ComputeLineVOslicesIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
9126 int IgnoreSameNode, SUMA_ALL_DO **pado)
9127 {/* determine intersection */
9128 static char FuncName[]={"SUMA_ComputeLineVOslicesIntersect"};
9129 float P0f[3], P1f[3], pinter[3], I[3];
9130 int NP, N_Hit, okinten=0;
9131 float delta_t_tmp, dmin, val;
9132 struct timeval tt_tmp;
9133 int ip, it, id, ii, imin, I1d, Irw, Hit, ive, icolplane, indef=-1;
9134 int *MembDOs=NULL, N_MembDOs, UseAlphaTresh=1;
9135 float valpha=0.0;
9136 SUMA_DO_Types ttv[12];
9137 char sfield[100], sdestination[100], CommString[SUMA_MAX_COMMAND_LENGTH];
9138 SUMA_VolumeObject *VO=NULL;
9139 SUMA_Boolean NodeIgnored = NOPE;
9140 SUMA_RENDERED_SLICE *rslc;
9141 SUMA_ALL_DO *ado = NULL;
9142 SUMA_DSET *dset = NULL;
9143 SUMA_OVERLAYS *colplane=NULL;
9144 SUMA_VOL_SAUX *VSaux = NULL;
9145 SUMA_PICK_RESULT *PR=NULL;
9146 DListElmt *el=NULL;
9147 SUMA_Boolean LocalHead = NOPE;
9148
9149 SUMA_ENTRY;
9150
9151 P0f[0] = sv->Pick0[0];
9152 P0f[1] = sv->Pick0[1];
9153 P0f[2] = sv->Pick0[2];
9154 P1f[0] = sv->Pick1[0];
9155 P1f[1] = sv->Pick1[1];
9156 P1f[2] = sv->Pick1[2];
9157
9158 ttv[0] = VO_type; ttv[1] = NOT_SET_type;
9159 MembDOs = SUMA_ViewState_Membs(&(sv->VSv[sv->iState]), ttv, &N_MembDOs);
9160 SUMA_LHv("Searching for hit: %f %f %f --> %f %f %f\n",
9161 P0f[0], P0f[1], P0f[2], P1f[0], P1f[1], P1f[2]);
9162 N_Hit = 0;
9163 for (ii=0; ii<N_MembDOs; ++ii) {
9164 {
9165 VO = (SUMA_VolumeObject *)(dov[MembDOs[ii]].OP);
9166 ado = (SUMA_ALL_DO *)VO;
9167 if (!(VSaux = SUMA_ADO_VSaux(ado))) continue;
9168 SUMA_LH("%d slices on %s", dlist_size(VSaux->slcl), ADO_LABEL(ado));
9169 if (!dlist_size(VSaux->slcl)) continue;
9170 /* now compute intersection from the top down */
9171 Hit = 0;
9172 el = NULL;
9173 do {
9174 if (!el) el = dlist_head(VSaux->slcl);
9175 else el = dlist_next(el);
9176 rslc = (SUMA_RENDERED_SLICE *)el->data;
9177 /* does line intersect this plane? */
9178 SUMA_SEGMENT_PLANE_INTERSECT(P0f, P1f, rslc->Eq, Hit, pinter);
9179 if (Hit) {/* is the intersection point in the volume? */
9180 Hit = 0; /* demote, real hit decided on below */
9181 ive = 0;
9182 while (VO->VE && VO->VE[ive]) {
9183 AFF44_MULT_I(I, VO->VE[ive]->X2I, pinter);
9184 SUMA_LH("On %s: Inter at X=[%f %f %f] --> ijk=[%f %f %f]",
9185 SUMA_VE_Headname(VO->VE, ive),
9186 pinter[0], pinter[1], pinter[2], I[0], I[1], I[2]);
9187 I[0] = (int)I[0]; I[1] = (int)I[1]; I[2] = (int)I[2];
9188 if (I[0] >= 0.0f && I[1] >= 0.0f && I[2] >= 0.0f &&
9189 I[0] < VO->VE[ive]->Ni && I[1] < VO->VE[ive]->Nj &&
9190 I[2] < VO->VE[ive]->Nk) {
9191 dset = SUMA_VE_dset(VO->VE, ive);
9192 colplane = SUMA_Fetch_OverlayPointerByDset(
9193 (SUMA_ALL_DO *)VO, dset, &icolplane);
9194 /* here you check on the value at I in the dataset */
9195 I1d = I[2]*VO->VE[ive]->Ni*VO->VE[ive]->Nj +
9196 I[1]*VO->VE[ive]->Ni+I[0];
9197 Irw = SUMA_GetNodeRow_FromNodeIndex_eng(dset, I1d,-1);
9198 if (!colplane->V) {
9199 SUMA_S_Err("Need SUMA_GetDsetValInCol to get vals");
9200 SUMA_RETURN(NOPE);
9201 } else {
9202 val = colplane->V[Irw];
9203 }
9204 SUMA_LH("Have intersection on ive %d inside VE %s\n"
9205 "IJK [%d %d %d], I1d=%d, Irw=%d, \n"
9206 "val %f, thr [%f %f]\n",
9207 ive, SUMA_VE_Headname(VO->VE, ive),
9208 (int)I[0], (int)I[1], (int)I[2],
9209 I1d, Irw, val,
9210 colplane->OptScl->ThreshRange[0],
9211 colplane->OptScl->ThreshRange[1]);
9212
9213 /* Do we meet intensity thresholds? */
9214 okinten = 0;
9215 if ( SUMA_Val_Meets_Thresh(val,
9216 colplane->OptScl->ThreshRange,
9217 colplane->OptScl->ThrMode ) &&
9218 (val != 0.0f || !colplane->OptScl->MaskZero)) {
9219 okinten = 1;
9220 }
9221
9222 indef = -1;
9223 UseAlphaTresh = 1;/* control from interface someday */
9224 valpha = 2.0; /* no masking */
9225 if (UseAlphaTresh && okinten && colplane->ColAlpha) {
9226 /* Also mask if value is below alpha thresh
9227 This is a slow search... So you may not want
9228 to use it all the time.
9229 Problem is finding the row of the voxel in
9230 NodeDef, and that's too slow for a big
9231 volume to be run repeatedly...Would
9232 be easier if I had a function to recompute
9233 a voxel's alpha, rather than search for it
9234 in ColAlpha. Oh, well, someday I guess. For
9235 now we search*/
9236 if ((indef=SUMA_GetSortedNodeOverInd(colplane, I1d))>=0){
9237 valpha = colplane->ColAlpha[indef]/255.0;
9238 }
9239 }
9240
9241 if ( okinten && (valpha > colplane->AlphaThresh) ) {
9242 SUMA_LH("FOUND IT, on VE %s, IJK [%d %d %d], val %f,"
9243 "thresh[%f %f], UseAlphaTresh = %d, "
9244 "valpha=%f, ColAlphaThresh=%f\n",
9245 SUMA_VE_Headname(VO->VE, ive),
9246 (int)I[0], (int)I[1], (int)I[2], val,
9247 colplane->OptScl->ThreshRange[0],
9248 colplane->OptScl->ThreshRange[1],
9249 UseAlphaTresh,
9250 valpha, colplane->AlphaThresh*255);
9251 PR = SUMA_New_Pick_Result(NULL);
9252 PR->ado_idcode_str = SUMA_replace_string(
9253 PR->ado_idcode_str, ADO_ID(ado));
9254 if (pado) *pado = ado; /* user wants it */
9255 PR->primitive = SUMA_replace_string(
9256 PR->primitive,"voxel");
9257 PR->primitive_index = -1;
9258 PR->PickXYZ[0] = pinter[0];
9259 PR->PickXYZ[1] = pinter[1];
9260 PR->PickXYZ[2] = pinter[2];
9261 PR->ignore_same_datum = IgnoreSameNode;
9262 PR->datum_index = I1d;
9263 PR->iAltSel[SUMA_VOL_I] = I[0];
9264 PR->iAltSel[SUMA_VOL_J] = I[1];
9265 PR->iAltSel[SUMA_VOL_K] = I[2];
9266 PR->iAltSel[SUMA_VOL_IJK] = I1d;
9267 PR->iAltSel[SUMA_VOL_SLC_NUM] = rslc->slc_num;
9268 PR->iAltSel[SUMA_VOL_SLC_VARIANT] =
9269 (int)SUMA_SlcVariantToCode(rslc->variant);
9270 PR->dAltSel[SUMA_VOL_SLC_EQ0] = rslc->Eq[0];
9271 PR->dAltSel[SUMA_VOL_SLC_EQ1] = rslc->Eq[1];
9272 PR->dAltSel[SUMA_VOL_SLC_EQ2] = rslc->Eq[2];
9273 PR->dAltSel[SUMA_VOL_SLC_EQ3] = rslc->Eq[3];
9274 PR->dset_idcode_str = SUMA_replace_string(
9275 PR->dset_idcode_str, SDSET_ID(dset));
9276 if (!SUMA_Add_To_PickResult_List(sv, ado,
9277 "voxel", &PR)) {
9278 SUMA_S_Err("Failed to add selected ado");
9279 SUMA_RETURN(0);
9280 }
9281 Hit = 1;
9282 ++N_Hit;
9283 /* You could leave at the first hit IF:
9284 you only have one direction of slices in the
9285 entire stack, AND if they are properly
9286 ordered for rendering.
9287 Should speed be an issue you can check for
9288 this condition and bolt with the line below */
9289 /* goto GOT_IT; */
9290 }
9291 }
9292 ++ive;
9293 }
9294 }
9295 SUMA_LH("el now %p,\n"
9296 "tail = %p, N_Hit = %d",
9297 el, dlist_tail(VSaux->slcl), N_Hit);
9298 } while(el != dlist_tail(VSaux->slcl));
9299 }
9300 }
9301
9302
9303 GOT_IT:
9304 SUMA_RETURN(N_Hit);
9305 }/* determine intersection with slices of VO*/
9306
9307 /*
9308 This function is almost identical to SUMA_ComputeLineVOslicesIntersect()
9309 They could be merged quite readily but for some reason this feels
9310 cleaner to me.
9311 Make sure that any change here is mirrored verbatim (to the degree possible)
9312 in SUMA_ComputeLineVOslicesIntersect() .
9313
9314 Consider merging SUMA_ComputeLineVOvrIntersect() into
9315 SUMA_ComputeLineVOslicesIntersect() in the future if maintenance is a problem
9316
9317
9318 */
SUMA_ComputeLineVOvrIntersect(SUMA_SurfaceViewer * sv,SUMA_DO * dov,int IgnoreSameNode,SUMA_ALL_DO ** pado)9319 int SUMA_ComputeLineVOvrIntersect (SUMA_SurfaceViewer *sv, SUMA_DO *dov,
9320 int IgnoreSameNode, SUMA_ALL_DO **pado)
9321 {/* determine intersection */
9322 static char FuncName[]={"SUMA_ComputeLineVOvrIntersect"};
9323 float P0f[3], P1f[3], pinter[3], I[3];
9324 int NP, N_Hit, okinten=0;
9325 float delta_t_tmp, dmin, val;
9326 struct timeval tt_tmp;
9327 int ip, it, id, ii, imin, I1d, Irw, Hit, ive, icolplane, indef=-1;
9328 int *MembDOs=NULL, N_MembDOs, UseAlphaTresh=1;
9329 float valpha=0.0;
9330 SUMA_DO_Types ttv[12];
9331 char sfield[100], sdestination[100], CommString[SUMA_MAX_COMMAND_LENGTH];
9332 SUMA_VolumeObject *VO=NULL;
9333 SUMA_Boolean NodeIgnored = NOPE;
9334 SUMA_RENDERED_SLICE *rslc;
9335 SUMA_ALL_DO *ado = NULL;
9336 SUMA_DSET *dset = NULL;
9337 SUMA_OVERLAYS *colplane=NULL;
9338 SUMA_VOL_SAUX *VSaux = NULL;
9339 SUMA_PICK_RESULT *PR=NULL;
9340 DListElmt *el=NULL;
9341 SUMA_Boolean LocalHead = NOPE;
9342
9343 SUMA_ENTRY;
9344
9345 P0f[0] = sv->Pick0[0];
9346 P0f[1] = sv->Pick0[1];
9347 P0f[2] = sv->Pick0[2];
9348 P1f[0] = sv->Pick1[0];
9349 P1f[1] = sv->Pick1[1];
9350 P1f[2] = sv->Pick1[2];
9351
9352 ttv[0] = VO_type; ttv[1] = NOT_SET_type;
9353 MembDOs = SUMA_ViewState_Membs(&(sv->VSv[sv->iState]), ttv, &N_MembDOs);
9354 SUMA_LHv("Searching for hit: %f %f %f --> %f %f %f\n",
9355 P0f[0], P0f[1], P0f[2], P1f[0], P1f[1], P1f[2]);
9356 N_Hit = 0;
9357 for (ii=0; ii<N_MembDOs; ++ii) {
9358 {
9359 VO = (SUMA_VolumeObject *)(dov[MembDOs[ii]].OP);
9360 ado = (SUMA_ALL_DO *)VO;
9361 if (!(VSaux = SUMA_ADO_VSaux(ado))) continue;
9362 SUMA_LH("%d VR slices on %s, show=%d, VrSelect=%d",
9363 dlist_size(VSaux->vrslcl),
9364 ADO_LABEL(ado), VSaux->ShowVrSlc,
9365 VSaux->VrSelect);
9366 if (!VSaux->ShowVrSlc || !VSaux->VrSelect) continue;
9367 if (!dlist_size(VSaux->vrslcl)) continue;
9368 /* now compute intersection from the top down */
9369 Hit = 0;
9370 el = NULL;
9371 do {
9372 if (!el) el = dlist_head(VSaux->vrslcl);
9373 else el = dlist_next(el);
9374 rslc = (SUMA_RENDERED_SLICE *)el->data;
9375 /* does line intersect this plane? */
9376 SUMA_SEGMENT_PLANE_INTERSECT(P0f, P1f, rslc->Eq, Hit, pinter);
9377 if (Hit) {/* is the intersection point in the volume? */
9378 Hit = 0; /* demote, real hit decided on below */
9379 ive = 0;
9380 while (VO->VE && VO->VE[ive]) {
9381 AFF44_MULT_I(I, VO->VE[ive]->X2I, pinter);
9382 SUMA_LH("On %s: Inter at X=[%f %f %f] --> ijk=[%f %f %f]",
9383 SUMA_VE_Headname(VO->VE, ive),
9384 pinter[0], pinter[1], pinter[2], I[0], I[1], I[2]);
9385 I[0] = (int)I[0]; I[1] = (int)I[1]; I[2] = (int)I[2];
9386 if (I[0] >= 0.0f && I[1] >= 0.0f && I[2] >= 0.0f &&
9387 I[0] < VO->VE[ive]->Ni && I[1] < VO->VE[ive]->Nj &&
9388 I[2] < VO->VE[ive]->Nk) {
9389 dset = SUMA_VE_dset(VO->VE, ive);
9390 colplane = SUMA_Fetch_OverlayPointerByDset(
9391 (SUMA_ALL_DO *)VO, dset, &icolplane);
9392 /* here you check on the value at I in the dataset */
9393 I1d = I[2]*VO->VE[ive]->Ni*VO->VE[ive]->Nj +
9394 I[1]*VO->VE[ive]->Ni+I[0];
9395 Irw = SUMA_GetNodeRow_FromNodeIndex_eng(dset, I1d,-1);
9396 if (!colplane->V) {
9397 SUMA_S_Err("Need SUMA_GetDsetValInCol to get vals");
9398 SUMA_RETURN(NOPE);
9399 } else {
9400 val = colplane->V[Irw];
9401 }
9402 SUMA_LH("Have intersection on ive %d inside VE %s\n"
9403 "IJK [%d %d %d], I1d=%d, Irw=%d, \n"
9404 "val %f, thr [%f %f]\n",
9405 ive, SUMA_VE_Headname(VO->VE, ive),
9406 (int)I[0], (int)I[1], (int)I[2],
9407 I1d, Irw, val,
9408 colplane->OptScl->ThreshRange[0],
9409 colplane->OptScl->ThreshRange[1]);
9410
9411 /* Do we meet intensity thresholds? */
9412 okinten = 0;
9413 if ( SUMA_Val_Meets_Thresh(val,
9414 colplane->OptScl->ThreshRange,
9415 colplane->OptScl->ThrMode ) &&
9416 (val != 0.0f || !colplane->OptScl->MaskZero)) {
9417 okinten = 1;
9418 }
9419
9420 indef = -1;
9421 UseAlphaTresh = 1;/* control from interface someday */
9422 valpha = 2.0; /* no masking */
9423 if (UseAlphaTresh && okinten && colplane->ColAlpha) {
9424 /* Also mask if value is below alpha thresh
9425 This is a slow search... So you may not want
9426 to use it all the time.
9427 Problem is finding the row of the voxel in
9428 NodeDef, and that's too slow for a big
9429 volume to be run repeatedly...Would
9430 be easier if I had a function to recompute
9431 a voxel's alpha, rather than search for it
9432 in ColAlpha. Oh, well, someday I guess. For
9433 now we search*/
9434 if ((indef=SUMA_GetSortedNodeOverInd(colplane, I1d))>=0){
9435 valpha = colplane->ColAlpha[indef]/255.0;
9436 }
9437 }
9438
9439 if ( okinten && (valpha > colplane->AlphaThresh) ) {
9440 SUMA_LH("FOUND IT, on VE %s, IJK [%d %d %d], val %f,"
9441 "thresh[%f %f], UseAlphaTresh = %d, "
9442 "valpha=%f, ColAlphaThresh=%f\n",
9443 SUMA_VE_Headname(VO->VE, ive),
9444 (int)I[0], (int)I[1], (int)I[2], val,
9445 colplane->OptScl->ThreshRange[0],
9446 colplane->OptScl->ThreshRange[1],
9447 UseAlphaTresh,
9448 valpha, colplane->AlphaThresh*255);
9449 PR = SUMA_New_Pick_Result(NULL);
9450 PR->ado_idcode_str = SUMA_replace_string(
9451 PR->ado_idcode_str, ADO_ID(ado));
9452 if (pado) *pado = ado; /* user wants it */
9453 PR->primitive = SUMA_replace_string(
9454 PR->primitive,"voxel");
9455 PR->primitive_index = -1;
9456 PR->PickXYZ[0] = pinter[0];
9457 PR->PickXYZ[1] = pinter[1];
9458 PR->PickXYZ[2] = pinter[2];
9459 PR->ignore_same_datum = IgnoreSameNode;
9460 PR->datum_index = I1d;
9461 PR->iAltSel[SUMA_VOL_I] = I[0];
9462 PR->iAltSel[SUMA_VOL_J] = I[1];
9463 PR->iAltSel[SUMA_VOL_K] = I[2];
9464 PR->iAltSel[SUMA_VOL_IJK] = I1d;
9465 PR->iAltSel[SUMA_VOL_SLC_NUM] = rslc->slc_num;
9466 PR->iAltSel[SUMA_VOL_SLC_VARIANT] =
9467 (int)SUMA_SlcVariantToCode(rslc->variant);
9468 PR->dAltSel[SUMA_VOL_SLC_EQ0] = rslc->Eq[0];
9469 PR->dAltSel[SUMA_VOL_SLC_EQ1] = rslc->Eq[1];
9470 PR->dAltSel[SUMA_VOL_SLC_EQ2] = rslc->Eq[2];
9471 PR->dAltSel[SUMA_VOL_SLC_EQ3] = rslc->Eq[3];
9472 PR->dset_idcode_str = SUMA_replace_string(
9473 PR->dset_idcode_str, SDSET_ID(dset));
9474 if (!SUMA_Add_To_PickResult_List(sv, ado,
9475 "voxel", &PR)) {
9476 SUMA_S_Err("Failed to add selected ado");
9477 SUMA_RETURN(0);
9478 }
9479 Hit = 1;
9480 ++N_Hit;
9481 /* You could leave at the first hit IF:
9482 you only have one direction of slices in the
9483 entire stack, AND if they are properly
9484 ordered for rendering.
9485 Should speed be an issue you can check for
9486 this condition and bolt with the line below */
9487 /* goto GOT_IT; */
9488 }
9489 }
9490 ++ive;
9491 }
9492 }
9493 SUMA_LH("el now %p,\n"
9494 "tail = %p, N_Hit = %d",
9495 el, dlist_tail(VSaux->vrslcl), N_Hit);
9496 } while(el != dlist_tail(VSaux->vrslcl));
9497 }
9498 }
9499
9500
9501 GOT_IT:
9502 SUMA_RETURN(N_Hit);
9503 }/* determine intersection with 3D rendering of VO*/
9504
SUMA_Apply_PR_VO(SUMA_SurfaceViewer * sv,SUMA_VolumeObject * VO,SUMA_PICK_RESULT ** PRi)9505 int SUMA_Apply_PR_VO(SUMA_SurfaceViewer *sv, SUMA_VolumeObject *VO,
9506 SUMA_PICK_RESULT **PRi)
9507 {
9508 static char FuncName[]={"SUMA_Apply_PR_VO"};
9509 SUMA_ALL_DO *ado=NULL;
9510 int iv3[3], iv15[15];
9511 float fv15[15];
9512 DList *list = NULL;
9513 SUMA_Boolean NodeIgnored = NOPE;
9514 SUMA_PICK_RESULT *PR;
9515 SUMA_EngineData *ED = NULL;
9516 SUMA_DSET *dset=NULL;
9517 DListElmt *Location=NULL, *el=NULL, *SetNodeElem = NULL;
9518 SUMA_Boolean LocalHead = NOPE;
9519
9520 SUMA_ENTRY;
9521
9522 SUMA_LH("Here");
9523 if (!sv || !VO || !PRi || !*PRi) { SUMA_S_Err("Niente"); SUMA_RETURN(-1); }
9524
9525 /* Mark intersection Facsets */
9526 ado = (SUMA_ALL_DO *)VO;
9527
9528 PR = *PRi; /* Keep local copy */
9529 /* Store the PR in ado, hide it from return potential */
9530 SUMA_ADO_StorePickResult(ado, PRi);
9531
9532 if (!(dset = SUMA_FindDset_s(PR->dset_idcode_str, SUMAg_CF->DsetList))) {
9533 SUMA_S_Err("NULL dset?");
9534 SUMA_RETURN(0);
9535 }
9536
9537 sv->Focus_DO_ID = ADO_iDO(ado);
9538 SUMA_UpdateViewerTitle(sv);
9539
9540 /* if the surface controller is open, update it */
9541 if (SUMA_isADO_Cont_Realized(ado))
9542 SUMA_Init_SurfCont_SurfParam(ado);
9543
9544 fprintf(SUMA_STDOUT, "\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv\n");
9545 fprintf(SUMA_STDOUT, "Selected voxel RAI [%.3f %.3f %.3f]mm \n"
9546 " IJK [%ld %ld %ld] on volume %s.\n",
9547 PR->PickXYZ[0], PR->PickXYZ[1], PR->PickXYZ[2],
9548 PR->iAltSel[SUMA_VOL_I], PR->iAltSel[SUMA_VOL_J], PR->iAltSel[SUMA_VOL_K],
9549 SDSET_FILENAME(dset));
9550 fprintf(SUMA_STDOUT, "\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n");
9551
9552
9553 /* Set the voxel selection */
9554 if (!list) list = SUMA_CreateList();
9555 if (PR->ignore_same_datum &&
9556 SUMA_ADO_SelectedDatum(ado, NULL, NULL) == PR->datum_index) {
9557 SUMA_LHv("Ignoring identical voxel selection %d on volume %s\n",
9558 SUMA_ADO_SelectedDatum(ado, NULL, NULL), SUMA_ADO_Label(ado));
9559 NodeIgnored = YUP;
9560 } else {
9561 ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
9562 SetNodeElem = SUMA_RegisterEngineListCommand ( list, ED,
9563 SEF_i, (void*)&PR->datum_index,
9564 SES_Suma, (void *)sv, NOPE,
9565 SEI_Head, NULL);
9566 if (!SetNodeElem) {
9567 fprintf( SUMA_STDERR,
9568 "Error %s: Failed to register SetNodeElem\n", FuncName);
9569 SUMA_RETURN (-1);
9570 } else {
9571 SUMA_RegisterEngineListCommand ( list, ED,
9572 SEF_ngr, NULL,
9573 SES_Suma, (void *)sv, NOPE,
9574 SEI_In, SetNodeElem);
9575 }
9576
9577 iv15[SUMA_VOL_I] = (int)PR->iAltSel[SUMA_VOL_I];
9578 iv15[SUMA_VOL_J] = (int)PR->iAltSel[SUMA_VOL_J];
9579 iv15[SUMA_VOL_K] = (int)PR->iAltSel[SUMA_VOL_K];
9580 iv15[SUMA_VOL_IJK] = (int)PR->iAltSel[SUMA_VOL_IJK];
9581
9582 fv15[SUMA_VOL_SLC_EQ0] = (float)PR->dAltSel[SUMA_VOL_SLC_EQ0];
9583 fv15[SUMA_VOL_SLC_EQ1] = (float)PR->dAltSel[SUMA_VOL_SLC_EQ1];
9584 fv15[SUMA_VOL_SLC_EQ2] = (float)PR->dAltSel[SUMA_VOL_SLC_EQ2];
9585 fv15[SUMA_VOL_SLC_EQ3] = (float)PR->dAltSel[SUMA_VOL_SLC_EQ3];
9586
9587 SUMA_RegisterEngineListCommand ( list, ED,
9588 SEF_iv15, (void *)iv15,
9589 SES_Suma, (void *)sv, NOPE,
9590 SEI_In, SetNodeElem);
9591 SUMA_RegisterEngineListCommand ( list, ED,
9592 SEF_fv15, (void *)fv15,
9593 SES_Suma, (void *)sv, NOPE,
9594 SEI_In, SetNodeElem);
9595 }
9596
9597
9598 /* Now set the cross hair position at the selected node*/
9599 if (!list) list = SUMA_CreateList();
9600 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
9601 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
9602 SEF_fv3, (void*)PR->PickXYZ,
9603 SES_Suma, (void *)sv, NOPE,
9604 SEI_Head, NULL))) {
9605 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9606 SUMA_RETURN(-1);
9607 }
9608 /* and add the object with this location */
9609 SUMA_RegisterEngineListCommand ( list, ED,
9610 SEF_vp, (void *)dset,
9611 SES_Suma, (void *)sv, NOPE,
9612 SEI_In, Location);
9613
9614 /* attach the cross hair to the selected object
9615 Note that binding here is to voxel of dset */
9616 iv3[0] = ADO_iDO(ado);
9617 iv3[1] = PR->iAltSel[SUMA_VOL_IJK];
9618 iv3[2] = -1;
9619
9620 ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
9621 if (!SUMA_RegisterEngineListCommand ( list, ED,
9622 SEF_iv3, (void*)iv3,
9623 SES_Suma, (void *)sv, NOPE,
9624 SEI_Head, NULL)) {
9625 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9626 SUMA_RETURN(-1);
9627 }
9628
9629 /* call with the list */
9630 if (!SUMA_Engine (&list)) {
9631 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
9632 SUMA_RETURN(-1);
9633 }
9634
9635 /* check to see if AFNI needs to be notified */
9636 if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] &&
9637 sv->LinkAfniCrossHair) {
9638 int it;
9639 SUMA_LH("Notifying Afni of CrossHair XYZ");
9640 /* register a call to SetAfniCrossHair */
9641 if (!list) list = SUMA_CreateList();
9642 it = SUMA_ShftCont_Event(PR->evr);
9643 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
9644 if (!SUMA_RegisterEngineListCommand ( list, ED,
9645 SEF_i, (void*)&it,
9646 SES_Suma, (void *)sv, NOPE,
9647 SEI_Tail, NULL)) {
9648 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
9649 SUMA_RETURN (-1);
9650 }
9651 if (MASK_MANIP_MODE(sv) && SUMAg_CF->Dev) {
9652 SUMA_ALL_DO *ado = SUMA_whichADOg(sv->MouseMode_ado_idcode_str);
9653 DListElmt *Location=NULL;
9654 if (ado && ado->do_type == MASK_type) {
9655 SUMA_MaskDO *mdo = (SUMA_MaskDO *)ado;
9656 ED = SUMA_InitializeEngineListData (SE_SetAfniMask);
9657 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
9658 SEF_fv3, (void*)mdo->cen,
9659 SES_Suma, (void *)sv, NOPE,
9660 SEI_Tail, NULL))) {
9661 SUMA_S_Err("Failed to register element\n");
9662 SUMA_RETURN (-1);
9663 }
9664 SUMA_RegisterEngineListCommand ( list, ED,
9665 SEF_s, (void *)(ADO_ID(ado)),
9666 SES_Suma, (void *)sv, NOPE,
9667 SEI_In, Location);
9668 }
9669 }
9670 if (!SUMA_Engine (&list)) {
9671 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
9672 SUMA_RETURN(-1);
9673 }
9674 }
9675
9676 SUMA_RETURN(1);
9677 }
9678
9679 /*!
9680 \brief Show the contents of a brush stroke
9681 SUMA_ShowBrushStroke (sv, Out);
9682
9683 */
SUMA_ShowBrushStroke(SUMA_SurfaceViewer * sv,FILE * out)9684 void SUMA_ShowBrushStroke (SUMA_SurfaceViewer *sv, FILE *out)
9685 {
9686 static char FuncName[]={"SUMA_ShowBrushStroke"};
9687 int i, k, N=0;
9688 SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
9689 DListElmt *Next_Elm = NULL;
9690
9691 SUMA_ENTRY;
9692
9693 if (!out) out = SUMA_STDERR;
9694
9695 if (!sv->BS) {
9696 fprintf(out, "%s: NULL sv->BS\n", FuncName);
9697 SUMA_RETURNe;
9698 }
9699
9700 N = dlist_size(sv->BS);
9701 if (!N) {
9702 fprintf(out, "%s: Empty sv->BS. (N = 0)\n", FuncName);
9703 SUMA_RETURNe;
9704 }
9705
9706 fprintf(out, "%s: Brush stroke has %d elements:\n", FuncName, N);
9707
9708 i = 0;
9709 do {
9710 if (Next_Elm==NULL) Next_Elm = dlist_head(sv->BS);
9711 else Next_Elm = Next_Elm->next;
9712 if (!Next_Elm->data) {
9713 fprintf(out, "%s: Element->data %d is NULL!\n", FuncName, i);
9714 }else {
9715 bsd = (SUMA_BRUSH_STROKE_DATUM *)Next_Elm->data;
9716 fprintf(out, "%d: (%f %f) [%.2f, %.2f, %.2f <--> %.2f, %.2f, %.2f]\t Node %d, Tri %d\n",
9717 i, bsd->x, bsd->y,
9718 bsd->NP[0], bsd->NP[1], bsd->NP[2],
9719 bsd->FP[0], bsd->FP[1], bsd->FP[2],
9720 bsd->SurfNode, bsd->SurfTri);
9721 }
9722 ++i;
9723 }while (dlist_tail(sv->BS) != Next_Elm);
9724
9725 fprintf(out, "\n");
9726
9727 SUMA_RETURNe;
9728 }
9729
9730 /*!
9731 \brief Clear the contents of sv->BS and sets it to NULL
9732
9733 SUMA_ClearBrushStroke (sv);
9734
9735
9736 \sa SUMA_CreateBrushStroke
9737 */
SUMA_ClearBrushStroke(SUMA_SurfaceViewer * sv)9738 void SUMA_ClearBrushStroke (SUMA_SurfaceViewer *sv)
9739 {
9740 static char FuncName[]={"SUMA_ClearBrushStroke"};
9741
9742 SUMA_ENTRY;
9743
9744 /* THE NEW VERSION */
9745 if (sv->BS) {
9746 SUMA_EmptyDestroyList(sv->BS);
9747 sv->BS = NULL;
9748 }
9749
9750 SUMA_RETURNe;
9751 }
9752 /*!
9753 \brief Creates the BrushStroke structure inside sv structure
9754 success = SUMA_CreateBrushStroke (sv);
9755
9756 \param sv (SUMA_SurfaceViewer *) Surface viewer structure
9757 \return YUP/NOPE
9758
9759 sv->BS must be null before this function is called.
9760 The liat and its components are then allocated for.
9761
9762 \sa SUMA_ClearBrushStroke
9763 */
SUMA_CreateBrushStroke(SUMA_SurfaceViewer * sv)9764 SUMA_Boolean SUMA_CreateBrushStroke (SUMA_SurfaceViewer *sv)
9765 {
9766 static char FuncName[]={"SUMA_CreateBrushStroke"};
9767
9768 SUMA_ENTRY;
9769
9770 /* New Version */
9771 if (sv->BS) { /* bad news, this should be NULL to begin with */
9772 SUMA_RegisterMessage (SUMAg_CF->MessageList,
9773 "Brush Stroke not NULL.", FuncName,
9774 SMT_Critical, SMA_LogAndPopup);
9775 SUMA_RETURN(NOPE);
9776
9777 }
9778 sv->BS = (DList *)SUMA_calloc(1,sizeof(DList));
9779 dlist_init(sv->BS, SUMA_FreeBSDatum);
9780
9781 SUMA_RETURN (YUP);
9782 }
9783
SUMA_CreateBSDatum(void)9784 SUMA_BRUSH_STROKE_DATUM * SUMA_CreateBSDatum(void)
9785 {
9786 static char FuncName[]={"SUMA_CreateBSDatum"};
9787 SUMA_BRUSH_STROKE_DATUM *bsd = NULL;
9788
9789 SUMA_ENTRY;
9790
9791 bsd = (SUMA_BRUSH_STROKE_DATUM *)
9792 SUMA_calloc(1,sizeof(SUMA_BRUSH_STROKE_DATUM));
9793 if (!bsd) {
9794 SUMA_RegisterMessage (SUMAg_CF->MessageList,
9795 "Failed to allocate.", FuncName,
9796 SMT_Critical, SMA_LogAndPopup);
9797 SUMA_RETURN(NULL);
9798 }
9799 /* setup defaults */
9800 bsd->x = bsd->y = 0.0;
9801 bsd->NP[0] = bsd->NP[1] = bsd->NP[2] = 0.0;
9802 bsd->FP[0] = bsd->FP[1] = bsd->FP[2] = 0.0;
9803 bsd->SurfNode = -1;
9804 bsd->SurfTri = -1;
9805 bsd->Decimated = NOPE;
9806
9807 SUMA_RETURN(bsd);
9808 }
9809
9810 /*!
9811 \brief free a brush stroke datum that is contained inside the doubly linked BS
9812 */
SUMA_FreeBSDatum(void * bsd)9813 void SUMA_FreeBSDatum (void *bsd)
9814 {
9815 static char FuncName[]={"SUMA_FreeBSDatum"};
9816
9817 SUMA_ENTRY;
9818
9819 /* nothing is allocated for inside bsd */
9820 if (bsd) SUMA_free(bsd);
9821
9822 SUMA_RETURNe;
9823 }
9824
9825
9826
9827 /*!
9828 \brief Adds, new point to the brush stroke
9829 success = SUMA_AddToBrushStroke ( sv, x, y, Show);
9830
9831 \param sv (SUMA_SurfaceViewer *) pointer to surface viewer where stroke is occuring
9832 \param x (int) X coordinate of mouse
9833 \param y (int) Y coordinate of mouse
9834 \param NP (GLdouble *) vector of XYZ coordinates of Near Plane intersection point
9835 \param FP (GLdouble *) vector of XYZ coordinates of Far Plane intersection point.
9836 \param Show (SUMA_Boolean) if YUP: Then trace is drawn as you move the mouse
9837 \return YUP/NOPE, success indicator
9838
9839 */
SUMA_AddToBrushStroke(SUMA_SurfaceViewer * sv,int x,int y,GLdouble * NP,GLdouble * FP,SUMA_Boolean Show)9840 SUMA_Boolean SUMA_AddToBrushStroke (SUMA_SurfaceViewer *sv, int x, int y, GLdouble *NP, GLdouble *FP, SUMA_Boolean Show)
9841 {
9842 static char FuncName[]={"SUMA_AddToBrushStroke"};
9843 int ip;
9844 SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
9845
9846 SUMA_ENTRY;
9847
9848 /* New version */
9849 bsd = SUMA_CreateBSDatum();
9850 bsd->x = (float)x;
9851 bsd->y = (float)y;
9852 bsd->NP[0] = NP[0]; bsd->NP[1] = NP[1]; bsd->NP[2] = NP[2];
9853 bsd->FP[0] = FP[0]; bsd->FP[1] = FP[1]; bsd->FP[2] = FP[2];
9854 dlist_ins_next (sv->BS, dlist_tail(sv->BS), (void*)bsd);
9855
9856 /* incremental draw */
9857 if (Show) SUMA_DrawBrushStroke (sv, YUP);
9858
9859 SUMA_RETURN (YUP);
9860 }
9861
9862 /*!
9863 Sets the foreground color of the drawing area
9864 */
SUMA_SetSVForegroundColor(SUMA_SurfaceViewer * sv,const char * Color)9865 void SUMA_SetSVForegroundColor (SUMA_SurfaceViewer *sv, const char *Color)
9866 {
9867 static char FuncName[]={"SUMA_SetSVForegroundColor"};
9868 XColor col, unused;
9869
9870 SUMA_ENTRY;
9871
9872 #ifdef DARWIN
9873 SUMA_S_Warn("Calling this function from OS X seems to cause trouble");
9874 #endif
9875
9876 /* using sv->X->CMAP instead of
9877 DefaultColormapOfScreen(XtScreen(sv->X->GLXAREA))
9878 is useless */
9879 if (!XAllocNamedColor (sv->X->DPY,
9880 DefaultColormapOfScreen(XtScreen(sv->X->GLXAREA)),
9881 Color, &col, &unused)) {
9882 fprintf (SUMA_STDERR,
9883 "Error %s: Can't allocate for %s color.\n", FuncName, Color);
9884 SUMA_RETURNe;
9885 }
9886 XSetForeground (sv->X->DPY, sv->X->gc, col.pixel);
9887
9888 SUMA_RETURNe;
9889 }
9890
9891 /*!
9892 \brief Draws the brushstroke
9893
9894 \param sv (SUMA_SurfaceViewer *) pointer to surface viewer structure
9895 \param incremental (SUMA_Boolean) YUP: draw a line between the last two points
9896 NOPE: draw the whole thing
9897
9898 - NB: This function used to crash when run on SGI if display is not
9899 in TrueColor mode.
9900 This happens even though the visual chosen by SUMA does not change.
9901 To put the SGI in true color mode, you need to add to /var/X11/xdm/Xservers
9902 the following: -class TrueColor -depth 24
9903 and then restart X or the system.
9904 The bug was that the graphics context (sv->X->gc) was created using the
9905 Screen's root window and not the GLX visual's window.
9906 */
SUMA_DrawBrushStroke(SUMA_SurfaceViewer * sv,SUMA_Boolean incr)9907 void SUMA_DrawBrushStroke (SUMA_SurfaceViewer *sv, SUMA_Boolean incr)
9908 {
9909 static char FuncName[]={"SUMA_DrawBrushStroke"};
9910 int i, N;
9911 DListElmt *NE=NULL, *NEn=NULL;
9912 SUMA_BRUSH_STROKE_DATUM *bsd=NULL, *bsdn = NULL;
9913
9914 SUMA_ENTRY;
9915
9916 if (!sv->BS) SUMA_RETURNe;
9917
9918 N = dlist_size(sv->BS);
9919 if (N < 2) SUMA_RETURNe;
9920
9921 if (!incr) {
9922 do {
9923 if (!NE) NE = dlist_head(sv->BS);
9924 else NE = NE->next;
9925
9926 NEn = NE->next;
9927
9928 bsd = (SUMA_BRUSH_STROKE_DATUM *)NE->data;
9929 bsdn = (SUMA_BRUSH_STROKE_DATUM *)NEn->data;
9930
9931 SUMA_DrawWindowLine( sv, (int)bsd->x, (int)bsd->y,
9932 (int)bsdn->x, (int)bsdn->y, 1);
9933 } while (NEn != dlist_tail(sv->BS));
9934
9935 } else {
9936 NEn = dlist_tail(sv->BS);
9937 NE = NEn->prev;
9938
9939 bsd = (SUMA_BRUSH_STROKE_DATUM *)NE->data;
9940 bsdn = (SUMA_BRUSH_STROKE_DATUM *)NEn->data;
9941
9942 SUMA_DrawWindowLine( sv,
9943 (int)bsd->x, (int)bsd->y,
9944 (int)bsdn->x, (int)bsdn->y, 1 );
9945
9946 }
9947 SUMA_RETURNe;
9948
9949 }
9950
9951 /*!
9952 \brief Processes the brushstroke sent from a viewer
9953
9954 */
SUMA_ProcessBrushStroke(SUMA_SurfaceViewer * sv,SUMA_BRUSH_STROKE_ACTION BsA)9955 SUMA_DRAWN_ROI * SUMA_ProcessBrushStroke
9956 (SUMA_SurfaceViewer *sv, SUMA_BRUSH_STROKE_ACTION BsA)
9957 {
9958 static char FuncName[]={"SUMA_ProcessBrushStroke"};
9959 SUMA_DRAWN_ROI *DrawnROI = NULL;
9960 SUMA_ROI_DATUM *ROIstroke = NULL, *ROIlink=NULL, *ROIfill=NULL;
9961 SUMA_SurfaceObject *SO = NULL;
9962 int ii=0, TailNode = -1, FirstSurfNode = -1, ft = -1, N_SurfNode = 0;
9963 int HeadNode = -1, *ROI_Mask=NULL, N_ROI_Mask = 0;
9964 DListElmt *El = NULL;
9965 SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
9966 char *sbuf;
9967 SUMA_ROI_ACTION_STRUCT *ROIA;
9968 DListElmt *tmpStackPos=NULL;
9969 SUMA_Boolean Shaded = NOPE, LocalHead = NOPE;
9970
9971 SUMA_ENTRY;
9972
9973 SO = SUMA_SV_Focus_SO(sv);
9974
9975 if (!SO) {
9976 fprintf (SUMA_STDERR,
9977 "%s: No surface object in focus, nothing to do.\n", FuncName);
9978 SUMA_RETURN (DrawnROI);
9979 }
9980
9981 if (!sv->BS) {
9982 fprintf (SUMA_STDERR,
9983 "%s: No Brushstroke (BS), nothing to do.\n", FuncName);
9984 SUMA_RETURN (DrawnROI);
9985 }
9986
9987 if (!SUMAg_CF->ROI_mode) {
9988 fprintf (SUMA_STDERR, "%s: Not in ROI mode, nothing to do.\n", FuncName);
9989 SUMA_RETURN (DrawnROI);
9990 }
9991
9992 /* We are in ROI mode,
9993 is there an ROI in curDrawnROI that works with the current surface ? */
9994 if (SUMAg_CF->X->DrawROI->curDrawnROI) {
9995 if ( SUMA_isdROIrelated(SUMAg_CF->X->DrawROI->curDrawnROI,
9996 (SUMA_ALL_DO *)SO) &&
9997 SUMAg_CF->X->DrawROI->curDrawnROI->DrawStatus != SUMA_ROI_Finished){
9998 if (LocalHead)
9999 fprintf (SUMA_STDERR,"%s: using currDrawnROI.\n", FuncName);
10000 DrawnROI = SUMAg_CF->X->DrawROI->curDrawnROI;
10001 }else {
10002 if (LocalHead)
10003 fprintf (SUMA_STDERR,
10004 "%s: No match between currDrawnROI and SO.\n", FuncName);
10005 DrawnROI = NULL;
10006 }
10007 }
10008 if (!DrawnROI) { /* try some more */
10009 if ((DrawnROI = SUMA_FetchROI_InCreation (SO, SUMAg_DOv, SUMAg_N_DOv))){
10010 if (LocalHead)
10011 fprintf (SUMA_STDERR,"%s: using ROI in creation.\n", FuncName);
10012 /* There is an ROI being created on this surface,
10013 initialize DrawROI window*/
10014 SUMA_InitializeDrawROIWindow(DrawnROI);
10015 } else {
10016 /* wait till later */
10017 if (LocalHead)
10018 fprintf (SUMA_STDERR,"%s: will create a new ROI.\n", FuncName);
10019 }
10020 }
10021
10022 if (!DrawnROI && BsA == SUMA_BSA_JoinEnds) {
10023 SUMA_SLP_Err ("NO ROI to close.");
10024 SUMA_RETURN (DrawnROI);
10025 }
10026
10027 if (!DrawnROI) { /* No ROI found, create one */
10028 if (LocalHead)
10029 fprintf (SUMA_STDERR,
10030 "%s: No ROI found, creating a new one.\n", FuncName);
10031 SUMA_GET_TEXT_FIELD(SUMAg_CF->X->DrawROI->ROIlbl->textfield, sbuf);
10032 DrawnROI = SUMA_AllocateDrawnROI (SO->idcode_str, SUMA_ROI_InCreation,
10033 SUMA_ROI_OpenPath,
10034 sbuf,
10035 SUMAg_CF->X->DrawROI->ROIval->value);
10036 if (!DrawnROI) {
10037 SUMA_RegisterMessage (SUMAg_CF->MessageList,
10038 "Failed to allocate for DrawnROI.", FuncName,
10039 SMT_Critical, SMA_LogAndPopup);
10040 SUMA_RETURN (NULL);
10041 }
10042
10043 /* Although ROIs are stored as DOs,
10044 they are dependent on the surfaces they are related to
10045 ROIs at this stage are node indices only (and perhaps the mesh) but the coordinates of the indices
10046 come from the surface onto which they are displayed. So when you are
10047 drawing a surface, using CreateMesh,
10048 you will search DOv for ROIs related to the surface displayed and
10049 overlay them accordingly */
10050 /* Add the ROI to DO */
10051 if (!SUMA_AddDO ( SUMAg_DOv, &SUMAg_N_DOv,
10052 (void *)DrawnROI, ROIdO_type, SUMA_WORLD)) {
10053 fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AddDO.\n", FuncName);
10054 }
10055
10056 /* is the Switch ROI window open ? */
10057 SUMA_IS_DRAW_ROI_SWITCH_ROI_SHADED(Shaded);
10058 if (!Shaded) {
10059 SUMA_cb_DrawROI_SwitchROI (
10060 NULL,
10061 (XtPointer) SUMAg_CF->X->DrawROI->SwitchROIlst,
10062 NULL);
10063 }
10064
10065
10066 } else {
10067 if (LocalHead)
10068 fprintf( SUMA_STDOUT,
10069 "%s: ROI %p fetched. Status %d.\n",
10070 FuncName, DrawnROI, DrawnROI->DrawStatus);
10071 }
10072
10073 if (BsA == SUMA_BSA_AppendStrokeOrFill) {
10074 if ( DrawnROI->Type == SUMA_ROI_ClosedPath ||
10075 DrawnROI->Type == SUMA_ROI_FilledArea)
10076 BsA = SUMA_BSA_FillArea;
10077 else if (DrawnROI->Type == SUMA_ROI_OpenPath)
10078 BsA = SUMA_BSA_AppendStroke;
10079 }
10080 if ( DrawnROI->Type == SUMA_ROI_ClosedPath &&
10081 BsA != SUMA_BSA_FillArea) {
10082 SUMA_SLP_Err ( "You can only fill a closed path.\n"
10083 "You cannot append more paths to it.");
10084 SUMA_RETURN (DrawnROI);
10085 }
10086 if ( DrawnROI->Type == SUMA_ROI_FilledArea &&
10087 BsA != SUMA_BSA_FillArea) {
10088 SUMA_SLP_Err ("You cannot add paths to a filled ROI.");
10089 SUMA_RETURN (DrawnROI);
10090 }
10091
10092 /* Good, now initialize the DrawROI widget, if needed */
10093 if (SUMAg_CF->X->DrawROI->curDrawnROI != DrawnROI) {
10094 if (!SUMA_InitializeDrawROIWindow (DrawnROI)) {
10095 SUMA_SL_Err("Failed to initialize DrawWindow.");
10096 }
10097 }
10098
10099 /* Now you must transform the brushstroke to a series of nodes
10100 (not necessarily connected)*/
10101 if (LocalHead)
10102 fprintf (SUMA_STDERR,
10103 "%s: Turning BrushStroke to NodeStroke ...\n", FuncName);
10104 if (!SUMA_BrushStrokeToNodeStroke (sv)) {
10105 SUMA_RegisterMessage (SUMAg_CF->MessageList,
10106 "Failed in SUMA_BrushStrokeToNodeStroke.", FuncName,
10107 SMT_Error, SMA_LogAndPopup);
10108 SUMA_RETURN(NULL);
10109 }
10110
10111 switch (BsA) {
10112 case SUMA_BSA_AppendStroke:
10113 /* Turn the brush stroke into a series of connected nodes */
10114 if (LocalHead)
10115 fprintf (SUMA_STDERR,
10116 "%s: Turning NodeStroke to ROIStroke ...\n", FuncName);
10117 if (!(ROIstroke = SUMA_NodeStrokeToConnectedNodes (sv))) {
10118 SUMA_RegisterMessage (SUMAg_CF->MessageList,
10119 "Failed in SUMA_NodeStrokeToConnectedNodes.",
10120 FuncName,
10121 SMT_Critical, SMA_LogAndPopup);
10122 if (ROIlink) SUMA_FreeROIDatum((void *)ROIlink);
10123 ROIlink = NULL;
10124 if (ROIstroke) SUMA_FreeROIDatum((void *)ROIstroke);
10125 ROIstroke = NULL;
10126 SUMA_RETURN(NULL);
10127 }
10128
10129 if (LocalHead)
10130 fprintf (SUMA_STDERR,
10131 "%s: Turning NodeStroke to ROIStroke . DONE.\n",
10132 FuncName);
10133 /* if this is the first element of ROI,
10134 create the first ROIdatum and get out */
10135 if (dlist_size(DrawnROI->ROIstrokelist)) {
10136 /* Not the beginning of an ROI */
10137 if (LocalHead)
10138 fprintf (SUMA_STDERR,
10139 "%s: Adding ROIstroke to previous ones ...\n",
10140 FuncName);
10141 /* make sure new brushstroke is not just one node that is
10142 the tail of the ROI*/
10143 SUMA_DRAWN_ROI_TAIL_NODE(DrawnROI,TailNode);
10144
10145 SUMA_BS_FIRST_SURF_NODE(sv->BS, FirstSurfNode, ft, El);
10146 SUMA_BS_COUNT_SURF_NODES(sv->BS, N_SurfNode);
10147 if (FirstSurfNode == TailNode && N_SurfNode == 1) {
10148 /* nothing to do here */
10149 fprintf (SUMA_STDERR,
10150 "%s: New stroke has one node that is \n"
10151 "identical to tail node. Dumping element.\n", FuncName);
10152 SUMA_RETURN(DrawnROI);
10153 }
10154
10155 /* Connect this chunk to the last open Node in ROI */
10156 if (FirstSurfNode != TailNode) {
10157 if (LocalHead)
10158 fprintf (SUMA_STDERR,
10159 "%s: linking Tail Node to New stroke.\n", FuncName);
10160
10161 ROIlink = SUMA_LinkTailNodeToNodeStroke (sv, DrawnROI);
10162 if (!ROIlink) {
10163 SUMA_SL_Err("Failed to connect Tail node to Node stroke\n"
10164 ", try again.");
10165 SUMA_RETURN(NULL);
10166 }
10167 if (LocalHead) {
10168 fprintf (SUMA_STDERR,
10169 "%s: RIOlink, before prepending:\n", FuncName);
10170 SUMA_ShowDrawnROIDatum (ROIlink, NULL, NOPE);
10171 }
10172
10173 /* connect the ROIlink with the ROIstroke */
10174 if (LocalHead) {
10175 fprintf (SUMA_STDERR,
10176 "%s: RIOstroke, before prepending:\n", FuncName);
10177 SUMA_ShowDrawnROIDatum (ROIstroke, NULL, NOPE);
10178 }
10179 if (!SUMA_PrependToROIdatum (ROIlink, ROIstroke)) {
10180 SUMA_RegisterMessage (SUMAg_CF->MessageList,
10181 "Failed to merge ROIs.", FuncName,
10182 SMT_Critical, SMA_LogAndPopup);
10183 if (ROIlink) SUMA_FreeROIDatum((void *)ROIlink);
10184 ROIlink = NULL;
10185 if (ROIstroke) SUMA_FreeROIDatum((void *)ROIstroke);
10186 ROIstroke = NULL;
10187 SUMA_RETURN(NULL);
10188 }
10189
10190 if (LocalHead) {
10191 fprintf (SUMA_STDERR,
10192 "%s: RIOstroke, after prepending:\n", FuncName);
10193 SUMA_ShowDrawnROIDatum (ROIstroke, NULL, NOPE);
10194 }
10195 /* now free ROIlink, not needed anymore */
10196 if (ROIlink) SUMA_FreeROIDatum ((void *)ROIlink); ROIlink = NULL;
10197 }
10198 }else{
10199 if (LocalHead)
10200 fprintf (SUMA_STDERR, "%s: First ROIStroke of ROI.\n", FuncName);
10201 }
10202 break;
10203 case SUMA_BSA_JoinEnds:
10204 /* Join ends here */
10205 if (DrawnROI) { /* close ROI */
10206 SUMA_DRAWN_ROI_HEAD_NODE(DrawnROI,HeadNode);
10207 SUMA_BS_FIRST_SURF_NODE(sv->BS, FirstSurfNode, ft, El);
10208 bsd = (SUMA_BRUSH_STROKE_DATUM *)El->data;
10209 if (LocalHead)
10210 fprintf( SUMA_STDERR,
10211 "%s: Trying to join node %d to node %d.\n",
10212 FuncName, FirstSurfNode, HeadNode);
10213 /* Now compute the intersection of the surface with the plane */
10214 ROIstroke = SUMA_Surf_Plane_Intersect_ROI ( SO, FirstSurfNode,
10215 HeadNode, bsd->NP);
10216
10217 if (!ROIstroke) {
10218 SUMA_SL_Err ("Failed to close path. Repeat new stroke.");
10219 SUMA_RETURN(DrawnROI);
10220 }
10221 /* what is the last node of ROIstroke ?
10222 It is possible that the returned ROIstroke
10223 was not a successful closure (a partial success), investigate*/
10224 if (LocalHead)
10225 fprintf( SUMA_STDERR,
10226 "%s: Last node of ROIstroke is %d\n",
10227 FuncName, ROIstroke->nPath[ROIstroke->N_n-1]);
10228 if (ROIstroke->nPath[ROIstroke->N_n-1] != HeadNode) {
10229 /* pretend this is not a JoinEnds exercice */
10230 BsA = SUMA_BSA_AppendStroke;
10231 SUMA_SL_Err ("Failed to close path. Continue with stroke.");
10232 SUMA_RETURN(DrawnROI);
10233 }else {
10234 /* Do not remove the last point from ROIstroke,
10235 otherwise it will make drawing a closed ROI painful */
10236 }
10237 } else {
10238 /* tremors, nothing to do */
10239 }
10240 break;
10241 case SUMA_BSA_FillArea:
10242 SUMA_BS_FIRST_SURF_NODE(sv->BS, FirstSurfNode, ft, El);
10243 if (LocalHead)
10244 fprintf (SUMA_STDERR,
10245 "%s: Should be filling from node %d\n",
10246 FuncName, FirstSurfNode);
10247
10248 /* create the mask from ROIs on this surface */
10249 switch (SUMAg_CF->ROI_FillMode) {
10250 case SUMA_ROI_FILL_TO_ALLROI:
10251 ROI_Mask = SUMA_Build_Mask_AllROI ( SUMAg_DOv, SUMAg_N_DOv,
10252 SO, NULL, &N_ROI_Mask);
10253 break;
10254 case SUMA_ROI_FILL_TO_THISROI:
10255 ROI_Mask = (int *)SUMA_calloc (SO->N_Node, sizeof(int));
10256 if (!ROI_Mask) {
10257 SUMA_SLP_Crit("Failed to allocate");
10258 SUMA_RETURN(DrawnROI);
10259 }
10260 SUMA_Build_Mask_DrawnROI (DrawnROI, ROI_Mask);
10261 break;
10262 default:
10263 SUMA_SLP_Err("No such mode.");
10264 SUMA_RETURN(DrawnROI);
10265 break;
10266 }
10267
10268 /* Now fill it up */
10269 ROIfill = SUMA_FillToMask (SO, ROI_Mask, FirstSurfNode);
10270 if (ROI_Mask) SUMA_free(ROI_Mask); ROI_Mask = NULL;
10271 if (!ROIfill) {
10272 SUMA_SLP_Err( "Failed to fill area:\n"
10273 "Perhaps seed on edge\nor nothing to fill.");
10274 SUMA_RETURN(DrawnROI);
10275 }
10276
10277 break;
10278 default:
10279 fprintf (SUMA_STDERR,
10280 "Error %s: Why are you doing this to me ?.\n", FuncName);
10281 break;
10282 }
10283
10284
10285 /* Another switch on BsA,
10286 it is possible that its value changed within this function */
10287
10288 switch (BsA) {
10289 case SUMA_BSA_AppendStroke:
10290 /* store the action */
10291 ROIstroke->action = SUMA_BSA_AppendStroke;
10292 /*now add the ROIdatum to the list of ROIs */
10293 if (LocalHead)
10294 fprintf (SUMA_STDERR,
10295 "%s: Adding ROIStroke to DrawnROI->ROIstrokelist\n",
10296 FuncName);
10297 ROIA = (SUMA_ROI_ACTION_STRUCT *)
10298 SUMA_calloc(1,sizeof(SUMA_ROI_ACTION_STRUCT));
10299 /* this structure is freed in SUMA_DestroyROIActionData */
10300 ROIA->DrawnROI = DrawnROI;
10301 ROIA->ROId = ROIstroke;
10302 tmpStackPos = SUMA_PushActionStack (
10303 DrawnROI->ActionStack,
10304 DrawnROI->StackPos, SUMA_AddToTailROIDatum,
10305 (void *)ROIA, SUMA_DestroyROIActionData);
10306 if (tmpStackPos) DrawnROI->StackPos = tmpStackPos;
10307 else {
10308 fprintf (SUMA_STDERR,
10309 "Error %s: Failed in SUMA_PushActionStack.\n", FuncName);
10310 SUMA_RETURN (DrawnROI);
10311 }
10312 if ( SUMAg_CF->X->DrawROI->WhatDist == SW_DrawROI_WhatDistTrace ||
10313 SUMAg_CF->X->DrawROI->WhatDist == SW_DrawROI_WhatDistAll)
10314 SUMA_ReportDrawnROIDatumLength( SO, ROIA->ROId, NULL,
10315 SUMAg_CF->X->DrawROI->WhatDist);
10316 break;
10317 case SUMA_BSA_JoinEnds:
10318 /* store the action */
10319 ROIstroke->action = SUMA_BSA_JoinEnds;
10320 if (LocalHead) fprintf (SUMA_STDERR, "%s: Closing path.\n", FuncName);
10321 ROIA = (SUMA_ROI_ACTION_STRUCT *)
10322 SUMA_calloc(1,sizeof(SUMA_ROI_ACTION_STRUCT));
10323 /* this structure is freed in SUMA_DestroyROIActionData */
10324 ROIA->DrawnROI = DrawnROI;
10325 ROIA->ROId = ROIstroke;
10326 tmpStackPos = SUMA_PushActionStack (
10327 DrawnROI->ActionStack, DrawnROI->StackPos,
10328 SUMA_AddToTailJunctionROIDatum,
10329 (void *)ROIA, SUMA_DestroyROIActionData);
10330 if (tmpStackPos) DrawnROI->StackPos = tmpStackPos;
10331 else {
10332 fprintf (SUMA_STDERR,
10333 "Error %s: Failed in SUMA_PushActionStack.\n", FuncName);
10334 SUMA_RETURN (DrawnROI);
10335 }
10336 if ( SUMAg_CF->X->DrawROI->WhatDist == SW_DrawROI_WhatDistTrace ||
10337 SUMAg_CF->X->DrawROI->WhatDist == SW_DrawROI_WhatDistAll)
10338 SUMA_ReportDrawnROIDatumLength( SO, ROIA->ROId, NULL,
10339 SUMAg_CF->X->DrawROI->WhatDist);
10340 break;
10341 case SUMA_BSA_FillArea:
10342 /* store the action */
10343 ROIfill->action = SUMA_BSA_FillArea;
10344 /* Now add ROIdatum to stack */
10345 ROIA = (SUMA_ROI_ACTION_STRUCT *)
10346 SUMA_calloc(1,sizeof(SUMA_ROI_ACTION_STRUCT));
10347 /* this structure is freed in SUMA_DestroyROIActionData */
10348 ROIA->DrawnROI = DrawnROI;
10349 ROIA->ROId = ROIfill;
10350 tmpStackPos = SUMA_PushActionStack (
10351 DrawnROI->ActionStack, DrawnROI->StackPos,
10352 SUMA_AddFillROIDatum,
10353 (void *)ROIA, SUMA_DestroyROIActionData);
10354 if (tmpStackPos) DrawnROI->StackPos = tmpStackPos;
10355 else {
10356 fprintf (SUMA_STDERR,
10357 "Error %s: Failed in SUMA_PushActionStack.\n", FuncName);
10358 SUMA_RETURN (DrawnROI);
10359 }
10360 break;
10361 default:
10362 fprintf (SUMA_STDERR,
10363 "Error %s: Why are you doing this to me ??.\n", FuncName);
10364 break;
10365 }
10366
10367 /* Now update the Paint job on the ROI plane */
10368 if (!SUMA_Paint_SO_ROIplanes_w (SO, SUMAg_DOv, SUMAg_N_DOv)) {
10369 SUMA_SLP_Err("Failed in SUMA_Paint_SO_ROIplanes_w.");
10370 SUMA_RETURN(DrawnROI);
10371 }
10372 if (BsA == SUMA_BSA_FillArea) { /* ZSS Sept 29 06 */
10373 SUMA_OVERLAYS *Overlay=NULL;
10374 int junk;
10375 /* If you're drawing, and have just filled an area,
10376 better pop the dset to the top so it is visible */
10377 if (!(Overlay = SUMA_Fetch_OverlayPointer((SUMA_ALL_DO *)SO,
10378 DrawnROI->ColPlaneName,
10379 &junk))) {
10380 SUMA_S_Err("Unexpected! Could not find overlay pointer");
10381 } else {
10382 /* if the current col plane is not the same as this one,
10383 do the switching please */
10384 SUMA_InitializeColPlaneShell((SUMA_ALL_DO *)SO, Overlay);
10385 SUMA_UpdateColPlaneShellAsNeeded((SUMA_ALL_DO *)SO);
10386 /* update other open
10387 ColPlaneShells */
10388 }
10389 }
10390
10391 SUMA_RETURN(DrawnROI);
10392 }
10393
10394 /*!
10395 Function that turns a brushstroke to a series of nodes on the surface.
10396
10397 No surface paths are created from one node to the next yet.
10398
10399 It is not always the case that BrushStroke->N_SurfNodes is equal
10400 to BrushStroke->N
10401 */
SUMA_BrushStrokeToNodeStroke(SUMA_SurfaceViewer * sv)10402 SUMA_Boolean SUMA_BrushStrokeToNodeStroke (SUMA_SurfaceViewer *sv)
10403 {
10404 static char FuncName[]={"SUMA_BrushStrokeToNodeStroke"};
10405 DList * NS=NULL;
10406 SUMA_SurfaceObject *SO=NULL;
10407 SUMA_MT_INTERSECT_TRIANGLE *MTI = NULL;
10408 float delta_t_tmp;
10409 struct timeval tt_tmp;
10410 int N = -1;
10411 SUMA_Boolean LocalHead=NOPE;
10412 SUMA_BRUSH_STROKE_DATUM *bsd=NULL, *obsd=NULL;
10413 DListElmt *Elmt = NULL, *oElmt=NULL;
10414
10415 SUMA_ENTRY;
10416
10417 if (!(SO = SUMA_SV_Focus_SO(sv))) {
10418 SUMA_S_Err("No surface in focus");
10419 SUMA_RETURN(NOPE);
10420 }
10421
10422 /* ONLY WORK ON FocusSO */
10423 if (SO->FaceSetDim != 3) {
10424 SUMA_S_Err("SUMA_MT_intersect_triangle only works for triangular meshes.");
10425 SUMA_RETURN(NOPE);
10426 }
10427
10428 N = dlist_size(sv->BS);
10429 if (!N) {
10430 fprintf (SUMA_STDERR, "%s: Empty brushstroke, nothing to do.\n", FuncName);
10431 SUMA_RETURN(NOPE);
10432 }else SUMA_LHv("%d element(s) in sv->BS.\n", N);
10433
10434 /* the first node of the brushstroke is stored as the cross hair's node id,
10435 just copy it */
10436 Elmt = dlist_head(sv->BS);
10437 bsd = (SUMA_BRUSH_STROKE_DATUM *)Elmt->data;
10438
10439 bsd->SurfNode = SO->SelectedNode;
10440 bsd->SurfTri = SO->SelectedFaceSet;
10441
10442 #ifdef DISASTER_LOOP
10443 /* Now as a brute force method, do all the remaing nodes in the path.
10444 In the future, you want to downsample the path is some clever fashion */
10445 if (N > 1) {
10446 if (LocalHead) {
10447 fprintf (SUMA_STDERR, "%s: Disaster loop, hold on .\n", FuncName);
10448 SUMA_etime (&tt_tmp, 0);
10449 }
10450
10451 MTI = NULL;
10452 do {
10453 Elmt = Elmt->next;
10454 bsd = (SUMA_BRUSH_STROKE_DATUM *)Elmt->data;
10455
10456 MTI = SUMA_MT_intersect_triangle( bsd->NP, bsd->FP,
10457 SO->NodeList, SO->N_Node,
10458 SO->FaceSetList, SO->N_FaceSet,
10459 MTI,0);
10460
10461 if (!MTI) {
10462 fprintf(SUMA_STDERR,"Error %s: SUMA_MT_intersect_triangle failed.\n", FuncName);
10463 SUMA_RETURN (NOPE);
10464 }
10465
10466 if (MTI->N_hits) { /* There is a hit, store it if useful */
10467 oElmt = Elmt->prev;
10468 obsd = (SUMA_BRUSH_STROKE_DATUM *)oElmt->data;
10469 if (obsd->SurfNode != MTI->inodemin) { /* a new one, bring it on */
10470 bsd->SurfNode = MTI->inodemin;
10471 bsd->SurfTri = MTI->ifacemin;
10472 }else {
10473 /* destroy Elmt, it is redundant */
10474 if (LocalHead) fprintf (SUMA_STDERR, "%s: Removing redundant BS element.\n", FuncName);
10475 dlist_remove (sv->BS, Elmt, (void*)(&bsd));
10476 SUMA_FreeBSDatum (bsd);
10477 Elmt = oElmt;
10478 }
10479 }
10480
10481 }while (Elmt != dlist_tail(sv->BS));
10482
10483 /* free MTI */
10484 MTI = SUMA_Free_MT_intersect_triangle(MTI);
10485
10486 if (LocalHead) {
10487 delta_t_tmp = SUMA_etime (&tt_tmp, 1);
10488 if (LocalHead) fprintf (SUMA_STDERR, "Local Debug %s: Intersections took %f seconds.\n", FuncName, delta_t_tmp);
10489 }
10490
10491 }
10492 #else
10493 if (N > 1) { /* new, faster method */
10494 DListElmt *Eli=NULL, *Eln=NULL;
10495 float ip[3], d[3];
10496 int IncTri[100], N_IncTri=0, n1=-1, n2=-1, n3=-1, ni = -1,
10497 ti = -1, N_Neighb=0,DeciLevel = 0, i, j, Removed=0;
10498 int DeciReentry=0, UsedNode[3]={ 0 , 0, 0 };
10499 SUMA_BRUSH_STROKE_DATUM *bsdi=NULL, *bsdn=NULL, *bsd_deci=NULL;
10500 SUMA_Boolean DoesInters=NOPE; /* flag for Decimation mode */
10501 SUMA_Boolean TrackOscillation = YUP; /* flag to tracking
10502 algorithm oscillation */
10503 SUMA_Boolean TryBruteForce = NOPE;
10504 int *Visited = NULL;
10505
10506 if (TrackOscillation) {
10507 Visited = (int *)SUMA_calloc(SO->N_Node, sizeof(int));
10508 if (!Visited) {
10509 SUMA_SLP_Err("Failed to allocate for Visited.\n");
10510 SUMA_RETURN(NOPE);
10511 }
10512 }
10513
10514 Eli = Elmt; /* initialize current element to the
10515 very fist in the brushstroke */
10516 MTI = NULL;
10517 TryBruteForce = NOPE;
10518 do {
10519 bsdi = (SUMA_BRUSH_STROKE_DATUM *)Eli->data;
10520 n1 = bsdi->SurfNode;
10521
10522 Eln = Eli->next; /* get the next element in line */
10523 bsdn = (SUMA_BRUSH_STROKE_DATUM *)Eln->data;
10524
10525 if (LocalHead)
10526 fprintf(SUMA_STDERR,"%s: Working from node %d.\n", FuncName, n1);
10527
10528 if (!TryBruteForce) { /* try the fast method */
10529 N_Neighb = SO->FN->N_Neighb[n1];
10530 if (N_Neighb < 3) {
10531 /* nothing found */
10532 SUMA_SLP_Err ("Node has less than 3 neighbors.\n"
10533 "This method will not apply.");
10534 SUMA_RETURN(NOPE);
10535 }
10536
10537 /* does the ray formed by Eln's NP and FP hit any of
10538 the triangles incident to bsdi->SurfNode (or n1) ? */
10539 if (LocalHead)
10540 fprintf (SUMA_STDERR,
10541 "%s: Searching incident triangles:\n", FuncName);
10542 i=0;
10543 DoesInters = NOPE;
10544 while ((i < N_Neighb ) && (!DoesInters)) {
10545 n2 = SO->FN->FirstNeighb[n1][i];
10546 if ( i+1 == N_Neighb) n3 = SO->FN->FirstNeighb[n1][0];
10547 else n3 = SO->FN->FirstNeighb[n1][i+1];
10548 #if 0
10549 if (LocalHead) {
10550 fprintf (SUMA_STDERR, " %d: [%d %d %d] Tri %d\n",
10551 i, n1, n2, n3, SUMA_whichTri(SO->EL, n1, n2, n3, 1));
10552 fprintf (SUMA_STDERR, " %d: [%.2f, %.2f, %.2f]\n",
10553 n1, SO->NodeList[3*n1],
10554 SO->NodeList[3*n1+1], SO->NodeList[3*n1+2]);
10555 fprintf (SUMA_STDERR, " %d: [%.2f, %.2f, %.2f]\n",
10556 n2, SO->NodeList[3*n2],
10557 SO->NodeList[3*n2+1], SO->NodeList[3*n2+2]);
10558 fprintf (SUMA_STDERR, " %d: [%.2f, %.2f, %.2f]\n",
10559 n3, SO->NodeList[3*n3],
10560 SO->NodeList[3*n3+1], SO->NodeList[3*n3+2]);
10561 fprintf (SUMA_STDERR,
10562 " NP: [%.2f, %.2f, %.2f] FP: [%.3f, %.2f, %.2f]\n",
10563 bsdn->NP[0], bsdn->NP[1], bsdn->NP[2],
10564 bsdn->FP[0], bsdn->FP[1], bsdn->FP[2]);
10565 }
10566 #endif
10567 DoesInters = SUMA_MT_isIntersect_Triangle (bsdn->NP, bsdn->FP,
10568 &(SO->NodeList[3*n1]),
10569 &(SO->NodeList[3*n2]),
10570 &(SO->NodeList[3*n3]), ip, d, &ni);
10571 if (DoesInters) {
10572 if (ni == 0) ni = n1;
10573 else if (ni == 1) ni = n2;
10574 else ni = n3;
10575
10576 ti = SUMA_whichTri(SO->EL, n1, n2, n3, 1, 0);
10577 }
10578
10579 #if 0
10580 if (LocalHead)
10581 fprintf (SUMA_STDERR,
10582 "%s: DoesInters = %d, ni = %d\n",
10583 FuncName, DoesInters, ni);
10584 {
10585 /* for debuging */
10586 MTI = NULL;MTI =
10587 SUMA_MT_intersect_triangle( bsdn->NP, bsdn->FP,
10588 SO->NodeList, SO->N_Node,
10589 SO->FaceSetList,
10590 SO->N_FaceSet,
10591 MTI, 0);
10592 fprintf (SUMA_STDERR,
10593 "%s: Intersection would be with triangle %d, node %d\n",
10594 FuncName, MTI->ifacemin, MTI->inodemin);
10595 }
10596 #endif
10597 ++i;
10598 }
10599 if (LocalHead) fprintf (SUMA_STDERR, "\n");
10600
10601 } else { /* try brute force flag has been set*/
10602
10603 if (LocalHead) fprintf (SUMA_STDERR, "%s: Trying brute force here \n", FuncName);
10604 /* Now skip and remove decimated elements */
10605 SUMA_REMOVE_NEXT_NON_DECIMATED (sv->BS, Eli, Eln);
10606 DeciLevel = 0;
10607 DeciReentry = 0;
10608 if (!Eln) {
10609 SUMA_SL_Err ("I tried hard to figure out your trace.\nI failed, now you try again.");
10610 SUMA_RETURN(YUP);
10611 }
10612
10613 bsdn = (SUMA_BRUSH_STROKE_DATUM *)Eln->data;
10614 MTI = SUMA_MT_intersect_triangle( bsdn->NP, bsdn->FP,
10615 SO->NodeList, SO->N_Node,
10616 SO->FaceSetList, SO->N_FaceSet,
10617 MTI, 0);
10618
10619 if (!MTI) {
10620 SUMA_SL_Err ("I tried harder to figure out your trace.\nI failed, do try again.");
10621 SUMA_RETURN (YUP);
10622 }
10623
10624 if (MTI->N_hits) { /* There is a hit, store it if useful */
10625 DoesInters = YUP;
10626 if (bsdi->SurfNode != MTI->inodemin) { /* a new one, bring it on */
10627 if (LocalHead) fprintf (SUMA_STDERR, "%s: Brute Force: Found intersection at new node %d.\n", FuncName, MTI->inodemin);
10628 ni = MTI->inodemin;
10629 ti = MTI->ifacemin;
10630 }else {
10631 /* set ni to n1 and let the element be destroyed */
10632 if (LocalHead) fprintf (SUMA_STDERR, "%s: Brute Force: Found intersection at n1 = %d!.\n", FuncName, MTI->inodemin);
10633 ni = n1;
10634 }
10635 } else {
10636 /* No hits at all, get out of this business */
10637 SUMA_SL_Err ("Why are you drawing out of bounds ?");
10638 SUMA_RETURN (YUP);
10639 }
10640 /* reset the TryBruteForce flag */
10641 TryBruteForce = NOPE;
10642 }
10643
10644 if (!DoesInters) { /* no intersection found, insert an element between Eli and Eln and try again */
10645 ++DeciLevel;
10646 if (LocalHead) fprintf (SUMA_STDERR, "%s: No intersection found. Decimating, level %d.\n", FuncName, DeciLevel);
10647
10648 if (DeciLevel > 3000) { /* this condition is only here to keep things from going awry. */
10649 if (LocalHead) fprintf (SUMA_STDERR,"%s: Decimation method failed. Trying from brute force", FuncName);
10650 TryBruteForce = YUP;
10651 } else {
10652 bsd_deci = SUMA_CreateBSDatum();
10653 bsd_deci->Decimated = YUP;
10654 bsd_deci->x = (bsdi->x + bsdn->x)/2.0;
10655 bsd_deci->y = (bsdi->y + bsdn->y)/2.0;
10656 for (j=0; j < 3; ++j) bsd_deci->NP[j] = (bsdi->NP[j] + bsdn->NP[j])/2.0;
10657 for (j=0; j < 3; ++j) bsd_deci->FP[j] = (bsdi->FP[j] + bsdn->FP[j])/2.0;
10658 bsd_deci->SurfNode = -1;
10659 bsd_deci->SurfTri = -1;
10660
10661 dlist_ins_next (sv->BS, Eli, bsd_deci);
10662 }
10663 } else {
10664 /* intersection found */
10665 if (ni == n1 && !DeciLevel) {
10666 /* same node reached, not during decimation, perhaps path was too densely sampled, delete Eln */
10667 ++Removed;
10668 if (LocalHead) fprintf (SUMA_STDERR, "%s: Same node reached without decimation, deleting for the %dth time.\n",
10669 FuncName, Removed);
10670 dlist_remove(sv->BS, Eln, (void*)&bsdn);
10671 SUMA_FreeBSDatum(bsdn);
10672 } else {
10673 if (ni == n1 && DeciLevel) {
10674 /* back to the starting point during decimation */
10675 if (DeciLevel) { /* user went out of bounds or drawing over cuts in surface */
10676 #if 0
10677 /* same node reached during decimation, to hell with it, use brute force intersection: YOU PAY PRICE IN TIME MISTER*/
10678 TryBruteForce = YUP;
10679 /* cancel the find */
10680 DoesInters = NOPE;
10681 #else
10682 /* same node reached during decimation, try othernode in triangle */
10683 if (!DeciReentry) {
10684 UsedNode[0] = n1;
10685 if (LocalHead) fprintf (SUMA_STDERR, "%s: Same node reached during decimation.\n Switching to second closest node.\n", FuncName);
10686 if (d[1] < d[2]) {
10687 ni = n2;
10688 UsedNode[1] = n2;
10689 } else {
10690 ni = n3;
10691 UsedNode[1] = n3;
10692 }
10693 } else if (DeciReentry == 1){
10694 /* been there before, one last node is left */
10695 if (LocalHead) fprintf (SUMA_STDERR, "%s: Last chance!\n", FuncName);
10696 if (n2 != UsedNode[0] && n2 != UsedNode[1]) ni = n2;
10697 else if (n3 != UsedNode[0] && n3 != UsedNode[1]) ni = n3;
10698 } else {
10699 /* Decimation failed, Do intersection with entire surface */
10700 TryBruteForce = YUP;
10701 /* cancel the find */
10702 DoesInters = NOPE;
10703 }
10704 #endif
10705 ++DeciReentry;
10706 }
10707 }else {
10708 /* ni != n1 Reset DeciLevel */
10709 DeciLevel = 0;
10710 DeciReentry = 0;
10711 }
10712
10713 /* algorithm might fall into oscillatory patterns, keep track of nodes visited.
10714 It is possible that a node is visited multiple times when users go over the
10715 same region over and over and over.*/
10716 if (TrackOscillation) {
10717 ++Visited[ni];
10718 if (Visited[ni] == 9) {
10719 DoesInters = NOPE;
10720 TryBruteForce = YUP;
10721 SUMA_SL_Err ("Path tracing oscillation. Trying with brute force.");
10722 }
10723 if (Visited[ni] > 9) {
10724 SUMA_SL_Err ("Path tracing oscillation remaining. Quitting tracing.");
10725 SUMA_RETURN(YUP);
10726 }
10727 }
10728
10729 if (DoesInters) { /* it is possible that the find is cancelled */
10730 if (LocalHead) fprintf (SUMA_STDERR, "%s: Found new node.\n", FuncName);
10731 /* good, new node is useful*/
10732 bsdn->SurfNode = ni;
10733 bsdn->SurfTri = ti;
10734 /* set Eli to Eln */
10735 Eli = Eln;
10736 }
10737 }
10738 }
10739 /* repeat until you have no more element */
10740 } while (Eli != dlist_tail(sv->BS));
10741
10742 if (MTI) MTI = SUMA_Free_MT_intersect_triangle(MTI);
10743 if (TrackOscillation) {
10744 if (Visited) SUMA_free(Visited);
10745 }
10746 }/* new, faster method */
10747 #endif
10748 SUMA_RETURN(YUP);
10749 }
10750
10751
10752 /*!
10753 \brief Function to link a node on the surface to a certain node in NodeStroke
10754
10755 \param sv (SUMA_SurfaceViewer *) with a valid BrushStroke in it
10756 \param NonSurf (int) index of node on surface to connect to NinStroke
10757 \param ELinStroke (DListElmt *) sv->BS element containing in SurfNode the index of the node to connect NonSurf to
10758 \sa SUMA_LinkTailNodeToNodeStroke
10759 */
SUMA_LinkThisNodeToNodeInStroke(SUMA_SurfaceViewer * sv,int NonSurf,DListElmt * ELinStroke)10760 SUMA_ROI_DATUM *SUMA_LinkThisNodeToNodeInStroke (SUMA_SurfaceViewer *sv,
10761 int NonSurf, DListElmt *ELinStroke)
10762 {
10763 static char FuncName[]={"SUMA_LinkThisNodeToNodeInStroke"};
10764 SUMA_Boolean LocalHead = NOPE;
10765 SUMA_ROI_DATUM *ROId=NULL;
10766 SUMA_SurfaceObject *SO=NULL;
10767 int Nfrom, Nto;
10768 SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
10769
10770 SUMA_ENTRY;
10771
10772 if (!(SO = SUMA_SV_Focus_SO(sv))) {
10773 SUMA_S_Err("No SO in focus");
10774 SUMA_RETURN(NULL);
10775 }
10776
10777 Nfrom = NonSurf;
10778 bsd = (SUMA_BRUSH_STROKE_DATUM *)ELinStroke->data;
10779 Nto = bsd->SurfNode;
10780
10781 /* Now compute the intersection of the surface with the plane */
10782 ROId = SUMA_Surf_Plane_Intersect_ROI (SO, Nfrom, Nto, bsd->NP);
10783
10784 if (!ROId) {
10785 SUMA_S_Err("Failed to link tail node to first node in new stroke.\n"
10786 "Repeat new stroke.");
10787 SUMA_RETURN(NULL);
10788 }
10789
10790 SUMA_RETURN(ROId);
10791 }
10792
10793 /*!
10794 \brief Function to link a node on the surface to the first node
10795 of a NodeStroke
10796
10797 -This function returns an ROI_datum that represents the link between
10798 the last node visited and the first node of the Nodestroke
10799
10800 \sa SUMA_LinkThisNodeToNodeInStroke
10801 */
SUMA_LinkTailNodeToNodeStroke(SUMA_SurfaceViewer * sv,SUMA_DRAWN_ROI * DrawnROI)10802 SUMA_ROI_DATUM *SUMA_LinkTailNodeToNodeStroke ( SUMA_SurfaceViewer *sv,
10803 SUMA_DRAWN_ROI *DrawnROI)
10804 {
10805
10806 static char FuncName[]={"SUMA_LinkTailNodeToNodeStroke"};
10807 SUMA_ROI_DATUM *ROId=NULL;
10808 SUMA_SurfaceObject *SO=NULL;
10809 SUMA_Boolean LocalHead = NOPE;
10810 int Nfrom=-1, Nto=-1, Trito=-1;
10811 DListElmt *Elm=NULL;
10812 SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
10813
10814 SUMA_ENTRY;
10815
10816 if (!(SO = SUMA_SV_Focus_SO(sv))) {
10817 SUMA_S_Err("No SO in focus");
10818 SUMA_RETURN(NULL);
10819 }
10820
10821 /* get the equation of the plane fromed by TailNode,
10822 FirstNodeinBrushStroke and its NearPlanePoint */
10823 SUMA_DRAWN_ROI_TAIL_NODE(DrawnROI, Nfrom);
10824 if (Nfrom < 0) {
10825 fprintf (SUMA_STDERR, "Error %s: No tail node found.\n", FuncName);
10826 SUMA_RETURN(NULL);
10827 }
10828
10829 /* get the first node in the stroke */
10830 SUMA_BS_FIRST_SURF_NODE(sv->BS, Nto, Trito, Elm);
10831 if (Nto < 0 || !Elm) {
10832 SUMA_SLP_Err ("Failed in SUMA_BS_FIRST_SURF_NODE macro.");
10833 SUMA_RETURN(NULL);
10834 }
10835 bsd = (SUMA_BRUSH_STROKE_DATUM *)Elm->data;
10836
10837 /* Now compute the intersection of the surface with the plane */
10838 ROId = SUMA_Surf_Plane_Intersect_ROI (SO, Nfrom, Nto, bsd->NP);
10839
10840 if (!ROId) {
10841 SUMA_S_Err("Failed to link tail node to first node in new stroke.\n"
10842 "Repeat new stroke.");
10843 SUMA_RETURN(NULL);
10844 }
10845
10846 SUMA_RETURN(ROId);
10847 }
10848
10849
10850 /*!
10851 This function turns the NodeStroke into a datum of connected nodes
10852 */
SUMA_NodeStrokeToConnectedNodes(SUMA_SurfaceViewer * sv)10853 SUMA_ROI_DATUM *SUMA_NodeStrokeToConnectedNodes (SUMA_SurfaceViewer *sv)
10854 {
10855 static char FuncName[]={"SUMA_NodeStrokeToConnectedNodes"};
10856 SUMA_Boolean LocalHead = NOPE;
10857 SUMA_ROI_DATUM *ROId=NULL, *ROIlink = NULL;
10858 int i=0;
10859 SUMA_SurfaceObject *SO=NULL;
10860 DListElmt *Elmt = NULL, *oElmt = NULL;
10861 SUMA_BRUSH_STROKE_DATUM *bsd=NULL;
10862
10863 SUMA_ENTRY;
10864
10865 if (!(SO = SUMA_SV_Focus_SO(sv))) {
10866 SUMA_S_Err("No SO in focus");
10867 SUMA_RETURN(NULL);
10868 }
10869
10870 ROId = SUMA_AllocROIDatum();
10871
10872 /* fill up node series here */
10873 ROId->N_n = 1;
10874 ROId->N_t = 1;
10875 ROId->nPath = (int *) SUMA_calloc (ROId->N_n, sizeof(int));
10876 ROId->tPath = (int *) SUMA_calloc (ROId->N_t, sizeof(int));
10877
10878 SUMA_BS_FIRST_SURF_NODE(sv->BS, ROId->nPath[0], ROId->tPath[0], Elmt);
10879 ROId->Type = SUMA_ROI_NodeSegment;
10880
10881 /* try filling up the rest */
10882 oElmt = Elmt;
10883 do {
10884 /* get the next element with a surfnode */
10885 SUMA_BS_NEXT_SURF_NODE(sv->BS, oElmt, Elmt);
10886
10887 if (!Elmt) {
10888 /* perhaps reached end of list without success */
10889 SUMA_S_Note("Reached EOL without finding Elmt.\n"
10890 "Not necessarily a bad thing.");
10891 SUMA_RETURN(ROId);
10892 } else {
10893 if (LocalHead) {
10894 fprintf (SUMA_STDERR, "%s: Working with element %p.\n", FuncName, Elmt);
10895 }
10896 }
10897 bsd = (SUMA_BRUSH_STROKE_DATUM *)Elmt->data;
10898 SUMA_LHv("%d %d\nWill look for edge %d %d\n",
10899 ROId->N_n, bsd->SurfNode,
10900 ROId->nPath[ROId->N_n-1], bsd->SurfNode);
10901 if (SUMA_FindEdge(SO->EL, ROId->nPath[ROId->N_n-1], bsd->SurfNode) < 0) {
10902 /* Not found, link nodes together*/
10903 SUMA_LH("Edge not found, linking together.");
10904 if (!(ROIlink = SUMA_LinkThisNodeToNodeInStroke (sv,
10905 ROId->nPath[ROId->N_n-1], Elmt))) {
10906 SUMA_SLP_Err ("Failed to connect nodes in stroke.");
10907 SUMA_RETURN (ROId);
10908 }
10909 /* merge ROIlink with ROId */
10910 SUMA_LH("Merging ROIs together.");
10911 if (!SUMA_AppendToROIdatum (ROIlink, ROId)) {
10912 SUMA_RegisterMessage (SUMAg_CF->MessageList,
10913 "Failed to merge ROIs.", FuncName,
10914 SMT_Critical, SMA_LogAndPopup);
10915 if (ROIlink) SUMA_FreeROIDatum((void *)ROIlink); ROIlink = NULL;
10916 SUMA_RETURN(ROId);
10917 }
10918 if (ROIlink) SUMA_FreeROIDatum((void *)ROIlink); ROIlink = NULL;
10919 }else {
10920 SUMA_LH("Nodes connected.");
10921 /* nodes are connected, just add to path */
10922 ++ROId->N_n;
10923 ROId->nPath = (int *) SUMA_realloc (ROId->nPath, sizeof(int)*ROId->N_n);
10924 ROId->nPath[ROId->N_n-1] = bsd->SurfNode;
10925 }
10926
10927 oElmt = Elmt;
10928 } while (Elmt != dlist_tail(sv->BS));
10929
10930 SUMA_RETURN (ROId);
10931 }
10932
10933
10934 /*!
10935 Executes an action
10936 Adds it to the action stack
10937 Update the action stack pointer
10938 DO not do StckPos = SUMA_PushActionStack (..., StackPos, ....);
10939 that is because the function might return NULL if something failed and you'd lose the current stack position for good.
10940 */
SUMA_PushActionStack(DList * ActionStack,DListElmt * StackPos,SUMA_ACTION_RESULT (* ActionFunction)(void * ActionData,SUMA_ACTION_POLARITY Pol),void * ActionData,void (* ActionDataDestructor)(void * Actiondata))10941 DListElmt * SUMA_PushActionStack (DList *ActionStack, DListElmt *StackPos,
10942 SUMA_ACTION_RESULT (*ActionFunction)(void *ActionData, SUMA_ACTION_POLARITY Pol),
10943 void *ActionData,
10944 void (*ActionDataDestructor)(void *Actiondata))
10945 {
10946 static char FuncName[]={"SUMA_PushActionStack"};
10947 SUMA_Boolean LocalHead = NOPE;
10948 SUMA_ACTION_STACK_DATA *AS_data=NULL;
10949 SUMA_ACTION_RESULT ActionResult = SAR_Undefined;
10950
10951 SUMA_ENTRY;
10952
10953 /* execute action */
10954 if (LocalHead) fprintf (SUMA_STDERR, "%s: Executing Action.\n", FuncName);
10955 ActionResult = ActionFunction (ActionData, SAP_Do);
10956 switch (ActionResult) {
10957 case SAR_Fail:
10958 SUMA_SLP_Err("Action failed.");
10959 SUMA_RETURN(NULL);
10960 break;
10961 case SAR_Succeed:
10962 break;
10963 default:
10964 SUMA_SLP_Err("Action result not understood.");
10965 SUMA_RETURN(NULL);
10966 break;
10967 }
10968
10969 /* remove all elements above the position in the stack */
10970 if (LocalHead) fprintf (SUMA_STDERR, "%s: Removing Action Stack Elements above current position.\n", FuncName);
10971 while (StackPos != dlist_tail(ActionStack)) {
10972 void *asdata=NULL;
10973
10974 dlist_remove(ActionStack, dlist_tail(ActionStack), &asdata);
10975
10976 /* now free the asdata */
10977 SUMA_FreeActionStackData(asdata);
10978 }
10979
10980 /* Pushing the action and its data onto the stack */
10981 if (LocalHead) fprintf (SUMA_STDERR, "%s: Pushing the action and its data onto the stack.\n", FuncName);
10982 AS_data = (SUMA_ACTION_STACK_DATA *)
10983 SUMA_calloc(1,sizeof(SUMA_ACTION_STACK_DATA));
10984 AS_data->ActionDataDestructor = ActionDataDestructor;
10985 AS_data->ActionFunction = ActionFunction;
10986 AS_data->ActionData = ActionData;
10987 dlist_ins_next (ActionStack, dlist_tail(ActionStack), (void*)AS_data);
10988 if (LocalHead) fprintf (SUMA_STDERR, "%s: Updating StackPos ...\n", FuncName);
10989 StackPos = dlist_tail(ActionStack);
10990
10991 SUMA_RETURN(StackPos);
10992 }
10993
10994 /*!
10995 Redo an action of the ActionStack
10996 If StackPos is NULL, it is assumed that you are at the bottom of the stack
10997 */
SUMA_RedoAction(DList * ActionStack,DListElmt * StackPos)10998 DListElmt * SUMA_RedoAction (DList *ActionStack, DListElmt *StackPos)
10999 {
11000 static char FuncName[]={"SUMA_RedoAction"};
11001 SUMA_ACTION_STACK_DATA *AS_data=NULL;
11002 SUMA_ACTION_RESULT ActionResult = SAR_Undefined;
11003 SUMA_Boolean LocalHead = NOPE;
11004
11005 SUMA_ENTRY;
11006
11007 if (!StackPos) {
11008 if (LocalHead) fprintf (SUMA_STDERR, "%s: At bottom of stack. Working up.\n", FuncName);
11009 StackPos = dlist_head(ActionStack);
11010 } else if (StackPos == dlist_tail(ActionStack)) {
11011 SUMA_SLP_Err("At top of stack, nothing to do.");
11012 SUMA_RETURN(StackPos);
11013 } else {
11014 StackPos = dlist_next(StackPos);
11015 }
11016
11017 /* execute action above StackPos again */
11018 AS_data = (SUMA_ACTION_STACK_DATA *)StackPos->data;
11019 ActionResult = AS_data->ActionFunction (AS_data->ActionData, SAP_Redo);
11020 switch (ActionResult) {
11021 case SAR_Fail:
11022 SUMA_SLP_Err("Action failed.");
11023 SUMA_RETURN(NULL);
11024 break;
11025 case SAR_Succeed:
11026 break;
11027 default:
11028 SUMA_SLP_Err("Action result not understood.");
11029 SUMA_RETURN(NULL);
11030 break;
11031 }
11032
11033 SUMA_RETURN(StackPos);
11034 }
11035 /*!
11036 Undo an action on the ActionStack
11037
11038 \returns StackNewPos = StackPos if reached the bottom of the stack.
11039 It is your job to make sure this function is not called again.
11040 = StackPos->prev if all went well
11041 =NULL if trouble
11042
11043 */
SUMA_UndoAction(DList * ActionStack,DListElmt * StackPos)11044 DListElmt * SUMA_UndoAction (DList *ActionStack, DListElmt *StackPos)
11045 {
11046 static char FuncName[]={"SUMA_UndoAction"};
11047 SUMA_ACTION_STACK_DATA *AS_data=NULL;
11048 SUMA_ACTION_RESULT ActionResult = SAR_Undefined;
11049 SUMA_Boolean LocalHead = NOPE;
11050
11051 SUMA_ENTRY;
11052
11053 if (!StackPos) {
11054 SUMA_SLP_Err("At bottom of stack.");
11055 SUMA_RETURN(StackPos);
11056 }
11057
11058 AS_data = (SUMA_ACTION_STACK_DATA *)StackPos->data;
11059
11060 /* execute reverse of action */
11061 ActionResult = AS_data->ActionFunction (AS_data->ActionData, SAP_Undo);
11062 switch (ActionResult) {
11063 case SAR_Fail:
11064 SUMA_SLP_Err("Action failed.");
11065 SUMA_RETURN(NULL);
11066 break;
11067 case SAR_Succeed:
11068 break;
11069 default:
11070 SUMA_SLP_Err("Action result not understood.");
11071 SUMA_RETURN(NULL);
11072 break;
11073 }
11074
11075 /* now move StackPos down */
11076 if (StackPos == dlist_head(ActionStack)) {
11077 /* do nothing to StackPos */
11078 } else {
11079 StackPos = dlist_prev(StackPos);
11080 }
11081
11082 SUMA_RETURN(StackPos);
11083 }
11084
11085 /*!
11086 \brief Mark an ROI as finished
11087 */
SUMA_FinishedROI(void * data,SUMA_ACTION_POLARITY Pol)11088 SUMA_ACTION_RESULT SUMA_FinishedROI (void *data, SUMA_ACTION_POLARITY Pol)
11089 {
11090 static char FuncName[]={"SUMA_FinishedROI"};
11091 SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
11092 SUMA_SurfaceObject *SOparent=NULL;
11093 SUMA_Boolean LocalHead = NOPE;
11094
11095 SUMA_ENTRY;
11096
11097 ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
11098
11099 switch (Pol) {
11100 case SAP_Do:
11101 case SAP_Redo:
11102 if (LocalHead)
11103 fprintf (SUMA_STDERR, "%s: Marking as finished...\n", FuncName);
11104 /* set the drawing status */
11105 ROIA->DrawnROI->DrawStatus = SUMA_ROI_Finished;
11106
11107 SOparent = SUMA_findSOp_inDOv(ROIA->DrawnROI->Parent_idcode_str,
11108 SUMAg_DOv, SUMAg_N_DOv);
11109 if (!SOparent) {
11110 SUMA_SLP_Warn( "Parent surface\n"
11111 "not found for ROI\n"
11112 "No contour will\n"
11113 "be determined." );
11114 SUMA_RETURN(SAR_Succeed);
11115 }else {
11116 /* calculate the contours */
11117 if (!ROIA->DrawnROI->CE) { /* must create contour */
11118 int *Nodes, N_Nodes;
11119 SUMA_Boolean Unique = NOPE;
11120
11121 SUMA_LH("Getting Contour ");
11122 N_Nodes = 0;
11123 Unique = YUP; /* Set to YUP if you have node
11124 indices listed more than once. */
11125 Nodes = SUMA_NodesInROI (ROIA->DrawnROI, &N_Nodes, Unique);
11126 if (Nodes) {
11127 ROIA->DrawnROI->CE = SUMA_GetContour (
11128 SOparent,
11129 Nodes, N_Nodes, &(ROIA->DrawnROI->N_CE),
11130 0, NULL, NULL, 1);
11131 if (!ROIA->DrawnROI->CE) { SUMA_LH("Null DrawnROI->CE"); }
11132 else { SUMA_LH("Good DrawnROI->CE"); }
11133 SUMA_free(Nodes);
11134 }
11135 }else {
11136 SUMA_SLP_Err("Unexpected Contour");
11137 SUMA_RETURN(SAR_Fail);
11138 }
11139 }
11140
11141 break;
11142 case SAP_Undo:
11143 if (LocalHead)
11144 fprintf (SUMA_STDERR, "%s: Marking as InCreation...\n", FuncName);
11145 ROIA->DrawnROI->DrawStatus = SUMA_ROI_InCreation;
11146 /* remove any contour if present */
11147 if (ROIA->DrawnROI->CE) SUMA_free(ROIA->DrawnROI->CE);
11148 ROIA->DrawnROI->CE = NULL;
11149 ROIA->DrawnROI->N_CE = -1;
11150 break;
11151 default:
11152 fprintf (SUMA_STDERR, "Error %s: Should not be here.\n", FuncName);
11153 break;
11154 }
11155
11156 SUMA_RETURN(SAR_Succeed);
11157 }
11158
11159 /*!
11160 \brief This function is like SUMA_AddToTailROIDatum, except that it also updates the type of the ROI
11161 to be a filled one. You call this function when you are adding an ROIDatum that fills a closed path
11162 \param data (void *) of SUMA_ROI_ACTION_STRUCT * containing the ROIlist and the ROIdatum
11163 \param Pol (SUMA_ACTION_POLARITY) SAP_Do, SAP_Redo, SAP_Undo
11164 */
11165
SUMA_AddFillROIDatum(void * data,SUMA_ACTION_POLARITY Pol)11166 SUMA_ACTION_RESULT SUMA_AddFillROIDatum (void *data, SUMA_ACTION_POLARITY Pol)
11167 {
11168 static char FuncName[]={"SUMA_AddFillROIDatum"};
11169 SUMA_Boolean LocalHead = NOPE;
11170 SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
11171 void *eldata=NULL;
11172 DListElmt *tail_elm=NULL;
11173 SUMA_ROI_DATUM *ROId=NULL;
11174
11175 SUMA_ENTRY;
11176
11177 ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
11178
11179 switch (Pol) {
11180 case SAP_Do:
11181 case SAP_Redo:
11182 if (LocalHead) fprintf (SUMA_STDERR, "%s: Adding to ROIstrokelist...\n", FuncName);
11183 dlist_ins_next(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), (void *)ROIA->ROId);
11184 ROIA->DrawnROI->Type = SUMA_ROI_FilledArea;
11185 break;
11186 case SAP_Undo:
11187 if (LocalHead) fprintf (SUMA_STDERR, "%s: Removing from ROIstrokelist...\n", FuncName);
11188 dlist_remove(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), &eldata);
11189 /* eldata contains the ROIdatum that has been removed from the list. It should not be freed here
11190 This structure is to remain in the stack for later usage.*/
11191 /* if the tail is a segment, then turn the ROI type to a closedpath */
11192 tail_elm = dlist_tail(ROIA->DrawnROI->ROIstrokelist);
11193 ROId = (SUMA_ROI_DATUM *)tail_elm->data;
11194 if (ROId->Type == SUMA_ROI_NodeSegment) { /* we are no longer dealing with filled ROI */
11195 ROIA->DrawnROI->Type = SUMA_ROI_ClosedPath;
11196 }
11197 break;
11198 default:
11199 fprintf (SUMA_STDERR, "Error %s: Should not be here.\n", FuncName);
11200 break;
11201 }
11202
11203 SUMA_RETURN(SAR_Succeed);
11204 }
11205
11206 /*!
11207 \brief This function is like SUMA_AddToTailROIDatum, except that it also updates the type of the ROI
11208 to be a closed one. You call this function when you are addind the last ROIDatum that closes the path
11209 \param data (void *) of SUMA_ROI_ACTION_STRUCT * containing the ROIlist and the ROIdatum
11210 \param Pol (SUMA_ACTION_POLARITY) SAP_Do, SAP_Redo, SAP_Undo
11211 */
SUMA_AddToTailJunctionROIDatum(void * data,SUMA_ACTION_POLARITY Pol)11212 SUMA_ACTION_RESULT SUMA_AddToTailJunctionROIDatum (void *data,
11213 SUMA_ACTION_POLARITY Pol)
11214 {
11215 static char FuncName[]={"SUMA_AddToTailJunctionROIDatum"};
11216 SUMA_Boolean LocalHead = NOPE;
11217 SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
11218 void *eldata=NULL;
11219
11220 SUMA_ENTRY;
11221
11222 ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
11223
11224 switch (Pol) {
11225 case SAP_Do:
11226 case SAP_Redo:
11227 if (ROIA->DrawnROI->Type == SUMA_ROI_ClosedPath) {
11228 SUMA_SLP_Err ("Trying to close a closed path!");
11229 SUMA_RETURN(SAR_Fail);
11230 }
11231 if (LocalHead) fprintf (SUMA_STDERR, "%s: Adding to ROIstrokelist...\n", FuncName);
11232 dlist_ins_next(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), (void *)ROIA->ROId);
11233 ROIA->DrawnROI->Type = SUMA_ROI_ClosedPath;
11234 break;
11235 case SAP_Undo:
11236 if (ROIA->DrawnROI->Type == SUMA_ROI_OpenPath) {
11237 SUMA_SLP_Err ("Trying to open an open path!");
11238 SUMA_RETURN(SAR_Fail);
11239 }
11240 if (LocalHead)
11241 fprintf (SUMA_STDERR, "%s: Removing from ROIstrokelist...\n",
11242 FuncName);
11243 dlist_remove(ROIA->DrawnROI->ROIstrokelist,
11244 dlist_tail(ROIA->DrawnROI->ROIstrokelist), &eldata);
11245 /* eldata contains the ROIdatum that has been removed from the list.
11246 It should not be freed here
11247 This structure is to remain in the stack for later usage.*/
11248 ROIA->DrawnROI->Type = SUMA_ROI_OpenPath;
11249 break;
11250 default:
11251 fprintf (SUMA_STDERR, "Error %s: Should not be here.\n", FuncName);
11252 break;
11253 }
11254
11255 SUMA_RETURN(SAR_Succeed);
11256 }
11257
11258
11259 /*!
11260 \brief Adds (or removes) an ROIdatum to the tail of the ROI list
11261
11262 \param data (void *) of SUMA_ROI_ACTION_STRUCT * containing the ROIlist and the ROIdatum
11263 \param Pol (SUMA_ACTION_POLARITY) SAP_Do, SAP_Redo, SAP_Undo
11264 */
SUMA_AddToTailROIDatum(void * data,SUMA_ACTION_POLARITY Pol)11265 SUMA_ACTION_RESULT SUMA_AddToTailROIDatum (void *data, SUMA_ACTION_POLARITY Pol)
11266 {
11267 static char FuncName[]={"SUMA_AddToTailROIDatum"};
11268 SUMA_Boolean LocalHead = NOPE;
11269 SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
11270 void *eldata=NULL;
11271
11272 SUMA_ENTRY;
11273
11274 ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
11275
11276 switch (Pol) {
11277 case SAP_Do:
11278 case SAP_Redo:
11279 if (LocalHead) fprintf (SUMA_STDERR, "%s: Adding to ROIstrokelist...\n", FuncName);
11280 dlist_ins_next(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), (void *)ROIA->ROId);
11281 break;
11282 case SAP_Undo:
11283 if (LocalHead) fprintf (SUMA_STDERR, "%s: Removing from ROIstrokelist...\n", FuncName);
11284 dlist_remove(ROIA->DrawnROI->ROIstrokelist, dlist_tail(ROIA->DrawnROI->ROIstrokelist), &eldata);
11285 /* eldata contains the ROIdatum that has been removed from the list. It should not be freed here
11286 This structure is to remain in the stack for later usage.*/
11287 break;
11288 default:
11289 fprintf (SUMA_STDERR, "Error %s: Should not be here.\n", FuncName);
11290 break;
11291 }
11292
11293 SUMA_RETURN(SAR_Succeed);
11294 }
11295
11296 /*!
11297 A function to destroy the ROI action data structure.
11298
11299 \param data (void *) of SUMA_ROI_ACTION_STRUCT * containing the ROIlist and the ROIdatum
11300
11301 - Only ROIA->ROId and ROIA are freed. ROIA->DrawnROI should be freed when the DrawnROI list is destroyed.
11302 */
11303
SUMA_DestroyROIActionData(void * data)11304 void SUMA_DestroyROIActionData (void *data)
11305 {
11306 static char FuncName[]={"SUMA_DestroyROIActionData"};
11307 SUMA_Boolean LocalHead = NOPE;
11308 SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
11309
11310 SUMA_ENTRY;
11311
11312 ROIA = (SUMA_ROI_ACTION_STRUCT *)data;
11313
11314 if (!ROIA) SUMA_RETURNe;
11315
11316 if (ROIA->ROId) { /* free the ROI datum */
11317 SUMA_FreeROIDatum ((void *)ROIA->ROId);
11318 ROIA->ROId = NULL;
11319 }
11320
11321 ROIA->DrawnROI = NULL; /* this should not be freed here, it is freed when the function for destroying DrawnROI is called */
11322 SUMA_free(ROIA);
11323
11324 SUMA_RETURNe;
11325 }
11326
11327 /*!
11328 \brief set the position of light0
11329 \param s (char *) a strng containing X, Y, Z coordinates
11330 \param data (void *) a typecast of the pointer to the surface viewer to be affected
11331
11332 */
SUMA_SetLight0(char * s,void * data)11333 void SUMA_SetLight0 (char *s, void *data)
11334 {
11335 static char FuncName[]={"SUMA_SetLight0"};
11336 DList *list=NULL;
11337 SUMA_EngineData *ED = NULL;
11338 SUMA_SurfaceViewer *sv = NULL;
11339 float fv3[3];
11340 SUMA_Boolean LocalHead = NOPE;
11341
11342 SUMA_ENTRY;
11343
11344 if (!s) SUMA_RETURNe;
11345
11346 sv = (SUMA_SurfaceViewer *)data;
11347
11348 /* parse s */
11349 if (SUMA_StringToNum (s, (void*)fv3, 3, 1) != 3) {/*problem,beep and ignore */
11350 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
11351 SUMA_RETURNe;
11352 }
11353
11354 /* register fv3 with ED */
11355 if (!list) list = SUMA_CreateList();
11356 ED = SUMA_InitializeEngineListData (SE_SetLight0Pos);
11357 if (!SUMA_RegisterEngineListCommand ( list, ED,
11358 SEF_fv3, (void *)fv3,
11359 SES_Suma, (void *)sv, NOPE,
11360 SEI_Tail, NULL )) {
11361 fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
11362 SUMA_RETURNe;
11363 }
11364
11365 SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
11366
11367 if (!SUMA_Engine (&list)) {
11368 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
11369 }
11370
11371 SUMA_RETURNe;
11372 }
11373
11374 /*!
11375 \brief sets the number of smoothing operations to perform on foreground colors
11376 before display
11377 */
SUMA_SetNumForeSmoothing(char * s,void * data)11378 void SUMA_SetNumForeSmoothing (char *s, void *data)
11379 {
11380 static char FuncName[]={"SUMA_SetNumForeSmoothing"};
11381 DList *list=NULL;
11382 SUMA_EngineData *ED = NULL;
11383 SUMA_SurfaceViewer *sv = NULL;
11384 float fv3[3];
11385 SUMA_Boolean LocalHead = NOPE;
11386
11387 SUMA_ENTRY;
11388
11389 if (!s) SUMA_RETURNe;
11390
11391 sv = (SUMA_SurfaceViewer *)data;
11392
11393 /* parse s */
11394 if (SUMA_StringToNum (s, (void *)fv3, 1,1) != 1) {/*problem,beep and ignore */
11395 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
11396 SUMA_RETURNe;
11397 }
11398
11399 /* set sv */
11400
11401 if ((int)fv3[0] < 0) {
11402 SUMA_SLP_Err("Only positive integer\nvalues are valid.\n");
11403 SUMA_RETURNe;
11404 }
11405 SUMAg_CF->X->NumForeSmoothing = (int)fv3[0];
11406
11407 /* flag surfaces for remix */
11408 SUMA_SetAllRemixFlag(SUMAg_SVv, SUMAg_N_SVv);
11409
11410 /* register a redisplay for sv*/
11411 if (!list) list = SUMA_CreateList();
11412 SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_Redisplay_AllVisible,
11413 SES_Suma, sv);
11414 if (!SUMA_Engine (&list)) {
11415 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
11416 }
11417
11418 SUMA_RETURNe;
11419
11420 }
11421
SUMA_SetNumFinalSmoothing(char * s,void * data)11422 void SUMA_SetNumFinalSmoothing (char *s, void *data)
11423 {
11424 static char FuncName[]={"SUMA_SetNumFinalSmoothing"};
11425 DList *list=NULL;
11426 SUMA_EngineData *ED = NULL;
11427 SUMA_SurfaceViewer *sv = NULL;
11428 float fv3[3];
11429 SUMA_Boolean LocalHead = NOPE;
11430
11431 SUMA_ENTRY;
11432
11433 if (!s) SUMA_RETURNe;
11434
11435 sv = (SUMA_SurfaceViewer *)data;
11436
11437 /* parse s */
11438 if (SUMA_StringToNum (s, (void *)fv3, 1,1) != 1) {/*problem,beep and ignore */
11439 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
11440 SUMA_RETURNe;
11441 }
11442
11443 /* set sv */
11444
11445 if ((int)fv3[0] < 0) {
11446 SUMA_SLP_Err("Only positive integer\nvalues are valid.\n");
11447 SUMA_RETURNe;
11448 }
11449 SUMAg_CF->X->NumFinalSmoothing = (int)fv3[0];
11450
11451 /* flag surfaces for remix */
11452 SUMA_SetAllRemixFlag(SUMAg_SVv, SUMAg_N_SVv);
11453
11454 /* register a redisplay for sv*/
11455 if (!list) list = SUMA_CreateList();
11456 SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_Redisplay_AllVisible,
11457 SES_Suma, sv);
11458 if (!SUMA_Engine (&list)) {
11459 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
11460 }
11461
11462 SUMA_RETURNe;
11463
11464 }
11465
11466 /*!
11467 \brief Sets the screen clipping plane
11468
11469 \param s (char *) a strng containing a,b,c,d parameters of plane equation
11470 \param data (void *) a typecast of the pointer to the surface viewer to be affected
11471
11472 */
SUMA_SetScreenClip(char * s,void * data)11473 void SUMA_SetScreenClip (char *s, void *data)
11474 {
11475 SUMA_SetClip(s,(SUMA_SurfaceViewer *)data, SUMA_SCREEN_CLIP);
11476 }
SUMA_SetObjectClip(char * s,void * data)11477 void SUMA_SetObjectClip (char *s, void *data)
11478 {
11479 SUMA_SetClip(s,(SUMA_SurfaceViewer *)data, SUMA_ALL_OBJECT_CLIP);
11480 }
11481
SUMA_SetClip(char * s,SUMA_SurfaceViewer * sv,SUMA_CLIP_PLANE_TYPES tp)11482 void SUMA_SetClip (char *s, SUMA_SurfaceViewer *sv, SUMA_CLIP_PLANE_TYPES tp)
11483 {
11484 static char FuncName[]={"SUMA_SetScreenClip"};
11485 DList *list=NULL;
11486 SUMA_EngineData *ED = NULL;
11487 float fv15[15];
11488 int npar=0;
11489 char *sn;
11490 char namebuf[24];
11491 int itmp, ii, it=0;
11492 DListElmt *NextElm= NULL;
11493 SUMA_Boolean LocalHead = NOPE;
11494
11495 SUMA_ENTRY;
11496
11497 if (!s) {
11498 SUMA_Show_Clip_Planes(SUMAg_CF, NULL);
11499 SUMA_RETURNe;
11500 }
11501
11502 /* Get the name, if any */
11503 if ((sn = strstr(s,":"))) {/* found name */
11504 if (sn - s > 7) {
11505 SUMA_SLP_Err("Plane label too long!");
11506 SUMA_RETURNe;
11507 }
11508 ii=0;
11509 while (s[ii] != ':') { namebuf[ii] = s[ii]; ++ii; }/* copy name */
11510 namebuf[ii] = '\0';
11511 itmp = 0; ++ii;
11512 while (s[ii] != '\0') { s[itmp] = s[ii]; ++ii; ++itmp; } /* copy rest */
11513 s[itmp] = '\0';
11514 /* get the equation */
11515 npar = SUMA_StringToNum (s, (void *)fv15, 4, 1);
11516 if (npar != 4 && npar != 2 && npar != 0) { /* problem, beep and ignore */
11517 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
11518 SUMA_RETURNe;
11519 }
11520 if (npar == 2) { /* the z game */
11521 fv15[2] = fv15[0];
11522 fv15[3] = fv15[1];
11523 fv15[0] = 0.0;
11524 fv15[1] = 0.0;
11525 } else if (npar == 0) { /* the nothing */
11526 fv15[0] = 0.0;
11527 fv15[1] = 0.0;
11528 fv15[2] = 0.0;
11529 fv15[3] = 0.0;
11530 }
11531 }else {
11532 SUMA_SLP_Err("Must provide plane label!");
11533 SUMA_RETURNe;
11534 }
11535
11536
11537 /* register fv15 with ED */
11538 if (!list) list = SUMA_CreateList();
11539 ED = SUMA_InitializeEngineListData (SE_SetClip);
11540 if (!(NextElm = SUMA_RegisterEngineListCommand ( list, ED,
11541 SEF_fv15, (void *)fv15,
11542 SES_Suma, (void *)sv, NOPE,
11543 SEI_Head, NULL ))) {
11544 fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
11545 SUMA_RETURNe;
11546 }
11547 /* register type expected */
11548 it = (int)tp;
11549 if (!(SUMA_RegisterEngineListCommand ( list, ED,
11550 SEF_i, (void*)(&it),
11551 SES_Suma, (void *)sv, NOPE,
11552 SEI_In, NextElm ))) {
11553 fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
11554 SUMA_RETURNe;
11555 }
11556 /* register name of plane */
11557 if (!(SUMA_RegisterEngineListCommand ( list, ED,
11558 SEF_s, (void*)(namebuf),
11559 SES_Suma, (void *)sv, NOPE,
11560 SEI_In, NextElm ))) {
11561 fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
11562 SUMA_RETURNe;
11563 }
11564 if (!SUMA_Engine (&list)) {
11565 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
11566 }
11567
11568 SUMA_RETURNe;
11569 }
11570
11571 /*!
11572 \brief Sets the rotation center
11573
11574 \param s (char *) a strng containing X, Y, Z coordinates
11575 \param data (void *) a typecast of the pointer to the surface viewer to
11576 be affected
11577
11578 NOTE: This is a bit ugly because there is a jump in surface location with
11579 the change in center of rotation. Something also needs updating to keep this
11580 from happening ...
11581 */
11582
SUMA_SetRotCenter(char * s,void * data)11583 void SUMA_SetRotCenter (char *s, void *data)
11584 {
11585 static char FuncName[]={"SUMA_SetRotCenter"};
11586 DList *list=NULL;
11587 SUMA_EngineData *ED = NULL;
11588 SUMA_SurfaceViewer *sv = NULL;
11589 float fv3[3];
11590 SUMA_Boolean LocalHead = NOPE;
11591
11592 SUMA_ENTRY;
11593
11594 sv = (SUMA_SurfaceViewer *)data;
11595 if (!sv) {
11596 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
11597 SUMA_RETURNe;
11598 }
11599
11600 if (!s) {
11601 if (!SUMA_UpdateRotaCenter(sv, SUMAg_DOv, SUMAg_N_DOv)) {
11602 fprintf (SUMA_STDERR,
11603 "Error %s: Failed to update center of rotation", FuncName);
11604 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
11605 SUMA_RETURNe;
11606 }
11607 SUMA_RETURNe;
11608 }
11609
11610 /* parse s */
11611 if (SUMA_StringToNum (s, (void*)fv3, 3,1) != 3) {/*problem, beep and ignore */
11612 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
11613 SUMA_RETURNe;
11614 }
11615
11616 sv->GVS[sv->StdView].RotaCenter[0] = fv3[0];
11617 sv->GVS[sv->StdView].RotaCenter[1] = fv3[1];
11618 sv->GVS[sv->StdView].RotaCenter[2] = fv3[2];
11619
11620
11621 SUMA_RETURNe;
11622 }
11623
11624 /*!
11625 \brief rotates surface to face a certain coordinate
11626
11627 \param s (char *) a strng containing X, Y, Z coordinates
11628 \param data (void *) a typecast of the pointer to the surface viewer to be affected
11629
11630 */
SUMA_LookAtCoordinates(char * s,void * data)11631 void SUMA_LookAtCoordinates (char *s, void *data)
11632 {
11633 static char FuncName[]={"SUMA_LookAtCoordinates"};
11634 DList *list=NULL;
11635 SUMA_EngineData *ED = NULL;
11636 SUMA_SurfaceViewer *sv = NULL;
11637 float fv3[3];
11638 SUMA_Boolean LocalHead = NOPE;
11639
11640 SUMA_ENTRY;
11641
11642 if (!s) SUMA_RETURNe;
11643
11644 sv = (SUMA_SurfaceViewer *)data;
11645
11646 /* parse s */
11647 if (SUMA_StringToNum (s, (void *)fv3, 3,1) != 3) {/*problem,beep and ignore */
11648 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
11649 SUMA_RETURNe;
11650 }
11651
11652 /* register fv3 with ED */
11653 if (!list) list = SUMA_CreateList();
11654 ED = SUMA_InitializeEngineListData (SE_SetLookAt);
11655 if (!SUMA_RegisterEngineListCommand ( list, ED,
11656 SEF_fv3, (void *)fv3,
11657 SES_Suma, (void *)sv, NOPE,
11658 SEI_Head, NULL )) {
11659 fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
11660 SUMA_RETURNe;
11661 }
11662 if (!SUMA_Engine (&list)) {
11663 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
11664 }
11665
11666 SUMA_RETURNe;
11667 }
11668
SUMA_SV_SetRenderOrder(char * s,void * data)11669 void SUMA_SV_SetRenderOrder(char *s, void *data)
11670 {
11671 static char FuncName[]={"SUMA_SV_SetRenderOrder"};
11672 SUMA_SurfaceViewer *sv = NULL;
11673 SUMA_Boolean LocalHead = NOPE;
11674
11675 SUMA_ENTRY;
11676
11677 if (!s) SUMA_RETURNe;
11678
11679 sv = (SUMA_SurfaceViewer *)data;
11680 if (!sv) {
11681 SUMA_S_Err("Null sv");
11682 SUMA_RETURNe;
11683 }
11684
11685 sv->N_otseq = SUMA_SetObjectDisplayOrder(s, sv->otseq);
11686
11687 SUMA_RETURNe;
11688 }
11689
SUMA_JumpIndex(char * s,void * data)11690 void SUMA_JumpIndex (char *s, void *data)
11691 {
11692 static char FuncName[]={"SUMA_JumpIndex"};
11693 SUMA_SurfaceViewer *sv = NULL;
11694 SUMA_ALL_DO *ado=NULL;
11695 char *variant = NULL;
11696 SUMA_Boolean LocalHead = NOPE;
11697
11698 SUMA_ENTRY;
11699
11700 if (!s) SUMA_RETURNe;
11701
11702 sv = (SUMA_SurfaceViewer *)data;
11703 if (!(ado = SUMA_SV_Focus_ADO(sv))) {
11704 SUMA_S_Err("No ado in focus");
11705 SUMA_RETURNe;
11706 }
11707
11708 switch (ado->do_type) {
11709 case SO_type:
11710 SUMA_JumpIndex_SO (s, sv, (SUMA_SurfaceObject *)ado);
11711 break;
11712 case GDSET_type:
11713 SUMA_JumpIndex_GDSET (s, sv, (SUMA_DSET *)ado, variant);
11714 break;
11715 case CDOM_type:
11716 SUMA_JumpIndex_CO (s, sv, (SUMA_CIFTI_DO *)ado);
11717 break;
11718 case GRAPH_LINK_type: {
11719 SUMA_GraphLinkDO *gldo=(SUMA_GraphLinkDO *)ado;
11720 SUMA_DSET *dset=NULL;
11721 if (!(dset=SUMA_find_GLDO_Dset(gldo))) {
11722 SUMA_S_Errv("Failed to find dset for gldo %s!!!\n",
11723 SUMA_ADO_Label(ado));
11724 break;
11725 }
11726 SUMA_JumpIndex_GDSET (s, sv, dset, gldo->variant);
11727 break; }
11728 case TRACT_type: {
11729 SUMA_JumpIndex_TDO (s, sv, (SUMA_TractDO *)ado);
11730 break; }
11731 case MASK_type: {
11732 SUMA_JumpIndex_MDO (s, sv, (SUMA_MaskDO *)ado);
11733 break; }
11734 case VO_type: {
11735 SUMA_JumpIndex_VO (s, sv, (SUMA_VolumeObject *)ado);
11736 break; }
11737 default:
11738 SUMA_S_Errv("For %s nothing my dear\n",
11739 SUMA_ObjectTypeCode2ObjectTypeName(ado->do_type));
11740 break;
11741 }
11742 SUMA_RETURNe;
11743 }
11744
11745 /*!
11746 \brief sends the cross hair to a certain node index
11747 \param s (char *) a string containing node index
11748 \param data (void *) a typecast of the pointer to the surface
11749 viewer to be affected
11750
11751 */
SUMA_JumpIndex_SO(char * s,SUMA_SurfaceViewer * sv,SUMA_SurfaceObject * SO)11752 void SUMA_JumpIndex_SO (char *s, SUMA_SurfaceViewer *sv, SUMA_SurfaceObject *SO)
11753 {
11754 static char FuncName[]={"SUMA_JumpIndex_SO"};
11755 DList *list=NULL;
11756 SUMA_EngineData *ED = NULL;
11757 DListElmt *el=NULL, *Location=NULL;
11758 SUMA_SurfaceObject *SOc=NULL;
11759 SUMA_SO_SIDE sd=SUMA_NO_SIDE;
11760 float fv3[3];
11761 int it, iv3[3];
11762 SUMA_Boolean LocalHead = NOPE;
11763
11764 SUMA_ENTRY;
11765
11766 if (!s || !sv || !SO) SUMA_RETURNe;
11767
11768 /* HERE you should check if you have an L or R at the beginning
11769 or end of s.
11770 If you do, then first see if the side of SO (the focus surface)
11771 is the same as the letter. If it is, proceed. If it is not,
11772 try to get the contralateral surface with SUMA_Contralateral_SO
11773 then set the contralateral as the focus surface, then proceed
11774 with setting the focus node. Needs more work
11775 */
11776 /* parse s */
11777 SUMA_LHv("Parsing %s\n", s);
11778 if (SUMA_StringToNumSide(s, (void*)fv3, 1,1, &sd) != 1) {
11779 /*problem, beep and ignore */
11780 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
11781 SUMA_RETURNe;
11782 }
11783
11784 /* do we have side match with Focus node? */
11785 SUMA_LHv("Side of jump is %d, SO %s side %d\n", sd, SO->Label, SO->Side);
11786 if (sd == SUMA_RIGHT || sd == SUMA_LEFT) {
11787 if ((SO->Side == SUMA_RIGHT || SO->Side == SUMA_LEFT) &&
11788 SO->Side != sd) {
11789 /* Need to swith sides */
11790 if ((SOc = SUMA_Contralateral_SO(SO, SUMAg_DOv, SUMAg_N_DOv))) {
11791 sv->Focus_DO_ID = SUMA_findSO_inDOv(SOc->idcode_str,
11792 SUMAg_DOv, SUMAg_N_DOv);
11793 SUMA_LHv("Jumping to %s (contralateral of %s)\n",
11794 SOc->Label, SO->Label);
11795 SO = SOc;
11796 } else {
11797 SUMA_S_Errv("Failed to find contralateral surface to %s\n"
11798 "Ignoring jump to node's side marker\n",
11799 SO->Label);
11800 }
11801 }
11802 }
11803
11804
11805 /* Set the Nodeselection */
11806 it = (int) fv3[0];
11807 if (!list) list = SUMA_CreateList ();
11808 ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
11809 if (!(el = SUMA_RegisterEngineListCommand ( list, ED,
11810 SEF_i, (void*)(&it),
11811 SES_Suma, (void *)sv, NOPE,
11812 SEI_Head, NULL))) {
11813 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
11814 SUMA_RETURNe;
11815 } else {
11816 SUMA_RegisterEngineListCommand ( list, ED,
11817 SEF_ngr, NULL,
11818 SES_Suma, (void *)sv, NOPE,
11819 SEI_In, el);
11820 }
11821
11822
11823 /* Now set the cross hair position at the selected node*/
11824 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
11825 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
11826 SEF_fv3, (void*)&(SO->NodeList[3*it]),
11827 SES_Suma, (void *)sv, NOPE,
11828 SEI_Head, NULL))) {
11829 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
11830 SUMA_RETURNe;
11831 }
11832 /* and add the SO with this location, needed for VisX business*/
11833 SUMA_RegisterEngineListCommand ( list, ED,
11834 SEF_vp, (void *)SO,
11835 SES_Suma, (void *)sv, NOPE,
11836 SEI_In, Location);
11837
11838 /* attach the cross hair to the selected surface */
11839 iv3[0] = SUMA_findSO_inDOv(SO->idcode_str, SUMAg_DOv, SUMAg_N_DOv);
11840 iv3[1] = it;
11841 iv3[2] = -1;
11842 ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
11843 if (!SUMA_RegisterEngineListCommand ( list, ED,
11844 SEF_iv3, (void*)iv3,
11845 SES_Suma, (void *)sv, NOPE,
11846 SEI_Head, NULL)) {
11847 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
11848 SUMA_RETURNe;
11849 }
11850
11851 /* check to see if AFNI needs to be notified */
11852 if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
11853 if (LocalHead)
11854 fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
11855 /* register a call to SetAfniCrossHair */
11856 it = 0; /* Set to 1 if you want instacorr notice to AFNI */
11857 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
11858 if (!SUMA_RegisterEngineListCommand ( list, ED,
11859 SEF_i, (void*)&it,
11860 SES_Suma, (void *)sv, NOPE,
11861 SEI_Tail, NULL)) {
11862 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
11863 SUMA_RETURNe;
11864 }
11865
11866 }
11867
11868 /* and if GICOR needs some love */
11869 if ( SUMAg_CF->Connected_v[SUMA_GICORR_LINE] &&
11870 SUMAg_CF->giset && !SUMAg_CF->HoldClickCallbacks) {
11871 if (LocalHead)
11872 fprintf(SUMA_STDERR,
11873 "%s: Notifying GICOR of node selection\n", FuncName);
11874 /* register a call to SetGICORnode */
11875 SUMA_REGISTER_TAIL_COMMAND_NO_DATA( list, SE_SetGICORnode,
11876 SES_Suma, sv);
11877 }else {
11878 SUMA_LHv("No Notification to GICOR. %d %p\n",
11879 SUMAg_CF->Connected_v[SUMA_GICORR_LINE], SUMAg_CF->giset);
11880 }
11881
11882 /* call with the list */
11883 if (!SUMA_Engine (&list)) {
11884 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
11885 SUMA_RETURNe;
11886 }
11887
11888 /* now put in a request for locking cross hair but you must do this
11889 after the node selection has been executed
11890 NOTE: You do not always have SetNodeElem because the list might get emptied in
11891 the call to AFNI notification.
11892 You should just put the next call at the end of the list.*/
11893 if (!list) list = SUMA_CreateList();
11894 ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
11895 if (!SUMA_RegisterEngineListCommand ( list, ED,
11896 SEF_iv3, (void*)iv3,
11897 SES_Suma, (void *)sv, NOPE,
11898 SEI_Tail, NULL)) {
11899 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
11900 SUMA_RETURNe;
11901 }
11902
11903 /* call with the list */
11904 if (!SUMA_Engine (&list)) {
11905 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
11906 SUMA_RETURNe;
11907 }
11908
11909 /* redisplay curent only*/
11910 sv->ResetGLStateVariables = YUP;
11911 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
11912
11913 SUMA_RETURNe;
11914
11915 }
11916
11917 /* Jump to a certain edge on a graph dset */
SUMA_JumpIndex_GDSET(char * s,SUMA_SurfaceViewer * sv,SUMA_DSET * dset,char * variant)11918 void SUMA_JumpIndex_GDSET (char *s, SUMA_SurfaceViewer *sv,
11919 SUMA_DSET *dset, char *variant)
11920 {
11921 static char FuncName[]={"SUMA_JumpIndex_GDSET"};
11922 DList *list=NULL;
11923 DListElmt *el=NULL, *Location=NULL;
11924 SUMA_EngineData *ED = NULL;
11925 float fv3[3];
11926 int it, iv3[3];
11927 SUMA_Boolean LocalHead = NOPE;
11928
11929 SUMA_ENTRY;
11930
11931 if (!s || !sv) SUMA_RETURNe;
11932
11933 /* parse s */
11934 SUMA_LHv("Parsing %s\n", s);
11935 if (SUMA_StringToNum(s, (void*)fv3, 1,1) != 1) {
11936 /*problem, beep and ignore */
11937 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
11938 SUMA_RETURNe;
11939 }
11940
11941 /* Set the Nodeselection */
11942 it = (int) fv3[0];
11943 if (!list) list = SUMA_CreateList ();
11944 ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
11945 if (!(el = SUMA_RegisterEngineListCommand ( list, ED,
11946 SEF_i, (void*)(&it),
11947 SES_Suma, (void *)sv, NOPE,
11948 SEI_Head, NULL))) {
11949 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
11950 SUMA_RETURNe;
11951 } else {
11952 SUMA_RegisterEngineListCommand ( list, ED,
11953 SEF_ngr, NULL,
11954 SES_Suma, (void *)sv, NOPE,
11955 SEI_In, el);
11956 }
11957
11958
11959 /* Now set the cross hair position at the selected node*/
11960 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
11961 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
11962 SEF_fv3,
11963 (void*)(SUMA_GDSET_NodeXYZ(dset, it, variant, NULL)),
11964 SES_Suma, (void *)sv, NOPE,
11965 SEI_Head, NULL))) {
11966 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
11967 SUMA_RETURNe;
11968 }
11969 /* and add the object with this location */
11970 SUMA_RegisterEngineListCommand ( list, ED,
11971 SEF_vp, (void *)dset,
11972 SES_Suma, (void *)sv, NOPE,
11973 SEI_In, Location);
11974
11975 /* attach the cross hair to the selected object
11976 Note that binding here is to edge of graph and not to a node*/
11977 SUMA_find_Dset_GLDO(dset,variant, iv3); /* this will set iv3[0] */
11978 iv3[1] = it;
11979 iv3[2] = -1;
11980 ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
11981 if (!SUMA_RegisterEngineListCommand ( list, ED,
11982 SEF_iv3, (void*)iv3,
11983 SES_Suma, (void *)sv, NOPE,
11984 SEI_Head, NULL)) {
11985 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
11986 SUMA_RETURNe;
11987 }
11988
11989 /* check to see if AFNI needs to be notified */
11990 if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
11991 if (LocalHead)
11992 fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
11993 it = 0;
11994 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
11995 if (!SUMA_RegisterEngineListCommand ( list, ED,
11996 SEF_i, (void*)&it,
11997 SES_Suma, (void *)sv, NOPE,
11998 SEI_Tail, NULL)) {
11999 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12000 SUMA_RETURNe;
12001 }
12002
12003 }
12004
12005 /* call with the list */
12006 if (!SUMA_Engine (&list)) {
12007 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12008 SUMA_RETURNe;
12009 }
12010
12011 /* now put in a request for locking cross hair but you must do this
12012 after the node selection has been executed
12013 NOTE: You do not always have SetNodeElem because the list might get emptied in
12014 the call to AFNI notification.
12015 You should just put the next call at the end of the list.*/
12016 if (!list) list = SUMA_CreateList();
12017 ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
12018 if (!SUMA_RegisterEngineListCommand ( list, ED,
12019 SEF_iv3, (void*)iv3,
12020 SES_Suma, (void *)sv, NOPE,
12021 SEI_Tail, NULL)) {
12022 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12023 SUMA_RETURNe;
12024 }
12025
12026 /* call with the list */
12027 if (!SUMA_Engine (&list)) {
12028 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12029 SUMA_RETURNe;
12030 }
12031
12032 /* redisplay curent only*/
12033 sv->ResetGLStateVariables = YUP;
12034 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
12035
12036 SUMA_RETURNe;
12037
12038 }
12039
12040 /* Jump to a certain point on a tract object */
SUMA_JumpIndex_TDO(char * s,SUMA_SurfaceViewer * sv,SUMA_TractDO * tdo)12041 void SUMA_JumpIndex_TDO (char *s, SUMA_SurfaceViewer *sv,
12042 SUMA_TractDO *tdo)
12043 {
12044 static char FuncName[]={"SUMA_JumpIndex_TDO"};
12045 DList *list=NULL;
12046 SUMA_ALL_DO *ado = (SUMA_ALL_DO *)tdo;
12047 DListElmt *el=NULL, *Location=NULL;
12048 SUMA_EngineData *ED = NULL;
12049 float fv3[3];
12050 int it, iv15[15], iv3[3], nv = 0;
12051 char stmp[64];
12052 SUMA_Boolean revert_on_err = YUP;
12053 SUMA_Boolean LocalHead = NOPE;
12054
12055 SUMA_ENTRY;
12056
12057 if (!s || !sv || !tdo || !tdo->net) SUMA_RETURNe;
12058
12059 /* parse s */
12060 if ((nv = SUMA_StringToNum(s, (void*)fv3, 3,1)) != 1 &&
12061 nv != 3) {
12062 /*problem, beep and ignore */
12063 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12064 SUMA_RETURNe;
12065 }
12066 SUMA_LHv("Parsed %s to %d val(s)\n", s, nv);
12067 if (nv == 3) {/* bundle, tract, point */
12068 iv15[SUMA_NET_BUN] = (int)fv3[SUMA_NET_BUN];
12069 iv15[SUMA_BUN_TRC] = (int)fv3[SUMA_BUN_TRC];
12070 iv15[SUMA_TRC_PNT] = (int)fv3[SUMA_TRC_PNT];
12071 iv15[SUMA_NET_TRC] =
12072 Network_TB_to_1T(tdo->net, iv15[SUMA_BUN_TRC], iv15[SUMA_NET_BUN]);
12073 it = Network_PTB_to_1P(tdo->net,
12074 iv15[SUMA_TRC_PNT], iv15[SUMA_BUN_TRC], iv15[SUMA_NET_BUN]);
12075 if (it < 0) { /* no good */
12076 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12077 SUMA_LH("BTP %d %d %d could not be parsed\n",
12078 iv15[SUMA_NET_BUN], iv15[SUMA_BUN_TRC], iv15[SUMA_TRC_PNT]);
12079 if (revert_on_err) {
12080 sprintf(stmp,"%d", SUMA_ADO_SelectedDatum(ado, NULL, NULL));
12081 SUMA_JumpIndex_TDO(stmp, sv, tdo);
12082 }
12083 SUMA_RETURNe;
12084 }
12085 SUMA_LHv("Point ID %d from B%d T%d P%d (tract in net %d)\n",
12086 it, iv15[SUMA_NET_BUN], iv15[SUMA_BUN_TRC],
12087 iv15[SUMA_TRC_PNT], iv15[SUMA_NET_TRC]);
12088 } else {
12089 /* Set the point selection */
12090 it = (int) fv3[0];
12091 if (!Network_1P_to_PTB(tdo->net, it,
12092 iv15+SUMA_TRC_PNT, iv15+SUMA_BUN_TRC,
12093 iv15+SUMA_NET_BUN, iv15+SUMA_NET_TRC)) {
12094 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12095 SUMA_RETURNe;
12096 }
12097 SUMA_LHv("Point ID %d yielded B%d T%d P%d (tract in net %d) \n"
12098 " (which yields back %d)\n",
12099 it, iv15[SUMA_NET_BUN], iv15[SUMA_BUN_TRC], iv15[SUMA_TRC_PNT],
12100 iv15[SUMA_NET_TRC],
12101 Network_PTB_to_1P(tdo->net,
12102 iv15[SUMA_TRC_PNT], iv15[SUMA_BUN_TRC], iv15[SUMA_NET_BUN]));
12103 }
12104
12105 SUMA_TDO_PointXYZ(tdo, it, iv15, fv3);
12106 SUMA_LH(" Located at %f %f %f\n", fv3[0], fv3[1], fv3[2]);
12107
12108 if (!list) list = SUMA_CreateList ();
12109 ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
12110 if (!(el = SUMA_RegisterEngineListCommand ( list, ED,
12111 SEF_i, (void*)(&it),
12112 SES_Suma, (void *)sv, NOPE,
12113 SEI_Head, NULL))) {
12114 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12115 SUMA_RETURNe;
12116 } else {
12117 SUMA_RegisterEngineListCommand ( list, ED,
12118 SEF_ngr, NULL,
12119 SES_Suma, (void *)sv, NOPE,
12120 SEI_In, el);
12121 SUMA_RegisterEngineListCommand ( list, ED,
12122 SEF_iv15, (void *)iv15,
12123 SES_Suma, (void *)sv, NOPE,
12124 SEI_In, el);
12125 }
12126
12127
12128 /* Now set the cross hair position at the selected point*/
12129 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
12130 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
12131 SEF_fv3, (void*)fv3,
12132 SES_Suma, (void *)sv, NOPE,
12133 SEI_Head, NULL))) {
12134 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12135 SUMA_RETURNe;
12136 }
12137 /* and add the DO with this location, needed for VisX business*/
12138 SUMA_RegisterEngineListCommand ( list, ED,
12139 SEF_vp, (void *)tdo,
12140 SES_Suma, (void *)sv, NOPE,
12141 SEI_In, Location);
12142
12143 /* attach the cross hair to the selected object
12144 Note that binding here is to edge of graph and not to a node*/
12145 iv3[0] = SUMA_whichDO(SUMA_ADO_idcode(ado), SUMAg_DOv, SUMAg_N_DOv);
12146 iv3[1] = it;
12147 iv3[2] = -1;
12148 ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
12149 if (!SUMA_RegisterEngineListCommand ( list, ED,
12150 SEF_iv3, (void*)iv3,
12151 SES_Suma, (void *)sv, NOPE,
12152 SEI_Head, NULL)) {
12153 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12154 SUMA_RETURNe;
12155 }
12156
12157 /* check to see if AFNI needs to be notified */
12158 if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
12159 if (LocalHead)
12160 fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
12161 it = 0;
12162 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
12163 if (!SUMA_RegisterEngineListCommand ( list, ED,
12164 SEF_i, (void*)&it,
12165 SES_Suma, (void *)sv, NOPE,
12166 SEI_Tail, NULL)) {
12167 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12168 SUMA_RETURNe;
12169 }
12170
12171 }
12172
12173 /* call with the list */
12174 if (!SUMA_Engine (&list)) {
12175 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12176 SUMA_RETURNe;
12177 }
12178
12179 /* now put in a request for locking cross hair but you must do this
12180 after the node selection has been executed
12181 NOTE: You do not always have SetNodeElem because the list might get emptied in
12182 the call to AFNI notification.
12183 You should just put the next call at the end of the list.*/
12184 if (!list) list = SUMA_CreateList();
12185 ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
12186 if (!SUMA_RegisterEngineListCommand ( list, ED,
12187 SEF_iv3, (void*)iv3,
12188 SES_Suma, (void *)sv, NOPE,
12189 SEI_Tail, NULL)) {
12190 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12191 SUMA_RETURNe;
12192 }
12193
12194 /* call with the list */
12195 if (!SUMA_Engine (&list)) {
12196 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12197 SUMA_RETURNe;
12198 }
12199
12200 /* redisplay curent only*/
12201 sv->ResetGLStateVariables = YUP;
12202 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
12203
12204 SUMA_RETURNe;
12205
12206 }
12207
12208 /* Jump to a certain datum on a CIFTI object */
SUMA_JumpIndex_CO(char * s,SUMA_SurfaceViewer * sv,SUMA_CIFTI_DO * co)12209 void SUMA_JumpIndex_CO (char *s, SUMA_SurfaceViewer *sv,
12210 SUMA_CIFTI_DO *co)
12211 {
12212 static char FuncName[]={"SUMA_JumpIndex_CO"};
12213 DList *list=NULL;
12214 SUMA_ALL_DO *ado = (SUMA_ALL_DO *)co;
12215 DListElmt *el=NULL, *Location=NULL;
12216 SUMA_EngineData *ED = NULL;
12217 float fv3[3], fv15[15];
12218 int it, iv15[15], iv3[3], nv = 0, *dims=NULL;
12219 char stmp[64];
12220 SUMA_DSET *dset=NULL;
12221 SUMA_Boolean revert_on_err = YUP;
12222 SUMA_Boolean LocalHead = NOPE;
12223
12224 SUMA_ENTRY;
12225
12226 SUMA_LH("Called");
12227
12228 SUMA_S_Err("Not implemented, see SUMA_JumpIndex_VO and SUMA_JumpIndex_SO "
12229 "for inspiration. You will need to determine the domain of "
12230 "the index before jumping anyway");
12231
12232 SUMA_RETURNe;
12233 }
12234
12235 /* Jump to a certain point on a volume object */
SUMA_JumpIndex_VO(char * s,SUMA_SurfaceViewer * sv,SUMA_VolumeObject * vo)12236 void SUMA_JumpIndex_VO (char *s, SUMA_SurfaceViewer *sv,
12237 SUMA_VolumeObject *vo)
12238 {
12239 static char FuncName[]={"SUMA_JumpIndex_VO"};
12240 DList *list=NULL;
12241 SUMA_ALL_DO *ado = (SUMA_ALL_DO *)vo;
12242 DListElmt *el=NULL, *Location=NULL;
12243 SUMA_EngineData *ED = NULL;
12244 float fv3[3], fv15[15];
12245 int it, iv15[15], iv3[3], nv = 0, *dims=NULL;
12246 char stmp[64];
12247 SUMA_DSET *dset=NULL;
12248 SUMA_Boolean revert_on_err = YUP;
12249 SUMA_Boolean LocalHead = NOPE;
12250
12251 SUMA_ENTRY;
12252
12253 SUMA_LH("Called");
12254 if (!s || !sv || !vo ||
12255 !(dset = SUMA_VO_dset(vo)) ||
12256 !(dims = SUMA_GetDatasetDimensions(dset))) SUMA_RETURNe;
12257
12258 /* parse s */
12259 if ((nv = SUMA_StringToNum(s, (void*)fv3, 3,1)) != 1 &&
12260 nv != 3) {
12261 /*problem, beep and ignore */
12262 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12263 SUMA_RETURNe;
12264 }
12265 SUMA_LHv("Parsed %s to %d val(s)\n", s, nv);
12266 if (nv == 3) {/* i j k */
12267 iv15[SUMA_VOL_I] = (int)fv3[SUMA_VOL_I];
12268 iv15[SUMA_VOL_J] = (int)fv3[SUMA_VOL_J];
12269 iv15[SUMA_VOL_K] = (int)fv3[SUMA_VOL_K];
12270 if (iv15[SUMA_VOL_I] < 0 || iv15[SUMA_VOL_I] >= dims[0] ||
12271 iv15[SUMA_VOL_J] < 0 || iv15[SUMA_VOL_J] >= dims[1] ||
12272 iv15[SUMA_VOL_K] < 0 || iv15[SUMA_VOL_K] >= dims[2] ) {
12273 /* no good */
12274 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12275 SUMA_LH("IJK %d %d %d could not be parsed or out of range\n",
12276 iv15[SUMA_VOL_I], iv15[SUMA_VOL_J], iv15[SUMA_VOL_K]);
12277 if (revert_on_err) {
12278 sprintf(stmp,"%d", SUMA_ADO_SelectedDatum(ado, NULL, NULL));
12279 SUMA_JumpIndex_VO(stmp, sv, vo);
12280 }
12281 SUMA_RETURNe;
12282 }
12283
12284 iv15[SUMA_VOL_IJK] =
12285 SUMA_3D_2_1D_index(iv15[SUMA_VOL_I], iv15[SUMA_VOL_J], iv15[SUMA_VOL_K],
12286 dims[0], dims[0]*dims[1] );
12287
12288 it = iv15[SUMA_VOL_IJK];
12289
12290 SUMA_LHv("Voxel ID %d from I%d J%d K%d\n",
12291 iv15[SUMA_VOL_IJK], iv15[SUMA_VOL_I], iv15[SUMA_VOL_J],
12292 iv15[SUMA_VOL_K]);
12293 } else {
12294 /* Set the point selection */
12295 it = (int) fv3[0];
12296 if (it < 0 || it >= SDSET_NVOX(dset)) {
12297 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12298 SUMA_RETURNe;
12299 }
12300 Vox1D2Vox3D(it, dims[0], dims[0]*dims[1], (iv15+SUMA_VOL_I));
12301 SUMA_LHv("Point ID %d yielded I%d J%d K%d \n",
12302 it, iv15[SUMA_VOL_I], iv15[SUMA_VOL_J], iv15[SUMA_VOL_K]);
12303 }
12304
12305 SUMA_VO_PointXYZ(vo, it, iv15, fv3);
12306 SUMA_LH(" Located at %f %f %f\n", fv3[0], fv3[1], fv3[2]);
12307 SUMA_MARK_PLANE_NOT_SET(fv15+SUMA_VOL_SLC_EQ0); /* No cigar */
12308
12309 if (!list) list = SUMA_CreateList ();
12310 ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
12311 if (!(el = SUMA_RegisterEngineListCommand ( list, ED,
12312 SEF_i, (void*)(&it),
12313 SES_Suma, (void *)sv, NOPE,
12314 SEI_Head, NULL))) {
12315 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12316 SUMA_RETURNe;
12317 } else {
12318 SUMA_RegisterEngineListCommand ( list, ED,
12319 SEF_ngr, NULL,
12320 SES_Suma, (void *)sv, NOPE,
12321 SEI_In, el);
12322 SUMA_RegisterEngineListCommand ( list, ED,
12323 SEF_iv15, (void *)iv15,
12324 SES_Suma, (void *)sv, NOPE,
12325 SEI_In, el);
12326 SUMA_RegisterEngineListCommand ( list, ED,
12327 SEF_fv15, (void *)fv15,
12328 SES_Suma, (void *)sv, NOPE,
12329 SEI_In, el);
12330 }
12331
12332
12333 /* Now set the cross hair position at the selected point*/
12334 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
12335 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
12336 SEF_fv3, (void*)fv3,
12337 SES_Suma, (void *)sv, NOPE,
12338 SEI_Head, NULL))) {
12339 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12340 SUMA_RETURNe;
12341 }
12342 /* and add the DO with this location, needed for VisX business*/
12343 SUMA_RegisterEngineListCommand ( list, ED,
12344 SEF_vp, (void *)vo,
12345 SES_Suma, (void *)sv, NOPE,
12346 SEI_In, Location);
12347
12348 /* attach the cross hair to the selected object
12349 Note that binding here is to edge of graph and not to a node*/
12350 iv3[0] = SUMA_whichDO(SUMA_ADO_idcode(ado), SUMAg_DOv, SUMAg_N_DOv);
12351 iv3[1] = it;
12352 iv3[2] = -1;
12353 ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
12354 if (!SUMA_RegisterEngineListCommand ( list, ED,
12355 SEF_iv3, (void*)iv3,
12356 SES_Suma, (void *)sv, NOPE,
12357 SEI_Head, NULL)) {
12358 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12359 SUMA_RETURNe;
12360 }
12361
12362 /* check to see if AFNI needs to be notified */
12363 if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
12364 if (LocalHead)
12365 fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
12366 it = 0;
12367 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
12368 if (!SUMA_RegisterEngineListCommand ( list, ED,
12369 SEF_i, (void*)&it,
12370 SES_Suma, (void *)sv, NOPE,
12371 SEI_Tail, NULL)) {
12372 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12373 SUMA_RETURNe;
12374 }
12375
12376 }
12377
12378 /* call with the list */
12379 if (!SUMA_Engine (&list)) {
12380 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12381 SUMA_RETURNe;
12382 }
12383
12384 /* now put in a request for locking cross hair but you must do this
12385 after the node selection has been executed
12386 NOTE: You do not always have SetNodeElem because the list might get emptied in
12387 the call to AFNI notification.
12388 You should just put the next call at the end of the list.*/
12389 if (!list) list = SUMA_CreateList();
12390 ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
12391 if (!SUMA_RegisterEngineListCommand ( list, ED,
12392 SEF_iv3, (void*)iv3,
12393 SES_Suma, (void *)sv, NOPE,
12394 SEI_Tail, NULL)) {
12395 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12396 SUMA_RETURNe;
12397 }
12398
12399 /* call with the list */
12400 if (!SUMA_Engine (&list)) {
12401 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12402 SUMA_RETURNe;
12403 }
12404
12405 /* redisplay curent only*/
12406 sv->ResetGLStateVariables = YUP;
12407 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
12408
12409 SUMA_RETURNe;
12410
12411 }
12412
12413 /* Jump to a certain point on a mask object */
SUMA_JumpIndex_MDO(char * s,SUMA_SurfaceViewer * sv,SUMA_MaskDO * mo)12414 void SUMA_JumpIndex_MDO (char *s, SUMA_SurfaceViewer *sv, SUMA_MaskDO *mo)
12415 {
12416 static char FuncName[]={"SUMA_JumpIndex_MDO"};
12417 DList *list=NULL;
12418 SUMA_ALL_DO *ado = (SUMA_ALL_DO *)mo;
12419 DListElmt *el=NULL, *Location=NULL;
12420 SUMA_EngineData *ED = NULL;
12421 float fv3[3];
12422 int it, iv15[15], iv3[3], nv = 0, *dims=NULL;
12423 char stmp[64];
12424 SUMA_DSET *dset=NULL;
12425 SUMA_Boolean revert_on_err = YUP;
12426 SUMA_Boolean LocalHead = NOPE;
12427
12428 SUMA_ENTRY;
12429
12430 if (!s || !sv) SUMA_RETURNe;
12431
12432 SUMA_S_Err("Not ready for action");
12433 SUMA_RETURNe;
12434
12435 /* parse s */
12436 if ((nv = SUMA_StringToNum(s, (void*)fv3, 3,1)) != 1 &&
12437 nv != 3) {
12438 /*problem, beep and ignore */
12439 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12440 SUMA_RETURNe;
12441 }
12442 SUMA_LHv("Parsed %s to %d val(s)\n", s, nv);
12443 if (nv == 3) {/* i j k */
12444 iv15[SUMA_VOL_I] = (int)fv3[SUMA_VOL_I];
12445 iv15[SUMA_VOL_J] = (int)fv3[SUMA_VOL_J];
12446 iv15[SUMA_VOL_K] = (int)fv3[SUMA_VOL_K];
12447 if (iv15[SUMA_VOL_I] < 0 || iv15[SUMA_VOL_I] >= dims[0] ||
12448 iv15[SUMA_VOL_J] < 0 || iv15[SUMA_VOL_J] >= dims[1] ||
12449 iv15[SUMA_VOL_K] < 0 || iv15[SUMA_VOL_K] >= dims[2] ) {
12450 /* no good */
12451 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12452 SUMA_LH("IJK %d %d %d could not be parsed or out of range\n",
12453 iv15[SUMA_VOL_I], iv15[SUMA_VOL_J], iv15[SUMA_VOL_K]);
12454 if (revert_on_err) {
12455 sprintf(stmp,"%d", SUMA_ADO_SelectedDatum(ado, NULL, NULL));
12456 SUMA_JumpIndex_MDO(stmp, sv, mo);
12457 }
12458 SUMA_RETURNe;
12459 }
12460
12461 iv15[SUMA_VOL_IJK] =
12462 SUMA_3D_2_1D_index(iv15[SUMA_VOL_I], iv15[SUMA_VOL_J], iv15[SUMA_VOL_K],
12463 dims[0], dims[0]*dims[1] );
12464
12465
12466 SUMA_LHv("Voxel ID %d from I%d J%d K%d\n",
12467 iv15[SUMA_VOL_IJK], iv15[SUMA_VOL_I], iv15[SUMA_VOL_J],
12468 iv15[SUMA_VOL_K]);
12469 } else {
12470 /* Set the point selection */
12471 it = (int) fv3[0];
12472 if (it < 0 || it >= SDSET_NVOX(dset)) {
12473 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12474 SUMA_RETURNe;
12475 }
12476 Vox1D2Vox3D(it, dims[0], dims[0]*dims[1], (iv15+SUMA_VOL_I));
12477 SUMA_LHv("Point ID %d yielded I%d J%d K%d \n",
12478 it, iv15[SUMA_VOL_I], iv15[SUMA_VOL_J], iv15[SUMA_VOL_K]);
12479 }
12480
12481 SUMA_MDO_PointXYZ(mo, it, iv15, fv3);
12482 SUMA_LH(" Located at %f %f %f\n", fv3[0], fv3[1], fv3[2]);
12483
12484 if (!list) list = SUMA_CreateList ();
12485 ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
12486 if (!(el = SUMA_RegisterEngineListCommand ( list, ED,
12487 SEF_i, (void*)(&it),
12488 SES_Suma, (void *)sv, NOPE,
12489 SEI_Head, NULL))) {
12490 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12491 SUMA_RETURNe;
12492 } else {
12493 SUMA_RegisterEngineListCommand ( list, ED,
12494 SEF_ngr, NULL,
12495 SES_Suma, (void *)sv, NOPE,
12496 SEI_In, el);
12497 SUMA_RegisterEngineListCommand ( list, ED,
12498 SEF_iv15, (void *)iv15,
12499 SES_Suma, (void *)sv, NOPE,
12500 SEI_In, el);
12501 }
12502
12503
12504 /* Now set the cross hair position at the selected point*/
12505 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
12506 if (!(Location=SUMA_RegisterEngineListCommand ( list, ED,
12507 SEF_fv3, (void*)fv3,
12508 SES_Suma, (void *)sv, NOPE,
12509 SEI_Head, NULL))) {
12510 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12511 SUMA_RETURNe;
12512 }
12513 /* and add the DO with this location, needed for VisX business*/
12514 SUMA_RegisterEngineListCommand ( list, ED,
12515 SEF_vp, (void *)mo,
12516 SES_Suma, (void *)sv, NOPE,
12517 SEI_In, Location);
12518
12519 /* attach the cross hair to the selected object
12520 Note that binding here is to edge of graph and not to a node*/
12521 iv3[0] = SUMA_whichDO(SUMA_ADO_idcode(ado), SUMAg_DOv, SUMAg_N_DOv);
12522 iv3[1] = it;
12523 iv3[2] = -1;
12524 ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
12525 if (!SUMA_RegisterEngineListCommand ( list, ED,
12526 SEF_iv3, (void*)iv3,
12527 SES_Suma, (void *)sv, NOPE,
12528 SEI_Head, NULL)) {
12529 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12530 SUMA_RETURNe;
12531 }
12532
12533 /* check to see if AFNI needs to be notified */
12534 if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
12535 if (LocalHead)
12536 fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
12537 it = 0;
12538 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
12539 if (!SUMA_RegisterEngineListCommand ( list, ED,
12540 SEF_i, (void*)&it,
12541 SES_Suma, (void *)sv, NOPE,
12542 SEI_Tail, NULL)) {
12543 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12544 SUMA_RETURNe;
12545 }
12546
12547 }
12548
12549 /* call with the list */
12550 if (!SUMA_Engine (&list)) {
12551 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12552 SUMA_RETURNe;
12553 }
12554
12555 /* now put in a request for locking cross hair but you must do this
12556 after the node selection has been executed
12557 NOTE: You do not always have SetNodeElem because the list might get emptied in
12558 the call to AFNI notification.
12559 You should just put the next call at the end of the list.*/
12560 if (!list) list = SUMA_CreateList();
12561 ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
12562 if (!SUMA_RegisterEngineListCommand ( list, ED,
12563 SEF_iv3, (void*)iv3,
12564 SES_Suma, (void *)sv, NOPE,
12565 SEI_Tail, NULL)) {
12566 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12567 SUMA_RETURNe;
12568 }
12569
12570 /* call with the list */
12571 if (!SUMA_Engine (&list)) {
12572 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12573 SUMA_RETURNe;
12574 }
12575
12576 /* redisplay curent only*/
12577 sv->ResetGLStateVariables = YUP;
12578 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
12579
12580 SUMA_RETURNe;
12581
12582 }
12583
12584 /*!
12585 \brief sends the cross hair to a certain XYZ location.
12586
12587 \param s (char *) a string containing XYZ coordinates
12588 \param data (void *) a typecast of the pointer to the surface viewer to be affected
12589
12590 - Update to AFNI is done if linked
12591 - Update to other viewers is performed IF they are XYZ locked
12592 (that can get confusing)
12593 */
SUMA_JumpXYZ(char * s,void * data)12594 void SUMA_JumpXYZ (char *s, void *data)
12595 {
12596 static char FuncName[]={"SUMA_JumpXYZ"};
12597 DList *list=NULL;
12598 DListElmt *Location=NULL;
12599 SUMA_EngineData *ED = NULL;
12600 SUMA_SurfaceViewer *sv = NULL;
12601 float fv3[3];
12602 SUMA_Boolean LocalHead = NOPE;
12603
12604 SUMA_ENTRY;
12605
12606 if (!s) SUMA_RETURNe;
12607
12608 sv = (SUMA_SurfaceViewer *)data;
12609
12610 /* parse s */
12611 if (SUMA_StringToNum (s, (void*)fv3, 3,1) != 3) {/*problem, beep and ignore */
12612 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12613 SUMA_RETURNe;
12614 }
12615
12616 /* Now set the cross hair position */
12617 if (!list) list = SUMA_CreateList ();
12618 ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
12619 if (!(Location = SUMA_RegisterEngineListCommand ( list, ED,
12620 SEF_fv3, (void*)fv3,
12621 SES_Suma, (void *)sv, NOPE,
12622 SEI_Head, NULL))) {
12623 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12624 SUMA_RETURNe;
12625 }
12626 /* and add the SO with this location (not possible here), needed for VisX
12627 business*/
12628 SUMA_RegisterEngineListCommand ( list, ED,
12629 SEF_vp, NULL,
12630 SES_Suma, (void *)sv, NOPE,
12631 SEI_In, Location);
12632
12633 /* check to see if AFNI needs to be notified */
12634 if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && sv->LinkAfniCrossHair) {
12635 int it;
12636 if (LocalHead)
12637 fprintf(SUMA_STDERR,"%s: Notifying Afni of CrossHair XYZ\n", FuncName);
12638 it = 0;
12639 ED = SUMA_InitializeEngineListData (SE_SetAfniCrossHair);
12640 if (!SUMA_RegisterEngineListCommand ( list, ED,
12641 SEF_i, (void*)&it,
12642 SES_Suma, (void *)sv, NOPE,
12643 SEI_Tail, NULL)) {
12644 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12645 SUMA_RETURNe;
12646 }
12647
12648 }
12649
12650 /* call with the list */
12651 if (!SUMA_Engine (&list)) {
12652 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12653 SUMA_RETURNe;
12654 }
12655
12656 /* now put in a request for locking cross hair but you must
12657 do this after the node selection has been executed
12658 NOTE: You do not always have SetNodeElem because the list might
12659 get emptied in the call to AFNI notification.
12660 You should just put the next call at the end of the list.*/
12661 /* NOTE2: Only viewers that are XYZ locked will be affected */
12662 if (!list) list = SUMA_CreateList();
12663 ED = SUMA_InitializeEngineListData (SE_LockCrossHair);
12664 if (!SUMA_RegisterEngineListCommand ( list, ED,
12665 SEF_Empty, NULL,
12666 SES_Suma, (void *)sv, NOPE,
12667 SEI_Tail, NULL)) {
12668 SUMA_SLP_Err("Failed to register element");
12669 SUMA_RETURNe;
12670 }
12671
12672 /* call with the list */
12673 if (!SUMA_Engine (&list)) {
12674 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12675 SUMA_RETURNe;
12676 }
12677
12678
12679 /* redisplay curent only*/
12680 sv->ResetGLStateVariables = YUP;
12681 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
12682
12683 SUMA_RETURNe;
12684 }
12685
12686 /*!
12687 \brief Changes the focus node without moving the cross hair
12688 \param s (char *) a string containing node index
12689 \param data (void *) a typecast of the pointer to the surface viewer to be affected
12690
12691 -actions of this function are limited to the viewer that launched it
12692 */
12693
SUMA_JumpFocusNode(char * s,void * data)12694 void SUMA_JumpFocusNode (char *s, void *data)
12695 {
12696 static char FuncName[]={"SUMA_JumpFocusNode"};
12697 DList *list=NULL;
12698 DListElmt *el=NULL;
12699 SUMA_EngineData *ED = NULL;
12700 SUMA_SurfaceViewer *sv = NULL;
12701 float fv3[3];
12702 int it;
12703 SUMA_SurfaceObject *SO=NULL, *SOc=NULL;
12704 SUMA_SO_SIDE sd=SUMA_NO_SIDE;
12705 SUMA_Boolean LocalHead = NOPE;
12706
12707 SUMA_ENTRY;
12708
12709 if (!s) SUMA_RETURNe;
12710
12711 sv = (SUMA_SurfaceViewer *)data;
12712 if (!(SO = SUMA_SV_Focus_SO(sv))) {
12713 SUMA_S_Err("No SO in focus");
12714 SUMA_RETURNe;
12715 }
12716
12717
12718 /* HERE you should check if you have an L or R at the beginning
12719 or end of s.
12720 If you do, then first see if the side of SO (the focus surface)
12721 is the same as the letter. If it is, proceed. If it is not,
12722 try to get the contralateral surface with SUMA_Contralateral_SO
12723 then set the contralateral as the focus surface, then proceed
12724 with setting the focus node. Needs more work
12725 */
12726 /* parse s */
12727 SUMA_LHv("Parsing %s\n", s);
12728 if (SUMA_StringToNumSide(s, (void*)fv3, 1,1, &sd) != 1) {
12729 /*problem, beep and ignore */
12730 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12731 SUMA_RETURNe;
12732 }
12733
12734 SUMA_LHv("Side of focus jump is %d\n", sd);
12735 /* do we have side match with Focus node? */
12736 if (sd == SUMA_RIGHT || sd == SUMA_LEFT) {
12737 if ((SO->Side == SUMA_RIGHT || SO->Side == SUMA_LEFT) &&
12738 SO->Side != sd) {
12739 /* Need to swith sides */
12740 if ((SOc = SUMA_Contralateral_SO(SO, SUMAg_DOv, SUMAg_N_DOv))) {
12741 sv->Focus_DO_ID = SUMA_findSO_inDOv(SOc->idcode_str,
12742 SUMAg_DOv, SUMAg_N_DOv);
12743 SUMA_LHv("Jumping focus only to %s (contralateral of %s)\n",
12744 SOc->Label, SO->Label);
12745 SO = SOc;
12746 } else {
12747 SUMA_S_Errv("Failed to find contralateral surface to %s\n"
12748 "Ignoring jump to node's side marker\n",
12749 SO->Label);
12750 }
12751 }
12752 }
12753 /* Set the Nodeselection */
12754 it = (int) fv3[0];
12755 if (!list) list = SUMA_CreateList ();
12756 ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
12757 if (!(el=SUMA_RegisterEngineListCommand ( list, ED,
12758 SEF_i, (void*)(&it),
12759 SES_Suma, (void *)sv, NOPE,
12760 SEI_Head, NULL))) {
12761 SUMA_SLP_Err("Failed to register element");
12762 SUMA_RETURNe;
12763 } else {
12764 SUMA_RegisterEngineListCommand ( list, ED,
12765 SEF_ngr, NULL,
12766 SES_Suma, (void *)sv, NOPE,
12767 SEI_In, el);
12768 }
12769
12770 /* call with the list */
12771 if (!SUMA_Engine (&list)) {
12772 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12773 SUMA_RETURNe;
12774 }
12775
12776 /* redisplay curent only*/
12777 sv->ResetGLStateVariables = YUP;
12778 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
12779
12780 SUMA_RETURNe;
12781
12782 }
12783
12784 /*!
12785 \brief changes the selected faceset (Focus FaceSet)
12786 \param s (char *) a string containing FaceSet index
12787 \param data (void *) a typecast of the pointer to the surface viewer to be affected
12788
12789 */
SUMA_JumpFocusFace(char * s,void * data)12790 void SUMA_JumpFocusFace (char *s, void *data)
12791 {
12792 static char FuncName[]={"SUMA_JumpFocusFace"};
12793 DList *list=NULL;
12794 SUMA_EngineData *ED = NULL;
12795 SUMA_SurfaceViewer *sv = NULL;
12796 float fv3[3];
12797 int it;
12798
12799 SUMA_ENTRY;
12800
12801 if (!s) SUMA_RETURNe;
12802
12803 sv = (SUMA_SurfaceViewer *)data;
12804
12805 /* parse s */
12806 if (SUMA_StringToNum (s, (void*)fv3, 1,1) != 1) {/*problem, beep and ignore */
12807 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12808 SUMA_RETURNe;
12809 }
12810
12811
12812
12813 /* Set the Faceselection */
12814 it = (int) fv3[0];
12815 if (!list) list = SUMA_CreateList ();
12816 ED = SUMA_InitializeEngineListData (SE_SetSelectedFaceSet);
12817 if (!SUMA_RegisterEngineListCommand ( list, ED,
12818 SEF_i, (void*)&it,
12819 SES_Suma, (void *)sv, NOPE,
12820 SEI_Head, NULL)) {
12821 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12822 SUMA_RETURNe;
12823 }
12824
12825 /* call with the list */
12826 if (!SUMA_Engine (&list)) {
12827 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12828 SUMA_RETURNe;
12829 }
12830
12831 /* redisplay curent only*/
12832 sv->ResetGLStateVariables = YUP;
12833 SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
12834
12835 SUMA_RETURNe;
12836
12837 }
12838
12839 /*!
12840 \brief Highlight a set of nodes within a box
12841 \param s (char *) a string containing box center followed by box size (6 values)
12842 \param data (void *) a typecast of the pointer to the surface viewer to be affected
12843
12844 - operates by coloring nodes inside box.
12845 - coloring is not permanent and modifies other colors already present
12846 - operates on current viewer only
12847 */
SUMA_HighlightBox(char * s,void * data)12848 void SUMA_HighlightBox (char *s, void *data)
12849 {
12850 static char FuncName[]={"SUMA_HighlightBox"};
12851 DList *list=NULL;
12852 SUMA_EngineData *ED = NULL;
12853 SUMA_SurfaceViewer *sv = NULL;
12854 float fv15[15];
12855
12856 SUMA_ENTRY;
12857
12858 if (!s) SUMA_RETURNe;
12859
12860 sv = (SUMA_SurfaceViewer *)data;
12861
12862 /* parse s */
12863 if (SUMA_StringToNum (s, (void*)fv15, 6,1) != 6) {
12864 /*problem, beep and ignore */
12865 XBell (XtDisplay (sv->X->TOPLEVEL), 50);
12866 SUMA_RETURNe;
12867 }
12868
12869 /* register fv15 with ED */
12870 if (!list) list = SUMA_CreateList();
12871 ED = SUMA_InitializeEngineListData (SE_HighlightNodes);
12872 if (!SUMA_RegisterEngineListCommand ( list, ED,
12873 SEF_fv15, (void*)fv15,
12874 SES_Suma, (void *)sv, NOPE,
12875 SEI_Head, NULL)) {
12876 fprintf(SUMA_STDERR,"Error %s: Failed to register element\n", FuncName);
12877 SUMA_RETURNe;
12878 }
12879
12880 SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay, SES_Suma, sv);
12881
12882 if (!SUMA_Engine (&list)) {
12883 fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
12884 }
12885
12886
12887 SUMA_RETURNe;
12888
12889 }
12890