1 #include "SUMA_suma.h"
2 
3 extern SUMA_CommonFields *SUMAg_CF;
4 extern SUMA_DO *SUMAg_DOv;
5 extern int SUMAg_N_DOv;
6 extern SUMA_SurfaceViewer *SUMAg_SVv;
7 extern int SUMAg_N_SVv;
8 
9 /*! functions dealing with Drawable Object Manipulation */
10 
11 /*!
12    This function Links one Inode to another.
13    This is different from CreateInode in that no new node is being allocated for, only a link is created.
14    SUMA_CreateInodeLink (SUMA_INODE * FromIN, SUMA_INODE *ToIN)
15 
16    FromIN = SUMA_CreateInodeLink (FromIN, ToIN);
17 
18    \param FromIN (SUMA_INODE *) this is the pointer to the IDnode wich will be linked to ToIN.
19           As silly as this sounds, this should be a pointer to NULL otherwise the link will not
20           be established. The use of this function will help reduce the risk of linking pointers
21           that are pointing to allocated space.
22    \param ToIN (SUMA_INODE *) pointer where the link is going
23    \ret FromIN (SUMA_INODE *) if all is well, FromIN = ToIN
24       otherwise, NULL is returned
25 
26       All this function does is check the FromIN is NULL and ToIN isn't and then it calls SUMA_AddLink (ToIN)
27    \sa SUMA_BreakInodeLink
28    \sa SUMA_isInodeLink
29 */
SUMA_CreateInodeLink(SUMA_INODE * FromIN,SUMA_INODE * ToIN)30 SUMA_INODE *SUMA_CreateInodeLink (SUMA_INODE * FromIN, SUMA_INODE *ToIN)
31 {
32    static char FuncName[] = {"SUMA_CreateInodeLink"};
33 
34    SUMA_ENTRY;
35 
36    if (FromIN) {
37       fprintf (SUMA_STDERR,"Error %s: FromIN Inode is not NULL. \n\tFromIN pointer is left undisturbed.\n", FuncName);
38       SUMA_RETURN(FromIN);
39    }
40    if (!ToIN) {
41       fprintf (SUMA_STDERR,"Error %s: ToIN is NULL.\n\t Can't link to NULL, returning NULL.\n", FuncName);
42       SUMA_RETURN(NULL);
43    }
44 
45    /* add a link to ToIN */
46    if (!SUMA_AddLink (ToIN)) {
47       fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_AddLink.\n", FuncName);
48       SUMA_RETURN(NULL);
49    }
50 
51    /* now return the pointer to be linked to */
52    SUMA_RETURN(ToIN);
53 
54 }
55 
56 /*!
57    This function determines if an Inode in a SO is a link or not.
58    an Inode is a link if IN->ParentIDcode and HolderIDcode are different.
59    The function is nothing more than a strcmp.
60 
61    SUMA_Boolean SUMA_isInodeLink (SUMA_INODE *IN, const char *HolderIDcode)
62 
63     returns NOPE if IN == NULL or IN->ParentIDcode != HolderIDcode
64 */
SUMA_isInodeLink(SUMA_INODE * IN,const char * HolderIDcode)65 SUMA_Boolean SUMA_isInodeLink (SUMA_INODE *IN, const char *HolderIDcode)
66 {
67    static char FuncName[] = {"SUMA_isInodeLink"};
68 
69    SUMA_ENTRY;
70 
71    if (!IN) {
72       fprintf (SUMA_STDERR, "Warning %s: IN is null.\n", FuncName);
73       SUMA_RETURN(NOPE);
74    }
75    if (!strcmp(IN->ParentIDcode, HolderIDcode)) SUMA_RETURN(YUP);
76 
77    SUMA_RETURN(NOPE);
78 }
79 
80 /*!
81    function to remove the link of one IDnode to the next
82    SUMA_INODE * SUMA_BreakInodeLink (SUMA_INODE *IN, const char *HolderIDcode);
83    \param IN (SUMA_INODE *) the linked inode
84    \param HolderIDcode (const char *) the ID code that holds/contains IN
85    \ret NULL if the link was broken or IN == NULL
86       IN if IN is not a link but an actuak Inode (meaning IN->ParentIDcode == HolderIDcode
87 
88 
89 */
SUMA_BreakInodeLink(SUMA_INODE * IN,const char * HolderIDcode)90 SUMA_INODE * SUMA_BreakInodeLink (SUMA_INODE *IN, const char *HolderIDcode)
91 {
92    static char FuncName[] = {"SUMA_BreakInodeLink"};
93 
94    SUMA_ENTRY;
95 
96    if (!IN) {
97       fprintf (SUMA_STDERR, "Warning %s: IN is null, nothing to do.\n", FuncName);
98       SUMA_RETURN(NULL);
99    }
100    if (!SUMA_isInodeLink (IN, HolderIDcode)) {
101       fprintf (SUMA_STDERR, "Error %s: Inode IN is not a link. Nothing done.\n", FuncName);
102       SUMA_RETURN(IN);
103    }
104 
105    /* release the link */
106    if (SUMA_ReleaseLink (IN) < 0) {
107       fprintf (SUMA_STDERR, "Error %s: IN has no links. Nothing done.\n", FuncName);
108       SUMA_RETURN(IN);
109    }
110 
111    /* OK, link released, not return NULL */
112    SUMA_RETURN(NULL);
113 }
114 
115 /*!
116    This function decrements the N_link field in IN by 1 and returns the resultant N_link value
117    a -1 is returned if IN->N_link = 0 or IN == NULL
118 
119 
120    ans = SUMA_ReleaseLink (IN);
121 
122    \param IN (SUMA_INODE *) pointer to SUMA_INODE structure
123    \ret ans (int) value of IN->N_link
124 
125    \sa SUMA_AddLink
126 */
SUMA_ReleaseLink(SUMA_INODE * IN)127 int SUMA_ReleaseLink (SUMA_INODE * IN)
128 {
129    static char FuncName[]={"SUMA_ReleaseLink"};
130    SUMA_Boolean LocalHead = NOPE;
131 
132    SUMA_ENTRY;
133 
134    if (!IN) {
135       /* This typically happens when A link was never created in the first place.
136       It used to be an error message but now it is just a warning because some
137       programs compute things like SO->Cx without creating an inode with it ...*/
138       fprintf (SUMA_STDERR,"Warning %s: Inode is null. Returning -1.\n", FuncName);
139       SUMA_RETURN(-1);
140    }
141    if (!IN->N_link) {
142       if (LocalHead) fprintf (SUMA_STDERR,"%s: No links. Returning -1.\n", FuncName);
143       /* You do not want to return a 0 because freeing is done when no links remain
144       THIS STUPID SYSTEM SHOULD BE ELIMINATED IN FAVOR OF THE METHOD USED FOR OVERLAYS*/
145       SUMA_RETURN(-1);
146    }
147    else {
148       IN->N_link--;
149       SUMA_RETURN(IN->N_link);
150    }
151 }
152 
153 /*!
154    This function increments the N_link field in IN by 1 and returns the resultant N_link value
155    a zero is returned in case of an error
156 
157 
158    ans = SUMA_AddLink (IN);
159 
160    \param IN (SUMA_INODE *) pointer to SUMA_INODE structure
161    \ret ans (int) value of IN->N_link
162    \sa SUMA_ReleaseLink
163 */
SUMA_AddLink(SUMA_INODE * IN)164 int SUMA_AddLink (SUMA_INODE * IN)
165 {
166    static char FuncName[]={"SUMA_AddLink"};
167 
168    SUMA_ENTRY;
169 
170    if (!IN) {
171       fprintf (SUMA_STDERR,"Error %s: Inode is null.\n", FuncName);
172 
173       SUMA_RETURN(0);
174    } else {
175       IN->N_link++;
176       SUMA_RETURN(IN->N_link);
177    }
178 }
179 
180 /*!
181    Function to create a SUMA_INODE structure
182    ans = SUMA_CreateInode (data, ParentIDcode);
183 
184    \param data (void *) pointer to data location
185    \param ParentIDcode (char[SUMA_IDCODE_LENGTH]) containing the IDcode of the creator of the data
186    \ret ans (SUMA_INODE *) pointer to SUMA_INODE for data
187       NULL if error is encountered
188 */
189 
SUMA_CreateInode(void * data,char * ID)190 SUMA_INODE *SUMA_CreateInode (void *data, char *ID)
191 {
192    static char FuncName[]={"SUMA_CreateInode"};
193    SUMA_INODE *IN;
194 
195    SUMA_ENTRY;
196 
197    IN = (SUMA_INODE *)SUMA_malloc (sizeof(SUMA_INODE));
198    if (IN == NULL) {
199       fprintf (SUMA_STDERR,"Error %s: failed to allocate for Inode.\n", FuncName);
200       SUMA_RETURN(NULL);
201    }
202 
203    IN->data = data;
204    strcpy (IN->ParentIDcode, ID);
205    IN->N_link = 0;
206 
207    SUMA_RETURN(IN);
208 }
209 
210 /*!
211 Create a Displayable Object data structure
212 */
SUMA_Alloc_DisplayObject_Struct(int N)213 SUMA_DO *SUMA_Alloc_DisplayObject_Struct (int N)
214 {
215    static char FuncName[]={"SUMA_Alloc_DisplayObject_Struct"};
216    SUMA_DO *dov;
217 
218    SUMA_ENTRY;
219 
220    dov = (SUMA_DO *)SUMA_malloc(sizeof(SUMA_DO)*N);
221    if (dov == NULL) {
222       SUMA_alloc_problem("SUMA_Alloc_DisplayObject_Struct: could not allocate memory for SO");
223    }
224    SUMA_RETURN(dov);
225 }/*SUMA_Alloc_DisplayObject_Struct*/
226 
227 
228 /*!
229 Free a Displayable Object data structure
230 */
SUMA_Free_Displayable_Object(SUMA_DO * dov)231 SUMA_Boolean SUMA_Free_Displayable_Object (SUMA_DO *dov)
232 {
233    static char FuncName[]={"SUMA_Free_Displayable_Object"};
234 
235    SUMA_ENTRY;
236 
237    switch (dov->ObjectType) {
238       case VO_type:
239          if (!SUMA_FreeVolumeObject ((SUMA_VolumeObject *)dov->OP)) {
240             SUMA_S_Err("could not free volume");
241          }
242          break;
243       case SO_type:
244          if (!SUMA_Free_Surface_Object ((SUMA_SurfaceObject *)dov->OP)) {
245             fprintf(SUMA_STDERR,
246                "Error SUMA_Free_Displayable_Object, could not free surface\n");
247          }
248          break;
249       case ROIdO_type:
250          if (!SUMA_freeDrawnROI ((SUMA_DRAWN_ROI *)dov->OP)) {
251             fprintf(SUMA_STDERR,
252                "Error SUMA_freeDrawnROI, could not free  ROI.\n");
253          }
254          break;
255       case ROIO_type:
256          if (!SUMA_freeROI ((SUMA_ROI *)dov->OP)) {
257             fprintf(SUMA_STDERR,"Error SUMA_freeROI, could not free  ROI.\n");
258          }
259          break;
260       case ONBV_type:
261       case NBV_type:
262       case OLS_type:
263       case LS_type:
264       case ODIR_type:
265       case DIR_type:
266       case NBLS_type:
267       case NBOLS_type:
268          SUMA_free_SegmentDO ((SUMA_SegmentDO *)dov->OP);
269          break;
270       case AO_type:
271          SUMA_Free_Axis((SUMA_Axis*)dov->OP);
272          break;
273       case GO_type:
274          fprintf(SUMA_STDERR,
275                   "Error SUMA_Free_Displayable_Object, "
276                   "Not trained to free GO objects\n");
277          break;
278       case not_DO_type:
279          /* not a DO, leave it to beaver */
280          break;
281       case NOT_SET_type:
282          fprintf(SUMA_STDERR,
283                   "Error SUMA_Free_Displayable_Object, "
284                   "no free NOT_SET_type\n");
285          break;
286       case PNT_type:
287       case NBSP_type:
288       case SP_type:
289          SUMA_free_SphereDO ((SUMA_SphereDO *)dov->OP);
290          break;
291       case PL_type:
292          SUMA_free_PlaneDO ((SUMA_PlaneDO *)dov->OP);
293          break;
294       case NIDO_type:
295          SUMA_free_NIDO((SUMA_NIDO*)dov->OP);
296          break;
297       case CDOM_type:
298          SUMA_FreeCIFTIObject((SUMA_CIFTI_DO *)dov->OP);
299          break;
300       case NBT_type:
301       case SBT_type:
302       case DBT_type:
303          /* those types are not used */
304          SUMA_S_Warnv("Type %d should not be in  use!\n", dov->ObjectType);
305          break;
306       case GDSET_type:
307       case MD_DSET_type:
308       case ANY_DSET_type:
309          SUMA_FreeDset(dov->OP);
310          break;
311       case TRACT_type:
312          SUMA_free_TractDO(dov->OP);
313          break;
314       case MASK_type:
315          SUMA_free_MaskDO(dov->OP);
316          break;
317       case GRAPH_LINK_type:
318          SUMA_free_GraphLinkDO(dov->OP);
319          break;
320       default:
321          SUMA_S_Errv("Type %d not accounted for!\n", dov->ObjectType);
322          break;
323    }
324 
325    SUMA_RETURN(YUP);
326 }
327 
SUMA_Free_Displayable_Object_Vect(SUMA_DO * dov,int N)328 SUMA_Boolean SUMA_Free_Displayable_Object_Vect (SUMA_DO *dov, int N)
329 {
330    static char FuncName[] = {"SUMA_Free_Displayable_Object_Vect"};
331    int i;
332    SUMA_Boolean Ret = YUP;
333 
334    SUMA_ENTRY;
335 
336    for (i=0; i < N; ++i) {
337       if (&dov[i] != NULL) {
338          Ret = Ret * SUMA_Free_Displayable_Object (&dov[i]);
339       }
340    }
341 
342    if (dov) SUMA_free(dov);
343    SUMA_RETURN(Ret);
344 
345 }
346 
347 /*!
348    Find a DO's index  by idcodestring
349 */
SUMA_FindDOi_byID(SUMA_DO * dov,int N_dov,char * idcode_str)350 int SUMA_FindDOi_byID(SUMA_DO *dov, int N_dov, char *idcode_str)
351 {
352    static char FuncName[] = {"SUMA_FindDOi_byID"};
353    int i;
354    void *op;
355    SUMA_ALL_DO *ado=NULL;
356    SUMA_Boolean LocalHead = NOPE;
357 
358    SUMA_ENTRY;
359 
360    SUMA_LHv("idcode %s\n", idcode_str);
361    if (!dov || !idcode_str) {
362       SUMA_RETURN(-1);
363    }
364 
365    for (i=0; i<N_dov; ++i) {
366       if (dov[i].ObjectType > not_DO_type) {
367          ado = (SUMA_ALL_DO *)dov[i].OP;
368          SUMA_LHv("ado %p: Object %d/%d type: %d\n",
369                   ado, i, N_dov, dov[i].ObjectType);
370          SUMA_LHv("ado->idcode_str= %s\n",
371                   SUMA_CHECK_NULL_STR(SUMA_ADO_idcode(ado)));
372          SUMA_LHv("idcode_str= %s\n",
373                   SUMA_CHECK_NULL_STR(idcode_str));
374          if (SUMA_ADO_idcode(ado) &&
375              strcmp(SUMA_ADO_idcode(ado), idcode_str) == 0) {
376             SUMA_RETURN(i);
377          }
378       } else {
379          SUMA_SL_Warn("Strange, no type for DO");
380       }
381    }
382    if (LocalHead) SUMA_Show_DOv (dov, N_dov, NULL);
383    SUMA_RETURN(-1);
384 }
385 
386 /*!
387 Add a displayable object to dov
388 */
SUMA_AddDO(SUMA_DO * dov,int * N_dov,void * op,SUMA_DO_Types DO_Type,SUMA_DO_CoordType DO_CoordType)389 SUMA_Boolean SUMA_AddDO(SUMA_DO *dov, int *N_dov, void *op,
390                         SUMA_DO_Types DO_Type, SUMA_DO_CoordType DO_CoordType)
391 {
392    static char FuncName[] = {"SUMA_AddDO"};
393    SUMA_ALL_DO *ado=NULL;
394    static int nm=0;
395    void *eo=NULL;
396    int ieo;
397    SUMA_Boolean LocalHead = NOPE;
398 
399    SUMA_ENTRY;
400 
401    ado = (SUMA_ALL_DO *)op;
402    if (!SUMA_ADO_idcode(ado)) {
403       SUMA_error_message (FuncName, "Need an idcode_str for do",0);
404       SUMA_RETURN(NOPE);
405    }
406    if (DO_Type <= not_DO_type || DO_Type >= N_DO_TYPES) {
407       SUMA_S_Errv("DO_type %d not valid\n", DO_Type);
408       SUMA_RETURN(NOPE);
409    }
410    /* Does that baby exist? */
411    if ((ieo = SUMA_FindDOi_byID(dov, *N_dov, SUMA_ADO_idcode(ado))) >= 0) {
412       if (DO_Type == SO_type) {
413          SUMA_SLP_Err("Surface exists, cannot be replaced this way.");
414          SUMA_RETURN(NOPE);
415       }
416       if (DO_Type == VO_type) {
417          SUMA_S_Warn("Replacing volume object, might get complicated...");
418       }
419       if (LocalHead ||
420           (!(nm % 300) && !SUMA_ADO_isLabel(ado,"AHorseWithNoName"))) {
421          SUMA_SL_Note( "Object %s existed as %s and will be replaced.\n"
422                         "Message shown intermittently",
423                         ADO_LABEL(ado), ADO_LABEL((SUMA_ALL_DO *)(dov[ieo].OP)));
424          ++nm;
425       }
426       /* free olde one */
427       if (!SUMA_Free_Displayable_Object(&(dov[ieo]))) {
428          SUMA_SL_Err("Failed to free displayable object");
429          SUMA_RETURN(NOPE);
430       }
431       dov[ieo].OP = op;
432       dov[ieo].ObjectType = DO_Type;
433       dov[ieo].CoordType = DO_CoordType;
434    } else {
435       /* Addington */
436       /* make sure you did not exceed allocated space */
437       if (*N_dov >= SUMA_MAX_DISPLAYABLE_OBJECTS) {
438          SUMA_error_message (FuncName, "Reached limit of DOv storage",0);
439          SUMA_RETURN(NOPE);
440       }
441       dov[*N_dov].OP = op;
442       dov[*N_dov].ObjectType = DO_Type;
443       dov[*N_dov].CoordType = DO_CoordType;
444       *N_dov = *N_dov+1;
445    }
446 
447 
448 
449 
450    SUMA_RETURN(YUP);
451 }
452 
453 /*!
454    \brief Remove a displayable object from dov
455    success = SUMA_RemoveDO(dov, N_dov, op, Free_op);
456 
457    \param dov (SUMA_DO*) vector containing displayable objects
458    \param N_dov (int *) number of elements in dov
459    \param op (void *) pointer to object sought
460    \param Free_op (SUMA_Boolean) Flag for freeing space allocated for op's data.
461          Freeing is done via SUMA_Free_Displayable_Object()
462    \return success (SUMA_Boolean)  flag.
463 */
SUMA_RemoveDO(SUMA_DO * dov,int * N_dov,void * op,SUMA_Boolean Free_op)464 SUMA_Boolean SUMA_RemoveDO(SUMA_DO *dov, int *N_dov, void *op,
465                            SUMA_Boolean Free_op)
466 {
467    static char FuncName[] = {"SUMA_RemoveDO"};
468    int i;
469    SUMA_Boolean Found=NOPE, State=YUP;
470    SUMA_Boolean LocalHead = NOPE;
471 
472    SUMA_ENTRY;
473 
474    SUMA_LH("Called");
475    if (LocalHead) {
476       SUMA_LH("Before deletion, %d objects", *N_dov);
477       for (i=0; i<*N_dov; ++i) {
478          fprintf(SUMA_STDERR,"%d: Label %s Type %s\n",
479                   i, ADO_LABEL((SUMA_ALL_DO*)dov[i].OP),
480                   ADO_TNAME((SUMA_ALL_DO*)dov[i].OP));
481       }
482    }
483    for (i=0; i<*N_dov; ++i) {
484       if (dov[i].OP == op) {
485          Found = YUP;
486          SUMA_LH("found object. Removing it from dov.");
487          if (Free_op) {
488             if (LocalHead) SUMA_S_Err("Freeing object.");
489             if (!SUMA_Free_Displayable_Object (&dov[i])) {
490                SUMA_SLP_Crit("Failed to free displayable object.");
491                SUMA_RETURN(NOPE);
492             }
493          }
494          *N_dov = *N_dov-1;
495          dov[i].OP = dov[*N_dov].OP;
496          dov[i].ObjectType = dov[*N_dov].ObjectType;
497          dov[i].CoordType = dov[*N_dov].CoordType;
498       }
499    }
500 
501    if (LocalHead) {
502       SUMA_LH("At exit, %d objects", *N_dov);
503       for (i=0; i<*N_dov; ++i) {
504          fprintf(SUMA_STDERR,"%d: Label %s Type %s\n",
505                   i, ADO_LABEL((SUMA_ALL_DO*)dov[i].OP),
506                   ADO_TNAME((SUMA_ALL_DO*)dov[i].OP));
507       }
508    }
509 
510    if (Found) {
511       State=YUP;
512       /* Refresh all things indexing dov */
513       if (!SUMA_AllSV_RegisteredDO_Refresh()) {
514          SUMA_S_Err("Failed to refresh all registDO vectors");
515          State=NOPE;
516       }
517       if (!SUMA_AllViewState_MembsRefresh()) {
518          SUMA_S_Err("Failed to refresh all viewstate hist vectors");
519          State=NOPE;
520       }
521       SUMA_RETURN(State);
522    } else {
523       SUMA_RETURN(NOPE);
524    }
525 }
526 
527 /*
528    A function that must be called each time order of objects in
529    SUMAg_DOv is disturbed
530 */
SUMA_SV_RegisteredDO_Refresh(SUMA_SurfaceViewer * sv)531 SUMA_Boolean SUMA_SV_RegisteredDO_Refresh(SUMA_SurfaceViewer *sv)
532 {
533    static char FuncName[]={"SUMA_SV_RegisteredDO_Refresh"};
534    int ii=0, found = -1;
535    SUMA_Boolean LocalHead = NOPE;
536    SUMA_ENTRY;
537 
538    if (!sv) SUMA_RETURN(NOPE);
539 
540    ii = 0;
541    while (ii < sv->N_DO) {
542       if ( sv->RegistDO &&
543           (found = SUMA_whichDOg(sv->RegistDO[ii].idcode_str)) >= 0) {
544          /* A good thing, refresh index mapping */
545          sv->RegistDO[ii].dov_ind = found;
546       } else {
547          SUMA_LH("A bad entry in RegistDO at index %d/%d, cleaning",
548                      ii, sv->N_DO);
549          if (ii != sv->N_DO-1) {
550             strcpy(sv->RegistDO[ii].idcode_str,
551                 sv->RegistDO[sv->N_DO-1].idcode_str);
552          }
553          sv->RegistDO[ii].dov_ind = sv->RegistDO[sv->N_DO-1].dov_ind;
554          sv->N_DO = sv->N_DO-1;
555       }
556       ++ii;
557    }
558 
559    SUMA_RETURN(YUP);
560 }
561 
SUMA_AllSV_RegisteredDO_Refresh(void)562 SUMA_Boolean SUMA_AllSV_RegisteredDO_Refresh(void)
563 {
564    static char FuncName[]={"SUMA_AllSV_RegisteredDO_Refresh"};
565    int i;
566    SUMA_Boolean state = YUP;
567 
568    SUMA_ENTRY;
569 
570    state = YUP;
571    for (i=0; i<SUMAg_N_SVv; ++i) {
572       if ((SUMAg_SVv+i) &&
573           !SUMA_SV_RegisteredDO_Refresh(SUMAg_SVv+i)) state = NOPE;
574    }
575 
576    SUMA_RETURN(state);
577 }
578 
SUMA_FindFirst_dov_ind(SUMA_DO_LOCATOR * x0,SUMA_DO_LOCATOR * x1,int val)579 int SUMA_FindFirst_dov_ind (SUMA_DO_LOCATOR *x0, SUMA_DO_LOCATOR *x1, int val)
580 {/*SUMA_FindFirst_dov_ind*/
581    SUMA_DO_LOCATOR *xi=x0;
582    while(x0<x1) if ((*x0).dov_ind==val) return((int)(x0-xi)); else ++x0;
583    return(-1);
584 }
585 
586 /*!
587 Register a DO with surface viewer RegisteredDO vector
588 if dov_id is present in cSV, nothing is done
589 if not found then dov_id is registered at the end of cSV->RegisteredDO
590 
591 When a DO is registered, a ColorList is created if the DO is a surface object.
592 and N_DO is updated
593 */
SUMA_RegisterDO(int dov_id,SUMA_SurfaceViewer * cSVu)594 SUMA_Boolean SUMA_RegisterDO(int dov_id, SUMA_SurfaceViewer *cSVu)
595 {
596    static char FuncName[]={"SUMA_RegisterDO"};
597    int i, is, icsvmin=0, icsvmax=0, icsv=0;
598    char *sid=NULL;
599    SUMA_SurfaceViewer *cSV=NULL;
600    SUMA_Boolean LocalHead = NOPE;
601 
602    SUMA_ENTRY;
603 
604    if (LocalHead) {
605       SUMA_DUMP_TRACE("at RegisterDO");
606    }
607 
608    if (dov_id < 0) {
609       SUMA_S_Err("A negative dov_id!");
610       SUMA_DUMP_TRACE("Negative dov_id bro? What gives?");
611       SUMA_RETURN(NOPE);
612    }
613 
614    if (!cSVu) { /* Do this for all viewers */
615       SUMA_LHv("Working all %d svs (%d open X-realized)\n",
616                SUMA_MAX_SURF_VIEWERS, SUMAg_N_SVv);
617       icsvmin = 0; icsvmax=SUMAg_N_SVv;
618    } else {
619       icsvmin = SUMA_WhichSV(cSVu, SUMAg_SVv, SUMA_MAX_SURF_VIEWERS);
620       if (icsvmin >=0) icsvmax = icsvmin+1;
621       else {
622          SUMA_DUMP_TRACE("No SV???");
623          SUMA_S_Err("Could not find sv!");
624          SUMA_RETURN(NOPE);
625       }
626       SUMA_LHv("Working from sv %d to %d\n", icsvmin, icsvmax);
627    }
628 
629    icsv = icsvmin;
630    while (icsv < icsvmax) {
631       cSV = &(SUMAg_SVv[icsv]);
632       SUMA_LH("Process for viewer %d, %p, [%c]", icsv, cSV, 65+icsv);
633       #if 0
634       if (LocalHead) {
635          /* scan for trouble */
636          for (i=0; i<cSV->N_DO; ++i) {
637             if (cSV->RegistDO[i].dov_ind < 0) {
638                SUMA_DUMP_TRACE("What the what?");
639                exit(1);
640             }
641          }
642       }
643       #endif
644 
645       if (LocalHead &&
646           SUMA_WhichSV(cSV, SUMAg_SVv, SUMA_MAX_SURF_VIEWERS) != 0) {
647          fprintf(SUMA_STDERR,"%s: Muted for viewer %p [%c]\n",
648               FuncName, cSV,
649               65+SUMA_WhichSV(cSV, SUMAg_SVv, SUMA_MAX_SURF_VIEWERS) );
650          /* turn off the LocalHead, too much output*/
651          LocalHead = NOPE;
652       }
653 
654 
655       switch (iDO_type(dov_id)) {
656          case SO_type: /* add it regardless. This may need revisiting if you
657                           begin to load surfaces interactively, not from
658                           the initial startup */
659             /* check to see if dov_id exists */
660 
661             if (SUMA_FindFirst_dov_ind(cSV->RegistDO,
662                                          cSV->RegistDO+cSV->N_DO,
663                                          dov_id) >= 0) { // found, do nothing
664                goto NEXT_CSV;
665             }
666 
667             // Not yet registered so add it
668             cSV->RegistDO[cSV->N_DO].dov_ind = dov_id;
669             sid = iDO_idcode(dov_id);
670             strcpy(cSV->RegistDO[cSV->N_DO].idcode_str,sid);
671             cSV->N_DO += 1;
672 
673             // Now add the ColorList, if DO is a surface object
674             if (SUMA_isSO(SUMAg_DOv[dov_id])) {
675                if (LocalHead)
676                   fprintf (SUMA_STDERR,"%s: Adding color list...\n", FuncName);
677                // add the ColorList
678                if (!SUMA_FillColorList (cSV,
679                               (SUMA_ALL_DO *)SUMAg_DOv[dov_id].OP)) {
680                   fprintf(SUMA_STDERR,
681                           "Error %s: Failed in SUMA_FillColorList.\n", FuncName);
682                   SUMA_RETURN (NOPE);
683                }
684             }
685             SUMA_LHv("Back from SUMA_FillColorList. (%s/%d).\n",
686                    cSV->ColList[0]->idcode_str, cSV->N_ColList);
687 
688             break;
689          case GRAPH_LINK_type:
690             {
691             SUMA_GraphLinkDO *GLDO=(SUMA_GraphLinkDO *)(SUMAg_DOv[dov_id].OP);
692             SUMA_LHv("With GLDO %s, variant %s, Anat Correctedness %s\n",
693                      DO_label(GLDO), GLDO->variant,
694                      SUMA_isDO_AnatCorrect(&(SUMAg_DOv[dov_id]))?"YES":"NO");
695             if (SUMA_isDO_AnatCorrect(&(SUMAg_DOv[dov_id]))) {
696                if (SUMA_FirstGoodAnatCorrState(cSV) < 0) {
697                                             /* have nothing yet, add one */
698                   SUMA_LH("Not one anatomical state to be found for sv %p [%c],"
699                           " adding one", cSV,
700                           SUMA_WhichSVc(cSV, SUMAg_SVv, SUMA_MAX_SURF_VIEWERS));
701                   if (SUMA_Which_iDO_State(dov_id, cSV, 1) < 0) {
702                      SUMA_S_Err("State could not be added!!!");
703                      SUMA_RETURN (NOPE);
704                   }
705                }
706 
707                /* Register it also in all states of VSv that are AnatCorrect */
708                for (is=0; is < cSV->N_VSv; ++is) {
709                   if (cSV->VSv[is].AnatCorrect &&
710                      SUMA_FindFirst_dov_ind(cSV->VSv[is].MembDO,
711                                   cSV->VSv[is].MembDO+cSV->VSv[is].N_MembDO,
712                                   dov_id) < 0) {
713                      cSV->VSv[is].N_MembDO += 1;
714                      cSV->VSv[is].MembDO =
715                         (SUMA_DO_LOCATOR *)SUMA_realloc(cSV->VSv[is].MembDO,
716                               cSV->VSv[is].N_MembDO*sizeof(SUMA_DO_LOCATOR));
717                      cSV->VSv[is].MembDO[cSV->VSv[is].N_MembDO-1].dov_ind =
718                                                                         dov_id;
719                      sid = iDO_idcode(dov_id);
720                      strcpy(
721                         cSV->VSv[is].MembDO[cSV->VSv[is].N_MembDO-1].idcode_str,
722                         sid);
723                   }
724                }
725                /* if the current state is anatomical, register object also
726                   in cSV->RegistDO */
727                if (SUMA_isViewerStateAnatomical(cSV)) {
728                   if (SUMA_FindFirst_dov_ind(cSV->RegistDO,
729                                          cSV->RegistDO+cSV->N_DO,
730                                          dov_id) < 0) {
731                      cSV->RegistDO[cSV->N_DO].dov_ind = dov_id;
732                      sid = iDO_idcode(dov_id);
733                      strcpy(cSV->RegistDO[cSV->N_DO].idcode_str,sid);
734                      cSV->N_DO += 1;
735                   } else {
736                      SUMA_LHv("   GLDO %s, %s already in the bag at"
737                               " cSV->RegisteredDO[%d]\n",
738                                  DO_label(GLDO), GLDO->variant,
739                                  SUMA_FindFirst_dov_ind(cSV->RegistDO,
740                                          cSV->RegistDO+cSV->N_DO,
741                                          dov_id));
742                   }
743                   SUMA_LH("Adding color list (if necessary)...");
744                   /* add the ColorList */
745                   if (!SUMA_FillColorList (cSV,
746                                  (SUMA_ALL_DO *)SUMAg_DOv[dov_id].OP)) {
747                      SUMA_S_Err("Failed in SUMA_FillColorList.");
748                      SUMA_RETURN (NOPE);
749                   }
750 
751                } else {
752                   SUMA_LHv(" Viewer state (%s) not anatomical for GLDO %s, %s\n",
753                            cSV->State, DO_label(GLDO), GLDO->variant);
754                }
755             } else {
756                is = SUMA_Which_iDO_State(dov_id, cSV, 1);
757                /* If we are in the proper state add it to RegisteredDO*/
758                SUMA_LHv("For GLDO  %s\n      State:%s,Group:%s found.\n"
759                         "Comparing to current viewer state of %s\n",
760                         GLDO->Label, SUMA_iDO_state(dov_id),
761                         SUMA_iDO_group(dov_id), cSV->State);
762                if (!strcmp(cSV->State, SUMA_iDO_state(dov_id))) {
763                   if (SUMA_FindFirst_dov_ind(cSV->RegistDO,
764                                       cSV->RegistDO+cSV->N_DO,
765                                       dov_id) < 0) {/* not present, add it */
766                      SUMA_LHv("   GLDO %s, %s has been appended\n",
767                            DO_label(GLDO), GLDO->variant);
768                   cSV->RegistDO[cSV->N_DO].dov_ind = dov_id;
769                   sid = iDO_idcode(dov_id);
770                   strcpy(cSV->RegistDO[cSV->N_DO].idcode_str,sid);
771                   cSV->N_DO += 1;
772                   } else {
773                      SUMA_LHv("   GLDO %s, %s already in the bag at"
774                            " cSV->RegisteredDO[%d]\n",
775                               DO_label(GLDO), GLDO->variant,
776                               SUMA_FindFirst_dov_ind(cSV->RegistDO,
777                                       cSV->RegistDO+cSV->N_DO,
778                                       dov_id));
779                   }
780                   SUMA_LH("Adding color list.");
781                   /* add the ColorList */
782                   if (!SUMA_FillColorList (cSV,
783                                  (SUMA_ALL_DO *)SUMAg_DOv[dov_id].OP)) {
784                      SUMA_S_Err("Failed in SUMA_FillColorList.");
785                      SUMA_RETURN (NOPE);
786                   }
787                }
788             }
789             }
790             break;
791          case MASK_type:
792          case VO_type:
793 	 case CDOM_type:
794          case TRACT_type:
795             {
796 	    SUMA_ALL_DO *ADO=(SUMA_ALL_DO *)(SUMAg_DOv[dov_id].OP);
797             SUMA_LHv("With ADO %s, Anat Correctedness %s\n",
798                      ADO_LABEL(ADO),
799                      SUMA_isDO_AnatCorrect(&(SUMAg_DOv[dov_id]))?"YES":"NO");
800             if (SUMA_isDO_AnatCorrect(&(SUMAg_DOv[dov_id]))) {
801                if (SUMA_FirstGoodAnatCorrState(cSV) < 0) {
802                      SUMA_LH("Not one anatomical state to be found, adding one");
803                   if (SUMA_Which_iDO_State(dov_id, cSV, 1) < 0) {
804                      SUMA_S_Err("State could not be added!!!");
805                      SUMA_RETURN (NOPE);
806                   }
807                }
808                /* Register it also in all states of VSv that are AnatCorrect */
809                for (is=0; is < cSV->N_VSv; ++is) {
810                   if (cSV->VSv[is].AnatCorrect &&
811                      SUMA_FindFirst_dov_ind(cSV->VSv[is].MembDO,
812                                   cSV->VSv[is].MembDO+cSV->VSv[is].N_MembDO,
813                                   dov_id) < 0) {
814                      cSV->VSv[is].N_MembDO += 1;
815                      cSV->VSv[is].MembDO =
816                         (SUMA_DO_LOCATOR *)SUMA_realloc(cSV->VSv[is].MembDO,
817                                  cSV->VSv[is].N_MembDO*sizeof(SUMA_DO_LOCATOR));
818                      cSV->VSv[is].MembDO[cSV->VSv[is].N_MembDO-1].dov_ind =
819                                                                         dov_id;
820                      sid = iDO_idcode(dov_id);
821                      strcpy(
822                         cSV->VSv[is].MembDO[cSV->VSv[is].N_MembDO-1].idcode_str,
823                         sid);
824                   }
825                }
826                /* if the current state is anatomical, register object also
827                   in cSV->RegistDO */
828                if (SUMA_isViewerStateAnatomical(cSV)) {
829                   if (SUMA_FindFirst_dov_ind(cSV->RegistDO,
830                                          cSV->RegistDO+cSV->N_DO,
831                                          dov_id) < 0) {
832                      cSV->RegistDO[cSV->N_DO].dov_ind = dov_id;
833                      sid = iDO_idcode(dov_id);
834                      strcpy(cSV->RegistDO[cSV->N_DO].idcode_str,sid);
835                      cSV->N_DO += 1;
836                   } else {
837                      SUMA_LHv("   ADO %s, already in the bag at"
838                               " cSV->RegisteredDO[%d]\n",
839                                  ADO_LABEL(ADO),
840                                  SUMA_FindFirst_dov_ind(cSV->RegistDO,
841                                          cSV->RegistDO+cSV->N_DO,
842                                          dov_id));
843                   }
844                   SUMA_LH("Adding color list for %s (id %s), viewer %p %d [%c]",
845                            iDO_label(dov_id), iDO_idcode(dov_id), cSV,
846                            SUMA_WhichSV(cSV, SUMAg_SVv, SUMA_MAX_SURF_VIEWERS),
847                            SUMA_WhichSVc(cSV, SUMAg_SVv, SUMA_MAX_SURF_VIEWERS));
848                   /* add the ColorList */
849                   if (!SUMA_FillColorList (cSV,
850                                  (SUMA_ALL_DO *)SUMAg_DOv[dov_id].OP)) {
851                      SUMA_S_Err("Failed in SUMA_FillColorList.");
852                      SUMA_RETURN (NOPE);
853                   }
854 
855                } else {
856                   SUMA_LHv(" Viewer state (%s) not anatomical for ADO %s\n",
857                            cSV->State, ADO_LABEL(ADO));
858                }
859             } else {
860                SUMA_S_Err("Tracts are supposed to be anatomically correct\n"
861                           "If this is not an error, you'll need to put in\n"
862                           "a block here that parallels what is not with \n"
863                           "anatomically incorrect GLDOs above.");
864                SUMA_RETURN(NOPE);
865             }
866             }
867             break;
868          default:
869             SUMA_LHv("Just adding DO %s, no states, nothing\n",
870                      iDO_label(dov_id));
871             if (SUMA_FindFirst_dov_ind(cSV->RegistDO,
872                                          cSV->RegistDO+cSV->N_DO,
873                                          dov_id) < 0){
874                /* just add for now */
875                cSV->RegistDO[cSV->N_DO].dov_ind = dov_id;
876                sid = iDO_idcode(dov_id);
877                strcpy(cSV->RegistDO[cSV->N_DO].idcode_str,sid);
878                cSV->N_DO += 1;
879             }
880             break;
881       }
882       if (LocalHead) {
883          fprintf (SUMA_STDERR,"%s: RegisteredDO is now:\n", FuncName);
884          for (i=0; i< cSV->N_DO; ++i) {
885             fprintf(SUMA_STDERR,
886                         "RegisteredDO[%d] = %d , type=%d (%s) label %s\t", i,
887                         cSV->RegistDO[i].dov_ind,
888                         iDO_type(cSV->RegistDO[i].dov_ind),
889         SUMA_ObjectTypeCode2ObjectTypeName(iDO_type(cSV->RegistDO[i].dov_ind)),
890                         iDO_label(cSV->RegistDO[i].dov_ind));
891          }
892          fprintf(SUMA_STDERR,"\n");
893       }
894 
895       /* update the title bar */
896       SUMA_UpdateViewerTitle(cSV);
897 
898       NEXT_CSV:
899       ++icsv;
900    }
901 
902 
903    SUMA_RETURN(YUP);
904 }
905 /*!
906 remove DO with I.D. dov_id from RegisteredDO list of that current viewer
907 removal of dov_id element is done by replacing it with the last entry in RegistDO
908 list. If not found, nothing happens.
909 */
SUMA_UnRegisterDO_idcode(char * idcode_str,SUMA_SurfaceViewer * cSV)910 SUMA_Boolean SUMA_UnRegisterDO_idcode(char *idcode_str, SUMA_SurfaceViewer *cSV)
911 {
912    static char FuncName[]={"SUMA_UnRegisterDO_idcode"};
913    int id = SUMA_FindDOi_byID(SUMAg_DOv, SUMAg_N_DOv, idcode_str), isv;
914    SUMA_Boolean LocalHead = NOPE;
915 
916    SUMA_ENTRY;
917 
918    SUMA_LH("Unregistering %s, iid %d (%s), sv %p",
919             idcode_str, id, iDO_label(id), cSV);
920    if (id >= 0) {
921       if (cSV) {
922          SUMA_RETURN(SUMA_UnRegisterDO(id, cSV));
923       } else {
924          for (isv=0; isv<SUMAg_N_SVv; ++isv) {
925             SUMA_UnRegisterDO(id,SUMAg_SVv+isv);
926          }
927          SUMA_RETURN(YUP);
928       }
929    }
930    SUMA_RETURN(YUP);
931 }
932 
SUMA_UnRegisterDO(int dov_id,SUMA_SurfaceViewer * cSV)933 SUMA_Boolean SUMA_UnRegisterDO(int dov_id, SUMA_SurfaceViewer *cSV)
934 {
935    int i;
936    static char FuncName[]={"SUMA_UnRegisterDO"};
937    SUMA_ALL_DO *ado=NULL;
938    SUMA_Boolean LocalHead = NOPE;
939 
940    SUMA_ENTRY;
941 
942    if (!cSV) SUMA_RETURN(NOPE);
943 
944    if (LocalHead) {
945       fprintf (SUMA_STDERR,"%s: RegistDO begins (target %d -- %s):\n",
946                FuncName, dov_id, ADO_LABEL((SUMA_ALL_DO*)SUMAg_DOv[dov_id].OP));
947       for (i=0; i< cSV->N_DO; ++i) {
948          fprintf(SUMA_STDERR,"RegistDO[%d] = %d in DOv (%s)\n",
949             i, cSV->RegistDO[i].dov_ind,
950             ADO_LABEL((SUMA_ALL_DO*)SUMAg_DOv[cSV->RegistDO[i].dov_ind].OP));
951       }
952       fprintf(SUMA_STDERR,"\n");
953    }
954 
955    /* check to see if dov_id exists */
956    i = 0;
957    while (i < cSV->N_DO) {
958       if (cSV->RegistDO[i].dov_ind == dov_id) {
959          SUMA_LH("Removing %d", dov_id);
960          /* found, replace it by the last in the list */
961          cSV->RegistDO[i].dov_ind = cSV->RegistDO[cSV->N_DO-1].dov_ind;
962          if (i != cSV->N_DO-1) {
963             strcpy(cSV->RegistDO[i].idcode_str,
964                    cSV->RegistDO[cSV->N_DO-1].idcode_str);
965          }
966          /*remove the last element of the list */
967          cSV->RegistDO[cSV->N_DO-1].dov_ind = -1;
968          cSV->RegistDO[cSV->N_DO-1].idcode_str[0]='\0';
969          cSV->N_DO -= 1;
970 
971          /* empty the ColorList for this surface */
972          ado = iDO_ADO(dov_id);
973          switch (ado->do_type) {
974             case SO_type:
975                SUMA_LH("Emptying ColorList ...");
976                if (!SUMA_EmptyColorList (cSV, ADO_ID(ado))) {
977                   SUMA_S_Err("Failed in SUMA_EmptyColorList\n");
978                   SUMA_RETURN(NOPE);
979                }
980                break;
981             case GRAPH_LINK_type: {
982                SUMA_DSET *dset=SUMA_find_GLDO_Dset((SUMA_GraphLinkDO *)ado);
983                if (dset) SUMA_RETURN(SUMA_EmptyColorList(cSV,SDSET_ID(dset)));
984                } break;
985             default:
986                if (!SUMA_EmptyColorList (cSV, ADO_ID(ado))) {
987                   SUMA_S_Err("Failed to empty color list for %s, type %s\n",
988                               ADO_LABEL(ado), ADO_TNAME(ado));
989                   SUMA_RETURN(NOPE);
990                }
991                break;
992          }
993 
994          if (LocalHead) {
995             fprintf (SUMA_STDERR,"%s: RegistDO is now:\n", FuncName);
996             for (i=0; i< cSV->N_DO; ++i) {
997                fprintf(SUMA_STDERR,"RegistDO[%d] = %d in DOv (%s)\n",
998                         i, cSV->RegistDO[i].dov_ind,
999                ADO_LABEL((SUMA_ALL_DO*)SUMAg_DOv[cSV->RegistDO[i].dov_ind].OP));
1000             }
1001             fprintf(SUMA_STDERR,"\n");
1002          }
1003 
1004          /* update the title bar */
1005          SUMA_UpdateViewerTitle(cSV);
1006 
1007 
1008          SUMA_RETURN(YUP);
1009       }
1010       ++i;
1011    }
1012    /* Not found, nothing happens */
1013 
1014    if (LocalHead) {
1015       fprintf (SUMA_STDERR,"%s: Nothing found, registeredDO still:\n", FuncName);
1016       for (i=0; i< cSV->N_DO; ++i) {
1017          fprintf(SUMA_STDERR,"RegistDO[%d] = %d\t", i, cSV->RegistDO[i].dov_ind);
1018       }
1019       fprintf(SUMA_STDERR,"\n");
1020       SUMA_DUMP_TRACE("Why nothing found?");
1021    }
1022 
1023    SUMA_RETURN(YUP);
1024 }
1025 
1026 
SUMA_DOv_Info(SUMA_DO * dov,int N_dov,int detail)1027 char *SUMA_DOv_Info (SUMA_DO *dov, int N_dov, int detail)
1028 {
1029    static char FuncName[]={"SUMA_DOv_Info"};
1030    int i;
1031    SUMA_COL_TYPE ctp;
1032    char *s=NULL, stmp[200];
1033    SUMA_SurfaceObject *so_op=NULL;
1034    SUMA_VolumeObject *vo_op=NULL;
1035    SUMA_CIFTI_DO *co=NULL;
1036    SUMA_STRING *SS=NULL;
1037    SUMA_Boolean LocalHead = NOPE;
1038    SUMA_ENTRY;
1039 
1040    SS = SUMA_StringAppend(NULL, NULL);
1041 
1042    if (dov) {
1043       SS = SUMA_StringAppend_va(SS, "\nDOv contents (%d elements):\n", N_dov);
1044       for (i=0; i < N_dov; ++i) {
1045          switch (dov[i].ObjectType) {
1046             case VO_type:
1047                vo_op = (SUMA_VolumeObject *)dov[i].OP;
1048                SS = SUMA_StringAppend_va(SS,
1049                      "DOv ID: %d\n\tName: %s\n"
1050                      "\tType: %d (%s), Axis Attachment %d\n",
1051                      i,  SUMA_CHECK_NULL_STR(vo_op->Label),
1052                      dov[i].ObjectType,
1053                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1054                      dov[i].CoordType);
1055                break;
1056             case CDOM_type:
1057                co = (SUMA_CIFTI_DO *)dov[i].OP;
1058                SS = SUMA_StringAppend_va(SS,
1059                      "DOv ID: %d\n\tName: %s\n"
1060                      "\tType: %d (%s), Axis Attachment %d\n",
1061                      i,  SUMA_CHECK_NULL_STR(co->Label),
1062                      dov[i].ObjectType,
1063                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1064                      dov[i].CoordType);
1065                break;
1066             case SO_type:
1067                so_op = (SUMA_SurfaceObject *)dov[i].OP;
1068                #if 0
1069                if (so_op->FileType != SUMA_SUREFIT) {
1070                   SS = SUMA_StringAppend_va(SS,
1071                      "DOv ID: %d\n\tName: %s/%s\n"
1072                      "\tType: %d (%s), Axis Attachment %d\n",
1073                      i,  SUMA_CHECK_NULL_STR(so_op->Name.Path),
1074                      SUMA_CHECK_NULL_STR(so_op->Name.FileName),
1075                      dov[i].ObjectType,
1076                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1077                      dov[i].CoordType);
1078                } else {
1079                   SS = SUMA_StringAppend_va(SS,
1080                      "DOv ID: %d\n\tNameCoord: %s/%s\n"
1081                      "\tNameTopo: %s/%s\n\tType: %d (%s), Axis Attachment %d\n",
1082                      i, SUMA_CHECK_NULL_STR(so_op->Name_coord.Path),
1083                      SUMA_CHECK_NULL_STR(so_op->Name_coord.FileName),
1084                      so_op->Name_topo.Path, so_op->Name_topo.FileName,
1085                      dov[i].ObjectType,
1086                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1087                      dov[i].CoordType);
1088                }
1089                #else
1090                   SS = SUMA_StringAppend_va(SS,
1091                      "DOv ID: %d\n\tName: %s\n"
1092                      "\tType: %d (%s), Axis Attachment %d\n",
1093                      i,  SUMA_CHECK_NULL_STR(so_op->Label),
1094                      dov[i].ObjectType,
1095                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1096                      dov[i].CoordType);
1097                #endif
1098                break;
1099             case AO_type:
1100                {
1101                   SUMA_Axis* ao;
1102                   SUMA_LH("HERE\n");
1103                   ao = (SUMA_Axis*) dov[i].OP;
1104                   SS = SUMA_StringAppend_va(SS,
1105                      "DOv ID: %d\n\tAxis Object\n"
1106                      "\tType: %d (%s), Axis Attachment %d\n",
1107                      i,dov[i].ObjectType,
1108                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1109                      dov[i].CoordType);
1110                   SS = SUMA_StringAppend_va(SS,
1111                      "\tName: %s\n\tidcode: %s\n", ao->Label, ao->idcode_str);
1112                }
1113                break;
1114             case OLS_type:
1115                {
1116                   SUMA_SegmentDO *sdo=NULL;
1117 
1118                   sdo = (SUMA_SegmentDO *)dov[i].OP;
1119                   SS = SUMA_StringAppend_va(SS,
1120                      "DOv ID: %d\n\tOriented Line Segment Object\n"
1121                      "\tType: %d (%s), Axis Attachment %d\n",
1122                      i,dov[i].ObjectType,
1123                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1124                      dov[i].CoordType);
1125                   SS = SUMA_StringAppend_va(SS,
1126                      "\tLabel: %s\n\tidcode: %s\n", sdo->Label, sdo->idcode_str);
1127 
1128                }
1129                break;
1130             case DIR_type:
1131                {
1132                   SUMA_SegmentDO *sdo=NULL;
1133 
1134                   sdo = (SUMA_SegmentDO *)dov[i].OP;
1135                   SS = SUMA_StringAppend_va(SS,
1136                      "DOv ID: %d\n\tDirection Object\n"
1137                      "\tType: %d (%s), Axis Attachment %d\n",
1138                      i,dov[i].ObjectType,
1139                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1140                      dov[i].CoordType);
1141                   SS = SUMA_StringAppend_va(SS,
1142                      "\tLabel: %s\n\tidcode: %s\n", sdo->Label, sdo->idcode_str);
1143                }
1144                break;
1145             case ODIR_type:
1146                {
1147                   SUMA_SegmentDO *sdo=NULL;
1148 
1149                   sdo = (SUMA_SegmentDO *)dov[i].OP;
1150                   SS = SUMA_StringAppend_va(SS,
1151                      "DOv ID: %d\n\tOriented Direction Object\n"
1152                      "\tType: %d (%s), Axis Attachment %d\n",
1153                      i,dov[i].ObjectType,
1154                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1155                      dov[i].CoordType);
1156                   SS = SUMA_StringAppend_va(SS,
1157                      "\tLabel: %s\n\tidcode: %s\n", sdo->Label, sdo->idcode_str);
1158 
1159                }
1160                break;
1161             case ONBV_type:
1162                {
1163                   SUMA_SegmentDO *sdo=NULL;
1164 
1165                   sdo = (SUMA_SegmentDO *)dov[i].OP;
1166                   SS = SUMA_StringAppend_va(SS,
1167                      "DOv ID: %d\n\tNode-Based Ball-Vector\n"
1168                      "\tType: %d (%s), Axis Attachment %d\n",
1169                         i,dov[i].ObjectType,
1170                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1171                      dov[i].CoordType);
1172                   SS = SUMA_StringAppend_va(SS,
1173                      "\tLabel: %s\n\tidcode: %s\n", sdo->Label, sdo->idcode_str);
1174 
1175                }
1176                break;
1177             case NBV_type:
1178                {
1179                   SUMA_SegmentDO *sdo=NULL;
1180 
1181                   sdo = (SUMA_SegmentDO *)dov[i].OP;
1182                   SS = SUMA_StringAppend_va(SS,
1183                      "DOv ID: %d\n\tNode-Based Vector\n"
1184                      "\tType: %d (%s), Axis Attachment %d\n",
1185                      i,dov[i].ObjectType,
1186                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1187                      dov[i].CoordType);
1188                   SS = SUMA_StringAppend_va(SS,
1189                      "\tLabel: %s\n\tidcode: %s\n", sdo->Label, sdo->idcode_str);
1190 
1191                }
1192                break;
1193             case LS_type:
1194                {
1195                   SUMA_SegmentDO *sdo=NULL;
1196 
1197                   sdo = (SUMA_SegmentDO *)dov[i].OP;
1198                   SS = SUMA_StringAppend_va(SS,
1199                      "DOv ID: %d\n\tLine Segment Object\n"
1200                      "\tType: %d (%s), Axis Attachment %d\n",
1201                      i,dov[i].ObjectType,
1202                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1203                      dov[i].CoordType);
1204                   SS = SUMA_StringAppend_va(SS,
1205                      "\tLabel: %s\n\tidcode: %s\n", sdo->Label, sdo->idcode_str);
1206 
1207                }
1208                break;
1209             case NBSP_type:
1210                {
1211                   SUMA_SphereDO *sdo=NULL;
1212 
1213                   sdo = (SUMA_SphereDO *)dov[i].OP;
1214                   SS = SUMA_StringAppend_va(SS,
1215                      "DOv ID: %d\n\tNode-Based Sphere Object\n"
1216                      "\tType: %d (%s), Axis Attachment %d\n",
1217                      i,dov[i].ObjectType,
1218                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1219                      dov[i].CoordType);
1220                   SS = SUMA_StringAppend_va(SS,
1221                      "\tLabel: %s\n\tidcode: %s\n", sdo->Label, sdo->idcode_str);
1222 
1223                }
1224                break;
1225             case SP_type:
1226                {
1227                   SUMA_SphereDO *sdo=NULL;
1228 
1229                   sdo = (SUMA_SphereDO *)dov[i].OP;
1230                   SS = SUMA_StringAppend_va(SS,
1231                      "DOv ID: %d\n\tSphere Object\n"
1232                      "\tType: %d (%s), Axis Attachment %d\n",
1233                      i,dov[i].ObjectType,
1234                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1235                      dov[i].CoordType);
1236                   SS = SUMA_StringAppend_va(SS,
1237                      "\tLabel: %s\n\tidcode: %s\n", sdo->Label, sdo->idcode_str);
1238 
1239                }
1240                break;
1241             case PNT_type:
1242                {
1243                   SUMA_SphereDO *sdo=NULL;
1244 
1245                   sdo = (SUMA_SphereDO *)dov[i].OP;
1246                   SS = SUMA_StringAppend_va(SS,
1247                      "DOv ID: %d\n\tPoint Object\n"
1248                      "\tType: %d (%s), Axis Attachment %d\n",
1249                      i,dov[i].ObjectType,
1250                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1251                      dov[i].CoordType);
1252                   SS = SUMA_StringAppend_va(SS,
1253                      "\tLabel: %s\n\tidcode: %s\n", sdo->Label, sdo->idcode_str);
1254 
1255                }
1256                break;
1257             case PL_type:
1258                {
1259                   SUMA_PlaneDO *pdo=NULL;
1260 
1261                   pdo = (SUMA_PlaneDO *)dov[i].OP;
1262                   SS = SUMA_StringAppend_va(SS,
1263                      "DOv ID: %d\n\tPlane Object\n"
1264                      "\tType: %d (%s), Axis Attachment %d\n",
1265                      i,dov[i].ObjectType,
1266                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1267                      dov[i].CoordType);
1268                   SS = SUMA_StringAppend_va(SS,
1269                      "\tLabel: %s\n\tidcode: %s\n", pdo->Label, pdo->idcode_str);
1270 
1271                }
1272                break;
1273             case ROIdO_type:
1274                {
1275                   SUMA_DRAWN_ROI *dROI = NULL;
1276 
1277                   dROI = (SUMA_DRAWN_ROI *)dov[i].OP;
1278                   SS = SUMA_StringAppend_va(SS,
1279                      "DOv ID: %d\n\tLine Segment Object\n"
1280                      "\tType: %d (%s), Axis Attachment %d\n",
1281                      i,dov[i].ObjectType,
1282                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1283                      dov[i].CoordType);
1284                   SS = SUMA_StringAppend_va(SS,
1285                      "\tLabel: %s\n\tidcode: %s\n",
1286                      dROI->Label, dROI->idcode_str);
1287                }
1288                break;
1289             case ROIO_type:
1290                {
1291                   SUMA_ROI *ROI = NULL;
1292 
1293                   ROI = (SUMA_ROI *)dov[i].OP;
1294                   SS = SUMA_StringAppend_va(SS,
1295                      "DOv ID: %d\n\tLine Segment Object\n"
1296                      "\tType: %d (%s), Axis Attachment %d\n",
1297                      i,dov[i].ObjectType,
1298                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1299                      dov[i].CoordType);
1300                   SS = SUMA_StringAppend_va(SS,"\tLabel: %s\n\tidcode: %s\n",
1301                            ROI->Label, ROI->idcode_str);
1302                }
1303                break;
1304             case GO_type:
1305                SS = SUMA_StringAppend_va(SS,"DOv ID: %d\n\tGrid Object\n", i);
1306                break;
1307             case NIDO_type:
1308                SS = SUMA_StringAppend_va(SS,
1309                         "DOv ID: %d\n\tNIDO  Object\n"
1310                         "\tType: %d (%s), Axis Attachment %d\n",
1311                         i,dov[i].ObjectType,
1312                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1313                      dov[i].CoordType);
1314                break;
1315             case GRAPH_LINK_type: {
1316                SUMA_GraphLinkDO *gldo=(SUMA_GraphLinkDO *)dov[i].OP;
1317                SUMA_DSET *dset = SUMA_find_GLDO_Dset(gldo);
1318                SS = SUMA_StringAppend_va(SS,
1319                         "DOv ID: %d\n\tGLDO Label: %s, id: %s%s\n"
1320                         "\tType: %d (%s), Axis Attachment %d, Variant: %s,\n"
1321                         "\tParent:  %s (id %s)\n",
1322                         i, gldo->Label, gldo->idcode_str,
1323                      strcmp(gldo->variant,"TheShadow")?
1324                            "":"(id always same as Parent's)",
1325                      dov[i].ObjectType,
1326                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1327                      dov[i].CoordType,
1328                      gldo->variant, SDSET_LABEL(dset), gldo->Parent_idcode_str);
1329                break; }
1330             case TRACT_type: {
1331                SS = SUMA_StringAppend_va(SS,
1332                         "DOv ID: %d\n\tTract  Object\n"
1333                         "\tType: %d (%s), Axis Attachment %d\n",
1334                         i,dov[i].ObjectType,
1335                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1336                      dov[i].CoordType);
1337                break; }
1338             case MASK_type: {
1339                SS = SUMA_StringAppend_va(SS,
1340                         "DOv ID: %d\tLabel: %s\n\tMask  Object\n"
1341                         "\tType: %d (%s), Axis Attachment %d\n",
1342                         i, ADO_LABEL((SUMA_ALL_DO *)dov[i].OP),
1343                         dov[i].ObjectType,
1344                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType),
1345                      dov[i].CoordType);
1346                break; }
1347             default:
1348                SS = SUMA_StringAppend_va(SS,"DOv ID: %d\n"
1349                                             "\tUnknown Type (%d) %s!\n",
1350                                              i, dov[i].ObjectType,
1351                      SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType)
1352                      );
1353                break;
1354          }
1355       }
1356 
1357    } else {
1358       SS = SUMA_StringAppend(SS, "NULL DO.");
1359    }
1360 
1361    SUMA_SS2S(SS, s);
1362 
1363    SUMA_RETURN(s);
1364 }
1365 
SUMA_TractDOInfo(SUMA_TractDO * tdo,int detail)1366 char *SUMA_TractDOInfo (SUMA_TractDO *tdo, int detail)
1367 {
1368    static char FuncName[]={"SUMA_TractDOInfo"};
1369    int i;
1370    SUMA_COL_TYPE ctp;
1371    char *s=NULL, stmp[200];
1372    SUMA_STRING *SS=NULL;
1373    NI_group *ngr=NULL;
1374 
1375    SUMA_ENTRY;
1376 
1377    SS = SUMA_StringAppend(NULL, NULL);
1378 
1379    if (tdo) {
1380       SS = SUMA_StringAppend_va(SS, "Tract %p\n", tdo);
1381       s = SUMA_Taylor_Network_Info(tdo->net, 2,5);
1382       SS = SUMA_StringAppend(SS,s);
1383       SUMA_ifree(s);
1384    } else {
1385       SS = SUMA_StringAppend(SS, "NULL Tract.");
1386    }
1387 
1388    SUMA_SS2S(SS, s);
1389 
1390    SUMA_RETURN(s);
1391 }
1392 
SUMA_MaskDOInfo(SUMA_MaskDO * mdo,int detail)1393 char *SUMA_MaskDOInfo (SUMA_MaskDO *mdo, int detail)
1394 {
1395    static char FuncName[]={"SUMA_MaskDOInfo"};
1396    int i;
1397    SUMA_COL_TYPE ctp;
1398    char *s=NULL, stmp[200];
1399    SUMA_STRING *SS=NULL;
1400    NI_group *ngr=NULL;
1401 
1402    SUMA_ENTRY;
1403 
1404    SS = SUMA_StringAppend(NULL, NULL);
1405 
1406    if (mdo) {
1407       SS = SUMA_StringAppend_va(SS, "Mask %p\n", mdo);
1408       SS = SUMA_StringAppend(SS,"No info for masks yet.");
1409       SUMA_ifree(s);
1410    } else {
1411       SS = SUMA_StringAppend(SS, "NULL Mask.");
1412    }
1413 
1414    SUMA_SS2S(SS, s);
1415 
1416    SUMA_RETURN(s);
1417 }
1418 
SUMA_VolumeObjectInfo(SUMA_VolumeObject * vo,int detail)1419 char *SUMA_VolumeObjectInfo (SUMA_VolumeObject *vo, int detail)
1420 {
1421    static char FuncName[]={"SUMA_VolumeObjectInfo"};
1422    int i;
1423    SUMA_COL_TYPE ctp;
1424    char *s=NULL, stmp[200];
1425    SUMA_STRING *SS=NULL;
1426    NI_group *ngr=NULL;
1427 
1428    SUMA_ENTRY;
1429 
1430    SS = SUMA_StringAppend(NULL, NULL);
1431 
1432    if (vo) {
1433       SS = SUMA_StringAppend_va(SS, "VolumeObject %p\n", vo);
1434       SS = SUMA_StringAppend(SS,"No info for volumes yet.");
1435       SUMA_ifree(s);
1436    } else {
1437       SS = SUMA_StringAppend(SS, "NULL VO.");
1438    }
1439 
1440    SUMA_SS2S(SS, s);
1441 
1442    SUMA_RETURN(s);
1443 }
1444 
1445 
1446 /*!
1447 print out the data contained in dov
1448 */
SUMA_Show_DOv(SUMA_DO * dov,int N_dov,FILE * Out)1449 void SUMA_Show_DOv (SUMA_DO *dov, int N_dov, FILE *Out)
1450 {
1451    int i;
1452    char *si=NULL;
1453    static char FuncName[]={"SUMA_Show_DOv"};
1454 
1455    SUMA_ENTRY;
1456 
1457    if (Out == NULL) Out = stdout;
1458 
1459    si = SUMA_DOv_Info(dov, N_dov, 0);
1460 
1461    fprintf(Out,"%s\n", si);
1462 
1463    if (si) SUMA_free(si); si = NULL;
1464 
1465    SUMA_RETURNe;
1466 }
1467 
1468 /*!
1469 returns a vector of indices into dov for DO that meet DO_Type
1470 You should free the returned pointer once you're done with it
1471 N contains the number of elements found
1472 */
SUMA_GetDO_Type(SUMA_DO * dov,int N_dov,SUMA_DO_Types DO_Type,int * N)1473 int * SUMA_GetDO_Type(SUMA_DO *dov, int N_dov, SUMA_DO_Types DO_Type, int *N)
1474 {
1475    static char FuncName[]={"SUMA_GetDO_Type"};
1476    int *do_id, i;
1477    SUMA_Boolean LocalHead = NOPE;
1478 
1479    SUMA_ENTRY;
1480 
1481    *N = 0;
1482 
1483    do_id = (int *)SUMA_calloc (SUMA_MAX_DISPLAYABLE_OBJECTS, sizeof(int));
1484 
1485    if (do_id == NULL) {
1486       fprintf(stderr,"Error SUMA_GetDO_Type: Could not allocate for do_id\n");
1487       SUMA_RETURN(NULL);
1488    }
1489       i = 0;
1490       while (i < N_dov) {
1491          if (dov[i].ObjectType == DO_Type) {
1492             do_id[*N] = i;
1493             *N = *N + 1;
1494          }
1495       ++i;
1496       }
1497       SUMA_RETURN(do_id);
1498 }
1499 
1500 /*!
1501    searches all SO_type DO objects for idcode
1502    YUP if found, NOPE if not
1503 */
SUMA_existSO(char * idcode,SUMA_DO * dov,int N_dov)1504 SUMA_Boolean SUMA_existSO(char *idcode, SUMA_DO *dov, int N_dov)
1505 {
1506    static char FuncName[]={"SUMA_existSO"};
1507    SUMA_SurfaceObject *SO;
1508    int i;
1509 
1510    SUMA_ENTRY;
1511 
1512    if (idcode == NULL) {
1513       fprintf(SUMA_STDERR,"Warning SUMA_existSO: NULL idcode.\n");
1514       SUMA_RETURN (NOPE);
1515    }
1516    for (i=0; i< N_dov; ++i) {
1517       if (dov[i].ObjectType == SO_type) {
1518          SO = (SUMA_SurfaceObject *)dov[i].OP;
1519          if (strcmp(idcode, SO->idcode_str)== 0) {
1520             SUMA_RETURN (YUP);
1521          }
1522       }
1523    }
1524    SUMA_RETURN(NOPE);
1525 }
1526 /*!
1527    searches all VO_type DO objects for idcode
1528    YUP if found, NOPE if not
1529 */
SUMA_existVO(char * idcode,SUMA_DO * dov,int N_dov)1530 SUMA_Boolean SUMA_existVO(char *idcode, SUMA_DO *dov, int N_dov)
1531 {
1532    static char FuncName[]={"SUMA_existVO"};
1533    SUMA_VolumeObject *VO;
1534    int i;
1535 
1536    SUMA_ENTRY;
1537 
1538    if (idcode == NULL) {
1539       fprintf(SUMA_STDERR,"Warning SUMA_existVO: NULL idcode.\n");
1540       SUMA_RETURN (NOPE);
1541    }
1542    for (i=0; i< N_dov; ++i) {
1543       if (dov[i].ObjectType == VO_type) {
1544          VO = (SUMA_VolumeObject *)dov[i].OP;
1545          if (strcmp(idcode, VO->idcode_str)== 0) {
1546             SUMA_RETURN (YUP);
1547          }
1548       }
1549    }
1550    SUMA_RETURN(NOPE);
1551 }
1552 
1553 /*!
1554    searches all DO objects with an idcode_str for idcode
1555 
1556    YUP if found, NOPE if not
1557 */
SUMA_existDO(char * idcode,SUMA_DO * dov,int N_dov)1558 SUMA_Boolean SUMA_existDO(char *idcode, SUMA_DO *dov, int N_dov)
1559 {
1560    static char FuncName[]={"SUMA_existDO"};
1561    int i;
1562    SUMA_SurfaceObject *SO = NULL;
1563    SUMA_VolumeObject *VO = NULL;
1564    SUMA_DRAWN_ROI *dROI = NULL;
1565    SUMA_ROI *ROI = NULL;
1566    SUMA_SegmentDO *sdo = NULL;
1567    SUMA_Axis *sax = NULL;
1568    SUMA_SphereDO *spdo=NULL;
1569    SUMA_NIDO *nido=NULL;
1570    SUMA_ENTRY;
1571 
1572    if (idcode == NULL) {
1573       fprintf(SUMA_STDERR,"Warning %s: NULL idcode.\n", FuncName);
1574       SUMA_RETURN (NOPE);
1575    }
1576    for (i=0; i< N_dov; ++i) {
1577       switch (dov[i].ObjectType) {
1578          case (VO_type):
1579             VO = (SUMA_VolumeObject *)dov[i].OP;
1580             if (strcmp(idcode, VO->idcode_str)== 0) {
1581                SUMA_RETURN (YUP);
1582             }
1583             break;
1584          case (SO_type):
1585             SO = (SUMA_SurfaceObject *)dov[i].OP;
1586             if (strcmp(idcode, SO->idcode_str)== 0) {
1587                SUMA_RETURN (YUP);
1588             }
1589             break;
1590          case (ROIdO_type):
1591             dROI = (SUMA_DRAWN_ROI *)dov[i].OP;
1592             if (strcmp(idcode, dROI->idcode_str)== 0) {
1593                SUMA_RETURN (YUP);
1594             }
1595             break;
1596          case (ROIO_type):
1597             ROI = (SUMA_ROI *)dov[i].OP;
1598             if (strcmp(idcode, ROI->idcode_str)== 0) {
1599                SUMA_RETURN (YUP);
1600             }
1601             break;
1602          case (AO_type):
1603             sax = (SUMA_Axis *)dov[i].OP;
1604             if (strcmp(idcode, sax->idcode_str)== 0) {
1605                SUMA_RETURN (YUP);
1606             }
1607             break;
1608          case (SP_type):
1609             spdo = (SUMA_SphereDO *)dov[i].OP;
1610             if (strcmp(idcode, spdo->idcode_str)== 0) {
1611                SUMA_RETURN (YUP);
1612             }
1613             break;
1614          case (OLS_type):
1615          case (LS_type):
1616             sdo = (SUMA_SegmentDO *)dov[i].OP;
1617             if (strcmp(idcode, sdo->idcode_str)== 0) {
1618                SUMA_RETURN (YUP);
1619             }
1620             break;
1621          case (NIDO_type):
1622             nido = (SUMA_NIDO *)dov[i].OP;
1623             if (strcmp(idcode, nido->idcode_str)== 0) {
1624                SUMA_RETURN (i);
1625             }
1626             break;
1627          default:
1628             SUMA_S_Warnv("Object type %d not checked.\n", dov[i].ObjectType);
1629             break;
1630       }
1631    }
1632    SUMA_RETURN(NOPE);
1633 }
1634 
SUMA_DO_dbg_info(char * idcode)1635 char *SUMA_DO_dbg_info(char *idcode)
1636 {
1637    static char FuncName[]={"SUMA_DO_dbg_info"};
1638    static int icall=0;
1639    static char Ret[10][500];
1640    char *s=NULL;
1641    int doid;
1642    SUMA_ALL_DO *ado=NULL;
1643 
1644    SUMA_ENTRY;
1645    ++icall; if (icall > 9) icall = 0;
1646    s = (char *)Ret[icall];
1647    s[0] = '\0';
1648 
1649    if (!idcode) {
1650       snprintf(s,499,"NULL idcode passed");
1651    } else if ( (doid = SUMA_whichDOg(idcode)) < 0) {
1652       snprintf(s,499,"id %s not found in global list.", idcode);
1653    } else {
1654       ado = iDO_ADO(doid);
1655       snprintf(s,499,"id %s: %s %s",
1656                idcode, ADO_LABEL(ado), ADO_TNAME(ado));
1657    }
1658    SUMA_RETURN(s);
1659 }
1660 
1661 /*!
1662    searches for DO object with an idcode_str equal to idcode
1663    It returns the DO's index into dov
1664    -1 if nothing was found
1665 
1666 */
SUMA_whichDO(char * idcode,SUMA_DO * dov,int N_dov)1667 int SUMA_whichDO(char *idcode, SUMA_DO *dov, int N_dov)
1668 {
1669    static char FuncName[]={"SUMA_whichDO"};
1670    int i;
1671    SUMA_VolumeObject *VO = NULL;
1672    SUMA_SurfaceObject *SO = NULL;
1673    SUMA_DRAWN_ROI *dROI = NULL;
1674    SUMA_ROI *ROI = NULL;
1675    SUMA_SegmentDO *sdo = NULL;
1676    SUMA_Axis *sax = NULL;
1677    SUMA_SphereDO *spdo=NULL;
1678    SUMA_NIDO *nido=NULL;
1679    SUMA_GraphLinkDO *gldo =NULL;
1680    SUMA_TractDO *tdo = NULL;
1681    SUMA_MaskDO *mdo=NULL;
1682    SUMA_CIFTI_DO *CO=NULL;
1683    SUMA_Boolean LocalHead=NOPE;
1684 
1685    SUMA_ENTRY;
1686 
1687    if (SUMA_IS_EMPTY_STR_ATTR(idcode)) { /* might come in as ~ at times */
1688       fprintf(SUMA_STDERR,"Warning %s: NULL idcode.\n", FuncName);
1689       if (LocalHead) SUMA_DUMP_TRACE("NUULL id");
1690       SUMA_RETURN (-1);
1691    }
1692    for (i=0; i< N_dov; ++i) {
1693       switch (dov[i].ObjectType) {
1694          case (VO_type):
1695             VO = (SUMA_VolumeObject *)dov[i].OP;
1696             if (strcmp(idcode, VO->idcode_str)== 0) {
1697                SUMA_RETURN (i);
1698             }
1699             break;
1700          case (SO_type):
1701             SO = (SUMA_SurfaceObject *)dov[i].OP;
1702             if (strcmp(idcode, SO->idcode_str)== 0) {
1703                SUMA_RETURN (i);
1704             }
1705             break;
1706          case (ROIdO_type):
1707             dROI = (SUMA_DRAWN_ROI *)dov[i].OP;
1708             if (strcmp(idcode, dROI->idcode_str)== 0) {
1709                SUMA_RETURN (i);
1710             }
1711             break;
1712          case (ROIO_type):
1713             ROI = (SUMA_ROI *)dov[i].OP;
1714             if (strcmp(idcode, ROI->idcode_str)== 0) {
1715                SUMA_RETURN (i);
1716             }
1717             break;
1718          case (AO_type):
1719             sax = (SUMA_Axis *)dov[i].OP;
1720             if (strcmp(idcode, sax->idcode_str)== 0) {
1721                SUMA_RETURN (i);
1722             }
1723             break;
1724          case (SP_type):
1725             spdo = (SUMA_SphereDO *)dov[i].OP;
1726             if (strcmp(idcode, spdo->idcode_str)== 0) {
1727                SUMA_RETURN (i);
1728             }
1729             break;
1730          case (OLS_type):
1731          case (LS_type):
1732             sdo = (SUMA_SegmentDO *)dov[i].OP;
1733             if (strcmp(idcode, sdo->idcode_str)== 0) {
1734                SUMA_RETURN (i);
1735             }
1736             break;
1737          case (NIDO_type):
1738             nido = (SUMA_NIDO *)dov[i].OP;
1739             if (strcmp(idcode, nido->idcode_str)== 0) {
1740                SUMA_RETURN (i);
1741             }
1742             break;
1743          case (GRAPH_LINK_type):
1744             gldo = (SUMA_GraphLinkDO *)dov[i].OP;
1745             if (strcmp(idcode, gldo->idcode_str)== 0) {
1746                SUMA_RETURN (i);
1747             }
1748             break;
1749          case TRACT_type:
1750             tdo = (SUMA_TractDO *)dov[i].OP;
1751             if (strcmp(idcode, tdo->idcode_str)== 0) {
1752                SUMA_RETURN (i);
1753             }
1754             break;
1755          case MASK_type:
1756             mdo = (SUMA_MaskDO *)dov[i].OP;
1757             if (strcmp(idcode, mdo->idcode_str)== 0) {
1758                SUMA_RETURN (i);
1759             }
1760             break;
1761          case CDOM_type:
1762 	    CO = (SUMA_CIFTI_DO *)dov[i].OP;
1763 	    if (strcmp(idcode, CO->idcode_str)== 0) {
1764                SUMA_RETURN (i);
1765             }
1766             break;
1767 	 default:
1768             SUMA_S_Warnv("Object type %d (%s) not checked.\n",
1769                dov[i].ObjectType,
1770                SUMA_ObjectTypeCode2ObjectTypeName(dov[i].ObjectType));
1771             break;
1772       }
1773    }
1774    SUMA_RETURN(-1);
1775 }
1776 
SUMA_whichADO(char * idcode,SUMA_DO * dov,int N_dov)1777 SUMA_ALL_DO* SUMA_whichADO(char *idcode, SUMA_DO *dov, int N_dov)
1778 {
1779    static char FuncName[]={"SUMA_whichADO"};
1780    int ido = SUMA_whichDO(idcode, dov, N_dov);
1781 
1782    if (ido < 0) return(NULL);
1783    return((SUMA_ALL_DO *)dov[ido].OP);
1784 }
1785 
1786 /*!
1787    ans = SUMA_findSO_inDOv(idcode, dov, N_dov);
1788    searches all SO_type DO objects for idcode
1789 
1790    \param idcode (char *) idcode of SO you are searching for
1791    \param dov (SUMA_DO*) pointer to vector of Displayable Objects,
1792                          typically SUMAg_DOv
1793    \param N_dov (int) number of DOs in dov
1794    \return ans (int) index into dov of object with matching idcode
1795        -1 if not found
1796   \sa SUMA_findSOp_inDOv
1797 */
SUMA_findSO_inDOv(char * idcode,SUMA_DO * dov,int N_dov)1798 int SUMA_findSO_inDOv(char *idcode, SUMA_DO *dov, int N_dov)
1799 {
1800    static char FuncName[]={"SUMA_findSO_inDOv"};
1801    SUMA_SurfaceObject *SO;
1802    int i;
1803    SUMA_Boolean LocalHead = NOPE;
1804 
1805    SUMA_ENTRY;
1806 
1807    for (i=0; i<N_dov; ++i) {
1808       if (dov[i].ObjectType == SO_type) {
1809          SO = (SUMA_SurfaceObject *)dov[i].OP;
1810          if (LocalHead)
1811             fprintf (SUMA_STDERR,
1812                      "%s: Comparing \n\t:%s:to\n\t:%s:\n",
1813                      FuncName, idcode, SO->idcode_str);
1814          if (strcmp(idcode, SO->idcode_str)== 0) {
1815             SUMA_RETURN (i);
1816          }
1817       }
1818    }
1819    SUMA_RETURN(-1);
1820 }
1821 /*!
1822    ans = SUMA_findVO_inDOv(idcode, dov, N_dov);
1823    searches all VO_type DO objects for idcode
1824 
1825    \param idcode (char *) idcode of VO you are searching for
1826    \param dov (SUMA_DO*) pointer to vector of Displayable Objects,
1827                          typically SUMAg_DOv
1828    \param N_dov (int) number of DOs in dov
1829    \return ans (int) index into dov of object with matching idcode
1830        -1 if not found
1831   \sa SUMA_findVOp_inDOv
1832 */
SUMA_findVO_inDOv(char * idcode,SUMA_DO * dov,int N_dov)1833 int SUMA_findVO_inDOv(char *idcode, SUMA_DO *dov, int N_dov)
1834 {
1835    static char FuncName[]={"SUMA_findVO_inDOv"};
1836    SUMA_VolumeObject *VO;
1837    int i;
1838    SUMA_Boolean LocalHead = NOPE;
1839 
1840    SUMA_ENTRY;
1841 
1842    for (i=0; i<N_dov; ++i) {
1843       if (dov[i].ObjectType == VO_type) {
1844          VO = (SUMA_VolumeObject *)dov[i].OP;
1845          if (LocalHead)
1846             fprintf (SUMA_STDERR,
1847                      "%s: Comparing \n\t:%s:to\n\t:%s:\n",
1848                      FuncName, idcode, VO->idcode_str);
1849          if (strcmp(idcode, VO->idcode_str)== 0) {
1850             SUMA_RETURN (i);
1851          }
1852       }
1853    }
1854    SUMA_RETURN(-1);
1855 }
1856 
1857 /*!
1858 
1859   SO = SUMA_findSOp_inDOv(char *idcode, SUMA_DO *dov, int N_dov)
1860    searches all SO_type DO objects for idcode
1861 
1862    \param idcode (char *) idcode of SO you are searching for
1863    \param dov (SUMA_DO*) pointer to vector of Displayable Objects,
1864                          typically SUMAg_DOv
1865    \param N_dov (int) number of DOs in dov
1866    \return SO (SUMA_SurfaceObject *) pointer of SO with matching idcode
1867        NULL if not found
1868    \sa SUMA_findSO_inDOv
1869 */
SUMA_findSOp_inDOv(char * idcode,SUMA_DO * dov,int N_dov)1870 SUMA_SurfaceObject * SUMA_findSOp_inDOv(char *idcode, SUMA_DO *dov, int N_dov)
1871 {
1872    static char FuncName[]={"SUMA_findSOp_inDOv"};
1873    SUMA_SurfaceObject *SO;
1874    int i;
1875 
1876    SUMA_ENTRY;
1877 
1878    if (!idcode) SUMA_RETURN(NULL);
1879 
1880    for (i=0; i<N_dov; ++i) {
1881       if (dov[i].ObjectType == SO_type) {
1882          SO = (SUMA_SurfaceObject *)dov[i].OP;
1883          if (strcmp(idcode, SO->idcode_str)== 0) {
1884             SUMA_RETURN (SO);
1885          }
1886       }
1887    }
1888    SUMA_RETURN(NULL);
1889 }
1890 
1891 /*!
1892 
1893   VO = SUMA_findVOp_inDOv(char *idcode, SUMA_DO *dov, int N_dov)
1894    searches all VO_type DO objects for idcode
1895 
1896    \param idcode (char *) idcode of VO you are searching for
1897    \param dov (SUMA_DO*) pointer to vector of Displayable Objects,
1898                          typically SUMAg_DOv
1899    \param N_dov (int) number of DOs in dov
1900    \return VO (SUMA_VolumeObject *) pointer of VO with matching idcode
1901        NULL if not found
1902    \sa SUMA_findVO_inDOv
1903 */
SUMA_findVOp_inDOv(char * idcode,SUMA_DO * dov,int N_dov)1904 SUMA_VolumeObject * SUMA_findVOp_inDOv(char *idcode, SUMA_DO *dov, int N_dov)
1905 {
1906    static char FuncName[]={"SUMA_findVOp_inDOv"};
1907    SUMA_VolumeObject *VO;
1908    int i;
1909 
1910    SUMA_ENTRY;
1911 
1912    if (!idcode) SUMA_RETURN(NULL);
1913 
1914    for (i=0; i<N_dov; ++i) {
1915       if (dov[i].ObjectType == VO_type) {
1916          VO = (SUMA_VolumeObject *)dov[i].OP;
1917          if (strcmp(idcode, VO->idcode_str)== 0) {
1918             SUMA_RETURN (VO);
1919          }
1920       }
1921    }
1922    SUMA_RETURN(NULL);
1923 }
1924 
1925 /*!
1926 
1927   SO = SUMA_FindSOp_inDOv_from_N_Node(
1928                         int N_Node, SUMA_SO_SIDE side,
1929                         int check_unique, int return_parent,
1930                         SUMA_DO *dov, int N_dov)
1931    searches all SO_type DO objects for a surface that best accommodates
1932    a mesh with N_Node node .
1933 
1934    \param N_Node (int) Number of nodes forming the mesh
1935    \param side (SUMA_SO_SIDE) surface must be of the same side as 'side'
1936    \param check_unique (int): if 1, then be sure there is only one match
1937    \param return_parent (int): return local domain parent for that surface
1938    \param dov (SUMA_DO*) pointer to vector of Displayable Objects,
1939                          typically SUMAg_DOv
1940    \param N_dov (int) number of DOs in dov
1941    \return SO (SUMA_SurfaceObject *) pointer of SO with matching criteria
1942 
1943    Search logic:
1944       For each surface found:
1945          if SO->N_Node == N_Node && same side the return
1946 
1947        NULL if not found
1948    \sa SUMA_findSO_inDOv
1949 */
1950 
SUMA_FindSOp_inDOv_from_N_Node(int N_Node,SUMA_SO_SIDE side,int check_unique,int return_parent,SUMA_DO * dov,int N_dov)1951 SUMA_SurfaceObject *SUMA_FindSOp_inDOv_from_N_Node(
1952                         int N_Node, SUMA_SO_SIDE side,
1953                         int check_unique, int return_parent,
1954                         SUMA_DO *dov, int N_dov)
1955 {
1956    static char FuncName[]={"SUMA_FindSOp_inDOv_from_N_Node"};
1957    int nFound=0, i = 0;
1958    SUMA_SurfaceObject *SO=NULL, *tSO=NULL;
1959 
1960    SUMA_ENTRY;
1961 
1962    i=0;
1963    while ((!nFound || check_unique) && i < N_dov) {
1964       if (dov[i].ObjectType == SO_type) {
1965          tSO = (SUMA_SurfaceObject *)dov[i].OP;
1966          if (return_parent &&
1967              !SUMA_isLocalDomainParent(tSO)) { /* Need parent only */
1968             if (!(tSO = SUMA_findSOp_inDOv(
1969                            tSO->LocalDomainParentID, dov, N_dov))) {
1970                goto NEXT;
1971             }
1972          }
1973          if (  tSO != SO /* Happens often if you are picking parents */&&
1974                tSO->N_Node == N_Node) { /* candidate */
1975             if (side == SUMA_RIGHT || side == SUMA_LEFT || side == SUMA_LR) {
1976                if (tSO->Side != side) {
1977                   goto NEXT;
1978                }
1979             }
1980             /* Looks like we made it */
1981             if (!SO) SO = tSO; /* only find the first */
1982             ++nFound;
1983          }
1984       }
1985       NEXT:
1986       ++i;
1987    }
1988 
1989    if (check_unique && nFound > 1) {
1990       if (check_unique > 0) { /* error */
1991          SUMA_SLP_Err("More than 1 SO candidate found");
1992       } else { /* warning */
1993          SUMA_SLP_Warn("More than 1 SO candidate found. Returning first.");
1994       }
1995    }
1996 
1997    SUMA_RETURN(SO);
1998 }
1999 
SUMA_is_ID_4_SO(char * idcode,SUMA_SurfaceObject ** SOp)2000 SUMA_Boolean  SUMA_is_ID_4_SO(char *idcode, SUMA_SurfaceObject **SOp)
2001 {
2002    static char FuncName[]={"SUMA_is_ID_4_SO"};
2003    SUMA_SurfaceObject *SO=NULL;
2004 
2005    SUMA_ENTRY;
2006 
2007    if (SOp) *SOp = NULL;
2008    if (!idcode) SUMA_RETURN(NOPE);
2009 
2010    SO = SUMA_findSOp_inDOv(idcode, SUMAg_DOv, SUMAg_N_DOv);
2011 
2012    if (SO) {
2013       if (SOp) *SOp = SO;
2014       SUMA_RETURN(YUP);
2015    }
2016 
2017    SUMA_RETURN(NOPE);
2018 }
2019 
2020 
2021 /*!
2022    Returns an index into dov of a surface domain parent with the largest
2023    number of nodes
2024 */
SUMA_BiggestLocalDomainParent(SUMA_DO * dov,int N_dov)2025 int SUMA_BiggestLocalDomainParent(SUMA_DO *dov, int N_dov)
2026 {
2027    static char FuncName[]={"SUMA_BiggestLocalDomainParent"};
2028    SUMA_SurfaceObject *SO;
2029    int i, imax = -1, MaxNode=-1;
2030 
2031    SUMA_ENTRY;
2032    MaxNode = -1;
2033    imax = -1;
2034    for (i=0; i<N_dov; ++i) {
2035       if (dov[i].ObjectType == SO_type) {
2036          SO = (SUMA_SurfaceObject *)dov[i].OP;
2037          if (SUMA_isLocalDomainParent(SO)) {
2038             if (SO->N_Node > MaxNode) {
2039                imax = i;
2040                MaxNode= SO->N_Node;
2041             }
2042          }
2043       }
2044    }
2045 
2046    SUMA_RETURN(imax);
2047 }
2048 
SUMA_isSurfaceOfSide(SUMA_SurfaceObject * SO,SUMA_SO_SIDE ss)2049 int SUMA_isSurfaceOfSide(SUMA_SurfaceObject *SO, SUMA_SO_SIDE ss)
2050 {
2051    if (!SO) return(0);
2052    if (SO->Side == ss) return(1);
2053    if (ss == SUMA_NO_SIDE || ss == SUMA_SIDE_ERROR) return(1);
2054    return(0);
2055 }
2056 
SUMA_BiggestLocalDomainParent_Side(SUMA_DO * dov,int N_dov,SUMA_SO_SIDE ss)2057 int SUMA_BiggestLocalDomainParent_Side(SUMA_DO *dov, int N_dov, SUMA_SO_SIDE ss)
2058 {
2059    static char FuncName[]={"SUMA_BiggestLocalDomainParent_Side"};
2060    SUMA_SurfaceObject *SO;
2061    int i, imax = -1, MaxNode=-1;
2062 
2063    SUMA_ENTRY;
2064    MaxNode = -1;
2065    imax = -1;
2066    for (i=0; i<N_dov; ++i) {
2067       if (dov[i].ObjectType == SO_type) {
2068          SO = (SUMA_SurfaceObject *)dov[i].OP;
2069          if (SUMA_isLocalDomainParent(SO) && SUMA_isSurfaceOfSide(SO,ss)) {
2070             if (SO->N_Node > MaxNode) {
2071                imax = i;
2072                MaxNode= SO->N_Node;
2073             }
2074          }
2075       }
2076    }
2077    SUMA_RETURN(imax);
2078 }
2079 
2080 /* Try to find any idcode_str, not complete yet */
SUMA_find_any_object(char * idcode_str,SUMA_DO_Types * do_type)2081 void *SUMA_find_any_object(char *idcode_str, SUMA_DO_Types *do_type)
2082 {
2083    static char FuncName[]={"SUMA_find_any_object"};
2084    int i;
2085    void *PP=NULL;
2086 
2087    SUMA_ENTRY;
2088 
2089    if (!idcode_str) SUMA_RETURN(PP);
2090    if (do_type) *do_type = NOT_SET_type;
2091    if ((PP = SUMA_FindDset_s(idcode_str, SUMAg_CF->DsetList))) {
2092       if (do_type) {
2093          if (SUMA_isGraphDset((SUMA_DSET *)PP)) *do_type = GDSET_type;
2094 	 else if (SUMA_isMD_Dset((SUMA_DSET *)PP)) *do_type = MD_DSET_type;
2095          else *do_type = ANY_DSET_type;
2096       }
2097       SUMA_RETURN(PP);
2098    } else if ((PP = SUMA_findSOp_inDOv (idcode_str, SUMAg_DOv, SUMAg_N_DOv))){
2099       if (do_type) *do_type = SO_type;
2100       SUMA_RETURN(PP);
2101    } else if ((PP = SUMA_findVOp_inDOv (idcode_str, SUMAg_DOv, SUMAg_N_DOv))){
2102       if (do_type) *do_type = VO_type;
2103       SUMA_RETURN(PP);
2104    } else if ((i = SUMA_FindDOi_byID(SUMAg_DOv, SUMAg_N_DOv,idcode_str))>=0) {
2105       PP = (SUMAg_DOv[i].OP);
2106       if (do_type) *do_type = SUMAg_DOv[i].ObjectType;
2107       SUMA_RETURN(PP);
2108    } else {
2109       /* Can still search in overlay planes, ROIs, etc.
2110          But wait until we need them .. */
2111    }
2112 
2113    SUMA_RETURN(NULL);
2114 
2115 }
2116 
SUMA_findanySOp(int * dov_id)2117 SUMA_SurfaceObject * SUMA_findanySOp(int *dov_id) {
2118    return(SUMA_findanySOp_inDOv(SUMAg_DOv, SUMAg_N_DOv, dov_id));
2119 }
SUMA_findanySOp_inDOv(SUMA_DO * dov,int N_dov,int * dov_id)2120 SUMA_SurfaceObject * SUMA_findanySOp_inDOv(SUMA_DO *dov, int N_dov, int *dov_id)
2121 {
2122    static char FuncName[]={"SUMA_findanySOp_inDOv"};
2123    SUMA_SurfaceObject *SO;
2124    int i;
2125 
2126    SUMA_ENTRY;
2127 
2128    if (dov_id) *dov_id = -1;
2129    SO = NULL;
2130    for (i=0; i<N_dov; ++i) {
2131       if (dov[i].ObjectType == SO_type) {
2132          SO = (SUMA_SurfaceObject *)dov[i].OP;
2133          if (dov_id) *dov_id = i;
2134          SUMA_RETURN (SO);
2135       }
2136    }
2137 
2138    SUMA_RETURN(NULL);
2139 }
2140 
SUMA_findanyVOp(int * dov_id)2141 SUMA_VolumeObject * SUMA_findanyVOp(int *dov_id) {
2142    return(SUMA_findanyVOp_inDOv(SUMAg_DOv, SUMAg_N_DOv, dov_id));
2143 }
SUMA_findanyVOp_inDOv(SUMA_DO * dov,int N_dov,int * dov_id)2144 SUMA_VolumeObject * SUMA_findanyVOp_inDOv(SUMA_DO *dov, int N_dov, int *dov_id)
2145 {
2146    static char FuncName[]={"SUMA_findanyVOp_inDOv"};
2147    SUMA_VolumeObject *VO;
2148    int i;
2149 
2150    SUMA_ENTRY;
2151 
2152    if (dov_id) *dov_id = -1;
2153    VO = NULL;
2154    for (i=0; i<N_dov; ++i) {
2155       if (dov[i].ObjectType == VO_type) {
2156          VO = (SUMA_VolumeObject *)dov[i].OP;
2157          if (dov_id) *dov_id = i;
2158          SUMA_RETURN (VO);
2159       }
2160    }
2161 
2162    SUMA_RETURN(NULL);
2163 }
2164 
SUMA_findanyTDOp(int * dov_id)2165 SUMA_TractDO * SUMA_findanyTDOp(int *dov_id) {
2166    return(SUMA_findanyTDOp_inDOv(SUMAg_DOv, SUMAg_N_DOv, dov_id));
2167 }
2168 
SUMA_findanyTDOp_inDOv(SUMA_DO * dov,int N_dov,int * dov_id)2169 SUMA_TractDO * SUMA_findanyTDOp_inDOv(SUMA_DO *dov, int N_dov, int *dov_id)
2170 {
2171    static char FuncName[]={"SUMA_findanyTDOp_inDOv"};
2172    SUMA_TractDO *TDO;
2173    int i;
2174 
2175    SUMA_ENTRY;
2176 
2177    if (dov_id) *dov_id = -1;
2178    TDO = NULL;
2179    for (i=0; i<N_dov; ++i) {
2180       if (dov[i].ObjectType == TRACT_type) {
2181          TDO = (SUMA_TractDO *)dov[i].OP;
2182          if (dov_id) *dov_id = i;
2183          SUMA_RETURN (TDO);
2184       }
2185    }
2186 
2187    SUMA_RETURN(NULL);
2188 }
2189 
SUMA_findanyMDOp(int * dov_id)2190 SUMA_MaskDO * SUMA_findanyMDOp(int *dov_id)
2191 {
2192    return(SUMA_findanyMDOp_inDOv(SUMAg_DOv, SUMAg_N_DOv, dov_id));
2193 }
2194 
SUMA_findanyMDOp_inDOv(SUMA_DO * dov,int N_dov,int * dov_id)2195 SUMA_MaskDO * SUMA_findanyMDOp_inDOv(SUMA_DO *dov, int N_dov, int *dov_id)
2196 {
2197    static char FuncName[]={"SUMA_findanyMDOp_inDOv"};
2198    SUMA_MaskDO *MDO;
2199    int i;
2200 
2201    SUMA_ENTRY;
2202 
2203    if (dov_id) *dov_id = -1;
2204    MDO = NULL;
2205    for (i=0; i<N_dov; ++i) {
2206       if (dov[i].ObjectType == MASK_type) {
2207          MDO = (SUMA_MaskDO *)dov[i].OP;
2208          if (dov_id) *dov_id = i;
2209          SUMA_RETURN (MDO);
2210       }
2211    }
2212 
2213    SUMA_RETURN(NULL);
2214 }
2215 
SUMA_findShadowMDOp_inDOv(SUMA_DO * dov,int N_dov,int * dov_id)2216 SUMA_MaskDO * SUMA_findShadowMDOp_inDOv(SUMA_DO *dov, int N_dov, int *dov_id)
2217 {
2218    static char FuncName[]={"SUMA_findShadowMDOp_inDOv"};
2219    SUMA_MaskDO *MDO;
2220    int i;
2221 
2222    SUMA_ENTRY;
2223 
2224    if (dov_id) *dov_id = -1;
2225    MDO = NULL;
2226    for (i=0; i<N_dov; ++i) {
2227       if (dov[i].ObjectType == MASK_type) {
2228          MDO = (SUMA_MaskDO *)dov[i].OP;
2229          if (MDO_IS_SHADOW(MDO)) {
2230             if (dov_id) *dov_id = i;
2231             SUMA_RETURN (MDO);
2232          }
2233       }
2234    }
2235 
2236    SUMA_RETURN(NULL);
2237 }
2238 
SUMA_find_SOLabel_from_idcode(char * idcode,SUMA_DO * dov,int N_dov)2239 char *SUMA_find_SOLabel_from_idcode (char *idcode, SUMA_DO *dov, int N_dov)
2240 {
2241    static char FuncName[]={"SUMA_find_SOLabel_from_idcode"};
2242    SUMA_SurfaceObject *SO;
2243    int i;
2244 
2245    SUMA_ENTRY;
2246 
2247    if (!idcode) SUMA_RETURN(NULL);
2248 
2249    for (i=0; i<N_dov; ++i) {
2250       if (dov[i].ObjectType == SO_type) {
2251          SO = (SUMA_SurfaceObject *)dov[i].OP;
2252          if (strcmp(idcode, SO->idcode_str)== 0) {
2253             SUMA_RETURN (SO->Label);
2254          }
2255       }
2256    }
2257    SUMA_RETURN(NULL);
2258 }
2259 
SUMA_find_VOLabel_from_idcode(char * idcode,SUMA_DO * dov,int N_dov)2260 char *SUMA_find_VOLabel_from_idcode (char *idcode, SUMA_DO *dov, int N_dov)
2261 {
2262    static char FuncName[]={"SUMA_find_VOLabel_from_idcode"};
2263    SUMA_VolumeObject *VO;
2264    int i;
2265 
2266    SUMA_ENTRY;
2267 
2268    if (!idcode) SUMA_RETURN(NULL);
2269 
2270    for (i=0; i<N_dov; ++i) {
2271       if (dov[i].ObjectType == VO_type) {
2272          VO = (SUMA_VolumeObject *)dov[i].OP;
2273          if (strcmp(idcode, VO->idcode_str)== 0) {
2274             SUMA_RETURN (VO->Label);
2275          }
2276       }
2277    }
2278    SUMA_RETURN(NULL);
2279 }
2280 
SUMA_find_SOidcode_from_label(char * label,SUMA_DO * dov,int N_dov)2281 char *SUMA_find_SOidcode_from_label (char *label, SUMA_DO *dov, int N_dov)
2282 {
2283    static char FuncName[]={"SUMA_find_SOidcode_from_label"};
2284    SUMA_SurfaceObject *SO;
2285    int i;
2286    char *found = NULL;
2287 
2288    SUMA_ENTRY;
2289 
2290    if (!label) SUMA_RETURN(NULL);
2291 
2292    for (i=0; i<N_dov; ++i) {
2293       if (dov[i].ObjectType == SO_type) {
2294          SO = (SUMA_SurfaceObject *)dov[i].OP;
2295          if (strcmp(label, SO->Label)== 0) {
2296             if (!found) { found = SO->idcode_str; }
2297             else {
2298                SUMA_S_Errv("More than one surface with label %s found.\n",
2299                            label);
2300                SUMA_RETURN(NULL);
2301             }
2302          }
2303       }
2304    }
2305 
2306    if (!found) { /* try less stringent search */
2307       for (i=0; i<N_dov; ++i) {
2308          if (dov[i].ObjectType == SO_type) {
2309             SO = (SUMA_SurfaceObject *)dov[i].OP;
2310             if (SUMA_iswordin(SO->Label, label)) {
2311                if (!found) { found = SO->idcode_str; }
2312                else {
2313                   SUMA_S_Errv(
2314                "Found more than one surface with labels patially matching %s.\n"
2315                "For example: surfaces %s, and %s .\n",
2316                               label,
2317                               SUMA_find_SOLabel_from_idcode(found, dov, N_dov),
2318                               SO->Label);
2319                   SUMA_RETURN(NULL);
2320                }
2321             }
2322          }
2323       }
2324    }
2325 
2326    if (!found) { /* even less stringent search */
2327       for (i=0; i<N_dov; ++i) {
2328          if (dov[i].ObjectType == SO_type) {
2329             SO = (SUMA_SurfaceObject *)dov[i].OP;
2330             if (SUMA_iswordin_ci(SO->Label, label)) {
2331                if (!found) { found = SO->idcode_str; }
2332                else {
2333                   SUMA_S_Errv(
2334                "Found more than one surface with labels patially matching %s.\n"
2335                "For example: surfaces %s, and %s .\n",
2336                               label,
2337                               SUMA_find_SOLabel_from_idcode(found, dov, N_dov),
2338                               SO->Label);
2339                   SUMA_RETURN(NULL);
2340                }
2341             }
2342          }
2343       }
2344    }
2345    SUMA_RETURN(found);
2346 }
2347 
SUMA_find_ADOidcode_from_label(char * label,SUMA_DO * dov,int N_dov)2348 char *SUMA_find_ADOidcode_from_label (char *label, SUMA_DO *dov, int N_dov)
2349 {
2350    static char FuncName[]={"SUMA_find_ADOidcode_from_label"};
2351    SUMA_ALL_DO *ADO;
2352    int i;
2353    char *found = NULL;
2354 
2355    SUMA_ENTRY;
2356 
2357    if (!label) SUMA_RETURN(NULL);
2358 
2359    for (i=0; i<N_dov; ++i) {
2360       {
2361          ADO = (SUMA_ALL_DO *)dov[i].OP;
2362          if (strcmp(label, ADO_LABEL(ADO))== 0) {
2363             if (!found) { found = ADO_ID(ADO); }
2364             else {
2365                SUMA_S_Errv("More than one ADO with label %s found.\n",
2366                            label);
2367                SUMA_RETURN(NULL);
2368             }
2369          }
2370       }
2371    }
2372 
2373    if (!found) { /* try less stringent search */
2374       for (i=0; i<N_dov; ++i) {
2375          {
2376             ADO = (SUMA_ALL_DO *)dov[i].OP;
2377             if (SUMA_iswordin(ADO_LABEL(ADO), label)) {
2378                if (!found) { found = ADO_ID(ADO); }
2379                else {
2380                   SUMA_S_Errv(
2381                "Found more than one ADO with labels partially matching %s.\n"
2382                "For example: surfaces %s, and %s .\n",
2383                               label,
2384                               ADO_LABEL(SUMA_whichADO(found, dov, N_dov)),
2385                               ADO_LABEL(ADO));
2386                   SUMA_RETURN(NULL);
2387                }
2388             }
2389          }
2390       }
2391    }
2392 
2393    if (!found) { /* even less stringent search */
2394       for (i=0; i<N_dov; ++i) {
2395          {
2396             ADO = (SUMA_ALL_DO *)dov[i].OP;
2397             if (SUMA_iswordin_ci(ADO_LABEL(ADO), label)) {
2398                if (!found) { found = ADO_ID(ADO); }
2399                else {
2400                   SUMA_S_Errv(
2401                "Found more than one surface with labels patially matching %s.\n"
2402                "For example: surfaces %s, and %s .\n",
2403                               label,
2404                               ADO_LABEL(SUMA_whichADO(found, dov, N_dov)),
2405                               ADO_LABEL(ADO));
2406                   SUMA_RETURN(NULL);
2407                }
2408             }
2409          }
2410       }
2411    }
2412    SUMA_RETURN(found);
2413 }
2414 
SUMA_find_VOidcode_from_label(char * label,SUMA_DO * dov,int N_dov)2415 char *SUMA_find_VOidcode_from_label (char *label, SUMA_DO *dov, int N_dov)
2416 {
2417    static char FuncName[]={"SUMA_find_VOidcode_from_label"};
2418    SUMA_VolumeObject *VO;
2419    int i;
2420    char *found = NULL;
2421 
2422    SUMA_ENTRY;
2423 
2424    if (!label) SUMA_RETURN(NULL);
2425 
2426    for (i=0; i<N_dov; ++i) {
2427       if (dov[i].ObjectType == VO_type) {
2428          VO = (SUMA_VolumeObject *)dov[i].OP;
2429          if (strcmp(label, VO->Label)== 0) {
2430             if (!found) { found = VO->idcode_str; }
2431             else {
2432                SUMA_S_Errv("More than one volume with label %s found.\n",
2433                            label);
2434                SUMA_RETURN(NULL);
2435             }
2436          }
2437       }
2438    }
2439 
2440    if (!found) { /* try less stringent search */
2441       for (i=0; i<N_dov; ++i) {
2442          if (dov[i].ObjectType == VO_type) {
2443             VO = (SUMA_VolumeObject *)dov[i].OP;
2444             if (SUMA_iswordin(VO->Label, label)) {
2445                if (!found) { found = VO->idcode_str; }
2446                else {
2447                   SUMA_S_Errv(
2448                "Found more than one volume with labels patially matching %s.\n"
2449                "For example: volumes %s, and %s .\n",
2450                               label,
2451                               SUMA_find_VOLabel_from_idcode(found, dov, N_dov),
2452                               VO->Label);
2453                   SUMA_RETURN(NULL);
2454                }
2455             }
2456          }
2457       }
2458    }
2459 
2460    if (!found) { /* even less stringent search */
2461       for (i=0; i<N_dov; ++i) {
2462          if (dov[i].ObjectType == VO_type) {
2463             VO = (SUMA_VolumeObject *)dov[i].OP;
2464             if (SUMA_iswordin_ci(VO->Label, label)) {
2465                if (!found) { found = VO->idcode_str; }
2466                else {
2467                   SUMA_S_Errv(
2468                "Found more than one volume with labels patially matching %s.\n"
2469                "For example: volumes %s, and %s .\n",
2470                               label,
2471                               SUMA_find_VOLabel_from_idcode(found, dov, N_dov),
2472                               VO->Label);
2473                   SUMA_RETURN(NULL);
2474                }
2475             }
2476          }
2477       }
2478    }
2479    SUMA_RETURN(found);
2480 }
2481 
2482 /*!
2483 
2484   VO = SUMA_find_named_VOp_inDOv(char *filename, SUMA_DO *dov, int N_dov)
2485    searches all VO_type DO objects constructed from a dset from file filename
2486 
2487    \param filename (char *) filename of VO (as returned by DSET_HEADNAME)
2488    \param dov (SUMA_DO*) pointer to vector of Displayable Objects,
2489                         typically SUMAg_DOv
2490    \param N_dov (int) number of DOs in dov
2491    \return VO (SUMA_VolumeObject *) pointer of VO with matching idcode
2492        NULL if not found
2493    \sa SUMA_findVO_inDOv
2494    \sa SUMA_findVOp_inDOv
2495 */
SUMA_find_named_VOp_inDOv(char * filename,SUMA_DO * dov,int N_dov)2496 SUMA_VolumeObject * SUMA_find_named_VOp_inDOv( char *filename,
2497                                                 SUMA_DO *dov, int N_dov)
2498 {
2499    static char FuncName[]={"SUMA_find_named_VOp_inDOv"};
2500    SUMA_VolumeObject *VO = NULL, *VOf = NULL;
2501    SUMA_STRING *SS=NULL;
2502    char *stmp=NULL, *coordname=NULL;
2503    int i;
2504    SUMA_FileName sf;
2505 
2506    SUMA_ENTRY;
2507 
2508    if (!filename || !dov) SUMA_RETURN(NULL);
2509 
2510 
2511    i=0;
2512    VOf = NULL;
2513    while (i<N_dov) {
2514       if (dov[i].ObjectType == VO_type) {
2515          VO = (SUMA_VolumeObject *)dov[i].OP;
2516          if (VO->VE && VO->VE[0] &&
2517              !strcmp(filename, SUMA_VE_Headname(VO->VE, 0))) {
2518             if (VOf) {
2519                SUMA_S_Errv("Volume name %s\n"
2520                            "is not a unique identifier.\n",
2521                            filename);
2522                SUMA_RETURN(NULL);
2523             }
2524             VOf = VO;
2525          }
2526       }
2527       ++i;
2528    }
2529 
2530    SUMA_RETURN(VOf);
2531 }
2532 
2533 /*!
2534 
2535   SO = SUMA_find_named_SOp_inDOv(char *idcode, SUMA_DO *dov, int N_dov)
2536    searches all SO_type DO objects for idcode
2537 
2538    \param coordname (char *) filename of SO (without path) that you are searching for.
2539    If surface is specified by 2 files, then use the coord file
2540                              name.
2541    \param dov (SUMA_DO*) pointer to vector of Displayable Objects, typically SUMAg_DOv
2542    \param N_dov (int) number of DOs in dov
2543    \return SO (SUMA_SurfaceObject *) pointer of SO with matching idcode
2544        NULL if not found
2545    \sa SUMA_findSO_inDOv
2546    \sa SUMA_findSOp_inDOv
2547 */
SUMA_find_named_SOp_inDOv(char * coordnamei,SUMA_DO * dov,int N_dov)2548 SUMA_SurfaceObject * SUMA_find_named_SOp_inDOv( char *coordnamei,
2549                                                 SUMA_DO *dov, int N_dov)
2550 {
2551    static char FuncName[]={"SUMA_find_named_SOp_inDOv"};
2552    SUMA_SurfaceObject *SO = NULL, *SOf = NULL;
2553    SUMA_STRING *SS=NULL;
2554    char *stmp=NULL, *coordname=NULL;
2555    int i;
2556    SUMA_FileName sf;
2557 
2558    SUMA_ENTRY;
2559 
2560    if (!coordnamei || !dov) SUMA_RETURN(NULL);
2561 
2562    /* remove the path from coordname, to be sure */
2563    sf = SUMA_StripPath(coordnamei);
2564    if (!sf.FileName) SUMA_RETURN(NULL);
2565    else coordname = sf.FileName;
2566 
2567    i=0;
2568    SOf = NULL;
2569    while (i<N_dov) {
2570       if (dov[i].ObjectType == SO_type) {
2571          SO = (SUMA_SurfaceObject *)dov[i].OP;
2572          switch(SO->FileType) {
2573             case SUMA_SUREFIT:
2574             case SUMA_VEC:
2575                if (strstr(SO->Name_coord.FileName, coordname)) {
2576                   if (SOf) {
2577                      SS = SUMA_StringAppend_va(NULL, NULL);
2578                      SS = SUMA_StringAppend_va(SS,
2579                                     "Error %s:\n"
2580                                     "Surface name %s\n"
2581                                     "is not a unique identifier.\n"
2582                                     "Found %s and %s so far.\n"
2583                                     "Be more specific.\n", FuncName,
2584                                     coordname, SOf->Name_coord.FileName,
2585                                     SO->Name_coord.FileName);
2586                      SUMA_SS2S(SS, stmp);
2587                      SUMA_SL_Err("%s",stmp);
2588                      if (stmp) SUMA_free(stmp); stmp = NULL;
2589                      if (sf.FileName) SUMA_free(sf.FileName);
2590                         sf.FileName = NULL;
2591                      if (sf.Path) SUMA_free(sf.Path);
2592                         sf.Path = NULL;
2593                      SUMA_RETURN(NULL);
2594                   }
2595                   SOf = SO;
2596                }
2597                break;
2598             case SUMA_FREE_SURFER:
2599             case SUMA_FREE_SURFER_PATCH:
2600             case SUMA_INVENTOR_GENERIC:
2601             case SUMA_OBJ_MESH:
2602             case SUMA_OPENDX_MESH:
2603             case SUMA_PREDEFINED:
2604             case SUMA_BRAIN_VOYAGER:
2605             case SUMA_BYU:
2606             case SUMA_GIFTI:
2607             case SUMA_MNI_OBJ:
2608             case SUMA_STL:
2609             case SUMA_PLY:
2610                if (strstr(SO->Name.FileName, coordname)) {
2611                   if (SOf) {
2612                      SS = SUMA_StringAppend_va(NULL, NULL);
2613                      SS = SUMA_StringAppend_va(SS,
2614                                     "Error %s:\n"
2615                                     "Surface name %s\n"
2616                                     "is not a unique identifier.\n"
2617                                     "Found %s and %s so far.\n"
2618                                     "Be more specific.\n", FuncName,
2619                                     coordname, SOf->Name_coord.FileName,
2620                                     SO->Name_coord.FileName);
2621                      SUMA_SS2S(SS, stmp);
2622                      SUMA_SL_Err("%s",stmp);
2623                      if (stmp) SUMA_free(stmp); stmp = NULL;
2624                      if (sf.FileName) SUMA_free(sf.FileName);
2625                         sf.FileName = NULL;
2626                      if (sf.Path) SUMA_free(sf.Path);
2627                         sf.Path = NULL;                     SUMA_RETURN(NULL);
2628                   }
2629                   SOf = SO;
2630                }
2631                break;
2632             default:
2633                SUMA_SL_Err("Filetype not supported.");
2634                SUMA_RETURN(NULL);
2635          }
2636       }
2637       ++i;
2638    }
2639 
2640    if (sf.FileName) SUMA_free(sf.FileName);
2641       sf.FileName = NULL;
2642    if (sf.Path) SUMA_free(sf.Path);
2643       sf.Path = NULL;
2644 
2645    SUMA_RETURN(SOf);
2646 }
2647 
2648 /*!
2649    determines if a Surface Object is mappable (ie LocalDomainParentID != NULL)
2650    ans = SUMA_ismappable (SUMA_SurfaceObject *SO)
2651    \param SO (SUMA_SurfaceObject *)
2652    \ret YUP/NOPE
2653 */
SUMA_ismappable(SUMA_SurfaceObject * SO)2654 SUMA_Boolean SUMA_ismappable (SUMA_SurfaceObject *SO)
2655 {
2656    static char FuncName[]={"SUMA_ismappable"};
2657 
2658    SUMA_ENTRY;
2659 
2660    if (SO->LocalDomainParentID != NULL) {
2661       /* SO is mappable */
2662       SUMA_RETURN (YUP);
2663    }
2664 
2665    SUMA_RETURN (NOPE);
2666 
2667 }
2668 
2669 /*!
2670    Left here temporarily for backward compatibility
2671 
2672    use the more appropriately named SUMA_isLocalDomainParent
2673 */
SUMA_isINHmappable(SUMA_SurfaceObject * SO)2674 SUMA_Boolean SUMA_isINHmappable (SUMA_SurfaceObject *SO)
2675 {
2676    static char FuncName[]={"SUMA_isINHmappable"};
2677 
2678    SUMA_ENTRY;
2679 
2680    SUMA_RETURN(SUMA_isLocalDomainParent(SO));
2681 }
2682 
2683 /*!
2684    determines if a Surface Object is a local domain parent (ie LocalDomainParentID == idcode_str)
2685    (used to be called inherently mappable)
2686    ans = SUMA_isLocalDomainParent (SUMA_SurfaceObject *SO)
2687    \param SO (SUMA_SurfaceObject *)
2688    \ret YUP/NOPE
2689 
2690    -- Used to be called SUMA_isINHmappable
2691 */
SUMA_isLocalDomainParent(SUMA_SurfaceObject * SO)2692 SUMA_Boolean SUMA_isLocalDomainParent (SUMA_SurfaceObject *SO)
2693 {
2694    static char FuncName[]={"SUMA_isLocalDomainParent"};
2695 
2696    SUMA_ENTRY;
2697 
2698    if (SO->LocalDomainParentID == NULL) {
2699       SUMA_RETURN (NOPE);
2700    }
2701    if (strcmp(SO->LocalDomainParentID, SO->idcode_str) == 0) {
2702       /* SO is the local domain parent */
2703       SUMA_RETURN (YUP);
2704    }
2705    SUMA_RETURN (NOPE);
2706 }
2707 
2708 
SUMA_isRelated(SUMA_ALL_DO * ado1,SUMA_ALL_DO * ado2,int level)2709 SUMA_Boolean SUMA_isRelated( SUMA_ALL_DO *ado1, SUMA_ALL_DO *ado2 , int level)
2710 {
2711    static char FuncName[]={"SUMA_isRelated"};
2712    char *p1=NULL, *p2=NULL;
2713    SUMA_Boolean LocalHead = NOPE;
2714 
2715    SUMA_ENTRY;
2716 
2717    if (!ado1 || !ado2) SUMA_RETURN(NOPE);
2718 
2719    if (LocalHead) SUMA_DUMP_TRACE("Relatives!");
2720 
2721    if (ado1 == ado2) SUMA_RETURN(YUP);
2722 
2723    switch (ado1->do_type) {
2724       case SO_type:
2725          if (ado1->do_type != ado2->do_type) SUMA_RETURN(NOPE);
2726          SUMA_RETURN(SUMA_isRelated_SO((SUMA_SurfaceObject *)ado1,
2727                                        (SUMA_SurfaceObject *)ado2,level));
2728          break;
2729       case GDSET_type:
2730       case GRAPH_LINK_type:
2731          if (ado2->do_type != GDSET_type && ado2->do_type != GRAPH_LINK_type)
2732                                                          SUMA_RETURN(NOPE);
2733          if ((p1=SUMA_ADO_Parent_idcode(ado1)) &&
2734              (p2=SUMA_ADO_Parent_idcode(ado2)) &&
2735              !strcmp(p1,p2)) {
2736             SUMA_RETURN(YUP);
2737          }
2738          SUMA_RETURN(NOPE);
2739          break;
2740       case CDOM_type:
2741          SUMA_S_Err("Fill me with love. Some day we might have 'isotopic' CIFTI "
2742                     "domains. Let us leave complications alone for now");
2743          SUMA_RETURN(NOPE);
2744          break;
2745       case VO_type:
2746       case TRACT_type:
2747          if (ado2->do_type != ado1->do_type) SUMA_RETURN(NOPE);
2748          if ((p1=SUMA_ADO_Parent_idcode(ado1)) &&
2749              (p2=SUMA_ADO_Parent_idcode(ado2)) &&
2750              !strcmp(p1,p2)) {
2751             SUMA_RETURN(YUP);
2752          } else if (!p1 && !p2 && !strcmp(ADO_ID(ado1),ADO_ID(ado2))) {
2753             SUMA_RETURN(YUP);
2754          }
2755          SUMA_RETURN(NOPE);
2756          break;
2757       case MASK_type:
2758          if (ado2->do_type == ado1->do_type ||
2759              ado2->do_type == TRACT_type) {
2760             SUMA_RETURN(YUP);
2761          }
2762          SUMA_RETURN(NOPE);
2763          break;
2764       default:
2765          SUMA_S_Errv("Not ready to deal with type %s\n",
2766                      SUMA_ObjectTypeCode2ObjectTypeName(ado1->do_type));
2767          SUMA_RETURN(NOPE);
2768    }
2769    SUMA_RETURN(NOPE);
2770 }
2771 
2772 /*!
2773    \brief ans = SUMA_isRelated_SO (SUMA_SurfaceObject *SO1,
2774                                    SUMA_SurfaceObject *SO2, int level);
2775 
2776    returns YUP if SO1 and SO2 are related at level 1 or 2
2777    level 1 means nuclear family (share the same parent)
2778    level 2 means extended family (share a grandparent, ultimately this could be
2779             the grand icosahedron duc
2780             Surfaces must be the of the same hemi side since both hemispheres
2781             can have the same grandparent, use level 3 if you want to go across
2782             hemis.)
2783    level 3 is like level 2 with no care for what side of the brain we're working
2784             with
2785 
2786    For more definitions on relationships:
2787 
2788    \sa SUMA_WhatAreYouToMe
2789 */
SUMA_isRelated_SO(SUMA_SurfaceObject * SO1,SUMA_SurfaceObject * SO2,int level)2790 SUMA_Boolean SUMA_isRelated_SO ( SUMA_SurfaceObject *SO1,
2791                                  SUMA_SurfaceObject *SO2, int level)
2792 {
2793    static char FuncName[]={"SUMA_isRelated_SO"};
2794    SUMA_DOMAIN_KINSHIPS kin;
2795    static int iwarn=0;
2796    SUMA_Boolean LocalHead = NOPE;
2797 
2798    SUMA_ENTRY;
2799 
2800    kin =  SUMA_WhatAreYouToMe (SO1, SO2);
2801    switch (level) {
2802       case 3: /* anything goes */
2803          if (  (kin > SUMA_DOMAINS_NOT_RELATED) ) SUMA_RETURN(YUP);
2804          break;
2805       case 2: /* share an ancestor, but same side */
2806          if (  (kin > SUMA_DOMAINS_NOT_RELATED) ) {
2807                if ( (SO1->Side == SO2->Side) ) {
2808                   SUMA_RETURN(YUP);
2809                } else {
2810                   if (!(iwarn % 25)) {
2811                      SUMA_S_Note( "Surfaces appear related at level 2 "
2812                                "but sides are not the same.\n"                                                   "Kinship level is being ignored.\n"
2813                                "(Message shown intermittenly)\n");
2814                   }
2815                   if ((SO1->Side < SUMA_LR || SO2->Side < SUMA_LR)) {
2816                      SUMA_S_Note("Surface sides are not clearly defined. "
2817                                  "If this is in error, consider adding \n"
2818                                  "Hemisphere = R  (or L or B) in the spec file\n"
2819                                  "to make sure surfaces sides are correctly "
2820                                  "labeled.\n");
2821                   }
2822                   ++iwarn;
2823                }
2824          }
2825          break;
2826       case 1: /* nuclear family only */
2827          if (  (kin > SUMA_DOMAINS_NOT_RELATED) &&
2828                (kin < SUMA_NUCELAR_FAMILY ) ) {
2829                if (SO1->Side == SO2->Side) {
2830                    SUMA_RETURN(YUP);
2831                      /* last condition is not really necessary but it
2832                      don't hoyt...*/
2833                } else {
2834                   SUMA_S_Note( "Surfaces appear related at level 2 "
2835                                "but sides are not the same.\n"                                                   "Kinship level is being ignored.\n");
2836                   if (SO1->Side < SUMA_LR || SO2->Side < SUMA_LR) {
2837                      SUMA_S_Note("Surface sides are not clearly defined. "
2838                                  "If this is in error, consider adding \n"
2839                                  "Hemisphere = R  (or L or B) in the spec file\n"
2840                                  "to make sure surfaces sides are correctly "
2841                                  "labeled.\n");
2842                   }
2843                }
2844          }
2845          break;
2846       default:
2847          SUMA_SL_Err("Bad value for level.");
2848          break;
2849    }
2850    SUMA_RETURN(NOPE);
2851 }
2852 
2853 /*!
2854    \brief finds a contralateral surface to SO that is of the same
2855    Group AND State
2856 */
SUMA_Contralateral_SO(SUMA_SurfaceObject * SO,SUMA_DO * dov,int N_dov)2857 SUMA_SurfaceObject *SUMA_Contralateral_SO(SUMA_SurfaceObject *SO,
2858                                           SUMA_DO *dov, int N_dov)
2859 {
2860    static char FuncName[]={"SUMA_Contralateral_SO"};
2861    SUMA_SurfaceObject *SOC=NULL;
2862    int findside = SUMA_SIDE_ERROR;
2863    int i;
2864    static int iwarn=0;
2865 
2866    SUMA_ENTRY;
2867 
2868    if (!SO) {
2869       SUMA_S_Err("NULL input");
2870       SUMA_RETURN(SOC);
2871    }
2872    if (!SO->Group) {
2873       SUMA_S_Err("Need SO->Group");
2874       SUMA_RETURN(SOC);
2875    }
2876 
2877    if (SO->Side != SUMA_LEFT && SO->Side != SUMA_RIGHT) {
2878       if (SO->Side < SUMA_LR) {
2879          if (!iwarn) {
2880             SUMA_S_Warn("Surface sides are not clearly defined. "
2881                      "If this is in error, consider adding \n"
2882                      "Hemisphere = R  (or L or B) in the spec file\n"
2883                      "to make sure surfaces sides are correctly "
2884                      "labeled.\n"
2885                      "Similar warnings will be muted\n");
2886             ++iwarn;
2887          }
2888       }
2889       SUMA_RETURN(SOC);
2890    }
2891 
2892    if (SO->Side == SUMA_LEFT) findside = SUMA_RIGHT;
2893    else findside = SUMA_LEFT;
2894 
2895    fprintf(stderr, "SUMA_Contralateral_SO: N_dov=%d\n", N_dov);
2896    for (i=0; i<N_dov; ++i) {
2897       fprintf(stderr, "SUMA_Contralateral_SO: (i,SO->Group) =(%d, %s)\n", i, SO->Group);
2898       if (SUMA_isSO_G(dov[i], SO->Group)) {
2899          SOC = (SUMA_SurfaceObject *)dov[i].OP;
2900          if (SOC->Side == findside && !strcmp(SOC->State, SO->State) ) break;
2901          else SOC = NULL;
2902       }
2903    }
2904 
2905    if (SOC && SUMA_isRelated_SO(SOC, SO, 1)) {
2906       SUMA_S_Warn("Unexpected surface pair with same localdomainparent.\n"
2907                   "Good Luck To You");
2908    }
2909    /*
2910       if (SOC) SOC = SUMA_findSOp_inDOv( SOC->LocalDomainParentID,
2911                                       dov, N_dov);
2912    */
2913 
2914 
2915    SUMA_RETURN(SOC);
2916 }
2917 
SUMA_isContralateral_name(char * s1,char * s2)2918 SUMA_Boolean SUMA_isContralateral_name(char *s1, char *s2)
2919 {
2920    static char FuncName[]={"SUMA_isContralateral_name"};
2921    char *sd=NULL, *sc1=NULL, *sc2=NULL;
2922    int ic1, ic2;
2923    SUMA_Boolean LocalHead = NOPE;
2924    SUMA_ENTRY;
2925 
2926    if (s1 && s2 && strstr(s1,"FuncAfni_") && strstr(s2,"FuncAfni_") &&
2927        (sc1 = strstr(s1,TMP_NAME_SEP)) && (sc2 = strstr(s2,TMP_NAME_SEP)) ) {
2928       /* temporarily mask the idcode part */
2929       ic1 = sc1-s1; ic2 = sc2 - s2;
2930       s1[ic1] = '\0';
2931       s2[ic2] = '\0';
2932    }
2933    sd = SUMA_StringDiff(s1,s2);
2934    /* now put things back */
2935    if (sc1 && sc2) {
2936       s1[ic1] = sc1[0];
2937       s2[ic2] = sc2[0];
2938    }
2939    sc1 = sc2 = NULL;
2940 
2941    SUMA_LHv("Diff of \n%s and \n%s is \n%s\n",
2942             CHECK_NULL_STR(s1), CHECK_NULL_STR(s2), CHECK_NULL_STR(sd));
2943 
2944    if (!sd || sd[0] == '\0') SUMA_RETURN(NOPE);
2945 
2946    /* If name is for live dsets from AFNI, make sure you cut after idcode_str */
2947    /* check for l or r only */
2948    if (sd[0] != 'l' && sd[0] != 'L' && sd[0] != 'r' && sd[0] != 'R') {
2949       /* not begginning with l or r */
2950       SUMA_free(sd); SUMA_RETURN(NOPE);
2951    } else if (sd[1] == '\0') { /* make sure it is only l or r */
2952       SUMA_free(sd); SUMA_RETURN(YUP);
2953    }
2954    if (strstr(s1,"GRP_ICORR") && strstr(s2,"GRP_ICORR")) {
2955       /* special treatment */
2956       if (strncasecmp(sd,"left",4) && strncasecmp(sd,"right",5)) {
2957          SUMA_free(sd); SUMA_RETURN(NOPE);
2958       }
2959    } else {
2960       /* not left and not right? */
2961       if (strcasecmp(sd,"left") && strcasecmp(sd,"right")) {
2962          SUMA_free(sd); SUMA_RETURN(NOPE);
2963       }
2964    }
2965    SUMA_free(sd);
2966    SUMA_RETURN(YUP);
2967 }
2968 
SUMA_Contralateral_file(char * f1)2969 char *SUMA_Contralateral_file(char *f1)
2970 {
2971    static char FuncName[]={"SUMA_Contralateral_file"};
2972    char *f1C=NULL, *ff1=NULL;
2973    int ii=0;
2974    THD_string_array *sar=NULL;
2975    SUMA_Boolean LocalHead = NOPE;
2976 
2977    SUMA_ENTRY;
2978 
2979    if (!f1) SUMA_RETURN(f1C);
2980 
2981    if (!(sar=THD_get_all_files(SUMA_FnameGet(f1, "pa", SUMAg_CF->cwd),0))){
2982       SUMA_RETURN(f1C);
2983    }
2984 
2985    ff1 = SUMA_FnameGet(f1, "F", SUMAg_CF->cwd);
2986    for( ii=0 ; ii < sar->num ; ii++ ) {
2987       SUMA_LHv("%s vs\n"
2988                "%s\n", sar->ar[ii], ff1);
2989       if (SUMA_isContralateral_name(sar->ar[ii], ff1)) {
2990          if (!f1C) {
2991             f1C = SUMA_copy_string(sar->ar[ii]);
2992          } else {
2993             /* ambiguous contralateral files names */
2994             SUMA_S_Warnv("Found more than 1 contralateral candidates for %s\n"
2995                          "%s and %s\n",
2996                          ff1, f1C, sar->ar[ii]);
2997             DESTROY_SARR(sar) ; SUMA_free(f1C); f1C = NULL;
2998             SUMA_RETURN(f1C);
2999          }
3000       }
3001    }
3002 
3003    DESTROY_SARR(sar) ; sar = NULL;
3004    if (f1C) {
3005       SUMA_LHv("%s is matched by\n%s\n",
3006             f1C, f1);
3007    } else {
3008       SUMA_LHv("No cigar for %s\n", f1);
3009    }
3010    SUMA_RETURN(f1C);
3011 }
3012 
SUMA_Contralateral_dset(SUMA_DSET * dset,SUMA_SurfaceObject * SO,SUMA_SurfaceObject ** SOCp)3013 SUMA_DSET * SUMA_Contralateral_dset(SUMA_DSET *dset, SUMA_SurfaceObject *SO,
3014                                     SUMA_SurfaceObject**SOCp)
3015 {
3016    static char FuncName[]={"SUMA_Contralateral_dset"};
3017    SUMA_DSET *cdset=NULL, *dd=NULL;
3018    DListElmt *el=NULL;
3019    char *namediff=NULL;
3020    SUMA_SurfaceObject *SOC=NULL;
3021    SUMA_Boolean LocalHead = NOPE;
3022 
3023    SUMA_ENTRY;
3024 
3025    if (!dset) {
3026       SUMA_S_Err("NULL input");
3027       SUMA_RETURN(cdset);
3028    }
3029 
3030    if (!SO) {
3031       if (!(SO =
3032             SUMA_findSOp_inDOv(  SUMA_sdset_idmdom(dset),
3033                                  SUMAg_DOv, SUMAg_N_DOv))){
3034          SUMA_S_Err("Can't find dset's domain parent");
3035          SUMA_RETURN(cdset);
3036       }
3037    }
3038 
3039    if (!(SOC = SUMA_Contralateral_SO(SO, SUMAg_DOv, SUMAg_N_DOv))) {
3040       /* Nothing there, return */
3041       SUMA_RETURN(cdset);
3042    }
3043 
3044    SUMA_LH("Have contralateral surface to consider\n");
3045    el = dlist_head(SUMAg_CF->DsetList);
3046    while (el) {
3047       dd = (SUMA_DSET*)el->data;
3048       if (SUMA_isDsetRelated(dd,SOC)) {
3049          SUMA_LHv("Have Dset %s related to SOC\n", SDSET_LABEL(dd));
3050          /* Does dd relate to dset ? */
3051          if (  SUMA_isContralateral_name(SDSET_FILENAME(dset),
3052                                          SDSET_FILENAME(dd)) &&
3053                SUMA_isSameDsetColTypes(dset, dd) ) {
3054             if (!cdset) {
3055                cdset = dd;
3056             }else {
3057                SUMA_S_Warn("More than one dset matches\n"
3058                            "Returning NULL");
3059                SUMA_RETURN(NULL);
3060             }
3061          }
3062       }
3063       el = dlist_next(el);
3064    }
3065 
3066    if (SOCp) *SOCp=SOC;
3067    SUMA_RETURN(cdset);
3068 }
3069 
SUMA_Contralateral_overlay(SUMA_OVERLAYS * over,SUMA_SurfaceObject * SO,SUMA_SurfaceObject ** SOCp)3070 SUMA_OVERLAYS *SUMA_Contralateral_overlay(SUMA_OVERLAYS *over,
3071                                           SUMA_SurfaceObject *SO,
3072                                     SUMA_SurfaceObject**SOCp)
3073 {
3074    static char FuncName[]={"SUMA_Contralateral_overlay"};
3075    SUMA_DSET *dsetC=NULL, *dset=NULL, *dd=NULL;
3076    DListElmt *el=NULL;
3077    SUMA_OVERLAYS *overC=NULL;
3078    int OverInd = -1;
3079    char *namediff=NULL;
3080    SUMA_SurfaceObject *SOC=NULL;
3081    SUMA_Boolean LocalHead = NOPE;
3082 
3083    SUMA_ENTRY;
3084 
3085    if (!over || !over->dset_link) {
3086       SUMA_S_Errv("NULL input (%p) or NULL dset_link (%p)",
3087                   over, over ? over->dset_link:NULL);
3088       SUMA_RETURN(overC);
3089    }
3090 
3091    dset = over->dset_link;
3092    if (!SO) {
3093       if (!(SO =
3094             SUMA_findSOp_inDOv(  SUMA_sdset_idmdom(dset),
3095                                  SUMAg_DOv, SUMAg_N_DOv))){
3096          SUMA_S_Err("Can't find dset's domain parent");
3097          SUMA_RETURN(overC);
3098       }
3099    }
3100 
3101    if (!(SOC = SUMA_Contralateral_SO(SO, SUMAg_DOv, SUMAg_N_DOv))) {
3102       /* Nothing there, return */
3103       SUMA_RETURN(overC);
3104    }
3105 
3106    SUMA_LH("Have contralateral surface to consider");
3107    el = dlist_head(SUMAg_CF->DsetList);
3108    while (el) {
3109       dd = (SUMA_DSET*)el->data;
3110       if (SUMA_isDsetRelated(dd,SOC)) {
3111          SUMA_LHv("Have Dset %s (filename %s) related to SOC\n",
3112                   SDSET_LABEL(dd), SDSET_FILENAME(dd));
3113          /* Does dd relate to dset ? */
3114          if (  SUMA_isContralateral_name(SDSET_FILENAME(dset),
3115                                           SDSET_FILENAME(dd)) &&
3116                SUMA_isSameDsetColTypes(dset, dd) ) {
3117             if (!dsetC) {
3118                dsetC = dd;
3119             }else {
3120                SUMA_S_Warn("More than one dset matches\n"
3121                            "Returning NULL");
3122                SUMA_RETURN(NULL);
3123             }
3124          }
3125       }
3126       el = dlist_next(el);
3127    }
3128    if (!dsetC) {
3129       SUMA_LH("Quest failed, returning");
3130       SUMA_RETURN(overC);
3131    }
3132    if (!(overC=SUMA_Fetch_OverlayPointerByDset ((SUMA_ALL_DO *)SOC,
3133                                                 dsetC, &OverInd))) {
3134       SUMA_S_Err("Failed oh failed to find overlay for contralateral dset");            SUMA_RETURN(NULL);
3135    }
3136 
3137    if (!SUMA_isADO_Cont_Realized((SUMA_ALL_DO *)SOC)) {
3138       if (!(SUMA_OpenCloseSurfaceCont(NULL, (SUMA_ALL_DO *)SOC, NULL))) {
3139          SUMA_S_Err("Could not ensure controller is ready");
3140          SOC = NULL; overC=NULL;
3141       }
3142    }
3143    if (SOCp) *SOCp=SOC;
3144    SUMA_RETURN(overC);
3145 }
3146 
3147 /*!
3148    \brief ans = SUMA_WhatAreYouToMe (SUMA_SurfaceObject *SO1, SUMA_SurfaceObject *SO2);
3149    returns a code for the kinship between two surfaces:
3150 
3151    SO1->idcode_str = SO2->idcode_str (in this case SO1 = SO2) or
3152    SO1->LocalDomainParentID = SO2->idcode_str (SO2 is the mapping reference of SO1) or
3153    SO1->idcode_str = SO2->LocalDomainParentID (SO1 is the mapping reference of SO2)
3154    SO1->LocalDomainParentID = SO2->LocalDomainParentID (SO1 and SO2 have the same mapping reference) or
3155    SO1->DomainGrandParentID = SO2->idcode_str (SO2 is the granddaddy of SO1) or
3156    SO1->idcode_str = SO2->DomainGrandParentID (SO1 is the granddaddy of SO2) or
3157    SO1->DomainGrandParentID = SO2->DomainGrandParentID (SO1 and SO2 have the same granddaddy)
3158 
3159    \sa definition of SUMA_DOMAIN_KINSHIPS and
3160    \sa SUMA_DomainKinships_String
3161 */
SUMA_WhatAreYouToMe(SUMA_SurfaceObject * SO1,SUMA_SurfaceObject * SO2)3162 SUMA_DOMAIN_KINSHIPS SUMA_WhatAreYouToMe (SUMA_SurfaceObject *SO1,
3163                                           SUMA_SurfaceObject *SO2)
3164 {
3165    static char FuncName[]={"SUMA_WhatAreYouToMe"};
3166    SUMA_Boolean LocalHead = NOPE;
3167 
3168    SUMA_ENTRY;
3169 
3170    if (!SO1 && !SO2) {
3171       SUMA_S_Err("Total NULLness");
3172       SUMA_RETURN (SUMA_DOMAINS_NOT_RELATED);
3173    }
3174 
3175    if (!SO1 || !SO2) {
3176       SUMA_LH("One NULL SO"); /* Don't die, it is ok */
3177       SUMA_RETURN (SUMA_DOMAINS_NOT_RELATED);
3178    }
3179 
3180    if (!SO1->idcode_str || !SO2->idcode_str) {
3181       SUMA_S_Err("NULL SO->idcode_str.");
3182       if (LocalHead) SUMA_DUMP_TRACE("Strange init");
3183       SUMA_RETURN (SUMA_DOMAINS_NOT_RELATED);
3184    }
3185 
3186    if (SO1 == SO2 ||
3187        strcmp (SO1->idcode_str, SO2->idcode_str) == 0) {
3188       /* SO1 = SO2 */
3189       SUMA_LH("%s",SUMA_DomainKinships_String (SUMA_SO1_is_SO2));
3190       SUMA_RETURN (SUMA_SO1_is_SO2);
3191    }
3192 
3193    if (SO1->LocalDomainParentID) {
3194       if (strcmp (SO1->LocalDomainParentID, SO2->idcode_str) == 0) {
3195          /* SO2 is the local domain parent of SO1 */
3196          SUMA_LH("%s",SUMA_DomainKinships_String (SUMA_SO2_is_LDPSO1));
3197          SUMA_RETURN (SUMA_SO2_is_LDPSO1);
3198       }
3199    }
3200 
3201    if (SO2->LocalDomainParentID) {
3202       if (strcmp (SO1->idcode_str, SO2->LocalDomainParentID) == 0) {
3203           /* SO1 is the local domain parent of SO2 */
3204           SUMA_LH("%s",SUMA_DomainKinships_String (SUMA_SO1_is_LDPSO2));
3205           SUMA_RETURN (SUMA_SO1_is_LDPSO2);
3206       }
3207    }
3208 
3209    if (SO1->LocalDomainParentID && SO2->LocalDomainParentID) {
3210       if (strcmp (SO1->LocalDomainParentID, SO2->LocalDomainParentID) == 0) {
3211          /* SO1 and SO2 have the same local domain parent */
3212          SUMA_LH("%s",SUMA_DomainKinships_String (SUMA_LDPSO1_is_LDPSO2));
3213          SUMA_RETURN (SUMA_LDPSO1_is_LDPSO2);
3214       }
3215    }
3216 
3217    if (SO1->DomainGrandParentID && SO2->idcode_str) {
3218       if (strcmp (SO1->DomainGrandParentID, SO2->idcode_str) == 0) {
3219          /* SO2 is the grand daddy of SO1 */
3220          SUMA_LH("%s",SUMA_DomainKinships_String (SUMA_SO2_is_GPSO1));
3221          SUMA_RETURN (SUMA_SO2_is_GPSO1);
3222       }
3223    }
3224 
3225    if (SO1->idcode_str && SO2->DomainGrandParentID) {
3226       if (strcmp (SO1->idcode_str, SO2->DomainGrandParentID) == 0) {
3227          /* SO1 is the grand daddy of SO2 */
3228          SUMA_LH("%s",SUMA_DomainKinships_String (SUMA_SO1_is_GPSO2));
3229          SUMA_RETURN (SUMA_SO1_is_GPSO2);
3230       }
3231    }
3232 
3233    if (SO1->DomainGrandParentID && SO2->DomainGrandParentID) {
3234       if (strcmp (SO1->DomainGrandParentID, SO2->DomainGrandParentID) == 0) {
3235          /* SO1 and SO2 have the same grand daddy */
3236          SUMA_LH("%s", SUMA_DomainKinships_String (SUMA_GPSO1_is_GPSO2));
3237          SUMA_RETURN (SUMA_GPSO1_is_GPSO2);
3238       }
3239    }
3240    if (SO1->N_Node == SO2->N_Node) {
3241       SUMA_LH("%s", SUMA_DomainKinships_String (SUMA_N_NODE_SAME));
3242       SUMA_RETURN (SUMA_N_NODE_SAME);
3243    }
3244 
3245    SUMA_LH("%s", SUMA_DomainKinships_String (SUMA_DOMAINS_NOT_RELATED));
3246    SUMA_RETURN (SUMA_DOMAINS_NOT_RELATED);
3247 
3248 }
3249 
3250 /*!
3251    \brief SUMA_Boolean SUMA_isSO_G (SUMA_DO DO, char *Group)
3252    returns YUP if DO is a surface object
3253    and is a part of the group Group
3254 
3255    \sa SUMA_isSO
3256 */
SUMA_isSO_G(SUMA_DO DO,char * Group)3257 SUMA_Boolean SUMA_isSO_G (SUMA_DO DO, char *Group)
3258 {
3259    static char FuncName[]={"SUMA_isSO_G"};
3260    SUMA_SurfaceObject *SO = NULL;
3261 
3262    SUMA_ENTRY;
3263 
3264    if (!Group) {
3265       SUMA_SL_Err("Null Group");
3266       SUMA_RETURN(NOPE);
3267    }
3268 
3269    if (SUMA_isSO(DO)) {
3270       SO = (SUMA_SurfaceObject *)DO.OP;
3271      if (!SO->Group) {
3272          SUMA_SL_Err("Surface has no group, imbecile");
3273          SUMA_RETURN(NOPE);
3274       }
3275       if (strcmp(SO->Group, Group)) { SUMA_RETURN(NOPE); }
3276       else { SUMA_RETURN(YUP); }
3277   }
3278 
3279    SUMA_RETURN(NOPE);
3280 }
3281 /*!
3282    \brief SUMA_Boolean SUMA_isSO (SUMA_DO DO)
3283    returns YUP if DO is of SO_type
3284    ans = SUMA_isSO (DO) ;
3285 
3286    \sa SUMA_isSO_G (SUMA_DO DO, char *Group)
3287 */
SUMA_isSO(SUMA_DO DO)3288 SUMA_Boolean SUMA_isSO (SUMA_DO DO)
3289 {
3290    static char FuncName[]={"SUMA_isSO"};
3291 
3292    SUMA_ENTRY;
3293 
3294    if (DO.ObjectType == SO_type) {
3295       SUMA_RETURN (YUP);
3296    }
3297    SUMA_RETURN (NOPE);
3298 }
3299 
3300 /*!
3301    \brief SUMA_Boolean SUMA_isVO (SUMA_DO DO)
3302    returns YUP if DO is of VO_type
3303    ans = SUMA_isVO (DO) ;
3304 
3305    \sa SUMA_isVO_G (SUMA_DO DO, char *Group)
3306 */
SUMA_isVO(SUMA_DO DO)3307 SUMA_Boolean SUMA_isVO (SUMA_DO DO)
3308 {
3309    static char FuncName[]={"SUMA_isVO"};
3310 
3311    SUMA_ENTRY;
3312 
3313    if (DO.ObjectType == VO_type) {
3314       SUMA_RETURN (YUP);
3315    }
3316    SUMA_RETURN (NOPE);
3317 }
3318 
3319 /*!
3320    \brief Returns a list of the ROIs loaded into dov.
3321 
3322    \param dov (SUMA_DO *) pointer to vector of DOs
3323    \param N_dov (int) number of DOs in dov
3324    \param SortByLabel (SUMA_Boolean) if YUP then returned strings are sorted by their ROI's labels
3325             (The parents must be part of dov). If Nope then strings are sorted by the labels of
3326              the ROI's parent.
3327    \return clist (SUMA_ASSEMBLE_LIST_STRUCT *) pointer to structure containing results
3328 
3329    \sa SUMA_FreeAssembleListStruct
3330    \sa SUMA_CreateAssembleListStruct
3331 
3332 */
SUMA_AssembleAllROIList(SUMA_DO * dov,int N_dov,SUMA_Boolean SortByLabel)3333 SUMA_ASSEMBLE_LIST_STRUCT * SUMA_AssembleAllROIList (SUMA_DO * dov, int N_dov,
3334                                                       SUMA_Boolean SortByLabel)
3335 {
3336    static char FuncName[]={"SUMA_AssembleAllROIList"};
3337    int i=-1, N_clist=-1;
3338    DList *list=NULL, *listop = NULL;
3339    DListElmt *Elm = NULL, *Elmop = NULL;
3340    char Label[SUMA_MAX_NAME_LENGTH],
3341         Parent_Label[SUMA_MAX_NAME_LENGTH], *store=NULL;
3342    SUMA_SurfaceObject *SO = NULL;
3343    char **clist=NULL;
3344    void **oplist=NULL;
3345    SUMA_DRAWN_ROI *ROI=NULL;
3346    SUMA_ASSEMBLE_LIST_STRUCT *clist_str = NULL;
3347    SUMA_Boolean Found = NOPE;
3348    SUMA_Boolean LocalHead = NOPE;
3349 
3350    SUMA_ENTRY;
3351 
3352    list = (DList *)SUMA_malloc(sizeof(DList));
3353    listop = (DList *)SUMA_malloc(sizeof(DList));
3354 
3355    clist = NULL;
3356    N_clist = -1;
3357 
3358    dlist_init(list, NULL);
3359    dlist_init(listop, NULL);
3360    for (i=0; i < N_dov; ++i) {
3361       if (dov[i].ObjectType == ROIdO_type) {
3362          ROI = (SUMA_DRAWN_ROI *)dov[i].OP;
3363          if (LocalHead)
3364             fprintf (SUMA_STDERR, "%s: Found an ROI %s\n", FuncName, ROI->Label);
3365          if (!ROI->Label) sprintf (Label,"NULL");
3366          else sprintf (Label,"%s", ROI->Label);
3367          if (!ROI->Parent_idcode_str) sprintf (Parent_Label,"NULL");
3368          else {
3369             SO = SUMA_findSOp_inDOv(ROI->Parent_idcode_str, dov, N_dov);
3370             if (!SO) sprintf (Parent_Label,"Unknown");
3371             else if (!SO->Label) sprintf (Parent_Label,"Empty");
3372             else sprintf (Parent_Label,"%s", SO->Label);
3373          }
3374          /* Now allocate space for that label */
3375          store = (char *)SUMA_calloc(strlen(Label)+strlen(Parent_Label)+5,
3376                                        sizeof(char));
3377          if (SortByLabel) {
3378             sprintf(store,"%s:%s", Label, Parent_Label);
3379          } else  {
3380             sprintf(store,"%s:%s", Parent_Label, Label);
3381          }
3382 
3383          /* now place it in the list by aplhpabetical order */
3384          if (!list->size) {
3385             dlist_ins_next(list, dlist_tail(list), (void*)store);
3386             dlist_ins_next(listop, dlist_tail(listop), (void*)ROI);
3387          }else { /* must sort first */
3388             Elm = NULL;
3389             Elmop = NULL;
3390             do {
3391                Found = NOPE;
3392                if (!Elm) {
3393                   Elm = dlist_head(list);
3394                   Elmop = dlist_head(listop);
3395                } else {
3396                   Elm = dlist_next(Elm);
3397                   Elmop = dlist_next(Elmop);
3398                }
3399 
3400                if (strcmp(store, (char*)Elm->data) <= 0) {
3401                   dlist_ins_prev(list, Elm, (void *)store);
3402                   dlist_ins_prev(listop, Elmop, (void *)ROI);
3403                   Found = YUP;
3404                } else if (Elm == dlist_tail(list)) {
3405                   /* reached the end, append */
3406                   dlist_ins_next(list, Elm, (void *)store);
3407                   dlist_ins_next(listop, Elmop, (void *)ROI);
3408                   Found = YUP;
3409                }
3410             } while (!Found);
3411          }
3412 
3413       }
3414    }
3415 
3416    if (!list->size) { /* Nothing found */
3417       N_clist = 0;
3418 
3419    }else {
3420 
3421       Elm = NULL;
3422       Elmop = NULL;
3423       clist = (char **)SUMA_calloc(list->size, sizeof(char *));
3424       oplist = (void **)SUMA_calloc(list->size, sizeof(void*));
3425       for (i=0; i< list->size; ++i) {
3426          if (!Elm) {
3427             Elm = dlist_head(list);
3428             Elmop = dlist_head(listop);
3429          } else {
3430             Elm = dlist_next(Elm);
3431             Elmop = dlist_next(Elmop);
3432          }
3433          clist[i] = (char*)Elm->data;
3434          oplist[i] = Elmop->data;
3435       }
3436 
3437       N_clist = list->size;
3438       /* destroy list */
3439       dlist_destroy(list);SUMA_free(list);
3440       dlist_destroy(listop);SUMA_free(listop);
3441 
3442 
3443    }
3444 
3445    clist_str = SUMA_CreateAssembleListStruct();
3446    clist_str->clist = clist;
3447    clist_str->oplist = oplist;
3448    clist_str->N_clist = N_clist;
3449 
3450    /* return */
3451    SUMA_RETURN (clist_str);
3452 }
3453 
3454 /*!
3455    \brief Creates an SUMA_ASSEMBLE_LIST_STRUCT *structure
3456    \sa SUMA_FreeAssembleListStruct
3457 */
SUMA_CreateAssembleListStruct(void)3458 SUMA_ASSEMBLE_LIST_STRUCT *SUMA_CreateAssembleListStruct(void)
3459 {
3460    static char FuncName[]={"SUMA_CreateAssembleListStruct"};
3461    SUMA_ASSEMBLE_LIST_STRUCT *str=NULL;
3462 
3463    SUMA_ENTRY;
3464 
3465    str = (SUMA_ASSEMBLE_LIST_STRUCT *)SUMA_malloc(sizeof(SUMA_ASSEMBLE_LIST_STRUCT));
3466    str->clist = NULL;
3467    str->N_clist = -1;
3468    str->oplist = NULL;
3469    str->content_id = NULL;
3470    SUMA_RETURN(str);
3471 }
3472 /*!
3473    \brief frees SUMA_ASSEMBLE_LIST_STRUCT *
3474    \param SUMA_ASSEMBLE_LIST_STRUCT *str
3475 
3476    \return NULL always
3477 
3478    -This function frees each string in clist. BUT NOT pointers in oplist (for obvious reasons)
3479 */
SUMA_FreeAssembleListStruct(SUMA_ASSEMBLE_LIST_STRUCT * str)3480 SUMA_ASSEMBLE_LIST_STRUCT *SUMA_FreeAssembleListStruct(
3481                                                 SUMA_ASSEMBLE_LIST_STRUCT *str)
3482 {
3483    static char FuncName[]={"SUMA_FreeAssembleListStruct"};
3484    int i;
3485 
3486    SUMA_ENTRY;
3487 
3488    if (!str) SUMA_RETURN(NULL);
3489 
3490    if (str->clist) {
3491       for (i=0; i < str->N_clist; ++i)
3492          if (str->clist[i]) SUMA_free(str->clist[i]);
3493       SUMA_free(str->clist);
3494    }
3495    if (str->oplist) SUMA_free(str->oplist);
3496    if (str->content_id) SUMA_free(str->content_id);
3497 
3498    SUMA_free(str);
3499 
3500    SUMA_RETURN(NULL);
3501 }
3502 
3503 
3504 /*!
3505 \brief Returns an ROI that is related to SO and is in InCreation (being actively drawn) DrawStatus
3506  There should only be one ROI in creation at any one time for a group of related surfaces.
3507 
3508  ROI = SUMA_
3509  ROI_InCreation (SO,  dov,  N_dov);
3510 
3511  \param SO (SUMA_SurfaceObject *) pointer to surface object
3512  \param dov (SUMA_DO *) pointer to vector of DOs (typically SUMAg_DOv)
3513  \param N_dov (int) number of elements in dov
3514  \return ROI (SUMA_DRAWN_ROI *) pointer to ROI object, NULL if no such object is found.
3515 
3516 */
SUMA_FetchROI_InCreation(SUMA_SurfaceObject * SO,SUMA_DO * dov,int N_dov)3517 SUMA_DRAWN_ROI * SUMA_FetchROI_InCreation (SUMA_SurfaceObject *SO,
3518                                            SUMA_DO * dov, int N_dov)
3519 {
3520    int i;
3521    SUMA_DRAWN_ROI *ROI = NULL;
3522    static char FuncName[]={"SUMA_FetchROI_InCreation"};
3523 
3524    SUMA_ENTRY;
3525 
3526    for (i=0; i < N_dov; ++i) {
3527       if (dov[i].ObjectType == ROIdO_type) {
3528          ROI = (SUMA_DRAWN_ROI *)dov[i].OP;
3529          if (ROI->DrawStatus == SUMA_ROI_InCreation) {
3530             if (SUMA_isdROIrelated (ROI, (SUMA_ALL_DO *)SO)) {
3531                /* found an ROI, should be the only one, return */
3532                SUMA_RETURN (ROI);
3533             }
3534          }
3535       }
3536    }
3537    SUMA_RETURN (NULL);
3538 }
3539 
3540 /*!
3541 \brief Returns YUP if the surface: NBV(or NBSP)->Parent_idcode_str is the same as SO->idcode_str.
3542 NOPE otherwise
3543 
3544 ans = SUMA_isNBDOrelated (NBDO, SO);
3545 
3546 \param NBV (SUMA_NB_DO * ) pointer to NBV/NBSP object
3547 \param SO (SUMA_SurfaceObject *) pointer to surface object
3548 \return ans (SUMA_Boolean) YUP/NOPE
3549 \sa SUMA_isNIDOrelated
3550 */
SUMA_isNBDOrelated(SUMA_NB_DO * SDO,SUMA_SurfaceObject * SO)3551 SUMA_Boolean SUMA_isNBDOrelated (SUMA_NB_DO *SDO, SUMA_SurfaceObject *SO)
3552 {
3553    static char FuncName[]={"SUMA_isNBDOrelated"};
3554    SUMA_SurfaceObject *SO_NB = NULL;
3555    SUMA_Boolean LocalHead = NOPE;
3556 
3557    SUMA_ENTRY;
3558 
3559    /* Just compare the idcodes, not allowing for kinship yet but
3560       code below could do that */
3561    if (strcmp(SO->idcode_str, SDO->Parent_idcode_str) == 0) {
3562       SUMA_RETURN(YUP);
3563    } else {
3564       SUMA_RETURN(NOPE);
3565    }
3566 
3567    SUMA_LHv(" %s SO->LocalDomainParentID\n"
3568             " %s SDO->Parent_idcode_str\n"
3569             " %s SO->idcode_str\n",
3570       SO->LocalDomainParentID, SDO->Parent_idcode_str, SO->idcode_str);
3571 
3572    /* find the pointer to the surface having for an idcode_str:
3573          ROI->Parent_idcode_str */
3574    SO_NB = SUMA_findSOp_inDOv(SDO->Parent_idcode_str, SUMAg_DOv, SUMAg_N_DOv);
3575 
3576    if (!SO_NB) {
3577       SUMA_SL_Err("Could not find surface of SDO->Parent_idcode_str");
3578       SUMA_RETURN (NOPE);
3579    }
3580 
3581    if (SUMA_isRelated_SO(SO, SO_NB, 1)){ /* relationship of the 1st order only */
3582       SUMA_RETURN (YUP);
3583    }
3584 
3585    /* If you get here, you have SO_NB so return happily */
3586    SUMA_RETURN (NOPE);
3587 }
3588 
SUMA_isNIDO_SurfBased(SUMA_NIDO * nido)3589 SUMA_Boolean SUMA_isNIDO_SurfBased(SUMA_NIDO *nido)
3590 {
3591    static char FuncName[]={"SUMA_isNIDO_SurfBased"};
3592    char *atr=NULL;
3593 
3594    SUMA_ENTRY;
3595 
3596    atr = NI_get_attribute(nido->ngr,"bond");
3597    if (!atr) SUMA_RETURN(NOPE);
3598 
3599    if (atr[0] == 's') SUMA_RETURN(YUP);
3600 
3601    SUMA_RETURN(NOPE);
3602 }
3603 
3604 /*!
3605    If you make changes here, look into  SUMA_isNBDOrelated
3606    */
SUMA_isNIDOrelated(SUMA_NIDO * SDO,SUMA_SurfaceObject * SO)3607 SUMA_Boolean SUMA_isNIDOrelated (SUMA_NIDO *SDO, SUMA_SurfaceObject *SO)
3608 {
3609    static char FuncName[]={"SUMA_isNIDOrelated"};
3610    SUMA_SurfaceObject *SO_NB = NULL;
3611    char *Parent_idcode_str=NULL;
3612    SUMA_Boolean LocalHead = NOPE;
3613 
3614    SUMA_ENTRY;
3615 
3616    /* Just compare the idcodes, not allowing
3617    for kinship yet but code below could do that */
3618    if ((Parent_idcode_str = NI_get_attribute(SDO->ngr, "Parent_idcode_str")) &&
3619        strcmp(SO->idcode_str, Parent_idcode_str) == 0) {
3620       SUMA_RETURN(YUP);
3621    } else {
3622       SUMA_RETURN(NOPE);
3623    }
3624 
3625    SUMA_LHv(" %s SO->LocalDomainParentID\n"
3626             " %s SDO->Parent_idcode_str\n"
3627             "  %s SO->idcode_str\n",
3628             SO->LocalDomainParentID, Parent_idcode_str, SO->idcode_str);
3629 
3630    /* find the pointer to the surface having for an idcode_str:
3631       ROI->Parent_idcode_str */
3632    SO_NB = SUMA_findSOp_inDOv(Parent_idcode_str, SUMAg_DOv, SUMAg_N_DOv);
3633 
3634    if (!SO_NB) {
3635       SUMA_SL_Err("Could not find surface of SDO->Parent_idcode_str");
3636       SUMA_RETURN (NOPE);
3637    }
3638 
3639    if (SUMA_isRelated_SO(SO, SO_NB, 1)){ /*relationship of the 1st order only */
3640       SUMA_RETURN (YUP);
3641    }
3642 
3643    /* If you get here, you have SO_NB so return happily */
3644    SUMA_RETURN (NOPE);
3645 }
3646 
3647 
3648 
3649 /*!
3650 \brief Returns YUP if the surface: dROI->Parent_idcode_str is related to SO->idcode_str or SO->LocalDomainParentID.
3651 NOPE otherwise
3652 
3653 ans = SUMA_isdROIrelated (dROI, SO);
3654 
3655 \param ROI (SUMA_DRAWN_ROI *) pointer to drawn ROI
3656 \param SO (SUMA_SurfaceObject *) pointer to surface object
3657 \return ans (SUMA_Boolean) YUP/NOPE
3658 
3659 */
SUMA_isdROIrelated(SUMA_DRAWN_ROI * ROI,SUMA_ALL_DO * ado)3660 SUMA_Boolean SUMA_isdROIrelated (SUMA_DRAWN_ROI *ROI, SUMA_ALL_DO *ado)
3661 {
3662    static char FuncName[]={"SUMA_isdROIrelated"};
3663    SUMA_SurfaceObject *SO_ROI = NULL;
3664    SUMA_Boolean LocalHead = NOPE;
3665 
3666    SUMA_ENTRY;
3667 
3668    if (!ado || !ROI) {
3669       SUMA_S_Err("NULL input");
3670       SUMA_RETURN(NOPE);
3671    }
3672    switch (ado->do_type) {
3673       case SO_type: {
3674          SUMA_SurfaceObject *SO = (SUMA_SurfaceObject *)ado;
3675          if (LocalHead) {
3676             fprintf (SUMA_STDERR,
3677                      "%s: %s SO->LocalDomainParentID\n",
3678                      FuncName, SO->LocalDomainParentID);
3679             fprintf (SUMA_STDERR,
3680                      "%s: %s ROI->Parent_idcode_str\n",
3681                      FuncName, ROI->Parent_idcode_str);
3682             fprintf (SUMA_STDERR,
3683                      "%s: %s SO->idcode_str\n",
3684                      FuncName, SO->idcode_str);
3685          }
3686 
3687          /* find the pointer to the surface having for an
3688             idcode_str: ROI->Parent_idcode_str */
3689          SO_ROI = SUMA_findSOp_inDOv(ROI->Parent_idcode_str,
3690                                      SUMAg_DOv, SUMAg_N_DOv);
3691 
3692          if (!SO_ROI) {
3693             SUMA_SL_Err("Could not find surface of ROI->Parent_idcode_str");
3694             SUMA_RETURN(NOPE);
3695          }
3696 
3697          if (SUMA_isRelated_SO(SO, SO_ROI, 1)) {
3698             /* relationship of the 1st order only */
3699             SUMA_RETURN (YUP);
3700          }
3701          break; }
3702       default:
3703          SUMA_S_Errv("Not ready for %s\n",
3704              SUMA_ObjectTypeCode2ObjectTypeName(ado->do_type));
3705          break;
3706    }
3707 
3708    SUMA_RETURN (NOPE);
3709 }
3710 
3711 /*!
3712 \brief Returns YUP if if the surface: ROI->Parent_idcode_str is related to SO->idcode_str or SO->LocalDomainParentID.
3713 NOPE otherwise
3714 
3715 ans = SUMA_isROIrelated (ROI, SO);
3716 
3717 \param ROI (SUMA_ROI *) pointer to ROI
3718 \param SO (SUMA_SurfaceObject *) pointer to surface object
3719 \return ans (SUMA_Boolean) YUP/NOPE
3720 
3721 */
SUMA_isROIrelated(SUMA_ROI * ROI,SUMA_SurfaceObject * SO)3722 SUMA_Boolean SUMA_isROIrelated (SUMA_ROI *ROI, SUMA_SurfaceObject *SO)
3723 {
3724    static char FuncName[]={"SUMA_isROIrelated"};
3725    SUMA_SurfaceObject *SO_ROI = NULL;
3726 
3727    SUMA_ENTRY;
3728 
3729    /* find the pointer to the surface having for an idcode_str:
3730       ROI->Parent_idcode_str */
3731    SO_ROI = SUMA_findSOp_inDOv(ROI->Parent_idcode_str, SUMAg_DOv, SUMAg_N_DOv);
3732 
3733    if (!SO_ROI) {
3734       SUMA_SL_Err("Could not find surface of ROI->Parent_idcode_str");
3735       SUMA_RETURN (NOPE);
3736    }
3737 
3738    if (SUMA_isRelated_SO(SO, SO_ROI, 1)){/* relationship of the 1st order only */
3739       SUMA_RETURN (YUP);
3740    }
3741 
3742    SUMA_RETURN (NOPE);
3743 }
3744 
3745 /*!
3746 \brief Return a mask of the nodes belonging to any ROI of a certain surface
3747    Mask = SUMA_Build_Mask_AllROI (dov, N_dov, SO, Mask, N_added);
3748 
3749 \param dov (SUMA_DO*) pointer to vector of displayable objects to consider
3750 \param N_dov (int) number of elements in dov
3751 \param SO (SUMA_SurfaceObject *)
3752 \param Mask (int *) pointer to mask vector.
3753          0 if node belongs to no ROI
3754          n if node belongs to n ROIs
3755          Pass NULL if you're calling this function for the first time.
3756 \param N_added (int *)integer containing the total number of nodes added to Mask.
3757       That would be the sum of the number of nodes found in all ROIs.
3758       Duplicate nodes are counted twice. If you want the number of nodes without
3759       the duplicates, you need to count non-zero values in Mask.
3760 \return Mask (int *) pointer to modified mask vector.
3761 */
SUMA_Build_Mask_AllROI(SUMA_DO * dov,int N_do,SUMA_SurfaceObject * SO,int * Mask,int * N_added)3762 int * SUMA_Build_Mask_AllROI (SUMA_DO *dov, int N_do, SUMA_SurfaceObject *SO,
3763                               int *Mask, int *N_added)
3764 {
3765    static char FuncName[]={"SUMA_Build_Mask_AllROI"};
3766    int Npart = 0,i;
3767    SUMA_DRAWN_ROI *D_ROI=NULL;
3768    SUMA_ROI *ROI = NULL;
3769    SUMA_Boolean LocalHead = NOPE;
3770 
3771    SUMA_ENTRY;
3772 
3773    *N_added = -1;
3774 
3775    if (!Mask) { /* allocate for it */
3776       Mask = (int *)SUMA_calloc(SO->N_Node, sizeof(int));
3777       if (!Mask) {
3778          SUMA_S_Err ("Failed to allocate for Mask.");
3779          SUMA_RETURN(NULL);
3780       }
3781    }
3782 
3783    for (i=0; i < N_do; ++i) {
3784       switch (dov[i].ObjectType) { /* case Object Type */
3785          case ROIdO_type:
3786             D_ROI = (SUMA_DRAWN_ROI *)dov[i].OP;
3787             if (SUMA_isdROIrelated (D_ROI, (SUMA_ALL_DO *)SO)) {
3788                SUMA_LH("Found a drawn ROI, building mask...");
3789 
3790                Npart = SUMA_Build_Mask_DrawnROI (D_ROI, Mask);
3791                if (Npart < 0) {
3792                   SUMA_S_Err ("Badness in SUMA_Build_Mask_DrawnROI");
3793                   if (Mask) SUMA_free(Mask);
3794                   *N_added = -1;
3795                   SUMA_RETURN(NULL);
3796                }else {
3797                   *N_added = *N_added + Npart;
3798                   SUMA_LHv("%d nodes found in that ROI.\n", Npart);
3799                }
3800             }
3801             break;
3802          case ROIO_type:
3803             ROI = (SUMA_ROI *)dov[i].OP;
3804             if (SUMA_isROIrelated (ROI, SO)) {
3805                SUMA_S_Err ("Not dealing with regular ROIs yet");
3806             }
3807             break;
3808          default:
3809             /* not an ROI */
3810             break;
3811       }
3812    }
3813 
3814    SUMA_RETURN(Mask);
3815 }
3816 
3817 /*!
3818 \brief Return a mask of the nodes belonging to a drawn ROI of a certain surface
3819    N_added = SUMA_Build_Mask_DrawnROI (dROI, Mask);
3820 
3821 \param dROI (SUMA_DRAWN_ROI *) the pointer to the ROI structure
3822 \param Mask (int *) pointer to mask vector.
3823          0 if node belongs to no ROI
3824          n if node belongs to n ROIs
3825       It is the calling function's responsability to make sure enough space is allocated for
3826       Mask and that cleanup is properly handled.
3827 \return N_added (int *)integer containing the number of nodes found in dROI.
3828       This variable is set to -1 when trouble occurs.
3829 */
SUMA_Build_Mask_DrawnROI(SUMA_DRAWN_ROI * D_ROI,int * Mask)3830 int SUMA_Build_Mask_DrawnROI (SUMA_DRAWN_ROI *D_ROI, int *Mask)
3831 {
3832    static char FuncName[]={"SUMA_Build_Mask_DrawnROI"};
3833    DListElmt *NextElm=NULL;
3834    int ii, N_added;
3835    SUMA_ROI_DATUM *ROId=NULL;
3836 
3837    SUMA_ENTRY;
3838 
3839    N_added = -1;
3840 
3841    if (!Mask) {
3842       SUMA_S_Err ("Mask is NULL");
3843       SUMA_RETURN(N_added);
3844    }
3845 
3846    if (!D_ROI->ROIstrokelist) {
3847      N_added = 0;
3848      SUMA_RETURN(N_added);
3849    }
3850 
3851    if (!dlist_size(D_ROI->ROIstrokelist)) {
3852      N_added = 0;
3853      SUMA_RETURN(N_added);
3854    }
3855 
3856    /* start with the first element */
3857    NextElm = NULL;
3858    do {
3859       if (!NextElm) {
3860          NextElm = dlist_head(D_ROI->ROIstrokelist);
3861       }else {
3862          NextElm = dlist_next(NextElm);
3863       }
3864       ROId = (SUMA_ROI_DATUM *)NextElm->data;
3865       if (ROId->N_n) {
3866          for (ii = 0; ii < ROId->N_n; ++ii) {
3867             ++Mask[ROId->nPath[ii]];
3868             ++N_added;
3869          }
3870       }
3871    } while (NextElm != dlist_tail(D_ROI->ROIstrokelist));
3872 
3873    SUMA_RETURN (N_added);
3874 }
3875 
3876 /*!
3877    \brief deletes an ROI from the list of drawn objects
3878 */
SUMA_DeleteROI(SUMA_DRAWN_ROI * ROI)3879 SUMA_Boolean SUMA_DeleteROI (SUMA_DRAWN_ROI *ROI)
3880 {
3881    static char FuncName[]={"SUMA_DeleteROI"};
3882    SUMA_ASSEMBLE_LIST_STRUCT *ALS = NULL;
3883    SUMA_DRAWN_ROI *NextROI=NULL;
3884    int i;
3885    SUMA_Boolean WasCurrent = NOPE, Shaded = NOPE;
3886    SUMA_Boolean LocalHead = NOPE;
3887 
3888    SUMA_ENTRY;
3889 
3890    if (!ROI) {
3891       SUMA_LH("Null ROI");
3892       SUMA_RETURN(YUP);
3893    }
3894 
3895    /* form a list of the current ROI available for editing */
3896 
3897    /* assemble the ROI list */
3898    ALS = SUMA_AssembleAllROIList (SUMAg_DOv, SUMAg_N_DOv, YUP);
3899 
3900    NextROI = NULL;
3901    if (ALS) {
3902       if (ALS->N_clist)  {
3903          i=0;
3904          while (!NextROI && i<ALS->N_clist) {
3905             if (ALS->oplist[i] != (void*)ROI)
3906                NextROI = (SUMA_DRAWN_ROI *)ALS->oplist[i];
3907             ++i;
3908          }
3909       }
3910       SUMA_FreeAssembleListStruct(ALS);
3911    }
3912 
3913    /* check to see if ROI being deleted is current one */
3914    if (ROI == SUMAg_CF->X->DrawROI->curDrawnROI) {
3915       WasCurrent = YUP;
3916    }else {
3917       WasCurrent = NOPE;
3918    }
3919 
3920    /* Close the ROIlist window if it is open */
3921    SUMA_IS_DRAW_ROI_SWITCH_ROI_SHADED(Shaded);
3922    if (!Shaded) {
3923       SUMA_LH("Closing switch ROI window ...");
3924       SUMA_cb_CloseSwitchROI(NULL,
3925                   (XtPointer) SUMAg_CF->X->DrawROI->SwitchROIlst, NULL);
3926    }
3927 
3928    /* remove ROI for SUMAg_DO and clear the ROI structure*/
3929    if (!SUMA_RemoveDO(SUMAg_DOv, &SUMAg_N_DOv, (void *)ROI, YUP)) {
3930       SUMA_SLP_Err("Failed to remove DO from list.");
3931       SUMA_RETURN(NOPE);
3932    }
3933 
3934    if (WasCurrent) {
3935       SUMAg_CF->X->DrawROI->curDrawnROI = NextROI;
3936 
3937       /* reinitialize the draw ROI window */
3938       SUMA_InitializeDrawROIWindow(SUMAg_CF->X->DrawROI->curDrawnROI);
3939    }
3940 
3941    SUMA_RETURN(YUP);
3942 }
3943 
3944 /*!
3945    \brief return  +1 if surface is typically the outer layer surface used in Vol2Surf
3946                   -1 if surface is typically the inner layer surface used in Vol2Surf
3947                    0 if no comment
3948 */
SUMA_isTypicalSOforVolSurf(SUMA_SurfaceObject * SO)3949 int SUMA_isTypicalSOforVolSurf (SUMA_SurfaceObject *SO)
3950 {
3951    static char FuncName[]={"SUMA_isTypicalSOforVolSurf"};
3952 
3953    SUMA_ENTRY;
3954 
3955    switch (SO->FileType) {
3956       case SUMA_STL:
3957       case SUMA_PLY:
3958       case SUMA_VEC:
3959       case SUMA_FREE_SURFER:
3960          if (SUMA_iswordin (SO->Name.FileName, "smoothwm")) SUMA_RETURN(-1);
3961          else if (SUMA_iswordin (SO->Name.FileName, "pial")) SUMA_RETURN(1);
3962          else SUMA_RETURN(0);
3963          break;
3964       default:
3965          SUMA_RETURN(0);
3966          break;
3967    }
3968 
3969    SUMA_RETURN(0);
3970 }
3971 
3972 /*!
3973    \brief Allow users to exclude certain states from being sent
3974    to AFNI
3975    SUMA_ExcludeFromToAfni
3976 */
SUMA_ExcludeFromSendToAfni(SUMA_SurfaceObject * SO)3977 int SUMA_ExcludeFromSendToAfni (SUMA_SurfaceObject *SO)
3978 {
3979    static char FuncName[]={"SUMA_ExcludeFromSendToAfni"};
3980 
3981    SUMA_ENTRY;
3982 
3983    if (SUMA_EnvEquals("SUMA_DoNotSendStates", SO->State, 1, " ,;"))
3984       RETURN(1);
3985 
3986    RETURN(0);
3987 }
3988 
SUMA_Find_XformByID(char * idcode_str)3989 SUMA_XFORM *SUMA_Find_XformByID(char *idcode_str)
3990 {
3991    static char FuncName[]={"SUMA_Find_XformByID"};
3992    SUMA_XFORM *xf = NULL, *xft=NULL;
3993    DListElmt *el=NULL;
3994    DList *lst = SUMAg_CF->xforms;
3995 
3996    SUMA_ENTRY;
3997 
3998    if (!lst || !idcode_str) SUMA_RETURN(xf);
3999 
4000    el = dlist_head(lst);
4001 
4002    while (el && !xf) {
4003       xft = (SUMA_XFORM *)el->data;
4004       if (!strcmp(xft->idcode_str,idcode_str)) {
4005          xf = xft; break;
4006       }
4007       el = dlist_next(el);
4008    }
4009 
4010    SUMA_RETURN(xf);
4011 }
4012 
4013 
4014 /*!
4015    Find a transform with a particular name AND a parent with a matching idcode
4016 */
SUMA_Find_XformByParent(char * name,char * parent_idcode,int * iloc)4017 SUMA_XFORM *SUMA_Find_XformByParent(char *name, char *parent_idcode, int *iloc)
4018 {
4019    static char FuncName[]={"SUMA_Find_XformByParent"};
4020    SUMA_XFORM *xf = NULL, *xft=NULL;
4021    DListElmt *el=NULL;
4022    DList *lst = SUMAg_CF->xforms;
4023    int i;
4024 
4025    SUMA_ENTRY;
4026 
4027    if (!lst || !name || !parent_idcode) SUMA_RETURN(xf);
4028 
4029    el = dlist_head(lst);
4030 
4031    while (el && !xf) {
4032       xft = (SUMA_XFORM *)el->data;
4033       if (!strcmp(xft->name,name)) {
4034          for (i=0; i<xft->N_parents; ++i) {
4035             if (!strcmp(xft->parents[i], parent_idcode)) {
4036                xf = xft;
4037                if (iloc) *iloc = i;
4038                break;
4039             }
4040          }
4041       }
4042       el = dlist_next(el);
4043    }
4044 
4045    SUMA_RETURN(xf);
4046 }
4047 
SUMA_Find_XformByChild(char * name,char * child_idcode,int * iloc)4048 SUMA_XFORM *SUMA_Find_XformByChild(char *name, char *child_idcode, int *iloc)
4049 {
4050    static char FuncName[]={"SUMA_Find_XformByChild"};
4051    SUMA_XFORM *xf = NULL, *xft=NULL;
4052    DListElmt *el=NULL;
4053    DList *lst = SUMAg_CF->xforms;
4054    int i;
4055 
4056    SUMA_ENTRY;
4057 
4058    if (!lst || !name || !child_idcode) SUMA_RETURN(xf);
4059 
4060    el = dlist_head(lst);
4061 
4062    while (el && !xf) {
4063       xft = (SUMA_XFORM *)el->data;
4064       if (!strcmp(xft->name,name)) {
4065          for (i=0; i<xft->N_children; ++i) {
4066             if (!strcmp(xft->children[i], child_idcode)) {
4067                xf = xft;
4068                if (iloc) *iloc = i;
4069                break;
4070             }
4071          }
4072       }
4073       el = dlist_next(el);
4074    }
4075 
4076    SUMA_RETURN(xf);
4077 }
4078 
4079 
SUMA_Show_Xforms(DList * dl,FILE * Out,int detail)4080 void SUMA_Show_Xforms (DList *dl, FILE *Out, int detail)
4081 {
4082    static char FuncName[]={"SUMA_Show_Xforms"};
4083    char *s = NULL;
4084 
4085    SUMA_ENTRY;
4086 
4087    if (Out == NULL) Out = stdout;
4088 
4089    s = SUMA_Xforms_Info (dl, detail);
4090 
4091    if (s) {
4092       fprintf(Out, "%s", s);
4093       SUMA_free(s); s = NULL;
4094    }else {
4095       SUMA_SL_Err("Failed in SUMA_Xforms_Info");
4096    }
4097 
4098    SUMA_RETURNe;
4099 }
4100 
SUMA_Xforms_Info(DList * dl,int detail)4101 char *SUMA_Xforms_Info(DList *dl, int detail)
4102 {
4103    static char FuncName[]={"SUMA_Xforms_Info"};
4104    DListElmt *el=NULL;
4105    char *s = NULL;
4106    SUMA_STRING *SS = NULL;
4107    SUMA_XFORM *xf=NULL;
4108    SUMA_DSET *dset=NULL;
4109    SUMA_SurfaceObject *SO=NULL;
4110    int i;
4111 
4112    SUMA_ENTRY;
4113 
4114    SS = SUMA_StringAppend(NULL, NULL);
4115 
4116    if (!dl) {
4117       SS = SUMA_StringAppend(SS,"NULL Overlay Xforms List\n");
4118       SUMA_SS2S(SS, s);
4119       SUMA_RETURN(s);
4120    } else {
4121       SS = SUMA_StringAppend_va(SS,"%d Overlay Xforms in list.\n",
4122                                  dlist_size(dl));
4123    }
4124 
4125    el = dlist_head(dl);
4126    while(el) {
4127       xf = (SUMA_XFORM *)el->data;
4128       SS = SUMA_StringAppend_va( SS,"Xform name: %s, id: %s\n"
4129                                     "           active (1=Y, -1=N): %d\n",
4130                                  xf->name, xf->idcode_str,
4131                                  xf->active);
4132       for (i=0; i<xf->N_parents; ++i) {
4133          SS = SUMA_StringAppend_va( SS,
4134                                     "  parent %d:  %s\n",
4135                                     i, xf->parents[i]);
4136          if (SUMA_is_ID_4_SO(xf->parents[i], &SO)) {
4137             SS = SUMA_StringAppend_va( SS,
4138                                     "     SO labeled %s \n",
4139                                     CHECK_NULL_STR(SO->Label));
4140          } else if (SUMA_is_ID_4_DSET(xf->parents[i], &dset)) {
4141             SS = SUMA_StringAppend_va( SS,
4142                                     "     DSET labeled %s \n",
4143                                     CHECK_NULL_STR(SDSET_LABEL(dset)));
4144          } else {
4145             SS = SUMA_StringAppend_va( SS,
4146                                     "     %s is neither SO, not DSET.\n",
4147                                     xf->parents[i]);
4148          }
4149          if (SUMA_is_ID_4_SO(xf->parents_domain[i], &SO)) {
4150             SS = SUMA_StringAppend_va( SS,
4151                                     "  parent_domain: %s, labeled %s\n",
4152                                     xf->parents_domain[i],
4153                                     CHECK_NULL_STR(SO->Label));
4154          } else {
4155             SS = SUMA_StringAppend_va( SS,
4156                                     "  parent_domain: %s, Not found!\n",
4157                                     xf->parents_domain[i]);
4158          }
4159 
4160       }
4161 
4162       for (i=0; i<xf->N_children; ++i) {
4163          SS = SUMA_StringAppend_va( SS,
4164                                     "  child %d:  %s\n",
4165                                     i, xf->children[i]);
4166          if (SUMA_is_ID_4_SO(xf->children[i], &SO)) {
4167             SS = SUMA_StringAppend_va( SS,
4168                                     "     SO labeled %s \n",
4169                                     CHECK_NULL_STR(SO->Label));
4170          } else if (SUMA_is_ID_4_DSET(xf->parents[i], &dset)) {
4171             SS = SUMA_StringAppend_va( SS,
4172                                     "     DSET labeled %s \n",
4173                                     CHECK_NULL_STR(SDSET_LABEL(dset)));
4174          } else {
4175             SS = SUMA_StringAppend_va( SS,
4176                                     "     %s is neither SO, not DSET.\n",
4177                                     xf->children[i]);
4178          }
4179       }
4180 
4181       if (xf->XformOpts) {
4182          s = SUMA_NI_nel_Info((NI_element *)xf->XformOpts, detail);
4183          SS = SUMA_StringAppend_va( SS,
4184                                     "  XformOpts is:\n"
4185                                     "%s\n",
4186                                     s);
4187          SUMA_free(s);
4188       } else {
4189          SS = SUMA_StringAppend_va( SS,
4190                                     "  XformOpts is NULL");
4191       }
4192 
4193       if (xf->gui) {
4194          SS = SUMA_StringAppend_va( SS,
4195                                     "     GUI is not null");
4196       } else {
4197          SS = SUMA_StringAppend_va( SS,
4198                                     "     GUI is null");
4199       }
4200 
4201       SS = SUMA_StringAppend(SS, "\n");
4202 
4203       el = dlist_next(el);
4204    }
4205 
4206    SUMA_SS2S(SS, s);
4207 
4208    SUMA_RETURN(s);
4209 }
4210 
SUMA_Show_Callbacks(DList * dl,FILE * Out,int detail)4211 void SUMA_Show_Callbacks (DList *dl, FILE *Out, int detail)
4212 {
4213    static char FuncName[]={"SUMA_Show_Callbacks"};
4214    char *s = NULL;
4215 
4216    SUMA_ENTRY;
4217 
4218    if (Out == NULL) Out = stdout;
4219 
4220    s = SUMA_Callbacks_Info (dl, detail);
4221 
4222    if (s) {
4223       fprintf(Out, "%s", s);
4224       SUMA_free(s); s = NULL;
4225    }else {
4226       SUMA_SL_Err("Failed in SUMA_Callbacks_Info");
4227    }
4228 
4229    SUMA_RETURNe;
4230 }
4231 
SUMA_Callbacks_Info(DList * dl,int detail)4232 char *SUMA_Callbacks_Info(DList *dl, int detail)
4233 {
4234    static char FuncName[]={"SUMA_Callbacks_Info"};
4235    char *s = NULL;
4236    DListElmt *el=NULL;
4237    NI_group *ngr=NULL;
4238    NI_element *nel = NULL;
4239    SUMA_STRING *SS = NULL;
4240    SUMA_DSET *dset=NULL;
4241    SUMA_SurfaceObject *SO=NULL;
4242    SUMA_CALLBACK *cb=NULL;
4243    SUMA_XFORM *xf=NULL;
4244    int i;
4245 
4246    SUMA_ENTRY;
4247    SS = SUMA_StringAppend(NULL, NULL);
4248 
4249    if (!dl) {
4250       SS = SUMA_StringAppend(SS,"NULL Callbacks List\n");
4251       SUMA_SS2S(SS, s);
4252       SUMA_RETURN(s);
4253    } else {
4254       SS = SUMA_StringAppend_va(SS,"%d Callbacks in list.\n",
4255                                  dlist_size(dl));
4256    }
4257 
4258    el = dlist_head(dl);
4259    while(el) {
4260       cb = (SUMA_CALLBACK *)el->data;
4261       xf = SUMA_Find_XformByID(cb->creator_xform);
4262       SS = SUMA_StringAppend_va( SS,"CB trigger event: %d \n"
4263                                     "           active (1=Y, -1=N): %d\n"
4264                                     "           pending (1=Y, 0=N): %d\n"
4265                                     "           trigger source %d\n"
4266                                     , cb->event
4267                                     , cb->active, cb->pending
4268                                     , cb->trigger_source );
4269       if (xf) {
4270          SS = SUMA_StringAppend_va( SS,"   Creator Xform: %s\n", xf->name);
4271       } else {
4272          SS = SUMA_StringAppend_va( SS,"   No creator xform found.\n");
4273       }
4274       for (i=0; i<cb->N_parents; ++i) {
4275          SS = SUMA_StringAppend_va( SS,
4276                                     "  parent %d:  %s\n",
4277                                     i, cb->parents[i]);
4278 
4279          if (SUMA_is_ID_4_SO(cb->parents[i], &SO)) {
4280             SS = SUMA_StringAppend_va( SS,
4281                                     "     SO labeled %s \n",
4282                                     CHECK_NULL_STR(SO->Label));
4283          } else if (SUMA_is_ID_4_DSET(cb->parents[i], &dset)) {
4284             SS = SUMA_StringAppend_va( SS,
4285                                     "     DSET labeled %s \n",
4286                                     CHECK_NULL_STR(SDSET_LABEL(dset)));
4287          } else {
4288             SS = SUMA_StringAppend_va( SS,
4289                                     "     %s is neither SO, not DSET.\n",
4290                                     cb->parents[i]);
4291          }
4292          if (SUMA_is_ID_4_SO(cb->parents_domain[i], &SO)) {
4293             SS = SUMA_StringAppend_va( SS,
4294                                     "  parent_domain: %s, labeled %s\n",
4295                                     cb->parents_domain[i],
4296                                     CHECK_NULL_STR(SO->Label));
4297          } else {
4298             SS = SUMA_StringAppend_va( SS,
4299                                     "  parent_domain: %s, Not found!\n",
4300                                     cb->parents_domain[i]);
4301          }
4302       }
4303 
4304       SS = SUMA_StringAppend_va( SS,
4305                                  "  Function Name %s (%p)\n",
4306                                  cb->FunctionName, cb->FunctionPtr);
4307 
4308       s = SUMA_NI_nel_Info((NI_element *)cb->FunctionInput, detail);
4309       SS = SUMA_StringAppend_va( SS,
4310                                  "  Function Params:\n%s\n-----\n",
4311                                  s); SUMA_free(s); s = NULL;
4312 
4313       SS = SUMA_StringAppend(SS, "\n");
4314 
4315       if (detail > 1) {
4316          SUMA_S_Note("Detailed nel view\n");
4317          SUMA_ShowNel(nel);
4318       }
4319       el = dlist_next(el);
4320    }
4321 
4322 
4323    SUMA_SS2S(SS, s);
4324 
4325    SUMA_RETURN(s);
4326 }
4327 
4328 
4329 
SUMA_SetXformActive(SUMA_XFORM * xf,int active,int fromgui)4330 SUMA_Boolean SUMA_SetXformActive(SUMA_XFORM *xf, int active, int fromgui)
4331 {
4332    static char FuncName[]={"SUMA_SetXformActive"};
4333    SUMA_CALLBACK *cb;
4334    DListElmt *el=NULL;
4335    DList *dl=SUMAg_CF->callbacks;
4336    SUMA_Boolean LocalHead = NOPE;
4337 
4338    SUMA_ENTRY;
4339 
4340    if (!xf) SUMA_RETURN(NOPE);
4341 
4342    xf->active = active;
4343 
4344    if (!xf->gui) {
4345       /* create GUI */
4346       SUMA_CreateXformInterface(xf);
4347    } else if (!fromgui){
4348       /* Raise GUI */
4349       if (LocalHead)
4350          fprintf (SUMA_STDERR,"%s: raising Xform GUI window \n", FuncName);
4351       XMapRaised(SUMAg_CF->X->DPY_controller1,
4352                   XtWindow(xf->gui->AppShell));
4353    }
4354 
4355 
4356    if (0 && !fromgui) { /* not sure why I have this here.
4357                            SUMA_InitializeXformInterface is called in SUMA_D_Key,
4358                            which is the function called in both GUI and non GUI
4359                            modes... */
4360       /* initialize the gui */
4361       SUMA_InitializeXformInterface(xf);
4362    }
4363 
4364    if (!dl) SUMA_RETURN(YUP);
4365 
4366    /* Now reflect that in all callbacks that were created by xform */
4367    el = dlist_head(dl);
4368    while (el) {
4369       cb = (SUMA_CALLBACK *)el->data;
4370       if (!strcmp(cb->creator_xform, xf->idcode_str)) {
4371          cb->active = active;
4372          if (!cb->active < 1) {
4373             SUMA_SetCallbackPending(cb, 0, SES_Empty);
4374          }
4375       }
4376       el = dlist_next(el);
4377    }
4378    SUMA_RETURN(YUP);
4379 }
4380 
SUMA_SetXformShowPreProc(SUMA_XFORM * xf,int ShowPreProc,int fromgui)4381 SUMA_Boolean SUMA_SetXformShowPreProc(SUMA_XFORM *xf, int ShowPreProc,
4382                                       int fromgui)
4383 {
4384    static char FuncName[]={"SUMA_SetXformShowPreProc"};
4385    SUMA_CALLBACK *cb;
4386    DListElmt *el=NULL;
4387    DList *dl=SUMAg_CF->callbacks;
4388    NI_element *dotopt=NULL;
4389    int ii=0;
4390    SUMA_DSET *in_dset=NULL, *pp_dset=NULL;
4391    SUMA_Boolean LocalHead = NOPE;
4392 
4393    SUMA_ENTRY;
4394 
4395    if (!xf) SUMA_RETURN(NOPE);
4396 
4397    xf->ShowPreProc = ShowPreProc;
4398 
4399    if (!xf->gui) {
4400       /* create GUI */
4401       SUMA_CreateXformInterface(xf);
4402    } else if (!fromgui){
4403       /* Raise GUI */
4404       if (LocalHead)
4405          fprintf (SUMA_STDERR,"%s: raising Xform GUI window \n", FuncName);
4406       XMapRaised(SUMAg_CF->X->DPY_controller1,
4407                   XtWindow(xf->gui->AppShell));
4408    }
4409 
4410    if (!fromgui) {
4411       /* initialize the gui */
4412       SUMA_InitializeXformInterface(xf);
4413    }
4414 
4415    if (!dl) SUMA_RETURN(YUP);
4416 
4417    /* Now do something about showing */
4418    if (!strcmp(xf->name,"Dot")) {
4419       if (!(dotopt = SUMA_FindNgrNamedElement(xf->XformOpts, "dotopts"))) {
4420          SUMA_S_Err("dotopt not found");
4421          SUMA_RETURN(NOPE);
4422       }
4423       for (ii=0; ii<xf->N_parents; ++ii) {
4424          if (!SUMA_is_ID_4_DSET(xf->parents[ii], &in_dset)) {
4425             SUMA_S_Err("Parent not found");
4426             SUMA_RETURN(NOPE);
4427          }
4428          if (!(pp_dset = SUMA_GetDotPreprocessedDset(in_dset, dotopt))){
4429             SUMA_S_Err("PreProcParent not found");
4430             SUMA_RETURN(NOPE);
4431          }
4432          /* now make it visible */
4433          /* For this to work, you'll need to have a version of the
4434          block under LoadDsetFile beginning from OverInd = -1;
4435          To make matters more exciting, you'll need to update this sucker,
4436          any time that the preprocessing is redone because of changes in
4437          orts or bandpass, etc. So leave this feature out for now */
4438       }
4439    } else {
4440       SUMA_S_Errv("Don't know how to do this for %s\n", xf->name);
4441       SUMA_RETURN(NOPE);
4442    }
4443 
4444    SUMA_RETURN(YUP);
4445 }
4446 
SUMA_is_XformParent(SUMA_XFORM * xf,char * id,int * iloc)4447 SUMA_Boolean SUMA_is_XformParent (SUMA_XFORM *xf, char *id, int *iloc)
4448 {
4449    static char FuncName[]={"SUMA_is_XformParent"};
4450    int ii;
4451 
4452    SUMA_ENTRY;
4453 
4454    if (!xf || !id) SUMA_RETURN(NOPE);
4455 
4456    for (ii=0; ii<xf->N_parents; ++ii) {
4457       if (!strcmp(xf->parents[ii],id)) {
4458          if (iloc) *iloc=ii;
4459          SUMA_RETURN(YUP);
4460       }
4461    }
4462 
4463    SUMA_RETURN(NOPE);
4464 }
4465 
SUMA_AddXformParent(SUMA_XFORM * xf,char * parent_idcode,char * parent_domain)4466 SUMA_Boolean SUMA_AddXformParent (SUMA_XFORM *xf,
4467                                   char *parent_idcode, char *parent_domain)
4468 {
4469    static char FuncName[]={"SUMA_AddXformParent"};
4470    SUMA_DSET *dset=NULL;
4471 
4472    SUMA_ENTRY;
4473 
4474    if (!xf || !parent_idcode) {
4475       SUMA_S_Err("NULL input");
4476       SUMA_RETURN(NOPE);
4477    }
4478    if (SUMA_is_XformParent(xf, parent_idcode, NULL)) {
4479       SUMA_S_Err("Parent exists");
4480       SUMA_RETURN(NOPE);
4481    }
4482 
4483    strcpy(xf->parents[xf->N_parents], parent_idcode);
4484    if (!parent_domain) {
4485       if (SUMA_is_ID_4_DSET(parent_idcode, &dset)) {
4486          strcpy( xf->parents_domain[xf->N_parents],
4487                  SDSET_IDMDOM(dset));
4488       } else {
4489          xf->parents_domain[xf->N_parents][0] = '\0';
4490       }
4491    } else {
4492       strcpy( xf->parents_domain[xf->N_parents],
4493               parent_domain);
4494    }
4495 
4496 
4497    ++xf->N_parents;
4498    SUMA_RETURN(YUP);
4499 
4500 }
4501 
SUMA_is_XformChild(SUMA_XFORM * xf,char * id,int * iloc)4502 SUMA_Boolean SUMA_is_XformChild (SUMA_XFORM *xf, char *id, int *iloc)
4503 {
4504    static char FuncName[]={"SUMA_is_XformChild"};
4505    int ii;
4506 
4507    SUMA_ENTRY;
4508 
4509    if (!xf || !id) SUMA_RETURN(NOPE);
4510 
4511    for (ii=0; ii<xf->N_children; ++ii) {
4512       if (!strcmp(xf->children[ii],id)) {
4513          if (iloc) *iloc=ii;
4514          SUMA_RETURN(YUP);
4515       }
4516    }
4517 
4518    SUMA_RETURN(NOPE);
4519 }
4520 
SUMA_AddXformChild(SUMA_XFORM * xf,char * child_idcode)4521 SUMA_Boolean SUMA_AddXformChild (SUMA_XFORM *xf,
4522                                  char *child_idcode)
4523 {
4524    static char FuncName[]={"SUMA_AddXformChild"};
4525    SUMA_DSET *dset=NULL;
4526    int ii;
4527 
4528    SUMA_ENTRY;
4529 
4530    if (!xf || !child_idcode) {
4531       SUMA_S_Err("NULL input");
4532       SUMA_RETURN(NOPE);
4533    }
4534    if (SUMA_is_XformChild(xf, child_idcode, NULL)) {
4535       SUMA_S_Err("Child exists");
4536       SUMA_RETURN(NOPE);
4537    }
4538 
4539    strcpy(xf->children[xf->N_children], child_idcode);
4540 
4541    ++xf->N_children;
4542    SUMA_RETURN(YUP);
4543 
4544 }
4545 
4546 
SUMA_NewXform(char * name,char * parent_idcode,char * parent_domain)4547 SUMA_XFORM *SUMA_NewXform(char *name, char *parent_idcode, char *parent_domain)
4548 {
4549    static char FuncName[]={"SUMA_NewXform"};
4550    SUMA_XFORM *xf = NULL;
4551 
4552    SUMA_ENTRY;
4553    if (!name || !parent_idcode) SUMA_RETURN(xf);
4554 
4555    if (  !SUMA_is_ID_4_SO(parent_idcode, NULL) &&
4556          !SUMA_is_ID_4_DSET(parent_idcode, NULL) ) {
4557       SUMA_S_Err("Invalid parent_idcode");
4558       SUMA_RETURN(xf);
4559    }
4560 
4561    if (SUMA_Find_XformByParent("Dot", parent_idcode, NULL)) {
4562       SUMA_S_Err("An xform exists already");
4563       SUMA_RETURN(xf);
4564    }
4565 
4566    xf = (SUMA_XFORM *)SUMA_calloc(1, sizeof(SUMA_XFORM));
4567 
4568    snprintf(xf->name, 127*sizeof(char), "%s", name);
4569    UNIQ_idcode_fill(xf->idcode_str);
4570 
4571    if (!SUMA_AddXformParent(xf,parent_idcode, parent_domain)) {
4572       SUMA_S_Err("Failed to add parent");
4573       SUMA_FreeXform(xf); xf = NULL;
4574       SUMA_RETURN(xf);
4575    }
4576 
4577 
4578    xf->N_children = 0;
4579 
4580    xf->active = 0;
4581    xf->ShowPreProc = 0;
4582 
4583    xf->XformOpts = NI_new_group_element();
4584    NI_rename_group(xf->XformOpts, "XformOpts");
4585 
4586    dlist_ins_next(SUMAg_CF->xforms, dlist_tail(SUMAg_CF->xforms), xf);
4587 
4588    SUMA_RETURN(xf);
4589 }
4590 
SUMA_FreeXform(void * data)4591 void SUMA_FreeXform(void *data)
4592 {
4593    static char FuncName[]={"SUMA_FreeXform"};
4594    SUMA_XFORM *xf = (SUMA_XFORM *)data;
4595 
4596    SUMA_ENTRY;
4597 
4598    if (xf) {
4599       if (xf->XformOpts) NI_free_element(xf->XformOpts);
4600       if (xf->gui) SUMA_FreeXformInterface(xf->gui);
4601       SUMA_free(xf);
4602    }
4603 
4604    SUMA_RETURNe;
4605 }
4606 
SUMA_NewXformInterface(SUMA_XFORM * xf)4607 SUMA_GENERIC_XFORM_INTERFACE * SUMA_NewXformInterface(
4608                                  SUMA_XFORM *xf)
4609 {
4610    static char FuncName[]={"SUMA_NewXformInterface"};
4611    SUMA_GENERIC_XFORM_INTERFACE *gui=NULL;
4612 
4613    SUMA_ENTRY;
4614 
4615 
4616    gui = (SUMA_GENERIC_XFORM_INTERFACE *)
4617             SUMA_calloc(1,sizeof(SUMA_GENERIC_XFORM_INTERFACE));
4618 
4619    gui->AF0 =
4620       (SUMA_ARROW_TEXT_FIELD *)calloc(1, sizeof(SUMA_ARROW_TEXT_FIELD));
4621    gui->AF1 =
4622       (SUMA_ARROW_TEXT_FIELD *)calloc(1, sizeof(SUMA_ARROW_TEXT_FIELD));
4623    gui->AF2 =
4624       (SUMA_ARROW_TEXT_FIELD *)calloc(1, sizeof(SUMA_ARROW_TEXT_FIELD));
4625 
4626    SUMA_RETURN(gui);
4627 }
4628 
SUMA_FreeXformInterface(SUMA_GENERIC_XFORM_INTERFACE * gui)4629 void SUMA_FreeXformInterface(SUMA_GENERIC_XFORM_INTERFACE *gui)
4630 {
4631    static char FuncName[]={"SUMA_FreeXformInterface"};
4632 
4633    SUMA_ENTRY;
4634    if (gui) {
4635       if (gui->AF0) SUMA_free(gui->AF0);
4636       if (gui->AF1) SUMA_free(gui->AF1);
4637       if (gui->AF2) SUMA_free(gui->AF2);
4638 
4639       SUMA_free(gui);
4640    }
4641    SUMA_RETURNe;
4642 }
4643 
SUMA_is_CallbackParent(SUMA_CALLBACK * cb,char * id,int * iloc)4644 SUMA_Boolean SUMA_is_CallbackParent (SUMA_CALLBACK *cb, char *id, int *iloc)
4645 {
4646    static char FuncName[]={"SUMA_is_CallbackParent"};
4647    int ii;
4648 
4649    SUMA_ENTRY;
4650 
4651    if (!cb || !id) SUMA_RETURN(NOPE);
4652 
4653    for (ii=0; ii<cb->N_parents; ++ii) {
4654       if (!strcmp(cb->parents[ii],id)) {
4655          if (iloc) *iloc=ii;
4656          SUMA_RETURN(YUP);
4657       }
4658    }
4659 
4660    SUMA_RETURN(NOPE);
4661 }
4662 
4663 
4664 /*!
4665    Find a callback with a particular name AND a parent with a matching idcode
4666 */
SUMA_Find_CallbackByParent(char * FunctionName,char * parent_idcode,int * iloc)4667 SUMA_CALLBACK *SUMA_Find_CallbackByParent(char *FunctionName,
4668                                        char *parent_idcode, int *iloc)
4669 {
4670    static char FuncName[]={"SUMA_Find_CallbackByParent"};
4671    SUMA_CALLBACK *cb = NULL, *cbt=NULL;
4672    DListElmt *el=NULL;
4673    DList *lst = SUMAg_CF->callbacks;
4674    int i;
4675 
4676    SUMA_ENTRY;
4677 
4678    if (!lst || !FunctionName || !parent_idcode) SUMA_RETURN(cb);
4679 
4680    el = dlist_head(lst);
4681 
4682    while (el && !cb) {
4683       cbt = (SUMA_CALLBACK *)el->data;
4684       if (!strcmp(cbt->FunctionName, FunctionName)) {
4685          for (i=0; i<cbt->N_parents; ++i) {
4686             if (!strcmp(cbt->parents[i], parent_idcode)) {
4687                cb = cbt;
4688                if (iloc) *iloc = i;
4689                break;
4690             }
4691          }
4692       }
4693       el = dlist_next(el);
4694    }
4695 
4696    SUMA_RETURN(cb);
4697 }
4698 
SUMA_Find_CallbackByCreatorXformID(char * creator_xform_idcode)4699 SUMA_CALLBACK *SUMA_Find_CallbackByCreatorXformID(char *creator_xform_idcode)
4700 {
4701    static char FuncName[]={"SUMA_Find_CallbackByCreatorXformID"};
4702    SUMA_CALLBACK *cb = NULL, *cbf=NULL;
4703    DListElmt *el=NULL;
4704    DList *lst = SUMAg_CF->callbacks;
4705    int i, found=0;
4706 
4707    SUMA_ENTRY;
4708 
4709    if (!lst || !creator_xform_idcode) SUMA_RETURN(cbf);
4710 
4711    el = dlist_head(lst);
4712    cbf=NULL;
4713    while (el && !cbf) {
4714       cb = (SUMA_CALLBACK *)el->data;
4715       if (!strcmp(cb->creator_xform, creator_xform_idcode)) {
4716          ++found; cbf = cb;
4717       }
4718       el = dlist_next(el);
4719    }
4720    if (found > 1) {
4721       SUMA_S_Errv("%d callbacks found\n"
4722                   "write a new function to return them all\n",
4723                   found);
4724    }
4725    SUMA_RETURN(cbf);
4726 }
4727 
SUMA_AddCallbackParent(SUMA_CALLBACK * cb,char * parent_idcode,char * parent_domain)4728 SUMA_Boolean SUMA_AddCallbackParent (SUMA_CALLBACK *cb,
4729                                      char *parent_idcode,
4730                                      char *parent_domain)
4731 {
4732    static char FuncName[]={"SUMA_AddCallbackParent"};
4733    SUMA_DSET *dset=NULL;
4734 
4735    SUMA_ENTRY;
4736 
4737    if (!cb || !parent_idcode) {
4738       SUMA_S_Err("NULL input");
4739       SUMA_RETURN(NOPE);
4740    }
4741 
4742    if (SUMA_is_CallbackParent(cb, parent_idcode, NULL)) {
4743       SUMA_S_Err("Parent exists");
4744       SUMA_RETURN(NOPE);
4745    }
4746 
4747    strcpy(cb->parents[cb->N_parents], parent_idcode);
4748    if (!parent_domain) {
4749       if (SUMA_is_ID_4_DSET(parent_idcode, &dset)) {
4750          strcpy( cb->parents_domain[cb->N_parents],
4751                  SDSET_IDMDOM(dset));
4752       } else {
4753          cb->parents_domain[cb->N_parents][0] = '\0';
4754       }
4755    } else {
4756       strcpy( cb->parents_domain[cb->N_parents],
4757               parent_domain);
4758    }
4759 
4760    ++cb->N_parents;
4761    SUMA_RETURN(YUP);
4762 
4763 }
4764 
SUMA_SetCallbackPending(SUMA_CALLBACK * cb,SUMA_Boolean pen,SUMA_ENGINE_SOURCE src)4765 SUMA_Boolean SUMA_SetCallbackPending (SUMA_CALLBACK *cb,
4766                                       SUMA_Boolean pen, SUMA_ENGINE_SOURCE src)
4767 {
4768    static char FuncName[]={"SUMA_SetCallbackPending"};
4769 
4770    SUMA_ENTRY;
4771 
4772    if (!cb) SUMA_RETURN(NOPE);
4773 
4774    if (cb->active < 1 && pen) {
4775       SUMA_S_Notev("Callback %s inactive. Pending flag not set\n",
4776                   cb->FunctionName);
4777       SUMA_RETURN(YUP);
4778    }
4779 
4780    if (src <= SES_Empty && pen) {
4781       SUMA_S_Errv("Source %d is not appropriate.\n",src);
4782       SUMA_RETURN(NOPE);
4783    }
4784 
4785    if (cb->pending && pen) {
4786       SUMA_S_Errv("Callback %s is already pending. \n",
4787                   cb->FunctionName);
4788       SUMA_RETURN(NOPE);
4789    }
4790 
4791    cb->pending = pen;
4792    if (!pen) cb->trigger_source = SES_Empty;
4793    else cb->trigger_source = pen;
4794 
4795    SUMA_RETURN(YUP);
4796 }
4797 
SUMA_NewCallback(char * FunctionName,SUMA_CALLBACK_ACTIVATE_EVENTS event,void * FunctionPtr,char * parent_idcode,char * parent_domain,char * creator_xform)4798 SUMA_CALLBACK *SUMA_NewCallback  (char *FunctionName,
4799                                SUMA_CALLBACK_ACTIVATE_EVENTS event,
4800                                void *FunctionPtr,
4801                                char *parent_idcode,
4802                                char *parent_domain,
4803                                char *creator_xform)
4804 {
4805    static char FuncName[]={"SUMA_NewCallback"};
4806    SUMA_XFORM *xf = NULL;
4807    NI_element *nel=NULL;
4808    SUMA_CALLBACK *cb = NULL;
4809    char stmp[256];
4810    SUMA_Boolean LocalHead = NOPE;
4811 
4812    SUMA_ENTRY;
4813 
4814    SUMA_LH("Checks");
4815    if (!parent_idcode || !FunctionName ||
4816        strlen(FunctionName) > 125  ) SUMA_RETURN(cb);
4817 
4818    if (  !SUMA_is_ID_4_SO(parent_idcode, NULL) &&
4819          !SUMA_is_ID_4_DSET(parent_idcode, NULL) ) {
4820       SUMA_S_Err("Invalid parent_idcode");
4821       SUMA_RETURN(cb);
4822    }
4823 
4824    if (SUMA_Find_CallbackByParent(FunctionName, parent_idcode, NULL)) {
4825       SUMA_S_Err("A callback exists already");
4826       SUMA_RETURN(cb);
4827    }
4828 
4829    SUMA_LH("New callback");
4830    cb = (SUMA_CALLBACK *)calloc(1,sizeof(SUMA_CALLBACK));
4831 
4832    cb->event = event;
4833    cb->active = 0;
4834    cb->pending = 0;
4835    cb->trigger_source = SES_Empty;
4836    strcpy(cb->FunctionName, FunctionName);
4837    cb->FunctionPtr = FunctionPtr;
4838 
4839    SUMA_LH("Func input");
4840    cb->FunctionInput = NI_new_group_element();
4841    snprintf(stmp,sizeof(char)*64,"input.%s",FunctionName);
4842    NI_rename_group(cb->FunctionInput, stmp);
4843 
4844    SUMA_LH("defaults");
4845    /* Set defaults for generic parameters */
4846    nel = NI_new_data_element("event_parameters", 0);
4847    NI_add_to_group(cb->FunctionInput, nel);
4848    NI_SET_INT(nel,"event.new_node", -1);
4849    NI_set_attribute(nel, "event.DO_idcode", "");
4850    NI_set_attribute(nel,"event.overlay_name", "");
4851 
4852    SUMA_LH("Adding parent");
4853    if (!SUMA_AddCallbackParent(cb, parent_idcode, parent_domain)){
4854       SUMA_S_Err("Failed to add parent");
4855       SUMA_RETURN(NOPE);
4856    }
4857 
4858 
4859    if (creator_xform) {
4860       if (!(xf=SUMA_Find_XformByID(creator_xform))) {
4861          SUMA_S_Err("Failed to find xform");
4862          SUMA_RETURN(NOPE);
4863       }
4864       strcpy(cb->creator_xform, creator_xform);
4865    }
4866 
4867    dlist_ins_next(SUMAg_CF->callbacks, dlist_tail(SUMAg_CF->callbacks), cb);
4868 
4869    SUMA_RETURN(cb);
4870 }
4871 
4872 
SUMA_FreeCallback(void * data)4873 void SUMA_FreeCallback(void *data)
4874 {
4875    static char FuncName[]={"SUMA_FreeCallback"};
4876    SUMA_CALLBACK *cb = (SUMA_CALLBACK *)data;
4877 
4878    SUMA_ENTRY;
4879 
4880    if (cb) {
4881       if (cb->FunctionInput) {
4882          NI_free_element(cb->FunctionInput);
4883       }
4884       SUMA_free(cb);
4885    }
4886 
4887    SUMA_RETURNe;
4888 }
4889 
SUMA_FlushCallbackEventParameters(SUMA_CALLBACK * cb)4890 SUMA_Boolean SUMA_FlushCallbackEventParameters (SUMA_CALLBACK *cb)
4891 {
4892    static char FuncName[]={"SUMA_FlushCallbackEventParameters"};
4893    NI_element *nelpars=NULL;
4894 
4895    SUMA_ENTRY;
4896 
4897    if (!cb ||
4898        !(nelpars = SUMA_FindNgrNamedElement(
4899                      cb->FunctionInput, "event_parameters"))) {
4900       SUMA_S_Err("NULL cb or Bad callback content");
4901       SUMA_RETURN(NOPE);
4902    }
4903 
4904    switch (cb->event) {
4905       case SUMA_NEW_NODE_ACTIVATE_EVENT:
4906          SUMA_XFORM_SAVE_FLUSH_EVENT(nelpars);
4907          break;
4908       case SUMA_ERROR_ACTIVATE_EVENT:
4909       case SUMA_NO_ACTIVATE_EVENT:
4910       case SUMA_N_ACTIVATE_EVENTS:
4911          SUMA_S_Warn("This should not come up");
4912          break;
4913       default:
4914          SUMA_S_Err("Seriously off folks");
4915          SUMA_RETURN(NOPE);
4916          break;
4917    }
4918 
4919    SUMA_RETURN(YUP);
4920 }
4921 
SUMA_ExecuteCallback(SUMA_CALLBACK * cb,int refresh,SUMA_ALL_DO * ado,int doall)4922 SUMA_Boolean SUMA_ExecuteCallback(SUMA_CALLBACK *cb,
4923                                   int refresh, SUMA_ALL_DO *ado,
4924                                   int doall)
4925 {
4926    static char FuncName[]={"SUMA_ExecuteCallback"};
4927    SUMA_SurfaceObject *curSO=NULL, *targetSO=NULL;
4928    SUMA_OVERLAYS *targetSover=NULL;
4929    int i, jj=0;
4930    SUMA_DSET *targetDset=NULL;
4931    SUMA_Boolean LocalHead = NOPE;
4932 
4933    SUMA_ENTRY;
4934 
4935    SUMA_LH("Calling FunctionPtr(cb)");
4936    cb->FunctionPtr((void *)cb);
4937 
4938    SUMA_LH("Set callback pending");
4939    SUMA_SetCallbackPending(cb, 0, SES_Empty);
4940 
4941    /* flush event specific parameters */
4942    SUMA_FlushCallbackEventParameters(cb);
4943    SUMA_LH("Flushing done");
4944    if (refresh) {/* Now decide on what needs refreshing */
4945       if (!ado) {
4946          curSO = NULL;
4947       } else {
4948          curSO = SUMA_Cont_SO(SUMA_ADO_Cont(ado));
4949       }
4950       SUMA_LH("curSO = %p, ado = %p", curSO, ado);
4951       for (i=0; i<cb->N_parents; ++i) {
4952          if (SUMA_is_ID_4_DSET(cb->parents[i], &targetDset)) {
4953             targetSO = SUMA_findSOp_inDOv(cb->parents_domain[i],
4954                                           SUMAg_DOv, SUMAg_N_DOv);
4955             if (!targetSO) {
4956                if (ado && ado->do_type == SO_type) {
4957                   SUMA_S_Warn("Could not find targetSO, using SO instead");
4958                   targetSO = (SUMA_SurfaceObject *)ado;
4959                } else {
4960                   SUMA_S_Err("Don't know what do do here");
4961                   SUMA_RETURN(NOPE);
4962                }
4963             }
4964             /* refresh overlay and SO for this callback */
4965             targetSover = SUMA_Fetch_OverlayPointerByDset(
4966                                  (SUMA_ALL_DO*)targetSO,
4967                                  targetDset,
4968                                  &jj);
4969             SUMA_LHv("Colorizing %s\n", targetSover->Name);
4970             SUMA_ColorizePlane(targetSover);
4971             SUMA_LHv("Setting remix flag for %s\n",targetSO->Label);
4972             if (!SUMA_SetRemixFlag( targetSO->idcode_str,
4973                                     SUMAg_SVv, SUMAg_N_SVv)) {
4974                SUMA_SLP_Err("Failed in SUMA_SetRemixFlag.\n");
4975                SUMA_RETURN(NOPE);
4976             }
4977             if (doall || curSO != targetSO) {
4978                SUMA_UPDATE_ALL_NODE_GUI_FIELDS((SUMA_ALL_DO*)targetSO);
4979                SUMA_Remixedisplay((SUMA_ALL_DO*)targetSO);
4980             } else {
4981                /* Update and Remix will be done for curSO
4982                   by the function who called this one */
4983             }
4984             /* it is possible that the callback caused a change
4985                in the p value so update it to be sure,
4986                but I am not fond of doing this all the time,
4987                every time there is a button click triggering the
4988                event .... */
4989             SUMA_LHv("Updating threshold at %f\n",
4990                      targetSO->SurfCont->curColPlane->OptScl->ThreshRange[0]);
4991             SUMA_UpdatePvalueField( (SUMA_ALL_DO *)targetSO,
4992                      targetSO->SurfCont->curColPlane->OptScl->ThreshRange[0]);
4993          } else if (SUMA_is_ID_4_SO(cb->parents[i], &targetSO)) {
4994             SUMA_S_Note("Got surface, don't know \n"
4995                         "what to do in case like this yet\n");
4996          } else {
4997             SUMA_S_Err("Dunno what to do with such an object...");
4998          }
4999       }
5000 
5001    }
5002    SUMA_RETURN(YUP);
5003 }
5004 
5005