1 #include "SUMA_suma.h"
2 
3 /**************************************/
4 /** global data for NIML connections **/
5 /**************************************/
6 extern int SUMAg_N_DOv;
7 extern SUMA_DO *SUMAg_DOv;
8 extern SUMA_CommonFields *SUMAg_CF;
9 extern SUMA_SurfaceViewer *SUMAg_SVv;
10 extern int SUMAg_N_SVv;
11 
12 /*-----------------------------------------------*/
SUMA_freep(void * p)13 void SUMA_freep( void *p ){ free(p) ; return ; }  /* RWC: 07 Oct 2015 */
14 /*-----------------------------------------------*/
15 
16 /*-----------------------------------------------*/
17 /*! Flag to tell if NIML things are initialized. */
18 
19 static int started = 0 ;
20 static int dsq = 0;
21 
SUMA_init_ports_assignments(SUMA_CommonFields * cf)22 int SUMA_init_ports_assignments(SUMA_CommonFields *cf)
23 {
24    static char FuncName[]={"SUMA_init_ports_assignments"};
25    int i;
26    float dsmw = 5*60, dsmwc = 5;
27    char *eee=NULL;
28 
29    SUMA_ENTRY;
30 
31    if (cf->TCP_port[0]) {
32       SUMA_S_Warn("Looks like ports have been initialized. Returning.");
33       SUMA_RETURN(YUP);
34    }
35 
36    eee = getenv("SUMA_DriveSumaMaxWait");
37    if (eee) {
38       dsmw = atof(eee);
39       if (dsmw < 0 || dsmw > 60000) {
40          SUMA_S_Warnv(
41                 "Environment variable SUMA_DriveSumaMaxWait %f is invalid.\n"
42                 "value must be between 0 and 60000 seconds.\n"
43                 "Using default of %d\n",
44                 dsmw, 5*60);
45          dsmw = (float)5*60;/* wait for 5 minutes */
46       }
47    } else {
48       dsmw = (float)5*60;
49    }
50    eee = getenv("SUMA_DriveSumaMaxCloseWait");
51    if (eee) {
52       dsmwc = atof(eee);
53       if (dsmwc < 0 || dsmwc > 60000) {
54          SUMA_S_Warnv(
55                "Environment variable SUMA_DriveSumaMaxCloseWait %f is invalid.\n"
56                 "value must be between 0 and 60000 seconds.\n"
57                 "Using default of %d\n",
58                 dsmwc, 5);
59          dsmwc = (float)5;/* wait for 5 secs */
60       }
61    } else {
62       dsmwc = (float)5;
63    }
64    if (SUMA_isEnv("SUMA_DriveSumaQuiet","y")) dsq = 1;
65    else dsq = 0;
66 
67 
68 
69    for (i=0; i<SUMA_MAX_STREAMS; ++i) {
70       cf->ns_v[i] = NULL;
71       switch(i) { /* set time out */
72          case SUMA_GICORR_LINE:
73          case SUMA_DRIVESUMA_LINE:
74             cf->ns_to[i] = (int)(dsmw*1000);
75             cf->ns_toc[i] = (int)(dsmwc*1000);
76             break;
77          default:
78             cf->ns_to[i] = SUMA_WRITECHECKWAITMAX;
79             cf->ns_toc[i] = (int)(SUMA_WRITECHECKWAITMAX*1000);
80             break;
81       }
82       cf->ns_flags_v[i] = 0;
83       cf->Connected_v[i] = NOPE;
84       cf->TrackingId_v[i] = 0;
85       cf->NimlStream_v[i][0] = '\0';
86       cf->HostName_v[i][0] = '\0';
87       cf->TalkMode[i] = NI_BINARY_MODE;
88       switch(i) { /* set port numbers */
89          case SUMA_AFNI_STREAM_INDEX: /* AFNI listening */
90             cf->TCP_port[i] = get_port_named("AFNI_SUMA_NIML");
91             break;
92          case SUMA_AFNI_STREAM_INDEX2:  /* AFNI listening */
93             cf->TCP_port[i] = get_port_named("AFNI_DEFAULT_LISTEN_NIML");
94             break;
95          case SUMA_TO_MATLAB_STREAM_INDEX: /*Matlab listening */
96             cf->TCP_port[i] = get_port_named("MATLAB_SUMA_NIML");
97             break;
98          case SUMA_GENERIC_LISTEN_LINE: /* SUMA listening */
99             cf->TCP_port[i] = get_port_named("SUMA_DEFAULT_LISTEN_NIML");
100             break;
101          case SUMA_GEOMCOMP_LINE:
102             cf->TCP_port[i] = get_port_named("SUMA_GEOMCOMP_NIML");
103             break;
104          case SUMA_BRAINWRAP_LINE:
105             cf->TCP_port[i] = get_port_named("SUMA_BRAINWRAP_NIML");
106             break;
107          case SUMA_DRIVESUMA_LINE:
108             cf->TCP_port[i] = get_port_named("SUMA_DRIVESUMA_NIML");
109             break;
110          case SUMA_GICORR_LINE:
111             cf->TCP_port[i] = get_port_named("SUMA_GroupInCorr_NIML");
112             break;
113          case SUMA_HALLO_SUMA_LINE:
114             cf->TCP_port[i] = get_port_named("SUMA_HALLO_SUMA_NIML");
115             break;
116          case SUMA_INSTA_TRACT_LINE:
117             cf->TCP_port[i] = get_port_named("SUMA_INSTA_TRACT_NIML");
118             break;
119          default:
120             SUMA_S_Errv("Bad stream index %d. Ignoring it.\n", i);
121             break;
122       }
123    }
124    cf->Listening = NOPE;
125    cf->niml_work_on = NOPE;
126 
127    SUMA_RETURN(YUP);
128 }
129 
130 /*-----------------------------------------------------------------------*/
131 /*! NIML workprocess.
132     - Read and process any new data from open connection.
133 
134   (If the return is True, that means don't call this workproc again.
135    If the return is False, that means call this workproc again.......)
136 -------------------------------------------------------------------------*/
137 
SUMA_niml_workproc(XtPointer thereiselvis)138 Boolean SUMA_niml_workproc( XtPointer thereiselvis )
139 {
140    static char FuncName[]={"SUMA_niml_workproc"};
141    int cc , nn, ngood = 0, id;
142    void *nini ;
143    static int nwarn=0;
144    char tmpcom[100], *nel_track;
145    SUMA_SurfaceViewer *sv;
146    NI_element *nel ;
147    DList *list = NULL;
148    SUMA_EngineData *ED = NULL;
149    SUMA_Boolean LocalHead = NOPE;
150 
151    if (SUMA_NIML_WORKPROC_IO_NOTIFY) {SUMA_ENTRY;}
152 
153    if (!SUMAg_CF->niml_work_on) SUMAg_CF->niml_work_on = YUP;
154 
155    sv = (SUMA_SurfaceViewer *)thereiselvis;
156    SUMA_LH("In");
157 
158    for (cc=0; cc<SUMA_MAX_STREAMS; ++cc) {
159      if (cc == SUMA_AFNI_STREAM_INDEX2) continue;
160          /*      this stream is listened to by AFNI and is used by non-suma
161                  SUMA programs to communicate with AFNI directly.
162                  SUMA programs are not to receive elements back on this stream
163                  (unlike suma with SUMA_AFNI_STREAM_INDEX)
164                   because communications for now are one way only. */
165 
166       /* *** post Dec. 18 03, making SUMA listen to people's needs */
167       /* open streams that aren't open */
168 
169       if (  cc != SUMA_AFNI_STREAM_INDEX  &&
170             cc != SUMA_AFNI_STREAM_INDEX2 &&
171             cc != SUMA_TO_MATLAB_STREAM_INDEX ) {
172          /* Leave AFNI's and MATLAB streams alone,
173             SUMA initiates the connection on those.
174             This block is for streams on which SUMA gets contacted
175             first. */
176          if (LocalHead)
177             fprintf (SUMA_STDERR,
178                      "%s: Checking on stream %d, %s\n",
179                      FuncName, cc,  SUMAg_CF->NimlStream_v[cc]);
180          if( SUMAg_CF->ns_v[cc] == NULL &&
181             (SUMAg_CF->ns_flags_v[cc] & SUMA_FLAG_SKIP)==0 ){
182             if (LocalHead)
183                fprintf (SUMA_STDERR, "%s: \tNot Skipped.\n", FuncName);
184             SUMAg_CF->ns_v[cc] =
185                NI_stream_open( SUMAg_CF->NimlStream_v[cc] , "r" ) ;
186             if( SUMAg_CF->ns_v[cc] == NULL ){
187                fprintf (SUMA_STDERR,
188                         "%s: Stream %d, %s open returned NULL\n",
189                         FuncName, cc,  SUMAg_CF->NimlStream_v[cc]);
190                SUMAg_CF->ns_flags_v[cc] = SUMA_FLAG_SKIP ; continue;
191             }
192             if (LocalHead)
193                fprintf (SUMA_STDERR,
194                         "%s: Stream %d, %s open returned NOT null\n",
195                         FuncName, cc,  SUMAg_CF->NimlStream_v[cc]);
196             SUMAg_CF->ns_flags_v[cc]  = SUMA_FLAG_WAITING ;
197          }else {
198             if (SUMAg_CF->ns_v[cc] == NULL) {
199                SUMA_LH("\tSkipped");
200                continue;
201             }
202          }
203 
204          ngood ++;
205       } else {
206          if(   cc == SUMA_AFNI_STREAM_INDEX &&
207                SUMAg_CF->ns_v[cc]) {
208             ngood ++;
209          } else if (  cc == SUMA_TO_MATLAB_STREAM_INDEX &&
210                SUMAg_CF->ns_v[cc]) {
211             ngood ++;
212          } else {
213             /* do nothing otherwise */
214             continue;
215          }
216 
217       }
218 
219 
220      /* check if stream has gone bad */
221      nn = NI_stream_goodcheck( SUMAg_CF->ns_v[cc] , 1 ) ;
222 
223      if( nn < 0 && cc == SUMA_AFNI_STREAM_INDEX){
224          /* first check in case we are dealing with the
225          intermittent AFNI disruption */
226          if (SUMA_isEnv("SUMA_AttemptTalkRecover","y")) {
227             NI_stream_close( SUMAg_CF->ns_v[cc] ) ;
228             SUMAg_CF->ns_v[cc] = NULL ;
229             /* try again, a way to get around the weird disruption in
230                SHM connection*/
231             SUMA_S_Note("Attempting recovery...");
232             SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] = NOPE;
233             if (!list) list = SUMA_CreateList();
234             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_ToggleConnected,
235                                             SES_Suma, sv);
236             if (!SUMA_Engine (&list)) {
237             fprintf (SUMA_STDERR,
238                      "Error %s: Failed in SUMA_Engine.\n\a", FuncName);
239             }
240             nn = NI_stream_goodcheck( SUMAg_CF->ns_v[cc] , 1 ) ;
241          } else {
242             if (!nwarn) {
243                SUMA_SLP_Note(
244                   "Afni connection stream gone bad.\n"
245                   "If Afni did not shutdown, and you \n"
246                   "did not close the connection, you \n"
247                   "can recover by pressing 't' twice in SUMA.\n"
248                   "The disconnection is a known bug with\n"
249                   "an as of yet unknown source. \n"
250                   "\n"
251                   "You can also turn on the automatic recovery mode,\n"
252                   "with the environment variable \n"
253                   "SUMA_AttemptTalkRecover set to yes (see \n"
254                   "suma -environment or the environment section in\n"
255                   "SUMA's ctrl+h help output for details.)\n"
256                   "\n"
257                   "Lastly, you can use -ah 127.0.0.1 to use sockets\n"
258                   "instead of shared memory. But that kind of connection\n"
259                   "is slow.\n"
260                   "\n"
261                   "This message is shown once per session.\n");
262             }
263             ++ nwarn;
264          }
265      }
266 
267      if( nn < 0 ){                          /* is bad */
268        if (SUMAg_CF->ns_v[cc]) NI_stream_close( SUMAg_CF->ns_v[cc] ) ;
269        SUMAg_CF->ns_v[cc] = NULL ; /* this will get checked next time */
270        SUMA_S_Errv("Stream %d gone bad. Stream closed. \n", cc);
271 
272        /* close everything */
273        if (!list) list = SUMA_CreateList();
274        ED = SUMA_InitializeEngineListData(SE_CloseStream4All);
275        if (!SUMA_RegisterEngineListCommand ( list, ED,
276                                           SEF_i, (void*)&cc,
277                                           SES_Suma, (void *)sv, NOPE,
278                                           SEI_Head, NULL)) {
279          fprintf (SUMA_STDERR,
280                   "Error %s: Failed to register command.\n", FuncName);
281        }
282 
283        if (!SUMA_Engine (&list)) {
284          fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_Engine.\n\a", FuncName);
285        }
286 
287        continue;  /* skip to next stream */
288      }
289 
290      if (nn == 0) { /* waiting, come back later */
291          continue;
292      }
293 
294      /* if here, stream is good;
295         see if there is any data to be read */
296      if (!SUMAg_CF->TCP_port[0]) SUMA_init_ports_assignments(SUMAg_CF);
297 
298      if (SUMAg_CF->ns_flags_v[cc] & SUMA_FLAG_WAITING) {
299          SUMAg_CF->ns_flags_v[cc] = SUMA_FLAG_CONNECTED;
300          SUMA_S_Notev(
301                   "++ NIML connection opened from %s on port %d (%dth stream)\n",
302                   NI_stream_name(SUMAg_CF->ns_v[cc]),
303                   SUMAg_CF->TCP_port[cc], cc) ;
304          if (cc == SUMA_HALLO_SUMA_LINE) { /* Connected flag for AFNI line
305                                               handled elsewhere */
306             SUMA_S_Note("Connected on HALLO_SUMA");
307             SUMAg_CF->Connected_v[cc] = YUP;
308          }
309          if (cc == SUMA_INSTA_TRACT_LINE) { /* Connected flag for AFNI line
310                                               handled elsewhere */
311             SUMA_S_Note("Connected on INSTA_TRACT_LINE");
312             SUMAg_CF->Connected_v[cc] = YUP;
313          }
314      }
315    #if 0
316       /* not good enough, checks socket only, not buffer */
317       nn = NI_stream_readcheck( SUMAg_CF->ns , 1 ) ;
318    #else
319       nn = NI_stream_hasinput( SUMAg_CF->ns_v[cc] , 1 ) ;
320    #endif
321 
322      if( nn > 0 ){                                   /* has data */
323        int ct = NI_clock_time() ;
324        if (LocalHead)
325          fprintf(SUMA_STDERR,"%s: reading data stream", FuncName) ;
326 
327        nini = NI_read_element( SUMAg_CF->ns_v[cc] , 1 ) ;  /* read it */
328          #if SUMA_SUMA_NIML_DEBUG /* debugging corruption of niml ...*/
329             nel = (NI_element *)nini ;
330             if(   strcmp(nel->name,"SUMA_irgba") == 0 ||
331                   strcmp(nel->name,"Node_RGBAb") == 0)
332             {
333                int *ibad=NULL;
334 
335                ibad = (int *)nel->vec[0];
336                if (ibad[0] > 1000) {
337                   fprintf (SUMA_STDERR,
338                            "**********\n\tibad[0] = %d\n****************\n",
339                            ibad[0]);
340                   fprintf (SUMA_STDOUT,
341                            "********** ibad[0] = %d ****************",
342                            ibad[0]);
343                }
344                if( nel->vec_len  < 1 || nel->vec_filled <  1) {
345                         /* empty element?             */
346                   fprintf(SUMA_STDERR,
347                            "--------\n"
348                            "\tEmpty SUMA_irgba (len = %d, len = %d)\n"
349                            "--------\n",
350                      nel->vec_len, nel->vec_filled);
351                   fprintf(SUMA_STDOUT,
352                            "-------- Empty SUMA_irgba "
353                            "(len = %d, filled = %d) --------",
354                      nel->vec_len, nel->vec_filled);
355                }
356                fprintf (SUMA_STDOUT,"\n");
357             }
358          #endif
359 
360        if (LocalHead)
361          fprintf( SUMA_STDERR,
362                   " time=%d ms\n",
363                   NI_clock_time()-ct) ; ct = NI_clock_time() ;
364 
365        if( nini != NULL ) {
366          nel = (NI_element *)nini ;
367          if (SUMAg_CF->TrackingId_v[cc]) {
368             nel_track = NI_get_attribute(nel,"Tracking_ID");
369             if (nel_track) {
370                id = atoi(nel_track);
371                if (id != SUMAg_CF->TrackingId_v[cc] + 1) {
372                   /* remember, "StartTracking" nel is the #1 element,
373                      first data element starts at 2 */
374                   fprintf (SUMA_STDERR,
375                            "Warning %s:\n"
376                            " Expected element %d, received element %d.\n",
377                            FuncName,  SUMAg_CF->TrackingId_v[cc] + 1 , id );
378                   SUMA_BEEP;
379                }
380                SUMAg_CF->TrackingId_v[cc] = id;
381             }
382          }
383          if (LocalHead)   {
384             fprintf( SUMA_STDERR,
385                      "%s:     name=%s vec_len=%d vec_filled=%d, vec_num=%d\n",
386                      FuncName, nel->name, nel->vec_len,
387                      nel->vec_filled, nel->vec_num );
388          }
389           if (!SUMA_process_NIML_data( nini , sv)) {
390              fprintf(SUMA_STDERR,
391                      "Error %s: Failed in SUMA_process_NIML_data.\n", FuncName);
392           }
393       }
394 
395       NI_free_element( nini ) ;
396 
397       if (LocalHead)
398          fprintf(SUMA_STDERR,"processing time=%d ms\n",NI_clock_time()-ct) ;
399 
400      }
401 
402    }/* for cc*/
403 
404    if (ngood == 0) {
405       SUMAg_CF->niml_work_on = NOPE;
406       SUMAg_CF->Listening = NOPE;
407       if (SUMA_NIML_WORKPROC_IO_NOTIFY) {
408          SUMA_RETURN(True) ;  /* don't call me back */
409       }
410          else return (True);
411    }
412 
413    if (SUMA_NIML_WORKPROC_IO_NOTIFY) {
414       SUMA_RETURN(False) ;  /* call me back baby*/
415    }
416       else return (False);
417 }
418 
SUMA_which_stream_index(SUMA_CommonFields * cf,char * nel_stream_name)419 int SUMA_which_stream_index (SUMA_CommonFields *cf, char *nel_stream_name)
420 {
421    static char FuncName[]={"SUMA_which_stream_index"};
422    int i;
423    SUMA_Boolean LocalHead = NOPE;
424 
425    SUMA_ENTRY;
426 
427    for (i=0; i < SUMA_MAX_STREAMS; ++i) {
428       if (strcmp(nel_stream_name, cf->NimlStream_v[i]) == 0) SUMA_RETURN(i);
429    }
430 
431    SUMA_RETURN(-1);
432 }
433 
SUMA_niml_hangup(SUMA_CommonFields * cf,char * nel_stream_name,SUMA_Boolean fromSUMA,SUMA_Boolean killit)434 SUMA_Boolean SUMA_niml_hangup (SUMA_CommonFields *cf, char *nel_stream_name,
435                                SUMA_Boolean fromSUMA, SUMA_Boolean killit)
436 {
437    static char FuncName[]={"SUMA_niml_hangup"};
438    int i;
439    SUMA_Boolean LocalHead = NOPE;
440 
441    SUMA_ENTRY;
442 
443    if (!nel_stream_name) {
444       if (!fromSUMA) { SUMA_SL_Err("NULL stream name"); }
445       else { SUMA_SLP_Err("NULL stream name"); }
446       SUMA_RETURN(NOPE);
447    }
448 
449 
450    i = SUMA_which_stream_index (cf, nel_stream_name);
451 
452 
453    if (i < 0) {
454       if (!fromSUMA) { SUMA_SL_Err("Stream not found"); }
455       else {  SUMA_SLP_Err("Stream not found"); }
456       SUMA_RETURN(NOPE);
457    } else {
458       SUMA_LH("Stream found.");
459       fprintf (SUMA_STDERR,"%s: stream index %d\n", FuncName, i);
460       if (killit) {
461          SUMA_LH("Killing stream");
462          NI_stream_kill(cf->ns_v[i]);
463       }else {
464         SUMA_LH("Just closing stream");
465          NI_stream_close(cf->ns_v[i]);
466       }
467       cf->ns_v[i] = NULL;
468       cf->Connected_v[i] = NOPE;
469       cf->ns_flags_v[i] = 0;
470       cf->TrackingId_v[i] = 0;
471    }
472 
473    SUMA_RETURN(YUP);
474 }
475 
476 static int SUMA_WriteCheckWaitMax;
477 
SUMA_GetWriteCheckWaitMax(void)478 int SUMA_GetWriteCheckWaitMax(void) {
479    return(SUMA_WriteCheckWaitMax);
480 }
SUMA_SetWriteCheckWaitMax(int val)481 void SUMA_SetWriteCheckWaitMax(int val) {
482    if (val == 0) val = SUMA_WRITECHECKWAITMAX;
483    SUMA_WriteCheckWaitMax = val;
484 }
485 
486 /*!
487    \brief Initiates a call on stream cf->ns_v[si]
488 
489    \param cf (SUMA_CommonFields *) Overkill common field structure.
490                                     Only fields used are the niml
491                                     communication ones....
492    \param si (int) index of stream to use
493    \param fromSUMA (SUMA_Boolean) YUP means call is initiated from SUMA
494    \return NOPE: Sucked
495            YUP : Did not suck
496 
497    \sa SUMA_niml_hangup
498 */
SUMA_niml_call(SUMA_CommonFields * cf,int si,SUMA_Boolean fromSUMA)499 SUMA_Boolean SUMA_niml_call ( SUMA_CommonFields *cf, int si,
500                               SUMA_Boolean fromSUMA)
501 {
502    static char FuncName[]={"SUMA_niml_call"};
503    int nn=-1, Wait_tot;
504    SUMA_Boolean LocalHead = NOPE;
505 
506    SUMA_ENTRY;
507 
508    if (si < 0 || si >= SUMA_MAX_STREAMS) {
509       SUMA_SL_Err("Bad value for stream index.");
510       SUMA_RETURN(NOPE);
511    }
512 
513      /* find out if the stream has been established already */
514       if (cf->ns_v[si]) { /* stream is open, nothing to do */
515          cf->ns_flags_v[si] = SUMA_FLAG_CONNECTED;
516          if (LocalHead)
517             fprintf(SUMA_STDOUT,"%s: Stream existed, reusing.\n", FuncName);
518          if(dsq==0)
519          fprintf(SUMA_STDOUT,"%s: Connected.\n", FuncName); fflush(SUMA_STDOUT);
520       }else {   /* must open stream */
521          /* contact afni */
522             SUMA_SetWriteCheckWaitMax(cf->ns_to[si]);
523             if(dsq==0) {
524                fprintf( SUMA_STDOUT,
525                         "%s: Contacting on %s (%d), maximum wait %.3f sec \n"
526                "(You can change max. wait time with env. SUMA_DriveSumaMaxWait)\n",
527                         FuncName, cf->NimlStream_v[si], si,
528                         (float)cf->ns_to[si]/1000.0);
529             }
530             fflush(SUMA_STDOUT);
531             cf->ns_v[si] =  NI_stream_open( cf->NimlStream_v[si] , "w" ) ;
532             if (!cf->ns_v[si]) {
533                cf->ns_flags_v[si] = 0;
534                cf->TrackingId_v[si] = 0;
535 
536                if (fromSUMA) { SUMA_SLP_Err("NI_stream_open failed (1p)."); }
537                else { SUMA_SL_Err("NI_stream_open failed (1)."); }
538                SUMA_BEEP;
539                cf->Connected_v[si] = !cf->Connected_v[si];
540                SUMA_RETURN(NOPE) ;
541             }
542             if (!strcmp(cf->HostName_v[si],"localhost")) {
543                /* only try shared memory when
544                   AfniHostName is localhost */
545                if(dsq==0)
546                fprintf (SUMA_STDERR,
547                         "%s: Trying local connection...\n", FuncName);
548 
549                if( strstr( cf->NimlStream_v[si] , "tcp:localhost:" ) != NULL ) {
550                   if (!NI_stream_reopen( cf->ns_v[si] , "shm:WeLikeElvis:1M" )){
551                      fprintf (SUMA_STDERR,
552                               "Warning %s: "
553                               "Shared memory communcation failed.\n",
554                               FuncName);
555                   }
556                }
557             }
558 
559             if( cf->ns_v[si] == NULL ){
560                if (fromSUMA) { SUMA_SLP_Err("NI_stream_open failed (2p)");}
561                else { SUMA_SL_Err("NI_stream_open failed (2)");}
562                SUMA_BEEP;
563                cf->Connected_v[si] = !cf->Connected_v[si];
564                cf->ns_flags_v[si] = 0;
565                cf->TrackingId_v[si] = 0;
566 
567                SUMA_RETURN(NOPE) ;
568             }
569 
570          Wait_tot = 0;
571          /*
572          fprintf(stderr, "nn = %d\n", nn);
573          fprintf(stderr, "SUMA_WriteCheckWaitMax = %d\n", SUMA_WriteCheckWaitMax);
574          */
575          while(Wait_tot < SUMA_WriteCheckWaitMax){
576             nn = NI_stream_writecheck( cf->ns_v[si] , SUMA_WriteCheckWait) ;
577             /*
578              fprintf(stderr, "Wait_tot = %d, nn = %d, SUMA_WriteCheckWait=%d,
579                 cf->ns_v[si]=%p\r", Wait_tot, nn, SUMA_WriteCheckWait, cf->ns_v[si]);
580                 */
581             if( nn == 1 ){
582                fprintf(stderr,"\n") ;
583                cf->ns_flags_v[si] = SUMA_FLAG_CONNECTED;
584                SUMA_RETURN(YUP) ;
585             }
586             if( nn <  0 ){
587                fprintf(stderr,"BAD\n");
588                cf->Connected_v[si] = !cf->Connected_v[si];
589                cf->ns_v[si] = NULL;
590                cf->ns_flags_v[si] = 0;
591                cf->TrackingId_v[si] = 0;
592                SUMA_RETURN(NOPE);
593             }
594             Wait_tot += SUMA_WriteCheckWait;
595             fprintf(SUMA_STDERR,".") ;
596          }
597          // fprintf(stderr, "\n");
598 
599          /* make sure you did not exit because of time out */
600          // SUMA_S_Errv("nn = %d\n", nn);
601          if (nn!=1) {
602             cf->Connected_v[si] = !cf->Connected_v[si];
603             cf->ns_v[si] = NULL;
604             cf->ns_flags_v[si] = 0;
605             cf->TrackingId_v[si] = 0;
606             SUMA_S_Errv("WriteCheck timed out (> %d ms).\n",
607                         SUMA_WriteCheckWaitMax);
608             SUMA_RETURN(NOPE);
609          }
610       }
611 
612       /* Stream is open */
613    SUMA_RETURN(YUP);
614 }
615 
616 /*
617    Return label for Overlay from AFNI
618 */
SUMA_AfniOverlayLabel(SUMA_ALL_DO * ado,int num)619 char *SUMA_AfniOverlayLabel(SUMA_ALL_DO *ado, int num)
620 {
621    static char FuncName[]={"SUMA_AfniOverlayLabel"};
622    static char scc[10][64];
623    static int ncall=0;
624    char *cc=NULL;
625 
626    SUMA_ENTRY;
627 
628    ++ncall;
629    if (ncall > 9) ncall = 0;
630    cc = scc[ncall];
631    cc[0] = '\0';
632 
633    switch (ado->do_type) {
634       case SO_type: {
635          SUMA_SurfaceObject *SO = (SUMA_SurfaceObject *)ado;
636          switch (SO->Side) {
637             case SUMA_LEFT:
638                snprintf(cc,63,"lh.FuncAfni_%02d",num);
639                break;
640             case SUMA_RIGHT:
641                snprintf(cc,63,"rh.FuncAfni_%02d",num);
642                break;
643             default:
644                snprintf(cc,63,"FuncAfni_%02d",num);
645                break;
646          }
647          break; }
648       case TRACT_type: {
649          snprintf(cc,63,"TR.%s.FuncAfni_%02d",
650                   SUMA_ADO_sLabel(ado), num);
651          break; }
652       case MASK_type: {
653          snprintf(cc,63,"MS.%s.FuncAfni_%02d",
654                   SUMA_ADO_sLabel(ado), num);
655          break; }
656       case VO_type: {
657          snprintf(cc,63,"VO.%s.FuncAfni_%02d",
658                   SUMA_ADO_sLabel(ado), num);
659          break; }
660       default:
661          SUMA_S_Err("No Afni Overlay Label for %s\n",
662                    SUMA_ADO_sLabel(ado));
663          snprintf(cc,63,"Errific");
664          break;
665    }
666 
667    SUMA_RETURN(cc);
668 }
669 
670 /*----------------------------------------------------------------------*/
671 /*! Process NIML data.
672 ------------------------------------------------------------------------*/
673 
SUMA_process_NIML_data(void * nini,SUMA_SurfaceViewer * sv)674 SUMA_Boolean SUMA_process_NIML_data( void *nini , SUMA_SurfaceViewer *sv)
675 {
676    static char FuncName[]={"SUMA_process_NIML_data"};
677    int tt = NI_element_type(nini) ;
678    int OverInd, loc_ID, iview, *IJK=NULL, N_Node, *FaceSetList=NULL, N_FaceSet;
679    int i, I_C = -1, nodeid = -1, iv3[3], dest_SO_ID = -1,
680          N_SOlist, SOlist[SUMA_MAX_DISPLAYABLE_OBJECTS], ip = 0;
681    NI_element *nel = NULL ;
682    NI_group *ngr = NULL;
683    SUMA_EngineData *ED = NULL;
684    DList *list = NULL;
685    DListElmt *Elm = NULL, *el=NULL;
686    char CommString[SUMA_MAX_COMMAND_LENGTH], *nel_surfidcode = NULL,
687          *nel_nodeid = NULL;
688    char s[SUMA_MAX_STRING_LENGTH], sfield[100], sdestination[100], ssource[100];
689    float **fm, dimfact,  *XYZ=NULL, *NodeList=NULL;
690    byte *r, *g, *b;
691    byte BrandNew = YUP;
692    SUMA_NEW_SO_OPT *nsoopt=NULL;
693    SUMA_Boolean Empty_irgba = NOPE,  Found = NOPE;
694    SUMA_SurfaceObject *SO = NULL;
695    SUMA_ALL_DO *ado=NULL;
696    SUMA_SurfaceViewer *svi = NULL;
697    SUMA_OVERLAYS * tmpptr;
698    SUMA_OVERLAY_PLANE_DATA sopd;
699    SUMA_SurfSpecFile *Spec=NULL;
700    SUMA_Boolean iselement = YUP;
701    SUMA_Boolean LocalHead = NOPE;
702 
703    SUMA_ENTRY;
704 
705    if( tt < 0 ) {/* should never happen unless nini was NULL*/
706       fprintf(SUMA_STDERR,"Error %s: Should never have happened.\n", FuncName);
707       SUMA_RETURN(NOPE);
708    }
709 
710    SUMA_LH("Checking on nini type");
711    /* check if group or element */
712    if(tt == NI_GROUP_TYPE) {
713       iselement = NOPE;
714       SUMA_LH("Dealing with group");
715    } else if (tt == NI_ELEMENT_TYPE) {
716       iselement = YUP;
717       SUMA_LH("Dealing with element");
718    } else {
719       fprintf(SUMA_STDERR,"Error %s: Not an element, nor a group. \n"
720                           "What the hell are you doing?\n", FuncName);
721       SUMA_RETURN(NOPE);
722    }
723 
724 
725    if (iselement) {
726       /* if here, have a single data element;
727          process the data based on the element name */
728 
729       nel = (NI_element *) nini ;
730 
731       if (LocalHead)  {
732          fprintf(SUMA_STDERR,
733                  "%s:     name=%s vec_len=%d vec_filled=%d, vec_num=%d\n",
734                  FuncName,
735                  nel->name, nel->vec_len, nel->vec_filled, nel->vec_num );
736          /* SUMA_ShowNel(nel); */
737       }
738 
739       /*--- stream closer ---*/
740       if( strcmp(nel->name,"CloseKillStream") == 0) { /* CloseKillStream */
741          if (LocalHead)
742             fprintf (SUMA_STDERR,"%s:\nClosing then killing stream %s ...\n",
743                      FuncName, NI_get_attribute(nel, "ni_stream_name"));
744          if (!SUMA_niml_hangup (SUMAg_CF,
745                                 NI_get_attribute(nel, "ni_stream_name"),
746                                 NOPE, YUP)) {
747             SUMA_SL_Err("Failed in SUMA_niml_hangup.\n");
748             SUMA_RETURN(NOPE);
749          }
750          SUMA_RETURN(YUP);
751       } /* CloseStreamKill */
752 
753       /*--- stream tracking ON ---*/
754       if( strcmp(nel->name,"StartTracking") == 0) { /* Start tracking */
755          if (LocalHead)
756             fprintf (SUMA_STDERR,"%s:\n"
757                                  " Starting NI element tracking for %s ...\n",
758                                  FuncName,
759                                  NI_get_attribute(nel, "ni_stream_name"));
760          i = SUMA_which_stream_index(SUMAg_CF,
761                                      NI_get_attribute(nel, "ni_stream_name"));
762          if ( i < 0) {
763             SUMA_SL_Err("Failed to find stream!\n");
764             SUMA_RETURN(NOPE);
765          }
766          if (NI_get_attribute(nel, "Tracking_ID")) {
767             if (atoi(NI_get_attribute(nel, "Tracking_ID")) != 1) {
768                SUMA_SL_Err("First tracking element is not 1.\n\n"
769                            "Tracking ignored.\n");
770                SUMA_RETURN(YUP);
771             }
772          }
773          SUMA_LH("Tracking on ...");
774          SUMAg_CF->TrackingId_v[i] = 1; /* this is to be the first element ! */
775          SUMA_RETURN(YUP);
776       } /* Start tracking */
777 
778       /*--- stream tracking OFF ---*/
779       if( strcmp(nel->name,"StopTracking") == 0) { /* Stop tracking */
780          if (LocalHead)
781             fprintf (SUMA_STDERR,
782                      "%s:\n Stopping NI element tracking for %s ...\n",
783                      FuncName, NI_get_attribute(nel, "ni_stream_name"));
784          i = SUMA_which_stream_index(SUMAg_CF,
785                                      NI_get_attribute(nel, "ni_stream_name"));
786          if ( i < 0) {
787             SUMA_SL_Err("Failed to find stream!\n");
788             SUMA_RETURN(NOPE);
789          }
790          SUMA_LH("Tracking Off ...");
791          SUMAg_CF->TrackingId_v[i] = 0; /* this is to be the first element ! */
792          SUMA_RETURN(YUP);
793       } /* Stop tracking */
794 
795 
796       if (strcmp(nel->name,"underlay_array") == 0) { /* underlay array */
797          SUMA_S_Note("Have underlay array!");
798          SUMA_RETURN(YUP) ;
799       }
800 
801       /* New surface mesh_IJK, This one is now obsolete,
802          along with NewNode_XYZ, they were used to send a surface in chunks, now
803          I can send an entire surface. Look at commented out section in
804          SUMA_Mesh_IJK2Mesh_IJK_nel if you want to reuse this chunk*/
805       if (strcmp(nel->name,"NewMesh_IJK") == 0) { /* NewMesh_IJK */
806          SUMA_SL_Err("Element obsolete. Please use SUMA_SurfaceObject");
807          SUMA_RETURN(NOPE) ;
808          if( nel->vec_len  < 1 || nel->vec_filled <  1) {/* empty element? */
809             fprintf(SUMA_STDERR,"%s: Empty NewMesh_IJK\n", FuncName);
810             SUMA_RETURN(NOPE);
811          }else {
812             if( nel->vec_num != 1 || nel->vec_typ[0] != NI_INT) {
813                  fprintf(SUMA_STDERR,"%s: NewMesh_IJK Bad format\n", FuncName);
814                SUMA_RETURN(NOPE);
815             }
816          }
817          /* show me nel */
818          /* if (LocalHead) SUMA_nel_stdout (nel); */
819          /* look for the surface idcode */
820          nel_surfidcode = NI_get_attribute(nel, "surface_idcode");
821          if (SUMA_IS_EMPTY_STR_ATTR(nel_surfidcode))
822             nel_surfidcode = NI_get_attribute(nel, "domain_parent_idcode");
823          if (SUMA_IS_EMPTY_STR_ATTR(nel_surfidcode)) {
824             fprintf( SUMA_STDERR,
825                      "Error %s: surface_idcode missing in nel (%s).\n",
826                      FuncName, nel->name);
827             SUMA_RETURN(NOPE);
828          }
829 
830          SUMA_LH("Checking for new surface...");
831          SO = SUMA_findSOp_inDOv (nel_surfidcode, SUMAg_DOv, SUMAg_N_DOv);
832          if (SO) {
833             fprintf( SUMA_STDERR,
834                      "Warning %s: nel idcode was found in DOv.\n"
835                      "Checking for mesh compatibility\n", FuncName);
836             if (SO->N_FaceSet * SO->FaceSetDim == nel->vec_len) {
837                fprintf(SUMA_STDERR,
838                        "Note %s: Mesh dimensions match. \n"
839                        "New mesh will be adopted.\n", FuncName);
840             } else {
841                fprintf(SUMA_STDERR,
842                        "Error %s: Mesh dimensions mismatch.\n", FuncName);
843                SUMA_RETURN(NOPE);
844             }
845          }
846 
847          /* get the number of nodes */
848          if (!NI_get_attribute(nel, "N_Node")) {
849             fprintf( SUMA_STDERR,
850                      "Error %s: NULL or non existent N_Node field.\n", FuncName);
851             SUMA_RETURN(NOPE);
852          }
853 
854          if (LocalHead)
855             fprintf( SUMA_STDERR,"Number of nodes:%s...\n",
856                      NI_get_attribute(nel, "N_Node"));
857          N_Node = atoi(NI_get_attribute(nel, "N_Node"));
858          if (N_Node <= 0 || N_Node > 1000000) {
859             fprintf(SUMA_STDERR,
860                     "Error %s: Bad number of nodes %d \n"
861                     "(limit of 1000000 nodes.)\n", FuncName, N_Node);
862             SUMA_RETURN(NOPE);
863          }
864 
865          if (!SO) {
866             SUMA_LH("A brand new surface.");
867             BrandNew = YUP;
868             NodeList = (float *)SUMA_malloc(3 * N_Node * sizeof(float));
869                      /* do not use calloc so that you can see something ... */
870             FaceSetList = (int *)SUMA_malloc(nel->vec_len * sizeof(int));
871             if (!NodeList || !FaceSetList) {
872                SUMA_SL_Crit("Failed to allocate for NodeList || FaceSetList");
873                SUMA_RETURN(NOPE);
874             }
875             IJK = (int *)nel->vec[0];
876             N_FaceSet = nel->vec_len / 3;
877             if (nel->vec_len % 3) {
878                fprintf(SUMA_STDERR,
879                        "Error %s: Bad number of elements in IJK vector\n"
880                        " not divisible by 3! %d\n", FuncName, nel->vec_len);
881                SUMA_RETURN(NOPE);
882             }
883             SUMA_LH("Copying new mesh");
884             for (i=0; i < nel->vec_len; ++i) FaceSetList[i] = IJK[i];
885             /* Now form the new surface */
886             SUMA_LH("Now forming new surface");
887             nsoopt = SUMA_NewNewSOOpt();
888             nsoopt->DoNormals = NOPE; nsoopt->DoMetrics = NOPE;
889             nsoopt->DoCenter = NOPE;
890             nsoopt->idcode_str = SUMA_copy_string(nel_surfidcode);
891             SO = SUMA_NewSO(&NodeList, N_Node, &FaceSetList, N_FaceSet, nsoopt);
892             nsoopt=SUMA_FreeNewSOOpt(nsoopt);
893          } else {
894             SUMA_LH("A refit of an existing surface.");
895             BrandNew = NOPE;
896             if (N_Node != SO->N_Node) {
897                fprintf( SUMA_STDERR,
898                         "Error %s: Mismatch in number of nodes between new \n"
899                         "mesh and pre-existing one (%d vs %d)\n",
900                         FuncName, N_Node, SO->N_Node);
901                SUMA_RETURN(NOPE);
902             }
903             IJK = (int *)nel->vec[0];
904             for (i=0; i < nel->vec_len; ++i) SO->FaceSetList[i] = IJK[i];
905          }
906 
907          /* work the mesh a little and add it to DOv NO LONGER DONE HERE...*/
908          SO->Group = SUMA_copy_string(NI_get_attribute(nel, "Group"));
909          if (!SO->Group)
910             SO->Group = SUMA_copy_string(NI_get_attribute(nel, "Subject_Label"));
911          SO->State = SUMA_copy_string(NI_get_attribute(nel, "State"));
912          if (!SO->State)
913             SO->State = SUMA_copy_string(NI_get_attribute(nel, "Layer_Name"));
914          SO->Label = SUMA_copy_string(NI_get_attribute(nel, "Label"));
915          if (!SO->Label)
916             SO->Label = SUMA_copy_string(NI_get_attribute(nel, "Object_Label"));
917          SO->EmbedDim = atoi(NI_get_attribute(nel, "EmbedDim"));
918          if (!SO->EmbedDim)
919             SO->EmbedDim = atoi(NI_get_attribute(nel, "Embedding_Dimension"));
920          SO->AnatCorrect = atoi(NI_get_attribute(nel, "AnatCorrect"));
921          if (!SO->AnatCorrect) {
922             char *tmp = NI_get_attribute(nel, "Anatomically_Correct");
923             if (tmp) {
924                if (strstr(tmp,"yes")) SO->AnatCorrect = 1;
925                else if (strstr(tmp,"no")) SO->AnatCorrect = 0;
926             }
927          }
928          /* add this surface to DOv */
929          if (BrandNew) {
930             if (!SUMA_AddDO(SUMAg_DOv, &(SUMAg_N_DOv), (void *)SO,
931                             SO_type, SUMA_WORLD)) {
932                fprintf(SUMA_STDERR,"Error %s: Error Adding DO\n", FuncName);
933                SUMA_RETURN(NOPE);
934             }
935          }
936 
937          /* don't free nel, it's freed later on */
938          SUMA_RETURN(YUP) ;
939       }/* NewMesh_IJK */
940 
941       if (strcmp(nel->name,"PrepNewSurface") == 0) { /* PrepNewSurface */
942          int viewopt = 0;
943          /* show me nel */
944          /* if (LocalHead) SUMA_nel_stdout (nel); */
945          /* look for the surface idcode */
946          nel_surfidcode = NI_get_attribute(nel, "surface_idcode");
947          if (SUMA_IS_EMPTY_STR_ATTR(nel_surfidcode))
948             nel_surfidcode = NI_get_attribute(nel, "domain_parent_idcode");
949          if (SUMA_IS_EMPTY_STR_ATTR(nel_surfidcode)) {
950             fprintf(SUMA_STDERR,
951                     "Error %s: surface_idcode missing in nel (%s).\n",
952                     FuncName, nel->name);
953             SUMA_RETURN(NOPE);
954          }
955          SUMA_LH("Looking for  surface...");
956          SO = SUMA_findSOp_inDOv (nel_surfidcode, SUMAg_DOv, SUMAg_N_DOv);
957          if (!SO) {
958             fprintf(SUMA_STDERR,
959                     "Error %s: nel idcode was not found in DOv.\n", FuncName);
960             SUMA_RETURN(NOPE);
961          }
962 
963          if (LocalHead)
964             fprintf(SUMA_STDERR, "%s: Surface SO about to be prepped: "
965                                  "Label %s, State %s, Group %s\n",
966                                  FuncName, SO->Label, SO->State, SO->Group);
967 
968          #if 0
969          if (NI_get_attribute(nel, "VolParFilecode")) {
970             SO->VolPar = SUMA_VolPar_Attr (NI_get_attribute(nel,
971                                                             "VolParFilecode"));
972             if (!SO->VolPar) {
973                SUMA_S_Err("Failed in SUMA_VolPar_Attr");
974                SUMA_RETURN(NOPE);
975             }
976             SO->SUMA_VolPar_Aligned = YUP; /* Surface should already be in
977                                               alignment with volume, should not
978                                               call SUMA_Align_to_VolPar ... */
979          }
980          #else
981             /* VolPar should have been dealt with by now */
982             if (!SO->VolPar) SO->SUMA_VolPar_Aligned = NOPE;
983             else SO->SUMA_VolPar_Aligned = YUP; /* Surface should already be in
984                                                    alignment with volume, should
985                                                    not call SUMA_Align_to_VolPar
986                                                    ... */
987          #endif
988 
989          /* make this surface friendly for suma */
990          if (!SUMA_PrepSO_GeomProp_GL(SO)) {
991             SUMA_S_Err("Failed in SUMA_PrepSO_GeomProp_GL");
992             SUMA_RETURN(NOPE);
993          }
994          /* Add this surface to SUMA's displayable objects */
995          if (!SUMA_PrepAddmappableSO(SO, SUMAg_DOv, &(SUMAg_N_DOv),
996                                      0, SUMAg_CF->DsetList)) {
997             SUMA_S_Err("Failed to add mappable SOs ");
998             SUMA_RETURN(NOPE);
999          }
1000          /* create a fake spec, be damned gates of spec! */
1001          Spec = SUMA_SOGroup_2_Spec (&SO, 1);
1002 
1003          /* register the new group with SUMA */
1004          if (!SUMA_RegisterSpecGroup(SUMAg_CF, Spec)) {
1005             SUMA_SL_Err("Failed to register group");
1006             SUMA_RETURN(NOPE);
1007          }
1008 
1009 	      /* Register the surfaces in Spec file with the surface
1010             viewer and perform setups */
1011          viewopt = 0;
1012          if(dsq==0)
1013             fprintf (SUMA_STDERR,
1014                   "%s: Registering surfaces with surface viewers, "
1015                   "viewopt = %d...\n", FuncName, viewopt);
1016 
1017          for (i = 0; i< SUMA_MAX_SURF_VIEWERS; ++i) {
1018             if (!SUMA_SetupSVforDOs (Spec, SUMAg_DOv, SUMAg_N_DOv,
1019                      &(SUMAg_SVv[i]), viewopt)) {
1020 			      fprintf (SUMA_STDERR,
1021                         "Error %s: Failed in SUMA_SetupSVforDOs function.\n",
1022                         FuncName);
1023 			      SUMA_RETURN(NOPE);
1024 		      }
1025 	      }
1026 
1027          if (!SUMA_FreeSpecFields(Spec)) {
1028             SUMA_S_Err("Failed to free spec fields");
1029          }
1030          SUMA_free(Spec); Spec = NULL;
1031 
1032          /* switch viewer 0 to the group in question */
1033          if (!sv) sv = &(SUMAg_SVv[0]);
1034          if (!SUMA_SwitchGroups (sv, SO->Group)) {
1035             SUMA_SL_Err("Failed to switch groups!");
1036             SUMA_RETURN(NOPE);
1037          }
1038          if ((i = SUMA_WhichState(SO->State, sv, sv->CurGroupName)) < 0) {
1039             SUMA_SL_Err("Failed to find state!");
1040             SUMA_RETURN(NOPE);
1041          } else {
1042             if (!SUMA_SwitchState(  SUMAg_DOv, SUMAg_N_DOv,
1043                                     sv, i, sv->CurGroupName)) {
1044                SUMA_SL_Err("Failed to switch states!");
1045                SUMA_RETURN(NOPE);
1046             }
1047          }
1048 
1049          /* file a redisplay request
1050          In the past, when surface was sent in chunks, redisplay was
1051          held until geometry was received, now that a whole surface can be sent
1052          at once, redisplay is appropriate here ZSS Sept. 06*/
1053          if (LocalHead)
1054             fprintf(SUMA_STDERR, "%s: Redisplaying all visible...\n", FuncName);
1055          if (!list) list = SUMA_CreateList();
1056          SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay_AllVisible,
1057                                              SES_SumaFromAny, sv);
1058          if (!SUMA_Engine (&list)) {
1059             fprintf(SUMA_STDERR,
1060                "Error %s: SUMA_Engine call failed.\n", FuncName);
1061             SUMA_RETURN(NOPE);
1062          }
1063 
1064          /* do we need to notify AFNI ? */
1065          /* YOU'll need to do the same using Send2Matlab
1066             The only difference is the changing stream index
1067             So you should set this at the top and use the
1068             same instructions.
1069             Also, you'll need to pass the stream along with the
1070             SE_ToggleConnected and SE_SetAfniThisSurf and others
1071             Or perhaps consider checking all applicable Connected_v
1072             at the targets in SUMA_Engine.c */
1073          if (NI_get_attribute(nel, "Send2Afni")) {
1074             SUMA_LH("Attempting to talk to AFNI");
1075             if (!SO->VolPar) {
1076                SUMA_SL_Err("Have no VolPar, cannot send to AFNI!\n"
1077                            "Command ignored.");
1078             } else {
1079                if (!SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX]) {
1080                   /* need to send a toggle request */
1081                   if (LocalHead)
1082                      fprintf(SUMA_STDERR,
1083                         "%s: Sending talk request...\n", FuncName);
1084                   if (!list) list = SUMA_CreateList();
1085                   SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_ToggleConnected,
1086                                                       SES_SumaFromAny, sv);
1087                   if (!SUMA_Engine (&list)) {
1088                      fprintf( SUMA_STDERR,
1089                               "Warning %s: "
1090                               "SUMA_Engine call failed.\nContinuing...",
1091                               FuncName);
1092                   }
1093                } else {
1094                   SUMA_LH("Looks like they're talking already");
1095                }
1096                /* now send the surface */
1097                SUMA_LH("Now trying to send surface");
1098                if (!SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX]) {
1099                   fprintf( SUMA_STDERR,
1100                            "Warning %s: "
1101                            "Failed to open connection.\nContinuing...",
1102                            FuncName);
1103                } else {
1104                   SUMA_LH("Making Call");
1105                   if (!list) list = SUMA_CreateList();
1106                   ED = SUMA_InitializeEngineListData (SE_SetAfniThisSurf);
1107                   if (!( Elm = SUMA_RegisterEngineListCommand (
1108                                  list, ED,
1109                                  SEF_cp, (void *)SO->idcode_str,
1110                                  SES_Suma, NULL, NOPE,
1111                                  SEI_Tail, NULL ))) {
1112                      fprintf( SUMA_STDERR,
1113                               "Error %s: Failed to register command\n"
1114                               "Ignoring ...", FuncName);
1115                   }else {
1116                      int ti= 0;
1117                      SUMA_RegisterEngineListCommand (
1118                         list, ED,
1119                         SEF_s, (void *)("NodeList, FaceSetList, NodeNormList"),
1120                         SES_Suma, NULL, NOPE,
1121                         SEI_In, Elm );
1122                      SUMA_RegisterEngineListCommand (
1123                         list, ED,
1124                         SEF_i, (void *)&ti, /* 0, be quiet about it */
1125                         SES_Suma, NULL, NOPE,
1126                         SEI_In, Elm );
1127                      if (!SUMA_Engine (&list)) {
1128                         fprintf(SUMA_STDERR,
1129                            "Warning %s: SUMA_Engine call failed.\nContinuing...",
1130                            FuncName);
1131                      }
1132                   }
1133                }
1134             }
1135          } else {
1136             SUMA_LH("No talking to AFNI requested.");
1137          }
1138          /* don't free nel, it's freed later on */
1139          SUMA_RETURN(YUP) ;
1140       } /* PrepNewSurface */
1141 
1142       /* NewNode_XYZ NOW OBSOLETE, see comment for NewMesh_IJK*/
1143       if( strcmp(nel->name,"NewNode_XYZ") == 0) {/* NewNode_XYZ */
1144          SUMA_SL_Err("Obsolete element, please use SUMA_SurfaceObject "
1145                      "element instead");
1146          SUMA_RETURN(NOPE);
1147          if( nel->vec_len  < 1 || nel->vec_filled <  1) {/* empty element? */
1148             fprintf(SUMA_STDERR,"%s: Empty NewNode_XYZ\n", FuncName);
1149             SUMA_RETURN(NOPE);
1150          }else {
1151             if( nel->vec_num != 1 || nel->vec_typ[0] != NI_FLOAT) {
1152                  fprintf(SUMA_STDERR,"%s: NewNode_XYZ Bad format\n", FuncName);
1153                SUMA_RETURN(NOPE);
1154             }
1155          }
1156          /* show me nel */
1157          /* if (LocalHead) SUMA_nel_stdout (nel); */
1158 
1159          /* look for the surface idcode */
1160          nel_surfidcode = NI_get_attribute(nel, "surface_idcode");
1161          if (SUMA_IS_EMPTY_STR_ATTR(nel_surfidcode))
1162                nel_surfidcode = NI_get_attribute(nel, "domain_parent_idcode");
1163          if (SUMA_IS_EMPTY_STR_ATTR(nel_surfidcode)) {
1164             fprintf(SUMA_STDERR,
1165                     "Error %s: surface_idcode missing in nel (%s).\n",
1166                     FuncName, nel->name);
1167             SUMA_RETURN(NOPE);
1168          }
1169 
1170          SO = SUMA_findSOp_inDOv (nel_surfidcode, SUMAg_DOv, SUMAg_N_DOv);
1171          if (!SO) {
1172             SUMA_S_Err("%s: nel idcode is not found in DOv.\n", nel->name);
1173             SUMA_RETURN(NOPE);
1174          }
1175 
1176          /* now copy the new node coordinates over the old ones */
1177          if (nel->vec_len != SO->N_Node * 3) {
1178             SUMA_S_Err("Expected %d * 3 = %d values, found %d (%f * 3)\n",
1179                        SO->N_Node,
1180                        SO->N_Node * 3, nel->vec_len,
1181                        (float)nel->vec_len/3.0);
1182             SUMA_RETURN(NOPE);
1183          }
1184 
1185          XYZ = (float *)nel->vec[0];
1186          for (i=0; i < nel->vec_len; ++i) SO->NodeList[i] = XYZ[i];
1187 
1188          /* don't free nel, it's freed later on */
1189          SUMA_RETURN(YUP) ;
1190       } /* NewNode_XYZ */
1191 
1192       /* Node_XYZ */
1193       if( strcmp(nel->name,"Node_XYZ") == 0) {/* Node_XYZ */
1194          if( nel->vec_len  < 1 || nel->vec_filled <  1) {/* empty element?*/
1195             fprintf(SUMA_STDERR,"%s: Empty Node_XYZ\n", FuncName);
1196             SUMA_RETURN(NOPE);
1197          }else {
1198             if( nel->vec_num != 1 || nel->vec_typ[0] != NI_FLOAT) {
1199                  fprintf(SUMA_STDERR,"%s: Node_XYZ Bad format\n", FuncName);
1200                SUMA_RETURN(NOPE);
1201             }
1202          }
1203          /* show me nel */
1204          if (0 && LocalHead) SUMA_nel_stdout (nel);
1205 
1206          /* look for the surface idcode */
1207          nel_surfidcode = NI_get_attribute(nel, "surface_idcode");
1208          if (SUMA_IS_EMPTY_STR_ATTR(nel_surfidcode))
1209                nel_surfidcode = NI_get_attribute(nel, "domain_parent_idcode");
1210          if (SUMA_IS_EMPTY_STR_ATTR(nel_surfidcode)) {
1211             fprintf( SUMA_STDERR,
1212                      "Error %s: surface_idcode missing in nel (%s).\n",
1213                      FuncName, nel->name);
1214             SUMA_RETURN(NOPE);
1215          }
1216 
1217          SO = SUMA_findSOp_inDOv (nel_surfidcode, SUMAg_DOv, SUMAg_N_DOv);
1218          if (!SO) {
1219             SO = SUMA_findSOp_inDOv(
1220                   SUMA_find_SOidcode_from_label(NI_get_attribute(nel,
1221                                                 "Target_Object_Label"),
1222                                                 SUMAg_DOv, SUMAg_N_DOv),
1223                                                    SUMAg_DOv, SUMAg_N_DOv);
1224          }
1225          if (!SO) {
1226             SUMA_S_Err("%s: nel idcode (%s) is not found in DOv. "
1227                        "Object Label %s, Target Object Label %s.\n",
1228                         nel->name, nel_surfidcode,
1229                         NI_get_attribute (nel, "Object_Label"),
1230                         NI_get_attribute(nel, "Target_Object_Label"));
1231             SUMA_RETURN(NOPE);
1232          }
1233 
1234          /* now copy the new node coordinates over the old ones */
1235          if (nel->vec_len != SO->N_Node * 3) {
1236             SUMA_S_Err("Expected %d * 3 = %d values, found %d (%f * 3)\n",
1237                        SO->N_Node,
1238                        SO->N_Node * 3, nel->vec_len,
1239                        (float)nel->vec_len/3.0);
1240             SUMA_RETURN(NOPE);
1241          }
1242 
1243          XYZ = (float *)nel->vec[0];
1244          for (i=0; i < nel->vec_len; ++i) SO->NodeList[i] = XYZ[i];
1245 
1246          /* must recompute normals */
1247          SUMA_RECOMPUTE_NORMALS(SO);
1248 
1249          /* file a redisplay request */
1250          if (LocalHead) fprintf(SUMA_STDERR, "%s: Redisplaying all visible...\n", FuncName);
1251          if (!list) list = SUMA_CreateList();
1252          SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_Redisplay_AllVisible,
1253                                              SES_SumaFromAny, sv);
1254 
1255          /* Need to deal with "Send2Matlab" as per comment above */
1256          if (NI_get_attribute(nel, "Send2Afni")) {
1257             if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX]) {
1258                SUMA_LH("Putting request for sending to afni ...");
1259                ED = SUMA_InitializeEngineListData (SE_SetAfniThisSurf);
1260                if (!( Elm = SUMA_RegisterEngineListCommand (
1261                                  list, ED,
1262                                  SEF_cp, (void *)SO->idcode_str,
1263                                  SES_Suma, NULL, NOPE,
1264                                  SEI_Tail, NULL ))) {
1265                   fprintf(SUMA_STDERR,"Error %s: Failed to register command\n",
1266                           FuncName);
1267                   SUMA_RETURN(NOPE);
1268                }
1269 
1270                /* You could save time and not send the NodeNormList
1271                   but that means AFNI will end up with a bad set of
1272                   normals for the final version of the surface
1273                   not a good idea... */
1274                   SUMA_RegisterEngineListCommand (
1275                         list, ED,
1276                         SEF_s, (void *)("NodeList, NodeNormList"),
1277                         SES_Suma, NULL, NOPE,
1278                         SEI_In, Elm );
1279                   { int ti = 0; /* keep it quiet */
1280                      SUMA_RegisterEngineListCommand ( list, ED,
1281                                                    SEF_i, (void *)&ti,
1282                                                    SES_Suma, NULL, NOPE,
1283                                                    SEI_In, Elm );
1284                   }
1285             } else {
1286                if (LocalHead) {
1287                   SUMA_SL_Note("Cannot send surface to afni, "
1288                                "no connection established");
1289                }
1290             }
1291          }
1292 
1293          if (!SUMA_Engine (&list)) {
1294             fprintf( SUMA_STDERR, "Error %s: SUMA_Engine call failed.\n",
1295                      FuncName);
1296             SUMA_RETURN(NOPE);
1297          }
1298 
1299          /* don't free nel, it's freed later on */
1300          SUMA_RETURN(YUP) ;
1301 
1302 
1303       }/* Node_XYZ */
1304 
1305       /* SUMA_irgba Node colors */
1306       if(   strcmp(nel->name,"SUMA_irgba") == 0 ||
1307             strcmp(nel->name,"Node_RGBAb") == 0) {/* SUMA_irgba */
1308          SUMA_OVERLAYS *ColPlane=NULL;
1309          int itmp=-1,popit = 0;
1310 
1311          if( nel->vec_len  < 1 || nel->vec_filled <  1) { /* empty element?  */
1312             if (LocalHead)
1313                fprintf(SUMA_STDERR,"%s: Empty SUMA_irgba.\n", FuncName);
1314             Empty_irgba = YUP;
1315            }else {
1316             if(   nel->vec_num != 5 ||
1317                   nel->vec_typ[0] != NI_INT ||
1318                   nel->vec_typ[1] != NI_BYTE ||
1319                   nel->vec_typ[2] != NI_BYTE ||
1320                   nel->vec_typ[3] != NI_BYTE) {
1321                  fprintf(SUMA_STDERR,"%s: SUMA_irgba Bad format\n", FuncName);
1322                SUMA_RETURN(NOPE);
1323            }
1324          }
1325          #if SUMA_SUMA_NIML_DEBUG
1326             fprintf(SUMA_STDERR,"Warning %s:\nSleeping ONLY ...\n", FuncName);
1327             NI_sleep(200);
1328             SUMA_RETURN(YUP);
1329 
1330             if (0) {  /* At times, I found the value in nel->vec[0]
1331                         to be corrupted, use this to check on it */
1332                int *ibad;
1333                ibad = (int *)nel->vec[0];
1334                fprintf (SUMA_STDERR,"ibad[0] = %d\n", ibad[0]);
1335             }
1336          #endif
1337 
1338          /* show me nel */
1339          /* if (LocalHead) SUMA_nel_stdout (nel); */
1340 
1341          /* look for the surface idcode */
1342          nel_surfidcode = NI_get_attribute(nel, "surface_idcode");
1343          if (SUMA_IS_EMPTY_STR_ATTR(nel_surfidcode))
1344             nel_surfidcode = NI_get_attribute(nel, "domain_parent_idcode");
1345          if (SUMA_IS_EMPTY_STR_ATTR(nel_surfidcode)) {
1346             fprintf( SUMA_STDERR,
1347                      "Error %s: surface_idcode missing in nel (%s).\n",
1348                      FuncName, nel->name);
1349             SUMA_RETURN(NOPE);
1350          }
1351 
1352          ado = SUMA_whichADO(nel_surfidcode, SUMAg_DOv, SUMAg_N_DOv);
1353          if (!ado) {
1354             SUMA_S_Err("%s: nel idcode is not found in DOv.\n", nel->name);
1355             SUMA_RETURN(NOPE);
1356          }
1357          if (ado->do_type != SO_type && ado->do_type != TRACT_type) {
1358             SUMA_S_Err("Not ready to receive stuff for %s, only surfs and tracts"
1359                        , SUMA_ADO_Label(ado));
1360             SUMA_RETURN(NOPE);
1361          }
1362 
1363          /* store the node colors */
1364          /* create a color overlay plane */
1365          /* you could create an overlay plane with partial node coverage
1366             but you'd have to clean up and SUMA_reallocate
1367             with each new data sent since the number of colored nodes will
1368             change. So I'll allocate for the entire node list
1369             for the FuncAfni_0 color plane although only some values will
1370             be used*/
1371 
1372          memset(&sopd, 0, sizeof(SUMA_OVERLAY_PLANE_DATA));
1373          sopd.Type = SOPT_ibbb;
1374          sopd.Source = SES_Afni;
1375          sopd.GlobalOpacity = SUMA_AFNI_COLORPLANE_OPACITY;
1376          sopd.isBackGrnd = NOPE;
1377          sopd.Show = YUP;
1378          /* dim colors from maximum intensity to
1379             preserve surface shape highlights,
1380             division by is no longer necessary.
1381          */
1382          sopd.DimFact = SUMA_DIM_AFNI_COLOR_FACTOR;
1383          sopd.dtlvl = SUMA_ELEM_DAT;
1384 
1385          if (!Empty_irgba) {
1386             sopd.i = (void *)nel->vec[0];
1387             sopd.r = (void *)nel->vec[1];
1388             sopd.g = (void *)nel->vec[2];
1389             sopd.b = (void *)nel->vec[3];
1390             sopd.a = NULL;
1391             sopd.N = nel->vec_len;
1392          } else {
1393             sopd.i = sopd.r = sopd.g = sopd.b = sopd.a = NULL;
1394             sopd.N = 0;
1395          }
1396 
1397          if (!SUMA_Fetch_OverlayPointer(ado,
1398                         SUMA_AfniOverlayLabel(ado, 0), &itmp)) {
1399             /* first timer, pop it up */
1400             popit = 1;
1401          } else popit = 0;
1402 
1403          if (!SUMA_iRGB_to_OverlayPointer (  ado,
1404                                              SUMA_AfniOverlayLabel(ado, 0),
1405                                              &sopd, &OverInd,
1406                                              SUMAg_DOv, SUMAg_N_DOv,
1407                                              SUMAg_CF->DsetList)) {
1408             SUMA_SLP_Err("Failed to fetch or create overlay pointer.");
1409             SUMA_RETURN(NOPE);
1410          }
1411          if (popit) {
1412             ColPlane = SUMA_Fetch_OverlayPointer(ado,
1413                                           SUMA_AfniOverlayLabel(ado, 0),&itmp);
1414             if (!ColPlane) {
1415                SUMA_S_Err("Failed to find dset %s",
1416                            SUMA_AfniOverlayLabel(ado, 0));
1417             } else {
1418                if (LocalHead)
1419                   fprintf (SUMA_STDERR,
1420                            "%s: Retrieved ColPlane named %s\n",
1421                            FuncName, ColPlane->Name);
1422                SUMA_InitializeColPlaneShell(ado, ColPlane);
1423                SUMA_UpdateColPlaneShellAsNeeded(ado);
1424                               /* update other open ColPlaneShells */
1425                /* If you're viewing one plane at a time, do a remix */
1426                if (SUMA_ADO_ShowCurForeOnly(ado)) SUMA_Remixedisplay(ado);
1427             }
1428          }
1429          /* register a color remix request */
1430          if (LocalHead)
1431             fprintf( SUMA_STDERR,
1432                      "%s: Setting Remix Flag for all related objects. ...\n",
1433                      FuncName);
1434          if(!SUMA_SetRemixFlag (SUMA_ADO_idcode(ado), SUMAg_SVv, SUMAg_N_SVv)) {
1435             fprintf (SUMA_STDERR,
1436                      "Error %s: Failed in SUMA_SetRemixFlag.\n", FuncName);
1437             SUMA_RETURN(NOPE);
1438          }
1439 
1440          /* file a redisplay request */
1441          if (LocalHead)
1442             fprintf(SUMA_STDERR, "%s: Redisplaying all visible...\n", FuncName);
1443          if (!list) list = SUMA_CreateList();
1444          if (strcmp(nel->name,"SUMA_irgba") == 0) {
1445             /* call from AFNI */
1446             SUMA_REGISTER_HEAD_COMMAND_NO_DATA( list, SE_Redisplay_AllVisible,
1447                                                 SES_SumaFromAfni, sv);
1448          } else {
1449             SUMA_REGISTER_HEAD_COMMAND_NO_DATA(list, SE_Redisplay_AllVisible,
1450                                                 SES_SumaFromAny, sv);
1451          }
1452 
1453          if (!SUMA_Engine (&list)) {
1454             fprintf( SUMA_STDERR,
1455                      "Error %s: SUMA_Engine call failed.\n", FuncName);
1456             SUMA_RETURN(NOPE);
1457          }
1458 
1459          /* don't free nel, it's freed later on */
1460          SUMA_RETURN(YUP) ;
1461 
1462 
1463       }/* SUMA_irgba */
1464 
1465       if (!strcmp(nel->name,"AuRevoir")) {
1466          int cc = SUMA_AFNI_STREAM_INDEX;
1467          /* Afni's gone to sleep */
1468          SUMAg_CF->Connected_v[cc] = NOPE;
1469          if (SUMAg_CF->ns_v[cc])
1470             NI_stream_close( SUMAg_CF->ns_v[cc] ) ;
1471          SUMAg_CF->ns_v[cc] = NULL ;
1472          SUMA_S_Note("AFNI has bid us farewell");
1473          if (!list) list = SUMA_CreateList();
1474          ED = SUMA_InitializeEngineListData(SE_CloseStream4All);
1475          if (!SUMA_RegisterEngineListCommand ( list, ED,
1476                                           SEF_i, (void*)&cc,
1477                                           SES_Suma, (void *)sv, NOPE,
1478                                           SEI_Head, NULL)) {
1479             fprintf (SUMA_STDERR,
1480                   "Error %s: Failed to register command.\n", FuncName);
1481          }
1482 
1483          if (!SUMA_Engine (&list)) {
1484             fprintf (SUMA_STDERR,
1485                      "Error %s: Failed in SUMA_Engine.\n\a", FuncName);
1486          }
1487 
1488          SUMA_RETURN(YUP) ;
1489       }
1490 
1491       if ( strcmp(nel->name,"3dGroupInCorr_setup") == 0 ){
1492          SUMA_LH("Got me a 3dGroupInCorr_setup");
1493          if (!SUMA_GICOR_setup_func( SUMAg_CF->ns_v[SUMA_GICORR_LINE], nel )) {
1494             SUMA_S_Err("Catastropha!");
1495             SUMA_RETURN(NOPE);
1496          }
1497          SUMAg_CF->Connected_v[SUMA_GICORR_LINE] = YUP;
1498          SUMA_RETURN(YUP) ;
1499       }
1500 
1501       if( strcmp(nel->name,"3dGroupInCorr_dataset") == 0 ){
1502          SUMA_LH("Got me a 3dGroupInCorr_dataset");
1503          if (!SUMA_GICOR_process_dataset( nel  ) ) {
1504             SUMA_S_Err("Maledizione!");
1505             SUMA_RETURN(NOPE);
1506          }
1507          SUMA_RETURN(YUP) ;
1508       }
1509 
1510       /*** If here, then name of element didn't match anything ***/
1511 
1512       SUMA_S_Errv("Unknown NIML input: %s\n", nel->name) ;
1513       SUMA_RETURN(NOPE) ;
1514    } /* end parse nels */ else { /* is group */
1515       ngr = (NI_group *) nini ;
1516       if( strcmp(ngr->name,"SUMA_crosshair") == 0) {/* SUMA_crosshair */
1517          nel = SUMA_FindNgrNamedElement(ngr, "SUMA_crosshair_xyz"); /* XYZ */
1518          if (!nel) {
1519             SUMA_S_Err("Missing bare minimum of crosshair group");
1520             SUMA_RETURN(NOPE);
1521          }
1522          {/* SUMA_crosshair_xyz */
1523             int found_type = 0;
1524             SUMA_SurfaceObject *SOaf=NULL;
1525             DListElmt *Location=NULL;
1526             /* Do it for all viewers */
1527             for (iview = 0; iview < SUMAg_N_SVv; ++iview) {
1528                found_type = 0;
1529                svi = &(SUMAg_SVv[iview]);
1530                SUMA_LHv("Processing viewer %c\n", 65+iview);
1531                if (svi->LinkAfniCrossHair) {/* link cross hair */
1532 
1533                   /* Are we in Mask manip mode? */
1534                   if (MASK_MANIP_MODE(svi)) {
1535                      SUMA_MaskDO *mdo=NULL;
1536                      SUMA_ALL_DO *ado=NULL;
1537                      SUMA_LH("Moving mask, from AFNI");
1538                      if ((ado=SUMA_whichADOg(svi->MouseMode_ado_idcode_str)) &&
1539                            ado->do_type == MASK_type &&
1540                            nel->vec[0] && nel->vec_len == 3 &&
1541                            nel->vec_typ[0] == NI_FLOAT ) {
1542                         SUMA_NEW_MASKSTATE();
1543                         SUMA_MDO_New_Cen((SUMA_MaskDO *)ado,
1544                                           (float *)nel->vec[0]);
1545                         if (!list) list = SUMA_CreateList();
1546                         svi->ResetGLStateVariables = YUP;
1547 
1548                         /* Tell AFNI of new position */
1549                         ED = SUMA_InitializeEngineListData (SE_SetAfniMask);
1550                         mdo = (SUMA_MaskDO *)ado;
1551 
1552                         /* turn off dopplegangeriness */
1553                         SUMA_MDO_New_Doppel(mdo, NULL);
1554                         if (!(Location=
1555                                     SUMA_RegisterEngineListCommand (  list, ED,
1556                                                       SEF_fv3, (void*)mdo->cen,
1557                                                       SES_Suma, (void *)sv, NOPE,
1558                                                       SEI_Tail, NULL))) {
1559                            SUMA_S_Err("Failed to register element\n");
1560                            SUMA_RETURN (NOPE);
1561                         }
1562                         SUMA_RegisterEngineListCommand (  list, ED,
1563                                               SEF_s, (void *)(ADO_ID(ado)),
1564                                               SES_Suma, (void *)sv, NOPE,
1565                                               SEI_In, Location);
1566 
1567                         SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list, SE_Redisplay,
1568                                                      SES_SumaFromAfni, svi);
1569                         if (!SUMA_Engine (&list)) {
1570                            fprintf( SUMA_STDERR,
1571                                "Error %s: SUMA_Engine call failed.\n", FuncName);
1572                         }
1573                      }
1574 
1575                      /* Don't proceed, for now, if we're in mask nudging mode,
1576                      no need to parse for surfaces/node indices with all what
1577                      comes along. If you choose to go down that route, you
1578                      will need better handling of cases where there are no
1579                      surfaces specified with the cross hair location.
1580                      Talking no longer requires surfaces.... Apr. 2014 */
1581                      continue;
1582                   }
1583 
1584                   /* look for the surface idcode */
1585                   nel_surfidcode = NI_get_attribute(nel, "surface_idcode");
1586                   if (SUMA_IS_EMPTY_STR_ATTR(nel_surfidcode))
1587                      nel_surfidcode =
1588                         NI_get_attribute(nel, "domain_parent_idcode");
1589                   if (SUMA_IS_EMPTY_STR_ATTR(nel_surfidcode)) {
1590                      if (LocalHead)
1591                         fprintf(SUMA_STDERR,
1592                                "%s: surface_idcode missing in nel (%s), "
1593                                "using svi->Focus_DO_ID.\n", FuncName, nel->name);
1594                      if (!(SOaf = SUMA_SV_Focus_any_SO(svi, &dest_SO_ID))) {
1595                         SUMA_LH("No surface I can work with.\n"
1596                           "This happens in error or when talking without surfs");
1597                         SUMA_RETURN(NOPE);
1598                      }
1599                   } else {
1600                      SOaf = SUMA_findSOp_inDOv (nel_surfidcode,
1601                                                 SUMAg_DOv, SUMAg_N_DOv);
1602                      if (!SOaf) {
1603                         SUMA_S_Warn("AFNI sending unkown id %s, "
1604                                     "taking default for viewer",
1605                                     nel_surfidcode?nel_surfidcode:"NULL");
1606                         if (!(SOaf = SUMA_SV_Focus_any_SO(svi, NULL))) {
1607                            SUMA_S_Err("No surface I can work with");
1608                            SUMA_RETURN(NOPE);
1609                         }
1610                      }
1611 
1612                      /* first try to find out if one of the displayed surfaces
1613                         is or has a parent equal to nel_surfidcode */
1614                      if (LocalHead)
1615                         fprintf (SUMA_STDERR,
1616                                  "%s: Searching displayed surfaces.\n",
1617                                  FuncName);
1618                      N_SOlist = SUMA_RegisteredSOs(svi, SUMAg_DOv, SOlist);
1619                      Found = NOPE;
1620                      i = 0;
1621                      while (i < N_SOlist && !Found) {
1622                         SO = (SUMA_SurfaceObject *)(SUMAg_DOv[SOlist[i]].OP);
1623                         SUMA_LHv("Checking %s\n   %s versus\n   %s\n",
1624                                  SO->Label, nel_surfidcode, SO->idcode_str);
1625                         if (strcmp(nel_surfidcode, SO->idcode_str) == 0) {
1626                            Found = YUP;
1627                            dest_SO_ID = SOlist[i];
1628                            found_type = 1; /* found surface currently
1629                                               in viewer */
1630                         }
1631                         ++i;
1632                      }
1633                      if (!Found) { /* try for the parent */
1634                         i = 0;
1635                         while (i < N_SOlist && !Found) {
1636                            SO = (SUMA_SurfaceObject *)(SUMAg_DOv[SOlist[i]].OP);
1637                            SUMA_LHv("Checking %s\n   %s versus\n   %s\n",
1638                                     SO->Label, nel_surfidcode,
1639                                     SO->LocalDomainParentID);
1640                            if (SUMA_isRelated_SO(SOaf, SO, 1)) {
1641                               /* ZSS Aug. 06 (used to be:
1642                                  (strcmp( nel_surfidcode,
1643                                           SO->LocalDomainParentID) == 0) */
1644                               Found = YUP;
1645                               dest_SO_ID = SOlist[i];
1646                               found_type = 2;   /* found related surface
1647                                                    currently in viewer */
1648                           }
1649                            ++i;
1650                         }
1651                      }
1652                      /* if not found, look for any DO */
1653                      if (!Found) {
1654                         if (LocalHead)
1655                            fprintf (SUMA_STDERR,
1656                                     "%s: None of the displayed surfaces "
1657                                     "(or their parents) match nel_surfidcode. "
1658                                     "Trying all of DOv...\n", FuncName);
1659                         dest_SO_ID = SUMA_findSO_inDOv ( nel_surfidcode,
1660                                                          SUMAg_DOv, SUMAg_N_DOv);
1661                         if (dest_SO_ID < 0) {
1662                            if (LocalHead)
1663                               fprintf( SUMA_STDERR,
1664                                        "%s:%s: nel idcode is not "
1665                                        "found in DOv.\n",
1666                                        FuncName, nel->name);
1667                            SUMA_SV_Focus_any_SO(svi, &dest_SO_ID);
1668                         } else { /* good, set SO accordingly */
1669                            SO = (SUMA_SurfaceObject *)(SUMAg_DOv[dest_SO_ID].OP);
1670                            if (LocalHead)
1671                               fprintf( SUMA_STDOUT,
1672                                        "%s: DOv[%d] Matched idcode for "
1673                                        "surface (%s)\n",
1674                                        FuncName, dest_SO_ID, SO->Label);
1675                         }
1676                         found_type = 3;   /* found surface NOT in viewer */
1677                      }
1678                   }
1679 
1680                   if (dest_SO_ID < 0) {
1681                      SUMA_S_Err("Confounded Tintin!"
1682                                 "No surface for the life of me.");
1683                      SUMA_RETURN(NOPE);
1684                   }
1685                   SO = (SUMA_SurfaceObject *)(SUMAg_DOv[dest_SO_ID].OP);
1686 
1687                   if (LocalHead) SUMA_nel_stdout (nel);
1688 
1689                   /* check for node id */
1690                   nel_nodeid = NI_get_attribute (nel, "surface_nodeid");
1691                   if (!nel_nodeid) nodeid = -1;
1692                   else {
1693                      if (strlen(nel_nodeid))
1694                            nodeid = (int)strtod(nel_nodeid, NULL);
1695                      else nodeid = -1;
1696                   }
1697 
1698                   /*-- check element for suitability --*/
1699                   if( nel->vec_len    < 1 || nel->vec_filled <  1) {
1700                                     /* empty element?             */
1701                      SUMA_SLP_Warn ("Empty crosshair xyz.\n");
1702                      SUMA_RETURN(YUP);
1703                   }
1704 
1705                   if(   nel->vec_len != 3 || nel->vec_num != 1 ||
1706                         nel->vec_typ[0] != NI_FLOAT) {
1707                      SUMA_SLP_Err(  "SUMA_crosshair_xyz requires\n"
1708                                     "3 floats in one vector.\n");
1709                      SUMA_RETURN(NOPE);
1710                   }
1711 
1712                   /* nodeid is supplied, even if the distance from the cross hair
1713                      to the node is large,  set a limit */
1714                   if (nodeid >= 0) {
1715                      SUMA_LH("Node index courtesy of AFNI");
1716                      if (SO->AnatCorrect == YUP) {
1717                         I_C = nodeid; /* node index and XYZ are set by AFNI */
1718                         XYZ = (float *)SUMA_malloc(3*sizeof(float));
1719                         {  float *tf = nel->vec[0];
1720                            XYZ[0] = tf[0]; XYZ[1] = tf[1]; XYZ[2] = tf[2]; }
1721                      } else {
1722                         I_C = nodeid; /* node index is set by AFNI */
1723                         XYZ = SUMA_XYZmap_XYZ ( nel->vec[0], SO,
1724                                                 SUMAg_DOv, SUMAg_N_DOv, &I_C, 1);
1725                         if (!XYZ) {
1726                            XBell (svi->X->DPY, 50);
1727                            SUMA_SL_Warn("XYZ could not be determined\n"
1728                                         "No action taken.");
1729                            break;
1730                         }
1731                         I_C = nodeid; /* node index is set by AFNI */
1732                      }
1733                   } else {
1734                      SUMA_LH("Searching for node index.");
1735                      /* set the cross hair XYZ for now and let
1736                         SUMA_XYZmap_XYZ set the node index*/
1737                      I_C = -1;
1738                      XYZ = SUMA_XYZmap_XYZ ( nel->vec[0], SO,
1739                                              SUMAg_DOv, SUMAg_N_DOv, &I_C, 0);
1740 
1741                      if (XYZ == NULL || I_C < 0) {
1742                         SUMA_SL_Warn("AFNI cross hair too\n"
1743                                     "far from surface.\n"
1744                                     "No node id from AFNI.\n"
1745                                     "No action taken.");
1746                         XBell (svi->X->DPY, 50);
1747                         if (XYZ) SUMA_free(XYZ); XYZ = NULL;
1748                         break;
1749                      }
1750                   }
1751 
1752                   /* SUMA_nel_stdout (nel); */
1753                   if (iview == 0) {
1754                      fprintf(SUMA_STDOUT, "***********************\n"
1755                                           "AFNI cross hair notice:\n"
1756                                           "From Afni: \n"
1757                                           "  Surface: %s\n"
1758                                           "  Node: %s, XYZ: %3.2f %3.2f %3.2f\n",
1759                          SUMA_find_SOLabel_from_idcode(nel_surfidcode,
1760                                                        SUMAg_DOv, SUMAg_N_DOv),
1761                          SUMA_CHECK_NULL_STR(nel_nodeid),
1762                          *((float *)nel->vec[0]),
1763                          *((float *)nel->vec[0]+1),
1764                          *((float *)nel->vec[0]+2) );
1765                   }
1766                   fprintf(SUMA_STDOUT, "In Controller [%c]:\n"
1767                                        "  Surface: %s, adopted: %s\n"
1768                                        "  Node: %d, XYZ: %3.2f %3.2f %3.2f\n"
1769                                        ,
1770                                        65+iview,
1771                                        (found_type == 1 || found_type == 2) ?
1772                                              SO->Label:"NULL",
1773                                        SO->Label, I_C,
1774                                        XYZ[0], XYZ[1], XYZ[2]);
1775                   if (iview == SUMAg_N_SVv-1) {
1776                      fprintf(SUMA_STDOUT, "\n");
1777                   }
1778 
1779                   /* attach the cross hair to the selected surface */
1780                   iv3[0] = dest_SO_ID; /* nel_surfidcode == NULL is
1781                                              handled above, May 15 03*/
1782 
1783                   iv3[1] = I_C; /* use the closest node for a link
1784                                    otherwise when you switch states,
1785                                    you'll get a wandering cross hair */
1786                   iv3[2] = -1;
1787                   if (!list) list = SUMA_CreateList();
1788 
1789                   /* set the SO in Focus, if surface was visible */                                                                    /*ZSS Added this Aug. 06 */
1790                   if (found_type == 1 || found_type == 2) {
1791                      /* To set a surface in focus, it must be in the viewer.
1792                         If not, then SO in focus would be set to a surface that
1793                         is not in view, and that can lead to severe crashes.
1794                         One way to deal with that situation would be to make SUMA
1795                         switch state to that visible surface
1796                         but that's too visually complicated and jerky looking,
1797                         I would imagine. */
1798                      ED = SUMA_InitializeEngineListData (SE_SetSOinFocus);
1799                      if (!SUMA_RegisterEngineListCommand (
1800                                           list, ED,
1801                                           SEF_i, (void*)&dest_SO_ID,
1802                                           SES_SumaFromAfni, (void *)svi, NOPE,
1803                                           SEI_Head, NULL)) {
1804                         fprintf( SUMA_STDERR,
1805                                  "Error %s: Failed to register element\n",
1806                                  FuncName);
1807                         SUMA_RETURN (NOPE);
1808                      }
1809                   }
1810                   /* set selected node */          /*ZSS Added this Aug. 06 */
1811                   ED = SUMA_InitializeEngineListData (SE_SetSelectedNode);
1812                   if (!(el=SUMA_RegisterEngineListCommand (
1813                                        list, ED,
1814                                        SEF_i, (void*)&I_C,
1815                                        SES_SumaFromAfni, (void *)svi, NOPE,
1816                                        SEI_Tail, NULL))) {
1817                      fprintf( SUMA_STDERR,
1818                               "Error %s: Failed to register element\n",
1819                               FuncName);
1820                      SUMA_RETURN (NOPE);
1821                   } else {
1822                      /* add the whole damned group, EngineData would want
1823                         to work with it various components */
1824                      SUMA_RegisterEngineListCommand (
1825                                        list, ED,
1826                                        SEF_ngr, (void*)ngr,
1827                                        SES_SumaFromAfni, (void *)svi, NOPE,
1828                                        SEI_In, el);
1829                   }
1830 
1831                   ED = SUMA_InitializeEngineListData (SE_BindCrossHair);
1832                   if (!SUMA_RegisterEngineListCommand (
1833                                        list, ED,
1834                                        SEF_iv3, (void*)iv3,
1835                                        SES_SumaFromAfni, (void *)svi, NOPE,
1836                                        SEI_Tail, NULL)) {
1837                      fprintf( SUMA_STDERR,
1838                               "Error %s: Failed to register element\n",
1839                               FuncName);
1840                      SUMA_RETURN (NOPE);
1841                   }
1842 
1843                   /* send cross hair coordinates */
1844                   if (SO && SO->VisX.Applied ) {       /* apply VisX */
1845                      SUMA_Apply_VisX_Chain(XYZ, 1, SO->VisX.Xchain, 0);
1846                   }
1847                   ED = SUMA_InitializeEngineListData (SE_SetCrossHair);
1848                   if (!(Location=SUMA_RegisterEngineListCommand (
1849                                        list, ED,
1850                                        SEF_fv3, (void*)XYZ,
1851                                        SES_SumaFromAfni, svi, NOPE,
1852                                        SEI_Tail, NULL))) {
1853                      fprintf(SUMA_STDERR,
1854                              "Error %s: Failed to register element\n", FuncName);
1855                      SUMA_RETURN (NOPE);
1856                   }
1857                   /* and add the SO with this location*/
1858                   SUMA_RegisterEngineListCommand (  list, ED,
1859                                            SEF_vp, (void *)SO,
1860                                            SES_SumaFromAfni, (void *)svi, NOPE,
1861                                            SEI_In, Location);
1862 
1863                   svi->ResetGLStateVariables = YUP;
1864 
1865 
1866                   SUMA_REGISTER_TAIL_COMMAND_NO_DATA(list, SE_Redisplay,
1867                                                      SES_SumaFromAfni, svi);
1868                   if (!SUMA_Engine (&list)) {
1869                      fprintf( SUMA_STDERR,
1870                               "Error %s: SUMA_Engine call failed.\n", FuncName);
1871                   }
1872 
1873 
1874                   if (XYZ) SUMA_free(XYZ); XYZ = NULL;
1875                } /* link cross hair */
1876             } /* iview ... for all viewers */
1877             /* don't free nel, it's freed later on
1878                dont't free attributes obtained in NI_get_attribute,
1879                they are copies of pointers in nel  */
1880          }/* SUMA_crosshair_xyz */
1881          SUMA_RETURN(YUP) ;
1882       }/* SUMA_crosshair */
1883 
1884       if (strcmp(ngr->name,"SurfaceObject") == 0) { /* New Surface Object */
1885          SUMA_SurfaceObject *SOn=NULL;
1886 
1887          SOn = SUMA_nimlSO2SO(ngr);
1888          if (!SOn) {
1889             SUMA_SL_Err("Failed to interpret SO");
1890             SUMA_RETURN(NOPE) ;
1891          }
1892 
1893          SUMA_LH("Checking for new surface...");
1894          SO = SUMA_findSOp_inDOv (SOn->idcode_str, SUMAg_DOv, SUMAg_N_DOv);
1895          if (SO) {
1896             fprintf(SUMA_STDERR,"Warning %s: nel idcode was found in DOv.\n"
1897                                 "Checking for mesh compatibility\n", FuncName);
1898             if (  SO->N_FaceSet * SO->FaceSetDim ==
1899                   SOn->N_FaceSet * SOn->FaceSetDim) {
1900                fprintf(SUMA_STDERR,"Note %s: Mesh dimensions match. \n"
1901                                    "New mesh will be adopted.\n", FuncName);
1902             } else {
1903                fprintf( SUMA_STDERR,"Error %s: Mesh dimensions mismatch.\n",
1904                         FuncName);
1905                SUMA_RETURN(NOPE);
1906             }
1907          }
1908 
1909          if (!SO) {
1910             BrandNew = YUP;
1911          } else {
1912             SUMA_LHv("A refit of an existing surface. SO->SurfCont = %p\n",
1913                      SO->SurfCont);
1914             BrandNew = NOPE;
1915             if (SOn->N_Node != SO->N_Node) {
1916                fprintf(SUMA_STDERR,"Error %s: Mismatch in number of nodes\n"
1917                                    "between new mesh and pre-existing one\n"
1918                                    "(%d vs %d)\n",
1919                                    FuncName, SO->N_Node, SO->N_Node);
1920                SUMA_RETURN(NOPE);
1921             }
1922             memcpy((void*)SO->FaceSetList, (void *)SOn->FaceSetList,
1923                    SOn->N_FaceSet * SOn->FaceSetDim * sizeof(int));
1924                            /* this one's likely to be completely useless! */
1925             memcpy((void*)SO->NodeList, (void *)SOn->NodeList,
1926                    SOn->N_Node * SOn->NodeDim * sizeof(float));
1927             /* swap VolPar */
1928             if (SOn->VolPar) {
1929                if (SO->VolPar) SUMA_Free_VolPar(SO->VolPar);
1930                SO->VolPar = SOn->VolPar;
1931                SOn->VolPar = NULL;
1932             }
1933             SUMA_Free_Surface_Object(SOn); SOn = NULL;
1934                   /* alas, not needed no more.
1935                      Perhaps you should consider eliminating SO's EdgeLists,
1936                      area vectors and the like,
1937                      You should also perhaps update VolPar with SOn's... */
1938             SUMA_LHv("Refit done, SO->SurfCont = %p\n", SO->SurfCont);
1939          }
1940 
1941          /* add this surface to DOv */
1942          if (BrandNew) {
1943             if (!SUMA_AddDO(SUMAg_DOv, &(SUMAg_N_DOv),
1944                             (void *)SOn,  SO_type, SUMA_WORLD)) {
1945                fprintf(SUMA_STDERR,"Error %s: Error Adding DO\n", FuncName);
1946                SUMA_RETURN(NOPE);
1947             }
1948             SUMA_LHv("A brand new surface. SO->SurfCont = %p\n", SOn->SurfCont);
1949          }
1950 
1951          /* don't free nel, it's freed later on */
1952          SUMA_RETURN(YUP) ;
1953       } else if (strcmp(ngr->name,"EngineCommand") == 0) {
1954          SUMA_nimlEngine2Engine(ngr);
1955          /* don't free nel, it's freed later on */
1956          SUMA_RETURN(YUP) ;
1957       } else if (strcmp(ngr->name,"Segment_DO") == 0) {
1958          SUMA_SegmentDO *SDO = SUMA_niSDO2SDO(ngr);
1959          /* addDO (mixing is taken care of internally)*/
1960          if (!SUMA_AddDO(SUMAg_DOv, &SUMAg_N_DOv, (void *)SDO,
1961                          SDO->do_type, SUMA_WORLD)) {
1962             fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AddDO.\n", FuncName);
1963             SUMA_RETURN(NOPE);
1964          }
1965 
1966          if (!sv) sv = &(SUMAg_SVv[0]);
1967 
1968          /* register DO with viewer */
1969          if (!SUMA_RegisterDO(SUMAg_N_DOv-1, sv)) {
1970             fprintf( SUMA_STDERR,
1971                      "Error %s: Failed in SUMA_RegisterDO.\n", FuncName);
1972             SUMA_RETURN(NOPE);
1973          }
1974 
1975          /* redisplay curent only*/
1976          sv->ResetGLStateVariables = YUP;
1977          SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
1978 
1979          /* don't free nel, it's freed later on */
1980          SUMA_RETURN(YUP);
1981       } else if (strcmp(ngr->name,"network") == 0) {
1982          SUMA_TractDO *TDO=NULL;
1983          TAYLOR_NETWORK *net=NULL;
1984          SUMA_LH( "I got me some network. FIX ME. "
1985                   "Check ADO replacement, registration, etc.!");
1986          /* SUMA_ShowNel(ngr); */
1987          if (!(net = NIgr_2_Network(ngr))) {
1988             SUMA_S_Err("Failed to turn group element to network\n");
1989             SUMA_RETURN(NOPE);
1990          }
1991          if (!(TDO = SUMA_Net2TractDO(net, "InstaTract", NULL))) {
1992             SUMA_S_Err("Failed to turn net to TDO\n");
1993             SUMA_RETURN(NOPE);
1994          }
1995 
1996          if (!SUMA_AddDO(SUMAg_DOv, &SUMAg_N_DOv, (void *)TDO,
1997                          TDO->do_type, SUMA_WORLD)) {
1998             fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_AddDO.\n", FuncName);
1999             SUMA_RETURN(NOPE);
2000          }
2001 
2002          if (!sv) sv = &(SUMAg_SVv[0]);
2003 
2004          /* register DO with viewer */
2005          if (!SUMA_RegisterDO(SUMAg_N_DOv-1, sv)) {
2006             fprintf( SUMA_STDERR,
2007                      "Error %s: Failed in SUMA_RegisterDO.\n", FuncName);
2008             SUMA_RETURN(NOPE);
2009          }
2010 
2011          /* redisplay curent only*/
2012          sv->ResetGLStateVariables = YUP;
2013          SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
2014 
2015          /* don't free ngr, it's freed later on */
2016          SUMA_RETURN(YUP);
2017       } else if (strcmp(ngr->name,"IT.griddef") == 0) {
2018          NI_group *gngr=NULL;
2019 
2020          SUMAg_CF->ITset = New_Insta_Tract_Setup(SUMAg_CF->ITset);
2021          SUMA_LH("Grid from InstaTract");
2022          if (!(gngr = (NI_group *)SUMA_FindNgrNamedAny(ngr, "AFNI_dataset"))) {
2023             SUMA_S_Err("Failed to get grid element");
2024             SUMA_RETURN(NOPE);
2025          }
2026          if (!(SUMAg_CF->ITset->grid = THD_niml_to_dataset( gngr , 1 ))) {
2027             SUMA_S_Err("Failed to get grid");
2028             SUMA_RETURN(NOPE);
2029          }
2030          SUMA_LH("Yay!");
2031          /* don't free ngr, it's freed later on */
2032          SUMA_RETURN(YUP);
2033       }
2034 
2035       /*** If here, then name of group didn't match anything
2036            Try processing its parts ***/
2037       if (LocalHead)  {
2038          fprintf(SUMA_STDERR,"%s:  Working group %s \n", FuncName, ngr->name);
2039       }
2040       for( ip=0 ; ip < ngr->part_num ; ip++ ){
2041          switch( ngr->part_typ[ip] ){
2042             /*-- a sub-group ==> recursion! --*/
2043             case NI_GROUP_TYPE:
2044                if (!SUMA_process_NIML_data( (VOID_CAST)ngr->part_typ[ip] , sv)) {
2045                   NI_group *ngr2=(NIGRP_CAST)ngr->part_typ[ip];
2046                   SUMA_S_Errv("Failed in SUMA_process_NIML_data for\n"
2047                               " group %s's subgroup %s\n",
2048                               ngr->name, ngr2->name);
2049                }
2050                break ;
2051             case NI_ELEMENT_TYPE:
2052                nel = (NI_element *)ngr->part[ip] ;
2053                if (!SUMA_process_NIML_data( (void *)nel , sv)) {
2054                      SUMA_S_Errv("Failed in SUMA_process_NIML_data for \n"
2055                                  " group %s's element %s\n",
2056                                  ngr->name, nel->name);
2057                }
2058                break;
2059             default:
2060                SUMA_SL_Err("Don't know what to make of this group element\n"
2061                            "ignoring.");
2062                break;
2063          }
2064       }
2065       SUMA_RETURN(YUP) ;
2066    }
2067 }
2068 
2069 /*------------------------------------------------------------------*/
2070 /*! Make a NIML data element for a NI surface element IXYZ
2071    \param SO (SUMA_SurfaceObject *) surface object to turn to NI
2072    \ret  NULL if you input stupid values, NI if you input smart values
2073 --------------------------------------------------------------------*/
2074 
SUMA_makeNI_SurfIXYZ(SUMA_SurfaceObject * SO)2075 NI_element * SUMA_makeNI_SurfIXYZ (SUMA_SurfaceObject *SO)
2076 {
2077    static char FuncName[]={"SUMA_makeNI_SurfIXYZ"};
2078    NI_element *nel;
2079    int *ic, ii, ND, id;
2080    float *xc, *yc, *zc;
2081 
2082    SUMA_ENTRY;
2083 
2084 
2085    if (SO == NULL) {
2086       fprintf(SUMA_STDERR,"Error %s: Null SO.\n", FuncName);
2087       SUMA_RETURN (NULL);
2088    }
2089    if (SO->N_Node <= 0) {
2090       fprintf(SUMA_STDERR,"Error %s: No nodes in SO.\n", FuncName);
2091       SUMA_RETURN (NULL);
2092    }
2093 
2094    /* make a new data element, to be filled by columns */
2095    nel = NI_new_data_element( "SUMA_ixyz" , SO->N_Node) ;
2096 
2097    /* make the columns to be put in the element */
2098    ic = (int *)   SUMA_malloc( sizeof(int)   * SO->N_Node ) ;
2099    xc = (float *) SUMA_malloc( sizeof(float) * SO->N_Node ) ;
2100    yc = (float *) SUMA_malloc( sizeof(float) * SO->N_Node ) ;
2101    zc = (float *) SUMA_malloc( sizeof(float) * SO->N_Node ) ;
2102 
2103    if (!nel || !ic || !xc || !yc || !zc) {
2104       SUMA_S_Err("Failed to allocate for nel, ic, xc, yc or zc.\n");
2105       SUMA_RETURN (NULL);
2106    }
2107 
2108 
2109    /* load the columns from the struct array */
2110    ND = SO->NodeDim;
2111    for( ii=0 ; ii < SO->N_Node ; ii++ ){
2112       ic[ii] = ii;
2113       id = ND * ii;
2114       xc[ii] = SO->NodeList[id];
2115       yc[ii] = SO->NodeList[id+1];
2116       zc[ii] = SO->NodeList[id+2];
2117    }
2118 
2119    /* put columns into element */
2120 
2121    NI_add_column( nel , NI_INT   , ic ) ; SUMA_free(ic) ;
2122    NI_add_column( nel , NI_FLOAT , xc ) ; SUMA_free(xc) ;
2123    NI_add_column( nel , NI_FLOAT , yc ) ; SUMA_free(yc) ;
2124    NI_add_column( nel , NI_FLOAT , zc ) ; SUMA_free(zc) ;
2125 
2126    if (SO->VolPar) {
2127       NI_set_attribute (nel, "volume_idcode", SO->VolPar->vol_idcode_str);
2128       NI_set_attribute (nel, "volume_filecode", SO->VolPar->filecode);
2129       NI_set_attribute (nel, "volume_headname", SO->VolPar->headname);
2130       NI_set_attribute (nel, "volume_dirname", SO->VolPar->dirname);
2131    }
2132    NI_set_attribute (nel, "surface_idcode", SO->idcode_str);
2133    NI_set_attribute (nel, "surface_label", SO->Label);
2134    NI_set_attribute (nel, "local_domain_parent_ID", SO->LocalDomainParentID);
2135    NI_set_attribute (nel, "local_domain_parent", SO->LocalDomainParent);
2136    if (SO->SpecFile.FileName)
2137       NI_set_attribute (nel, "surface_specfile_name", SO->SpecFile.FileName);
2138    else NI_set_attribute (nel, "surface_specfile_name", "Unknown");
2139    if (SO->SpecFile.Path)
2140       NI_set_attribute (nel, "surface_specfile_path", SO->SpecFile.Path);
2141    else NI_set_attribute (nel, "surface_specfile_path", "Unknown");
2142 
2143    SUMA_RETURN (nel);
2144 }
2145 
SUMA_offset_NI_SurfIXYZ(NI_element * nel,float * del)2146 int SUMA_offset_NI_SurfIXYZ (NI_element *nel, float *del)
2147 {
2148    static char FuncName[]={"SUMA_offset_NI_SurfIXYZ"};
2149    float *x, *y, *z;
2150    int i;
2151 
2152    SUMA_ENTRY;
2153 
2154    if (!nel || !del || nel->vec_num != 4 || nel->vec_len < 1) SUMA_RETURN(0);
2155 
2156    x = (float *)nel->vec[1];
2157    y = (float *)nel->vec[2];
2158    z = (float *)nel->vec[3];
2159 
2160    if (!x || !y || !z) SUMA_RETURN(0);
2161 
2162    for (i=0; i<nel->vec_len; ++i) {
2163       x[i] += del[0];
2164       y[i] += del[1];
2165       z[i] += del[2];
2166    }
2167 
2168    SUMA_RETURN(1);
2169 }
2170 
2171 /*------------------------------------------------------------------*/
2172 /*! Make a NIML data element for a NI surface element i nx ny nz
2173     onde index followed by node normal
2174    \param SO (SUMA_SurfaceObject *) surface object to turn to NI
2175    \ret  NULL if you input stupid values, NI if you input smart values
2176 --------------------------------------------------------------------*/
2177 /* #define DOINDEX */ /* uncomment if you want to pass node index along with normals */
SUMA_makeNI_SurfINORM(SUMA_SurfaceObject * SO)2178 NI_element * SUMA_makeNI_SurfINORM (SUMA_SurfaceObject *SO)
2179 {
2180    static char FuncName[]={"SUMA_makeNI_SurfINORM"};
2181    NI_element *nel=NULL;
2182    int *ic=NULL, ii, ND, id;
2183    float *xc=NULL, *yc=NULL, *zc=NULL;
2184 
2185    SUMA_ENTRY;
2186 
2187 
2188    if (SO == NULL) {
2189       fprintf(SUMA_STDERR,"Error %s: Null SO.\n", FuncName);
2190       SUMA_RETURN (NULL);
2191    }
2192    if (SO->N_Node <= 0) {
2193       fprintf(SUMA_STDERR,"Error %s: No nodes in SO.\n", FuncName);
2194       SUMA_RETURN (NULL);
2195    }
2196    if (!SO->NodeNormList) {
2197       fprintf(SUMA_STDERR,"Error %s: No normals in SO.\n", FuncName);
2198       SUMA_RETURN (NULL);
2199    }
2200    /* make a new data element, to be filled by columns */
2201    nel = NI_new_data_element( "SUMA_node_normals" , SO->N_Node) ;
2202 
2203    /* make the columns to be put in the element */
2204    #ifdef DOINDEX
2205    ic = (int *)   SUMA_malloc( sizeof(int)   * SO->N_Node ) ;
2206    #endif
2207    xc = (float *) SUMA_malloc( sizeof(float) * SO->N_Node ) ;
2208    yc = (float *) SUMA_malloc( sizeof(float) * SO->N_Node ) ;
2209    zc = (float *) SUMA_malloc( sizeof(float) * SO->N_Node ) ;
2210 
2211    if (!nel || !xc || !yc || !zc) {
2212       fprintf(SUMA_STDERR,"Error %s: Failed to allocate for nel, ic, xc, yc or zc.\n", FuncName);
2213       SUMA_RETURN (NULL);
2214    }
2215 
2216 
2217    /* load the columns from the struct array */
2218    ND = SO->NodeDim;
2219    for( ii=0 ; ii < SO->N_Node ; ii++ ){
2220    #ifdef DOINDEX
2221       ic[ii] = ii;
2222    #endif
2223       id = ND * ii;
2224       xc[ii] = SO->NodeNormList[id];
2225       yc[ii] = SO->NodeNormList[id+1];
2226       zc[ii] = SO->NodeNormList[id+2];
2227    }
2228 
2229    /* put columns into element */
2230 
2231    #ifdef DOINDEX
2232       NI_add_column( nel , NI_INT   , ic ) ; SUMA_free(ic) ;
2233    #endif
2234    NI_add_column( nel , NI_FLOAT , xc ) ; SUMA_free(xc) ;
2235    NI_add_column( nel , NI_FLOAT , yc ) ; SUMA_free(yc) ;
2236    NI_add_column( nel , NI_FLOAT , zc ) ; SUMA_free(zc) ;
2237    if (SO->VolPar) {
2238       NI_set_attribute (nel, "volume_idcode", SO->VolPar->vol_idcode_str);
2239       NI_set_attribute (nel, "volume_headname", SO->VolPar->headname);
2240       NI_set_attribute (nel, "volume_filecode", SO->VolPar->filecode);
2241       NI_set_attribute (nel, "volume_dirname", SO->VolPar->dirname);
2242    }
2243    NI_set_attribute (nel, "surface_idcode", SO->idcode_str);
2244    NI_set_attribute (nel, "surface_label", SO->Label);
2245    NI_set_attribute (nel, "local_domain_parent_ID", SO->LocalDomainParentID);
2246    NI_set_attribute (nel, "local_domain_parent", SO->LocalDomainParent);
2247    SUMA_RETURN (nel);
2248 }
2249 
2250 /*------------------------------------------------------------------*/
2251 /*! Make a NIML data element for a NI surface element IJK
2252    \param SO (SUMA_SurfaceObject *) surface object to turn to NI
2253    \ret  NULL if you input stupid values, NI if you input smart values
2254 --------------------------------------------------------------------*/
2255 
SUMA_makeNI_SurfIJK(SUMA_SurfaceObject * SO)2256 NI_element * SUMA_makeNI_SurfIJK (SUMA_SurfaceObject *SO)
2257 {
2258    static char FuncName[]={"SUMA_makeNI_SurfIJK"};
2259    NI_element *nel;
2260    int  ii,  ip, NP;
2261    int *I, *J, *K;
2262 
2263    SUMA_ENTRY;
2264 
2265 
2266    if (SO == NULL) {
2267       fprintf(SUMA_STDERR,"Error %s: Null SO.\n", FuncName);
2268       SUMA_RETURN (NULL);
2269    }
2270    if (SO->N_FaceSet <= 0) {
2271       fprintf(SUMA_STDERR,"Error %s: No FaceSets in SO.\n", FuncName);
2272       SUMA_RETURN (NULL);
2273    }
2274 
2275    NP = SO->FaceSetDim;
2276    /* make a new data element, to be filled by columns */
2277    nel = NI_new_data_element( "SUMA_ijk" , SO->N_FaceSet) ;
2278 
2279    /* make the columns to be put in the element */
2280    I = (int *) SUMA_malloc( sizeof(int) * SO->N_FaceSet ) ;
2281    J = (int *) SUMA_malloc( sizeof(int) * SO->N_FaceSet ) ;
2282    K = (int *) SUMA_malloc( sizeof(int) * SO->N_FaceSet ) ;
2283 
2284    if (!nel || !I || !J || !K ) {
2285       fprintf(SUMA_STDERR,"Error %s: Failed to allocate for nel, I, J or K.\n", FuncName);
2286       SUMA_RETURN (NULL);
2287    }
2288 
2289 
2290    /* load the columns from the struct array */
2291 
2292    for( ii=0 ; ii < SO->N_FaceSet ; ii++ ){
2293       ip = NP * ii;
2294       I[ii] = SO->FaceSetList[ip];
2295       J[ii] = SO->FaceSetList[ip+1];
2296       K[ii] = SO->FaceSetList[ip+2];
2297    }
2298 
2299    /* put columns into element */
2300 
2301    NI_add_column( nel , NI_INT   , I ) ; SUMA_free(I) ;
2302    NI_add_column( nel , NI_INT   , J ) ; SUMA_free(J) ;
2303    NI_add_column( nel , NI_INT   , K ) ; SUMA_free(K) ;
2304 
2305    if (SO->VolPar) {
2306       NI_set_attribute (nel, "volume_idcode", SO->VolPar->vol_idcode_str);
2307    }
2308 
2309    NI_set_attribute (nel, "surface_idcode", SO->idcode_str);
2310    NI_set_attribute (nel, "surface_label", SO->Label);
2311    NI_set_attribute (nel, "local_domain_parent_ID", SO->LocalDomainParentID);
2312    NI_set_attribute (nel, "local_domain_parent", SO->LocalDomainParent);
2313    if (SO->SpecFile.FileName)
2314       NI_set_attribute (nel, "surface_specfile_name", SO->SpecFile.FileName);
2315    else NI_set_attribute (nel, "surface_specfile_name", "Unknown");
2316    if (SO->SpecFile.Path)
2317       NI_set_attribute (nel, "surface_specfile_path", SO->SpecFile.Path);
2318    else NI_set_attribute (nel, "surface_specfile_path", "Unknown");
2319 
2320    SUMA_RETURN (nel);
2321 }
2322 
SUMA_nel_stdout(NI_element * nel)2323 SUMA_Boolean SUMA_nel_stdout (NI_element *nel)
2324 {
2325    static char FuncName[]={"SUMA_nel_stdout"};
2326    NI_stream nstdout;
2327 
2328    SUMA_ENTRY;
2329 
2330    nstdout = NI_stream_open( "fd:1","w");
2331    if( nstdout == NULL ){
2332       fprintf(SUMA_STDERR,"%s: Can't open fd:1\n", FuncName);
2333       SUMA_RETURN(NOPE);
2334    }
2335    fprintf (stdout,
2336       "\n----------------------------nel stdout begin-------------------\n");
2337    NI_write_element( nstdout , nel , NI_TEXT_MODE ) ;
2338    fprintf (stdout,
2339       "----------------------------nel stdout end  -------------------\n");
2340    NI_stream_close(nstdout);
2341 
2342    SUMA_RETURN(YUP);
2343 }
2344 
SUMA_makeNI_CrossHair(SUMA_SurfaceViewer * sv)2345 NI_element * SUMA_makeNI_CrossHair (SUMA_SurfaceViewer *sv)
2346 {
2347    static char FuncName[]={"SUMA_makeNI_CrossHair"};
2348    NI_element *nel=NULL;
2349    float *XYZmap;
2350    int I_C = -1, ip, ivsel[SUMA_N_IALTSEL_TYPES];
2351    SUMA_ALL_DO *ado = NULL;
2352    SUMA_OVERLAYS *curColPlane=NULL;
2353    SUMA_DSET *curDset=NULL;
2354    SUMA_Boolean LocalHead = NOPE;
2355 
2356    SUMA_ENTRY;
2357 
2358    if (sv == NULL) {
2359       fprintf(SUMA_STDERR,"Error %s: Null sv.\n", FuncName);
2360       SUMA_RETURN (NULL);
2361    }
2362    if (sv->Ch == NULL) {
2363       fprintf(SUMA_STDERR,"Error %s: NULL Ch.\n", FuncName);
2364       SUMA_RETURN (NULL);
2365    }
2366 
2367    if (!(ado=SUMA_SV_Focus_ADO(sv))) {
2368       SUMA_S_Warn("No ADO in focus.");
2369       SUMA_RETURN(NULL);
2370    }
2371    switch(ado->do_type) {
2372       case SO_type: {
2373          SUMA_SurfaceObject *SO=NULL;
2374          SO = (SUMA_SurfaceObject *)ado;
2375          I_C = SO->SelectedNode;
2376          XYZmap = SUMA_XYZ_XYZmap (sv->Ch->c_noVisX, SO,
2377                                    SUMAg_DOv, SUMAg_N_DOv, &I_C, 0);
2378 
2379          if (XYZmap == NULL){
2380             SUMA_S_Err("Linkage is not posible, using current XYZ");
2381             XYZmap = (float *)SUMA_calloc (3, sizeof(float));
2382             if (XYZmap == NULL) {
2383                SUMA_S_Err("Give me a break !");
2384                SUMA_RETURN (NULL);
2385             }
2386             XYZmap[0] = sv->Ch->c[0];
2387             XYZmap[1] = sv->Ch->c[1];
2388             XYZmap[2] = sv->Ch->c[2];
2389          }
2390 
2391          /* make a new data element */
2392          if (!(nel= NI_new_data_element( "SUMA_crosshair_xyz" , 3))) {
2393             SUMA_S_Err("Failed to allocate for nel");
2394             SUMA_RETURN (NULL);
2395          }
2396 
2397          /* add some info about surface in question */
2398          NI_SETA_INT(nel, "surface_nodeid", SO->SelectedNode);
2399          NI_set_attribute( nel, "surface_idcode", SO->idcode_str);
2400          NI_set_attribute( nel, "surface_label", SO->Label);
2401          /* Add info about overlay */
2402 
2403          NI_add_column( nel , NI_FLOAT , XYZmap );
2404 
2405          if (XYZmap) SUMA_free(XYZmap);
2406          break; }
2407       case TRACT_type:
2408          if (!(nel= NI_new_data_element( "SUMA_crosshair_xyz" , 3))) {
2409             SUMA_S_Err("Failed to allocate for nel");
2410             SUMA_RETURN (NULL);
2411          }
2412 
2413          /* add some info about surface in question */
2414          ip = SUMA_ADO_SelectedDatum(ado, (void *)ivsel, NULL);
2415          NI_SETA_INT(nel, "network_pointid", ip);
2416          NI_SETA_INT(nel, "net_bundle_id", ivsel[SUMA_NET_BUN]);
2417          NI_SETA_INT(nel, "bundle_tract_id", ivsel[SUMA_BUN_TRC]);
2418          NI_SETA_INT(nel, "tract_point_id", ivsel[SUMA_TRC_PNT]);
2419          NI_SETA_INT(nel, "net_tract_id", ivsel[SUMA_NET_TRC]);
2420          NI_set_attribute(nel, "network_idcode", ADO_ID(ado));
2421          NI_set_attribute(nel, "surface_label", ADO_LABEL(ado));
2422 
2423          NI_add_column( nel , NI_FLOAT , sv->Ch->c_noVisX );
2424          break;
2425       case MASK_type:
2426          if (!(nel= NI_new_data_element( "SUMA_crosshair_xyz" , 3))) {
2427             SUMA_S_Err("Failed to allocate for nel");
2428             SUMA_RETURN (NULL);
2429          }
2430 
2431          /* add some info about surface in question */
2432          ip = SUMA_ADO_SelectedDatum(ado, (void *)ivsel, NULL);
2433          NI_add_column( nel , NI_FLOAT , sv->Ch->c_noVisX );
2434          break;
2435       case GDSET_type:
2436          break;
2437       case CDOM_type:
2438          SUMA_S_Err("Implement me");SUMA_RETURN (NULL);
2439          break;
2440       case GRAPH_LINK_type:
2441          if (strcmp(SUMA_ADO_variant(ado),"G3D")) break;
2442          if (!(nel= NI_new_data_element( "SUMA_crosshair_xyz" , 3))) {
2443             SUMA_S_Err("Failed to allocate for nel");
2444             SUMA_RETURN (NULL);
2445          }
2446 
2447          /* add some info about object in question */
2448          ip = SUMA_ADO_SelectedDatum(ado, NULL, NULL);
2449          NI_SETA_INT(nel, "edge_id", ip);
2450          NI_set_attribute(nel, "graph_idcode", ADO_ID(ado));
2451          NI_set_attribute(nel, "graph_label", ADO_LABEL(ado));
2452 
2453          NI_add_column( nel , NI_FLOAT , sv->Ch->c_noVisX );
2454          break;
2455       case VO_type:
2456          if (!(nel= NI_new_data_element( "SUMA_crosshair_xyz" , 3))) {
2457             SUMA_S_Err("Failed to allocate for nel");
2458             SUMA_RETURN (NULL);
2459          }
2460 
2461          /* add some info about object in question */
2462          ip = SUMA_ADO_SelectedDatum(ado, (void*)ivsel, NULL);
2463          NI_SETA_INT(nel, "voxel_id", ip);
2464          NI_set_attribute(nel, "volume_idcode", ADO_ID(ado));
2465          NI_set_attribute(nel, "volume_label", ADO_LABEL(ado));
2466 
2467          NI_add_column( nel , NI_FLOAT , sv->Ch->c_noVisX );
2468          break;
2469       default:
2470          SUMA_LH("No nel for type %s", ADO_TNAME(ado));
2471          break;
2472    }
2473 
2474    /* add dset of current colplane (ZSS April 2014, for NNO) */
2475    if (  nel && (curColPlane = SUMA_ADO_CurColPlane(ado)) &&
2476          (curDset = curColPlane->dset_link) && !SDSET_IS_VOL(curDset) ) {
2477       char *s=NULL;
2478       if ((s = SDSET_FILENAME(curDset))) {
2479          NI_set_attribute(nel, "current_overlay_dset_id",
2480                                SDSET_ID(curDset));
2481          NI_set_attribute(nel, "current_overlay_dset_filename", s);
2482          if (LocalHead) {
2483             SUMA_LH("Nel with overlay info");
2484             SUMA_ShowNel(nel);
2485          }
2486       }
2487    }
2488 
2489    SUMA_RETURN (nel);
2490 }
2491 
SUMA_makeNI_InstaTract_Query(SUMA_SurfaceViewer * sv)2492 NI_group * SUMA_makeNI_InstaTract_Query (SUMA_SurfaceViewer *sv)
2493 {
2494    static char FuncName[]={"SUMA_makeNI_InstaTract_Query"};
2495    NI_element *nel=NULL;
2496    NI_group *ngr=NULL;
2497    THD_3dim_dataset *gset=NULL;
2498    float *XYZmap, find[3];
2499    int I_C = -1, ip, iv4[4], *nind=NULL, ninmask=-1;
2500    SUMA_ALL_DO *ado = NULL;
2501    SUMA_SurfaceObject *SO=NULL;
2502    MCW_cluster *nbhd=NULL;
2503 
2504    SUMA_ENTRY;
2505 
2506    if (sv == NULL) {
2507       SUMA_S_Err("Null sv.");
2508       SUMA_RETURN (NULL);
2509    }
2510    if (sv->Ch == NULL) {
2511       SUMA_S_Err("NULL Ch.");
2512       SUMA_RETURN (NULL);
2513    }
2514    if (!SUMAg_CF->ITset || !(gset = SUMAg_CF->ITset->grid)) {
2515       SUMA_S_Err("NULL ITset(%p) or ITset->grid (%p)",
2516                   SUMAg_CF->ITset, SUMAg_CF->ITset?SUMAg_CF->ITset->grid:NULL);
2517       SUMA_RETURN(NULL);
2518    }
2519 
2520    if (!(ado=SUMA_SV_Focus_ADO(sv))) SUMA_RETURN(NULL);
2521 
2522    if (!(nel = SUMA_makeNI_CrossHair(sv))) {
2523       SUMA_S_Err("Failed to form cross hair nel");
2524       SUMA_RETURN(NULL);
2525    }
2526    XYZmap = (float*)nel->vec[0]; /* Supposed to be an anatomically correct XYZ */
2527    if (!(SUMA_THD_dicomm_to_3dfind(gset,
2528                      XYZmap[0], XYZmap[1], XYZmap[2], find))) {
2529       SUMA_S_Err("No good ijk for %f %f %f",
2530                   XYZmap[0], XYZmap[1], XYZmap[2]);
2531       NI_free_element(nel); SUMA_RETURN(NULL);
2532    }
2533 
2534    /* Now determine the voxels to be part of the ROI sent to InstaTract */
2535    switch(ado->do_type) {
2536       case SO_type:
2537          SO = (SUMA_SurfaceObject *)ado;
2538          I_C = SO->SelectedNode;
2539          #if 0
2540          /* For ROI selection... somewhere else ... */
2541          /*
2542          1- From click location find all nodes with xmm radius
2543          2- For each incident triangle, identify voxels intersecting it
2544             AND that are within xmm of node
2545          3-    From each accepted voxel, travel along incident triangle's normal
2546                and accept encountered voxels until you reach the depth limit
2547                (for voxel triangle intersection see
2548                      SUMA_GetVoxelsIntersectingTriangle() and
2549                      SUMA_isVoxelIntersect_Triangle()
2550          */
2551          #endif
2552          /* For now just get something in the sphere, around XYZ.
2553          In the future you want to dig in (depending on the surface)
2554          and pick white matter. See Adam Greenberg's paper for
2555          an example */
2556          nbhd = MCW_spheremask( SUMA_ABS(DSET_DX(gset)),
2557                                 SUMA_ABS(DSET_DY(gset)),
2558                                 SUMA_ABS(DSET_DZ(gset)), 20 );
2559          nind = (int *)calloc(nbhd->num_pt, sizeof(int));
2560          ninmask = mri_load_nbhd_indices (
2561                         DSET_NX(gset), DSET_NY(gset) , DSET_NZ(gset),
2562                         NULL , (int)find[0], (int)find[1], (int)find[2],
2563                         nbhd, nind);
2564          KILL_CLUSTER(nbhd); nbhd = NULL;
2565          break;
2566       case TRACT_type:
2567          /* For now just get something in the sphere, around XYZ.
2568          In the future you want to dig in (depending on the surface)
2569          and pick white matter. See Adam Greenberg's paper for
2570          an example */
2571          nbhd = MCW_spheremask( SUMA_ABS(DSET_DX(gset)),
2572                                 SUMA_ABS(DSET_DY(gset)),
2573                                 SUMA_ABS(DSET_DZ(gset)), 20 );
2574          nind = (int *)calloc(nbhd->num_pt, sizeof(int));
2575          ninmask = mri_load_nbhd_indices (
2576                         DSET_NX(gset), DSET_NY(gset) , DSET_NZ(gset),
2577                         NULL , (int)find[0], (int)find[1], (int)find[2],
2578                         nbhd, nind);
2579          KILL_CLUSTER(nbhd); nbhd = NULL;
2580          break;
2581       case MASK_type:
2582          break;
2583       case GDSET_type:
2584          break;
2585       case CDOM_type:
2586          SUMA_S_Err("Implement me"); SUMA_RETURN(NULL);
2587          break;
2588       case GRAPH_LINK_type:
2589          if (strcmp(SUMA_ADO_variant(ado),"G3D")) break;
2590          /* For now just get something in the sphere, around XYZ.
2591          In the future you want to dig in (depending on the surface)
2592          and pick white matter. See Adam Greenberg's paper for
2593          an example */
2594          nbhd = MCW_spheremask( SUMA_ABS(DSET_DX(gset)),
2595                                 SUMA_ABS(DSET_DY(gset)),
2596                                 SUMA_ABS(DSET_DZ(gset)), 20 );
2597          nind = (int *)calloc(nbhd->num_pt, sizeof(int));
2598          ninmask = mri_load_nbhd_indices (
2599                         DSET_NX(gset), DSET_NY(gset) , DSET_NZ(gset),
2600                         NULL , (int)find[0], (int)find[1], (int)find[2],
2601                         nbhd, nind);
2602          KILL_CLUSTER(nbhd); nbhd = NULL;
2603          break;
2604       case VO_type:
2605          /* For now just get something in the sphere, around XYZ.
2606          In the future you want to dig in (depending on the surface)
2607          and pick white matter. See Adam Greenberg's paper for
2608          an example */
2609          nbhd = MCW_spheremask( SUMA_ABS(DSET_DX(gset)),
2610                                 SUMA_ABS(DSET_DY(gset)),
2611                                 SUMA_ABS(DSET_DZ(gset)), 20 );
2612          nind = (int *)calloc(nbhd->num_pt, sizeof(int));
2613          ninmask = mri_load_nbhd_indices (
2614                         DSET_NX(gset), DSET_NY(gset) , DSET_NZ(gset),
2615                         NULL , (int)find[0], (int)find[1], (int)find[2],
2616                         nbhd, nind);
2617          KILL_CLUSTER(nbhd); nbhd = NULL;
2618          break;
2619       default:
2620          break;
2621    }
2622 
2623    /* Now put it all together */
2624    if (ninmask) {
2625       ngr = NI_new_group_element();
2626       NI_rename_group(ngr, "InstaTract_Query");
2627       NI_add_to_group(ngr, nel);
2628       nel = NI_new_data_element("ROI", ninmask);
2629       NI_add_column(nel, NI_INT, nind);
2630       NI_add_to_group(ngr, nel);
2631    } else {
2632       NI_free_element(nel);
2633    }
2634    SUMA_ifree(nind);
2635 
2636    SUMA_RETURN (ngr);
2637 }
2638 
2639 
2640 /*!
2641    ans = SUMA_CanTalkToAfni (dov, N_dov);
2642    determines if any of the Surface Viewers is allowed to talk to afni
2643    \param dov (SUMA_DO *) the Displayable Objects vector (ususally SUMAg_DOv)
2644    \param N_dov (int) the number of elements in dov (usually SUMAg_N_DOv)
2645    \ret ans (SUMA_Boolean) NOPE if none of the SOs shown in the viewer has both
2646       LocalDomainParentID != NULL && VolPar != NULL
2647 
2648    This function is much different from the one prior to Tue Nov 19 11:44:24 EST 2002
2649 */
2650 
SUMA_CanTalkToAfni(SUMA_DO * dov,int N_dov)2651 SUMA_Boolean SUMA_CanTalkToAfni (SUMA_DO *dov, int N_dov)
2652 {
2653    static char FuncName[]={"SUMA_CanTalkToAfni"};
2654    int i;
2655    SUMA_SurfaceObject *SO;
2656 
2657    SUMA_ENTRY;
2658 
2659    for (i=0; i< N_dov; ++i) {
2660       switch (dov[i].ObjectType) {
2661          case SO_type:
2662             SO = (SUMA_SurfaceObject *)(dov[i].OP);
2663             if (SO->LocalDomainParentID != NULL && SO->VolPar != NULL) {
2664                SUMA_RETURN (YUP);
2665             }
2666             break;
2667          case VO_type:
2668          case MASK_type:
2669          case CDOM_type:
2670          case TRACT_type:
2671             SUMA_RETURN(YUP);
2672             break;
2673          case GDSET_type:
2674             break;
2675          case GRAPH_LINK_type:
2676             if (iDO_is_variant(i, "G3D")) SUMA_RETURN(YUP);
2677             break;
2678       }
2679 
2680    }
2681 
2682    SUMA_RETURN (NOPE);
2683 }
2684 
2685 
2686 /*------------------------------------------------------------------------*/
2687 static int num_workp      = 0 ;
2688 static XtWorkProc * workp = NULL ;
2689 static XtPointer *  datap = NULL ;
2690 static XtWorkProcId wpid ;
2691 
2692 /*#define WPDEBUG*/
2693 
SUMA_register_workproc(XtWorkProc func,XtPointer data)2694 void SUMA_register_workproc( XtWorkProc func , XtPointer data )
2695 {
2696    static char FuncName[]={"SUMA_register_workproc"};
2697 
2698    SUMA_ENTRY;
2699 
2700    if( func == NULL ){
2701       fprintf(SUMA_STDERR,"Error %s: func=NULL on entry!\n", FuncName) ;
2702       SUMA_RETURNe;
2703    }
2704 
2705    if( num_workp == 0 ){
2706       workp = (XtWorkProc *) SUMA_malloc( sizeof(XtWorkProc) ) ;
2707       datap = (XtPointer *)  SUMA_malloc( sizeof(XtPointer) ) ;
2708       wpid  = XtAppAddWorkProc(SUMAg_CF->X->App, SUMA_workprocess, NULL ) ;
2709 #ifdef WPDEBUG
2710       fprintf(stderr,"SUMA_register_workproc: wpid = %x\n",(int)wpid) ;
2711 #endif
2712    } else {
2713       workp = (XtWorkProc *) SUMA_realloc( workp, sizeof(XtWorkProc)*(num_workp+1) ) ;
2714       datap = (XtPointer*)   SUMA_realloc( datap, sizeof(XtPointer) *(num_workp+1) ) ;
2715    }
2716 
2717    workp[num_workp] = func ;
2718    datap[num_workp] = data ;
2719    num_workp++ ;
2720 
2721 #ifdef WPDEBUG
2722 fprintf(stderr,"SUMA_register_workproc: have %d workprocs\n",num_workp) ;
2723 #endif
2724 
2725    SUMA_RETURNe ;
2726 }
2727 
2728 /*!
2729 The difference between SUMA_remove_workproc2 and SUMA_remove_workproc is that
2730 the workprocess removed is identified not just by the function name but also the data pointer
2731 */
SUMA_remove_workproc2(XtWorkProc func,XtPointer data)2732 void SUMA_remove_workproc2( XtWorkProc func , XtPointer data )
2733 {
2734    int ii , ngood ;
2735    static char FuncName[]={"SUMA_remove_workproc2"};
2736    SUMA_Boolean LocalHead = NOPE;
2737 
2738    SUMA_ENTRY;
2739 
2740    if (LocalHead)   fprintf (SUMA_STDERR, "%s: func = %p, num_workp = %d\n", FuncName, func, num_workp);
2741 
2742    if( func == NULL) {
2743       fprintf(SUMA_STDERR,"%s: *** illegal parameters!\n", FuncName) ;
2744       SUMA_RETURNe ;
2745    }
2746    if (num_workp == 0) {
2747       if (LocalHead)   fprintf(SUMA_STDERR,"%s: Nothing to do.\n", FuncName) ;
2748       SUMA_RETURNe ;
2749    }
2750 
2751    if( num_workp < 1 ){
2752       #ifdef WPDEBUG
2753             fprintf(SUMA_STDERR,"%s: No workprocs left\n", FuncName) ;
2754       #endif
2755       XtRemoveWorkProc( wpid ) ;
2756       SUMA_free(workp) ; workp = NULL ; SUMA_free(datap) ; datap = NULL ;
2757       num_workp = 0 ;
2758    } else {
2759       for( ii=0 ; ii < num_workp ; ii++ ){
2760          if( func == workp[ii] && data == datap[ii]) {   /* move last Workprocess to location of workprocess to be deleted */
2761             workp[ii] = workp[num_workp-1] ;
2762             datap[ii] = datap[num_workp-1] ;
2763             workp[num_workp-1] = NULL;
2764             num_workp--;
2765          }
2766 
2767          #ifdef WPDEBUG
2768             fprintf(SUMA_STDERR,"%s: %d workprocs left\n", FuncName, ngood) ;
2769          #endif
2770       }
2771    }
2772 
2773    SUMA_RETURNe ;
2774 
2775 }
2776 
SUMA_remove_workproc(XtWorkProc func)2777 void SUMA_remove_workproc( XtWorkProc func )
2778 {
2779    int ii , ngood ;
2780    static char FuncName[]={"SUMA_remove_workproc"};
2781 
2782    SUMA_ENTRY;
2783 
2784    if( func == NULL || num_workp == 0 ){
2785       fprintf(SUMA_STDERR,"Error %s: *** illegal parameters!\n", FuncName) ;
2786       SUMA_RETURNe ;
2787    }
2788 
2789    if( num_workp < 1 ){
2790       #ifdef WPDEBUG
2791             fprintf(stderr,"SUMA_remove_workproc: No workprocs left\n") ;
2792       #endif
2793       XtRemoveWorkProc( wpid ) ;
2794       SUMA_free(workp) ; workp = NULL ; SUMA_free(datap) ; datap = NULL ;
2795       num_workp = 0 ;
2796    } else {
2797       for( ii=0 ; ii < num_workp ; ii++ ){
2798          if( func == workp[ii] ) {   /* move last Workprocess to location of workprocess to be deleted */
2799             workp[ii] = workp[num_workp-1] ;
2800             datap[ii] = datap[num_workp-1] ;
2801             workp[num_workp-1] = NULL;
2802             num_workp--;
2803          }
2804 
2805          #ifdef WPDEBUG
2806             fprintf(stderr,"SUMA_remove_workproc: %d workprocs left\n",ngood) ;
2807          #endif
2808       }
2809    }
2810 
2811    SUMA_RETURNe ;
2812 }
2813 
SUMA_workprocess(XtPointer fred)2814 Boolean SUMA_workprocess( XtPointer fred )
2815 {
2816    static char FuncName[]={"SUMA_workprocess"};
2817    int ii , ngood ;
2818    Boolean done ;
2819 
2820    if (SUMA_WORKPROC_IO_NOTIFY) {SUMA_ENTRY;}
2821 
2822 #ifdef WPDEBUG
2823    { static int ncall=0 ;
2824      if( (ncall++) % 1000 == 0 )
2825        fprintf(stderr,"SUMA_workprocess: entry %d\n",ncall) ; }
2826 #endif
2827 
2828    if( num_workp == 0 ) {
2829       if (SUMA_WORKPROC_IO_NOTIFY) {
2830          SUMA_RETURN(True) ;
2831       }
2832          else return(True);
2833    }
2834 
2835    for( ii=0,ngood=0 ; ii < num_workp ; ii++ ){
2836       if( workp[ii] != NULL ){
2837          done = workp[ii]( datap[ii] ) ;
2838          if( done == True ) workp[ii] = NULL ;
2839          else               ngood++ ;
2840       }
2841    }
2842 
2843    if( ngood == 0 ){
2844 #ifdef WPDEBUG
2845       fprintf(stderr,"Found no workprocs left\n") ;
2846 #endif
2847       SUMA_free(workp) ; workp = NULL ; SUMA_free(datap) ; datap = NULL ;
2848       num_workp = 0 ;
2849       if (SUMA_WORKPROC_IO_NOTIFY) {
2850          SUMA_RETURN(True) ;
2851       }
2852          else return (True);
2853    }
2854 
2855    if (SUMA_WORKPROC_IO_NOTIFY) {
2856       SUMA_RETURN(False) ;
2857    }
2858       else return(False);
2859 }
2860 
2861 /*---------------------------------------------------------------*/
2862 
2863 /*!
2864    \brief A function to take a SUMA_DRAWN_ROI struct and return an equivalent
2865    SUMA_NIML_DRAWN_ROI struct.
2866 
2867    - Do not free SUMA_NIML_DRAWN_ROI manually, many of its fields are
2868    pointer copies of values in SUMA_DRAWN_ROI.
2869 
2870    \sa SUMA_Free_NIMLDrawROI
2871 */
SUMA_DrawnROI_to_NIMLDrawnROI(SUMA_DRAWN_ROI * ROI)2872 SUMA_NIML_DRAWN_ROI * SUMA_DrawnROI_to_NIMLDrawnROI (SUMA_DRAWN_ROI *ROI)
2873 {
2874    static char FuncName[]={"SUMA_DrawnROI_to_NIMLDrawnROI"};
2875    SUMA_NIML_DRAWN_ROI *nimlROI=NULL;
2876    SUMA_ROI_DATUM *ROI_Datum=NULL;
2877    DListElmt *Elm = NULL;
2878    int i = -1;
2879    SUMA_Boolean LocalHead = NOPE;
2880 
2881    SUMA_ENTRY;
2882 
2883    if (!ROI) {
2884       SUMA_SL_Err("Null ROI");
2885       SUMA_RETURN(NULL);
2886    }
2887 
2888    /* allocate for nimlROI */
2889    nimlROI = (SUMA_NIML_DRAWN_ROI *)SUMA_malloc(sizeof(SUMA_NIML_DRAWN_ROI));
2890 
2891    nimlROI->Type = (int)ROI->Type;
2892    nimlROI->idcode_str = ROI->idcode_str;
2893    nimlROI->Parent_idcode_str = ROI->Parent_idcode_str;
2894    nimlROI->Parent_side =  ROI->Parent_side;
2895    nimlROI->Label = ROI->Label;
2896    nimlROI->iLabel = ROI->iLabel;
2897    nimlROI->N_ROI_datum = dlist_size(ROI->ROIstrokelist);
2898    nimlROI->ColPlaneName = ROI->ColPlaneName;
2899    nimlROI->FillColor[0] = ROI->FillColor[0];
2900    nimlROI->FillColor[1] = ROI->FillColor[1];
2901    nimlROI->FillColor[2] = ROI->FillColor[2];
2902    nimlROI->FillColor[3] = ROI->FillColor[3];
2903    nimlROI->EdgeColor[0] = ROI->EdgeColor[0];
2904    nimlROI->EdgeColor[1] = ROI->EdgeColor[1];
2905    nimlROI->EdgeColor[2] = ROI->EdgeColor[2];
2906    nimlROI->EdgeColor[3] = ROI->EdgeColor[3];
2907    nimlROI->EdgeThickness = ROI->EdgeThickness;
2908    if (!nimlROI->N_ROI_datum) {
2909       nimlROI->ROI_datum = NULL;
2910       SUMA_RETURN(nimlROI);
2911    }
2912    nimlROI->ROI_datum =
2913       (SUMA_NIML_ROI_DATUM *)SUMA_malloc( nimlROI->N_ROI_datum *
2914                                           sizeof(SUMA_NIML_ROI_DATUM));
2915 
2916    /* now fill the ROI_datum structures */
2917    Elm = NULL;
2918    i = 0;
2919    do {
2920       if (!Elm) Elm = dlist_head(ROI->ROIstrokelist);
2921       else Elm = Elm->next;
2922       ROI_Datum = (SUMA_ROI_DATUM *)Elm->data;
2923       nimlROI->ROI_datum[i].action = ROI_Datum->action;
2924       nimlROI->ROI_datum[i].Type = ROI_Datum->Type;
2925       nimlROI->ROI_datum[i].N_n = ROI_Datum->N_n;
2926       nimlROI->ROI_datum[i].nPath = ROI_Datum->nPath;
2927 
2928       /*
2929       nimlROI->ROI_datum[i].N_t = ROI_Datum->N_t;
2930       nimlROI->ROI_datum[i].tPath = ROI_Datum->tPath;
2931       */
2932       ++i;
2933    } while (Elm != dlist_tail(ROI->ROIstrokelist));
2934 
2935    SUMA_RETURN(nimlROI);
2936 }
2937 
2938 
2939 /*!
2940    \brief transfroms a SUMA_NIML_DRAWN_ROI * to a SUMA_DRAWN_ROI *
2941 
2942    \param nimlROI (SUMA_NIML_DRAWN_ROI *) the niml ROI structure
2943    \param ForDisplay (SUMA_Boolean) YUP: Action stack is created
2944                                           (use when ROIs will be displayed)
2945                                     NOPE: Action stack is not created
2946    \return ROI (SUMA_DRAWN_ROI *) the equivalent of niml ROI structure
2947 
2948    - Do not free SUMA_NIML_DRAWN_ROI manually, many of its fields are
2949    pointer copies of values in SUMA_DRAWN_ROI.
2950 
2951    \sa SUMA_Free_NIMLDrawROI
2952 */
SUMA_NIMLDrawnROI_to_DrawnROI(SUMA_NIML_DRAWN_ROI * nimlROI,SUMA_Boolean ForDisplay)2953 SUMA_DRAWN_ROI *SUMA_NIMLDrawnROI_to_DrawnROI (SUMA_NIML_DRAWN_ROI * nimlROI, SUMA_Boolean ForDisplay)
2954 {
2955    static char FuncName[]={"SUMA_NIMLDrawnROI_to_DrawnROI"};
2956    SUMA_ROI_ACTION_STRUCT *ROIA=NULL;
2957    SUMA_DRAWN_ROI *ROI = NULL;
2958    SUMA_ROI_DATUM *ROI_Datum = NULL;
2959    DListElmt *tmpStackPos=NULL;
2960    int i;
2961    SUMA_Boolean LocalHead = NOPE;
2962 
2963    SUMA_ENTRY;
2964 
2965    if (!nimlROI) SUMA_RETURN(NULL);
2966 
2967    /* allocate and initialize the whimpy fields
2968       Based on SUMA_AllocateDrawnROI*/
2969    ROI = (SUMA_DRAWN_ROI *) SUMA_calloc(1, sizeof(SUMA_DRAWN_ROI));
2970    if (  nimlROI->Type == SUMA_ROI_OpenPath ||
2971          nimlROI->Type == SUMA_ROI_ClosedPath ||
2972          nimlROI->Type == SUMA_ROI_FilledArea ) {
2973             /* this ROI will gradually be reconstructed,
2974                start with the basics */
2975          ROI->Type = SUMA_ROI_OpenPath;
2976             /* at the end of the construction you should reach nimlROI->Type */
2977    }else {
2978       /* nothing to reconstruct */
2979       ROI->Type = nimlROI->Type;
2980    }
2981 
2982    ROI->idcode_str = SUMA_copy_string(nimlROI->idcode_str);
2983    ROI->Parent_idcode_str = SUMA_copy_string(nimlROI->Parent_idcode_str);
2984    ROI->Parent_side = nimlROI->Parent_side;
2985    ROI->Label = SUMA_copy_string(nimlROI->Label);
2986    ROI->iLabel = nimlROI->iLabel;
2987    if (LocalHead)
2988       fprintf (SUMA_STDERR,
2989                "%s: ROI->Parent_idcode_str %s\n",
2990                FuncName, ROI->Parent_idcode_str);
2991 
2992    ROI->ROIstrokelist = (DList *)SUMA_malloc (sizeof(DList));
2993    dlist_init(ROI->ROIstrokelist, SUMA_FreeROIDatum);
2994 
2995    ROI->DrawStatus = SUMA_ROI_Finished;
2996    ROI->StackPos = NULL;
2997    ROI->ActionStack = SUMA_CreateActionStack ();
2998    ROI->ColPlaneName = SUMA_copy_string(nimlROI->ColPlaneName);
2999    ROI->FillColor[0] = nimlROI->FillColor[0];
3000    ROI->FillColor[1] = nimlROI->FillColor[1];
3001    ROI->FillColor[2] = nimlROI->FillColor[2];
3002    ROI->FillColor[3] = nimlROI->FillColor[3];
3003    ROI->EdgeColor[0] = nimlROI->EdgeColor[0];
3004    ROI->EdgeColor[1] = nimlROI->EdgeColor[1];
3005    ROI->EdgeColor[2] = nimlROI->EdgeColor[2];
3006    ROI->EdgeColor[3] = nimlROI->EdgeColor[3];
3007    ROI->EdgeThickness = nimlROI->EdgeThickness;
3008    ROI->CE = NULL;
3009    ROI->N_CE = -1;
3010    /* fill in the ROI datum stuff */
3011    for (i=0; i<nimlROI->N_ROI_datum; ++i) {
3012          ROI_Datum = SUMA_AllocROIDatum ();
3013          ROI_Datum->action = nimlROI->ROI_datum[i].action;
3014          ROI_Datum->nPath = nimlROI->ROI_datum[i].nPath;
3015          ROI_Datum->Type = nimlROI->ROI_datum[i].Type;
3016          ROI_Datum->N_n = nimlROI->ROI_datum[i].N_n;
3017       if (ForDisplay) { /* create DO/UNDO stack */
3018          ROIA = (SUMA_ROI_ACTION_STRUCT *) SUMA_malloc (sizeof(SUMA_ROI_ACTION_STRUCT));
3019          ROIA->DrawnROI = ROI;
3020          ROIA->ROId = ROI_Datum;
3021          switch (ROI_Datum->action) {
3022             case SUMA_BSA_AppendStroke:
3023                SUMA_LH("Appending Stroke Action");
3024                tmpStackPos = SUMA_PushActionStack (ROI->ActionStack, ROI->StackPos,
3025                   SUMA_AddToTailROIDatum, (void *)ROIA, SUMA_DestroyROIActionData);
3026                break;
3027             case SUMA_BSA_JoinEnds:
3028                SUMA_LH("Join Ends Action");
3029                tmpStackPos = SUMA_PushActionStack (ROI->ActionStack, ROI->StackPos,
3030                   SUMA_AddToTailJunctionROIDatum, (void *)ROIA, SUMA_DestroyROIActionData);
3031                break;
3032             case SUMA_BSA_FillArea:
3033                SUMA_LH("Fill Area Action");
3034                tmpStackPos = SUMA_PushActionStack (ROI->ActionStack, ROI->StackPos,
3035                   SUMA_AddFillROIDatum, (void *)ROIA, SUMA_DestroyROIActionData);
3036                break;
3037             default:
3038                fprintf (SUMA_STDERR, "Error %s: Not ready to deal with this action (%d).\n",
3039                   FuncName, ROI_Datum->action);
3040                break;
3041 
3042          }
3043 
3044          if (tmpStackPos) ROI->StackPos = tmpStackPos;
3045          else {
3046             fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_PushActionStack.\n", FuncName);
3047          }
3048       } else {
3049          /* ROI will not be used for display purposes, just add datum */
3050          dlist_ins_next(ROI->ROIstrokelist, dlist_tail(ROI->ROIstrokelist), (void *)ROI_Datum);
3051       }
3052    }
3053 
3054    if (ForDisplay) {
3055       /* Saved ROIs are considered finished, put a finish action on the top of the action stack */
3056       ROIA = (SUMA_ROI_ACTION_STRUCT *) SUMA_malloc (sizeof(SUMA_ROI_ACTION_STRUCT));
3057       ROIA->DrawnROI = ROI;
3058       ROIA->ROId = NULL;
3059       tmpStackPos = SUMA_PushActionStack (ROI->ActionStack, ROI->StackPos,
3060                   SUMA_FinishedROI, (void *)ROIA, SUMA_DestroyROIActionData);
3061       if (tmpStackPos) ROI->StackPos = tmpStackPos;
3062       else {
3063          SUMA_SL_Err("Failed in SUMA_PushActionStack.\n");
3064          SUMA_RETURN(NULL);
3065       }
3066    }
3067    SUMA_RETURN(ROI);
3068 }
3069 
3070 /*!
3071    \brief frees a nimlROI structure. These structures are created by
3072     the likes of SUMA_DrawnROI_to_NIMLDrawnROI
3073 
3074     \sa SUMA_DrawnROI_to_NIMLDrawnROI
3075 */
SUMA_Free_NIMLDrawROI(SUMA_NIML_DRAWN_ROI * nimlROI)3076 SUMA_NIML_DRAWN_ROI * SUMA_Free_NIMLDrawROI (SUMA_NIML_DRAWN_ROI *nimlROI)
3077 {
3078    static char FuncName[]={"SUMA_Free_NIMLDrawROI"};
3079    SUMA_Boolean LocalHead = NOPE;
3080 
3081    SUMA_ENTRY;
3082 
3083    if (!nimlROI) SUMA_RETURN(NULL);
3084 
3085    if (nimlROI->ROI_datum) SUMA_free(nimlROI->ROI_datum); /* DO NOT FREE MEMORY POINTED to by fields inside nimlROI->ROI_datum */
3086    SUMA_free(nimlROI);
3087 
3088    SUMA_RETURN(NULL);
3089 }
3090 
3091 
3092 
3093 /*!
3094 A temporary function to play with ni elements
3095 Solo does writing only
3096 */
3097 
3098 typedef struct {
3099   int num_nod ;
3100   int *nod ;
3101 } ROI_seg ;
3102 
3103 typedef struct {
3104   int num_seg ;
3105   float val ;
3106   char  name[128] ;
3107   ROI_seg *seg ;
3108 } ROI ;
3109 
SUMA_FakeIt(int Solo)3110 void SUMA_FakeIt (int Solo)
3111 {
3112       if (!Solo) {
3113       ROI *myroi ;
3114       ROI_seg *myseg , *inseg ;
3115       int roi_type ;
3116       NI_element *nel ;
3117       NI_stream ns ;
3118       char *atr ;
3119       int nseg,ii , nnod,jj ;
3120 
3121       /* define struct to read from element */
3122 
3123       roi_type = NI_rowtype_define( "ROI_seg" , "int,int[#1]" ) ;
3124       printf("roi_type code = %d\n",roi_type) ;
3125 
3126       /* open file and read 1 data element */
3127 
3128       ns = NI_stream_open( "file:qroi.dat" , "r" ) ;
3129       if( ns == NULL ){
3130         fprintf(stderr,"Can't open qroi.dat!\n"); exit(1);
3131       }
3132       nel = NI_read_element(ns,1) ;  NI_stream_close(ns) ;
3133       if( nel == NULL ){
3134         fprintf(stderr,"Can't read element from qroi.dat!\n"); exit(1);
3135       }
3136 
3137       /* check input element name and type */
3138 
3139       printf("element name = %s\n",nel->name) ;
3140       printf("  nel->vec_num     = %d\n",nel->vec_num) ;         /* # of vectors */
3141       printf("  nel->vec_type[0] = %d\n",nel->vec_typ[0]) ;    /* type of vec #0 */
3142       if( strcmp(nel->name,"ROI") != 0 ) exit(1) ;
3143 
3144       myroi = malloc(sizeof(ROI)) ;                  /* create output ROI struct */
3145       atr = NI_get_attribute( nel , "ROI_val") ;   /* set ROI val from attribute */
3146       myroi->val = (atr == NULL) ? 0.0 : strtod(atr,NULL) ;
3147       atr = NI_get_attribute( nel , "ROI_name") ; /* set ROI name from attribute */
3148       NI_strncpy(myroi->name,atr,128) ;
3149       myroi->num_seg = nseg = nel->vec_len ;      /* element is array of ROI_seg */
3150       inseg = nel->vec[0] ;                            /* input array of ROI_seg */
3151       myroi->seg = malloc(sizeof(ROI_seg)*nseg); /* make output array of ROI_seg */
3152 
3153       for( ii=0 ; ii < nseg ; ii++ ){        /* copy input array to output array */
3154         myroi->seg[ii].num_nod = nnod = inseg[ii].num_nod ;
3155         if( nnod > 0 ){
3156           myroi->seg[ii].nod = malloc(sizeof(int)*nnod) ;
3157           memcpy( myroi->seg[ii].nod , inseg[ii].nod , sizeof(int)*nnod ) ;
3158         } else {
3159           myroi->seg[ii].nod = NULL ;
3160         }
3161       }
3162 
3163       printf("  val    = %g\n"
3164              "  name   = %s\n"
3165              "  num_seg= %d\n" , myroi->val , myroi->name , myroi->num_seg ) ;
3166       for( ii=0 ; ii < nseg ; ii++ ){
3167         printf("  Segment #%d has %d nodes:",ii,myroi->seg[ii].num_nod) ;
3168         for( jj=0 ; jj < myroi->seg[ii].num_nod ; jj++ )
3169           printf(" %d",myroi->seg[ii].nod[jj]) ;
3170         printf("\n") ;
3171       }
3172 
3173       printf("\nWriting element to stdout\n") ; fflush(stdout) ;
3174       ns = NI_stream_open( "stdout:" , "w" ) ;
3175       NI_write_element( ns , nel , NI_TEXT_MODE | NI_HEADERSHARP_FLAG ) ;
3176       NI_stream_close( ns ) ; NI_free_element(nel) ;
3177    }
3178    /*********Me ROI*********/
3179    {
3180       char *idcode_str, *Parent_idcode_str, *Label, stmp[200];
3181       int *nPath0, *nPath1, N_n0, N_n1, i, niml_ROI_Datum_type;
3182       NI_element *nel ;
3183       NI_stream ns ;
3184       SUMA_NIML_DRAWN_ROI *niml_ROI = NULL;
3185 
3186       idcode_str = (char*) malloc(sizeof(char) * 200); sprintf(idcode_str,"Moma- idcode_str");
3187       Parent_idcode_str = (char*) malloc(sizeof(char) * 200); sprintf(Parent_idcode_str,"El Parent");
3188       Label = (char*) malloc(sizeof(char) * 200); sprintf(Label,"Da laba");
3189       N_n0 = 3;
3190       N_n1 = 4;
3191       nPath0 = (int*) calloc(N_n0, sizeof(int));
3192       nPath1 = (int*) calloc(N_n1, sizeof(int));
3193       nPath0[0] = 2; nPath0[1] = 1; nPath0[2] = 10;
3194       nPath1[0] = 9; nPath1[1] = 7; nPath1[2] = 23; nPath1[3] = -3;
3195 
3196       fprintf(stderr,"*********** Defining row type\n");
3197       niml_ROI_Datum_type =
3198          NI_rowtype_define("SUMA_NIML_ROI_DATUM", "int,int,int,int[#3]");
3199 
3200       niml_ROI = (SUMA_NIML_DRAWN_ROI *)malloc(sizeof(SUMA_NIML_DRAWN_ROI));
3201       memset(niml_ROI, 0, sizeof(SUMA_NIML_DRAWN_ROI)); /* LPatrol */
3202       niml_ROI->Type = 4;
3203       niml_ROI->idcode_str = idcode_str;
3204       niml_ROI->Parent_idcode_str = Parent_idcode_str;
3205       niml_ROI->Label = Label;
3206       niml_ROI->iLabel = 20;
3207       niml_ROI->N_ROI_datum = 2;
3208       niml_ROI->ROI_datum =
3209          (SUMA_NIML_ROI_DATUM *) /* 13 Feb 2009 [lesstif patrol] */
3210             calloc(niml_ROI->N_ROI_datum, sizeof(SUMA_NIML_ROI_DATUM));
3211 
3212       /* now fill the ROI_datum structures */
3213 
3214       niml_ROI->ROI_datum[0].N_n = N_n0;
3215       niml_ROI->ROI_datum[1].N_n = N_n1;
3216       if (1) {
3217          fprintf(stderr,"*********** Filling ROI_datum structures\n");
3218          niml_ROI->ROI_datum[0].nPath = nPath0;
3219          niml_ROI->ROI_datum[1].nPath = nPath1;
3220       }else {
3221          fprintf(stderr,"*********** Skipping ROI_datum structure fill.\n");
3222       }
3223 
3224       fprintf( stderr,
3225                "*********** Creating new data element, "
3226                "a column of %d elements \n", niml_ROI->N_ROI_datum);
3227       nel = NI_new_data_element("A_drawn_ROI",  niml_ROI->N_ROI_datum);
3228 
3229       fprintf(stderr,"*********** Adding column\n");
3230       NI_add_column( nel , niml_ROI_Datum_type, niml_ROI->ROI_datum );
3231 
3232       fprintf(stderr,"*********** Setting attributes element\n");
3233       NI_set_attribute (nel, "self_idcode", niml_ROI->idcode_str);
3234       NI_set_attribute (nel, "domain_parent_idcode",
3235                              niml_ROI->Parent_idcode_str);
3236       NI_set_attribute (nel, "Label", niml_ROI->Label);
3237       sprintf(stmp,"%d", niml_ROI->iLabel);
3238       NI_set_attribute (nel, "iLabel", stmp);
3239       sprintf(stmp,"%d", niml_ROI->Type);
3240       NI_set_attribute (nel, "Type", stmp);
3241 
3242       /* Now write the element */
3243       ns = NI_stream_open( "fd:1" , "w" ) ;
3244       if (NI_write_element( ns , nel , NI_TEXT_MODE | NI_HEADERSHARP_FLAG ) < 0) {
3245          fprintf(stderr,"*********** Badness, failed to write nel\n");
3246       }
3247       NI_stream_close( ns ) ;
3248 
3249       /* free nel */
3250       NI_free_element(nel) ; nel = NULL;
3251 
3252       /* free the rest */
3253       free(nPath0);
3254       free(nPath1);
3255       free(idcode_str);
3256       free(Parent_idcode_str);
3257       free(Label);
3258    }
3259 
3260 }
3261 
3262 /*!
3263    \brief, creates a srtucture for holding communication variables
3264 
3265    - free returned structure with SUMA_free
3266 */
SUMA_Create_CommSrtuct(void)3267 SUMA_COMM_STRUCT *SUMA_Create_CommSrtuct(void)
3268 {
3269    static char FuncName[]={"SUMA_Create_CommSrtuct"};
3270    SUMA_COMM_STRUCT *cs=NULL;
3271    int i;
3272 
3273    SUMA_ENTRY;
3274 
3275    cs = (SUMA_COMM_STRUCT *)SUMA_malloc(sizeof(SUMA_COMM_STRUCT));
3276    if (!cs) {
3277       SUMA_SL_Crit("Failed to allocate");
3278       SUMA_RETURN(NULL);
3279    }
3280 
3281    cs->talk_suma = 0;
3282    cs->comm_NI_mode = NI_BINARY_MODE;
3283    cs->rps = -1.0;
3284    cs->Send = NOPE;
3285    cs->afni_Send = NOPE;
3286    cs->GoneBad = NOPE;
3287    cs->afni_GoneBad = NOPE;
3288    cs->nelps = -1.0;
3289    cs->TrackID = 0;
3290    cs->istream = -1; /* the index of the stream in SUMAg_CF->ns_v */
3291    cs->afni_istream = -1;
3292    cs->suma_host_name = NULL;
3293    cs->afni_host_name = NULL;
3294    cs->kth = 1;
3295    cs->Feed2Afni = 0;
3296    for (i=0; i<SUMA_N_DSET_TYPES; ++i) cs->ElInd[i] = 0;
3297    SUMA_RETURN(cs);
3298 }
3299 
SUMA_Free_CommSrtuct(SUMA_COMM_STRUCT * cs)3300 SUMA_COMM_STRUCT *SUMA_Free_CommSrtuct(SUMA_COMM_STRUCT *cs)
3301 {
3302    static char FuncName[]={"SUMA_Free_CommSrtuct"};
3303 
3304    SUMA_ENTRY;
3305 
3306    if (cs) {
3307       if (cs->suma_host_name) SUMA_free(cs->suma_host_name); cs->suma_host_name = NULL;
3308       if (cs->afni_host_name) SUMA_free(cs->afni_host_name); cs->afni_host_name = NULL;
3309       SUMA_free(cs);
3310    }
3311 
3312    SUMA_RETURN(NULL);
3313 }
3314 
3315 /*! assign new afni host name
3316     SUMA_Assign_HostName (cf, HostName, istream)
3317 
3318    Assigns a new HostName for niml communication on a particular stream
3319 
3320    \param cf (SUMA_CommonFields *) pointer to Common Fields structure, field AfniHostName will be modified here
3321    \param HostName (char *) hostname in IP number form, or name form afni.nimh.nih.gov or afni (if in /etc/hosts file)
3322                                  NULL to set cf->HostName_v[istream] to localhost if i = SUMA_AFNI_STREAM_INDEX
3323                                                                                  127.0.0.1 otherwise. That's done to keep
3324                                                                                  Shared Memory communication betwen AFNI
3325                                                                                  and SUMA only.
3326    \param istream (int) if -1 then all streams are set to HostName
3327                         otherwise, only HostName_v[istream] is set
3328    \ret ans (SUMA_Boolean) YUP/NOPE
3329 
3330 
3331 */
SUMA_Assign_HostName(SUMA_CommonFields * cf,char * HostName,int istream)3332 SUMA_Boolean SUMA_Assign_HostName ( SUMA_CommonFields *cf,
3333                                     char *HostName, int istream)
3334 {
3335    static char FuncName[]={"SUMA_Assign_HostName"};
3336    int istart = 0, istop = 0, i = 0;
3337    SUMA_Boolean LocalHead = NOPE;
3338 
3339    SUMA_ENTRY;
3340 
3341    if (!cf->TCP_port[0]) SUMA_init_ports_assignments(cf);
3342 
3343    if (istream == -1) {
3344       istart = 0; istop = SUMA_MAX_STREAMS;
3345    } else {
3346       istart = istream; istop = istream + 1;
3347    }
3348 
3349    for (i = istart; i < istop; ++i) {
3350       if (HostName == NULL)
3351          if (i == SUMA_AFNI_STREAM_INDEX) {
3352             sprintf(cf->HostName_v[i], "localhost");
3353                /*  using localhost will allow the use of Shared Memory.
3354                    That is only allowed for SUMA<-->AFNI */
3355          } else {
3356             sprintf(cf->HostName_v[i], "127.0.0.1");
3357                                        /* force TCP for the commoners */
3358          }
3359       else {
3360          if (strlen(HostName) > SUMA_MAX_NAME_LENGTH - 20) {
3361             fprintf( SUMA_STDERR,
3362                      "Error %s: too long a host name (> %d chars).\n",
3363                      FuncName, SUMA_MAX_NAME_LENGTH - 20);
3364             SUMA_RETURN (NOPE);
3365          }
3366          sprintf(cf->HostName_v[i],"%s", HostName);
3367       }
3368 
3369 
3370       sprintf(cf->NimlStream_v[i],"tcp:%s:%d",
3371             cf->HostName_v[i], cf->TCP_port[i]);
3372 
3373       if (LocalHead)
3374          fprintf(SUMA_STDOUT, "%s: Set HostName %d to %s (stream name: %s)\n",
3375                      FuncName, i, cf->HostName_v[i], cf->NimlStream_v[i]);
3376    }
3377 
3378    SUMA_RETURN (YUP);
3379 }
3380 
3381 /*!
3382    \brief sends a full surface to SUMA
3383 */
SUMA_SendSumaNewSurface(SUMA_SurfaceObject * SO,SUMA_COMM_STRUCT * cs)3384 SUMA_Boolean SUMA_SendSumaNewSurface(SUMA_SurfaceObject *SO,
3385                                      SUMA_COMM_STRUCT *cs)
3386 {
3387    static char FuncName[]={"SUMA_SendSumaNewSurface"};
3388    NI_group *ngr=NULL;
3389 
3390    SUMA_ENTRY;
3391 
3392    fprintf(stderr, "****SUMA_SendSumaNewSurface***\n");
3393 
3394    if (!SO || !cs) { SUMA_SL_Err("NULL surface or NULL cs"); SUMA_RETURN(NOPE); }
3395    if (!cs->Send || !cs->talk_suma) {
3396       SUMA_SL_Err("Nothing to do");
3397       SUMA_RETURN(NOPE);
3398    }
3399 
3400 
3401 
3402    if (0) {
3403       /* send the mesh since this is a new surface */
3404       if (!SUMA_SendToSuma (SO, cs, (void *)SO->FaceSetList,
3405                             SUMA_NEW_MESH_IJK, 1)) {
3406          SUMA_SL_Err("Failed to initialize SUMA_SendToSuma");
3407          cs->Send = NOPE;
3408          cs->talk_suma = NOPE;
3409          SUMA_RETURN(NOPE);
3410       }
3411       /* now send the coordinates of the new surface */
3412       if (!SUMA_SendToSuma (SO, cs,
3413                      (void *)SO->NodeList, SUMA_NEW_NODE_XYZ, 1)) {
3414          SUMA_SL_Err("Failed to initialize SUMA_SendToSuma");
3415          cs->Send = NOPE;
3416          cs->talk_suma = NOPE;
3417          SUMA_RETURN(NOPE);
3418       }
3419       /* now send the command to register the new surface with viewers*/
3420       if (!SUMA_SendToSuma (SO, cs, NULL, SUMA_PREP_NEW_SURFACE, 1)) {
3421          SUMA_SL_Err("Failed to initialize SUMA_SendToSuma");
3422          cs->Send = NOPE;
3423          cs->talk_suma = NOPE;
3424          SUMA_RETURN(NOPE);
3425      }
3426       /* now manually clean up the function that created the new surface.
3427       last SUMA_SendToSuma call will only clean up the dtype that
3428       was being sent last.
3429       SUMA_SendToSuma can only clean when the same dtype is being sent.
3430       THAT NEEDS TO BE FIXED, perhaps send
3431       a flag to indicate how many objects you intend to send of any type.
3432       If it is one object then SendToSuma will do cleanup automatically
3433       without hangup ...*/
3434       SUMA_Mesh_IJK2Mesh_IJK_nel (SO, NULL, YUP, SUMA_NEW_MESH_IJK);
3435       SUMA_NodeXYZ2NodeXYZ_nel (SO, NULL, YUP, SUMA_NEW_NODE_XYZ);
3436    } else {
3437       /* the new way */
3438       ngr = SUMA_SO2nimlSO(SO, "NodeList, FaceSetList, VolPar", 1);
3439       if (!ngr) {
3440          SUMA_SL_Err("Failed to create surface");
3441          cs->Send = NOPE;
3442          cs->talk_suma = NOPE;
3443          SUMA_RETURN(NOPE);
3444       }
3445       /* now send the command to feed the new surface to suma*/
3446       if (!SUMA_SendToSuma (SO, cs, (void*)ngr, SUMA_SURFACE_OBJECT, 1)) {
3447          SUMA_SL_Err("Failed to initialize SUMA_SendToSuma");
3448          cs->Send = NOPE;
3449          cs->talk_suma = NOPE;
3450          SUMA_RETURN(NOPE);
3451       }
3452       NI_free_element(ngr); ngr = NULL;
3453 
3454       /* now send the command to register the new surface with viewers
3455          This now also causes a redisplay*/
3456       if (!SUMA_SendToSuma (SO, cs, NULL, SUMA_PREP_NEW_SURFACE, 1)) {
3457          SUMA_SL_Err("Failed to initialize SUMA_SendToSuma");
3458          cs->Send = NOPE;
3459          cs->talk_suma = NOPE;
3460          SUMA_RETURN(NOPE);
3461       }
3462    }
3463 
3464    SUMA_RETURN(YUP);
3465 }
3466 
SUMA_Mesh_IJK_nel2Mesh_IJK(SUMA_SurfaceObject * SO,NI_element * nel)3467 SUMA_Boolean SUMA_Mesh_IJK_nel2Mesh_IJK(SUMA_SurfaceObject *SO, NI_element *nel)
3468 {
3469    static char FuncName[]={"SUMA_Mesh_IJK_nel2Mesh_IJK"};
3470    SUMA_DSET_TYPE dtype;
3471    char *tmp=NULL;
3472    SUMA_Boolean LocalHead = NOPE;
3473 
3474    SUMA_ENTRY;
3475 
3476    dtype = SUMA_Dset_Type(nel->name);
3477    if (dtype != SUMA_NEW_MESH_IJK && dtype != SUMA_MESH_IJK) {
3478       SUMA_SL_Err("Bad dtype for this function!");
3479       SUMA_RETURN(NOPE);
3480    }
3481 
3482    tmp = NI_get_attribute(nel, "domain_parent_idcode");
3483    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
3484       if (strcmp(SO->idcode_str, tmp)) {
3485          SUMA_SL_Err("idcode mismatch."); SUMA_RETURN(NOPE);
3486       }
3487    }
3488    tmp = NI_get_attribute(nel, "self_idcode");
3489    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->facesetlist_idcode_str = SUMA_copy_string(tmp);
3490 
3491    tmp = NI_get_attribute(nel, "Mesh_Dim");
3492    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->FaceSetDim = atoi(tmp);
3493    else SO->FaceSetDim = 0;
3494 
3495    if (SO->FaceSetDim != 3) {
3496       SUMA_SL_Err("FaceSetDim must be 3!"); SUMA_RETURN(NOPE);
3497    }
3498 
3499    if (SO->N_FaceSet) {
3500       if (SO->N_FaceSet == nel->vec_len/SO->FaceSetDim ) {
3501          if (!SO->FaceSetList) {
3502             SUMA_SL_Err("Bad init variables. SO->N_FaceSet == nel->vec_len/SO->FaceSetDim && !SO->FaceSetList"); SUMA_RETURN(NOPE);
3503          }
3504       } else {
3505          if (SO->FaceSetList) SUMA_free(SO->FaceSetList); SO->FaceSetList = NULL;
3506       }
3507    } else {
3508       if (SO->FaceSetList) { SUMA_SL_Err("SO->FaceSetList should be null here!"); SUMA_RETURN(NOPE); }
3509    }
3510    SO->N_FaceSet = nel->vec_len/SO->FaceSetDim;
3511    if (!SO->FaceSetList) SO->FaceSetList = (int *)SUMA_malloc(nel->vec_len * sizeof(int));
3512    if (!SO->FaceSetList) {
3513       SUMA_SL_Crit("Failed to allocate for FaceSetList"); SUMA_RETURN(NOPE);
3514    }
3515    memcpy((void*)SO->FaceSetList, nel->vec[0], nel->vec_len*sizeof(int));
3516 
3517    SUMA_RETURN(YUP);
3518 }
3519 
3520 /*!
3521    A function to turn triangulation to nel to be sent to SUMA
3522    There's nothing to cleanup so worry not about making a cleanup call
3523    \sa SUMA_Mesh_IJK_nel2Mesh_IJK
3524 */
SUMA_Mesh_IJK2Mesh_IJK_nel(SUMA_SurfaceObject * SO,int * val,SUMA_Boolean cleanup,SUMA_DSET_TYPE dtype)3525 NI_element * SUMA_Mesh_IJK2Mesh_IJK_nel (SUMA_SurfaceObject *SO, int *val, SUMA_Boolean cleanup, SUMA_DSET_TYPE dtype)
3526 {
3527    static char FuncName[]={"SUMA_Mesh_IJK2Mesh_IJK_nel"};
3528    static int i_in=0;
3529    char buf[500];
3530    NI_element *nel=NULL;
3531    SUMA_Boolean LocalHead = NOPE;
3532 
3533    SUMA_ENTRY;
3534 
3535 
3536    if (dtype != SUMA_NEW_MESH_IJK && dtype != SUMA_MESH_IJK) {
3537       SUMA_SL_Err("Bad dtype for this function!");
3538       SUMA_RETURN(NULL);
3539    }
3540 
3541    if (cleanup) {
3542       SUMA_LH("Cleanup...");
3543       SUMA_RETURN(NULL);
3544    }
3545 
3546    if (SO->FaceSetDim != 3) { /* only deals with XYZ for the moment */
3547       SUMA_SL_Err("FaceSetDim must be 3!");
3548       SUMA_RETURN(nel);
3549    }
3550 
3551    if (!i_in) {
3552       /* Initialization block. Nothing to do , really */
3553    }
3554 
3555 
3556    /* Now create that data element and write it out */
3557    SUMA_allow_nel_use(1);
3558    nel = SUMA_NewNel (  dtype, /* one of SUMA_DSET_TYPE */
3559                         SO->idcode_str, /* idcode of Domain Parent */
3560                         NULL, /* idcode of geometry parent, not useful here*/
3561                         3*SO->N_FaceSet,
3562                         NULL,
3563                         SO->facesetlist_idcode_str);
3564    if (!nel) {
3565       fprintf (stderr,"Error  %s:\nFailed in SUMA_NewNel", FuncName);
3566       SUMA_RETURN(NULL);
3567    }
3568 
3569    sprintf(buf, "%d", SO->FaceSetDim);
3570    NI_set_attribute (nel, "Mesh_Dim", buf);
3571 
3572    /* set the label */
3573    if (SO->Label) {
3574       sprintf(buf, "FaceSetList for surface %s", SO->Label);
3575       NI_set_attribute (nel, "Object_Label", buf);
3576    } else {
3577       NI_set_attribute (nel, "Object_Label", SUMA_EMPTY_ATTR);
3578    }
3579 
3580    #if 0 /* no longer needed */
3581       if (!SO->idcode_str) { SUMA_SL_Err("Surface has a NULL idcode_str, BAD.\n"); SUMA_RETURN(NULL);}
3582       NI_set_attribute (nel, "surface_idcode", SO->idcode_str);
3583 
3584       if (!SO->Group) { SUMA_SL_Err("Surface has a NULL Group, BAD.\n"); SUMA_RETURN(NULL);}
3585       NI_set_attribute(nel, "Group", SO->Group);
3586       if (!SO->Label) { NI_set_attribute(nel, "Label", "Def_MeshIJK2MeshIJK_nel"); }
3587       else NI_set_attribute(nel, "Label", SO->Label);
3588       if (!SO->State) { SUMA_SL_Err("Surface has a NULL state, BAD.\n"); SUMA_RETURN(NULL);}
3589       NI_set_attribute(nel, "State", SO->State);
3590       sprintf(buf, "%d", SO->N_Node);
3591       NI_set_attribute(nel, "N_Node", buf);
3592       NI_set_attribute(nel, "EmbedDim", "3");
3593       NI_set_attribute(nel, "AnatCorrect", "1");
3594    #endif
3595 
3596    #if 0 /* the old way, no need for embellishments */
3597    /* Add the coordinate column */
3598    if (!SUMA_AddNelCol (nel, /* the famed nel */
3599                         "IJK indices",
3600                         SUMA_NODE_INT, /* the column's type (description),
3601                                             one of SUMA_COL_TYPE */
3602                         (void *)val, /* the coordinates */
3603                         NULL  /* that's an optional structure containing
3604                                  attributes of the added column.
3605                                  Not used at the moment */
3606                         ,1
3607                         )) {
3608       fprintf (stderr,"Error  %s:\nFailed in SUMA_AddNelCol", FuncName);
3609       SUMA_RETURN(NULL);
3610    }
3611    #else
3612       NI_add_column_stride ( nel, NI_INT, val, 1 );
3613    #endif
3614 
3615    ++i_in;
3616 
3617    /* return the element */
3618    SUMA_RETURN(nel);
3619 
3620 }
3621 
3622 /*!
3623    The inverse of SUMA_NodeXYZ2NodeXYZ_nel
3624 */
SUMA_NodeXYZ_nel2NodeXYZ(SUMA_SurfaceObject * SO,NI_element * nel)3625 SUMA_Boolean SUMA_NodeXYZ_nel2NodeXYZ (SUMA_SurfaceObject *SO, NI_element *nel)
3626 {
3627    static char FuncName[]={"SUMA_NodeXYZ_nel2NodeXYZ"};
3628    char *tmp = NULL;
3629    SUMA_DSET_TYPE dtype;
3630    SUMA_Boolean LocalHead = NOPE;
3631 
3632    SUMA_ENTRY;
3633 
3634    dtype = SUMA_Dset_Type(nel->name);
3635 
3636    if (dtype != SUMA_NODE_XYZ && dtype != SUMA_NEW_NODE_XYZ) {
3637       SUMA_SL_Err("Bad nel for this function");
3638       SUMA_RETURN(NOPE);
3639    }
3640 
3641    tmp = NI_get_attribute(nel, "Node_Dim");
3642    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
3643       SO->NodeDim = atoi(tmp);
3644       if (SO->NodeDim != 3) {
3645          SUMA_SL_Err("Not willing to deal with SO->NodeDim != 3");
3646          SUMA_RETURN(NOPE);
3647       }
3648    }
3649 
3650    tmp = NI_get_attribute(nel, "self_idcode");
3651    if (!SUMA_IS_EMPTY_STR_ATTR(tmp))
3652       SO->nodelist_idcode_str = SUMA_copy_string(tmp);
3653 
3654    tmp = NI_get_attribute(nel, "domain_parent_idcode");
3655    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
3656       if (strcmp(tmp, SO->idcode_str)) {
3657          SUMA_SL_Err("idcode of parent mismatch"); SUMA_RETURN(NOPE);
3658       }
3659    }
3660 
3661    /* how many elements? */
3662    if (SO->N_Node) {
3663       if (SO->N_Node == nel->vec_len/SO->NodeDim) {
3664          if (!SO->NodeList) {
3665             SUMA_SL_Err("Bad initial values in SO.\n"
3666                         "SO->N_Node == nel->vec_len/3 \n"
3667                         "but NULL SO->NodeList");
3668             SUMA_RETURN(NOPE);
3669          }
3670       } else {
3671          /* gotta cleanup */
3672          if (SO->NodeList)
3673             SUMA_free(SO->NodeList);
3674          SO->NodeList = NULL; SO->N_Node = 0;
3675       }
3676    } else {
3677       if (SO->NodeList) {
3678          SUMA_SL_Err("Should not have a NodeList here");
3679          SUMA_RETURN(NOPE);
3680       }
3681    }
3682 
3683    SO->N_Node = nel->vec_len/SO->NodeDim;
3684    if (!SO->NodeList) SO->NodeList = (float *)SUMA_malloc(nel->vec_len * sizeof(float));
3685    if (!SO->NodeList) {
3686       SUMA_SL_Crit("Failed to allocate"); SUMA_RETURN(NOPE);
3687    }
3688    memcpy((void *)SO->NodeList, nel->vec[0], nel->vec_len * sizeof(float));
3689 
3690    SUMA_RETURN(YUP);
3691 }
3692 
3693 /*!
3694    A function to turn node XYZ to nel to be sent to SUMA
3695    There's nothing to cleanup so worry not about making a cleanup call
3696    \sa SUMA_NodeXYZ_nel2NodeXYZ
3697 
3698 */
SUMA_NodeXYZ2NodeXYZ_nel(SUMA_SurfaceObject * SO,float * val,SUMA_Boolean cleanup,SUMA_DSET_TYPE dtype)3699 NI_element * SUMA_NodeXYZ2NodeXYZ_nel (
3700    SUMA_SurfaceObject *SO, float *val,
3701    SUMA_Boolean cleanup, SUMA_DSET_TYPE dtype)
3702 {
3703    static char FuncName[]={"SUMA_NodeXYZ2NodeXYZ_nel"};
3704    static int i_in=0;
3705    char stmp[500];
3706    NI_element *nel=NULL;
3707    SUMA_Boolean LocalHead = NOPE;
3708 
3709    SUMA_ENTRY;
3710 
3711    if (dtype != SUMA_NEW_NODE_XYZ && dtype != SUMA_NODE_XYZ) {
3712       SUMA_SL_Err("Bad dtype for this function!");
3713       SUMA_RETURN(NULL);
3714    }
3715 
3716    if (cleanup) {
3717       SUMA_LH("Cleanup...");
3718       SUMA_RETURN(NULL);
3719    }
3720 
3721    if (SO->NodeDim != 3) { /* only deals with XYZ for the moment */
3722       SUMA_SL_Err("NodeDim must be 3!");
3723       SUMA_RETURN(nel);
3724    }
3725 
3726    if (!i_in) {
3727       /* Initialization block. Nothing to do , really */
3728 
3729    }
3730 
3731 
3732    /* Now create that data element and write it out */
3733    SUMA_allow_nel_use(1);
3734    nel = SUMA_NewNel (  dtype, /* one of SUMA_DSET_TYPE */
3735                         SO->idcode_str, /* idcode of Domain Parent Surface*/
3736                         NULL, /* idcode of geometry parent, not useful here*/
3737                         3*SO->N_Node,
3738                         NULL,
3739                         SO->nodelist_idcode_str);
3740    if (!nel) {
3741       fprintf (stderr,"Error  %s:\nFailed in SUMA_NewNel", FuncName);
3742       SUMA_RETURN(NULL);
3743    }
3744 
3745    SUMA_LH("Setting attributes");
3746    sprintf(stmp, "%d", SO->NodeDim);
3747    NI_set_attribute (nel, "Node_Dim", stmp);
3748 
3749    #if 0 /* no longer needed */
3750    /* set the surface idcode attribute */
3751    NI_set_attribute (nel, "surface_idcode", SO->idcode_str);
3752    #endif
3753 
3754    /* set the label */
3755    if (SO->Label) {
3756       SUMA_LH(" label");
3757       sprintf(stmp, "NodeList for surface %s", SO->Label);
3758       NI_set_attribute (nel, "Object_Label", stmp);
3759       NI_set_attribute (nel, "Target_Object_Label", SO->Label);
3760    } else {
3761       SUMA_LH(" no label");
3762       NI_set_attribute (nel, "Object_Label", SUMA_EMPTY_ATTR);
3763       NI_set_attribute (nel, "Target_Object_Label", SUMA_EMPTY_ATTR);
3764    }
3765 
3766    SUMA_LH("Adding data");
3767    #if 0 /* old way */
3768    /* Add the coordinate column */
3769    if (!SUMA_AddNelCol (nel, /* the famed nel */
3770                         "XYZ coords",
3771                         SUMA_NODE_3C, /* the column's type (description),
3772                                             one of SUMA_COL_TYPE */
3773                         (void *)val, /* the coordinates */
3774                         NULL  /* that's an optional structure containing
3775                                  attributes of the added column.
3776                                  Not used at the moment */
3777                         ,1
3778                         )) {
3779       fprintf (stderr,"Error  %s:\nFailed in SUMA_AddNelCol", FuncName);
3780       SUMA_RETURN(NULL);
3781    }
3782    #else /* new way, no need for embellishments */
3783       NI_add_column_stride ( nel, NI_FLOAT, val, 1 );
3784    #endif
3785    ++i_in;
3786 
3787    /* return the element */
3788    SUMA_RETURN(nel);
3789 
3790 
3791 }
3792 
3793 /*!
3794    \brief the inverse of SUMA_SOVolPar2VolPar_nel
3795 */
SUMA_VolPar_nel2SOVolPar(SUMA_SurfaceObject * SO,NI_element * nel)3796 SUMA_Boolean SUMA_VolPar_nel2SOVolPar(SUMA_SurfaceObject *SO, NI_element *nel)
3797 {
3798    static char FuncName[]={"SUMA_VolPar_nel2SOVolPar"};
3799    char *tmp;
3800    float fv15[15];
3801    double dv15[15];
3802    SUMA_DSET_TYPE dtype;
3803    SUMA_Boolean LocalHead = NOPE;
3804 
3805    SUMA_ENTRY;
3806 
3807    dtype = SUMA_Dset_Type(nel->name);
3808    if (dtype != SUMA_SURFACE_VOLUME_PARENT) {
3809       SUMA_SL_Err("Bad dtype for this function!");
3810       SUMA_RETURN(NOPE);
3811    }
3812 
3813    if (SO->VolPar) { SUMA_SL_Err("SO->VolPar must be NULL here"); SUMA_RETURN(NOPE); }
3814    SO->VolPar = SUMA_Alloc_VolPar();
3815 
3816    tmp = NI_get_attribute(nel, "self_idcode");
3817    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->VolPar->idcode_str = SUMA_copy_string(tmp);
3818 
3819    tmp = NI_get_attribute(nel, "domain_parent_idcode");
3820    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
3821       if (strcmp(tmp, SO->idcode_str)) {
3822          SUMA_SL_Err("idcode of parent mismatch"); SUMA_RETURN(NOPE);
3823       }
3824    }
3825 
3826    tmp = NI_get_attribute(nel, "isanat");
3827    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->VolPar->isanat = atoi(tmp);
3828 
3829    tmp = NI_get_attribute(nel, "axis_hand");
3830    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->VolPar->Hand = atoi(tmp);
3831 
3832    tmp = NI_get_attribute(nel, "prefix");
3833    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->VolPar->prefix = SUMA_copy_string(tmp);
3834 
3835    tmp = NI_get_attribute(nel, "filecode");
3836    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->VolPar->filecode = SUMA_copy_string(tmp);
3837 
3838    tmp = NI_get_attribute(nel, "headname");
3839    if (!SUMA_IS_EMPTY_STR_ATTR(tmp))
3840       SO->VolPar->headname = SUMA_copy_string(tmp);
3841 
3842    tmp = NI_get_attribute(nel, "dirname");
3843    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->VolPar->dirname = SUMA_copy_string(tmp);
3844 
3845    tmp = NI_get_attribute(nel, "vol_idcode_str");
3846    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->VolPar->vol_idcode_str = SUMA_copy_string(tmp);
3847 
3848    tmp = NI_get_attribute(nel, "vol_idcode_date");
3849    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) SO->VolPar->vol_idcode_date = SUMA_copy_string(tmp);
3850 
3851    tmp = NI_get_attribute(nel, "nxyz");
3852    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) { SUMA_StringToNum(tmp, (void *)fv15, 3,1); SO->VolPar->nx = (int)fv15[0]; SO->VolPar->ny = (int)fv15[1];   SO->VolPar->nz = (int)fv15[2]; }
3853 
3854    tmp = NI_get_attribute(nel, "xyzorient");
3855    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) { SUMA_StringToNum(tmp, (void *)fv15, 3,1); SO->VolPar->xxorient = (int)fv15[0]; SO->VolPar->yyorient = (int)fv15[1];   SO->VolPar->zzorient = (int)fv15[2]; }
3856 
3857    tmp = NI_get_attribute(nel, "dxyz");
3858    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) { SUMA_StringToNum(tmp, (void *)fv15, 3,1); SO->VolPar->dx = fv15[0]; SO->VolPar->dy = fv15[1];   SO->VolPar->dz = fv15[2]; }
3859 
3860    tmp = NI_get_attribute(nel, "xyzorg");
3861    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) { SUMA_StringToNum(tmp, (void *)fv15, 3,1); SO->VolPar->xorg = fv15[0]; SO->VolPar->yorg = fv15[1];   SO->VolPar->zorg = fv15[2]; }
3862 
3863    tmp = NI_get_attribute(nel, "CENTER_OLD");
3864    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
3865       SUMA_StringToNum(tmp, (void*)dv15, 3,2);
3866       SO->VolPar->CENTER_OLD = (double*)SUMA_malloc(sizeof(double)*3);
3867       SUMA_COPY_VEC(fv15, SO->VolPar->CENTER_OLD, 2, double, double);
3868    }
3869 
3870    tmp = NI_get_attribute(nel, "CENTER_BASE");
3871    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
3872       SUMA_StringToNum(tmp, (void*)dv15, 3,2);
3873       SO->VolPar->CENTER_BASE = (double*)SUMA_malloc(sizeof(double)*3);
3874       SUMA_COPY_VEC(fv15, SO->VolPar->CENTER_BASE, 2, double, double);
3875    }
3876 
3877    tmp = NI_get_attribute(nel, "MATVEC");
3878    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
3879       SUMA_StringToNum(tmp, dv15, 12,2);
3880       SO->VolPar->MATVEC = (double*)SUMA_malloc(sizeof(double)*12);
3881       SUMA_COPY_VEC(fv15, SO->VolPar->MATVEC, 2, double, double);
3882    }
3883 
3884    tmp = NI_get_attribute(nel, "MATVEC_source");
3885    if (!SUMA_IS_EMPTY_STR_ATTR(tmp)) {
3886       SO->VolPar->MATVEC_source = (SUMA_WARP_TYPES)atoi(tmp);
3887    }
3888    SUMA_RETURN(YUP);
3889 }
3890 
3891 /*!
3892    A function to turn the VolPar structure to a nel, this one's a group
3893    \sa SUMA_VolPar_nel2SOVolPar
3894 */
SUMA_SOVolPar2VolPar_nel(SUMA_SurfaceObject * SO,SUMA_VOLPAR * VolPar,SUMA_DSET_TYPE dtype)3895 NI_element *SUMA_SOVolPar2VolPar_nel (SUMA_SurfaceObject *SO,
3896                                        SUMA_VOLPAR *VolPar, SUMA_DSET_TYPE dtype)
3897 {
3898    static char FuncName[]={"SUMA_SOVolPar2VolPar_nel"};
3899    NI_element *nel=NULL;
3900    int ibuf3[3], i;
3901    float fbuf3[3];
3902    char stmp[500];
3903    SUMA_Boolean LocalHead = NOPE;
3904 
3905    SUMA_ENTRY;
3906 
3907    if (dtype != SUMA_SURFACE_VOLUME_PARENT) {
3908       SUMA_SL_Err("Bad dtype for this function!");
3909       SUMA_RETURN(NULL);
3910    }
3911 
3912    if (!VolPar) {
3913       SUMA_SL_Err("NULL VolPar");
3914       SUMA_RETURN(NULL);
3915    }
3916 
3917 
3918    if (!VolPar->idcode_str) { SUMA_NEW_ID(VolPar->idcode_str, NULL); }
3919 
3920    /* Now create that data element and write it out */
3921    SUMA_allow_nel_use(1);
3922    nel = SUMA_NewNel (  dtype, /* one of SUMA_DSET_TYPE */
3923                         SO->idcode_str, /* idcode of Domain Parent Surface*/
3924                         NULL, /* idcode of geometry parent, not useful here*/
3925                         0,
3926                         NULL,
3927                         VolPar->idcode_str);
3928    if (!nel) {
3929       fprintf (stderr,"Error  %s:\nFailed in SUMA_NewNel", FuncName);
3930       SUMA_RETURN(NULL);
3931    }
3932 
3933    if (SO->Label) {
3934       sprintf(stmp,"Volume parent of %s", SO->Label);
3935       NI_set_attribute(nel, "Object_Label", stmp);
3936       NI_set_attribute (nel, "Target_Object_Label", SO->Label);
3937    } else {
3938       NI_set_attribute(nel, "Object_Label", SUMA_EMPTY_ATTR);
3939       NI_set_attribute (nel, "Target_Object_Label", SUMA_EMPTY_ATTR);
3940    }
3941 
3942    sprintf(stmp,"%d", VolPar->isanat);
3943    NI_set_attribute(nel, "isanat", stmp);
3944 
3945    sprintf(stmp,"%d", VolPar->Hand);
3946    NI_set_attribute(nel, "axis_hand", stmp);
3947 
3948    if (VolPar->prefix) NI_set_attribute(nel, "prefix", VolPar->prefix);
3949    else NI_set_attribute(nel, "prefix", SUMA_EMPTY_ATTR);
3950 
3951    if (VolPar->filecode) NI_set_attribute(nel, "filecode", VolPar->filecode);
3952    else NI_set_attribute(nel, "filecode", SUMA_EMPTY_ATTR);
3953 
3954    if (VolPar->headname) NI_set_attribute(nel, "headname", VolPar->headname);
3955    else NI_set_attribute(nel, "headname", SUMA_EMPTY_ATTR);
3956 
3957    if (VolPar->dirname) NI_set_attribute(nel, "dirname", VolPar->dirname);
3958    else NI_set_attribute(nel, "dirname", SUMA_EMPTY_ATTR);
3959 
3960    if (VolPar->vol_idcode_str)
3961       NI_set_attribute(nel, "vol_idcode_str", VolPar->vol_idcode_str);
3962    else NI_set_attribute(nel, "vol_idcode_str", SUMA_EMPTY_ATTR);
3963 
3964    if (VolPar->vol_idcode_date)
3965       NI_set_attribute(nel, "vol_idcode_date", VolPar->vol_idcode_date);
3966    else NI_set_attribute(nel, "vol_idcode_date", SUMA_EMPTY_ATTR);
3967 
3968    sprintf(stmp, "%d %d %d", VolPar->nx, VolPar->ny, VolPar->nz);
3969    NI_set_attribute(nel, "nxyz", stmp);
3970 
3971    sprintf(stmp, "%d %d %d",
3972       VolPar->xxorient, VolPar->yyorient, VolPar->zzorient);
3973    NI_set_attribute(nel, "xyzorient", stmp);
3974 
3975    sprintf(stmp, "%f %f %f", VolPar->dx, VolPar->dy, VolPar->dz);
3976    NI_set_attribute(nel, "dxyz", stmp);
3977 
3978    sprintf(stmp, "%f %f %f", VolPar->xorg, VolPar->yorg, VolPar->zorg);
3979    NI_set_attribute(nel, "xyzorg", stmp);
3980 
3981    if (VolPar->CENTER_OLD) {
3982       stmp[0] = '\0';
3983       for (i=0; i<3; ++i)
3984          sprintf(stmp+strlen(stmp)," %f", VolPar->CENTER_OLD[i]);
3985       NI_set_attribute(nel, "CENTER_OLD", stmp);
3986    }
3987    if (VolPar->CENTER_BASE) {
3988       stmp[0] = '\0';
3989       for (i=0; i<3; ++i)
3990          sprintf(stmp+strlen(stmp)," %f", VolPar->CENTER_BASE[i]);
3991       NI_set_attribute(nel, "CENTER_BASE", stmp);
3992    }
3993 
3994    if (VolPar->MATVEC) {
3995       stmp[0] = '\0';
3996       for (i=0; i<12; ++i)
3997          sprintf(stmp+strlen(stmp)," %f", VolPar->MATVEC[i]);
3998       NI_set_attribute(nel, "MATVEC", stmp);
3999    }
4000 
4001    sprintf(stmp, "%d", VolPar->MATVEC_source);
4002    NI_set_attribute(nel, "MATVEC_source", stmp);
4003 
4004    SUMA_RETURN(nel);
4005 }
4006 
4007 /*! Macro specific for SUMA_NodeVal2irgba_nel */
4008 #define SUMA_NODEVAL2IRGBA_CLEANUP { \
4009    if (node) SUMA_free(node); node = NULL;   \
4010    if (OptScl) SUMA_free(OptScl); OptScl = NULL;   \
4011    if (SV) SUMA_Free_ColorScaledVect (SV); SV = NULL; \
4012    if (rgba) SUMA_free(rgba); rgba = NULL;   \
4013 }
4014 /*!
4015    A function to turn node values into a colored nel to be sent to SUMA
4016    \param SO (SUMA_SurfaceObject *) Surface object, domain of data
4017    \param val (float *)  vector of node values to be colored and stored as nel
4018    \param instanceID (char *) a unique identifier used to tag a set of val
4019                               vectors that are sent through repeated calls.
4020                               With a new instanceID, static arrays are newly
4021                               allocated and will continue to be used as long as
4022                               instanceID does not change
4023                               When instanceID changes, the function cleans up and
4024                               reallocates automatically.
4025    \param option (int) Set this flag to:
4026                          1 to signal that you are done using this function
4027                               for good and want to make sure any local
4028                               allocations are freed.
4029                                  Returns NULL, does not need any previous params
4030                          -1 to signal that this function is to be called just
4031                               once under a particular instance and that the
4032                               function should cleanup before it returns.
4033                                  Returns valid nel, requires all params.
4034                                  You can also use -1 if that is the last call in
4035                                  a series
4036                         0 to signal that this function will still be called under
4037                            that instance
4038 
4039 */
SUMA_NodeVal2irgba_nel(SUMA_SurfaceObject * SO,float * val,char * instanceID,int cleanup)4040 NI_element * SUMA_NodeVal2irgba_nel (SUMA_SurfaceObject *SO, float *val,
4041                                      char *instanceID, int cleanup)
4042 {
4043    static char FuncName[]={"SUMA_NodeVal2irgba_nel"};
4044    static int i_in=0, *node=NULL;
4045    static SUMA_COLOR_MAP *CM=NULL;
4046    static SUMA_SCALE_TO_MAP_OPT * OptScl=NULL;
4047    static int MapType;
4048    static SUMA_COLOR_SCALED_VECT * SV=NULL;
4049    static byte *rgba=NULL;
4050    static char past_instance[50]={""};
4051    char idcode_str[50];
4052    NI_element *nel=NULL;
4053    int i, i4, i3;
4054    float IntRange[2], *Vsort= NULL;
4055    SUMA_Boolean LocalHead = NOPE;
4056 
4057    SUMA_ENTRY;
4058 
4059    if (cleanup == 1) {
4060       SUMA_LH("Cleanup...");
4061       SUMA_NODEVAL2IRGBA_CLEANUP;
4062       past_instance[0]='\0';
4063       i_in = 0;
4064       SUMA_RETURN(NULL);
4065    }
4066 
4067    if (!instanceID) {
4068       SUMA_SL_Err("This function requires instanceID to be non-null.");
4069       SUMA_RETURN(NULL);
4070    }
4071 
4072    if (strcmp(instanceID, past_instance)) {
4073       SUMA_LH("A new instance");
4074       /* clean up if necessary */
4075       if (i_in) SUMA_NODEVAL2IRGBA_CLEANUP;
4076       i_in = 0;
4077       sprintf(past_instance,"%s", instanceID);
4078    }
4079 
4080 
4081 
4082    if (!i_in) {
4083       /* first time around */
4084       /* create the color mapping of Cx (SUMA_CMAP_MATLAB_DEF_BYR64)*/
4085       CM = SUMA_FindNamedColMap ("byr64");
4086       if (CM == NULL) {
4087          fprintf (SUMA_STDERR,
4088                   "Error %s: Could not get standard colormap.\n", FuncName);
4089          SUMA_RETURN (NULL);
4090       }
4091 
4092       /* get the options for creating the scaled color mapping */
4093       OptScl = SUMA_ScaleToMapOptInit();
4094       if (!OptScl) {
4095          fprintf (SUMA_STDERR,
4096                   "Error %s: Could not get scaling option structure.\n",
4097                   FuncName);
4098          SUMA_RETURN (NULL);
4099       }
4100 
4101       /* work the options a bit */
4102       OptScl->ApplyClip = NOPE;
4103       OptScl->MaskZero = NOPE;
4104       IntRange[0] = 0; IntRange[1] = 100; /* percentile clipping range*/
4105       Vsort = SUMA_PercRange (val, NULL, SO->N_Node, IntRange, IntRange, NULL);
4106       if (Vsort[0] < 0 && Vsort[SO->N_Node -1] > 0 ) {
4107          /* the new method */
4108          if (fabs(IntRange[0]) > IntRange[1]) {
4109             IntRange[1] = -IntRange[0];
4110          } else {
4111             IntRange[0] = -IntRange[1];
4112          }
4113       }
4114       OptScl->IntRange[0] = IntRange[0]; OptScl->IntRange[1] = IntRange[1];
4115       OptScl->BrightFact = 1.0;
4116 
4117       /* create structure to hold the colored values */
4118       SV = SUMA_Create_ColorScaledVect(SO->N_Node, 0);
4119       if (!SV) {
4120          fprintf (SUMA_STDERR,
4121                   "Error %s: Could not allocate for SV.\n", FuncName);
4122          SUMA_RETURN (NULL);
4123       }
4124 
4125       /* node vector */
4126       node = (int *) SUMA_malloc(sizeof(int) * SO->N_Node);
4127       /* color vectors to hold RGBA colors*/
4128       rgba = (byte *) SUMA_malloc(sizeof(byte) * SO->N_Node * 4);
4129       if (!node || !rgba) {
4130          SUMA_SL_Err("Failed to allocate for node or rgba.");
4131          SUMA_RETURN(NULL);
4132       }
4133       for (i=0; i < SO->N_Node; ++i) node[i] = i;
4134 
4135       if (Vsort) SUMA_free(Vsort); Vsort = NULL;
4136    }
4137 
4138    /* map the values in val to the colormap */
4139 
4140    /* finally ! */
4141    if (!SUMA_ScaleToMap (val, SO->N_Node, OptScl->IntRange[0],
4142                          OptScl->IntRange[1], CM, OptScl, SV)) {
4143       fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_ScaleToMap.\n", FuncName);
4144       SUMA_RETURN (NOPE);
4145    }
4146 
4147    /* copy the colors to rgba */
4148    for (i=0; i < SO->N_Node; ++i) {
4149       i4 = 4 * i;
4150       i3 = 3 *i;
4151       rgba[i4] = (byte)(SV->cV[i3  ] * 255); ++i4;
4152       rgba[i4] = (byte)(SV->cV[i3+1] * 255); ++i4;
4153       rgba[i4] = (byte)(SV->cV[i3+2] * 255); ++i4;
4154       rgba[i4] = 255;
4155    }
4156 
4157    /* now create the niml element */
4158    UNIQ_idcode_fill (idcode_str);
4159    /* Now create that data element and write it out */
4160    SUMA_allow_nel_use(1);
4161    nel = SUMA_NewNel (  SUMA_NODE_RGBAb, /* one of SUMA_DSET_TYPE */
4162                         SO->idcode_str, /* idcode of Domain Parent */
4163                         NULL, /* idcode of geometry parent, not useful here*/
4164                         SO->N_Node,/* Number of elements */
4165                         NULL, NULL);
4166    if (!nel) {
4167       fprintf (stderr,"Error  %s:\nFailed in SUMA_NewNel", FuncName);
4168       SUMA_RETURN(NULL);
4169    }
4170    /* set the surface idcode attribute */
4171    NI_set_attribute (nel, "surface_idcode", SO->idcode_str);
4172 
4173    /* Add the columns */
4174    SUMA_allow_nel_use(1);
4175    if (!SUMA_AddNelCol (nel, /* the famed nel */
4176                         "node index",
4177                         SUMA_NODE_INDEX, /* the column's type (description),
4178                                             one of SUMA_COL_TYPE */
4179                         (void *)node, /* the list of node indices */
4180                         NULL  /* that's an optional structure containing
4181                                  attributes of the added column.
4182                                  Not used at the moment */
4183                         ,1 /* stride, useful when you need to copy a column
4184                               from a multiplexed vector. Say you have in p
4185                               [rgb rgb rgb rgb], to get the g column you
4186                               send in p+1 for the column pointer and a stride
4187                               of 3 */
4188                         )) {
4189       fprintf (stderr,"Error  %s:\nFailed in SUMA_AddNelCol", FuncName);
4190       SUMA_RETURN(NULL);
4191    }
4192 
4193    /* insert from multiplexed rgb vector */
4194    SUMA_allow_nel_use(1);
4195    if (!SUMA_AddNelCol (nel, "red", SUMA_NODE_Rb, (void *)rgba, NULL ,4 )) {
4196       fprintf (stderr,"Error  %s:\nFailed in SUMA_AddNelCol", FuncName);
4197       SUMA_RETURN(NULL);
4198    }
4199 
4200    SUMA_allow_nel_use(1);
4201    if (!SUMA_AddNelCol (nel, "green", SUMA_NODE_Gb, (void *)(rgba+1), NULL ,4)) {
4202       fprintf (stderr,"Error  %s:\nFailed in SUMA_AddNelCol", FuncName);
4203       SUMA_RETURN(NULL);
4204    }
4205 
4206    SUMA_allow_nel_use(1);
4207    if (!SUMA_AddNelCol (nel, "blue", SUMA_NODE_Bb, (void *)(rgba+2), NULL ,4)) {
4208       fprintf (stderr,"Error  %s:\nFailed in SUMA_AddNelCol", FuncName);
4209       SUMA_RETURN(NULL);
4210    }
4211 
4212    SUMA_allow_nel_use(1);
4213    if (!SUMA_AddNelCol (nel, "alpha", SUMA_NODE_Ab, (void *)(rgba+3), NULL ,4)) {
4214       fprintf (stderr,"Error  %s:\nFailed in SUMA_AddNelCol", FuncName);
4215       SUMA_RETURN(NULL);
4216    }
4217 
4218 
4219    ++i_in;
4220 
4221    if (cleanup == -1) {
4222       SUMA_LH("Last or one call only cleanup");
4223       SUMA_NODEVAL2IRGBA_CLEANUP;
4224       past_instance[0]='\0';
4225       i_in = 0;
4226    }
4227 
4228    /* return the element */
4229    SUMA_RETURN(nel);
4230 
4231 }
4232 #define SUMA_SEND_TO_SUMA_FUNC_CLEANUP {   \
4233       /* call all nel forming functions with cleanup. */ \
4234       SUMA_LH("Cleanup for SUMA_NodeVal2irgba_nel...");  \
4235       SUMA_NodeVal2irgba_nel (NULL, NULL, NULL, 1);   \
4236       SUMA_LH("Cleanup for SUMA_NodeXYZ2NodeXYZ_nel...");   \
4237       SUMA_NodeXYZ2NodeXYZ_nel (NULL, NULL, 1, SUMA_NODE_XYZ); \
4238       SUMA_LH("Cleanup for SUMA_Mesh_IJK2Mesh_IJK_nel..."); \
4239       SUMA_Mesh_IJK2Mesh_IJK_nel (NULL, NULL, 1, SUMA_NEW_MESH_IJK); \
4240 }
SUMA_Wait_Till_Stream_Goes_Bad(SUMA_COMM_STRUCT * cs,int slp,int WaitMax,int verb)4241 void SUMA_Wait_Till_Stream_Goes_Bad(SUMA_COMM_STRUCT *cs,
4242                                     int slp, int WaitMax, int verb)
4243 {
4244    static char FuncName[]={"SUMA_Wait_Till_Stream_Goes_Bad"};
4245    SUMA_Boolean good = YUP;
4246    int WaitClose = 0;
4247    SUMA_Boolean LocalHead = NOPE;
4248 
4249    SUMA_ENTRY;
4250 
4251    if (verb) {
4252       if(dsq==0) fprintf (SUMA_STDERR,"\nWaiting for SUMA to close stream .");
4253    }
4254 
4255    while (good && WaitClose < WaitMax) {
4256       if (NI_stream_goodcheck(SUMAg_CF->ns_v[cs->istream], 1) <= 0) {
4257          good = NOPE;
4258       } else {
4259          SUMA_LHv("Good Check OK. Sleeping for %d ms...", slp);
4260          NI_sleep(slp);
4261          if (verb) fprintf (SUMA_STDERR,".");
4262          WaitClose += slp;
4263       }
4264    }
4265 
4266    if (WaitClose >= WaitMax) {
4267       if (verb)
4268          SUMA_S_Warnv("\nFailed to detect closed stream after %d ms.\n"
4269          "(You can change max. wait time with env. SUMA_DriveSumaMaxCloseWait)\n"
4270                       "Closing shop anyway...", WaitMax);
4271    }else{
4272       if (verb) fprintf (SUMA_STDERR,"Done.\n");
4273    }
4274 
4275    SUMA_RETURNe;
4276 }
4277 
4278 /*!
4279    \brief Function to handle send data elements to AFNI
4280    \param SO (SUMA_SurfaceObject *) pointer to surface object structure
4281    \param cs (SUMA_COMM_STRUCT *) Communication structure.
4282                                  (initialized when action is 0)
4283                                  If cs is NULL then this call would be made
4284                                  by SUMA to drive itself to the twilight zone.
4285    \param data (void *) pointer to data that gets typecast as follows:
4286                         (float *) if dtype == Node_RGBAb or Node_XYZ
4287    \param dtype (SUMA_DSET_TYPE) Type of nel to be produced
4288                                  (this determines the typecasting of data)
4289    \param instanceID (char *) a unique identifier for the instance of data sent.
4290                               For data of a particular dtype, use same
4291                               instanceID for data that is being sent repeatedly
4292    \param action (int)  2: Make cleanup call to functions producing nel out
4293                            of data Close stream
4294                         1: Create a nel out of data and send to AFNI
4295                         0: start connection with AFNI
4296                            initialize cs
4297                            prepare functions producing
4298                            nels out of data
4299    \return errflag (SUMA_Boolean)
4300                      YUP: All is OK (although connection might get closed)
4301                       NOPE: Some'in bad a happening.
4302                       Connections getting closed in the midst of things are
4303                       not considered as errors because they should not halt
4304                       the execution of the main program
4305 
4306    NOTE: The cleanup automatically closes the connection.
4307          That is stupid whenever you need to send multiple types of data
4308          for multiple surfaces. Cleanup should be done without closing
4309          connections!
4310          See comment in function SUMA_SendSumaNewSurface's code.
4311          Also, send kth should be more clever, keeping separate counts per
4312          datatype and per surface
4313 */
SUMA_SendToSuma(SUMA_SurfaceObject * SO,SUMA_COMM_STRUCT * cs,void * data,SUMA_DSET_TYPE dtype,int action)4314 SUMA_Boolean SUMA_SendToSuma (SUMA_SurfaceObject *SO, SUMA_COMM_STRUCT *cs,
4315                               void *data, SUMA_DSET_TYPE dtype, int action)
4316 {
4317    static char FuncName[]={"SUMA_SendToSuma"};
4318    static float etm = 0.0;
4319    static int i_in = 0;
4320    char stmp[500];
4321    static struct  timeval tt;
4322    NI_element *nel=NULL;
4323    NI_group *ngr = NULL;
4324    float *f=NULL;
4325    int n=-1, WaitClose, WaitMax, *ip = NULL;
4326    float wtm;
4327    SUMA_Boolean good = YUP;
4328    SUMA_Boolean LocalHead = NOPE;
4329 
4330    SUMA_ENTRY;
4331 
4332    /* fprintf (SUMA_STDERR, "%s: LocalHead = %d\n", FuncName, LocalHead); */
4333 
4334    if (action == 0) { /* initialization of connection */
4335       if (!cs) { /* Nothing to do, return */
4336          SUMA_LH("No cs, probably talking to self");
4337          ++i_in;
4338          SUMA_RETURN(YUP);
4339       }
4340       SUMA_LH("Setting up for communication with SUMA ...");
4341       cs->Send = YUP;
4342       if(!SUMA_Assign_HostName (SUMAg_CF, cs->suma_host_name, cs->istream)) {
4343 		   SUMA_S_Err("Failed in SUMA_Assign_HostName");
4344 		   exit (1);
4345 	   }
4346       if (!SUMA_niml_call (SUMAg_CF, cs->istream, NOPE)) {
4347          SUMA_SL_Err("Failed in SUMA_niml_call");
4348          /* connection flag is reset in SUMA_niml_call */
4349          cs->Send = NOPE;
4350          SUMA_RETURN(NOPE);
4351       }
4352 
4353       nel = NI_new_data_element("StartTracking", 0);
4354       cs->TrackID = 1; /* that's the index for StartTracking command */
4355       NI_set_attribute(nel,"ni_stream_name",
4356                        SUMAg_CF->NimlStream_v[cs->istream]);
4357       sprintf(stmp, "%d", cs->TrackID);
4358       NI_set_attribute(nel,"Tracking_ID", stmp);
4359       if (NI_write_element( SUMAg_CF->ns_v[cs->istream] ,
4360                             nel, cs->comm_NI_mode ) < 0) {
4361          SUMA_SL_Err("Failed to start tracking.\nContinuing...");
4362       }
4363       if (nel) NI_free_element(nel); nel = NULL;
4364 
4365       /* here is where you would start the workprocess for this program
4366       But since communication is one way, then forget about it */
4367       ++i_in;
4368       SUMA_RETURN(YUP);
4369    }
4370 
4371    if (action == 1) { /* action == 1,  send data mode */
4372       if (cs) {
4373          if (!i_in) {
4374             SUMA_SL_Err("You must call SUMA_SendToSuma with action 0 "
4375                         "before action 1.\nNo Communcation cleanup done.");
4376             cs->Send = NOPE;
4377             SUMA_RETURN(NOPE);
4378          }
4379          if ((cs->ElInd[dtype] % cs->kth)) {
4380             SUMA_LHv("Skipping element %d of type %d\n",
4381                      cs->ElInd[dtype], dtype);
4382             ++cs->ElInd[dtype];
4383             SUMA_RETURN(YUP);
4384          }
4385          ++cs->ElInd[dtype];
4386       }
4387       SUMA_LH("Creating nel and sending it");
4388       switch (dtype) {
4389          case SUMA_NODE_RGBAb:
4390          case SUMA_NODE_XYZ:
4391          case SUMA_NEW_NODE_XYZ:
4392             n = 3 * SO->N_Node;
4393             f = (float *)data;
4394             break;
4395          case SUMA_NEW_MESH_IJK:
4396          case SUMA_MESH_IJK:
4397             n = 3 * SO->N_FaceSet;
4398             ip = (int *)data;
4399             break;
4400          case SUMA_PREP_NEW_SURFACE:
4401             break;
4402          case SUMA_SURFACE_OBJECT:
4403          case SUMA_SEGMENT_OBJECT:
4404          case SUMA_ENGINE_INSTRUCTION:
4405             break;
4406          default:
4407             SUMA_SL_Err("Data type not supported.");
4408             if (cs) {
4409                cs->GoneBad = YUP;
4410                cs->Send = NOPE;
4411             }
4412             SUMA_RETURN(NOPE);
4413             break;
4414       }
4415 
4416       if (cs) {
4417          /* make sure stream is still OK */
4418          if (NI_stream_goodcheck ( SUMAg_CF->ns_v[cs->istream] , 1 ) < 0) {
4419             cs->GoneBad = YUP;
4420             SUMA_SL_Warn("Communication stream gone bad.\n"
4421                          "Shutting down communication.");
4422             cs->Send = NOPE;
4423             SUMA_SEND_TO_SUMA_FUNC_CLEANUP;
4424             SUMA_RETURN(YUP);
4425                /* returning without error since program should continue */
4426          }
4427       }
4428 
4429       nel = NULL; ngr = NULL;
4430       switch (dtype) {
4431          case SUMA_NODE_RGBAb:
4432             /* colorize data */
4433             nel = SUMA_NodeVal2irgba_nel (SO, f, SO->idcode_str, 0);
4434             if (!nel) {
4435                SUMA_SL_Err("Failed in SUMA_NodeVal2irgba_nel.\n"
4436                            "Communication off.")
4437                if (cs) cs->Send = NOPE;
4438                SUMA_RETURN(NOPE);
4439             }
4440             break;
4441          case SUMA_NODE_XYZ:
4442          case SUMA_NEW_NODE_XYZ:
4443             /* turn XYZ to nel  */
4444             nel =  SUMA_NodeXYZ2NodeXYZ_nel(SO, f, NOPE, dtype);
4445             if (!nel) {
4446                SUMA_SL_Err("Failed in SUMA_NodeXYZ2NodeXYZ_nel.\n"
4447                            "Communication off.")
4448                if (cs) cs->Send = NOPE;
4449                SUMA_RETURN(NOPE);
4450             }
4451             if (cs->Feed2Afni) NI_set_attribute(nel, "Send2Afni", "DoItBaby");
4452             break;
4453          case SUMA_MESH_IJK:
4454          case SUMA_NEW_MESH_IJK:
4455             /* turn IJK to nel  */
4456             nel =  SUMA_Mesh_IJK2Mesh_IJK_nel(SO, ip, NOPE, dtype);
4457             if (!nel) {
4458                SUMA_SL_Err("Failed in SUMA_Mesh_IJK2Mesh_IJK_nel.\n"
4459                            "Communication off.")
4460                if (cs) cs->Send = NOPE;
4461                SUMA_RETURN(NOPE);
4462             }
4463             break;
4464          case SUMA_PREP_NEW_SURFACE:
4465             nel = NI_new_data_element(SUMA_Dset_Type_Name(dtype), 0);
4466             NI_set_attribute (nel, "surface_idcode", SO->idcode_str);
4467             if (SO->VolPar) {
4468                char *vppref=NULL;
4469                vppref = SUMA_append_replace_string(SO->VolPar->dirname,
4470                                        SO->VolPar->filecode, "/", 0);
4471                NI_set_attribute(nel, "VolParFilecode", vppref);
4472                SUMA_free(vppref); vppref = NULL;
4473                if (cs && cs->Feed2Afni)
4474                   NI_set_attribute(nel, "Send2Afni", "DoItBaby");
4475             }
4476             break;
4477          case SUMA_SURFACE_OBJECT:
4478          case SUMA_SEGMENT_OBJECT:
4479          case SUMA_ENGINE_INSTRUCTION:
4480             ngr = (NI_group *)data;
4481             break;
4482          default:
4483             SUMA_SL_Err("Unexpected element. Ignoring.");
4484             SUMA_RETURN(YUP);
4485             break;
4486       }
4487 
4488 
4489       if (!nel && !ngr) {/* !nel */
4490          SUMA_SL_Err("Flow error.");
4491          SUMA_RETURN(NOPE);
4492       }else {/* !nel */
4493          if (nel && ngr) {
4494             SUMA_SL_Err("Flow error.");
4495             SUMA_RETURN(NOPE);
4496          }
4497          /* add tracking */
4498          if (cs) {
4499             ++cs->TrackID;
4500             sprintf(stmp,"%d", cs->TrackID);
4501             if (nel) {
4502                NI_set_attribute (nel, "Tracking_ID", stmp);
4503             } else if (ngr) {
4504                NI_set_attribute (ngr, "Tracking_ID", stmp);
4505             }
4506          }
4507       }
4508 
4509       #if SUMA_SUMA_NIML_DEBUG /* writes every element to a
4510                                   text file for debugging ... */
4511       if (cs) {
4512          NI_stream ns;
4513          /* Test writing results in asc, 1D format */
4514          if (LocalHead) fprintf(stderr," %s:-\nWriting ascii 1D ...\n"
4515                         , FuncName);
4516          /* open the stream */
4517          sprintf(stmp, "file:niml_dbg_asc_TID_%d_.1D",cs->TrackID);
4518          ns = NI_stream_open( stmp , "w" ) ;
4519          if( ns == NULL ){
4520            fprintf (stderr,"Error  %s:\nCan't open Test_write_asc_1D!"
4521                         , FuncName);
4522             SUMA_RETURN(NOPE);
4523          }
4524 
4525          if (nel) {
4526             /* write out the element */
4527             if (NI_write_element( ns , nel ,
4528                                   NI_TEXT_MODE | NI_HEADERSHARP_FLAG ) < 0) {
4529                fprintf (stderr,"Error  %s:\nFailed in NI_write_element"
4530                               , FuncName);
4531                SUMA_RETURN(NOPE);
4532             }
4533          } else if (ngr) {
4534             /* write out the element */
4535             if (NI_write_element( ns , ngr ,
4536                                   NI_TEXT_MODE | NI_HEADERSHARP_FLAG ) < 0) {
4537                fprintf (stderr,"Error  %s:\nFailed in NI_write_element"
4538                               , FuncName);
4539                SUMA_RETURN(NOPE);
4540             }
4541          }
4542 
4543          /* close the stream */
4544          NI_stream_close( ns ) ;
4545       }
4546       #endif
4547 
4548       if (cs && cs->nelps > 0) { /* make sure that you are not sending
4549                               elements too fast */
4550          if (!etm) {
4551             etm = 100000.0; /* first pass, an eternity */
4552             if (LocalHead)
4553                fprintf (SUMA_STDOUT,"%s: Initializing timer\n", FuncName);
4554             SUMA_etime(&tt, 0);
4555          }
4556          else {
4557             if (LocalHead)
4558                fprintf (SUMA_STDOUT,"%s: Calculating etm\n", FuncName);
4559             etm = SUMA_etime(&tt, 1);
4560          }
4561          wtm = 1./cs->nelps - etm;
4562          if (wtm > 0) { /* wait */
4563             if (LocalHead)
4564                fprintf (SUMA_STDOUT,
4565                         "%s: Sleeping by %f to meet refresh rate...\n",
4566                         FuncName, wtm);
4567             NI_sleep((int)(wtm*1000));
4568          }
4569       }
4570 
4571       /* send it to SUMA */
4572       if (cs) {
4573          if (LocalHead)
4574             fprintf (SUMA_STDOUT,"Sending element %d comm_NI_mode = %d...\n",
4575                                  cs->TrackID, cs->comm_NI_mode);
4576          if (nel) {
4577             if (NI_write_element(   SUMAg_CF->ns_v[cs->istream] , nel,
4578                                     cs->comm_NI_mode ) < 0) {
4579                SUMA_LH("Failed updating SUMA...");
4580             }
4581          } else if (ngr) {
4582             if (NI_write_element(   SUMAg_CF->ns_v[cs->istream] , ngr,
4583                                     cs->comm_NI_mode ) < 0) {
4584                SUMA_LH("Failed updating SUMA...");
4585             }
4586          }
4587          if (LocalHead) {
4588             if (cs->nelps > 0)
4589                fprintf (SUMA_STDOUT,
4590                         "        element %d sent (%f sec)\n",
4591                         cs->TrackID, SUMA_etime(&tt, 1));
4592             else fprintf (SUMA_STDOUT,"        element %d sent \n", cs->TrackID);
4593          }
4594       } else {
4595          SUMA_LH("Straight into the bowels");
4596          if (nel) {
4597             if (!SUMA_process_NIML_data((void *)nel, NULL)) {
4598                SUMA_S_Err("Failed to process %s", nel->name);
4599             }
4600          } else if (ngr) {
4601             if (!SUMA_process_NIML_data((void *)ngr, NULL)) {
4602                SUMA_S_Err("Failed to process %s", ngr->name);
4603             }
4604          }
4605       }
4606       if (nel && nel != data) NI_free_element(nel) ; nel = NULL;
4607       if (ngr && ngr != data) NI_free_element(ngr) ; ngr = NULL;
4608 
4609       if (cs && cs->nelps > 0) {
4610          if (LocalHead)
4611             fprintf (SUMA_STDOUT,"%s: Resetting time...\n", FuncName);
4612          SUMA_etime(&tt, 0); /* start the timer */
4613       }
4614       ++i_in;
4615       SUMA_RETURN(YUP);
4616    }/* action == 1 */
4617 
4618    if (action == 2) {
4619       if (i_in < 2) {
4620          SUMA_SL_Err("You must call SUMA_SendToSuma with action 0 and 1"
4621                      " before action 2.\nNo Communcation cleanup done.");
4622          if (cs) cs->Send = NOPE;
4623          SUMA_RETURN(NOPE);
4624       }
4625       /* reset static variables */
4626          i_in = 0;
4627          etm = 0.0;
4628 
4629       SUMA_SEND_TO_SUMA_FUNC_CLEANUP;
4630 
4631       if (!cs) {
4632          SUMA_RETURN(YUP);
4633       }
4634 
4635       /* now close the stream*/
4636       if (cs->Send && !cs->GoneBad) {
4637          SUMA_LH("Cleanup of nel producing functions...");
4638          /* stop tracking */
4639          nel = NI_new_data_element("StopTracking", 0);
4640          NI_set_attribute(nel,"ni_stream_name",
4641                           SUMAg_CF->NimlStream_v[cs->istream]);
4642 
4643          if (NI_write_element( SUMAg_CF->ns_v[cs->istream] , nel,
4644                                cs->comm_NI_mode ) < 0) {
4645             SUMA_SL_Err("Failed to stop tracking.\nContinuing...");
4646          }
4647          if (nel) NI_free_element(nel); nel = NULL;
4648 
4649          /* tell suma you're done with that stream */
4650          nel = NI_new_data_element("CloseKillStream",0);
4651          if (!nel) {
4652             SUMA_SL_Err("Failed to create nel");
4653             exit(1);
4654          }
4655 
4656          NI_set_attribute (nel, "ni_stream_name",
4657                            SUMAg_CF->NimlStream_v[cs->istream]);
4658          if (NI_write_element( SUMAg_CF->ns_v[cs->istream] , nel,
4659                                cs->comm_NI_mode ) < 0) {
4660                         SUMA_LH("Failed updating SUMA...");
4661          }
4662          if (nel) NI_free_element(nel) ; nel = NULL;
4663 
4664 
4665          /* now wait till stream goes bad */
4666          SUMA_Wait_Till_Stream_Goes_Bad(cs, 1000,
4667                                     SUMAg_CF->ns_toc[cs->istream], 1);
4668 
4669          NI_stream_close(SUMAg_CF->ns_v[cs->istream]);
4670          SUMAg_CF->ns_v[cs->istream] = NULL;
4671          SUMAg_CF->ns_flags_v[cs->istream] = 0;
4672          SUMAg_CF->TrackingId_v[cs->istream] = 0;
4673          cs->Send = NOPE;
4674          cs->GoneBad = NOPE;
4675          cs->nelps = -1.0;
4676          cs->TrackID = 0;
4677          cs->istream = -1;
4678 
4679 
4680 
4681       }
4682 
4683       SUMA_RETURN(YUP);
4684    }
4685 
4686    /* should not get here */
4687    SUMA_SL_Err("Flow error.\nThis should not be");
4688    SUMA_RETURN(NOPE);
4689 }
4690 
4691 /*!
4692    \brief Function to handle send data elements to AFNI
4693    \param cs (SUMA_COMM_STRUCT *) Communication structure. (initialized when action is 0)
4694    \param data (void *) pointer to data that gets typecast as an afni dset
4695    \param action (int)  2: Make cleanup call to functions producing nel out of data
4696                            Close stream
4697                         1: Create a nel out of data and send to AFNI
4698                         0: start connection with AFNI
4699                            initialize cs
4700                            prepare functions producing
4701                            nels out of data
4702    \return errflag (SUMA_Boolean) YUP: All is OK (although connection might get closed)
4703                                   NOPE: Some'in bad a happening.
4704                                   Connections getting closed in the midst of things are
4705                                   not considered as errors because they should not halt
4706                                   the execution of the main program
4707 
4708 */
SUMA_SendToAfni(SUMA_COMM_STRUCT * cs,void * data,int action)4709 SUMA_Boolean SUMA_SendToAfni (SUMA_COMM_STRUCT *cs, void *data, int action)
4710 {
4711    static char FuncName[]={"SUMA_SendToAfni"};
4712    static float etm = 0.0;
4713    static int i_in = 0;
4714    char stmp[500];
4715    static struct  timeval tt;
4716    NI_element *nel=NULL;
4717    float *f=NULL;
4718    int n=-1, WaitClose, WaitMax, *ip = NULL;
4719    float wtm;
4720    SUMA_Boolean good = YUP;
4721    SUMA_Boolean LocalHead = NOPE;
4722 
4723    SUMA_ENTRY;
4724 
4725 
4726    if (action == 0) { /* initialization of connection */
4727 
4728       SUMA_LH("Setting up for communication with AFNI ...");
4729       cs->afni_Send = YUP;
4730       if(!SUMA_Assign_HostName (SUMAg_CF,
4731                            cs->afni_host_name, cs->afni_istream)) {
4732 		   fprintf (SUMA_STDERR,
4733                      "Error %s: Failed in SUMA_Assign_HostName", FuncName);
4734 		   exit (1);
4735 	   }
4736       if (!SUMA_niml_call (SUMAg_CF, cs->afni_istream, NOPE)) {
4737          SUMA_SL_Err("Failed in SUMA_niml_call");
4738          /* connection flag is reset in SUMA_niml_call */
4739          cs->afni_Send = NOPE;
4740          SUMA_RETURN(NOPE);
4741       }
4742 
4743       /* no tracking for talking to AFNI */
4744 
4745       /* here is where you would start the workprocess for this program
4746       But since communication is one way, then forget about it */
4747       ++i_in;
4748       SUMA_RETURN(YUP);
4749    }
4750 
4751    if (action == 1) { /* action == 1,  send data mode */
4752       if (!i_in) {
4753          SUMA_SL_Err(
4754             "You must call SUMA_SendToAfni with action 0 before action 1.\n"
4755             "No Communcation cleanup done.");
4756          cs->afni_Send = NOPE;
4757          SUMA_RETURN(NOPE);
4758       }
4759 
4760       SUMA_LH("Creating nel and sending it");
4761 
4762       /* make sure stream is till OK */
4763       if (NI_stream_goodcheck ( SUMAg_CF->ns_v[cs->afni_istream] , 1 ) < 0) {
4764          cs->afni_GoneBad = YUP;
4765          SUMA_SL_Warn("Communication stream with afni gone bad.\n"
4766                       "Shutting down communication.");
4767          cs->afni_Send = NOPE;
4768          SUMA_RETURN(YUP); /* returning without error since program
4769                                     should continue */
4770       }
4771 
4772       if (!SUMA_SendDset_Afni( SUMAg_CF->ns_v[cs->afni_istream],
4773                                  (SUMA_SEND_2AFNI *)data, 1)) {
4774          SUMA_SL_Err("Failed to send dset");
4775          cs->afni_Send = NOPE;
4776          SUMA_RETURN(NOPE);
4777       }
4778 
4779       ++i_in;
4780       SUMA_RETURN(YUP);
4781    }/* action == 1 */
4782 
4783    if (action == 2) {
4784       if (i_in < 2) {
4785          SUMA_SL_Err("You must call SUMA_SendToAfni with action 0 and 1 "
4786                      "before action 2.\nNo Communcation cleanup done.");
4787          cs->afni_Send = NOPE;
4788          SUMA_RETURN(NOPE);
4789       }
4790       /* reset static variables */
4791          i_in = 0;
4792          etm = 0.0;
4793 
4794       /* now close the stream*/
4795       if (cs->afni_Send && !cs->afni_GoneBad) {
4796          SUMA_LH("Cleanup of nel producing functions...");
4797 
4798          NI_stream_close(SUMAg_CF->ns_v[cs->afni_istream]);
4799          SUMAg_CF->ns_v[cs->afni_istream] = NULL;
4800          SUMAg_CF->ns_flags_v[cs->afni_istream] = 0;
4801          SUMAg_CF->TrackingId_v[cs->afni_istream] = 0;
4802          cs->afni_Send = NOPE;
4803          cs->afni_GoneBad = NOPE;
4804          cs->afni_istream = -1;
4805       }
4806 
4807       SUMA_RETURN(YUP);
4808    }
4809 
4810    /* should not get here */
4811    SUMA_SL_Err("Flow error.\nThis should not be");
4812    SUMA_RETURN(NOPE);
4813 }
4814 
SUMA_SendDset_Afni(NI_stream ns,SUMA_SEND_2AFNI * SS2A,int all)4815 SUMA_Boolean SUMA_SendDset_Afni( NI_stream ns, SUMA_SEND_2AFNI *SS2A, int all)
4816 {
4817    static char FuncName[]={"SUMA_SendDset_Afni"};
4818    NI_group *ngr = NULL;
4819    NI_element *nel = NULL;
4820    int iv;
4821    SUMA_Boolean LocalHead = NOPE;
4822 
4823    SUMA_ENTRY;
4824 
4825    if (!SS2A->dset) {
4826       SUMA_SL_Warn("NULL dset, nothing to do");
4827       SUMA_RETURN(YUP);
4828    }
4829 
4830    if (all == 1) {
4831       SUMA_LH("Sending all dset at once");
4832       ngr = THD_dataset_to_niml( SS2A->dset ) ;
4833       NI_set_attribute( ngr , "AFNI_prefix" , DSET_PREFIX(SS2A->dset) ) ;
4834       if (SS2A->at_sb >= 0) {
4835          if (DSET_NVALS(SS2A->dset) != 1) {
4836             SUMA_S_Warn("Not sure what happens when using"
4837                         "at_sb with more than one sub-brick");
4838          }
4839          nel = SUMA_FindNgrNamedElement(ngr, "VOLUME_DATA");
4840          NI_SET_INT(nel, "AFNI_index", SS2A->at_sb);
4841       }
4842       NI_write_element(ns, ngr, NI_BINARY_MODE);
4843       NI_free_element(ngr); ngr = NULL;
4844       SUMA_LH("Done.");
4845    } else {
4846       SUMA_SL_Warn("Sending one sub-brick at a time NOT TESTED IN SUMA YET");
4847       ngr = THD_nimlize_dsetatr( SS2A->dset ) ;   /* header only */
4848       NI_set_attribute( ngr , "AFNI_prefix" , DSET_PREFIX(SS2A->dset) ) ;
4849       NI_write_procins( ns , "keep_reading" ) ;
4850       NI_write_element( ns, ngr, NI_BINARY_MODE ) ;
4851       NI_free_element( ngr ) ; ngr = NULL;
4852       for( iv=0 ; iv < DSET_NVALS(SS2A->dset) ; iv++ ){
4853          nel = THD_subbrick_to_niml( SS2A->dset , iv , SBFLAG_INDEX ) ;
4854          NI_write_element( ns , nel , NI_BINARY_MODE ) ;
4855          NI_free_element(nel) ; nel = NULL;
4856       }
4857       NI_write_procins( ns , "pause_reading" ) ; /* not necessary but tidy */
4858    }
4859 
4860 
4861    SUMA_RETURN(YUP);
4862 }
4863