1 /*! Functions to create Displayable Objects */
2 #include "SUMA_suma.h"
3 
4 extern SUMA_CommonFields *SUMAg_CF;
5 extern SUMA_DO *SUMAg_DOv;
6 extern SUMA_SurfaceViewer *SUMAg_SVv;
7 extern int SUMAg_N_SVv;
8 extern int SUMAg_N_DOv;
9 
10 /* This macro is used to decide if displayable objects on a node 'n' are to be
11    drawn. For now, this condition is applied to certain objects only. T
12    The NIDO functions do not call on this macro yet.
13    The problem is that NIDO functions draw one object at a time and you don't
14    want to form the node mask in SUMA_ProcessDODrawMask each time a DO is to be
15    drawn. The byte mask should probably be formed at the level of main drawing
16    routine and freed afterwards. That also means that a subject's ID might need
17    to be checked, in addition to the node numbers. But that should not be too
18    bad. */
19 #define DO_DRAW(mask, n, nc) (((nc == n || (nc < 0 && (!mask || mask[n]))))?1:0)
SUMA_ProcessDODrawMask(SUMA_SurfaceViewer * sv,SUMA_SurfaceObject * SO,byte ** mask,int * ncross)20 int SUMA_ProcessDODrawMask(SUMA_SurfaceViewer *sv,
21                                     SUMA_SurfaceObject *SO,
22                                     byte **mask, int *ncross)
23 {
24    static char FuncName[]={"SUMA_ProcessDODrawMask"};
25    int N_inmask=0;
26    SUMA_Boolean LocalHead = NOPE;
27 
28    SUMA_ENTRY;
29 
30    if (!sv || !SO || !mask || !ncross) SUMA_RETURN(-1);
31    if (*mask) {
32       SUMA_S_Err("Must send me a null mask pointer");
33       SUMA_RETURN(-1);
34    }
35    *ncross = -1;
36    if (sv->DO_DrawMask != SDODM_All) {
37       /* Masking required, make sure surface qualifies */
38       if (!(sv->Ch && iDO_isSO(sv->Ch->adoID))) {
39          SUMA_LH("Cross hair not initialized yet, or not on surface");
40          SUMA_RETURN (0);
41       }
42       if (SO!=(SUMA_SurfaceObject *)(SUMAg_DOv[sv->Ch->adoID].OP)) {
43          /* Not the surface on which the cross hair lives, get out */
44          SUMA_RETURN (0);
45       }
46       if (sv->Ch->datumID < 0 || sv->Ch->datumID >= SO->N_Node) {
47          SUMA_S_Errv("Bad crosshair node %d on %s. This should not happen.\n",
48                      sv->Ch->datumID, SO->Label);
49          SUMA_RETURN (-1);
50       }
51    }
52    switch (sv->DO_DrawMask) {
53       case SDODM_n0CrossHair:
54       case SDODM_n1CrossHair:
55       case SDODM_n2CrossHair:
56       case SDODM_n3CrossHair:
57          if (sv->DO_DrawMask != SDODM_n0CrossHair) {
58             /* get neighbors */
59             if (!(*mask = SUMA_NodeNeighborMask(SO, sv->Ch->datumID,
60                                          SDODM_n0CrossHair-sv->DO_DrawMask,
61                                          &N_inmask))) {
62                SUMA_S_Warnv("Failed to get neighborhood for node %d\n"
63                             "Proceeding...\n", sv->Ch->datumID);
64                *ncross = sv->Ch->datumID; /* show something at least */
65                N_inmask = 1;
66             } else {
67                *(*mask+sv->Ch->datumID) = 1; ++N_inmask;
68             }
69          } else {
70             *ncross = sv->Ch->datumID; /* just this node */
71             N_inmask = 1;
72          }
73          break;
74       case SDODM_All:
75          N_inmask = SO->N_Node;
76          break;
77       case SDODM_Hide:
78          N_inmask = 0;
79          break;
80       default:
81          SUMA_S_Err("Bad draw mask mode");
82          SUMA_RETURN (-1);
83          break;
84    }
85    SUMA_LHv("Got ncross=%d. %d node objects to draw\n"
86             , *ncross, N_inmask );
87    SUMA_RETURN(N_inmask);
88 }
89 
SUMA_NewNewSOOpt(void)90 SUMA_NEW_SO_OPT *SUMA_NewNewSOOpt(void)
91 {
92    static char FuncName[]={"SUMA_NewNewSOOpt"};
93    SUMA_NEW_SO_OPT *nsoopt=NULL;
94    SUMA_ENTRY;
95 
96    nsoopt = (SUMA_NEW_SO_OPT *) SUMA_calloc(1,sizeof(SUMA_NEW_SO_OPT));
97    nsoopt->idcode_str = NULL;
98    nsoopt->LocalDomainParent = SUMA_copy_string("SAME");
99    nsoopt->LocalDomainParentID = NULL;
100    nsoopt->FileFormat = SUMA_ASCII;
101    nsoopt->FileType = SUMA_FT_NOT_SPECIFIED;
102    nsoopt->DoMetrics = YUP;
103    nsoopt->DoNormals = YUP;
104    nsoopt->DoCenter = YUP;
105    nsoopt->LargestBoxSize = -1.0;
106    SUMA_RETURN(nsoopt);
107 }
108 
SUMA_FreeNewSOOpt(SUMA_NEW_SO_OPT * nsopt)109 SUMA_NEW_SO_OPT *SUMA_FreeNewSOOpt(SUMA_NEW_SO_OPT *nsopt)
110 {
111    static char FuncName[]={"SUMA_FreeNewSOOpt"};
112    SUMA_ENTRY;
113 
114    if (!nsopt) SUMA_RETURN(NULL);
115    if (nsopt->idcode_str) SUMA_free(nsopt->idcode_str);
116    if (nsopt->LocalDomainParentID) SUMA_free(nsopt->LocalDomainParentID);
117    if (nsopt->LocalDomainParent) SUMA_free(nsopt->LocalDomainParent);
118    SUMA_free(nsopt);
119 
120    SUMA_RETURN(NULL);
121 }
122 
123 /*!
124    Creates a surface object and its normals and edge list from a list of Nodes and triangles.
125    NodeListp (float **) pointer to nodelist.
126                         This points to the vector of node coordinates.
127                         The copy into SO is done by pointer and *NodeListp
128                         is set to NULL
129                         to keep users on the straight and narrow.
130    N_Node (int) number of nodes
131 
132    FaceSetList (int **) pointer to facesetlist. Assumes triangular mesh
133    N_FaceSet (int) number of triangles
134    nsooptu (SUMA_NEW_SO_OPT *) an options structure to dictate what to do with certain
135                      fields of SO. At the moment, just pass NULL.
136 */
SUMA_NewSO(float ** NodeList,int N_Node,int ** FaceSetList,int N_FaceSet,SUMA_NEW_SO_OPT * nsooptu)137 SUMA_SurfaceObject *SUMA_NewSO ( float **NodeList, int N_Node,
138                                  int **FaceSetList, int N_FaceSet,
139                                  SUMA_NEW_SO_OPT *nsooptu)
140 {
141    static char FuncName[]={"SUMA_NewSO"};
142    SUMA_SurfaceObject *SO = NULL;
143    SUMA_NEW_SO_OPT *nsoopt=NULL;
144    SUMA_Boolean LocalHead = NOPE;
145 
146    SUMA_ENTRY;
147 
148    if (!nsooptu) {
149       nsoopt = SUMA_NewNewSOOpt();
150    } else {
151       nsoopt = nsooptu;
152    }
153 
154    SO = SUMA_Alloc_SurfObject_Struct(1);
155 
156    SO->FileFormat = nsoopt->FileFormat;
157    SO->FileType = nsoopt->FileType;
158 
159    SUMA_LH("NodeList");
160    SO->NodeDim = 3;
161    SO->NodeList = *NodeList; *NodeList = NULL;  /* keeps user from
162                                                    freeing afterwards ... */
163    SO->N_Node = N_Node;
164 
165    if (nsoopt->DoCenter) {
166       SUMA_LH("Center deal")
167       SUMA_DIM_CENTER(SO);
168    } else {
169       SUMA_LH("Skipping Center deal")
170    }
171 
172    if (nsoopt->LargestBoxSize > 0.0) {
173       SUMA_LH("BoxSize deal")
174       SUMA_LARGEST_SIZE_SCALE(SO, nsoopt->LargestBoxSize);
175    } else {
176       SUMA_LH("Skipping BoxSize deal")
177    }
178 
179    SUMA_LH("FaceSetList");
180    SO->FaceSetDim = 3;
181    SO->FaceSetList = *FaceSetList; *FaceSetList = NULL;  /* keeps user from
182                                                             freeing later ... */
183    SO->N_FaceSet = N_FaceSet;
184 
185    if (nsoopt->DoMetrics) {
186       SUMA_LH("Metrics");
187       if (!SUMA_SurfaceMetrics_eng( SO, "EdgeList, MemberFace",
188                                     NULL, 0, SUMAg_CF->DsetList)) {
189          SUMA_SL_Warn(  "Failed to compute metrics\n"
190                         "Returing with whatever is salvageable");
191       }
192    } else {
193       SUMA_LH("Skipping metrics");
194    }
195    if (nsoopt->DoNormals) {
196       SUMA_LH("Normals");
197       SUMA_RECOMPUTE_NORMALS(SO);
198    } else {
199       SUMA_LH("Skipping normals");
200    }
201    SUMA_LH("trimmings");
202    SO->idcode_str = (char *)SUMA_calloc (SUMA_IDCODE_LENGTH, sizeof(char));
203    if (nsoopt->idcode_str) sprintf(SO->idcode_str, "%s", nsoopt->idcode_str);
204    else UNIQ_idcode_fill (SO->idcode_str);
205    if (nsoopt->LocalDomainParentID)
206       SO->LocalDomainParentID = SUMA_copy_string(nsoopt->LocalDomainParentID);
207    else SO->LocalDomainParentID = SUMA_copy_string(SO->idcode_str);
208    if (nsoopt->LocalDomainParent)
209       SO->LocalDomainParent = SUMA_copy_string(nsoopt->LocalDomainParent);
210    else SO->LocalDomainParent = SUMA_copy_string("SAME");
211 
212    /* the stupid copies */
213    if (sizeof(GLfloat) != sizeof(float)) {
214       SUMA_SL_Crit("GLfloat and float have differing sizes!\n");
215       SUMA_RETURN(NOPE); }
216    if (sizeof(GLint) != sizeof(int)) {
217       SUMA_SL_Crit("GLint and int have differing sizes!\n");
218       SUMA_RETURN(NOPE); }
219 
220    SO->glar_NodeList = (GLfloat *)SO->NodeList;
221    SO->glar_FaceSetList = (GLint *) SO->FaceSetList;
222    SO->glar_NodeNormList = (GLfloat *) SO->NodeNormList;
223    SO->glar_FaceNormList = (GLfloat *) SO->FaceNormList;
224 
225    if (LocalHead) SUMA_Print_Surface_Object(SO, NULL);
226 
227    if (nsooptu != nsoopt) {
228       nsoopt=SUMA_FreeNewSOOpt(nsoopt);
229    }
230 
231    SUMA_RETURN(SO);
232 }
233 
234 /*!
235    \brief A function to create a surface that is a child of another.
236            function can also be used to replace NodeList and/or
237            FaceSetList in the same SurfaceObject
238    \param SO (SUMA_SurfaceObject *)
239    \param NodeList (float *): list of node coordinates, SO->NodeDim*N_Node elements long
240    \param N_Node (int) : number of nodes in NodeList
241    \param FaceSetList (int*): list of facesets, SO->FaceSetDim*N_FaceSet element long
242    \param N_FaceSet (int): number of facesets
243    \param replace: (SUMA_Boolean)   YUP = replace NodeList and/or FaceSetList in SO and return SO.
244                                     NOPE = return a new SurfaceObject,
245    \sa SUMA_NewSO
246 DO NOT FREE NodeList and/or FaceSetList upon returning
247 */
SUMA_CreateChildSO(SUMA_SurfaceObject * SO,float * NodeList,int N_Node,int * FaceSetList,int N_FaceSet,SUMA_Boolean replace)248 SUMA_SurfaceObject *SUMA_CreateChildSO(SUMA_SurfaceObject * SO,
249                                        float *NodeList, int N_Node,
250                                        int *FaceSetList, int N_FaceSet,
251                                        SUMA_Boolean replace)
252 {
253    static char FuncName[]={"SUMA_CreateChildSO"};
254    SUMA_SurfaceObject *SOn=NULL;
255    SUMA_Boolean RedoNormals = NOPE, RedoFaces = NOPE;
256    SUMA_Boolean LocalHead = NOPE;
257 
258    SUMA_ENTRY;
259 
260    if (!SO) SUMA_RETURN(NULL);
261    if (!NodeList && !FaceSetList && replace ) {
262       SUMA_SL_Err("Nothing to do");
263    }
264 
265    if (NodeList) {
266       if (N_Node != SO->N_Node) {
267          SUMA_SL_Err("Not ready for partial node lists.\n");
268          SUMA_RETURN(NULL);
269       }
270    }
271 
272    if (replace) { SUMA_LH("Reusing old surface"); SOn = SO; }
273    else { SUMA_LH("New Surface"); SOn =  SUMA_Alloc_SurfObject_Struct(1); }
274 
275    if (NodeList) {
276       if (!replace) {
277          SUMA_LH("New Node List");
278       } else {
279          SUMA_LH("Freeing old node list and setting new one ");
280          if (SOn->NodeList) SUMA_free(SOn->NodeList);
281       }
282       SOn->NodeDim = SO->NodeDim;
283       SOn->NodeList = NodeList; SOn->N_Node = N_Node;
284       SUMA_LH("Recalculating center");
285       SUMA_DIM_CENTER(SOn);
286       RedoNormals = YUP;
287    } else {
288       if (!replace) {
289          if (SOn->NodeList) {
290             SUMA_S_Err("Should not be here");
291             SUMA_RETURN(NULL);
292          }
293          SUMA_LH("Copying old node list");
294          SOn->NodeDim = SO->NodeDim;
295          SOn->N_Node = SO->N_Node;
296          SOn->NodeList = (float *)SUMA_malloc(SOn->N_Node*3*sizeof(float));
297          if (!SOn->NodeList) {
298             SUMA_SL_Crit("Failed to allocate."); SUMA_RETURN(NULL);
299          }
300          SUMA_COPY_VEC(SO->NodeList, SOn->NodeList, SOn->N_Node*3, float, float);
301          RedoNormals = YUP;
302       }
303    }
304 
305    if (FaceSetList) {
306       SUMA_LH("New FaceSet List");
307       if (SOn->FaceSetList) {
308          SUMA_S_Err("Should not be here");
309          SUMA_RETURN(NULL);
310       }
311       SOn->FaceSetList = FaceSetList;
312       SOn->N_FaceSet = N_FaceSet;
313       SOn->FaceSetDim = SO->FaceSetDim;
314       /* Need a new edge list */
315       if (!SUMA_SurfaceMetrics(SOn, "EdgeList, MemberFace", NULL)) {
316          SUMA_SL_Warn(  "Failed to compute metrics\n"
317                         "Returing with whatever is salvageable");
318       }
319       RedoNormals = YUP;
320    } else {
321       if (!replace) {
322          if (SOn->FaceSetList) {
323                   SUMA_S_Err("Should not be here");
324                   SUMA_RETURN(NULL);
325          }
326          SUMA_LH("Copying old FaceSet list");
327          SOn->N_FaceSet = SO->N_FaceSet;
328          SOn->FaceSetDim = SO->FaceSetDim;
329          SOn->FaceSetList =
330             (int *)SUMA_malloc(SOn->N_FaceSet*SOn->FaceSetDim*sizeof(int));
331          if (!SOn->FaceSetList) {
332             SUMA_SL_Crit("Failed to allocate."); SUMA_RETURN(NULL);
333          }
334          SUMA_COPY_VEC( SO->FaceSetList, SOn->FaceSetList,
335                         SOn->N_FaceSet*SOn->FaceSetDim, int, int);
336          RedoNormals = YUP;
337          /* Need to inherit edge list */
338          if (0 &&!SUMA_SurfaceMetrics(SOn, "EdgeList, MemberFace", SO)) {
339             SUMA_SL_Warn(  "Failed to compute metrics\n"
340                            "Returing with whatever is salvageable");
341          }
342       }
343    }
344 
345    if (RedoNormals) {
346       SUMA_LH("Recalculating normals and convexitation");
347       SUMA_RECOMPUTE_NORMALS(SOn);
348       if (0 &&!SUMA_SurfaceMetrics(SOn, "Convexity", SO)) {
349          SUMA_SL_Warn("Failed to compute metrics\n"
350                       "Returing with whatever is salvageable");
351       }
352    }
353 
354    if (!replace) {
355       SUMA_LH("New IDs");
356       SOn->idcode_str = (char *)SUMA_calloc (SUMA_IDCODE_LENGTH, sizeof(char));
357       UNIQ_idcode_fill (SOn->idcode_str);
358       SOn->LocalDomainParentID = SUMA_copy_string(SO->LocalDomainParentID);
359       SOn->Label = SUMA_append_string("cp.", SO->Label);
360    }
361 
362    /* the stupid copies */
363 
364    SOn->glar_NodeList = (GLfloat *)SOn->NodeList;
365    SOn->glar_NodeNormList = (GLfloat *)SOn->NodeNormList;
366    SOn->glar_FaceSetList = (GLint *) SOn->FaceSetList;
367    SOn->glar_FaceNormList = (GLfloat *) SOn->FaceNormList;
368 
369    SUMA_RETURN(SOn);
370 }
SUMA_Cmap_To_SO(SUMA_COLOR_MAP * Cmap,float orig[3],float topright[3],int verb)371 SUMA_SurfaceObject *SUMA_Cmap_To_SO (
372    SUMA_COLOR_MAP *Cmap, float orig[3], float topright[3], int verb)
373 {
374    static char FuncName[]={"SUMA_Cmap_To_SO"};
375    SUMA_SurfaceObject *SO= NULL;
376    int i, i3, i4, in, k;
377    float dh, dw, *hp = NULL;
378    SUMA_SURF_NORM SN;
379    SUMA_Boolean LocalHead = NOPE;
380 
381    SUMA_ENTRY;
382 
383    SUMA_LH("Allocating surface.");
384    SO = SUMA_Alloc_SurfObject_Struct(1);
385    if (!Cmap) { SUMA_SL_Err("No Cmap"); SUMA_RETURN(NULL); }
386    if (!Cmap->N_M[0]) { SUMA_SL_Err("No colours"); SUMA_RETURN(NULL); }
387    if (!SO) { SUMA_SL_Crit("Failed to allocate"); SUMA_RETURN(NULL); }
388 
389    #if 0
390    if (Cmap->frac) {
391       /* DEBUG ONLY */
392       verb = 2;
393       SUMA_SL_Note("DEBUG ONLY, Leaky approach .. ");
394       Cmap = SUMA_Linearize_Color_Map(Cmap, -1);
395    }
396    #endif
397 
398    /* scaling factors */
399    dh = (topright[1] - orig[1]) / Cmap->N_M[0];
400    hp = (float *)SUMA_calloc(Cmap->N_M[0]+1, sizeof(float));
401    if (!hp) {
402       SUMA_SL_Crit("malloc error");
403       SUMA_RETURN(NULL);
404    }
405    hp[0] = 0.0;
406    for (i=0; i<Cmap->N_M[0]; ++i) {
407       if (Cmap->frac) {
408          if (LocalHead)
409             fprintf (SUMA_STDERR, "%s: icol %d, frac=%f\n",
410                FuncName, i,  Cmap->frac[i]);
411          if (Cmap->Sgn >= 0) {
412             hp[i+1] = Cmap->frac[i]/Cmap->frac[Cmap->N_M[0]-1] *
413                         (topright[1] - orig[1]);
414          } else {
415             hp[i+1] = (1.0 +Cmap->frac[i]/Cmap->frac[Cmap->N_M[0]-1]) / 2.0 *
416                         (topright[1] - orig[1]);
417          }
418       } else hp[i+1] = hp[i]+dh;
419    }
420 
421    dw = topright[0] - orig[0];
422    if (dh <= 0 || dw <= 0) {
423       SUMA_SL_Err("Whatchyoutalkinaboutwillis?");
424       SUMA_RETURN(NULL);
425    }
426 
427    SUMA_LH("Allocating surface elements.");
428    /* allocate for the NodeList */
429    SO->FileType = SUMA_CMAP_SO;
430    SO->N_Node = 4 * (Cmap->N_M[0]);
431    SO->N_FaceSet = 2 * Cmap->N_M[0];
432    SO->NodeDim = 3;
433    SO->EmbedDim = 2;
434    SO->FaceSetDim = 3;
435    SO->idcode_str = (char *)SUMA_calloc(SUMA_IDCODE_LENGTH, sizeof(char));
436    SO->NodeList = (float *)SUMA_calloc(SO->N_Node * 3, sizeof(float));
437    SO->FaceSetList = (int *)SUMA_calloc(SO->N_FaceSet * 3,  sizeof(int));
438    SO->PermCol = (GLfloat *)SUMA_calloc(SO->N_Node * 4, sizeof(GLfloat));
439    if (!SO->idcode_str || !SO->NodeList || !SO->FaceSetList || !SO->PermCol) {
440       SUMA_SL_Crit("Failed to allocate");
441       SUMA_RETURN(NULL);
442    }
443 
444    SUMA_LH("Filling up surface id.");
445    /* fill up idcode*/
446    UNIQ_idcode_fill(SO->idcode_str);
447 
448    SUMA_LH("Filling up surface nodelist.");
449    /* fill up coordinates first */
450    i=0;     /* color index */
451    in = 0;  /* node index */
452    i3 = in * 3;
453    while (i < Cmap->N_M[0]) {
454       /* 4 nodes per color */
455       SO->NodeList[i3] =    orig[0];
456       SO->NodeList[i3+1] = hp[i]   + orig[1];
457       SO->NodeList[i3+2] = 0.0;
458                ++in; i3 = in * 3;
459       SO->NodeList[i3] = dw+orig[0];
460       SO->NodeList[i3+1] = hp[i]   + orig[1];
461       SO->NodeList[i3+2] = 0.0;
462                ++in; i3 = in * 3;
463       SO->NodeList[i3] = dw+orig[0];
464       SO->NodeList[i3+1] = hp[i+1] + orig[1];
465       SO->NodeList[i3+2] = 0.0;
466                ++in; i3 = in * 3;
467       SO->NodeList[i3] =    orig[0];
468       SO->NodeList[i3+1] = hp[i+1] + orig[1];
469       SO->NodeList[i3+2] = 0.0;
470                ++in; i3 = in * 3;
471       ++i;
472    }
473 
474    SUMA_LH("Bounding Box");
475    /* Calculate Min, Max, Mean */
476    SUMA_MIN_MAX_SUM_VECMAT_COL ( SO->NodeList, SO->N_Node, SO->NodeDim,
477                                  SO->MinDims, SO->MaxDims, SO->Center);
478 
479    SO->Center[0] /= SO->N_Node;
480    SO->Center[1] /= SO->N_Node;
481    SO->Center[2] /= SO->N_Node;
482 
483    SUMA_MIN_VEC (SO->MinDims, 3, SO->aMinDims );
484    SUMA_MAX_VEC (SO->MaxDims, 3, SO->aMaxDims);
485 
486    SUMA_LH("Filling up surface facesetlist.");
487    /* fill up triangles */
488    i = 0;   /* color index */
489    i4 = 4*i;
490    in = 0;  /* triangle index */
491    i3 = in *3;
492    while (i < Cmap->N_M[0]) {
493       /* 2 triangles per color, 4 nodes per color*/
494       SO->FaceSetList[i3] = i4;
495       SO->FaceSetList[i3+1] = i4+1;
496       SO->FaceSetList[i3+2] = i4+2;
497          ++in; i3 = in *3;
498       SO->FaceSetList[i3] = i4;
499       SO->FaceSetList[i3+1] = i4+2;
500       SO->FaceSetList[i3+2] = i4+3;
501          ++in; i3 = in *3;;
502       ++i; i4 = 4*i;
503    }
504 
505    SUMA_LH("Filling up surface colors.");
506    /* fill up the color vector */
507    i=0; /* color index */
508    in = 0;  /* node index */
509    i4 = in * 4;
510    while (i < Cmap->N_M[0]) {
511       for (k=0; k<4; ++k) {
512          /* 4 nodes per color */
513          SO->PermCol[i4]   = Cmap->M[i][0];
514          SO->PermCol[i4+1] = Cmap->M[i][1];
515          SO->PermCol[i4+2] = Cmap->M[i][2];
516          if (Cmap->N_M[1] == 4) {
517             SO->PermCol[i4+3] = Cmap->M[i][3];
518          } else {
519             SO->PermCol[i4+3] = 1.0;
520          }
521          ++in; i4 = in * 4;
522       }
523       ++i;
524    }
525 
526    /* if verb, write out the results for checking */
527    if (verb > 1) {
528       char *fname;
529       FILE *fout;
530 
531       SUMA_LH("writing out surface.");
532 
533       fname = SUMA_append_string(Cmap->Name, ".1D.NodeList");
534       if (!fname) { SUMA_SL_Err("Failed to create name"); SUMA_RETURN(SO); }
535       fout = fopen(fname,"w");
536       if (fout) {
537          for (i=0; i < SO->N_Node; ++i)
538             fprintf (fout,"%f %f %f\n", SO->NodeList[3*i],
539                         SO->NodeList[3*i+1], SO->NodeList[3*i+2]);
540          fclose(fout); SUMA_free(fname); fname = NULL;
541       } else { SUMA_SL_Err("Failed to write NodeList"); SUMA_RETURN(SO); }
542 
543       fname = SUMA_append_string(Cmap->Name, ".1D.FaceSetList");
544       if (!fname) { SUMA_SL_Err("Failed to create name"); SUMA_RETURN(SO); }
545       fout = fopen(fname,"w");
546       if (fout) {
547          for (i=0; i < SO->N_FaceSet; ++i)
548             fprintf (fout,"%d %d %d\n", SO->FaceSetList[3*i],
549                         SO->FaceSetList[3*i+1], SO->FaceSetList[3*i+2]);
550          fclose(fout); SUMA_free(fname); fname = NULL;
551       } else { SUMA_SL_Err("Failed to write FaceSetList"); SUMA_RETURN(SO); }
552 
553       fname = SUMA_append_string(Cmap->Name, ".1D.col");
554       if (!fname) { SUMA_SL_Err("Failed to create name"); SUMA_RETURN(SO); }
555       fout = fopen(fname,"w");
556       if (fout) {
557          for (i=0; i < SO->N_Node; ++i)
558             fprintf (fout,"%d %f %f %f %f\n", i,
559                   SO->PermCol[4*i], SO->PermCol[4*i+1],
560                   SO->PermCol[4*i+2], SO->PermCol[4*i+3]);
561          fclose(fout); SUMA_free(fname); fname = NULL;
562       } else { SUMA_SL_Err("Failed to write Col file"); SUMA_RETURN(SO); }
563    }
564 
565    /* free hp */
566    if (hp) SUMA_free(hp); hp = NULL;
567 
568    /* some more stuff */
569    SN = SUMA_SurfNorm(SO->NodeList, SO->N_Node, SO->FaceSetList, SO->N_FaceSet );
570    SO->NodeNormList = SN.NodeNormList;
571    SO->FaceNormList = SN.FaceNormList;
572 
573    /* the shameful pointer copies */
574    SO->glar_NodeList = (GLfloat *) SO->NodeList;
575    SO->glar_FaceSetList = (GLint *) SO->FaceSetList;
576    SO->glar_FaceNormList = (GLfloat *) SO->FaceNormList;
577    SO->glar_NodeNormList = (GLfloat *) SO->NodeNormList;
578 
579    SUMA_RETURN(SO);
580 }
581 
582 /*!
583    Create a surface object for the colormap
584    This one creates a surface where successive colors share an edge.
585    This makes the coloring annoying since you need to use flat shading
586    and make sure you colorize the proper nodes
587       (see p172, OpenGL programming guide and
588    NIH-3 lab-book 157. The coloring as implemented here is not correct in that
589    it does not follow the i+2 rule (see OpenGL book ref) but I have decided to
590    create a different surface which has 4 nodes per color and no sharing of
591    nodes/edges for successive colors.
592 
593    See SUMA_Cmap_To_SO
594 */
SUMA_Cmap_To_SO_old(SUMA_COLOR_MAP * Cmap,float orig[3],float topright[3],int verb)595 SUMA_SurfaceObject *SUMA_Cmap_To_SO_old (SUMA_COLOR_MAP *Cmap, float orig[3],
596                                           float topright[3], int verb)
597 {
598    static char FuncName[]={"SUMA_Cmap_To_SO_old"};
599    SUMA_SurfaceObject *SO= NULL;
600    int icol, i, i3, i4;
601    float dh, dw;
602    SUMA_SURF_NORM SN;
603    SUMA_Boolean LocalHead = NOPE;
604 
605    SUMA_ENTRY;
606 
607    SUMA_SL_Err("Function is obsolete.\nUse SUMA_Cmap_To_SO");
608 
609    SUMA_LH("Allocating surface.");
610    SO = SUMA_Alloc_SurfObject_Struct(1);
611    if (!Cmap) { SUMA_SL_Err("No Cmap"); SUMA_RETURN(NULL); }
612    if (!Cmap->N_M[0]) { SUMA_SL_Err("No colours"); SUMA_RETURN(NULL); }
613    if (!SO) { SUMA_SL_Crit("Failed to allocate"); SUMA_RETURN(NULL); }
614 
615    /* scaling factors */
616    dh = (topright[1] - orig[1]) / Cmap->N_M[0];
617    dw = topright[0] - orig[0];
618    if (dh <= 0 || dw <= 0) {
619       SUMA_SL_Err("Whatchyoutalkinaboutwillis?");
620       SUMA_RETURN(NULL);
621    }
622 
623    SUMA_LH("Allocating surface elements.");
624    /* allocate for the NodeList */
625    SO->FileType = SUMA_CMAP_SO;
626    SO->N_Node = 2 * (Cmap->N_M[0] + 1);
627    SO->N_FaceSet = 2 * Cmap->N_M[0];
628    SO->NodeDim = 3;
629    SO->EmbedDim = 2;
630    SO->FaceSetDim = 3;
631    SO->idcode_str = (char *)SUMA_calloc(SUMA_IDCODE_LENGTH, sizeof(char));
632    SO->NodeList = (float *)SUMA_calloc(SO->N_Node * 3, sizeof(float));
633    SO->FaceSetList = (int *)SUMA_calloc(SO->N_FaceSet * 3,  sizeof(int));
634    SO->PermCol = (GLfloat *)SUMA_calloc(SO->N_Node * 4, sizeof(GLfloat));
635    if (!SO->idcode_str || !SO->NodeList || !SO->FaceSetList || !SO->PermCol) {
636       SUMA_SL_Crit("Failed to allocate"); SUMA_RETURN(NULL);
637    }
638 
639    SUMA_LH("Filling up surface id.");
640    /* fill up idcode*/
641    UNIQ_idcode_fill(SO->idcode_str);
642 
643    SUMA_LH("Filling up surface nodelist.");
644    /* fill up coordinates first */
645    /* first fill the oth and the 1st node. They don't follow the cute series */
646    SO->NodeList[0] = orig[0];
647    SO->NodeList[1] = orig[1];
648    SO->NodeList[2] = 0.0;
649    SO->NodeList[3] = dw+orig[0];
650    SO->NodeList[4] = orig[1];
651    SO->NodeList[5] = 0.0;
652 
653    i=2;
654    while (i < SO->N_Node) {
655       /* even i */
656       i3 = i * 3;
657       SO->NodeList[i3] = dw+orig[0];
658       SO->NodeList[i3+1] = i/2 * dh + orig[1];
659       SO->NodeList[i3+2] = 0.0; ++i;
660       /* odd i */
661       i3 = i * 3;
662       SO->NodeList[i3] = orig[0];
663       SO->NodeList[i3+1] = i/2 * dh + orig[1];
664       SO->NodeList[i3+2] = 0.0; ++i;
665    }
666 
667    SUMA_LH("Filling up surface facesetlist.");
668    /* fill up triangles */
669    /* fill up the oth and 1st triangles, they don't follow the cute series */
670    SO->FaceSetList[0] = 0; SO->FaceSetList[1] = 1; SO->FaceSetList[2] = 2;
671    SO->FaceSetList[3] = 2; SO->FaceSetList[4] = 3; SO->FaceSetList[5] = 0;
672 
673    icol = 1;
674    while (icol < Cmap->N_M[0]) {
675       i = 2 * icol;    /* 2 triangles per color */
676       /* first triangle */
677       i3 = i * 3;
678       SO->FaceSetList[i3] = i+1;
679       SO->FaceSetList[i3+1] = i;
680       SO->FaceSetList[i3+2] = i+2;
681       /* second triangle */
682       i3 = (i+1) * 3;
683       SO->FaceSetList[i3] = i+2;
684       SO->FaceSetList[i3+1] = i+3;
685       SO->FaceSetList[i3+2] = i+1;
686       ++icol;
687    }
688 
689    SUMA_LH("Filling up surface colors.");
690    /* fill up the color vector */
691    /* Node 0 is special */
692    SO->PermCol[0] = Cmap->M[0][0]; SO->PermCol[1] = Cmap->M[0][1];
693    SO->PermCol[2] = Cmap->M[0][2]; SO->PermCol[3] = 1.0;
694    /* last node is special */
695    i4 = 4 * (SO->N_Node -1);
696    SO->PermCol[i4  ] = Cmap->M[Cmap->N_M[0]-1][0];
697    SO->PermCol[i4+1] = Cmap->M[Cmap->N_M[0]-1][1];
698    SO->PermCol[i4+2] = Cmap->M[Cmap->N_M[0]-1][2];
699    SO->PermCol[i4+3] = 1.0;
700 
701    i=1;
702    icol = 0;
703    while (i < SO->N_Node -1) {
704       /* Next two get the icolth color */
705       i4 = 4*i;
706       SO->PermCol[i4] = Cmap->M[icol][0];  SO->PermCol[i4+1] = Cmap->M[icol][1];
707       SO->PermCol[i4+2] = Cmap->M[icol][2];SO->PermCol[i4+3] = 1.0;  ++i;
708       i4 = 4*i;
709       SO->PermCol[i4] = Cmap->M[icol][0];  SO->PermCol[i4+1] = Cmap->M[icol][1];
710       SO->PermCol[i4+2] = Cmap->M[icol][2];SO->PermCol[i4+3] = 1.0;  ++i;
711       ++icol;
712    }
713 
714    /* if verb, write out the results for checking */
715    if (verb > 1) {
716       char *fname;
717       FILE *fout;
718 
719       SUMA_LH("writing out surface.");
720 
721       fname = SUMA_append_string(Cmap->Name, ".1D.NodeList");
722       if (!fname) { SUMA_SL_Err("Failed to create name"); SUMA_RETURN(SO); }
723       fout = fopen(fname,"w");
724       if (fout) {
725          for (i=0; i < SO->N_Node; ++i)
726             fprintf (fout,"%f %f %f\n",
727                   SO->NodeList[3*i], SO->NodeList[3*i+1], SO->NodeList[3*i+2]);
728          fclose(fout); SUMA_free(fname); fname = NULL;
729       }else { SUMA_SL_Err("Failed to write NodeList"); SUMA_RETURN(SO); }
730 
731       fname = SUMA_append_string(Cmap->Name, ".1D.FaceSetList");
732       if (!fname) { SUMA_SL_Err("Failed to create name"); SUMA_RETURN(SO); }
733       fout = fopen(fname,"w");
734       if (fout) {
735          for (i=0; i < SO->N_FaceSet; ++i)
736             fprintf (fout,"%d %d %d\n",
737           SO->FaceSetList[3*i], SO->FaceSetList[3*i+1],SO->FaceSetList[3*i+2]);
738          fclose(fout); SUMA_free(fname); fname = NULL;
739       }else { SUMA_SL_Err("Failed to write FaceSetList"); SUMA_RETURN(SO); }
740 
741       fname = SUMA_append_string(Cmap->Name, ".1D.col");
742       if (!fname) { SUMA_SL_Err("Failed to create name"); SUMA_RETURN(SO); }
743       fout = fopen(fname,"w");
744       if (fout) {
745          for (i=0; i < SO->N_Node; ++i)
746             fprintf (fout,"%d %f %f %f\n", i,
747                SO->PermCol[4*i], SO->PermCol[4*i+1], SO->PermCol[4*i+2]);
748          fclose(fout); SUMA_free(fname); fname = NULL;
749       }else { SUMA_SL_Err("Failed to write Col file"); SUMA_RETURN(SO); }
750    }
751 
752    /* some more stuff */
753    SN = SUMA_SurfNorm(SO->NodeList,  SO->N_Node,
754                       SO->FaceSetList, SO->N_FaceSet );
755    SO->NodeNormList = SN.NodeNormList;
756    SO->FaceNormList = SN.FaceNormList;
757 
758    /* the shameful pointer copies */
759    SO->glar_NodeList = (GLfloat *) SO->NodeList;
760    SO->glar_FaceSetList = (GLint *) SO->FaceSetList;
761    SO->glar_FaceNormList = (GLfloat *) SO->FaceNormList;
762    SO->glar_NodeNormList = (GLfloat *) SO->NodeNormList;
763 
764    SUMA_RETURN(SO);
765 }
766 
767 /*!
768    A poor man's function to sniff if a DO file contains spheres or segments
769    Not to be used as a general purpose DO file detector
770 */
SUMA_Guess_DO_Type(char * s)771 SUMA_DO_Types SUMA_Guess_DO_Type(char *s)
772 {
773    static char FuncName[]={"SUMA_Guess_DO_Type"};
774    SUMA_DO_Types dotp = not_DO_type;
775    FILE *fid=NULL;
776    char sbuf[2000];
777    int i;
778    SUMA_Boolean LocalHead = NOPE;
779 
780    SUMA_ENTRY;
781 
782    if (!s) {
783       SUMA_SL_Warn("Query with null file name");
784       SUMA_RETURN(dotp);
785    }
786 
787    if (strstr(s,"<nido_head")) SUMA_RETURN(NIDO_type);
788 
789    if (SUMA_isExtension(s,".niml.tract")) SUMA_RETURN(TRACT_type);
790 
791    fid = fopen(s,"r");
792 
793    if (!fid) {
794       SUMA_SLP_Err("Could not open file %s for reading.\n"
795                    "cwd is set to: %s\n",s, SUMAg_CF->cwd);
796       SUMA_RETURN(dotp);
797    }
798 
799    /* get first 100 chars */
800    i = 0;
801    sbuf[i] = '\0';
802    while (i<100 && !feof(fid)) {
803       sbuf[i] = fgetc(fid);
804       if (feof(fid)) {
805          break;
806       }
807       ++i;
808    }
809    sbuf[i] = '\0';
810 
811    /* check for tags */
812    if (strstr(sbuf,"#spheres")) {
813       dotp = SP_type;
814    } else if (strstr(sbuf,"#node-based_spheres")) {
815       dotp = NBSP_type;
816    } else if (strstr(sbuf,"#segments")) {
817       dotp = LS_type;
818    } else if (strstr(sbuf,"#directions")) {
819       dotp = DIR_type;
820    } else if (strstr(sbuf,"#oriented_directions")) {
821       dotp = ODIR_type;
822    } else if (strstr(sbuf,"#oriented_segments")) {
823       dotp = OLS_type;
824    } else if (strstr(sbuf,"#node-based_segments")) {
825       dotp = NBLS_type;
826    } else if (strstr(sbuf,"#points")) {
827       dotp = PNT_type;
828    } else if (strstr(sbuf,"#node-based_oriented_segments")) {
829       dotp = NBOLS_type;
830    } else if (strstr(sbuf,"#node-based_vectors")) {
831       dotp = NBV_type;
832    } else if (strstr(sbuf,"#node-based_ball-vectors")) {
833       dotp = ONBV_type;
834    } else if (strstr(sbuf,"#planes")) {
835       dotp = PL_type;
836    } else if (strstr(sbuf,"#node_based_text")) {
837       dotp = NBT_type;
838    } else if (strstr(sbuf,"#dicom_based_text")) {
839       dotp = DBT_type;
840    } else if (strstr(sbuf,"#screen_based_text")) {
841       dotp = SBT_type;
842    } else if (strstr(sbuf,"#mask")) {
843       dotp = MASK_type;
844    } else if (strstr(sbuf,"#suma_dset")) { /* this case should not happen */
845       dotp = ANY_DSET_type;
846    } else if (strstr(sbuf,"#suma_md_dset")){/*this case also should not happen*/
847       dotp = MD_DSET_type;
848    } else if (strstr(sbuf,"nido_head")) {
849       dotp = NIDO_type;
850    } else if (strstr(sbuf,"<") || strstr(sbuf,">")) {
851       SUMA_S_Warnv("Bad format likely in niml file %s.\n"
852                    "Could not find element '<nido_head'\n",
853                    s);
854    }
855    if (LocalHead) {
856       fprintf( SUMA_STDERR,
857                "%s: Searched header string:\n>>>%s<<<\ndotp = %d\n",
858                FuncName, sbuf, dotp);
859    }
860 
861    fclose(fid); fid = NULL;
862 
863    SUMA_RETURN(dotp);
864 }
865 
SUMA_isSymMaskDO(char * s,char * mtype)866 SUMA_Boolean SUMA_isSymMaskDO(char *s, char *mtype)
867 {
868    static char FuncName[]={"SUMA_isSymMaskDO"};
869    char sbuf[200];
870 
871    if (!s) return(NOPE);
872    if (!mtype) mtype = (char *)sbuf;
873 
874    SUMA_SymMaskDO(s,mtype, NULL, 1);
875    if (mtype[0] == '\0') return(NOPE);
876    return(YUP);
877 }
878 
SUMA_SymMaskDO(char * s,char * mtype,char * hid,byte mtypeonly)879 SUMA_MaskDO *SUMA_SymMaskDO(char *s, char *mtype, char *hid, byte mtypeonly)
880 {
881    static char FuncName[]={"SUMA_SymMaskDO"};
882    SUMA_MaskDO *mdo=NULL;
883    char *sc=NULL;
884    int i, i3, i4;
885    float cen[3]={0.0, 0.0, 0.0},
886          dim[3]={20.0, 20.0, 20.0},
887          col[4]={1.0, 1.0, 1.0, 1.0},
888          all[12];
889    SUMA_Boolean LocalHead = NOPE;
890 
891    SUMA_ENTRY;
892 
893    if (!s) {
894       SUMA_SL_Warn("Query with null file name");
895       SUMA_RETURN(mdo);
896    }
897 
898    mtype[0] = '\0';
899 
900 
901    /* start with the specialities */
902    if (strcasestr(s,"box")) { /* Have a string defined mask */
903       SUMA_LH("Have box in %s", s);
904       sprintf(mtype,"cube");
905    } else if (strcasestr(s,"sph")) { /* Have a string defined mask */
906       SUMA_LH("Have sphere in %s", s);
907       sprintf(mtype,"ball");
908    } else {
909       SUMA_LH("I don't know nothing");
910       SUMA_RETURN(mdo);
911    }
912 
913    /* Sphere or cube, parse params */
914    sc = SUMA_copy_string(s);
915    if (!strcmp(mtype,"cube") ||
916        !strcmp(mtype,"ball")) {
917       if (SUMA_CleanNumString(sc,(void *)6)) {
918          SUMA_LH("Have X, Y, Z, and all sizes");
919          SUMA_StringToNum(sc, (void*)all, 6, 1);
920          for (i=0; i<3; ++i) cen[i] = all[i];
921          for (i=0; i<3; ++i) dim[i] = all[i+3];
922       } else if (SUMA_CleanNumString(sc,(void *)4)) {
923          SUMA_LH("Have X, Y, Z, and one size");
924          SUMA_StringToNum(sc, (void*)all, 4, 1);
925          for (i=0; i<3; ++i) cen[i] = all[i];
926          for (i=0; i<3; ++i) dim[i] = all[3];
927       } else if (SUMA_CleanNumString(sc,(void *)4)) {
928          SUMA_LH("Have  3 sizes");
929          for (i=0; i<3; ++i) dim[i] = all[i];
930       } else if (SUMA_CleanNumString(sc,(void *)1)) {
931          SUMA_LH("Have one size");
932          for (i=0; i<3; ++i) dim[i] = all[0];
933       } else if (SUMA_CleanNumString(sc,(void *)0)) {
934          SUMA_LH("Have nothing");
935       }
936    } else {
937       SUMA_S_Err("Not ready for mtype %s", mtype);
938       SUMA_ifree(sc); SUMA_RETURN(NULL);
939    }
940 
941    SUMA_ifree(sc);
942    if (mtypeonly) SUMA_RETURN(NULL);
943 
944    /* Now create the mask */
945    SUMA_LH("Creating mask");
946    if (!(mdo = SUMA_Alloc_MaskDO (1, hid, hid, NULL, 1))) {
947       SUMA_S_Err("Failed in SUMA_Allocate_MaskDO.");
948       SUMA_RETURN(NULL);
949    }
950    strcpy(mdo->mtype, mtype);
951 
952    if (!SUMA_AddMaskSaux(mdo)) {
953       SUMA_S_Err("Failed to add Mask Saux");
954       SUMA_RETURN(NULL);
955    }
956 
957    /* fill up mdo */
958    SUMA_LH("Fill up mdo (%d obj)", mdo->N_obj);
959    mdo->dim = 1.0;
960    i = 0;
961    while (i < mdo->N_obj) {/* Have 1 object, for now...*/
962       i3 = 3*i; i4 = 4*i;
963       mdo->cen[i3]   = cen[0];
964       mdo->cen[i3+1] = cen[1];
965       mdo->cen[i3+2] = cen[2];
966       mdo->hdim[i3]  = dim[0];
967       mdo->hdim[i3+1]= dim[1];
968       mdo->hdim[i3+2]= dim[2];
969       mdo->init_col[i4]  = col[0];
970       mdo->init_col[i4+1]= col[1];
971       mdo->init_col[i4+2]= col[2];
972       mdo->init_col[i4+3]= col[3];
973       mdo->dcolv[i4]  = col[0]*mdo->dim;
974       mdo->dcolv[i4+1]= col[1]*mdo->dim;
975       mdo->dcolv[i4+2]= col[2]*mdo->dim;
976       mdo->dcolv[i4+3]= col[3];
977       ++i;
978    }
979 
980    memcpy(mdo->init_cen, mdo->cen, sizeof(float)*3*mdo->N_obj);
981    memcpy(mdo->init_hdim, mdo->hdim, sizeof(float)*3*mdo->N_obj);
982 
983    SUMA_MDO_SetVarName(mdo, NULL);
984    SUMA_RETURN(mdo);
985 }
986 
SUMA_MDO_GetVar(char * vn)987 SUMA_MaskDO *SUMA_MDO_GetVar(char *vn)
988 {
989    static char FuncName[]={"SUMA_MDO_GetVar"};
990    SUMA_MaskDO *mmm=NULL;
991    int i;
992 
993    SUMA_ENTRY;
994 
995    if (!vn) SUMA_RETURN(NULL);
996 
997    for (i=0; i<SUMAg_N_DOv; ++i) {
998       if (iDO_type(i) == MASK_type) {
999          mmm = (SUMA_MaskDO *)iDO_ADO(i);
1000          if (vn[0] == mmm->varname[0]) SUMA_RETURN(mmm);
1001       }
1002    }
1003 
1004    SUMA_RETURN(NULL);
1005 }
1006 
SUMA_MDO_OkVarName(char * this)1007 SUMA_Boolean SUMA_MDO_OkVarName(char *this)
1008 {
1009    static char FuncName[]={"SUMA_MDO_OkVarName"};
1010    if (this && this[0] >= 'a' && this[0] <= 'z' && this[1] == '\0') return(YUP);
1011    return(NOPE);
1012 }
1013 
SUMA_MDO_SetVarName(SUMA_MaskDO * mdo,char * this)1014 SUMA_Boolean SUMA_MDO_SetVarName(SUMA_MaskDO *mdo, char *this)
1015 {
1016    static char FuncName[]={"SUMA_MDO_SetVarName"};
1017    byte arr[256];
1018    int i, ivn;
1019    char vn;
1020    SUMA_MaskDO *mmm=NULL;
1021    SUMA_Boolean LocalHead = NOPE;
1022 
1023    SUMA_ENTRY;
1024 
1025    if (this) {
1026       if (this[0] < 'a' || this[0] > 'z') {
1027          SUMA_S_Err("Bad variable name %s", this);
1028          SUMA_RETURN(NOPE);
1029       }
1030       /* See if variable is in use */
1031       if ((mmm = SUMA_MDO_GetVar(this))) {
1032          /* take it away */
1033          mmm->varname[0] = '\0';
1034       }
1035       mdo->varname[0] = this[0];
1036       mdo->varname[1] = '\0';
1037       /* Reassign new name to mmm */
1038       if (mmm) SUMA_MDO_SetVarName(mmm, NULL);
1039    } else {
1040       SUMA_LH("varname now >%s< for %s",
1041                   mdo->varname, ADO_LABEL((SUMA_ALL_DO *)mdo));
1042       /* mark mdo's varname as available */
1043       mdo->varname[0] = '\0';
1044 
1045       /* mark all used variables */
1046       memset(arr, 0, sizeof(byte)*256);
1047       for (i=0; i<SUMAg_N_DOv; ++i) {
1048          if (iDO_type(i) == MASK_type) {
1049             mmm = (SUMA_MaskDO *)iDO_ADO(i);
1050             vn = mmm->varname[0];
1051             if (vn != '\0') {
1052                ivn = vn - 'a';
1053                if (ivn < 0 || ivn > 'z'-'a') {
1054                   SUMA_S_Err("Bad variable name for mdo %s", iDO_label(i));
1055                } else {
1056                   arr[ivn] = 1;
1057                }
1058             }
1059          }
1060       }
1061 
1062       ivn = 0;
1063       while (arr[ivn] && ivn < 'z'-'a') ++ivn;
1064       if (ivn < 'z'-'a') {
1065          mdo->varname[0] = 'a'+ivn;
1066          mdo->varname[1] = '\0';
1067       }
1068 
1069       SUMA_LH("varname now >%s<", mdo->varname);
1070    }
1071 
1072    SUMA_RETURN(YUP);
1073 }
1074 
SUMA_Set_MaskDO_Color(SUMA_MaskDO * mdo,float * col,float dim)1075 SUMA_Boolean SUMA_Set_MaskDO_Color(SUMA_MaskDO *mdo, float *col, float dim)
1076 {
1077    static char FuncName[]={"SUMA_Set_MaskDO_Color"};
1078    int i, i4;
1079 
1080    SUMA_ENTRY;
1081 
1082    if (!mdo || (!col && dim < 0)) SUMA_RETURN(NOPE);
1083 
1084    if (dim >= 0) mdo->dim = dim;
1085    if (!col) col = mdo->init_col; /* just use first 4 */
1086 
1087    i = 0;
1088    while (i < mdo->N_obj) { /* all will be colored by the same color! */
1089       i4 = 4*i;
1090       mdo->init_col[i4]  = col[0];
1091       mdo->init_col[i4+1]= col[1];
1092       mdo->init_col[i4+2]= col[2];
1093       mdo->init_col[i4+3]= col[3];
1094       mdo->dcolv[i4]  = col[0]*mdo->dim;
1095       mdo->dcolv[i4+1]= col[1]*mdo->dim;
1096       mdo->dcolv[i4+2]= col[2]*mdo->dim;
1097       mdo->dcolv[i4+3]= col[3];
1098       ++i;
1099    }
1100    SUMA_RETURN(YUP);
1101 }
1102 
SUMA_Set_MaskDO_Alpha(SUMA_MaskDO * mdo,float alpha)1103 SUMA_Boolean SUMA_Set_MaskDO_Alpha(SUMA_MaskDO *mdo, float alpha)
1104 {
1105    static char FuncName[]={"SUMA_Set_MaskDO_Alpha"};
1106    int i, i4;
1107 
1108    SUMA_ENTRY;
1109 
1110    if (!mdo || !mdo->dcolv || !mdo->init_col) SUMA_RETURN(NOPE);
1111 
1112    i = 0;
1113    while (i < mdo->N_obj) { /* all will be colored by the same color! */
1114       i4 = 4*i;
1115       mdo->dcolv[i4+3]= alpha;
1116       mdo->init_col[i4+3] = alpha;
1117       ++i;
1118    }
1119    SUMA_RETURN(YUP);
1120 }
1121 
SUMA_Set_MaskDO_Trans(SUMA_MaskDO * mdo,SUMA_TRANS_MODES T)1122 SUMA_Boolean SUMA_Set_MaskDO_Trans(SUMA_MaskDO *mdo, SUMA_TRANS_MODES T)
1123 {
1124    static char FuncName[]={"SUMA_Set_MaskDO_Trans"};
1125    int i, i4;
1126 
1127    SUMA_ENTRY;
1128 
1129    if (!mdo || !mdo->SO) SUMA_RETURN(NOPE);
1130 
1131    mdo->trans = T;
1132    mdo->SO->TransMode = T;
1133 
1134    SUMA_RETURN(YUP);
1135 }
1136 
1137 
SUMA_Set_MaskDO_Dim(SUMA_MaskDO * mdo,float * dim)1138 SUMA_Boolean SUMA_Set_MaskDO_Dim(SUMA_MaskDO *mdo, float *dim)
1139 {
1140    static char FuncName[]={"SUMA_Set_MaskDO_Dim"};
1141    int i, i3;
1142 
1143    SUMA_ENTRY;
1144 
1145    if (!mdo || !dim) SUMA_RETURN(NOPE);
1146 
1147    i = 0;
1148    while (i < mdo->N_obj) {
1149       i3 = 3*i;
1150       mdo->hdim[i3]  = dim[0];
1151       mdo->hdim[i3+1]= dim[1];
1152       mdo->hdim[i3+2]= dim[2];
1153       ++i;
1154    }
1155 
1156    SUMA_RETURN(YUP);
1157 }
1158 
SUMA_Set_MaskDO_InitDim(SUMA_MaskDO * mdo,float * dim)1159 SUMA_Boolean SUMA_Set_MaskDO_InitDim(SUMA_MaskDO *mdo, float *dim)
1160 {
1161    static char FuncName[]={"SUMA_Set_MaskDO_InitDim"};
1162    int i, i3;
1163 
1164    SUMA_ENTRY;
1165 
1166    if (!mdo || !dim) SUMA_RETURN(NOPE);
1167 
1168    i = 0;
1169    while (i < mdo->N_obj) {
1170       i3 = 3*i;
1171       mdo->init_hdim[i3]  = dim[0];
1172       mdo->init_hdim[i3+1]= dim[1];
1173       mdo->init_hdim[i3+2]= dim[2];
1174       ++i;
1175    }
1176 
1177    SUMA_RETURN(YUP);
1178 }
1179 
SUMA_Set_MaskDO_Cen(SUMA_MaskDO * mdo,float * cen)1180 SUMA_Boolean SUMA_Set_MaskDO_Cen(SUMA_MaskDO *mdo, float *cen)
1181 {
1182    static char FuncName[]={"SUMA_Set_MaskDO_Cen"};
1183    int i, i3;
1184 
1185    SUMA_ENTRY;
1186 
1187    if (!mdo || !cen) SUMA_RETURN(NOPE);
1188 
1189    i = 0;
1190    while (i < mdo->N_obj) {
1191       i3 = 3*i;
1192       mdo->cen[i3]  = cen[0];
1193       mdo->cen[i3+1]= cen[1];
1194       mdo->cen[i3+2]= cen[2];
1195       ++i;
1196    }
1197 
1198    SUMA_RETURN(YUP);
1199 }
1200 
SUMA_MDO_New_parent(SUMA_MaskDO * mdo,char * parent,int parent_datum_index)1201 int SUMA_MDO_New_parent(SUMA_MaskDO *mdo, char *parent, int parent_datum_index)
1202 {
1203    if (!mdo) return(0);
1204    SUMA_ifree(mdo->Parent_idcode_str);
1205    if (parent) {
1206       mdo->Parent_idcode_str = SUMA_copy_string(parent);
1207       mdo->Parent_datum_index = parent_datum_index;
1208    } else {
1209       mdo->Parent_datum_index = -1;
1210    }
1211    return(1);
1212 }
1213 
SUMA_MDO_New_Doppel(SUMA_MaskDO * mdo,float * xyz)1214 int SUMA_MDO_New_Doppel(SUMA_MaskDO *mdo, float *xyz)
1215 {
1216    if (!mdo) return(0);
1217    if (!xyz) {
1218       mdo->dodop = 0;
1219       mdo->dopxyz[0] = mdo->dopxyz[1] =  mdo->dopxyz[2] = 0.0;
1220    } else {
1221       mdo->dodop = 1;
1222       mdo->dopxyz[0] = xyz[0];
1223       mdo->dopxyz[1] = xyz[1];
1224       mdo->dopxyz[2] = xyz[2];
1225    }
1226    return(1);
1227 }
1228 
SUMA_MDO_New_Params(SUMA_MaskDO * mdo,float * cen,float * dim,float * col,char * Label,char * Type,float alpha,SUMA_TRANS_MODES tran,float colb)1229 int SUMA_MDO_New_Params(SUMA_MaskDO *mdo, float *cen, float *dim,
1230                         float *col, char *Label, char *Type,
1231                         float alpha, SUMA_TRANS_MODES tran, float colb)
1232 {
1233    static char FuncName[]={"SUMA_MDO_New_Params"};
1234    float off[3], fdim[3], ifdim[3], *idim=NULL;
1235    int i, i3, NewSurf=0, ResendToAfni=0, oldsent = 0;
1236    SUMA_Boolean LocalHead = NOPE;
1237 
1238    SUMA_ENTRY;
1239 
1240    if (!mdo || !(cen || dim || col || Label || Type || alpha >= 0.0 ||
1241                   tran < STM_N_TransModes || colb >=0.0)) SUMA_RETURN(-1);
1242 
1243    if (dim) {
1244       if (!MDO_IS_BOX(mdo) && !MDO_IS_SPH(mdo)) {
1245          SUMA_S_Err("Cannot change dims for type %s", mdo->mtype);
1246          SUMA_RETURN(-2);
1247       }
1248    }
1249 
1250    NewSurf = 0;
1251    ResendToAfni = 0;
1252 
1253    if (Type) {
1254       if (!SUMA_Ok_Sym_MaskDO_Type(Type)) {
1255          SUMA_S_Err("Not ready for type %s", Type);
1256          SUMA_RETURN(-2);
1257       }
1258       snprintf(mdo->mtype, 63, "%s", Type);
1259       if (MDO_IS_SPH(mdo) && !dim) {
1260          fdim[0] = fdim[1] = fdim[2] = mdo->hdim[0];
1261          dim = fdim;
1262          ifdim[0] = ifdim[1] = ifdim[2] = mdo->init_hdim[0];
1263          idim = ifdim;
1264       }
1265       NewSurf = 1;
1266       ResendToAfni = 1;
1267    }
1268 
1269    if (Label) {
1270       SUMA_STRING_REPLACE(mdo->Label, Label);
1271    }
1272    if (cen) {
1273       SUMA_LH("new cen");
1274       if (MDO_IS_BOX(mdo)|| MDO_IS_SPH(mdo)) {
1275          for (i=0; i<3; ++i) {/* offset everything by the center of 1st obj */
1276             off[i] = cen[i] - mdo->init_cen[i];
1277          }
1278          i = 0;
1279          while (i<3*mdo->N_obj) {
1280             mdo->cen[i] = mdo->init_cen[i] + off[0]; ++i;
1281             mdo->cen[i] = mdo->init_cen[i] + off[1]; ++i;
1282             mdo->cen[i] = mdo->init_cen[i] + off[2]; ++i;
1283          }
1284          NewSurf = 1;
1285       } else if (MDO_IS_SURF(mdo)) {
1286          SUMA_S_Warn("Not quite, you cannot revert to initial positions this way"
1287                      "Need at least to store initial center somewhere...");
1288          for (i=0; i<3; ++i) off[i] = cen[i] - mdo->SO->Center[i];
1289          for (i=0; i<mdo->SO->N_Node; ++i) {
1290             i3 = mdo->SO->NodeDim*i;
1291             mdo->SO->NodeList[i3  ] += off[0];
1292             mdo->SO->NodeList[i3+2] += off[1];
1293             mdo->SO->NodeList[i3+3] += off[2];
1294          }
1295          for (i=0; i<3; ++i) mdo->SO->Center[i] = cen[i];
1296       }
1297    }
1298 
1299    if (dim) {
1300       SUMA_LH("new Dim");
1301       NewSurf = 1;
1302       ResendToAfni = 1;
1303       SUMA_Set_MaskDO_Dim(mdo, dim);
1304       if (idim) SUMA_Set_MaskDO_InitDim(mdo, idim);
1305    }
1306 
1307    if (col) {
1308       SUMA_LH("new Col");
1309       NewSurf=1;
1310       ResendToAfni = 1;
1311       SUMA_Set_MaskDO_Color(mdo, col, -1);
1312    }
1313 
1314    if (tran < STM_N_TransModes) {
1315       SUMA_LH("new Trans");
1316       NewSurf=1;
1317       SUMA_Set_MaskDO_Trans(mdo, tran);
1318    }
1319 
1320    if (alpha >= 0.0) {
1321       SUMA_LH("new Trans");
1322       NewSurf=1;
1323       SUMA_Set_MaskDO_Alpha(mdo, alpha);
1324    }
1325    if (colb >= 0.0) {
1326       SUMA_LH("new dim factor");
1327       NewSurf=1;
1328       SUMA_Set_MaskDO_Color(mdo, NULL, colb);
1329    }
1330 
1331    if (mdo->SO) oldsent = mdo->SO->SentToAfni;
1332    if (NewSurf) {
1333       SUMA_LH("new surf");
1334       if (!SUMA_AccessorizeMDO(mdo)) {
1335          SUMA_S_Err("Failed to create SO etc!");
1336          SUMA_RETURN(-1);
1337       }
1338    }
1339    if (!ResendToAfni) mdo->SO->SentToAfni = oldsent;
1340 
1341    SUMA_RETURN(1);
1342 }
1343 
1344 
SUMA_Set_MaskDO_Label(SUMA_MaskDO * mdo,char * lab)1345 SUMA_Boolean SUMA_Set_MaskDO_Label(SUMA_MaskDO *mdo, char *lab)
1346 {
1347    static char FuncName[]={"SUMA_Set_MaskDO_Label"};
1348 
1349    SUMA_ENTRY;
1350 
1351    if (!mdo || !lab) SUMA_RETURN(NOPE);
1352 
1353    SUMA_STRING_REPLACE(mdo->Label, lab);
1354 
1355    SUMA_RETURN(YUP);
1356 }
1357 
SUMA_Set_MaskDO_Type(SUMA_MaskDO * mdo,char * lab)1358 SUMA_Boolean SUMA_Set_MaskDO_Type(SUMA_MaskDO *mdo, char *lab)
1359 {
1360    static char FuncName[]={"SUMA_Set_MaskDO_Type"};
1361 
1362    SUMA_ENTRY;
1363 
1364    if (!mdo || !lab) SUMA_RETURN(NOPE);
1365 
1366    snprintf(mdo->mtype, 63, "%s", lab);
1367 
1368    SUMA_RETURN(YUP);
1369 }
1370 
1371 
SUMA_AccessorizeMDO(SUMA_MaskDO * MDO)1372 SUMA_Boolean SUMA_AccessorizeMDO(SUMA_MaskDO *MDO)
1373 {
1374    static char FuncName[]={"SUMA_AccessorizeMDO"};
1375    SUMA_Boolean LocalHead=NOPE;
1376 
1377    SUMA_ENTRY;
1378 
1379    if (!MDO) {
1380       SUMA_S_Err("No mdo");
1381       SUMA_RETURN(NOPE);
1382    }
1383    if (MDO_IS_BOX(MDO)) {
1384       SUMA_LH("Forming SO for box");
1385       if (MDO->SO) SUMA_Free_Surface_Object(MDO->SO); MDO->SO=NULL;
1386       if (!(MDO->SO = SUMA_box_surface(MDO->hdim, MDO->cen,
1387                                        MDO->dcolv, MDO->N_obj))) {
1388          SUMA_S_Err("Failed to create box SO!");
1389          SUMA_RETURN(NOPE);
1390       }
1391    } else if (MDO_IS_SPH(MDO)) {
1392       if (MDO->N_obj > 1) {
1393          SUMA_S_Warn("Not ready for multi obj, or spheroidal objects.\n"
1394                      "This needs implementing");
1395       }
1396       if (MDO->SO) SUMA_Free_Surface_Object(MDO->SO); MDO->SO=NULL;
1397       if (!(MDO->SO = SUMA_ball_surface(MDO->hdim, MDO->cen,
1398                                        MDO->dcolv, MDO->N_obj))) {
1399          SUMA_S_Err("Failed to create sphere SO!");
1400          SUMA_RETURN(NOPE);
1401       }
1402    } else {
1403       SUMA_S_Err("Type %s not ready for prime time", MDO->mtype);
1404       SUMA_RETURN(NOPE);
1405    }
1406 
1407    MDO->SO->TransMode = MDO->trans;
1408 
1409    SUMA_RETURN(YUP);
1410 }
1411 
SUMA_Ok_Sym_MaskDO_Type(char * mtype)1412 SUMA_Boolean SUMA_Ok_Sym_MaskDO_Type(char *mtype)
1413 {
1414 
1415    if (!mtype) return(NOPE);
1416    if (!strcasecmp(mtype,"box") || !strcasecmp(mtype,"cube")) {
1417       return(YUP);
1418    } else if (!strstr(mtype,"sphere") || !strstr(mtype,"ball")) {
1419       return(YUP);
1420    } else {
1421       return(NOPE);
1422    }
1423 }
1424 
SUMA_Guess_Str_MaskDO_Type(char * s,char * mtype)1425 SUMA_Boolean SUMA_Guess_Str_MaskDO_Type(char *s, char *mtype)
1426 {
1427    static char FuncName[]={"SUMA_Guess_Str_MaskDO_Type"};
1428    FILE *fid=NULL;
1429    char sbuf[2000], *sc=NULL;
1430    int i;
1431    SUMA_Boolean LocalHead = NOPE;
1432 
1433    SUMA_ENTRY;
1434 
1435    if (!s || !mtype) {
1436       SUMA_SL_Warn("Query with null file name");
1437       SUMA_RETURN(NOPE);
1438    }
1439 
1440    mtype[0] = '\0';
1441 
1442    if (SUMA_isSymMaskDO(s,mtype)) SUMA_RETURN(YUP);
1443 
1444    /* Try file name */
1445    fid = fopen(s,"r");
1446 
1447    if (!fid) {
1448       SUMA_SLP_Err("Could not open file %s for reading.\n"
1449                    "cwd is set to: %s\n",s, SUMAg_CF->cwd);
1450       SUMA_RETURN(NOPE);
1451    }
1452 
1453    /* get first 100 chars */
1454    i = 0;
1455    sbuf[i] = '\0';
1456    while (i<100 && !feof(fid)) {
1457       sbuf[i] = fgetc(fid);
1458       if (feof(fid)) {
1459          break;
1460       }
1461       ++i;
1462    }
1463    sbuf[i] = '\0';
1464 
1465    /* check for tags */
1466    if (strstr(sbuf,"#mask-box")) {
1467       sprintf(mtype,"cube");
1468    } else if (strstr(sbuf,"#mask-sphere")) {
1469       sprintf(mtype,"ball");
1470    } else {
1471       SUMA_S_Err("Don't know of %s", sbuf);
1472       SUMA_RETURN(NOPE);
1473    }
1474 
1475    fclose(fid); fid = NULL;
1476 
1477    SUMA_RETURN(YUP);
1478 }
1479 
1480 /*
1481    If idcode_str is NULL, NIDO's idcode is a hash of the label
1482 */
SUMA_Alloc_NIDO(char * idcode_str,char * Label,char * Parent_idcode_str)1483 SUMA_NIDO * SUMA_Alloc_NIDO ( char *idcode_str, char *Label,
1484                               char *Parent_idcode_str)
1485 {
1486    static char FuncName[]={"SUMA_Alloc_NIDO"};
1487    SUMA_NIDO * nido= NULL;
1488    float FontCol[4]={1.0, 0.3, 1.0, 1.0};
1489 
1490    SUMA_ENTRY;
1491 
1492    nido = (SUMA_NIDO *) SUMA_calloc(1,sizeof (SUMA_NIDO));
1493    if (!nido) {
1494       fprintf(stderr,"Error %s: Failed to allocate for nido\n", FuncName);
1495       SUMA_RETURN (nido);
1496    }
1497 
1498    if (Label) nido->Label = SUMA_copy_string(Label);
1499    else nido->Label = SUMA_copy_string("nuda");
1500 
1501    if (idcode_str) nido->idcode_str = SUMA_copy_string(idcode_str);
1502    else nido->idcode_str = UNIQ_hashcode(nido->Label);
1503 
1504    nido->ngr = NI_new_group_element();
1505    NI_rename_group(nido->ngr, "nido_head");
1506 
1507    nido->do_type = NIDO_type;
1508    if (Parent_idcode_str) {
1509       NI_set_attribute(nido->ngr, "Parent_idcode_str", Parent_idcode_str);
1510    } else {
1511       NI_set_attribute(nido->ngr, "Parent_idcode_str", "");
1512    }
1513 
1514    /* setup some default values for NIDOs*/
1515    NI_set_attribute(nido->ngr,"default_font", "helvetica_18");
1516    NI_SET_FLOATv(nido->ngr,"default_color", FontCol,4);
1517 
1518    SUMA_RETURN (nido);
1519 }
1520 
SUMA_free_NIDO(SUMA_NIDO * NIDO)1521 SUMA_NIDO *SUMA_free_NIDO(SUMA_NIDO *NIDO)
1522 {
1523    static char FuncName[]={"SUMA_free_NIDO"};
1524 
1525    SUMA_ENTRY;
1526 
1527    if (!NIDO) SUMA_RETURN(NULL);
1528    if (NIDO->ngr) NI_free_element(NIDO->ngr);
1529    if (NIDO->idcode_str) SUMA_free(NIDO->idcode_str);
1530    if (NIDO->Label) SUMA_free(NIDO->Label);
1531    SUMA_free(NIDO); NIDO = NULL;
1532 
1533    SUMA_RETURN(NIDO);
1534 }
1535 
1536 
1537 /*!
1538  allocate for a segment DO
1539    SDO = SUMA_Alloc_SegmentDO ( N_n, Label)
1540 
1541    \param N_n (int) number of nodes to allocate for n0 and n1.
1542       if N_n > 0  SDO->n0 and n1 (GLfloat *) vector to 3*N_n elements
1543                   to contain the XYZ of nodes n0 and n1.
1544       else SDO->n0 and n1 = NULL
1545    \param Label (char *) label of segment DO. Pass NULL for no labels
1546    \param Parent_idcode_str (char *) Parent surface of SegmentDO.
1547                                      It should not be NULL
1548                                      if the DO is node based
1549    \param NodeBased (int) -1: (old usage) set to 0 if !Parent_idcode_str
1550                                                 1 if Parent_idcode_str
1551                           0: segment ends specified with XYZ coords
1552                           1: One end is specified by node index, second is by XYZ
1553                           2: Both ends are specified by node index.
1554    \returns SDO (SUMA_SegmentDO *)
1555 
1556 */
SUMA_Alloc_SegmentDO(int N_n,char * Label,int oriented,char * Parent_idcode_str,int NodeBased,SUMA_DO_Types type,SUMA_DO_Types Parent_type,char * DrawnDO_variant)1557 SUMA_SegmentDO * SUMA_Alloc_SegmentDO (int N_n, char *Label, int oriented,
1558                                        char *Parent_idcode_str, int NodeBased,
1559                                        SUMA_DO_Types type,
1560                                        SUMA_DO_Types Parent_type,
1561                                        char *DrawnDO_variant)
1562 {
1563    static char FuncName[]={"SUMA_Alloc_SegmentDO"};
1564    SUMA_SegmentDO * SDO= NULL;
1565    char *hs = NULL;
1566 
1567    SUMA_ENTRY;
1568 
1569    SDO = (SUMA_SegmentDO *) SUMA_calloc(1,sizeof (SUMA_SegmentDO));
1570    if (!SDO) {
1571          fprintf(stderr,"Error %s: Failed to allocate for SDO\n", FuncName);
1572          SUMA_RETURN (SDO);
1573    }
1574    if (!DrawnDO_variant) DrawnDO_variant="";
1575    SDO->do_type = type;
1576    SDO->Parent_do_type = Parent_type;
1577    SDO->DrawnDO_variant = SUMA_copy_string(DrawnDO_variant);
1578    if (NodeBased == -1) {
1579       /* backward comaptibility */
1580       if (Parent_idcode_str) NodeBased = 1;
1581       else NodeBased = 0;
1582    }
1583    if (!Parent_idcode_str && NodeBased > 0) {
1584       SUMA_S_Warnv(
1585             "Bad combination! Parent_idcode_str is NULL and NodeBased = %d\n",
1586             NodeBased );
1587    }
1588    if (N_n > 0) {
1589       if (!Parent_idcode_str) { /*  NodeBased must be = 0 */
1590          SDO->NodeBased = 0;
1591          SDO->NodeID = NULL;
1592          SDO->NodeID1 = NULL;
1593          SDO->Parent_idcode_str = NULL;
1594          SDO->n0 = (GLfloat *) SUMA_calloc (3*N_n, sizeof(GLfloat));
1595          SDO->n1 = (GLfloat *) SUMA_calloc (3*N_n, sizeof(GLfloat));
1596          SDO->N_SegNodes = -2; /* Cannot be set */
1597          SDO->N_AllNodes = -2; /* Cannot be set */
1598     } else {
1599          if (NodeBased == 1) {
1600             SDO->NodeBased = 1;
1601             SDO->n0 = NULL;
1602             SDO->n1 = (GLfloat *) SUMA_calloc (3*N_n, sizeof(GLfloat));
1603             SDO->Parent_idcode_str = SUMA_copy_string(Parent_idcode_str);
1604             SDO->NodeID = (int*) SUMA_calloc(N_n, sizeof(int));
1605             SDO->NodeID1 = NULL;
1606             SDO->N_SegNodes = -1;
1607             SDO->N_AllNodes = -1;
1608          } else if (NodeBased == 2) {
1609             SDO->NodeBased = 2;
1610             SDO->n0 = NULL;
1611             SDO->n1 = NULL;
1612             SDO->Parent_idcode_str = SUMA_copy_string(Parent_idcode_str);
1613             SDO->NodeID = (int*) SUMA_calloc(N_n, sizeof(int));
1614             SDO->NodeID1 = (int*) SUMA_calloc(N_n, sizeof(int));
1615             SDO->N_SegNodes = -1;
1616             SDO->N_AllNodes = -1;
1617         }
1618       }
1619 
1620       if (  (!SDO->NodeBased && !(SDO->n0 && SDO->n1)) ||
1621             (SDO->NodeBased == 1 && !(SDO->NodeID && SDO->n1)) ||
1622             (SDO->NodeBased == 2 && !(SDO->NodeID && SDO->NodeID1)) ) {
1623          fprintf(stderr,
1624                   "Error %s: Failed to allocate for SDO->n1 or SDO->n0\n"
1625                   "Have NodeBased = %d, n0=%p, n1=%p, NodeID=%p, NodeID1=%p\n",
1626             FuncName, SDO->NodeBased, SDO->n0, SDO->n1,
1627                       SDO->NodeID, SDO->NodeID1);
1628          if (SDO->n0) SUMA_free (SDO->n0);
1629          if (SDO->n1) SUMA_free (SDO->n1);
1630          if (SDO->NodeID) SUMA_free(SDO->NodeID);
1631          if (SDO->NodeID1) SUMA_free(SDO->NodeID1);
1632          if (SDO->Parent_idcode_str) SUMA_free(SDO->Parent_idcode_str);
1633          if (SDO) SUMA_free (SDO);
1634          SUMA_RETURN (NULL);
1635       }
1636    } else {
1637       SDO->NodeID = NULL;
1638       SDO->NodeID1 = NULL;
1639       SDO->NodeBased = 0;
1640       SDO->Parent_idcode_str = NULL;
1641       SDO->n0 = NULL;
1642       SDO->n1 = NULL;
1643       SDO->N_n = 0;
1644       SDO->N_SegNodes = -1;
1645       SDO->N_AllNodes = -1;
1646      }
1647 
1648    /* create a string to hash an idcode */
1649    if (Label) hs = SUMA_copy_string(Label);
1650    else hs = SUMA_copy_string("NULL_");
1651    if (Parent_idcode_str)
1652       hs = SUMA_append_replace_string(hs,Parent_idcode_str,"_",1);
1653    else hs = SUMA_append_replace_string(hs,"NULL","",1);
1654    SDO->idcode_str = UNIQ_hashcode(hs);
1655    SUMA_free(hs); hs = NULL;
1656 
1657    if (Label) {
1658       SDO->Label = (char *)SUMA_calloc (strlen(Label)+1, sizeof(char));
1659       SDO->Label = strcpy (SDO->Label, Label);
1660    } else {
1661       SDO->Label = NULL;
1662    }
1663 
1664    SDO->N_n = N_n;
1665    SDO->Stipple = SUMA_SOLID_LINE;
1666    /* setup some default values */
1667    SDO->LineWidth = 4.0;
1668    SDO->LineCol[0] = 1.0; SDO->LineCol[1] = 0.3;
1669    SDO->LineCol[2] = 1.0; SDO->LineCol[3] = 1.0;
1670 
1671    SDO->colv = NULL;
1672    SDO->thickv = NULL;
1673    SDO->stipv = NULL;
1674    SDO->Mstip = 1;
1675    SDO->stip = 0xAAAA;
1676 
1677    SDO->topobj = NULL;
1678    if (oriented) {
1679       SDO->botobj = gluNewQuadric();
1680    } else SDO->botobj = NULL;
1681 
1682    SUMA_RETURN (SDO);
1683 }
1684 
1685 
SUMA_Alloc_MaskDO(int N_n,char * Label,char * label_for_hash,char * Parent_idcode_str,int withcol)1686 SUMA_MaskDO * SUMA_Alloc_MaskDO (int N_n, char *Label, char *label_for_hash,
1687                                  char *Parent_idcode_str, int withcol)
1688 {
1689    static char FuncName[]={"SUMA_Alloc_MaskDO"};
1690    SUMA_MaskDO * MDO= NULL;
1691    char *hs = NULL;
1692 
1693    SUMA_ENTRY;
1694 
1695    MDO = (SUMA_MaskDO *) SUMA_calloc(1,sizeof (SUMA_MaskDO));
1696    if (!MDO) {
1697          fprintf(stderr,"Error %s: Failed to allocate for MDO\n", FuncName);
1698          SUMA_RETURN (MDO);
1699    }
1700    MDO->do_type = MASK_type;
1701    MDO->dcolv = NULL;
1702    MDO->init_col = NULL;
1703    MDO->dim = 0.5;
1704    MDO->N_obj = N_n;
1705    if (Parent_idcode_str)
1706       MDO->Parent_idcode_str = SUMA_copy_string(Parent_idcode_str);
1707    if (N_n > 0) {
1708       MDO->cen =(float *)SUMA_calloc (3*N_n, sizeof(float));
1709       MDO->hdim =(float *)SUMA_calloc (3*N_n, sizeof(float));
1710       MDO->init_cen =(float *)SUMA_calloc (3*N_n, sizeof(float));
1711       MDO->init_hdim =(float *)SUMA_calloc (3*N_n, sizeof(float));
1712       if (withcol) {
1713          MDO->dcolv = (GLfloat *)SUMA_calloc (4*N_n, sizeof(GLfloat));
1714          MDO->init_col = (float *)SUMA_calloc (4*N_n, sizeof(float));
1715       }
1716    }
1717 
1718    /* create a string to hash an idcode */
1719    if (label_for_hash) hs = SUMA_copy_string(label_for_hash);
1720    else if (Label) hs = SUMA_copy_string(Label);
1721    else hs = SUMA_copy_string("NULL_");
1722    if (Parent_idcode_str)
1723       hs = SUMA_append_replace_string(hs,Parent_idcode_str,"_",1);
1724    else hs = SUMA_append_replace_string(hs,"NULL","",1);
1725    MDO->idcode_str = UNIQ_hashcode(hs);
1726    SUMA_free(hs); hs = NULL;
1727 
1728    if (Label) {
1729       MDO->Label = (char *)SUMA_calloc (strlen(Label)+1, sizeof(char));
1730       MDO->Label = strcpy (MDO->Label, Label);
1731    } else {
1732       MDO->Label = NULL;
1733    }
1734 
1735    MDO->trans = STM_8;
1736    MDO->dodop = 0;
1737    MDO->dopxyz[0] = MDO->dopxyz[1] = MDO->dopxyz[2] = 0;
1738    MDO->Parent_datum_index = -1;
1739 
1740    SUMA_RETURN (MDO);
1741 }
1742 
SUMA_free_MaskDO(SUMA_MaskDO * MDO)1743 void SUMA_free_MaskDO (SUMA_MaskDO * MDO)
1744 {
1745    static char FuncName[]={"SUMA_free_MaskDO"};
1746    SUMA_ENTRY;
1747    if (MDO) {
1748       SUMA_ifree(MDO->cen); SUMA_ifree(MDO->hdim);
1749       SUMA_ifree(MDO->init_cen); SUMA_ifree(MDO->init_hdim);
1750       SUMA_ifree(MDO->Label); SUMA_ifree(MDO->Parent_idcode_str);
1751       SUMA_ifree(MDO->idcode_str);
1752       if (MDO->SO) SUMA_Free_Surface_Object(MDO->SO);
1753       SUMA_ifree(MDO->init_col);
1754       SUMA_ifree(MDO->dcolv);
1755       SUMA_free(MDO); MDO = NULL;
1756    }
1757    SUMA_RETURNe;
1758 }
1759 
1760 /* Set the number of unique points in a segment DO.
1761    if N is provided and is >= 0, them SDO->N_SegNodes is set to N
1762    and the function returns
1763    Otherwise, the function will figure out the number of unique points
1764    if possible, and if SDO->N_SegNodes is not = -2. A value of
1765    SDO->N_SegNodes = -2 is meant to flag that no attempt should
1766    be made to compute N_SegNodes.
1767 */
SUMA_Set_N_SegNodes_SegmentDO(SUMA_SegmentDO * SDO,int N)1768 int SUMA_Set_N_SegNodes_SegmentDO(SUMA_SegmentDO * SDO, int N)
1769 {
1770    static char FuncName[]={"SUMA_Set_N_SegNodes_SegmentDO"};
1771    int *uu=NULL, *uus=NULL;
1772 
1773    SUMA_ENTRY;
1774 
1775    if (!SDO) SUMA_RETURN(-2); /* error */
1776 
1777    if (SDO->N_SegNodes < -1) { /* flagged as not feasible, don't bother */
1778       SUMA_RETURN(SDO->N_SegNodes);
1779    }
1780    if (!SDO->NodeID && !SDO->NodeID1) { /* nothing possible */
1781       SDO->N_SegNodes = -2; SUMA_RETURN(SDO->N_SegNodes);
1782    }
1783    if (N >= 0) { /* use it, no questions asked */
1784       SDO->N_SegNodes = N; SUMA_RETURN(SDO->N_SegNodes);
1785    }
1786    if (SDO->N_SegNodes >= 0) { /* don't bother anew, return existing answer */
1787       SUMA_RETURN(SDO->N_SegNodes);
1788    }
1789 
1790    /* Now we need to figure things out here */
1791    if (!SDO->NodeID && SDO->NodeID1) {
1792       uu = SUMA_UniqueInt(SDO->NodeID1, SDO->N_n, &(SDO->N_SegNodes), 0);
1793       SUMA_ifree(uu);
1794       SUMA_RETURN(SDO->N_SegNodes);
1795    } else if (SDO->NodeID && !SDO->NodeID1) {
1796       uu = SUMA_UniqueInt(SDO->NodeID, SDO->N_n, &(SDO->N_SegNodes), 0);
1797       SUMA_ifree(uu);
1798       SUMA_RETURN(SDO->N_SegNodes);
1799    } else { /* Both are set */
1800       if (!(uu = (int *)SUMA_malloc(SDO->N_n*2 * sizeof(int)))) {
1801          SUMA_S_Crit("Failed to allocate");
1802          SDO->N_SegNodes = -2;
1803          SUMA_RETURN(SDO->N_SegNodes);
1804       }
1805       memcpy(uu, SDO->NodeID, SDO->N_n*sizeof(int));
1806       memcpy(uu+SDO->N_n, SDO->NodeID1, SDO->N_n*sizeof(int));
1807       uus = SUMA_UniqueInt(uu, 2*SDO->N_n, &(SDO->N_SegNodes), 0);
1808       SUMA_ifree(uus); SUMA_ifree(uu);
1809       SUMA_RETURN(SDO->N_SegNodes);
1810    }
1811    /* should not get here */
1812    SDO->N_SegNodes = -2;
1813    SUMA_RETURN(SDO->N_SegNodes);
1814 }
1815 
SUMA_Set_N_AllNodes_SegmentDO(SUMA_SegmentDO * SDO,int N)1816 int SUMA_Set_N_AllNodes_SegmentDO(SUMA_SegmentDO * SDO, int N)
1817 {
1818    static char FuncName[]={"SUMA_Set_N_AllNodes_SegmentDO"};
1819    int *uu=NULL, *uus=NULL;
1820    SUMA_DSET *dset=NULL;
1821 
1822    SUMA_ENTRY;
1823 
1824    if (!SDO) SUMA_RETURN(-2); /* error */
1825 
1826    if (SDO->N_AllNodes < -1) { /* flagged as not feasible, don't bother */
1827       SUMA_RETURN(SDO->N_AllNodes);
1828    }
1829    if (!SDO->NodeID && !SDO->NodeID1) { /* nothing possible */
1830       SDO->N_AllNodes = -2; SUMA_RETURN(SDO->N_AllNodes);
1831    }
1832    if (N >= 0) { /* use it, no questions asked */
1833       SDO->N_AllNodes = N; SUMA_RETURN(SDO->N_AllNodes);
1834    }
1835    if (SDO->N_AllNodes >= 0) { /* don't bother anew, return existing answer */
1836       SUMA_RETURN(SDO->N_AllNodes);
1837    }
1838 
1839    /* Now we need to figure things out here */
1840    if (!(dset = SUMA_find_GLDO_Dset(
1841                   (SUMA_GraphLinkDO *)SUMA_whichADOg(SDO->Parent_idcode_str)))) {
1842          SUMA_S_Err("Could not find dset for GLDO!");
1843          SDO->N_AllNodes = -2; SUMA_RETURN(SDO->N_AllNodes);
1844    }
1845    if (!SUMA_GDSET_GetPointIndexColumn(dset,
1846                                        &(SDO->N_AllNodes), NULL)) {
1847       SDO->N_AllNodes = -2; SUMA_RETURN(SDO->N_AllNodes);
1848    } else { /* all good */
1849       SUMA_RETURN(SDO->N_AllNodes);
1850    }
1851 
1852    /* should not get here */
1853    SDO->N_AllNodes = -2;
1854    SUMA_RETURN(SDO->N_AllNodes);
1855 }
1856 
SUMA_free_SegmentDO(SUMA_SegmentDO * SDO)1857 void SUMA_free_SegmentDO (SUMA_SegmentDO * SDO)
1858 {
1859    static char FuncName[]={"SUMA_free_SegmentDO"};
1860 
1861    SUMA_ENTRY;
1862 
1863    if (!SDO) SUMA_RETURNe;
1864    if (SDO->Parent_idcode_str) SUMA_free(SDO->Parent_idcode_str);
1865    if (SDO->NodeID) SUMA_free(SDO->NodeID);
1866    if (SDO->NodeID1) SUMA_free(SDO->NodeID1);
1867    if (SDO->n0) SUMA_free(SDO->n0);
1868    if (SDO->n1) SUMA_free(SDO->n1);
1869    if (SDO->idcode_str) SUMA_free(SDO->idcode_str);
1870    if (SDO->Label) SUMA_free(SDO->Label);
1871    if (SDO->thickv) SUMA_free(SDO->thickv);
1872    if (SDO->stipv) SUMA_free(SDO->stipv);
1873    if (SDO->colv) {
1874       switch (SDO->Parent_do_type) {
1875          case GRAPH_LINK_type:
1876             /* do nothing, it is a copy from the color list */
1877             SDO->colv = NULL;
1878             break;
1879          default:
1880             SUMA_free(SDO->colv); SDO->colv = NULL;
1881             break;
1882       }
1883    }
1884    if (SDO->botobj) gluDeleteQuadric(SDO->botobj);
1885    if (SDO->topobj) gluDeleteQuadric(SDO->topobj);
1886    if (SDO) SUMA_free(SDO);
1887 
1888    SUMA_RETURNe;
1889 }
1890 
1891 /* Create a blank NIDO header
1892    If idcode_str is NULL, the Label, determines the
1893    idcode_str. */
SUMA_BlankNIDO(char * idcode_str,char * Label,char * parent_so_id,char * coord_type,char * font_name)1894 SUMA_NIDO *SUMA_BlankNIDO (char *idcode_str, char *Label,
1895                            char *parent_so_id, char *coord_type,
1896                            char *font_name)
1897 {
1898    static char FuncName[]={"SUMA_BlankNIDO"};
1899    SUMA_NIDO *nido = NULL;
1900 
1901    SUMA_ENTRY;
1902 
1903    nido = SUMA_Alloc_NIDO(idcode_str, Label, parent_so_id);
1904 
1905    if (parent_so_id) {
1906       NI_set_attribute(nido->ngr, "bond", "surface");
1907    }
1908    NI_set_attribute( nido->ngr, "coord_type",
1909                      SUMA_CoordTypeName(SUMA_CoordType(coord_type)));
1910    NI_set_attribute(nido->ngr, "default_font",
1911                     SUMA_glutBitmapFontName(SUMA_glutBitmapFont(font_name)));
1912    NI_set_attribute(nido->ngr, "default_color",
1913                     "1.0 1.0 1.0 1.0");
1914 
1915    SUMA_RETURN(nido);
1916 }
1917 
SUMA_ReadNIDO(char * fname,char * parent_so_id)1918 SUMA_NIDO *SUMA_ReadNIDO (char *fname, char *parent_so_id)
1919 {
1920    static char FuncName[]={"SUMA_ReadNIDO"};
1921    SUMA_NIDO *nido = NULL;
1922    char *niname=NULL, *atr = NULL;
1923    float col[4];
1924    NI_element *nini=NULL;
1925    NI_stream ns=NULL;
1926    SUMA_Boolean LocalHead = NOPE;
1927 
1928 
1929    SUMA_ENTRY;
1930 
1931    if (!fname) SUMA_RETURN(NULL);
1932 
1933    if ((atr = strstr(fname,"<nido_head"))) {
1934       /* The fname is the nido */
1935       niname = SUMA_copy_string("str:");
1936       ns = NI_stream_open(niname, "r");
1937       NI_stream_setbuf( ns , atr ) ;
1938    } else if (SUMA_GuessFormatFromExtension(fname, NULL)==SUMA_NIML) {
1939       niname = SUMA_append_string("file:", fname);
1940       ns = NI_stream_open(niname, "r");
1941    } else {
1942       SUMA_S_Err("Only .niml.do format accepted");
1943       SUMA_RETURN(NULL);
1944    }
1945    {
1946       while ((nini = NI_read_element(ns, 1))) {
1947          if (SUMA_iswordin(nini->name,"nido_head")) {/* fill special fields */
1948             if (nido) {
1949                SUMA_S_Err("Not ready for a second header!");
1950                SUMA_RETURN(NULL);
1951             } else { /* time to create */
1952                /* is there an SO_label? */
1953                if ((atr = NI_get_attribute(nini,"SO_label"))) {
1954                   /* try to get parent */
1955                }
1956                atr = NI_get_attribute(nini,"bond");
1957                if (atr && atr[0] == 's' && !parent_so_id) {
1958                   SUMA_S_Err( "No surface available to which\n"
1959                               "the NIDO can bond");
1960                   SUMA_RETURN(NULL);
1961                }
1962                nido = SUMA_Alloc_NIDO(
1963                         NI_get_attribute(nini,"idcode_str"),
1964                         fname, parent_so_id);
1965                NI_set_attribute(nido->ngr, "bond", atr);
1966             }
1967             if ((atr = NI_get_attribute(nini,"render_mode"))) {
1968                NI_set_attribute(nido->ngr, "render_mode", atr);
1969             }
1970             if ((atr = NI_get_attribute(nini,"coord_type"))) {
1971                if (SUMA_CoordType(atr) != SUMA_COORD_TYPE_ERROR) {
1972                   NI_set_attribute(nido->ngr, "coord_type", atr);
1973                } else {
1974                   SUMA_S_Errv("coord_type attribute (%s) must be one of\n"
1975                               "local or screen, using default %s\n",
1976                               atr, SUMA_CoordTypeName(SUMA_CoordType(NULL)));
1977                   NI_set_attribute( nido->ngr,
1978                                     "coord_type",
1979                                     SUMA_CoordTypeName(SUMA_CoordType(NULL)));
1980                }
1981             } else {
1982                SUMA_LH("Defaulting to coord_type = world");
1983                NI_set_attribute( nido->ngr, "coord_type",
1984                                  SUMA_CoordTypeName(SUMA_CoordType(NULL)));
1985             }
1986             if ((atr = NI_get_attribute(nini,"default_font"))) {
1987                if (SUMA_glutBitmapFont(atr)) {
1988                   NI_set_attribute(nido->ngr, "default_font", atr);
1989                } else {
1990                   SUMA_S_Errv("default_font %s not found.\n"
1991                               "Defaulting to %s \n", atr,
1992                            SUMA_glutBitmapFontName(SUMA_glutBitmapFont(NULL)));
1993                   NI_set_attribute(nido->ngr, "default_font",
1994                            SUMA_glutBitmapFontName(SUMA_glutBitmapFont(NULL)));
1995                }
1996             } else {
1997                SUMA_LHv("Defaulting to font %s\n",
1998                         SUMA_glutBitmapFontName(SUMA_glutBitmapFont(NULL)));
1999                NI_set_attribute(nido->ngr, "default_font",
2000                         SUMA_glutBitmapFontName(SUMA_glutBitmapFont(NULL)));
2001             }
2002             if ((atr = NI_get_attribute(nini,"default_color"))) {
2003                NI_GET_FLOATv(nini, "default_color", col, 4, LocalHead);
2004                if (NI_GOT) {
2005                   NI_set_attribute(nido->ngr, "default_color", atr);
2006                } else {
2007                   SUMA_S_Errv("default_color %s not found.\n"
2008                               "Defaulting to default_color = 1 1 1 1\n", atr);
2009                   NI_set_attribute(nido->ngr, "default_color",
2010                                               "1.0 1.0 1.0 1.0");
2011                }
2012             } else {
2013                SUMA_LH("Defaulting to default_color = 1 1 1 1");
2014                NI_set_attribute(nido->ngr, "default_color", "1.0 1.0 1.0 1.0");
2015             }
2016          } else {
2017             if (!nido) {
2018                SUMA_S_Err("Found element before header!");
2019                SUMA_RETURN(NOPE);
2020             }
2021             NI_add_to_group(nido->ngr, nini);
2022             if (LocalHead) SUMA_ShowNel(nini);
2023          }
2024       }
2025       NI_stream_close( ns ) ; ns = NULL;
2026       SUMA_free(niname); niname=NULL;
2027       if (LocalHead) SUMA_ShowNel(nido->ngr);
2028    }
2029    SUMA_RETURN(nido);
2030 }
2031 
SUMA_ReadNBVecDO(char * s,int oriented,char * parent_SO_id)2032 SUMA_SegmentDO * SUMA_ReadNBVecDO (char *s, int oriented, char *parent_SO_id)
2033 {
2034    static char FuncName[]={"SUMA_ReadNBVecDO"};
2035    SUMA_SegmentDO *SDO = NULL;
2036    MRI_IMAGE * im = NULL;
2037    float *far=NULL;
2038    int itmp, itmp2, icol_thick = -1, icol_col=-1, icol_id = -1, icol_vec = -1;
2039    int nrow=-1, ncol=-1;
2040    SUMA_DO_Types dotp;
2041    char buf[30];
2042 
2043    SUMA_ENTRY;
2044 
2045    if (!s) {
2046       SUMA_SLP_Err("NULL s");
2047       SUMA_RETURN(NULL);
2048    }
2049 
2050    if (!parent_SO_id) {
2051       SUMA_SLP_Err("NULL parent_SO_id");
2052       SUMA_RETURN(NULL);
2053    }
2054    im = mri_read_1D (s);
2055 
2056    if (!im) {
2057       SUMA_SLP_Err("Failed to read 1D file");
2058       SUMA_RETURN(NULL);
2059    }
2060 
2061    if (oriented) {
2062       sprintf(buf,"Oriented Node-Based Vectors");
2063       dotp = ONBV_type;
2064    } else {
2065       dotp = NBV_type;
2066       sprintf(buf,"Bottomless Node-Based Vector ");
2067    }
2068    far = MRI_FLOAT_PTR(im);
2069    ncol = im->nx;
2070    nrow = im->ny;
2071 
2072    if (!ncol) {
2073       SUMA_SLP_Err("Empty file");
2074       SUMA_RETURN(NULL);
2075    }
2076 
2077    icol_col = -1;
2078    icol_thick = -1;
2079    icol_id = -1;
2080    icol_vec = -1;
2081    switch (nrow) {
2082       case 3:
2083          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2084                               "vx vy vz\n",
2085                               FuncName, buf, s);
2086          icol_vec = 0;
2087          break;
2088       case 4:
2089          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2090                               "n vx vy vz\n",
2091                               FuncName, buf, s);
2092          icol_id = 0;
2093          icol_vec = 1;
2094          break;
2095       case 5:
2096          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2097                               "n vx vy vz th\n",
2098                               FuncName, buf, s);
2099          icol_id = 0;
2100          icol_vec = 1;
2101          icol_thick = 4;
2102          break;
2103       case 8:
2104          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2105                               "n vx vy vz c0 c1 c2 c3\n",
2106                               FuncName, buf, s);
2107 
2108          icol_id = 0;
2109          icol_vec = 1;
2110          icol_col = 4;
2111          break;
2112       case 9:
2113          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2114                               "n vx vy vz c0 c1 c2 c3 th\n",
2115                               FuncName, buf, s);
2116 
2117          icol_id = 0;
2118          icol_vec = 1;
2119          icol_col = 4;
2120          icol_thick = 8;
2121          break;
2122       default:
2123          SUMA_SLP_Err("File must have\n"
2124                    "3,4,5,8 or 9 columns.");
2125          mri_free(im); im = NULL;   /* done with that baby */
2126          SUMA_RETURN(NULL);
2127    }
2128 
2129    /* allocate for segments DO */
2130    SDO = SUMA_Alloc_SegmentDO (ncol, s, oriented, parent_SO_id, 1,
2131                                dotp, SO_type, NULL);
2132    if (!SDO) {
2133       fprintf(SUMA_STDERR,
2134                      "Error %s: Failed in SUMA_Allocate_SegmentDO.\n", FuncName);
2135       SUMA_RETURN(NULL);
2136    }
2137 
2138    /* fill up SDO */
2139    itmp = 0;
2140    while (itmp < SDO->N_n) {
2141       itmp2 = 3*itmp;
2142       SDO->n1[itmp2]   = far[itmp+(icol_vec  )*ncol];
2143       SDO->n1[itmp2+1] = far[itmp+(icol_vec+1)*ncol];
2144       SDO->n1[itmp2+2] = far[itmp+(icol_vec+2)*ncol];
2145       ++itmp;
2146    }
2147 
2148    if (icol_id >= 0) {
2149       itmp = 0;
2150       while (itmp < SDO->N_n) {
2151          SDO->NodeID[itmp]   = far[itmp+(icol_id  )*ncol];
2152          ++itmp;
2153       }
2154    } else {
2155       itmp = 0;
2156       while (itmp < SDO->N_n) {
2157          SDO->NodeID[itmp]   = itmp;
2158          ++itmp;
2159       }
2160    }
2161 
2162    if (icol_col > 0) {
2163       SDO->colv = (GLfloat *)SUMA_malloc(4*sizeof(GLfloat)*SDO->N_n);
2164       if (!SDO->colv) {
2165          SUMA_SL_Crit("Failed in to allocate for colv.");
2166          SUMA_RETURN(NULL);
2167       }
2168       /* fill up idividual colors */
2169       itmp = 0;
2170       while (itmp < SDO->N_n) {
2171          itmp2 = 4*itmp;
2172          SDO->colv[itmp2]     = far[itmp+(icol_col  )*ncol];
2173          SDO->colv[itmp2+1]   = far[itmp+(icol_col+1)*ncol];
2174          SDO->colv[itmp2+2]   = far[itmp+(icol_col+2)*ncol];
2175          SDO->colv[itmp2+3]   = far[itmp+(icol_col+3)*ncol];
2176          ++itmp;
2177       }
2178    }
2179    if (icol_thick > 0) {
2180       SDO->thickv = (GLfloat *)SUMA_malloc(sizeof(GLfloat)*SDO->N_n);
2181       if (!SDO->thickv) {
2182          SUMA_SL_Crit("Failed in to allocate for colv.");
2183          SUMA_RETURN(NULL);
2184       }
2185       /* fill up idividual thickness */
2186       itmp = 0;
2187       while (itmp < SDO->N_n) {
2188          SDO->thickv[itmp]     = far[itmp+(icol_thick  )*ncol];
2189          ++itmp;
2190       }
2191    }
2192 
2193    mri_free(im); im = NULL; far = NULL;
2194 
2195    SUMA_RETURN(SDO);
2196 }
2197 
SUMA_int_to_stipplemask(int i)2198 GLushort SUMA_int_to_stipplemask(int i)
2199 {
2200    switch (i) {
2201       case 0:
2202          return(0xFFFF); /* solid */
2203       case 1:
2204          return(0x0101); /* dotted */
2205       case 2:
2206          return(0xAAAA);
2207       case 3:
2208          return(0x0C0F);
2209       case 4:
2210          return(0x00FF);
2211       case 5:
2212          return(0x1C47); /* dash dot dash */
2213       default:
2214          return(0x0101);
2215    }
2216    return(0xFFFF);
2217 }
2218 
2219 /* eventually make this return a much finer
2220 gradation of dottiness, no worries about
2221 ugly randomness here */
SUMA_int_to_stipplemask_cont(int i)2222 GLushort SUMA_int_to_stipplemask_cont(int i)
2223 {
2224    switch (i) {
2225       case 0:
2226          return(0xFFFF); /* solid */
2227       case 1:
2228          return(0x0101); /* dotted */
2229       case 2:
2230          return(0xAAAA);
2231       case 3:
2232          return(0x0C0F);
2233       case 4:
2234          return(0x00FF);
2235       case 5:
2236          return(0x1C47); /* dash dot dash */
2237       default:
2238          return(0x0101);
2239    }
2240    return(0xFFFF);
2241 }
2242 
SUMA_ReadDirDO(char * s,int oriented,char * parent_SO_id)2243 SUMA_SegmentDO * SUMA_ReadDirDO (char *s, int oriented, char *parent_SO_id)
2244 {
2245    static char FuncName[]={"SUMA_ReadDirDO"};
2246    SUMA_SegmentDO *SDO = NULL;
2247    MRI_IMAGE * im = NULL;
2248    float *far=NULL, gn, or[3];
2249    int itmp, itmp2, icol_thick = -1, icol_col=-1, icol_stip=-1,
2250          icol_orig = -1, icol_dir = -1, icol_amp = -1;
2251    int nrow=-1, ncol=-1, same = 0;
2252    char buf[30];
2253    SUMA_DO_Types dotp;
2254 
2255    SUMA_ENTRY;
2256 
2257    if (!s) {
2258       SUMA_SLP_Err("NULL s");
2259       SUMA_RETURN(NULL);
2260    }
2261 
2262    im = mri_read_1D (s);
2263 
2264    if (!im) {
2265       SUMA_SLP_Err("Failed to read 1D file");
2266       SUMA_RETURN(NULL);
2267    }
2268 
2269    if (oriented) {
2270       dotp = OLS_type;
2271       sprintf(buf,"Oriented direction");
2272    } else {
2273       dotp = LS_type;
2274       sprintf(buf,"Direction");
2275    }
2276    far = MRI_FLOAT_PTR(im);
2277    ncol = im->nx;
2278    nrow = im->ny;
2279 
2280    if (!ncol) {
2281       SUMA_SLP_Err("Empty file");
2282       SUMA_RETURN(NULL);
2283    }
2284 
2285    icol_orig = -1;
2286    icol_dir = -1;
2287    icol_col = -1;
2288    icol_amp = -1;
2289    icol_thick = -1;
2290    icol_stip = -1;
2291    switch (nrow) {
2292       case 3:
2293          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2294                               "dx dy dz\n",
2295                               FuncName, buf, s);
2296          icol_dir = 0;
2297          break;
2298       case 4:
2299          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2300                               "dx dy dz mag\n",
2301                               FuncName, buf, s);
2302          icol_dir = 0;
2303          icol_amp = 3;
2304          break;
2305       case 5:
2306          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2307                               "dx dy dz mag th\n",
2308                               FuncName, buf, s);
2309          icol_dir = 0;
2310          icol_amp = 3;
2311          icol_thick = 4;
2312          break;
2313       case 6:
2314          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2315                               "ox oy oz dx dy dz\n",
2316                               FuncName, buf, s);
2317          icol_orig = 0;
2318          icol_dir = 3;
2319          break;
2320       case 7:
2321          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2322                               "ox oy oz dx dy dz mag\n",
2323                               FuncName, buf, s);
2324          icol_orig = 0;
2325          icol_dir = 3;
2326          icol_amp = 6;
2327          break;
2328       case 8:
2329          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2330                               "ox oy oz dx dy dz mag th\n",
2331                               FuncName, buf, s);
2332          icol_orig = 0;
2333          icol_dir = 3;
2334          icol_amp = 6;
2335          icol_thick = 7;
2336          break;
2337       case 9:
2338          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2339                               "dx dy dz mag th c0 c1 c2 c3\n",
2340                               FuncName, buf, s);
2341          icol_dir = 0;
2342          icol_amp = 3;
2343          icol_thick = 4;
2344          icol_col = 5;
2345          break;
2346 
2347       case 11:
2348          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2349                               "ox oy oz dx dy dz mag c0 c1 c2 c3\n",
2350                               FuncName, buf, s);
2351          icol_orig = 0;
2352          icol_dir = 3;
2353          icol_amp = 6;
2354          icol_col = 7;
2355          break;
2356       case 12:
2357          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2358                               "ox oy oz dx dy dz mag th c0 c1 c2 c3\n",
2359                               FuncName, buf, s);
2360          icol_orig = 0;
2361          icol_dir = 3;
2362          icol_amp = 6;
2363          icol_thick = 7;
2364          icol_col = 8;
2365          break;
2366       default:
2367          SUMA_SLP_Err("File must have\n"
2368                    "3, 4, 5, 6, 7, 8, 9, 11 or 12 columns.");
2369          mri_free(im); im = NULL;   /* done with that baby */
2370          SUMA_RETURN(NULL);
2371    }
2372 
2373    if (icol_dir < 0) {
2374       SUMA_S_Err("No Directions found");
2375       mri_free(im); im = NULL;   /* done with that baby */
2376       SUMA_RETURN(NULL);
2377    }
2378 
2379    /* allocate for segments DO */
2380    SDO = SUMA_Alloc_SegmentDO (ncol, s, oriented, parent_SO_id, 0,
2381                      dotp, parent_SO_id ? SO_type:NOT_SET_type, NULL);
2382    if (!SDO) {
2383       fprintf(SUMA_STDERR,
2384               "Error %s: Failed in SUMA_Allocate_SegmentDO.\n", FuncName);
2385       SUMA_RETURN(NULL);
2386    }
2387 
2388    /* fill up SDO */
2389    itmp = 0;
2390    or[0] = or[1] = or[2] = 0.0;
2391    while (itmp < SDO->N_n) {
2392       if (icol_amp < 0) gn = 1.0;
2393       else gn = far[itmp+(icol_amp  )*ncol];
2394       itmp2 = 3*itmp;
2395       if (icol_orig >= 0) {
2396          or[0] = far[itmp+(icol_orig  )*ncol];
2397          or[1] = far[itmp+(icol_orig+1)*ncol];
2398          or[2] = far[itmp+(icol_orig+2)*ncol];
2399       }
2400       SDO->n0[itmp2]   = or[0];
2401       SDO->n0[itmp2+1] = or[1];
2402       SDO->n0[itmp2+2] = or[2];
2403       SDO->n1[itmp2]   = far[itmp+(icol_dir  )*ncol]*gn+or[0];
2404       SDO->n1[itmp2+1] = far[itmp+(icol_dir+1)*ncol]*gn+or[1];
2405       SDO->n1[itmp2+2] = far[itmp+(icol_dir+2)*ncol]*gn+or[2];
2406       ++itmp;
2407    }
2408 
2409    if (icol_col >= 0) {
2410       SDO->colv = (GLfloat *)SUMA_malloc(4*sizeof(GLfloat)*SDO->N_n);
2411       if (!SDO->colv) {
2412          SUMA_SL_Crit("Failed in to allocate for colv.");
2413          SUMA_RETURN(NULL);
2414       }
2415       /* fill up idividual colors */
2416       itmp = 0;
2417       while (itmp < SDO->N_n) {
2418          itmp2 = 4*itmp;
2419          SDO->colv[itmp2]     = far[itmp+(icol_col  )*ncol];
2420          SDO->colv[itmp2+1]   = far[itmp+(icol_col+1)*ncol];
2421          SDO->colv[itmp2+2]   = far[itmp+(icol_col+2)*ncol];
2422          SDO->colv[itmp2+3]   = far[itmp+(icol_col+3)*ncol];
2423          ++itmp;
2424       }
2425    } else {
2426       SDO->colv = (GLfloat *)SUMA_malloc(4*sizeof(GLfloat)*SDO->N_n);
2427       if (!SDO->colv) {
2428          SUMA_SL_Crit("Failed in to allocate for colv.");
2429          SUMA_RETURN(NULL);
2430       }
2431       /* fill up idividual colors */
2432       itmp = 0;
2433       while (itmp < SDO->N_n) {
2434          itmp2 = 4*itmp;
2435          SDO->colv[itmp2]     = SUMA_ABS(far[itmp+(icol_dir  )*ncol]);
2436          SDO->colv[itmp2+1]   = SUMA_ABS(far[itmp+(icol_dir+1)*ncol]);
2437          SDO->colv[itmp2+2]   = SUMA_ABS(far[itmp+(icol_dir+2)*ncol]);
2438          SDO->colv[itmp2+3]   = 1.0;
2439          ++itmp;
2440       }
2441    }
2442    SDO->LineWidth = 1;
2443    if (icol_thick > 0) {
2444       SDO->thickv = (GLfloat *)SUMA_malloc(sizeof(GLfloat)*SDO->N_n);
2445       if (!SDO->thickv) {
2446          SUMA_SL_Crit("Failed in to allocate for colv.");
2447          SUMA_RETURN(NULL);
2448       }
2449       /* fill up idividual thickness */
2450       itmp = 0;
2451       while (itmp < SDO->N_n) {
2452          SDO->thickv[itmp]     = far[itmp+(icol_thick  )*ncol];
2453          ++itmp;
2454       }
2455       /* One constant thickness?*/
2456       itmp = 0;
2457       while (itmp < SDO->N_n) {
2458          if (SDO->thickv[itmp] != SDO->thickv[0]) break;
2459          ++itmp;
2460       }
2461       if (itmp == SDO->N_n) { /* constant thickness, go for speed */
2462          SDO->LineWidth = SDO->thickv[0];
2463          SUMA_ifree(SDO->thickv);
2464       }
2465    }
2466 
2467    if (icol_stip > 0) {
2468       SDO->stipv = (GLushort *)SUMA_malloc(sizeof(GLushort)*SDO->N_n);
2469       if (!SDO->stipv) {
2470          SUMA_SL_Crit("Failed in to allocate for colv.");
2471          SUMA_RETURN(NULL);
2472       }
2473       /* fill up idividual stippliness */
2474       itmp = 0; same =  1;
2475       while (itmp < SDO->N_n) {
2476          SDO->stipv[itmp]     = SUMA_int_to_stipplemask(
2477                                  (int)far[itmp+(icol_stip  )*ncol]);
2478          if (same && SDO->stipv[itmp] != SDO->stipv[0]) same = 0;
2479          ++itmp;
2480       }
2481       if (same) {
2482          SDO->stip = (GLushort)SDO->stipv[0];
2483          SUMA_free(SDO->stipv); SDO->stipv=NULL;
2484       }
2485       if (SDO->stipv ||
2486           ( SDO->stip != 0 && SDO->stip != 0xFFFF)) {
2487                SDO->Stipple = SUMA_DASHED_LINE;
2488       } else {
2489          SDO->Stipple = SUMA_SOLID_LINE;
2490       }
2491    }
2492    mri_free(im); im = NULL; far = NULL;
2493 
2494    SUMA_RETURN(SDO);
2495 }
2496 
SUMA_ReadSegDO(char * s,int oriented,char * parent_SO_id)2497 SUMA_SegmentDO * SUMA_ReadSegDO (char *s, int oriented, char *parent_SO_id)
2498 {
2499    static char FuncName[]={"SUMA_ReadSegDO"};
2500    SUMA_SegmentDO *SDO = NULL;
2501    MRI_IMAGE * im = NULL;
2502    float *far=NULL;
2503    int itmp, itmp2, icol_thick = -1, icol_col=-1, icol_stip=-1;
2504    int nrow=-1, ncol=-1, same = 0;
2505    char buf[30];
2506    SUMA_DO_Types dotp;
2507 
2508    SUMA_ENTRY;
2509 
2510    if (!s) {
2511       SUMA_SLP_Err("NULL s");
2512       SUMA_RETURN(NULL);
2513    }
2514 
2515    im = mri_read_1D (s);
2516 
2517    if (!im) {
2518       SUMA_SLP_Err("Failed to read 1D file");
2519       SUMA_RETURN(NULL);
2520    }
2521 
2522    if (oriented) {
2523       dotp = OLS_type;
2524       sprintf(buf,"Oriented segment");
2525    } else {
2526       dotp = LS_type;
2527       sprintf(buf,"Segment");
2528    }
2529    far = MRI_FLOAT_PTR(im);
2530    ncol = im->nx;
2531    nrow = im->ny;
2532 
2533    if (!ncol) {
2534       SUMA_SLP_Err("Empty file");
2535       SUMA_RETURN(NULL);
2536    }
2537 
2538    icol_col = -1;
2539    icol_thick = -1;
2540    icol_stip = -1;
2541    switch (nrow) {
2542       case 6:
2543          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2544                               "x0 y0 z0 x1 y1 z1\n",
2545                               FuncName, buf, s);
2546          break;
2547       case 7:
2548          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2549                               "x0 y0 z0 x1 y1 z1 th\n",
2550                               FuncName, buf, s);
2551          icol_thick = 6;
2552          break;
2553       case 10:
2554          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2555                               "x0 y0 z0 x1 y1 z1 c0 c1 c2 c3\n",
2556                               FuncName, buf, s);
2557          icol_col = 6;
2558          break;
2559       case 11:
2560          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2561                               "x0 y0 z0 x1 y1 z1 c0 c1 c2 c3 th\n",
2562                               FuncName, buf, s);
2563          icol_col = 6;
2564          icol_thick = 10;
2565          break;
2566       case 12:
2567          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2568                               "x0 y0 z0 x1 y1 z1 c0 c1 c2 c3 th stp\n",
2569                               FuncName, buf, s);
2570          icol_col = 6;
2571          icol_thick = 10;
2572          icol_stip = 11;
2573          break;
2574       default:
2575          SUMA_SLP_Err("File must have\n"
2576                    "6,7,10, 11, 12 columns.");
2577          mri_free(im); im = NULL;   /* done with that baby */
2578          SUMA_RETURN(NULL);
2579    }
2580 
2581    /* allocate for segments DO */
2582    SDO = SUMA_Alloc_SegmentDO (ncol, s, oriented, parent_SO_id, 0,
2583                      dotp, parent_SO_id ? SO_type:NOT_SET_type, NULL);
2584    if (!SDO) {
2585       fprintf(SUMA_STDERR,
2586               "Error %s: Failed in SUMA_Allocate_SegmentDO.\n", FuncName);
2587       SUMA_RETURN(NULL);
2588    }
2589 
2590    /* fill up SDO */
2591    itmp = 0;
2592    while (itmp < SDO->N_n) {
2593       itmp2 = 3*itmp;
2594       SDO->n0[itmp2]   = far[itmp       ];
2595       SDO->n0[itmp2+1] = far[itmp+  ncol];
2596       SDO->n0[itmp2+2] = far[itmp+2*ncol];
2597       SDO->n1[itmp2]   = far[itmp+3*ncol];
2598       SDO->n1[itmp2+1] = far[itmp+4*ncol];
2599       SDO->n1[itmp2+2] = far[itmp+5*ncol];
2600       ++itmp;
2601    }
2602 
2603    if (icol_col > 0) {
2604       SDO->colv = (GLfloat *)SUMA_malloc(4*sizeof(GLfloat)*SDO->N_n);
2605       if (!SDO->colv) {
2606          SUMA_SL_Crit("Failed in to allocate for colv.");
2607          SUMA_RETURN(NULL);
2608       }
2609       /* fill up idividual colors */
2610       itmp = 0;
2611       while (itmp < SDO->N_n) {
2612          itmp2 = 4*itmp;
2613          SDO->colv[itmp2]     = far[itmp+(icol_col  )*ncol];
2614          SDO->colv[itmp2+1]   = far[itmp+(icol_col+1)*ncol];
2615          SDO->colv[itmp2+2]   = far[itmp+(icol_col+2)*ncol];
2616          SDO->colv[itmp2+3]   = far[itmp+(icol_col+3)*ncol];
2617          ++itmp;
2618       }
2619    }
2620    if (icol_thick > 0) {
2621       SDO->thickv = (GLfloat *)SUMA_malloc(sizeof(GLfloat)*SDO->N_n);
2622       if (!SDO->thickv) {
2623          SUMA_SL_Crit("Failed in to allocate for colv.");
2624          SUMA_RETURN(NULL);
2625       }
2626       /* fill up idividual thickness */
2627       itmp = 0;
2628       while (itmp < SDO->N_n) {
2629          SDO->thickv[itmp]     = far[itmp+(icol_thick  )*ncol];
2630          ++itmp;
2631       }
2632    }
2633    if (icol_stip > 0) {
2634       SDO->stipv = (GLushort *)SUMA_malloc(sizeof(GLushort)*SDO->N_n);
2635       if (!SDO->stipv) {
2636          SUMA_SL_Crit("Failed in to allocate for colv.");
2637          SUMA_RETURN(NULL);
2638       }
2639       /* fill up idividual stippliness */
2640       itmp = 0; same =  1;
2641       while (itmp < SDO->N_n) {
2642          SDO->stipv[itmp]     = SUMA_int_to_stipplemask(
2643                                  (int)far[itmp+(icol_stip  )*ncol]);
2644          if (same && SDO->stipv[itmp] != SDO->stipv[0]) same = 0;
2645          ++itmp;
2646       }
2647       if (same) {
2648          SDO->stip = (GLushort)SDO->stipv[0];
2649          SUMA_free(SDO->stipv); SDO->stipv=NULL;
2650       }
2651       if (SDO->stipv ||
2652           ( SDO->stip != 0 && SDO->stip != 0xFFFF)) {
2653                SDO->Stipple = SUMA_DASHED_LINE;
2654       } else {
2655          SDO->Stipple = SUMA_SOLID_LINE;
2656       }
2657    }
2658    mri_free(im); im = NULL; far = NULL;
2659 
2660    SUMA_RETURN(SDO);
2661 }
2662 
SUMA_ReadMaskDO(char * s,char * parent_ADO_id)2663 SUMA_MaskDO * SUMA_ReadMaskDO (char *s, char *parent_ADO_id)
2664 {
2665    static char FuncName[]={"SUMA_ReadMaskDO"};
2666    SUMA_MaskDO *MDO = NULL;
2667    MRI_IMAGE * im = NULL;
2668    float *far=NULL;
2669    char mtype[64];
2670    int itmp, itmp2, icol_col=-1;
2671    int nrow=-1, ncol=-1, same = 0;
2672    SUMA_DO_Types dotp;
2673    SUMA_Boolean LocalHead = NOPE;
2674 
2675    SUMA_ENTRY;
2676 
2677    if (!s) {
2678       SUMA_SLP_Err("NULL s");
2679       SUMA_RETURN(NULL);
2680    }
2681 
2682    if (!SUMA_Guess_Str_MaskDO_Type(s, (char *)mtype)) {
2683       SUMA_S_Err("Failed to guess MDO type");
2684       SUMA_RETURN(NULL);
2685    }
2686    SUMA_LH("Type is >%s<", mtype);
2687 
2688    im = mri_read_1D (s);
2689 
2690    if (!im) {
2691       SUMA_SLP_Err("Failed to read 1D file");
2692       SUMA_RETURN(NULL);
2693    }
2694 
2695    /* Check for subtypes */
2696 
2697    far = MRI_FLOAT_PTR(im);
2698    ncol = im->nx;
2699    nrow = im->ny;
2700 
2701    if (!ncol) {
2702       SUMA_SLP_Err("Empty file");
2703       SUMA_RETURN(NULL);
2704    }
2705 
2706    icol_col = -1;
2707    switch (nrow) {
2708       case 4:
2709          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2710                               "xc yc zc sz\n",
2711                               FuncName, mtype, s);
2712          break;
2713       case 6:
2714          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2715                               "Xc Yc Zc Xsz Ysz Zsz\n",
2716                               FuncName, mtype, s);
2717          break;
2718       case 7:
2719          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2720                               "xc yc zc sz R G B\n",
2721                               FuncName, mtype, s);
2722          icol_col = 4;
2723          break;
2724       case 9:
2725          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2726                               "Xc Yc Zc Xsz Ysz Zsz R G B\n",
2727                               FuncName, mtype, s);
2728          icol_col = 6;
2729          break;
2730       default:
2731          SUMA_SLP_Err("File must have\n"
2732                    "4,6,7 or 9 columns.");
2733          mri_free(im); im = NULL;   /* done with that baby */
2734          SUMA_RETURN(NULL);
2735    }
2736 
2737 
2738    /* allocate for Mask DOs */
2739    MDO = SUMA_Alloc_MaskDO (ncol, s, NULL, parent_ADO_id, 0);
2740    if (!MDO) {
2741       fprintf(SUMA_STDERR,
2742               "Error %s: Failed in SUMA_Allocate_MaskDO.\n", FuncName);
2743       SUMA_RETURN(NULL);
2744    }
2745    strcpy(MDO->mtype, mtype);
2746    if (!SUMA_AddMaskSaux(MDO)) {
2747       SUMA_S_Err("Failed to add Mask Saux");
2748       SUMA_RETURN(NULL);
2749    }
2750 
2751    /* fill up MDO */
2752    itmp = 0;
2753    while (itmp < MDO->N_obj) {
2754       itmp2 = 3*itmp;
2755       MDO->cen[itmp2]   = far[itmp       ];
2756       MDO->cen[itmp2+1] = far[itmp+  ncol];
2757       MDO->cen[itmp2+2] = far[itmp+2*ncol];
2758       MDO->hdim[itmp2]   = far[itmp+3*ncol]/2.0;
2759       switch (nrow) {
2760          case 6:
2761          case 9:
2762             MDO->hdim[itmp2+1] = far[itmp+4*ncol]/2.0;
2763             MDO->hdim[itmp2+2] = far[itmp+5*ncol]/2.0;
2764             break;
2765          case 4:
2766          case 7:
2767             MDO->hdim[itmp2+1] = MDO->hdim[itmp2+2] = MDO->hdim[itmp2];
2768             break;
2769          default:
2770             SUMA_S_Err("Should not be here");
2771             break;
2772       }
2773       ++itmp;
2774    }
2775 
2776    if (icol_col > 0) {
2777       MDO->dcolv = (GLfloat *)SUMA_malloc(4*sizeof(GLfloat)*MDO->N_obj);
2778       MDO->init_col = (float *)SUMA_malloc(4*sizeof(float)*MDO->N_obj);
2779       if (!MDO->dcolv || !MDO->init_col) {
2780          SUMA_SL_Crit("Failed in to allocate for colv.");
2781          SUMA_RETURN(NULL);
2782       }
2783       /* fill up idividual colors */
2784       itmp = 0;
2785       while (itmp < MDO->N_obj) {
2786          itmp2 = 4*itmp;
2787          MDO->init_col[itmp2]     = far[itmp+(icol_col  )*ncol];
2788          MDO->init_col[itmp2+1]   = far[itmp+(icol_col+1)*ncol];
2789          MDO->init_col[itmp2+2]   = far[itmp+(icol_col+2)*ncol];
2790          MDO->init_col[itmp2+3]   = 1.0;
2791          MDO->dcolv[itmp2]     = MDO->init_col[itmp2]*MDO->dim;
2792          MDO->dcolv[itmp2+1]   = MDO->init_col[itmp2+1]*MDO->dim;
2793          MDO->dcolv[itmp2+2]   = MDO->init_col[itmp2+2]*MDO->dim;
2794          MDO->dcolv[itmp2+3]   = 1.0;
2795          ++itmp;
2796       }
2797    }
2798 
2799    mri_free(im); im = NULL; far = NULL;
2800 
2801    memcpy(MDO->init_cen, MDO->cen, sizeof(float)*3*MDO->N_obj);
2802    memcpy(MDO->init_hdim, MDO->hdim, sizeof(float)*3*MDO->N_obj);
2803 
2804    SUMA_MDO_SetVarName(MDO, NULL);
2805 
2806    SUMA_RETURN(MDO);
2807 }
2808 
SUMA_ReadNBSegDO(char * s,int oriented,char * parent_SO_id)2809 SUMA_SegmentDO * SUMA_ReadNBSegDO (char *s, int oriented, char *parent_SO_id)
2810 {
2811    static char FuncName[]={"SUMA_ReadNBSegDO"};
2812    SUMA_SegmentDO *SDO = NULL;
2813    MRI_IMAGE * im = NULL;
2814    float *far=NULL;
2815    int itmp, itmp2, icol_thick = -1, icol_col=-1, icol_stip=-1;
2816    int nrow=-1, ncol=-1;
2817    int NodeBased = 2, same=0;
2818    char buf[30];
2819    SUMA_DO_Types dotp;
2820 
2821    SUMA_ENTRY;
2822 
2823    if (!s) {
2824       SUMA_SLP_Err("NULL s");
2825       SUMA_RETURN(NULL);
2826    }
2827 
2828    im = mri_read_1D (s);
2829 
2830    if (!im) {
2831       SUMA_SLP_Err("Failed to read 1D file");
2832       SUMA_RETURN(NULL);
2833    }
2834 
2835    if (oriented) {
2836       dotp = NBOLS_type;
2837       sprintf(buf,"Oriented Node-Based segment");
2838    } else {
2839       dotp = NBLS_type;
2840       sprintf(buf,"Node-Based Segment");
2841    }
2842    far = MRI_FLOAT_PTR(im);
2843    ncol = im->nx;
2844    nrow = im->ny;
2845 
2846    if (!ncol) {
2847       SUMA_SLP_Err("Empty file");
2848       SUMA_RETURN(NULL);
2849    }
2850 
2851    icol_col = -1;
2852    icol_thick = -1;
2853    icol_stip = -1;
2854    switch (nrow) {
2855       case 2:
2856          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2857                               "n0 n1\n",
2858                               FuncName, buf, s);
2859          break;
2860       case 3:
2861          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2862                               "n0 n1 th\n",
2863                               FuncName, buf, s);
2864          icol_thick = 2;
2865          break;
2866       case 6:
2867          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2868                               "n0 n1 c0 c1 c2 c3\n",
2869                               FuncName, buf, s);
2870          icol_col = 2;
2871          break;
2872       case 7:
2873          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2874                               "n0 n1 c0 c1 c2 c3 th\n",
2875                               FuncName, buf, s);
2876          icol_col = 2;
2877          icol_thick = 6;
2878          break;
2879       case 8:
2880          fprintf(SUMA_STDERR,"%s: %s file %s's format:\n"
2881                               "n0 n1 c0 c1 c2 c3 th st\n",
2882                               FuncName, buf, s);
2883          icol_col = 2;
2884          icol_thick = 6;
2885          icol_stip = 7;
2886          break;
2887       default:
2888          SUMA_SLP_Err("File must have\n"
2889                    "2, 3, 6, 7, or 8 columns.");
2890          mri_free(im); im = NULL;   /* done with that baby */
2891          SUMA_RETURN(NULL);
2892    }
2893 
2894    /* allocate for segments DO */
2895    SDO = SUMA_Alloc_SegmentDO (ncol, s, oriented,
2896               parent_SO_id, NodeBased, dotp,
2897               parent_SO_id?SO_type:NOT_SET_type, NULL);
2898    if (!SDO) {
2899       fprintf(SUMA_STDERR,
2900                "Error %s: Failed in SUMA_Allocate_SegmentDO.\n", FuncName);
2901       SUMA_RETURN(NULL);
2902    }
2903 
2904    /* fill up SDO */
2905    itmp = 0;
2906    while (itmp < SDO->N_n) {
2907       SDO->NodeID[itmp]  = far[itmp       ];
2908       SDO->NodeID1[itmp] = far[itmp+  ncol];
2909       ++itmp;
2910    }
2911 
2912    if (icol_col > 0) {
2913       SDO->colv = (GLfloat *)SUMA_malloc(4*sizeof(GLfloat)*SDO->N_n);
2914       if (!SDO->colv) {
2915          SUMA_SL_Crit("Failed in to allocate for colv.");
2916          SUMA_RETURN(NULL);
2917       }
2918       /* fill up idividual colors */
2919       itmp = 0;
2920       while (itmp < SDO->N_n) {
2921          itmp2 = 4*itmp;
2922          SDO->colv[itmp2]     = far[itmp+(icol_col  )*ncol];
2923          SDO->colv[itmp2+1]   = far[itmp+(icol_col+1)*ncol];
2924          SDO->colv[itmp2+2]   = far[itmp+(icol_col+2)*ncol];
2925          SDO->colv[itmp2+3]   = far[itmp+(icol_col+3)*ncol];
2926          ++itmp;
2927       }
2928    }
2929    if (icol_thick > 0) {
2930       SDO->thickv = (GLfloat *)SUMA_malloc(sizeof(GLfloat)*SDO->N_n);
2931       if (!SDO->thickv) {
2932          SUMA_SL_Crit("Failed in to allocate for colv.");
2933          SUMA_RETURN(NULL);
2934       }
2935       /* fill up idividual thickness */
2936       itmp = 0;
2937       while (itmp < SDO->N_n) {
2938          SDO->thickv[itmp]     = far[itmp+(icol_thick  )*ncol];
2939          ++itmp;
2940       }
2941    }
2942 
2943    if (icol_stip > 0) {
2944       SDO->stipv = (GLushort *)SUMA_malloc(sizeof(GLushort)*SDO->N_n);
2945       if (!SDO->stipv) {
2946          SUMA_SL_Crit("Failed in to allocate for colv.");
2947          SUMA_RETURN(NULL);
2948       }
2949       /* fill up idividual stipness */
2950       itmp = 0;
2951       while (itmp < SDO->N_n) {
2952          SDO->stipv[itmp]     = SUMA_int_to_stipplemask(
2953                                  (int)far[itmp+(icol_stip  )*ncol]);
2954          if (same && SDO->stipv[itmp] != SDO->stipv[0]) same = 0;
2955          ++itmp;
2956       }
2957       if (same) {
2958          SDO->stip = (GLushort)SDO->stipv[0];
2959          SUMA_free(SDO->stipv); SDO->stipv=NULL;
2960       }
2961       if (SDO->stipv ||
2962           ( SDO->stip != 0 && SDO->stip != 0xFFFF)) {
2963                SDO->Stipple = SUMA_DASHED_LINE;
2964       } else {
2965          SDO->Stipple = SUMA_SOLID_LINE;
2966       }
2967    }
2968    mri_free(im); im = NULL; far = NULL;
2969 
2970    SUMA_RETURN(SDO);
2971 }
2972 
2973 
SUMA_SDO2niSDO(SUMA_SegmentDO * SDO)2974 NI_group *SUMA_SDO2niSDO(SUMA_SegmentDO *SDO)
2975 {
2976    static char FuncName[]={"SUMA_SDO2niSDO"};
2977    NI_group *ngr = NULL;
2978    NI_element *nel = NULL;
2979 
2980    SUMA_ENTRY;
2981 
2982    if (!SDO) { SUMA_RETURN(ngr); }
2983 
2984    ngr = NI_new_group_element();
2985    NI_rename_group(ngr, "Segment_DO");
2986 
2987    NI_SET_STR(ngr, "idcode_str", SDO->idcode_str);
2988    NI_SET_STR(ngr, "Label", SDO->Label);
2989    NI_SET_INT(ngr, "NodeBased", SDO->NodeBased);
2990    NI_SET_STR(ngr, "Parent_idcode_str", SDO->Parent_idcode_str);
2991    NI_SET_INT(ngr, "N_n", SDO->N_n);
2992    NI_SET_FLOAT(ngr, "LineWidth", SDO->LineWidth);
2993    NI_SET_FLOATv(ngr, "LineCol", SDO->LineCol, 4);
2994    NI_SET_INT(ngr, "do_type", SDO->do_type);
2995    NI_SET_INT(ngr, "Parent_do_type", SDO->Parent_do_type);
2996    NI_SET_STR(ngr, "DrawnDO_variant", SDO->DrawnDO_variant);
2997    if (!SDO->DrawnDO_variant) SDO->DrawnDO_variant = SUMA_copy_string("");
2998 
2999    if (SDO->botobj) { NI_SET_INT(ngr, "oriented", 1); }
3000    else { NI_SET_INT(ngr, "oriented", 0); }
3001 
3002    if (SDO->NodeID) {
3003       nel = NI_new_data_element("NodeID", SDO->N_n);
3004       NI_add_column(nel, NI_INT, SDO->NodeID);
3005       NI_add_to_group( ngr, nel);
3006    }
3007    if (SDO->NodeID1) {
3008       nel = NI_new_data_element("NodeID1", SDO->N_n);
3009       NI_add_column(nel, NI_INT, SDO->NodeID1);
3010       NI_add_to_group( ngr, nel);
3011    }
3012    if (sizeof(GLfloat)!=sizeof(float)) {
3013       SUMA_S_Err("I hate life"); SUMA_RETURN(NULL); }
3014    if (SDO->n0) {
3015       nel = NI_new_data_element("n0", 3*SDO->N_n);
3016       NI_add_column(nel, NI_FLOAT, SDO->n0);
3017       NI_add_to_group( ngr, nel);
3018    }
3019    if (SDO->n1) {
3020       nel = NI_new_data_element("n1", 3*SDO->N_n);
3021       NI_add_column(nel, NI_FLOAT, SDO->n1);
3022       NI_add_to_group( ngr, nel);
3023    }
3024    if (SDO->colv) {
3025       nel = NI_new_data_element("colv", 4*SDO->N_n);
3026       NI_add_column(nel, NI_FLOAT, SDO->colv);
3027       NI_add_to_group( ngr, nel);
3028    }
3029    if (SDO->thickv) {
3030       nel = NI_new_data_element("thickv", SDO->N_n);
3031       NI_add_column(nel, NI_FLOAT, SDO->thickv);
3032       NI_add_to_group( ngr, nel);
3033    }
3034    NI_SET_INT(ngr, "Stipple", SDO->Stipple);
3035 
3036    SUMA_RETURN(ngr);
3037 }
3038 
SUMA_niSDO2SDO(NI_group * ngr)3039 SUMA_SegmentDO *SUMA_niSDO2SDO(NI_group *ngr)
3040 {
3041    static char FuncName[]={"SUMA_niSDO2SDO"};
3042    SUMA_SegmentDO *SDO=NULL;
3043    NI_element *nel = NULL;
3044    int N_n, oriented, ncp=0, NodeBased=-1;
3045    SUMA_DO_Types type, Parent_type;
3046    char att[500], *Parent_idcode_str=NULL, *Label=NULL,
3047         *idcode_str=NULL, *DrawnDO_variant= NULL;
3048    SUMA_Boolean LocalHead = NOPE;
3049 
3050    SUMA_ENTRY;
3051 
3052    if (!ngr) { SUMA_RETURN(SDO); }
3053 
3054    if (strcmp(ngr->name, "Segment_DO")) {
3055       SUMA_S_Err("NIML object not SDO");
3056       SUMA_RETURN(SDO);
3057    }
3058    NI_GET_STR_CP(ngr, "Parent_idcode_str", Parent_idcode_str);
3059    NI_GET_STR_CP(ngr, "Label", Label);
3060    NI_GET_INT(ngr, "oriented",oriented);
3061    NI_GET_INT(ngr, "N_n",N_n);
3062    NI_GET_INT(ngr, "do_type",type);
3063    NI_GET_INT(ngr, "NodeBased", NodeBased);
3064    if (!NI_GOT) { NodeBased = -1; }
3065    NI_GET_INT(ngr, "Parent_do_type", Parent_type);
3066    if (!NI_GOT) { Parent_type = NOT_SET_type; }
3067    NI_GET_STR_CP(ngr, "DrawnDO_variant", DrawnDO_variant);
3068    SDO = SUMA_Alloc_SegmentDO(N_n, Label, oriented, Parent_idcode_str,
3069                               NodeBased, type, Parent_type, DrawnDO_variant);
3070    if (Label) SUMA_free(Label); Label = NULL;
3071    if (Parent_idcode_str) SUMA_free(Parent_idcode_str); Parent_idcode_str = NULL;
3072    SUMA_ifree(DrawnDO_variant);
3073 
3074    NI_GET_STR_CP(ngr, "idcode_str", idcode_str);
3075    if (idcode_str) {
3076       SUMA_LHv("Have id %s in niml, replacing SDO's\n", idcode_str);
3077       SUMA_STRING_REPLACE(SDO->idcode_str, idcode_str);
3078       SUMA_free(idcode_str); idcode_str = NULL;
3079    }else {
3080       SUMA_LH("Have no id in niml");
3081    }
3082 
3083    NI_GET_FLOAT(ngr, "LineWidth", SDO->LineWidth);
3084    NI_GET_FLOATv(ngr, "LineCol", SDO->LineCol, 4,LocalHead);
3085    nel = SUMA_FindNgrNamedElement(ngr, "NodeID");
3086    if (!nel) {
3087       SDO->NodeID = NULL;
3088    } else {
3089       SDO->NodeID =
3090             (int *)SUMA_Copy_Part_Column(nel->vec[0],
3091                               NI_rowtype_find_code(nel->vec_typ[0]),
3092                               nel->vec_len, NULL, 0, &ncp);
3093    }
3094    nel = SUMA_FindNgrNamedElement(ngr, "NodeID1");
3095    if (!nel) {
3096       SDO->NodeID1 = NULL;
3097    } else {
3098       SDO->NodeID1 =
3099             (int *)SUMA_Copy_Part_Column(nel->vec[0],
3100                               NI_rowtype_find_code(nel->vec_typ[0]),
3101                               nel->vec_len, NULL, 0, &ncp);
3102    }
3103    nel = SUMA_FindNgrNamedElement(ngr, "n0");
3104    if (!nel) {
3105       SDO->n0 = NULL;
3106    } else {
3107       SDO->n0 = (float *)SUMA_Copy_Part_Column(nel->vec[0], NI_rowtype_find_code(nel->vec_typ[0]), nel->vec_len, NULL, 0, &ncp);
3108    }
3109    nel = SUMA_FindNgrNamedElement(ngr, "n1");
3110    if (!nel) {
3111       SDO->n1 = NULL;
3112    } else {
3113       SDO->n1 = (float *)SUMA_Copy_Part_Column(nel->vec[0], NI_rowtype_find_code(nel->vec_typ[0]), nel->vec_len, NULL, 0, &ncp);
3114    }
3115    nel = SUMA_FindNgrNamedElement(ngr, "colv");
3116    if (!nel) {
3117       SDO->colv = NULL;
3118    } else {
3119       SDO->colv = (float *)SUMA_Copy_Part_Column(nel->vec[0], NI_rowtype_find_code(nel->vec_typ[0]), nel->vec_len, NULL, 0, &ncp);
3120    }
3121    nel = SUMA_FindNgrNamedElement(ngr, "thickv");
3122    if (!nel) {
3123       SDO->thickv = NULL;
3124    } else {
3125       SDO->thickv = (float *)SUMA_Copy_Part_Column(nel->vec[0], NI_rowtype_find_code(nel->vec_typ[0]), nel->vec_len, NULL, 0, &ncp);
3126    }
3127    NI_GET_INT(ngr, "Stipple", SDO->Stipple);
3128 
3129    SUMA_RETURN(SDO);
3130 }
3131 
3132 
SUMA_CreateSegmentDO(int N_n,int oriented,int NodeBased,int Stipple,char * Label,char * idcode_str,char * Parent_idcode_str,SUMA_DO_Types Parent_do_type,char * DrawnDO_variant,float LineWidth,float * LineCol,int * NodeID,int * NodeID1,float * n0,float * n1,float * colv,float * thickv)3133 SUMA_SegmentDO *SUMA_CreateSegmentDO(
3134          int N_n, int oriented, int NodeBased, int Stipple,
3135          char *Label, char *idcode_str,
3136          char *Parent_idcode_str, SUMA_DO_Types Parent_do_type,
3137          char *DrawnDO_variant,
3138          float LineWidth, float *LineCol,
3139          int *NodeID, int *NodeID1, float *n0, float *n1,
3140          float *colv, float *thickv )
3141 {
3142    static char FuncName[]={"SUMA_CreateSegmentDO"};
3143    SUMA_SegmentDO *SDO=NULL;
3144    int ncp=0, i;
3145    SUMA_DO_Types type;
3146    SUMA_Boolean LocalHead = NOPE;
3147 
3148    SUMA_ENTRY;
3149 
3150    if (oriented) type = LS_type;
3151    else type = OLS_type;
3152 
3153    SDO = SUMA_Alloc_SegmentDO(N_n, Label, oriented, Parent_idcode_str,
3154                               NodeBased, type, Parent_do_type, DrawnDO_variant);
3155    if (idcode_str) SUMA_STRING_REPLACE(SDO->idcode_str, idcode_str);
3156    SDO->NodeBased = NodeBased;
3157    SDO->Stipple = Stipple;
3158    SDO->LineWidth =LineWidth;
3159    if (LineCol) { for (i=0; i<4; ++i) SDO->LineCol[i] = LineCol[i]; }
3160    else {   SDO->LineCol[0] = 0.4; SDO->LineCol[1] = 0.8;
3161             SDO->LineCol[2] = 0.1; SDO->LineCol[3] = 1.0; }
3162 
3163    if (NodeID) {
3164       SDO->NodeID = (int *)SUMA_Copy_Part_Column(
3165                               (void*)NodeID, NI_rowtype_find_code(NI_INT),
3166                               N_n, NULL, 0, &ncp);
3167    } else SDO->NodeID = NULL;
3168    if (NodeID1) {
3169       SDO->NodeID1 = (int *)SUMA_Copy_Part_Column(
3170                               (void*)NodeID1, NI_rowtype_find_code(NI_INT),
3171                               N_n, NULL, 0, &ncp);
3172    } else SDO->NodeID1 = NULL;
3173    if (!n0) {
3174       SDO->n0 = NULL;
3175    } else {
3176       SDO->n0 = (float *)SUMA_Copy_Part_Column(
3177                            (void *)n0,  NI_rowtype_find_code(NI_FLOAT),
3178                            3*N_n, NULL, 0, &ncp);
3179    }
3180    if (!n1) {
3181       SDO->n1 = NULL;
3182    } else {
3183       SDO->n1 = (float *)SUMA_Copy_Part_Column(
3184                            (void *)n1,  NI_rowtype_find_code(NI_FLOAT),
3185                            3*N_n, NULL, 0, &ncp);
3186    }
3187    if (!colv) {
3188       SDO->colv = NULL;
3189    } else {
3190       SDO->colv = (float *)SUMA_Copy_Part_Column(
3191                            (void *)colv,  NI_rowtype_find_code(NI_FLOAT),
3192                            4*N_n, NULL, 0, &ncp);
3193    }
3194    if (!thickv) {
3195       SDO->thickv = NULL;
3196    } else {
3197       SDO->thickv = (float *)SUMA_Copy_Part_Column(
3198                               (void *)thickv,  NI_rowtype_find_code(NI_FLOAT),
3199                               N_n, NULL, 0, &ncp);
3200    }
3201 
3202    SUMA_RETURN(SDO);
3203 }
3204 
SUMA_SphereStyleConvert(int v)3205 GLenum SUMA_SphereStyleConvert (int v)
3206 {
3207    switch (v) {
3208       case 0:
3209          return(GLU_POINT);
3210       case 1:
3211          return(GLU_LINE);
3212       case 2:
3213          return(GLU_FILL);
3214       default:
3215          return(GLU_FILL);
3216    }
3217 }
3218 
SUMA_ReadSphDO(char * s)3219 SUMA_SphereDO * SUMA_ReadSphDO (char *s)
3220 {
3221    static char FuncName[]={"SUMA_ReadSphDO"};
3222    SUMA_SphereDO *SDO = NULL;
3223    MRI_IMAGE * im = NULL;
3224    float *far=NULL;
3225    int itmp, itmp2, icol_rad=-1, icol_style = -1, icol_col = -1;
3226    int nrow=-1, ncol=-1;
3227 
3228    SUMA_ENTRY;
3229 
3230    if (!s) {
3231       SUMA_SLP_Err("NULL s");
3232       SUMA_RETURN(NULL);
3233    }
3234 
3235    im = mri_read_1D (s);
3236 
3237    if (!im) {
3238       SUMA_SLP_Err("Failed to read 1D file");
3239       SUMA_RETURN(NULL);
3240    }
3241 
3242    far = MRI_FLOAT_PTR(im);
3243    ncol = im->nx;
3244    nrow = im->ny;
3245 
3246    if (!ncol) {
3247       SUMA_SLP_Err("Empty file");
3248       SUMA_RETURN(NULL);
3249    }
3250 
3251    icol_col = -1;
3252    icol_rad = -1;
3253    icol_style = -1;
3254    switch (nrow) {
3255       case 3:
3256          fprintf(SUMA_STDERR,"%s: Sphere file %s's format:\n"
3257                               "ox oy oz\n", FuncName, s);
3258          break;
3259       case 4:
3260          fprintf(SUMA_STDERR,"%s: Sphere file %s's format:\n"
3261                               "ox oy oz rd\n", FuncName, s);
3262          icol_rad = 3;
3263          break;
3264       case 5:
3265          fprintf(SUMA_STDERR,"%s: Sphere file %s's format:\n"
3266                               "ox oy oz rd st\n", FuncName, s);
3267          icol_rad = 3;
3268          icol_style = 4;
3269          break;
3270       case 7:
3271          fprintf(SUMA_STDERR,"%s: Sphere file %s's format:\n"
3272                               "ox oy oz c0 c1 c2 c3\n", FuncName, s);
3273          icol_col = 3;
3274          break;
3275       case 8:
3276          fprintf(SUMA_STDERR,"%s: Sphere file %s's format:\n"
3277                               "ox oy oz c0 c1 c2 c3 rd\n", FuncName, s);
3278          icol_col = 3;
3279          icol_rad = 7;
3280          break;
3281       case 9:
3282          fprintf(SUMA_STDERR,"%s: Sphere file %s's format:\n"
3283                               "ox oy oz c0 c1 c2 c3 rd st\n", FuncName, s);
3284          icol_col = 3;
3285          icol_rad = 7;
3286          icol_style = 8;
3287          break;
3288       default:
3289          SUMA_SLP_Err("File must have\n"
3290                    "3,4,5,7,8 or 9 columns.");
3291          mri_free(im); im = NULL;   /* done with that baby */
3292          SUMA_RETURN(NULL);
3293    }
3294 
3295    /* allocate for segments DO */
3296    SDO = SUMA_Alloc_SphereDO (ncol, s, NULL, SP_type);
3297    if (!SDO) {
3298       fprintf(SUMA_STDERR,
3299          "Error %s: Failed in SUMA_Allocate_SphereDO.\n", FuncName);
3300       SUMA_RETURN(NULL);
3301    }
3302 
3303    /* fill up SDO */
3304    itmp = 0;
3305    while (itmp < SDO->N_n) {
3306       itmp2 = 3*itmp;
3307       SDO->cxyz[itmp2]   = far[itmp       ];
3308       SDO->cxyz[itmp2+1] = far[itmp+  ncol];
3309       SDO->cxyz[itmp2+2] = far[itmp+2*ncol];
3310       ++itmp;
3311    }
3312 
3313    if (icol_col > 0) {
3314       SDO->colv = (GLfloat *)SUMA_malloc(4*sizeof(GLfloat)*SDO->N_n);
3315       if (!SDO->colv) {
3316          SUMA_SL_Crit("Failed in to allocate for colv.");
3317          SUMA_RETURN(NULL);
3318       }
3319       /* fill up idividual colors */
3320       itmp = 0;
3321       while (itmp < SDO->N_n) {
3322          itmp2 = 4*itmp;
3323          SDO->colv[itmp2]     = far[itmp+(icol_col  )*ncol];
3324          SDO->colv[itmp2+1]   = far[itmp+(icol_col+1)*ncol];
3325          SDO->colv[itmp2+2]   = far[itmp+(icol_col+2)*ncol];
3326          SDO->colv[itmp2+3]   = far[itmp+(icol_col+3)*ncol];
3327          ++itmp;
3328       }
3329    }
3330    if (icol_rad > 0) {
3331       SDO->radv = (GLfloat *)SUMA_malloc(sizeof(GLfloat)*SDO->N_n);
3332       if (!SDO->radv) {
3333          SUMA_SL_Crit("Failed in to allocate for radv.");
3334          SUMA_RETURN(NULL);
3335       }
3336       /* fill up idividual radius */
3337       itmp = 0;
3338       while (itmp < SDO->N_n) {
3339          SDO->radv[itmp]     = far[itmp+(icol_rad  )*ncol];
3340          ++itmp;
3341       }
3342    }
3343    if (icol_style > 0) {
3344       SDO->stylev = (GLenum *)SUMA_malloc(sizeof(GLenum)*SDO->N_n);
3345       if (!SDO->stylev) {
3346          SUMA_SL_Crit("Failed in to allocate for radv.");
3347          SUMA_RETURN(NULL);
3348       }
3349       /* fill up idividual style */
3350       itmp = 0;
3351       while (itmp < SDO->N_n) {
3352          SDO->stylev[itmp] = SUMA_SphereStyleConvert(
3353                                  (int)far[itmp+(icol_style  )*ncol]);
3354          ++itmp;
3355       }
3356    }
3357    mri_free(im); im = NULL; far = NULL;
3358 
3359    SUMA_RETURN(SDO);
3360 }
3361 
SUMA_ReadPntDO(char * s)3362 SUMA_SphereDO * SUMA_ReadPntDO (char *s)
3363 {
3364    static char FuncName[]={"SUMA_ReadPntDO"};
3365    SUMA_SphereDO *SDO = NULL;
3366    MRI_IMAGE * im = NULL;
3367    float *far=NULL;
3368    int itmp, itmp2, icol_rad=-1, icol_style = -1, icol_col = -1;
3369    int nrow=-1, ncol=-1;
3370 
3371    SUMA_ENTRY;
3372 
3373    if (!s) {
3374       SUMA_SLP_Err("NULL s");
3375       SUMA_RETURN(NULL);
3376    }
3377 
3378    im = mri_read_1D (s);
3379 
3380    if (!im) {
3381       SUMA_SLP_Err("Failed to read 1D file");
3382       SUMA_RETURN(NULL);
3383    }
3384 
3385    far = MRI_FLOAT_PTR(im);
3386    ncol = im->nx;
3387    nrow = im->ny;
3388 
3389    if (!ncol) {
3390       SUMA_SLP_Err("Empty file");
3391       SUMA_RETURN(NULL);
3392    }
3393 
3394    icol_col = -1;
3395    icol_rad = -1;
3396    icol_style = -1;
3397    switch (nrow) {
3398       case 3:
3399          fprintf(SUMA_STDERR,"%s: Point file %s's format:\n"
3400                               "ox oy oz\n", FuncName, s);
3401          break;
3402       case 4:
3403          fprintf(SUMA_STDERR,"%s: Point file %s's format:\n"
3404                               "ox oy oz sz\n", FuncName, s);
3405          icol_rad = 3;
3406          break;
3407       case 7:
3408          fprintf(SUMA_STDERR,"%s: Point file %s's format:\n"
3409                               "ox oy oz c0 c1 c2 c3\n", FuncName, s);
3410          icol_col = 3;
3411          break;
3412       case 8:
3413          fprintf(SUMA_STDERR,"%s: Point file %s's format:\n"
3414                               "ox oy oz c0 c1 c2 c3 sz\n", FuncName, s);
3415          icol_col = 3;
3416          icol_rad = 7;
3417          break;
3418       default:
3419          SUMA_SLP_Err("File must have\n"
3420                    "3,4,7 or 8  columns.");
3421          mri_free(im); im = NULL;   /* done with that baby */
3422          SUMA_RETURN(NULL);
3423    }
3424 
3425    /* allocate for segments DO */
3426    SDO = SUMA_Alloc_SphereDO (ncol, s, NULL, SP_type);
3427    if (!SDO) {
3428       fprintf(SUMA_STDERR,
3429          "Error %s: Failed in SUMA_Allocate_SphereDO.\n", FuncName);
3430       SUMA_RETURN(NULL);
3431    }
3432 
3433    /* fill up SDO */
3434    itmp = 0;
3435    while (itmp < SDO->N_n) {
3436       itmp2 = 3*itmp;
3437       SDO->cxyz[itmp2]   = far[itmp       ];
3438       SDO->cxyz[itmp2+1] = far[itmp+  ncol];
3439       SDO->cxyz[itmp2+2] = far[itmp+2*ncol];
3440       ++itmp;
3441    }
3442 
3443    SDO->CommonCol[0] = SDO->CommonCol[1] =
3444    SDO->CommonCol[2] = SDO->CommonCol[3] = 1.0;
3445    if (icol_col > 0) {
3446       SDO->colv = (GLfloat *)SUMA_malloc(4*sizeof(GLfloat)*SDO->N_n);
3447       if (!SDO->colv) {
3448          SUMA_SL_Crit("Failed in to allocate for colv.");
3449          SUMA_RETURN(NULL);
3450       }
3451       /* fill up idividual colors */
3452       itmp = 0;
3453       while (itmp < SDO->N_n) {
3454          itmp2 = 4*itmp;
3455          SDO->colv[itmp2]     = far[itmp+(icol_col  )*ncol];
3456          SDO->colv[itmp2+1]   = far[itmp+(icol_col+1)*ncol];
3457          SDO->colv[itmp2+2]   = far[itmp+(icol_col+2)*ncol];
3458          SDO->colv[itmp2+3]   = far[itmp+(icol_col+3)*ncol];
3459          ++itmp;
3460       }
3461       /* constant color? */itmp = 0;
3462       while (itmp < SDO->N_n) {
3463          itmp2 = 4*itmp;
3464          if ( SDO->colv[itmp2  ] != SDO->colv[0] ||
3465               SDO->colv[itmp2+1] != SDO->colv[1] ||
3466               SDO->colv[itmp2+2] != SDO->colv[2] ||
3467               SDO->colv[itmp2+3] != SDO->colv[3]) break;
3468          ++itmp;
3469       }
3470       if (itmp == SDO->N_n) {
3471          SDO->CommonCol[0] = SDO->colv[0];
3472          SDO->CommonCol[1] = SDO->colv[1];
3473          SDO->CommonCol[2] = SDO->colv[2];
3474          SDO->CommonCol[3] = SDO->colv[3];
3475          SUMA_ifree(SDO->colv);
3476       }
3477    }
3478 
3479    SDO->CommonRad = 1;
3480    if (icol_rad > 0) {
3481       SDO->radv = (GLfloat *)SUMA_malloc(sizeof(GLfloat)*SDO->N_n);
3482       if (!SDO->radv) {
3483          SUMA_SL_Crit("Failed in to allocate for radv.");
3484          SUMA_RETURN(NULL);
3485       }
3486       /* fill up idividual radius */
3487       itmp = 0;
3488       while (itmp < SDO->N_n) {
3489          SDO->radv[itmp]     = far[itmp+(icol_rad  )*ncol];
3490          ++itmp;
3491       }
3492       /* One constant radius?*/
3493       itmp = 0;
3494       while (itmp < SDO->N_n) {
3495          if (SDO->radv[itmp] != SDO->radv[0]) break;
3496          ++itmp;
3497       }
3498       if (itmp == SDO->N_n) { /* constant radius, go for speed */
3499          SDO->CommonRad = SDO->radv[0];
3500          SUMA_ifree(SDO->radv);
3501       }
3502    }
3503    mri_free(im); im = NULL; far = NULL;
3504 
3505    SUMA_RETURN(SDO);
3506 }
3507 
SUMA_VE_Nvox(SUMA_VolumeElement ** VE,int ivo)3508 int SUMA_VE_Nvox(SUMA_VolumeElement **VE, int ivo)
3509 {
3510    static char FuncName[]={"SUMA_VE_Nvox"};
3511    SUMA_DSET *sdset=NULL;
3512 
3513    SUMA_ENTRY;
3514 
3515    if (ivo < 0) ivo = 0;
3516    if (!VE || !VE[ivo]) SUMA_RETURN(-1);
3517 
3518    SUMA_RETURN(VE[ivo]->Ni*VE[ivo]->Nj*VE[ivo]->Nk);
3519 }
3520 
SUMA_VE_Nij(SUMA_VolumeElement ** VE,int ivo)3521 int SUMA_VE_Nij(SUMA_VolumeElement **VE, int ivo)
3522 {
3523    static char FuncName[]={"SUMA_VE_Nij"};
3524 
3525    SUMA_ENTRY;
3526 
3527    if (ivo < 0) ivo = 0;
3528    if (!VE || !VE[ivo]) SUMA_RETURN(-1);
3529 
3530    SUMA_RETURN(VE[ivo]->Ni*VE[ivo]->Nj);
3531 }
3532 
SUMA_VE_Ni(SUMA_VolumeElement ** VE,int ivo)3533 int SUMA_VE_Ni(SUMA_VolumeElement **VE, int ivo)
3534 {
3535    static char FuncName[]={"SUMA_VE_Ni"};
3536 
3537    SUMA_ENTRY;
3538 
3539    if (ivo < 0) ivo = 0;
3540    if (!VE || !VE[ivo]) SUMA_RETURN(-1);
3541 
3542    SUMA_RETURN(VE[ivo]->Ni);
3543 }
3544 
SUMA_VE_Nj(SUMA_VolumeElement ** VE,int ivo)3545 int SUMA_VE_Nj(SUMA_VolumeElement **VE, int ivo)
3546 {
3547    static char FuncName[]={"SUMA_VE_Nj"};
3548 
3549    SUMA_ENTRY;
3550 
3551    if (ivo < 0) ivo = 0;
3552    if (!VE || !VE[ivo]) SUMA_RETURN(-1);
3553 
3554    SUMA_RETURN(VE[ivo]->Nj);
3555 }
3556 
SUMA_VE_Nk(SUMA_VolumeElement ** VE,int ivo)3557 int SUMA_VE_Nk(SUMA_VolumeElement **VE, int ivo)
3558 {
3559    static char FuncName[]={"SUMA_VE_Nk"};
3560 
3561    SUMA_ENTRY;
3562 
3563    if (ivo < 0) ivo = 0;
3564    if (!VE || !VE[ivo]) SUMA_RETURN(-1);
3565 
3566    SUMA_RETURN(VE[ivo]->Nk);
3567 }
3568 
SUMA_VE_orcode(SUMA_VolumeElement ** VE,int ivo)3569 char *SUMA_VE_orcode(SUMA_VolumeElement **VE, int ivo)
3570 {
3571    static char FuncName[]={"SUMA_VE_orcode"};
3572    SUMA_DSET *dset=NULL;
3573    char *orcode;
3574 
3575    SUMA_ENTRY;
3576 
3577    if (ivo < 0) ivo = 0;
3578    if (!VE || !VE[ivo] ||
3579       !(dset = DSET_FIND(VE[ivo]->dset_idcode_str)))
3580                         SUMA_RETURN(SUMA_Dset_orcode(NULL));
3581 
3582    SUMA_RETURN(SUMA_Dset_orcode(dset));
3583 }
3584 
SUMA_VO_orcode(SUMA_VolumeObject * VO)3585 char * SUMA_VO_orcode(SUMA_VolumeObject *VO)
3586 {
3587    static char FuncName[]={"SUMA_VO_orcode"};
3588    if (!VO || !VO->VE) return("XXX");
3589    return(SUMA_VE_orcode(VO->VE, 0));
3590 }
3591 
3592 
SUMA_VO_N_Slices(SUMA_VolumeObject * VO,char * variant)3593 int SUMA_VO_N_Slices(SUMA_VolumeObject *VO, char *variant)
3594 {
3595    static char FuncName[]={"SUMA_VO_N_Slices"};
3596    if (!VO || !VO->VE) return(-1);
3597    return(SUMA_VE_N_Slices(VO->VE, 0, variant));
3598 }
3599 
SUMA_VE_N_Slices(SUMA_VolumeElement ** VE,int ivo,char * variant)3600 int SUMA_VE_N_Slices(SUMA_VolumeElement **VE, int ivo, char *variant)
3601 {
3602    static char FuncName[]={"SUMA_VE_N_Slices"};
3603    char *orcode = NULL;
3604 
3605    SUMA_ENTRY;
3606 
3607    if (ivo < 0) ivo = 0;
3608    if (!VE || !VE[ivo] || !variant) SUMA_RETURN(-1);
3609 
3610    orcode = SUMA_VE_orcode(VE, ivo);
3611    switch (variant[0]) {
3612       case 'A':
3613               if (orcode[0] == 'I' || orcode[0] == 'S') SUMA_RETURN(VE[ivo]->Ni);
3614          else if (orcode[1] == 'I' || orcode[1] == 'S') SUMA_RETURN(VE[ivo]->Nj);
3615          else if (orcode[2] == 'I' || orcode[2] == 'S') SUMA_RETURN(VE[ivo]->Nk);
3616          break;
3617       case 'S':
3618               if (orcode[0] == 'R' || orcode[0] == 'L') SUMA_RETURN(VE[ivo]->Ni);
3619          else if (orcode[1] == 'R' || orcode[1] == 'L') SUMA_RETURN(VE[ivo]->Nj);
3620          else if (orcode[2] == 'R' || orcode[2] == 'L') SUMA_RETURN(VE[ivo]->Nk);
3621          break;
3622       case 'C':
3623               if (orcode[0] == 'A' || orcode[0] == 'P') SUMA_RETURN(VE[ivo]->Ni);
3624          else if (orcode[1] == 'A' || orcode[1] == 'P') SUMA_RETURN(VE[ivo]->Nj);
3625          else if (orcode[2] == 'A' || orcode[2] == 'P') SUMA_RETURN(VE[ivo]->Nk);
3626          break;
3627       case 'M': {
3628          int i=VE[ivo]->Ni;
3629          if (VE[ivo]->Nj > i) i = VE[ivo]->Nj;
3630          if (VE[ivo]->Nk > i) i = VE[ivo]->Nk;
3631          SUMA_RETURN(i);
3632          break; }
3633       default:
3634          SUMA_RETURN(-1);
3635    }
3636 
3637    SUMA_RETURN(-1);
3638 }
3639 
3640 
SUMA_VE_Headname(SUMA_VolumeElement ** VE,int ivo)3641 char * SUMA_VE_Headname(SUMA_VolumeElement **VE, int ivo)
3642 {
3643    static char FuncName[]={"SUMA_VE_Headname"};
3644    char *ss;
3645    SUMA_DSET *dset=NULL;
3646 
3647    SUMA_ENTRY;
3648 
3649    if (ivo < 0) ivo = 0;
3650    if (!VE || !VE[ivo] ||
3651        !(dset = DSET_FIND(VE[ivo]->dset_idcode_str))) SUMA_RETURN("");
3652    if (!dset->ngr ||
3653        !(ss = NI_get_attribute(dset->ngr,"DSET_HEADNAME"))) SUMA_RETURN("");
3654 
3655    SUMA_RETURN(ss);
3656 }
3657 
3658 
3659 
3660 
SUMA_VE_Set_Dims(SUMA_VolumeElement ** VE,int ive)3661 SUMA_Boolean SUMA_VE_Set_Dims(SUMA_VolumeElement **VE, int ive)
3662 {
3663    static char FuncName[]={"SUMA_VE_Set_Xforms"};
3664    float *v;
3665    int *dims;
3666    float B[4][4];
3667    SUMA_DSET *sdset = NULL;
3668    SUMA_Boolean LocalHead = NOPE;
3669 
3670    SUMA_ENTRY;
3671    if (ive < 0) ive = 0;
3672    if (!VE || !VE[ive] ||
3673        !(sdset = DSET_FIND(VE[ive]->dset_idcode_str))) SUMA_RETURN(NOPE);
3674 
3675    if (!(dims = SUMA_GetDatasetDimensions(sdset))) {
3676       SUMA_RETURN(NOPE);
3677    }
3678    VE[ive]->Ni = dims[0]; VE[ive]->Nj = dims[1]; VE[ive]->Nk = dims[2];
3679 
3680    /* transformation matrices */
3681    /* A == I2X == ijk_to_dicom_real
3682       invA = X2I
3683       B == I2T == ijk_to_texture
3684       invB == T2I == texture_to_ijk
3685       C == X2T == B invA == dicom_real_to_texture
3686    */
3687    SUMA_GetDatasetI2X(sdset, VE[ive]->I2X);  /* A */
3688    AFF44_INV(VE[ive]->X2I,  VE[ive]->I2X);   /* inv(A) */
3689    /* T = B I */
3690    AFF44_CARD_LOAD(B, (1.0/VE[ive]->Ni), (1.0/VE[ive]->Nj), (1.0/VE[ive]->Nk));
3691    AFF44_MULT(VE[ive]->X2T, B, VE[ive]->X2I);
3692    AFF44_INV(VE[ive]->T2X, VE[ive]->X2T);
3693 
3694    /* mm box corners */
3695    SUMA_dset_box_corners(sdset, VE[ive]->bcorners, 0);
3696    /* mm grid corners (voxel centers) */
3697    SUMA_dset_box_corners(sdset, VE[ive]->vcorners, 1);
3698    SUMA_LH("Box corners, edges:\n"
3699                "0 -- %f %f %f\n"
3700                "1 -- %f %f %f\n"
3701                "2 -- %f %f %f\n"
3702                "3 -- %f %f %f\n"
3703                "4 -- %f %f %f\n"
3704                "5 -- %f %f %f\n"
3705                "6 -- %f %f %f\n"
3706                "7 -- %f %f %f\n",
3707       VE[ive]->bcorners[0], VE[ive]->bcorners[1], VE[ive]->bcorners[2],
3708       VE[ive]->bcorners[3], VE[ive]->bcorners[4], VE[ive]->bcorners[5],
3709       VE[ive]->bcorners[6], VE[ive]->bcorners[7], VE[ive]->bcorners[8],
3710       VE[ive]->bcorners[9], VE[ive]->bcorners[10], VE[ive]->bcorners[11],
3711       VE[ive]->bcorners[12], VE[ive]->bcorners[13], VE[ive]->bcorners[14],
3712       VE[ive]->bcorners[15], VE[ive]->bcorners[16], VE[ive]->bcorners[17],
3713       VE[ive]->bcorners[18], VE[ive]->bcorners[19], VE[ive]->bcorners[20],
3714       VE[ive]->bcorners[21], VE[ive]->bcorners[22], VE[ive]->bcorners[23]);
3715 
3716    SUMA_RETURN(YUP);
3717 }
3718 
SUMA_TDO_N_tracts(SUMA_TractDO * tdo)3719 int SUMA_TDO_N_tracts(SUMA_TractDO *tdo)
3720 {
3721    static char FuncName[]={"SUMA_TDO_N_tracts"};
3722    int ntr = -1, ii;
3723    TAYLOR_BUNDLE *tb=NULL;
3724 
3725    SUMA_ENTRY;
3726 
3727    if (!tdo || !tdo->net) SUMA_RETURN(ntr);
3728 
3729    ntr = 0;
3730    for (ii=0; ii<tdo->net->N_tbv; ++ii) {
3731       if ((tb = tdo->net->tbv[ii])) ntr += tb->N_tracts;
3732    }
3733 
3734    SUMA_RETURN(ntr);
3735 }
3736 
SUMA_TDO_Max_N_tracts(SUMA_TractDO * tdo)3737 int SUMA_TDO_Max_N_tracts(SUMA_TractDO *tdo)
3738 {
3739    static char FuncName[]={"SUMA_TDO_N_tracts"};
3740    int ntr = -1, ii;
3741    TAYLOR_BUNDLE *tb=NULL;
3742 
3743    SUMA_ENTRY;
3744 
3745    if (!tdo || !tdo->net) SUMA_RETURN(ntr);
3746 
3747    SUMA_RETURN(Network_Max_tract_length(tdo->net, 0, NULL, NULL));
3748 
3749 }
3750 
SUMA_TDO_Grid_Center(SUMA_TractDO * tdo,float * here)3751 float *SUMA_TDO_Grid_Center(SUMA_TractDO *tdo, float *here)
3752 {
3753    static char FuncName[]={"SUMA_TDO_Grid_Center"};
3754    static int icall=0;
3755    static float fv[10][3];
3756    float A[4][4], I[3];
3757    THD_3dim_dataset *dset=NULL;
3758    SUMA_Boolean LocalHead = NOPE;
3759 
3760    SUMA_ENTRY;
3761 
3762    if (!here) {
3763       ++icall; if (icall > 9) icall = 0;
3764       here = (float *)(&fv[icall]);
3765    }
3766    here[0] = here[1] = here[2] =  0.0;
3767 
3768    if (!tdo || !tdo->net || !tdo->net->grid) SUMA_RETURN(here);
3769 
3770    dset = tdo->net->grid;
3771 
3772    if (  !dset->daxes ||
3773          !ISVALID_MAT44(dset->daxes->ijk_to_dicom_real)) {
3774       SUMA_S_Err("no valid ijk_to_dicom_real") ;
3775       SUMA_RETURN(here);
3776    }
3777    MAT44_TO_AFF44(A, dset->daxes->ijk_to_dicom_real);
3778    I[0] = DSET_NX(dset)/2.0;
3779    I[1] = DSET_NY(dset)/2.0;
3780    I[2] = DSET_NZ(dset)/2.0;
3781    AFF44_MULT_I(here, A, I);
3782 
3783    SUMA_RETURN(here);
3784 }
3785 
SUMA_MDO_Center(SUMA_MaskDO * MDO,float * here)3786 float *SUMA_MDO_Center(SUMA_MaskDO *MDO, float *here)
3787 {
3788    static char FuncName[]={"SUMA_MDO_Center"};
3789    static int icall=0;
3790    static float fv[10][3];
3791    float I[3];
3792    int *Nxyz, i;
3793    SUMA_DSET *dset=NULL;
3794    SUMA_Boolean LocalHead = NOPE;
3795 
3796    SUMA_ENTRY;
3797 
3798    if (!here) {
3799       ++icall; if (icall > 9) icall = 0;
3800       here = (float *)(&fv[icall]);
3801    }
3802    here[0] = here[1] = here[2] =  0.0;
3803 
3804    if (!MDO) SUMA_RETURN(here);
3805 
3806    for (i=0; i<MDO->N_obj; ++i) {
3807       here[0] += MDO->cen[3*i  ];
3808       here[1] += MDO->cen[3*i+1];
3809       here[2] += MDO->cen[3*i+2];
3810    }
3811    here[0] /= (float)MDO->N_obj;
3812    here[1] /= (float)MDO->N_obj;
3813    here[2] /= (float)MDO->N_obj;
3814 
3815    SUMA_RETURN(here);
3816 }
3817 
SUMA_VO_Grid_Center(SUMA_VolumeObject * vo,float * here)3818 float *SUMA_VO_Grid_Center(SUMA_VolumeObject *vo, float *here)
3819 {
3820    static char FuncName[]={"SUMA_VO_Grid_Center"};
3821    static int icall=0;
3822    static float fv[10][3];
3823    float I[3];
3824    int *Nxyz;
3825    SUMA_DSET *dset=NULL;
3826    SUMA_Boolean LocalHead = NOPE;
3827 
3828    SUMA_ENTRY;
3829 
3830    if (!here) {
3831       ++icall; if (icall > 9) icall = 0;
3832       here = (float *)(&fv[icall]);
3833    }
3834    here[0] = here[1] = here[2] =  0.0;
3835 
3836    if (!vo || !vo->VE[0] || !(dset = SUMA_VO_dset(vo))) SUMA_RETURN(here);
3837 
3838    Nxyz = SUMA_GetDatasetDimensions(dset);
3839    I[0] = Nxyz[0]/2.0;
3840    I[1] = Nxyz[1]/2.0;
3841    I[2] = Nxyz[2]/2.0;
3842    AFF44_MULT_I(here, vo->VE[0]->I2X, I);
3843 
3844    SUMA_RETURN(here);
3845 }
3846 
SUMA_TDO_Points_Center(SUMA_TractDO * tdo,float * here)3847 float *SUMA_TDO_Points_Center(SUMA_TractDO *tdo, float *here)
3848 {
3849    static char FuncName[]={"SUMA_TDO_Points_Center"};
3850    static int icall=0;
3851    static float fv[10][3];
3852    int ii, jj, kk, npts = 0;
3853    TAYLOR_BUNDLE *tb=NULL;
3854    TAYLOR_TRACT *tt=NULL;
3855    SUMA_Boolean LocalHead = NOPE;
3856 
3857    SUMA_ENTRY;
3858 
3859    if (!here) {
3860       ++icall; if (icall > 9) icall = 0;
3861       here = (float *)(&fv[icall]);
3862    }
3863    here[0] = here[1] = here[2] =  0.0;
3864 
3865    if (!tdo || !tdo->net || !tdo->net->tbv) SUMA_RETURN(here);
3866 
3867    npts = 0;
3868    for (ii=0; ii<tdo->net->N_tbv; ++ii) {
3869       if ((tb = tdo->net->tbv[ii])) {
3870          for (jj=0; jj<tb->N_tracts; ++jj) {
3871             if ((tt = tb->tracts+jj) && tt->N_pts3>2) {
3872                kk=0;
3873                do {
3874                   here[0] += tt->pts[kk++];
3875                   here[1] += tt->pts[kk++];
3876                   here[2] += tt->pts[kk++];
3877                } while (kk<tt->N_pts3);
3878                npts += tt->N_pts3/3;
3879             }
3880          }
3881       }
3882    }
3883 
3884    here[0] /= (float)npts;
3885    here[1] /= (float)npts;
3886    here[2] /= (float)npts;
3887 
3888    SUMA_RETURN(here);
3889 }
3890 
SUMA_TDO_XYZ_Range(SUMA_TractDO * tdo,float * here)3891 float *SUMA_TDO_XYZ_Range(SUMA_TractDO *tdo, float *here)
3892 {
3893    static char FuncName[]={"SUMA_TDO_XYZ_Range"};
3894    static int icall=0;
3895    static float fv[10][6];
3896    int ii, jj, kk, ok;
3897    TAYLOR_BUNDLE *tb=NULL;
3898    TAYLOR_TRACT *tt=NULL;
3899    SUMA_Boolean LocalHead = NOPE;
3900 
3901    SUMA_ENTRY;
3902 
3903    if (!here) {
3904       ++icall; if (icall > 9) icall = 0;
3905       here = (float *)(&fv[icall]);
3906    }
3907    here[0] = here[2] = here[4] =  -20;
3908    here[1] = here[3] = here[5] =   20;
3909    if (!tdo || !tdo->net || !tdo->net->tbv) SUMA_RETURN(here);
3910 
3911    here[0] = here[2] = here[4] =   2000000000000;
3912    here[1] = here[3] = here[5] =  -2000000000000;
3913    ok = 0;
3914    for (ii=0; ii<tdo->net->N_tbv; ++ii) {
3915       if ((tb = tdo->net->tbv[ii])) {
3916          for (jj=0; jj<tb->N_tracts; ++jj) {
3917             if ((tt = tb->tracts+jj) && tt->N_pts3>2) {
3918                kk=0;
3919                do {
3920                   if (here[0] > tt->pts[kk]) here[0] = tt->pts[kk];
3921                   if (here[1] < tt->pts[kk]) here[1] = tt->pts[kk]; ++kk;
3922 
3923                   if (here[2] > tt->pts[kk]) here[2] = tt->pts[kk];
3924                   if (here[3] < tt->pts[kk]) here[3] = tt->pts[kk]; ++kk;
3925 
3926                   if (here[4] > tt->pts[kk]) here[4] = tt->pts[kk];
3927                   if (here[5] < tt->pts[kk]) here[5] = tt->pts[kk]; ++kk;
3928                } while (kk<tt->N_pts3);
3929                if (!ok && kk>0) ok=1;
3930             }
3931          }
3932       }
3933    }
3934 
3935    if (!ok) { /* weird, nothing at all, revert to defaults */
3936       here[0] = here[2] = here[4] =  -20;
3937       here[1] = here[3] = here[5] =   20;
3938    }
3939 
3940    SUMA_RETURN(here);
3941 }
3942 
SUMA_SDO_XYZ_Range(SUMA_SurfaceObject * cso,float * here)3943 float *SUMA_SDO_XYZ_Range(SUMA_SurfaceObject *cso, float *here)
3944 {
3945    static char FuncName[]={"SUMA_SDO_XYZ_Range"};
3946    static int icall=0;
3947    static float fv[10][6];
3948    SUMA_Boolean LocalHead = NOPE;
3949 
3950    SUMA_ENTRY;
3951 
3952    if (!here) {
3953       ++icall; if (icall > 9) icall = 0;
3954       here = (float *)(&fv[icall]);
3955    }
3956    here[0] = here[2] = here[4] =  -20;
3957    here[1] = here[3] = here[5] =   20;
3958 
3959    if (!cso) SUMA_RETURN(here);
3960 
3961    here[0] = cso->MinDims[0]; here[1] = cso->MaxDims[0];
3962    here[2] = cso->MinDims[1]; here[3] = cso->MaxDims[1];
3963    here[4] = cso->MinDims[2]; here[5] = cso->MaxDims[2];
3964 
3965 
3966    SUMA_RETURN(here);
3967 }
3968 
SUMA_CIFTI_DO_XYZ_Range(SUMA_CIFTI_DO * CO,float * here)3969 float *SUMA_CIFTI_DO_XYZ_Range(SUMA_CIFTI_DO *CO, float *here)
3970 {
3971    static char FuncName[]={"SUMA_CIFTI_DO_XYZ_Range"};
3972    static int icall=0;
3973    static float fv[10][6];
3974    int k, j;
3975    float *xyzr=NULL, def[6] = {-20, 20, -20, 20, -20, 20};
3976    SUMA_ALL_DO *asdo=NULL;
3977    SUMA_Boolean LocalHead = NOPE;
3978 
3979    SUMA_ENTRY;
3980 
3981    if (!here) {
3982       ++icall; if (icall > 9) icall = 0;
3983       here = (float *)(&fv[icall]);
3984    }
3985    here[0] = here[2] = here[4] =  -20;
3986    here[1] = here[3] = here[5] =   20;
3987 
3988    if (!CO) SUMA_RETURN(here);
3989 
3990    for (k = 0; k < CO->N_subdoms; ++k) {
3991       asdo = SUMA_CIFTI_subdom_ado(CO,k);
3992       switch (asdo->do_type) {
3993 	 case SO_type:
3994 	    xyzr = SUMA_SDO_XYZ_Range((SUMA_SurfaceObject *)asdo,NULL);
3995 	    break;
3996 	 case VO_type:
3997       	    xyzr = SUMA_VO_XYZ_Range((SUMA_VolumeObject *)asdo,NULL);
3998 	    break;
3999 	 default:
4000 	    xyzr = def;
4001 	    SUMA_S_Warn("Not ready for %d in CIFTI", asdo->do_type);
4002 	    break;
4003       }
4004       if (k==0) {
4005          for (j=0; j<6; ++j) {
4006             here[j] = xyzr[j];
4007          }
4008       } else {
4009          for (j=0; j<3; ++j) {
4010             if (xyzr[2*j  ] < here[2*j  ])  here[2*j  ] = xyzr[2*j];
4011             if (xyzr[2*j+1] > here[2*j+1])  here[2*j+1] = xyzr[2*j+1];
4012          }
4013       }
4014    }
4015 
4016 
4017    SUMA_RETURN(here);
4018 }
4019 
SUMA_VO_XYZ_Range(SUMA_VolumeObject * VO,float * here)4020 float *SUMA_VO_XYZ_Range(SUMA_VolumeObject *VO, float *here)
4021 {
4022    static char FuncName[]={"SUMA_VO_XYZ_Range"};
4023    static int icall=0;
4024    static float fv[10][6];
4025    int ii, jj, kk, ok;
4026    SUMA_DSET *dset=NULL;
4027    SUMA_Boolean LocalHead = NOPE;
4028 
4029    SUMA_ENTRY;
4030 
4031    if (!here) {
4032       ++icall; if (icall > 9) icall = 0;
4033       here = (float *)(&fv[icall]);
4034    }
4035    here[0] = here[2] = here[4] =  -20;
4036    here[1] = here[3] = here[5] =   20;
4037    if (!VO || !(dset = SUMA_VO_dset(VO))) SUMA_RETURN(here);
4038 
4039    here[0] = here[2] = here[4] =   2000000000000;
4040    here[1] = here[3] = here[5] =  -2000000000000;
4041 
4042    here[0] = VO->VE[0]->bo0[0]; here[1] = VO->VE[0]->boN[0];
4043       if (here[0] > here[1]) { /* Happens for certain orientations.
4044                                   Point 0 is voxel i j k 0 0 0 */
4045          here[0] = here[1];
4046          here[1] = VO->VE[0]->bo0[0];
4047       }
4048    here[2] = VO->VE[0]->bo0[1]; here[3] = VO->VE[0]->boN[1];
4049       if (here[2] > here[3]) {
4050          here[2] = here[3];
4051          here[3] = VO->VE[0]->bo0[1];
4052       }
4053 
4054    here[4] = VO->VE[0]->bo0[2]; here[5] = VO->VE[0]->boN[2];
4055       if (here[4] > here[5]) {
4056          here[4] = here[5];
4057          here[5] = VO->VE[0]->bo0[2];
4058       }
4059    SUMA_RETURN(here);
4060 }
4061 
SUMA_MDO_XYZ_Range(SUMA_MaskDO * MDO,float * here)4062 float *SUMA_MDO_XYZ_Range(SUMA_MaskDO *MDO, float *here)
4063 {
4064    static char FuncName[]={"SUMA_MDO_XYZ_Range"};
4065    static int icall=0;
4066    static float fv[10][6];
4067    int ii, ok;
4068    float ff;
4069    SUMA_DSET *dset=NULL;
4070    SUMA_Boolean LocalHead = NOPE;
4071 
4072    SUMA_ENTRY;
4073 
4074    if (!here) {
4075       ++icall; if (icall > 9) icall = 0;
4076       here = (float *)(&fv[icall]);
4077    }
4078    here[0] = here[2] = here[4] =  -20;
4079    here[1] = here[3] = here[5] =   20;
4080    if (!MDO) SUMA_RETURN(here);
4081 
4082    here[0] = here[2] = here[4] =   2000000000000;
4083    here[1] = here[3] = here[5] =  -2000000000000;
4084 
4085    if (MDO->mtype[0] == 'c' || MDO->mtype[0] == 'b') { /* cube or sphere */
4086       for (ii=0; ii<MDO->N_obj; ++ii) {
4087          if ((ff = MDO->cen[3*ii+0]-MDO->hdim[3*ii+0])<here[0]) here[0] = ff;
4088          if ((ff = MDO->cen[3*ii+0]+MDO->hdim[3*ii+0])>here[1]) here[1] = ff;
4089          if ((ff = MDO->cen[3*ii+1]-MDO->hdim[3*ii+1])<here[2]) here[2] = ff;
4090          if ((ff = MDO->cen[3*ii+1]+MDO->hdim[3*ii+1])>here[3]) here[3] = ff;
4091          if ((ff = MDO->cen[3*ii+2]-MDO->hdim[3*ii+2])<here[4]) here[4] = ff;
4092          if ((ff = MDO->cen[3*ii+2]+MDO->hdim[3*ii+2])>here[5]) here[5] = ff;
4093       }
4094    } else if (MDO->mtype[0] == 's') { /* surface */
4095       if (!MDO->SO) {
4096          SUMA_S_Err("Surface not present");
4097       } else {
4098          here[0] = MDO->SO->MinDims[0]; here[1] = MDO->SO->MaxDims[0];
4099          here[2] = MDO->SO->MinDims[1]; here[3] = MDO->SO->MaxDims[1];
4100          here[4] = MDO->SO->MinDims[2]; here[5] = MDO->SO->MaxDims[2];
4101       }
4102    } else {
4103       SUMA_S_Err("Not ready for MDO->type=%s", MDO->mtype);
4104    }
4105    SUMA_RETURN(here);
4106 }
4107 
SUMA_ADO_Center(SUMA_ALL_DO * ado,float * here)4108 float *SUMA_ADO_Center(SUMA_ALL_DO *ado, float *here)
4109 {
4110    static char FuncName[]={"SUMA_ADO_Center"};
4111    static int icall=0;
4112    static float fv[10][3];
4113    SUMA_Boolean LocalHead = NOPE;
4114 
4115    SUMA_ENTRY;
4116 
4117    if (!here) {
4118       ++icall; if (icall > 9) icall = 0;
4119       here = (float *)(&fv[icall]);
4120    }
4121    here[0] = here[1] = here[2] =  0.0;
4122 
4123    if (!ado) SUMA_RETURN(here);
4124 
4125    switch (ado->do_type) {
4126       case SO_type: {
4127          SUMA_SurfaceObject *SO=(SUMA_SurfaceObject *)ado;
4128          here[0] = SO->Center[0];
4129          here[1] = SO->Center[1];
4130          here[2] = SO->Center[2];
4131          SUMA_RETURN(here);
4132          break; }
4133       case TRACT_type: {
4134          SUMA_TractDO *tdo = (SUMA_TractDO *)ado;
4135          SUMA_TRACT_SAUX *TSaux=NULL;
4136          if (!tdo || !tdo->net || !tdo->net->tbv
4137              || !(TSaux = TDO_TSAUX(tdo))) SUMA_RETURN(here);
4138          if (!TSaux->Center) {
4139             TSaux->Center = (float *)SUMA_malloc(3*sizeof(float));
4140             SUMA_TDO_Points_Center(tdo, TSaux->Center);
4141          }
4142          here[0] = TSaux->Center[0];
4143          here[1] = TSaux->Center[1];
4144          here[2] = TSaux->Center[2];
4145          SUMA_RETURN(here);
4146          break; }
4147       case MASK_type: {
4148          SUMA_MaskDO *mdo = (SUMA_MaskDO *)ado;
4149          SUMA_MDO_Center(mdo, here);
4150          SUMA_RETURN(here);
4151          break;}
4152       case VO_type: {
4153          SUMA_VolumeObject *vo = (SUMA_VolumeObject *)ado;
4154          SUMA_VO_Grid_Center(vo, here);
4155          SUMA_RETURN(here);
4156          break; }
4157       case GRAPH_LINK_type: {
4158          char *variant = NULL;
4159          SUMA_DSET *dset=NULL;
4160          SUMA_GRAPH_SAUX *GSaux=NULL;
4161          if(!(dset=SUMA_find_GLDO_Dset((SUMA_GraphLinkDO *)ado))){
4162             SUMA_S_Err("Gildaaaaaaaaaaaaaaaaaa");
4163             SUMA_RETURN(here);
4164          }
4165          variant = SUMA_ADO_variant(ado);
4166          if (!SUMA_IS_REAL_VARIANT(variant) ||
4167              !(GSaux = SDSET_GSAUX(dset))) {
4168             SUMA_RETURN(here);
4169          }
4170          if (!strcmp(variant,"G3D")) {
4171             if (!GSaux->Center_G3D) {
4172                GSaux->Center_G3D = (float *)SUMA_malloc(3*sizeof(float));
4173                SUMA_GDSET_XYZ_Center(dset, variant, GSaux->Center_G3D);
4174             }
4175             here[0] = GSaux->Center_G3D[0];
4176             here[1] = GSaux->Center_G3D[1];
4177             here[2] = GSaux->Center_G3D[2];
4178             SUMA_RETURN(here);
4179          } else if (!strcmp(variant,"GMATRIX")) {
4180             if (!GSaux->Center_GMATRIX) {
4181                GSaux->Center_GMATRIX = (float *)SUMA_malloc(3*sizeof(float));
4182                SUMA_GDSET_XYZ_Center(dset, variant, GSaux->Center_GMATRIX);
4183             }
4184             here[0] = GSaux->Center_GMATRIX[0];
4185             here[1] = GSaux->Center_GMATRIX[1];
4186             here[2] = GSaux->Center_GMATRIX[2];
4187             SUMA_RETURN(here);
4188          } else {
4189             SUMA_S_Err("Not ready for variant %s", variant);
4190             SUMA_RETURN(here);
4191          }
4192          break; }
4193       case CDOM_type: {
4194       	 float there[3] = {0,0,0};
4195 	 int k, i;
4196 	 SUMA_CIFTI_DO *CO=(SUMA_CIFTI_DO*)ado;
4197 	 SUMA_ALL_DO *asdo=NULL;
4198 	 for (k=0; k<CO->N_subdoms; ++k) {
4199             asdo = SUMA_CIFTI_subdom_ado(CO,k);
4200 	    switch(asdo->do_type) {
4201 	       case VO_type:
4202 	       case SO_type:
4203 	          SUMA_ADO_Center(asdo, there);
4204 	          for (i=0; i<3;++i) here[i] += there[i];
4205 		  break;
4206 	       case CDOM_type:
4207 	          SUMA_S_Err("This should not happen. "
4208 		     	     "If it does, consider recursion problems");
4209 		  break;
4210 	       default:
4211 	          SUMA_S_Err("No support for subtype %d",
4212 		     	     asdo->do_type);
4213 		  break;
4214 	    }
4215 	 }
4216 	 for (i=0; i<3;++i) here[i] /= ((float)CO->N_subdoms);
4217       	 break; }
4218       default:
4219          SUMA_S_Err("Not ready to return center for type %s", ADO_TNAME(ado));
4220          SUMA_RETURN(here);
4221          break;
4222    }
4223    SUMA_RETURN(here);
4224 }
4225 
SUMA_ADO_Range(SUMA_ALL_DO * ado,float * here)4226 float *SUMA_ADO_Range(SUMA_ALL_DO *ado, float *here)
4227 {
4228    static char FuncName[]={"SUMA_ADO_Range"};
4229    static int icall=0;
4230    static float fv[10][6];
4231    SUMA_Boolean LocalHead = NOPE;
4232 
4233    SUMA_ENTRY;
4234 
4235    if (!here) {
4236       ++icall; if (icall > 9) icall = 0;
4237       here = (float *)(&fv[icall]);
4238    }
4239    /* An error inspiring range */
4240    here[0] = here[2] = here[4] =   2000000000000;
4241    here[1] = here[3] = here[5] =  -2000000000000;
4242 
4243    if (!ado) SUMA_RETURN(here);
4244 
4245    switch (ado->do_type) {
4246       case SO_type: {
4247          SUMA_SurfaceObject *SO=(SUMA_SurfaceObject *)ado;
4248          here[0] = SO->MinDims[0];
4249          here[1] = SO->MaxDims[0];
4250          here[2] = SO->MinDims[1];
4251          here[3] = SO->MaxDims[1];
4252          here[4] = SO->MinDims[2];
4253          here[5] = SO->MaxDims[2];
4254          SUMA_RETURN(here);
4255          break; }
4256       case TRACT_type: {
4257          SUMA_TractDO *tdo = (SUMA_TractDO *)ado;
4258          SUMA_TRACT_SAUX *TSaux=NULL;
4259          if (!tdo || !tdo->net || !tdo->net->tbv
4260              || !(TSaux = TDO_TSAUX(tdo))) SUMA_RETURN(here);
4261          if (!TSaux->Range) {
4262             TSaux->Range = (float *)SUMA_malloc(6*sizeof(float));
4263             SUMA_TDO_XYZ_Range(tdo, TSaux->Range);
4264          }
4265          here[0] = TSaux->Range[0];
4266          here[1] = TSaux->Range[1];
4267          here[2] = TSaux->Range[2];
4268          here[3] = TSaux->Range[3];
4269          here[4] = TSaux->Range[4];
4270          here[5] = TSaux->Range[5];
4271          SUMA_RETURN(here);
4272          break; }
4273       case MASK_type: {
4274          SUMA_MaskDO *mdo = (SUMA_MaskDO *)ado;
4275          SUMA_MDO_XYZ_Range(mdo, here);
4276          SUMA_RETURN(here);
4277          break;}
4278       case VO_type: {
4279          SUMA_VolumeObject *vo = (SUMA_VolumeObject *)ado;
4280          SUMA_VO_XYZ_Range(vo, here);
4281          SUMA_RETURN(here);
4282          break; }
4283       case GRAPH_LINK_type: {
4284          char *variant = NULL;
4285          SUMA_DSET *dset=NULL;
4286          SUMA_GRAPH_SAUX *GSaux=NULL;
4287          if(!(dset=SUMA_find_GLDO_Dset((SUMA_GraphLinkDO *)ado))){
4288             SUMA_S_Err("Gildaaaaaaaaaaaaaaaaaa");
4289             SUMA_RETURN(here);
4290          }
4291          variant = SUMA_ADO_variant(ado);
4292          if (!SUMA_IS_REAL_VARIANT(variant) ||
4293              !(GSaux = SDSET_GSAUX(dset))) {
4294             SUMA_RETURN(here);
4295          }
4296          if (!strcmp(variant,"G3D")) {
4297             if (!GSaux->Range_G3D) {
4298                GSaux->Range_G3D = (float *)SUMA_malloc(6*sizeof(float));
4299                SUMA_GDSET_XYZ_Range(dset, variant, GSaux->Range_G3D);
4300             }
4301             here[0] = GSaux->Range_G3D[0];
4302             here[1] = GSaux->Range_G3D[1];
4303             here[2] = GSaux->Range_G3D[2];
4304             here[3] = GSaux->Range_G3D[3];
4305             here[4] = GSaux->Range_G3D[4];
4306             here[5] = GSaux->Range_G3D[5];
4307             SUMA_RETURN(here);
4308          } else if (!strcmp(variant,"GMATRIX")) {
4309             if (!GSaux->Range_GMATRIX) {
4310                SUMA_GDSET_XYZ_Range(dset, variant, GSaux->Range_GMATRIX);
4311             }
4312             here[0] = GSaux->Range_GMATRIX[0];
4313             here[1] = GSaux->Range_GMATRIX[1];
4314             here[2] = GSaux->Range_GMATRIX[2];
4315             here[3] = GSaux->Range_GMATRIX[3];
4316             here[4] = GSaux->Range_GMATRIX[4];
4317             here[5] = GSaux->Range_GMATRIX[5];
4318             SUMA_RETURN(here);
4319          } else {
4320             SUMA_S_Err("Not ready for variant %s", variant);
4321             SUMA_RETURN(here);
4322          }
4323          break; }
4324       case CDOM_type:
4325       	 SUMA_CIFTI_DO_XYZ_Range((SUMA_CIFTI_DO*)ado, here);
4326          SUMA_RETURN(here);
4327 	 break;
4328       default:
4329          SUMA_S_Err("Not ready to return center for type %s", ADO_TNAME(ado));
4330          SUMA_RETURN(here);
4331          break;
4332    }
4333    SUMA_RETURN(here);
4334 }
4335 
4336 
4337 /* Create some default datasets and their overlays
4338    At the moment, two overlays are created but
4339    you might want to create just one and refill
4340    it based on whether or not one wants to color
4341    by mid point or by local orientation
4342    Two tract coloring schemes (or more) seems like overkill to me*/
SUMA_TDO_DefaultOverlays(SUMA_TractDO * TDO)4343 SUMA_Boolean SUMA_TDO_DefaultOverlays(SUMA_TractDO *TDO)
4344 {
4345    static char FuncName[]={"SUMA_TDO_DefaultOverlays"};
4346    TAYLOR_NETWORK *net=NULL;
4347    SUMA_OVERLAY_PLANE_DATA sopd;
4348    SUMA_X_SurfCont *SurfCont=NULL;
4349    SUMA_ALL_DO *ado = (SUMA_ALL_DO *)TDO;
4350    int knet, n, N_pts, tid, pid, pid0, p, dotract= 0;
4351    float *pa, *pb, U[4], Un, fv5[5];
4352    int *iv=NULL, OverInd;
4353    char *ltmp=NULL;
4354    byte *rv=NULL,*gv=NULL, *bv=NULL;
4355    TAYLOR_BUNDLE *tb=NULL;
4356    TAYLOR_TRACT *tt=NULL;
4357    SUMA_Boolean LocalHead = NOPE;
4358 
4359    SUMA_ENTRY;
4360 
4361    dotract = dotract | 1; /* color by bundle id */
4362    dotract = dotract | 2; /* color by tract mid point orientation */
4363    dotract = dotract | 3; /* color by tract local orientation */
4364 
4365    memset(&sopd, 0, sizeof(SUMA_OVERLAY_PLANE_DATA));
4366    if (dotract & 1) {
4367    SUMA_LH("Coloring by bundle id");
4368    ltmp = SUMA_append_replace_string(
4369             without_afni_filename_extension(SUMA_ADO_Label(ado)), "BUN","_",0);
4370    if (!SUMA_Fetch_OverlayPointer (ado, ltmp, &OverInd)) {
4371       sopd.dtlvl = SUMA_LEV2_DAT; /* colors per bundle */
4372       if ( (sopd.N = SUMA_ADO_N_Datum_Lev(ado, sopd.dtlvl)) <= 0) {
4373          SUMA_S_Err("You give me nothing you get nothing for %s, %d",
4374                      SUMA_ADO_Label(ado), sopd.dtlvl);
4375          SUMA_RETURN(NOPE);
4376       }
4377       sopd.Type = SOPT_ibbb;
4378       iv = (int*)SUMA_calloc(sopd.N, sizeof(int));
4379       rv = (byte*)SUMA_calloc(sopd.N, sizeof(byte));
4380       gv = (byte*)SUMA_calloc(sopd.N, sizeof(byte));
4381       bv = (byte*)SUMA_calloc(sopd.N, sizeof(byte));
4382       sopd.Source = SES_Suma;
4383       sopd.GlobalOpacity = 1.0;
4384       sopd.isBackGrnd = NOPE;
4385       sopd.Show = YUP;
4386       sopd.DimFact = 1.0;
4387       if (!iv || !rv || !gv || !bv) {
4388          SUMA_S_Err("Failed to allocate for 4*%d bytes", sopd.N);
4389          SUMA_RETURN(NOPE);
4390       }
4391 
4392       #if 0 /* colors at rand */
4393       for (knet=0; knet<TDO->net->N_tbv; ++knet) {
4394          iv[knet] = knet;
4395          rv[knet] = (byte)(SUMA_IRAN(256));
4396          gv[knet] = (byte)(SUMA_IRAN(256));
4397          bv[knet] = (byte)(SUMA_IRAN(256));
4398       }
4399       #else /* colors from ROI colormap? */
4400       for (knet=0; knet<TDO->net->N_tbv; ++knet) {
4401          iv[knet] = knet;
4402          if (knet < 256 && SUMA_a_good_col("ROI_i256", knet, fv5)) {
4403             rv[knet] = (byte)(255.0*fv5[0]);
4404             gv[knet] = (byte)(255.0*fv5[1]);
4405             bv[knet] = (byte)(255.0*fv5[2]);
4406          } else {
4407             rv[knet] = (byte)(SUMA_IRAN(256));
4408             gv[knet] = (byte)(SUMA_IRAN(256));
4409             bv[knet] = (byte)(SUMA_IRAN(256));
4410          }
4411       }
4412       #endif
4413       sopd.i = (void *)iv;
4414       sopd.r = (void *)rv;
4415       sopd.g = (void *)gv;
4416       sopd.b = (void *)bv;
4417 
4418       SUMA_LH("Creating overlay %s for tract based data", ltmp);
4419       if (!SUMA_iRGB_to_OverlayPointer (  ado,
4420                                           ltmp,
4421                                           &sopd, &OverInd,
4422                                           SUMAg_DOv, SUMAg_N_DOv,
4423                                           SUMAg_CF->DsetList)) {
4424          SUMA_SLP_Err("Failed to fetch or create overlay pointer.");
4425          SUMA_RETURN(NOPE);
4426       }
4427 
4428       SUMA_ifree(iv); SUMA_ifree(rv); SUMA_ifree(gv); SUMA_ifree(bv);
4429       sopd.i = sopd.r = sopd.g = sopd.b = NULL;
4430    } else {
4431       SUMA_S_Warn("Overlay %s exists, nothing was done.", ltmp);
4432    }
4433    SUMA_ifree(ltmp);
4434    }
4435 
4436    if (dotract & 2) {
4437    SUMA_LH("Coloring by orientation at middle");
4438    ltmp = SUMA_append_replace_string(
4439             without_afni_filename_extension(SUMA_ADO_Label(ado)), "MID","_",0);
4440    if (!SUMA_Fetch_OverlayPointer (ado, ltmp, &OverInd)) {
4441       sopd.dtlvl = SUMA_LEV1_DAT; /* colors per tract */
4442       if ( (sopd.N = SUMA_ADO_N_Datum_Lev(ado, sopd.dtlvl)) <= 0) {
4443          SUMA_S_Err("You give me nothing you get nothing for %s, %d",
4444                      SUMA_ADO_Label(ado), sopd.dtlvl);
4445          SUMA_RETURN(NOPE);
4446       }
4447       sopd.Type = SOPT_ibbb;
4448       iv = (int*)SUMA_calloc(sopd.N, sizeof(int));
4449       rv = (byte*)SUMA_calloc(sopd.N, sizeof(byte));
4450       gv = (byte*)SUMA_calloc(sopd.N, sizeof(byte));
4451       bv = (byte*)SUMA_calloc(sopd.N, sizeof(byte));
4452       sopd.Source = SES_Suma;
4453       sopd.GlobalOpacity = 1.0;
4454       sopd.isBackGrnd = NOPE;
4455       sopd.Show = YUP;
4456       sopd.DimFact = 1.0;
4457       if (!iv || !rv || !gv || !bv) {
4458          SUMA_S_Err("Failed to allocate for 4*%d bytes", sopd.N);
4459          SUMA_RETURN(NOPE);
4460       }
4461       tid = 0; /* track id */
4462       for (knet=0; knet<TDO->net->N_tbv; ++knet) {
4463          tb = TDO->net->tbv[knet];
4464          for (n=0; tb && n<tb->N_tracts; ++n) {
4465             tt = tb->tracts+n;
4466             N_pts = TRACT_NPTS(tt);
4467             if (N_pts>=2) {
4468                /* set color based on mid point */
4469                pa = tt->pts+(N_pts/2)*3;
4470                pb = pa - 3;
4471                SUMA_SEG_DELTA_COL(pa,pb,U, Un);
4472                iv[tid] = tid;
4473                rv[tid] = (byte)(255.0*U[0]);
4474                gv[tid] = (byte)(255.0*U[1]);
4475                bv[tid] = (byte)(255.0*U[2]);
4476             } else {
4477                iv[tid] = tid;
4478                rv[tid] = 128;
4479                gv[tid] = 128;
4480                bv[tid] = 128;
4481             }
4482             ++tid;
4483          }
4484       }
4485       sopd.i = (void *)iv;
4486       sopd.r = (void *)rv;
4487       sopd.g = (void *)gv;
4488       sopd.b = (void *)bv;
4489 
4490       SUMA_LH("Creating overlay %s for tract based data", ltmp);
4491       if (!SUMA_iRGB_to_OverlayPointer (  ado,
4492                                           ltmp,
4493                                           &sopd, &OverInd,
4494                                           SUMAg_DOv, SUMAg_N_DOv,
4495                                           SUMAg_CF->DsetList)) {
4496          SUMA_SLP_Err("Failed to fetch or create overlay pointer.");
4497          SUMA_RETURN(NOPE);
4498       }
4499 
4500       SUMA_ifree(iv); SUMA_ifree(rv); SUMA_ifree(gv); SUMA_ifree(bv);
4501       sopd.i = sopd.r = sopd.g = sopd.b = NULL;
4502    } else {
4503       SUMA_S_Warn("Overlay %s exists, nothing was done.", ltmp);
4504    }
4505    SUMA_ifree(ltmp);
4506    }
4507 
4508    if (dotract & 3) {
4509    SUMA_LH("Coloring by local orientation");
4510    /* And now create the local orientation based coloring */
4511    ltmp = SUMA_append_replace_string(
4512          without_afni_filename_extension(SUMA_ADO_Label(ado)), "LOC","_",0);
4513    if (!SUMA_Fetch_OverlayPointer (ado, ltmp, &OverInd)) {
4514       sopd.dtlvl = SUMA_ELEM_DAT; /* colors per tract */
4515       if ( (sopd.N = SUMA_ADO_N_Datum_Lev(ado, sopd.dtlvl)) <= 0) {
4516          SUMA_S_Err("You give me nothing you get nothing for %s, %d",
4517                      SUMA_ADO_Label(ado), sopd.dtlvl);
4518          SUMA_RETURN(NOPE);
4519       }
4520       sopd.Type = SOPT_ibbb;
4521       iv = (int*)SUMA_calloc(sopd.N, sizeof(int));
4522       rv = (byte*)SUMA_calloc(sopd.N, sizeof(byte));
4523       gv = (byte*)SUMA_calloc(sopd.N, sizeof(byte));
4524       bv = (byte*)SUMA_calloc(sopd.N, sizeof(byte));
4525       sopd.Source = SES_Suma;
4526       sopd.GlobalOpacity = 1.0;
4527       sopd.isBackGrnd = NOPE;
4528       sopd.Show = YUP;
4529       sopd.DimFact = 1.0;
4530       if (!iv || !rv || !gv || !bv) {
4531          SUMA_S_Err("Failed to allocate for 4*%d bytes", sopd.N);
4532          SUMA_RETURN(NOPE);
4533       }
4534       pid = 0; /* point id */
4535       for (knet=0; knet<TDO->net->N_tbv; ++knet) {
4536          tb = TDO->net->tbv[knet];
4537          for (n=0; tb && n<tb->N_tracts; ++n) {
4538             tt = tb->tracts+n;
4539             if ((N_pts = TRACT_NPTS(tt)) >= 2) {
4540                pid0=pid; ++pid;
4541                for (p=1; p<N_pts; ++p) {
4542                   /* set color based on local orientation */
4543                   pa = tt->pts+p*3;
4544                   pb = pa - 3;
4545                   SUMA_SEG_DELTA_COL(pa,pb,U, Un);
4546                   iv[pid] = pid;
4547                   rv[pid] = (byte)(255.0*U[0]);
4548                   gv[pid] = (byte)(255.0*U[1]);
4549                   bv[pid] = (byte)(255.0*U[2]);
4550                   ++pid;
4551                }
4552                /* fill the zero slot */
4553                iv[pid0] = iv[pid0+1];
4554                rv[pid0] = rv[pid0+1];
4555                gv[pid0] = gv[pid0+1];
4556                bv[pid0] = bv[pid0+1];
4557             } else if (N_pts == 1) { /* Should not happen but oh well */
4558                iv[pid] = pid;
4559                rv[pid] = 128;
4560                gv[pid] = 128;
4561                bv[pid] = 128;
4562                ++pid;
4563             }
4564          }
4565       }
4566       sopd.i = (void *)iv;
4567       sopd.r = (void *)rv;
4568       sopd.g = (void *)gv;
4569       sopd.b = (void *)bv;
4570 
4571       SUMA_LH("Creating overlay %s for point based data, %d vals", ltmp, sopd.N);
4572       if (!SUMA_iRGB_to_OverlayPointer (  ado,
4573                                           ltmp,
4574                                           &sopd, &OverInd,
4575                                           SUMAg_DOv, SUMAg_N_DOv,
4576                                           SUMAg_CF->DsetList)) {
4577          SUMA_SLP_Err("Failed to fetch or create overlay pointer.");
4578          SUMA_RETURN(NOPE);
4579       }
4580 
4581       SUMA_ifree(iv); SUMA_ifree(rv); SUMA_ifree(gv); SUMA_ifree(bv);
4582       sopd.i = sopd.r = sopd.g = sopd.b = NULL;
4583    } else {
4584       SUMA_S_Warn("Overlay %s exists, nothing was done.", ltmp);
4585    }
4586    SUMA_ifree(ltmp);
4587    }
4588 
4589    /* add as current overlay */
4590    if ((SurfCont = SUMA_ADO_Cont(ado)) && !SurfCont->curColPlane) {
4591       SUMA_LH("Set curcolplane to overlay %p index %d",
4592                   SUMA_ADO_Overlay(ado,OverInd), OverInd);
4593       SurfCont->curColPlane = SUMA_ADO_Overlay(ado,OverInd);
4594    }
4595 
4596 
4597    SUMA_RETURN(YUP);
4598 }
4599 
SUMA_ReadTractDO(char * s,char * parent_SO_id)4600 SUMA_TractDO *SUMA_ReadTractDO(char *s, char *parent_SO_id)
4601 {
4602    static char FuncName[]={"SUMA_ReadTractDO"};
4603    TAYLOR_NETWORK *net=NULL;
4604    SUMA_TractDO *TDO=NULL;
4605 
4606    SUMA_ENTRY;
4607 
4608    if (!s) {
4609       SUMA_SLP_Err("NULL s");
4610       SUMA_RETURN(NULL);
4611    }
4612    if (!(net = Read_Network(s))) {
4613       SUMA_S_Errv("Failed to read %s\n",s);
4614       SUMA_RETURN(NULL);
4615    }
4616 
4617    SUMA_RETURN(SUMA_Net2TractDO(net, s, parent_SO_id));
4618 }
4619 
SUMA_Net2TractDO(TAYLOR_NETWORK * net,char * Label,char * parent_SO_id)4620 SUMA_TractDO *SUMA_Net2TractDO(TAYLOR_NETWORK *net,
4621                                char *Label, char *parent_SO_id)
4622 {
4623    static char FuncName[]={"SUMA_Net2TractDO"};
4624    SUMA_TractDO *TDO=NULL;
4625 
4626    SUMA_ENTRY;
4627 
4628    if (!net) {
4629       SUMA_SLP_Err("NULL net");
4630       SUMA_RETURN(NULL);
4631    }
4632 
4633    if (!(TDO = SUMA_Alloc_TractDO (Label, parent_SO_id))) {
4634       SUMA_S_Err("Failed to init TDO.");
4635       SUMA_RETURN(NULL);
4636    }
4637 
4638    TDO->net = net;
4639 
4640    if (!(SUMA_TDO_DefaultOverlays(TDO))) {
4641       SUMA_S_Warn("Failed to create default overlays");
4642    }
4643 
4644    SUMA_RETURN(TDO);
4645 }
4646 
4647 
SUMA_ReadNBSphDO(char * s,char * parent_SO_id)4648 SUMA_SphereDO * SUMA_ReadNBSphDO (char *s, char *parent_SO_id)
4649 {
4650    static char FuncName[]={"SUMA_ReadNBSphDO"};
4651    SUMA_SphereDO *SDO = NULL;
4652    MRI_IMAGE * im = NULL;
4653    float *far=NULL;
4654    int itmp, itmp2, icol_rad=-1, icol_style = -1, icol_col = -1, icol_id = -1;
4655    int nrow=-1, ncol=-1;
4656 
4657    SUMA_ENTRY;
4658 
4659    if (!s) {
4660       SUMA_SLP_Err("NULL s");
4661       SUMA_RETURN(NULL);
4662    }
4663    if (!parent_SO_id) {
4664       SUMA_SLP_Err("NULL parent_SO_id");
4665       SUMA_RETURN(NULL);
4666    }
4667    im = mri_read_1D (s);
4668 
4669    if (!im) {
4670       SUMA_SLP_Err("Failed to read 1D file");
4671       SUMA_RETURN(NULL);
4672    }
4673 
4674    far = MRI_FLOAT_PTR(im);
4675    ncol = im->nx;
4676    nrow = im->ny;
4677 
4678    if (!ncol) {
4679       SUMA_SLP_Err("Empty file");
4680       SUMA_RETURN(NULL);
4681    }
4682 
4683    icol_id = -1;
4684    icol_col = -1;
4685    icol_rad = -1;
4686    icol_style = -1;
4687    switch (nrow) {
4688       case 1:
4689          fprintf(SUMA_STDERR,"%s: Node-Based Sphere file %s's format:\n"
4690                               "n\n", FuncName, s);
4691          icol_id = 0;
4692          break;
4693       case 2:
4694          fprintf(SUMA_STDERR,"%s: Node-Based Sphere file %s's format:\n"
4695                               "n rd\n", FuncName, s);
4696          icol_id = 0;
4697          icol_rad = 1;
4698          break;
4699       case 3:
4700          fprintf(SUMA_STDERR,"%s: Node-Based Sphere file %s's format:\n"
4701                               "n rd st\n", FuncName, s);
4702          icol_id = 0;
4703          icol_rad = 1;
4704          icol_style = 2;
4705          break;
4706       case 5:
4707          fprintf(SUMA_STDERR,"%s: Node-Based Sphere file %s's format:\n"
4708                               "n c0 c1 c2 c3\n", FuncName, s);
4709          icol_id = 0;
4710          icol_col = 1;
4711          break;
4712       case 6:
4713          fprintf(SUMA_STDERR,"%s: Node-Based Sphere file %s's format:\n"
4714                               "n c0 c1 c2 c3 rd\n", FuncName, s);
4715          icol_id = 0;
4716          icol_col = 1;
4717          icol_rad = 5;
4718          break;
4719       case 7:
4720          fprintf(SUMA_STDERR,"%s: Node-Based Sphere file %s's format:\n"
4721                               "n c0 c1 c2 c3 rd st\n", FuncName, s);
4722          icol_id = 0;
4723          icol_col = 1;
4724          icol_rad = 5;
4725          icol_style = 6;
4726          break;
4727       default:
4728          SUMA_SLP_Err("Node-Based Sphere File must have\n"
4729                    "1,2,3,5,6 or 7 columns.");
4730          mri_free(im); im = NULL;   /* done with that baby */
4731          SUMA_RETURN(NULL);
4732    }
4733 
4734    /* allocate for segments DO */
4735    SDO = SUMA_Alloc_SphereDO (ncol, s, parent_SO_id, NBSP_type);
4736    if (!SDO) {
4737       SUMA_S_Err("Failed in SUMA_Allocate_SphereDO.\n");
4738       SUMA_RETURN(NULL);
4739    }
4740 
4741    /* fill up SDO */
4742    itmp = 0;
4743    while (itmp < SDO->N_n) {
4744       SDO->NodeID[itmp] = far[itmp +(icol_id  )*ncol];
4745       ++itmp;
4746    }
4747 
4748    if (icol_col > 0) {
4749       SDO->colv = (GLfloat *)SUMA_malloc(4*sizeof(GLfloat)*SDO->N_n);
4750       if (!SDO->colv) {
4751          SUMA_SL_Crit("Failed in to allocate for colv.");
4752          SUMA_RETURN(NULL);
4753       }
4754       /* fill up idividual colors */
4755       itmp = 0;
4756       while (itmp < SDO->N_n) {
4757          itmp2 = 4*itmp;
4758          SDO->colv[itmp2]     = far[itmp+(icol_col  )*ncol];
4759          SDO->colv[itmp2+1]   = far[itmp+(icol_col+1)*ncol];
4760          SDO->colv[itmp2+2]   = far[itmp+(icol_col+2)*ncol];
4761          SDO->colv[itmp2+3]   = far[itmp+(icol_col+3)*ncol];
4762          ++itmp;
4763       }
4764    }
4765    if (icol_rad > 0) {
4766       SDO->radv = (GLfloat *)SUMA_malloc(sizeof(GLfloat)*SDO->N_n);
4767       if (!SDO->radv) {
4768          SUMA_SL_Crit("Failed in to allocate for radv.");
4769          SUMA_RETURN(NULL);
4770       }
4771       /* fill up idividual radius */
4772       itmp = 0;
4773       while (itmp < SDO->N_n) {
4774          SDO->radv[itmp]     = far[itmp+(icol_rad  )*ncol];
4775          ++itmp;
4776       }
4777    }
4778    if (icol_style > 0) {
4779       SDO->stylev = (GLenum *)SUMA_malloc(sizeof(GLenum)*SDO->N_n);
4780       if (!SDO->stylev) {
4781          SUMA_SL_Crit("Failed in to allocate for radv.");
4782          SUMA_RETURN(NULL);
4783       }
4784       /* fill up idividual style */
4785       itmp = 0;
4786       while (itmp < SDO->N_n) {
4787          SDO->stylev[itmp]     = SUMA_SphereStyleConvert((int)far[itmp+(icol_style  )*ncol]);
4788          ++itmp;
4789       }
4790    }
4791    mri_free(im); im = NULL; far = NULL;
4792 
4793    SUMA_RETURN(SDO);
4794 }
4795 
4796 /* A function to take a single DO and propagate it so that it is
4797 reprenseted on all nodes on the surface.
4798 Basically, the function returns one NIDO with a element at each node.
4799 There can only be one element, not a whole NIDO duplicated at each node
4800 
4801 An alternalte approach is in SUMA_Multiply_NodeNIDOObjects
4802 
4803 An alternate approach, would return a vector of NIDO* with one NIDO pointer
4804 for each node. This way one could put a whole lot of stuff in there.
4805 At rendering time, instead of making one call to DrawNIDO, one calls
4806 DrawNIDO for each node that has a NIDO
4807 */
SUMA_Multiply_NodeObjects(SUMA_SurfaceObject * SO,SUMA_DO * DO)4808 SUMA_DO * SUMA_Multiply_NodeObjects ( SUMA_SurfaceObject *SO,
4809                                       SUMA_DO *DO )
4810 {
4811    static char FuncName[]={"SUMA_Multiply_NodeObjects"};
4812    SUMA_DO *DDO = NULL;
4813    SUMA_NIDO *nido=NULL, *niout=NULL;
4814    void *vel=NULL;
4815    char *atr=NULL;
4816    int i=0;
4817    SUMA_Boolean LocalHead = NOPE;
4818 
4819    SUMA_ENTRY;
4820 
4821    if (!SO || !DO) SUMA_RETURN(NULL);
4822 
4823    SUMA_LHv("Switch on DO type %s and coord type %d\n",
4824             SUMA_ObjectTypeCode2ObjectTypeName(DO->ObjectType),
4825             DO->CoordType);
4826    switch(DO->ObjectType) {
4827       case NIDO_type:
4828          nido=(SUMA_NIDO *)DO->OP;
4829          /* Easiest to duplicate the nido for each of the nodes */
4830          /* although its not efficient for fast drawing, it makes */
4831          /* is real easy to encode a boat load of information, and use*/
4832          /* drawNIDO without much headaches */
4833          if (nido->ngr->part_num != 1) {
4834             SUMA_S_Errv( "CommonNodeMarker has %d elements in it.\n"
4835                          "Not common I'd say.\n", nido->ngr->part_num);
4836             SUMA_RETURN(DDO);
4837          }
4838          if (nido->ngr->part_typ[0] !=  NI_ELEMENT_TYPE) {
4839             SUMA_S_Err("Not ready to duplicate anything but NI_ELEMENT_TYPE");
4840             SUMA_RETURN(DDO);
4841          }
4842          niout = SUMA_Alloc_NIDO(NULL, "from_CommonNodeObject", SO->idcode_str);
4843          if ((atr=NI_get_attribute(nido, "bond")))
4844             NI_set_attribute(niout->ngr, "bond", atr);
4845          else   NI_set_attribute(niout->ngr, "bond", "s");
4846          if ((atr=NI_get_attribute(nido, "coord_type")))
4847             NI_set_attribute(niout->ngr, "coord_type", atr);
4848          else NI_set_attribute(niout->ngr, "coord_type",
4849                      SUMA_CoordTypeName(SUMA_CoordType(NULL)));
4850          if ((atr=NI_get_attribute(nido, "default_font")))
4851             NI_set_attribute(niout->ngr, "default_font", atr);
4852          else NI_set_attribute(niout->ngr, "default_font",
4853                      SUMA_glutBitmapFontName(SUMA_glutBitmapFont(NULL)));
4854          if ((atr=NI_get_attribute(nido, "default_color")))
4855             NI_set_attribute(niout->ngr, "default_color", atr);
4856          else NI_set_attribute(niout->ngr, "default_color",
4857                                                 "1.0 1.0 1.0 1.0");
4858          if ((atr=NI_get_attribute(nido, "render_mode")))
4859             NI_set_attribute(niout->ngr, "render_mode", atr);
4860          else
4861             NI_set_attribute(niout->ngr, "render_mode", "");
4862 
4863          /* Now for each node, create a new copy of that element */
4864          for (i=0; i<SO->N_Node; ++i) {
4865             if ((vel = NI_duplicate(nido->ngr->part[0], 1))) {
4866                /* assign object to the node */
4867                NI_SET_INT((NI_element *)vel, "node", i);
4868                NI_add_to_group(niout->ngr, vel);
4869             } else {
4870                SUMA_S_Err("Failed to create duplicate element");
4871                SUMA_RETURN(DDO);
4872             }
4873          }
4874          break;
4875       default:
4876          SUMA_S_Errv("Sorry Chip, goose %s (%d) ain't ready to fly.\n",
4877                      SUMA_ObjectTypeCode2ObjectTypeName(DO->ObjectType),
4878                      DO->ObjectType);
4879          SUMA_RETURN(NULL);
4880    }
4881 
4882    /* Now put niout in DDO */
4883    DDO = (SUMA_DO *)SUMA_calloc(1,sizeof(SUMA_DO));
4884 
4885    DDO->OP = (void *)niout;
4886    DDO->ObjectType = NIDO_type;
4887    DDO->CoordType = SUMA_WORLD;
4888    niout = NULL;
4889 
4890    SUMA_RETURN(DDO);
4891 }
4892 
4893 /*
4894 An alternalte approach to SUMA_Multiply_NodeObjects
4895 
4896 An alternate approach, would return a vector of NIDO* with one NIDO pointer
4897 for each node. This way one could put a whole lot of stuff in there.
4898 At rendering time, instead of making one call to DrawNIDO, one calls
4899 DrawNIDO for each node that has a NIDO
4900 */
SUMA_Multiply_NodeNIDOObjects(SUMA_SurfaceObject * SO,SUMA_DO * DO,int * NodeID,int N_NodeID)4901 SUMA_NIDO ** SUMA_Multiply_NodeNIDOObjects ( SUMA_SurfaceObject *SO,
4902                                       SUMA_DO *DO, int *NodeID, int N_NodeID )
4903 {
4904    static char FuncName[]={"SUMA_Multiply_NodeNIDOObjects"};
4905    SUMA_NIDO **NIDOv = NULL;
4906    SUMA_NIDO *nido=NULL, *niout=NULL;
4907    void *vel=NULL;
4908    char *atr=NULL;
4909    int i=0, N_Nodes=0, node=0;
4910    SUMA_Boolean LocalHead = NOPE;
4911 
4912    SUMA_ENTRY;
4913 
4914    if (!SO || !DO) SUMA_RETURN(NULL);
4915 
4916    SUMA_LHv("Switch on DO type %s and coord type %d\n",
4917             SUMA_ObjectTypeCode2ObjectTypeName(DO->ObjectType),
4918             DO->CoordType);
4919    switch(DO->ObjectType) {
4920       case NIDO_type:
4921          nido=(SUMA_NIDO *)DO->OP;
4922 
4923          NIDOv = (SUMA_NIDO **)SUMA_calloc(SO->N_Node, sizeof(SUMA_NIDO*));
4924          /* Easiest to duplicate the nido for each of the nodes */
4925          /* although its not efficient for fast drawing, it makes */
4926          /* is real easy to encode a boat load of information, and use*/
4927          /* drawNIDO without much headaches */
4928 
4929          /* Now for each node, create a new copy of that element */
4930          if (NodeID) N_Nodes = N_NodeID;
4931          else N_Nodes = SO->N_Node;
4932          for (i=0; i<N_Nodes; ++i) {
4933             if (!NodeID) node = i;
4934             else {
4935                node = NodeID[i];
4936                if (node >= SO->N_Node || node < 0) {
4937                   static int nwarn = 0;
4938                   if (!nwarn) {
4939                      SUMA_S_Warn("Node %d is outside range for surface\n"
4940                               "This node and others like it will be ignored\n",
4941                               node);
4942                   }
4943                   ++nwarn;
4944                   continue;
4945                }
4946             }
4947             if ((vel = NI_duplicate(nido->ngr, 1))) {
4948                /* assign object to the node */
4949                NI_SET_INT((NI_element *)vel, "default_node", node);
4950                niout = SUMA_Alloc_NIDO(NULL,
4951                         "from_CommonNodeObject", SO->idcode_str);
4952                niout->ngr = vel;
4953                NIDOv[node] = niout; niout = NULL;
4954             } else {
4955                SUMA_S_Err("Failed to create duplicate element");
4956                SUMA_RETURN(NULL);
4957             }
4958          }
4959          break;
4960       default:
4961          SUMA_S_Errv("Sorry Chip, goose %s (%d) ain't ready to fly.\n",
4962                      SUMA_ObjectTypeCode2ObjectTypeName(DO->ObjectType),
4963                      DO->ObjectType);
4964          SUMA_RETURN(NULL);
4965    }
4966 
4967    SUMA_RETURN(NIDOv);
4968 }
4969 
4970 
SUMA_ReadPlaneDO(char * s)4971 SUMA_PlaneDO * SUMA_ReadPlaneDO (char *s)
4972 {
4973    static char FuncName[]={"SUMA_ReadPlaneDO"};
4974    SUMA_PlaneDO *SDO = NULL;
4975    MRI_IMAGE * im = NULL;
4976    float *far=NULL;
4977    int itmp, itmp2, icol_eq=-1, icol_cent = -1, icol_sz = -1;
4978    int nrow=-1, ncol=-1;
4979 
4980    SUMA_ENTRY;
4981 
4982    if (!s) {
4983       SUMA_SLP_Err("NULL s");
4984       SUMA_RETURN(NULL);
4985    }
4986 
4987    im = mri_read_1D (s);
4988 
4989    if (!im) {
4990       SUMA_SLP_Err("Failed to read 1D file");
4991       SUMA_RETURN(NULL);
4992    }
4993 
4994    far = MRI_FLOAT_PTR(im);
4995    ncol = im->nx;
4996    nrow = im->ny;
4997 
4998    if (!ncol) {
4999       SUMA_SLP_Err("Empty file");
5000       SUMA_RETURN(NULL);
5001    }
5002 
5003    icol_eq = -1;
5004    icol_cent = -1;
5005    icol_sz = -1;
5006    switch (nrow) {
5007       case 7:
5008          fprintf(SUMA_STDERR,"%s: Plane file %s's format:\n"
5009                               "a b c d cx cy cz\n", FuncName, s);
5010          icol_eq = 0;
5011          icol_cent = 4;
5012          break;
5013       case 8:
5014          fprintf(SUMA_STDERR,"%s: Plane file %s's format:\n"
5015                               "a b c d cx cy cz sz\n", FuncName, s);
5016          icol_eq = 0;
5017          icol_cent = 4;
5018          icol_sz = 7;
5019          break;
5020       default:
5021          SUMA_SLP_Err(  "File must have\n"
5022                         "7 columns.");
5023          mri_free(im); im = NULL;   /* done with that baby */
5024          SUMA_RETURN(NULL);
5025    }
5026 
5027    /* allocate for  DO */
5028    SDO = SUMA_Alloc_PlaneDO (ncol, s, PL_type);
5029    if (!SDO) {
5030       fprintf(SUMA_STDERR,
5031                "Error %s: Failed in SUMA_Allocate_PlaneDO.\n", FuncName);
5032       SUMA_RETURN(NULL);
5033    }
5034 
5035    /* fill up SDO */
5036    /* fill up equations */
5037    itmp = 0;
5038    while (itmp < SDO->N_n) {
5039       itmp2 = 4*itmp;
5040       SDO->pleq[itmp2]     = far[itmp+(icol_eq  )*ncol];
5041       SDO->pleq[itmp2+1]   = far[itmp+(icol_eq+1)*ncol];
5042       SDO->pleq[itmp2+2]   = far[itmp+(icol_eq+2)*ncol];
5043       SDO->pleq[itmp2+3]   = far[itmp+(icol_eq+3)*ncol];
5044       ++itmp;
5045    }
5046    /* fill up centers */
5047    itmp = 0;
5048    while (itmp < SDO->N_n) {
5049       itmp2 = 3*itmp;
5050       SDO->cxyz[itmp2]   = far[itmp+(icol_cent  )*ncol];
5051       SDO->cxyz[itmp2+1] = far[itmp+(icol_cent+1)*ncol];
5052       SDO->cxyz[itmp2+2] = far[itmp+(icol_cent+2)*ncol];
5053       ++itmp;
5054    }
5055 
5056    if (icol_sz >= 0) {
5057       if (!SDO->boxdimv)
5058          SDO->boxdimv = (float *)SUMA_calloc(3*SDO->N_n, sizeof(float));
5059       if (ncol == 8) {
5060          itmp = 0;
5061          while (itmp < SDO->N_n) {
5062             itmp2 = 3*itmp;
5063             SDO->boxdimv[itmp2] = far[itmp+(icol_sz  )*ncol];
5064             SDO->boxdimv[itmp2+1] = far[itmp+(icol_sz  )*ncol];
5065             SDO->boxdimv[itmp2+2] = far[itmp+(icol_sz  )*ncol];
5066             ++itmp;
5067          }
5068       } else {
5069          itmp = 0;
5070          while (itmp < SDO->N_n) {
5071             itmp2 = 3*itmp;
5072             SDO->boxdimv[itmp2  ] = far[itmp+(icol_sz  )*ncol];
5073             SDO->boxdimv[itmp2+1] = far[itmp+(icol_sz+1)*ncol];
5074             SDO->boxdimv[itmp2+2] = far[itmp+(icol_sz+2)*ncol];
5075             ++itmp;
5076          }
5077       }
5078    }
5079    mri_free(im); im = NULL; far = NULL;
5080 
5081    SUMA_RETURN(SDO);
5082 }
5083 
5084 /*! Allocate for a axis object */
SUMA_Alloc_Axis(const char * Name,SUMA_DO_Types type)5085 SUMA_Axis* SUMA_Alloc_Axis (const char *Name, SUMA_DO_Types type)
5086 {
5087    static char FuncName[]={"SUMA_Alloc_Axis"};
5088    SUMA_Axis* Ax;
5089 
5090    SUMA_ENTRY;
5091 
5092    Ax = (SUMA_Axis *) SUMA_calloc(1,sizeof (SUMA_Axis));
5093    if (Ax == NULL) {
5094       fprintf(stderr,"SUMA_Alloc_Axis Error: Failed to allocate Ax\n");
5095       SUMA_RETURN (Ax);
5096    }
5097    Ax->do_type = type;
5098 
5099    /* setup some default values */
5100    Ax->atype = SUMA_STD_ZERO_CENTERED;
5101    Ax->XaxisColor[0] = 1.0;
5102    Ax->XaxisColor[1] = 0.0;
5103    Ax->XaxisColor[2] = 0.0;
5104    Ax->XaxisColor[3] = 1.0;
5105 
5106    Ax->YaxisColor[0] = 0.0;
5107    Ax->YaxisColor[1] = 1.0;
5108    Ax->YaxisColor[2] = 0.0;
5109    Ax->YaxisColor[3] = 1.0;
5110 
5111    Ax->ZaxisColor[0] = 0.0;
5112    Ax->ZaxisColor[1] = 0.0;
5113    Ax->ZaxisColor[2] = 1.0;
5114    Ax->ZaxisColor[3] = 1.0;
5115 
5116    Ax->LineWidth = 1.0;
5117    Ax->Stipple = SUMA_SOLID_LINE;
5118    Ax->XYZspan[0] = Ax->XYZspan[1] = Ax->XYZspan[2] = 800;
5119 
5120    Ax->Center[0] = Ax->Center[1] = Ax->Center[2] = 0.0;
5121 
5122    if (Name != NULL) {
5123       if (strlen(Name) > SUMA_MAX_LABEL_LENGTH-1) {
5124          fprintf(SUMA_STDERR, "Error %s: Name too long (> %d).\n",\
5125             FuncName, SUMA_MAX_LABEL_LENGTH);
5126          Ax->Label = NULL;
5127          Ax->idcode_str = NULL;
5128       } else {
5129          Ax->Label = (char *)SUMA_calloc (strlen(Name)+1, sizeof(char));
5130          Ax->idcode_str = (char *)SUMA_calloc (SUMA_IDCODE_LENGTH+1, sizeof(char));
5131          if (Ax->Label == NULL) {
5132             fprintf(SUMA_STDERR,"Error %s: Failed to allocate for Ax->Name.\n", \
5133                FuncName);
5134          }
5135          sprintf(Ax->Label, "%s", Name);
5136          UNIQ_idcode_fill(Ax->idcode_str);
5137       }
5138 
5139    }
5140    SUMA_RETURN (Ax);
5141 }
SUMA_Free_Axis(SUMA_Axis * Ax)5142 void SUMA_Free_Axis (SUMA_Axis *Ax)
5143 {
5144    static char FuncName[]={"SUMA_Free_Axis"};
5145 
5146    SUMA_ENTRY;
5147 
5148    if (Ax->Label != NULL) SUMA_free(Ax->Label);
5149    if (Ax->idcode_str != NULL) SUMA_free(Ax->idcode_str);
5150    if (Ax) SUMA_free(Ax);
5151    SUMA_RETURNe;
5152 }
5153 
SUMA_EyeAxisStandard(SUMA_Axis * Ax,SUMA_SurfaceViewer * csv)5154 void SUMA_EyeAxisStandard (SUMA_Axis* Ax, SUMA_SurfaceViewer *csv)
5155 {
5156    static char FuncName[]={"SUMA_EyeAxisStandard"};
5157    SUMA_Boolean LocalHead = NOPE;
5158    char buf[200];
5159 
5160    SUMA_ENTRY;
5161 
5162    Ax->Stipple = SUMA_DASHED_LINE;
5163    Ax->XYZspan[0] = Ax->XYZspan[1] = Ax->XYZspan[2] = 1000.0;
5164    Ax->Center[0] = csv->GVS[csv->StdView].ViewCenter[0];
5165    Ax->Center[1] = csv->GVS[csv->StdView].ViewCenter[1];
5166    Ax->Center[2] = csv->GVS[csv->StdView].ViewCenter[2];
5167    SUMA_RETURNe;
5168 }
5169 
SUMA_MeshAxisStandard(SUMA_Axis * Ax,SUMA_ALL_DO * ado)5170 void SUMA_MeshAxisStandard (SUMA_Axis* Ax, SUMA_ALL_DO *ado)
5171 {
5172    static char FuncName[]={"SUMA_MeshAxisStandard"};
5173    SUMA_SurfaceViewer *sv=NULL;
5174    SUMA_SurfaceObject *cso=NULL;
5175    SUMA_Boolean LocalHead = NOPE;
5176 
5177    SUMA_ENTRY;
5178    if (!ado || !Ax) SUMA_RETURNe;
5179 
5180    switch (ado->do_type) {
5181       case SO_type:
5182          cso=(SUMA_SurfaceObject *)ado;
5183          Ax->Stipple = SUMA_SOLID_LINE;
5184          Ax->XYZspan[0]= Ax->XYZspan[1]= Ax->XYZspan[2]= 100.0;
5185          Ax->BR[0][0] = cso->MinDims[0]; Ax->BR[0][1] = cso->MaxDims[0];
5186          Ax->BR[1][0] = cso->MinDims[1]; Ax->BR[1][1] = cso->MaxDims[1];
5187          Ax->BR[2][0] = cso->MinDims[2]; Ax->BR[2][1] = cso->MaxDims[2];
5188          Ax->Center[0] = cso->Center[0];
5189          Ax->Center[1] = cso->Center[1];
5190          Ax->Center[2] = cso->Center[2];
5191          sv = SUMA_BestViewerForADO(ado);
5192          if (!sv) sv = SUMAg_SVv;
5193          Ax->MTspace = 10;
5194          Ax->mTspace = 2;
5195          Ax->MTsize = 4; Ax->mTsize = 2;
5196          SUMA_LHv("MTspace = %f, DimSclFac = %f\n",
5197             Ax->MTspace, sv->GVS[sv->StdView].DimSclFac);
5198          {
5199             char *eee = getenv("SUMA_UseCrossTicks");
5200             if (eee) {
5201                SUMA_TO_LOWER(eee);
5202                if (strcmp (eee, "yes") == 0) Ax->DoCross = 1;
5203                   else Ax->DoCross = 0;
5204             } else {
5205                Ax->DoCross = 0;
5206             }
5207          }
5208          break;
5209       case GRAPH_LINK_type:
5210          SUMA_S_Notev("Nothing done for GRAPH_LINK_type, variant %s yet\n",
5211                          SUMA_ADO_variant(ado));
5212          break;
5213       default:
5214          SUMA_S_Errv("Not ready for type %s\n",
5215          SUMA_ObjectTypeCode2ObjectTypeName(ado->do_type));
5216          break;
5217    }
5218 
5219    SUMA_RETURNe;
5220 }
5221 
SUMA_WorldAxisStandard(SUMA_Axis * Ax,SUMA_SurfaceViewer * sv)5222 void SUMA_WorldAxisStandard (SUMA_Axis* Ax, SUMA_SurfaceViewer *sv)
5223 {
5224    static char FuncName[]={"SUMA_WorldAxisStandard"};
5225    float MinDims[3], MaxDims[3], *xyzr=NULL;
5226    int i, j, Nsel, *Vis_IDs=NULL;
5227    SUMA_SurfaceObject *cso=NULL;
5228    SUMA_DSET *dset=NULL;
5229    SUMA_Boolean LocalHead = NOPE;
5230 
5231    SUMA_ENTRY;
5232 
5233    if (!Ax) {
5234       SUMA_SL_Err("NULL Ax!");
5235       SUMA_RETURNe;
5236    }
5237 
5238    Ax->Stipple = SUMA_SOLID_LINE;
5239    Ax->XYZspan[0]= Ax->XYZspan[1]= Ax->XYZspan[2]= 100.0;
5240    Ax->MTspace = 10/sv->GVS[sv->StdView].DimSclFac;
5241    Ax->mTspace = 2/sv->GVS[sv->StdView].DimSclFac;
5242    Ax->MTsize = 4/sv->GVS[sv->StdView].DimSclFac;
5243    Ax->mTsize = 2/sv->GVS[sv->StdView].DimSclFac;
5244    {
5245       char *eee = getenv("SUMA_UseCrossTicks");
5246       if (eee) {
5247          SUMA_TO_LOWER(eee);
5248          if (strcmp (eee, "yes") == 0) Ax->DoCross = 1;
5249             else Ax->DoCross = 0;
5250       } else {
5251          Ax->DoCross = 0;
5252       }
5253    }
5254 
5255    Ax->Center[0] = sv->GVS[sv->StdView].RotaCenter[0];
5256    Ax->Center[1] = sv->GVS[sv->StdView].RotaCenter[1];
5257    Ax->Center[2] = sv->GVS[sv->StdView].RotaCenter[2];
5258 
5259    Vis_IDs = (int *)SUMA_malloc(sizeof(int)*SUMAg_N_DOv);
5260    Nsel = SUMA_Selectable_ADOs (sv, SUMAg_DOv, Vis_IDs);
5261 
5262    /* init */
5263    MinDims[0]=MinDims[1]=MinDims[2]=1;
5264    MaxDims[0]=MaxDims[1]=MaxDims[2]=0;
5265    if (Nsel > 0) {
5266       for (i=0; i<Nsel; ++i) {
5267          switch (SUMAg_DOv[Vis_IDs[i]].ObjectType) {
5268             case SO_type:
5269                cso = (SUMA_SurfaceObject *)SUMAg_DOv[Vis_IDs[i]].OP;
5270 	       xyzr = SUMA_SDO_XYZ_Range(cso, NULL);
5271                break;
5272             case GRAPH_LINK_type:
5273                if(!(dset=SUMA_find_GLDO_Dset(
5274                               (SUMA_GraphLinkDO *)(SUMAg_DOv[Vis_IDs[i]].OP)))){
5275                   SUMA_S_Err("Gilda");
5276                   break;
5277                }
5278 
5279                if (!SUMA_IS_REAL_VARIANT(iDO_variant(Vis_IDs[i]))) break;
5280                xyzr = SUMA_GDSET_XYZ_Range(dset, iDO_variant(Vis_IDs[i]), NULL);
5281                break;
5282             case TRACT_type: {
5283                SUMA_TractDO *tdo=(SUMA_TractDO *)SUMAg_DOv[Vis_IDs[i]].OP;
5284                xyzr = SUMA_TDO_XYZ_Range(tdo, NULL);
5285                break; }
5286             case MASK_type: {
5287                SUMA_MaskDO *mdo=(SUMA_MaskDO *)SUMAg_DOv[Vis_IDs[i]].OP;
5288                xyzr = SUMA_MDO_XYZ_Range(mdo, NULL);
5289                break; }
5290             case VO_type: {
5291                SUMA_VolumeObject *VO=
5292                   (SUMA_VolumeObject *)SUMAg_DOv[Vis_IDs[i]].OP;
5293                xyzr = SUMA_VO_XYZ_Range(VO, NULL);
5294                break; }
5295             case CDOM_type: {
5296 	       xyzr = SUMA_CIFTI_DO_XYZ_Range((
5297 	             	SUMA_CIFTI_DO*)SUMAg_DOv[Vis_IDs[i]].OP, NULL);
5298 	       break; }
5299 	    default:
5300                SUMA_LHv("Ignoring dims of %s\n", iDO_label(Vis_IDs[i]));
5301                break;
5302          }
5303 	 if (MinDims[0] > MaxDims[0]) {/* initialize */
5304             for (j=0; j<3; ++j) {
5305                MinDims[j] = xyzr[2*j];
5306                MaxDims[j] = xyzr[2*j+1];
5307             }
5308          } else {
5309             for (j=0; j<3; ++j) {
5310                if (xyzr[2*j] < MinDims[j])  MinDims[j] = xyzr[2*j];
5311                if (xyzr[2*j+1] > MaxDims[j]) MaxDims[j] = xyzr[2*j+1];
5312             }
5313          }
5314       }
5315       if (MinDims[0] > MaxDims[0]) {/* Bad trip */
5316          SUMA_S_Warn("Nothing good for initialization, using default");
5317          MinDims[0]=MinDims[1]=MinDims[2]=-20;
5318          MaxDims[0]=MaxDims[1]=MaxDims[2]=20;
5319       }
5320       Ax->BR[0][0] = MinDims[0]; Ax->BR[0][1] = MaxDims[0];
5321       Ax->BR[1][0] = MinDims[1]; Ax->BR[1][1] = MaxDims[1];
5322       Ax->BR[2][0] = MinDims[2]; Ax->BR[2][1] = MaxDims[2];
5323    } else {
5324       SUMA_LH("No Surfs/Selectable DOs, Going with defaults for now");
5325       Ax->BR[0][0] = -20; Ax->BR[0][1] = 20;
5326       Ax->BR[1][0] = -20; Ax->BR[1][1] = 20;
5327       Ax->BR[2][0] = -20; Ax->BR[2][1] = 20;
5328    }
5329    if (Vis_IDs) SUMA_free(Vis_IDs);
5330 
5331    SUMA_RETURNe;
5332 }
5333 
SUMA_DrawSphereDO(SUMA_SphereDO * SDO,SUMA_SurfaceViewer * sv)5334 SUMA_Boolean SUMA_DrawSphereDO (SUMA_SphereDO *SDO, SUMA_SurfaceViewer *sv)
5335 {
5336    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0}, comcol[4], *cent=NULL;
5337    int i, N_n3, i3, ndraw=0, ncross=-1;
5338    GLfloat rad = 3;
5339    static char FuncName[]={"SUMA_DrawSphereDO"};
5340    float origwidth=0.0;
5341    SUMA_SurfaceObject *SO = NULL;
5342    byte *mask=NULL;
5343    byte AmbDiff = 0;
5344    SUMA_Boolean LocalHead = NOPE;
5345 
5346    SUMA_ENTRY;
5347 
5348    if (!SDO) {
5349       fprintf(stderr,"Error %s: NULL pointer.\n", FuncName);
5350       SUMA_RETURN (NOPE);
5351    }
5352 
5353    if (sv && sv->DO_PickMode) {
5354       SUMA_S_Warn("Function not ready for picking mode, should be fixed");
5355       SUMA_RETURN(YUP);
5356    }
5357 
5358    if (SDO->NodeBased) { /* Locate the surface in question */
5359       SUMA_LH("Node-based spheres");
5360       if (!SDO->Parent_idcode_str) {
5361          SUMA_SL_Err("Object's parent idcode_str not specified.");
5362          SUMA_RETURN (NOPE);
5363       }
5364       SO = SUMA_findSOp_inDOv(SDO->Parent_idcode_str, SUMAg_DOv, SUMAg_N_DOv);
5365       if (!SO) {
5366          SUMA_SL_Err("Object's parent surface not found.");
5367          SUMA_RETURN (NOPE);
5368       }
5369       /* masking? */
5370       if ((ndraw = SUMA_ProcessDODrawMask(sv, SO, &mask, &ncross)) < 0) {
5371          SUMA_RETURN (NOPE);
5372       }
5373       if (!ndraw) SUMA_RETURN(YUP);/* nothing to draw, nothing wrong */
5374       SUMA_LHv("ncross=%d\n", ncross);
5375    } else {
5376       SUMA_LH("Spheres ");
5377    }
5378 
5379    glGetFloatv(GL_LINE_WIDTH, &origwidth);
5380    glLineWidth(SDO->LineWidth);
5381 
5382    comcol[0] = SDO->CommonCol[0]; /* *SUMAg_SVv[0].dim_amb; Naahhhh */
5383    comcol[1] = SDO->CommonCol[1]; /* *SUMAg_SVv[0].dim_amb;*/
5384    comcol[2] = SDO->CommonCol[2]; /* *SUMAg_SVv[0].dim_amb;*/
5385    comcol[3] = SDO->CommonCol[3]; /* *SUMAg_SVv[0].dim_amb;*/
5386 
5387    if (!SDO->colv) {
5388       if (AmbDiff) {
5389          glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, comcol);
5390       } else {
5391          glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, NoColor);
5392       }
5393       glMaterialfv(GL_FRONT, GL_EMISSION, comcol);
5394    }
5395    if (!SDO->radv) rad = SDO->CommonRad;
5396    if (!SDO->stylev) {
5397       gluQuadricDrawStyle (SDO->sphobj, SDO->CommonStyle);
5398       if (SDO->CommonStyle == GLU_FILL)
5399          gluQuadricNormals (SDO->sphobj , GLU_SMOOTH);
5400       else gluQuadricNormals (SDO->sphobj , GLU_NONE);
5401    }
5402 
5403    for (i=0; i<SDO->N_n;++i) {
5404       i3 = 3*i;
5405       if (SDO->colv) {
5406          if (AmbDiff) {
5407             glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, &(SDO->colv[i*4]));
5408          } else {
5409             glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, NoColor);
5410          }
5411          glMaterialfv(GL_FRONT, GL_EMISSION, &(SDO->colv[i*4]));
5412       }
5413       if (SDO->radv) rad = SDO->radv[i];
5414       if (SDO->stylev) {
5415          gluQuadricDrawStyle (SDO->sphobj, SDO->stylev[i]);
5416          if (SDO->stylev[i] == GLU_FILL)
5417             gluQuadricNormals (SDO->sphobj , GLU_SMOOTH);
5418          else gluQuadricNormals (SDO->sphobj , GLU_NONE);
5419       }
5420       if (  SDO->NodeBased && SDO->NodeID[i] < SO->N_Node &&
5421             DO_DRAW(mask,SDO->NodeID[i],ncross)) {
5422          cent = &(SO->NodeList[3*SDO->NodeID[i]]);
5423       } else {
5424          cent = &(SDO->cxyz[i3]);
5425       }
5426       glTranslatef (cent[0], cent[1], cent[2]);
5427       gluSphere(SDO->sphobj, rad/* *SUMA_MAX_PAIR(sv->ZoomCompensate, 0.06)
5428                      User set values, not cool to play with dimensions! */,
5429                 SDO->CommonSlices, SDO->CommonStacks);
5430       glTranslatef (-cent[0], -cent[1], -cent[2]);
5431    }
5432 
5433    if (AmbDiff) {
5434       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, NoColor);
5435    }
5436    glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
5437    glLineWidth(origwidth);
5438 
5439    if (mask) SUMA_free(mask); mask=NULL;
5440    SUMA_RETURN (YUP);
5441 
5442 }
5443 
SUMA_DrawPointDO(SUMA_SphereDO * SDO,SUMA_SurfaceViewer * sv)5444 SUMA_Boolean SUMA_DrawPointDO (SUMA_SphereDO *SDO, SUMA_SurfaceViewer *sv)
5445 {
5446    static char FuncName[]={"SUMA_DrawPointDO"};
5447    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0}, comcol[4], *cent=NULL;
5448    int i, N_n3, i3, ndraw=0, ncross=-1, initPointsz;
5449    GLfloat rad = 3;
5450    SUMA_SurfaceObject *SO = NULL;
5451    byte *mask=NULL;
5452    byte AmbDiff = 0;
5453    SUMA_Boolean LocalHead = NOPE;
5454 
5455    SUMA_ENTRY;
5456 
5457    if (!SDO) {
5458       fprintf(stderr,"Error %s: NULL pointer.\n", FuncName);
5459       SUMA_RETURN (NOPE);
5460    }
5461 
5462    if (sv && sv->DO_PickMode) {
5463       SUMA_S_Warn("Function not ready for picking mode, should be fixed");
5464       SUMA_RETURN(YUP);
5465    }
5466 
5467    if (SDO->NodeBased) { /* Locate the surface in question */
5468       SUMA_LH("Node-based points");
5469       if (!SDO->Parent_idcode_str) {
5470          SUMA_SL_Err("Object's parent idcode_str not specified.");
5471          SUMA_RETURN (NOPE);
5472       }
5473       SO = SUMA_findSOp_inDOv(SDO->Parent_idcode_str, SUMAg_DOv, SUMAg_N_DOv);
5474       if (!SO) {
5475          SUMA_SL_Err("Object's parent surface not found.");
5476          SUMA_RETURN (NOPE);
5477       }
5478       /* masking? */
5479       if ((ndraw = SUMA_ProcessDODrawMask(sv, SO, &mask, &ncross)) < 0) {
5480          SUMA_RETURN (NOPE);
5481       }
5482       if (!ndraw) SUMA_RETURN(YUP);/* nothing to draw, nothing wrong */
5483       SUMA_LHv("ncross=%d\n", ncross);
5484    } else {
5485       SUMA_LH("Points ");
5486    }
5487 
5488 
5489    comcol[0] = SDO->CommonCol[0]; /* *SUMAg_SVv[0].dim_amb; Naahhhh */
5490    comcol[1] = SDO->CommonCol[1]; /* *SUMAg_SVv[0].dim_amb;*/
5491    comcol[2] = SDO->CommonCol[2]; /* *SUMAg_SVv[0].dim_amb;*/
5492    comcol[3] = SDO->CommonCol[3]; /* *SUMAg_SVv[0].dim_amb;*/
5493 
5494    if (!SDO->colv) {
5495       SUMA_LH("Color %f %f %f %f", comcol[0], comcol[1], comcol[2], comcol[3]);
5496       if (AmbDiff) {
5497          glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, comcol);
5498       } else {
5499          glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, NoColor);
5500       }
5501       glMaterialfv(GL_FRONT, GL_EMISSION, comcol);
5502    }
5503 
5504    glGetIntegerv(GL_POINT_SIZE, &initPointsz);
5505    if (!SDO->radv) {
5506       SUMA_LH("Constant radius");
5507       rad = SDO->CommonRad;
5508       glPointSize(rad);
5509       if (SDO->colv) {
5510          glColorMaterial(GL_FRONT, GL_EMISSION);
5511          glEnable(GL_COLOR_MATERIAL);
5512          glEnableClientState (GL_COLOR_ARRAY);
5513          glColorPointer (4, GL_FLOAT, 0, SDO->colv);
5514       }
5515       glEnableClientState (GL_VERTEX_ARRAY);
5516       glVertexPointer (3, GL_FLOAT, 0, SDO->cxyz);
5517       glDrawArrays(GL_POINTS, 0, SDO->N_n);
5518       if (SDO->colv) {
5519          glDisable(GL_COLOR_MATERIAL);
5520          glDisableClientState(GL_COLOR_ARRAY);
5521       }
5522       glDisableClientState(GL_VERTEX_ARRAY);
5523    } else { /* slow, relatively! */
5524       SUMA_LH("Variable radius");
5525       if (AmbDiff) {
5526          glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, comcol);
5527       } else {
5528          glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, NoColor);
5529       }
5530       for (i=0; i<SDO->N_n; ++i) {
5531          i3 = 3*i;
5532          if (SDO->colv) {
5533             glMaterialfv(GL_FRONT, GL_EMISSION, (SDO->colv+4*i));
5534          }
5535          glPointSize(SUMA_ABS(SDO->radv[i]));
5536          glBegin (GL_POINTS);
5537          glVertex3fv(SDO->cxyz+i3);
5538          glEnd();
5539       }
5540    }
5541    if (AmbDiff) {
5542       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, NoColor);
5543    }
5544    glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
5545 
5546    glPointSize(initPointsz);
5547    if (mask) SUMA_free(mask); mask=NULL;
5548    SUMA_RETURN (YUP);
5549 }
5550 
SUMA_Alloc_SphereDO(int N_n,char * Label,char * Parent_idcode_str,SUMA_DO_Types type)5551 SUMA_SphereDO * SUMA_Alloc_SphereDO (  int N_n, char *Label,
5552                                        char *Parent_idcode_str,
5553                                        SUMA_DO_Types type)
5554 {
5555    static char FuncName[]={"SUMA_Alloc_SphereDO"};
5556    SUMA_SphereDO* SDO;
5557    char *hs = NULL;
5558 
5559    SUMA_ENTRY;
5560 
5561    SDO = (SUMA_SphereDO*)SUMA_calloc(1,sizeof (SUMA_SphereDO));
5562    if (SDO == NULL) {
5563       fprintf(stderr,"SUMA_Alloc_SphereDO Error: Failed to allocate SDO\n");
5564       SUMA_RETURN (NULL);
5565    }
5566    SDO->do_type = type;
5567 
5568    if (N_n > 0) {
5569       if (!Parent_idcode_str) {
5570          SDO->NodeBased = 0;
5571          SDO->NodeID = NULL;
5572          SDO->Parent_idcode_str = NULL;
5573          SDO->cxyz = (GLfloat *) SUMA_calloc (3*N_n, sizeof(GLfloat));
5574 
5575          if (!SDO->cxyz) {
5576             fprintf( stderr,
5577                      "Error %s: Failed to allocate for SDO->cxyz\n", FuncName);
5578             if (SDO) SUMA_free (SDO);
5579             SUMA_RETURN (NULL);
5580          }
5581       } else {
5582          SDO->NodeBased = 1;
5583          SDO->Parent_idcode_str = SUMA_copy_string(Parent_idcode_str);
5584          SDO->NodeID = (int*) SUMA_calloc(N_n, sizeof(int));
5585          if (!SDO->NodeID) {
5586             fprintf(stderr,
5587                      "Error %s: Failed to allocate for SDO->NodeID\n", FuncName);
5588             if (SDO) SUMA_free (SDO);
5589             SUMA_RETURN (NULL);
5590          }
5591          SDO->cxyz = NULL;
5592       }
5593       SDO->N_n = N_n;
5594    } else {
5595       SDO->cxyz = NULL;
5596       SDO->NodeBased = 0;
5597       SDO->Parent_idcode_str = NULL;
5598       SDO->NodeID = NULL;
5599       SDO->N_n = 0;
5600    }
5601 
5602    /* create a string to hash an idcode */
5603    if (Label) hs = SUMA_copy_string(Label);
5604    else hs = SUMA_copy_string("NULL_");
5605    if (Parent_idcode_str)
5606       hs = SUMA_append_replace_string(hs,Parent_idcode_str,"_",1);
5607    else hs = SUMA_append_replace_string(hs,"NULL","",1);
5608    SDO->idcode_str = UNIQ_hashcode(hs);
5609    SUMA_free(hs); hs = NULL;
5610 
5611 
5612    if (Label) {
5613       SDO->Label = (char *)SUMA_calloc (strlen(Label)+1, sizeof(char));
5614       SDO->Label = strcpy (SDO->Label, Label);
5615    } else {
5616       SDO->Label = NULL;
5617    }
5618 
5619    /* create the ball object*/
5620    SDO->sphobj = gluNewQuadric();
5621 
5622    /* setup some default values */
5623    SDO->LineWidth = 4.0;
5624    SDO->CommonRad = 2.0;
5625    SDO->CommonCol[0] = 1.0;
5626    SDO->CommonCol[1] = 1.0;
5627    SDO->CommonCol[2] = 1.0;
5628    SDO->CommonCol[3] = 1.0;
5629    SDO->CommonSlices = 10;
5630    SDO->CommonStacks = 10;
5631    SDO->CommonStyle = GLU_FILL;
5632    SDO->radv=NULL;
5633    SDO->colv=NULL;
5634    SDO->stylev = NULL;
5635 
5636    SUMA_RETURN (SDO);
5637 }
5638 
SUMA_free_SphereDO(SUMA_SphereDO * SDO)5639 void SUMA_free_SphereDO (SUMA_SphereDO * SDO)
5640 {
5641    static char FuncName[]={"SUMA_free_SphereDO"};
5642 
5643    SUMA_ENTRY;
5644 
5645    if (!SDO) SUMA_RETURNe;
5646 
5647    if (SDO->Parent_idcode_str) SUMA_free(SDO->Parent_idcode_str);
5648    if (SDO->NodeID) SUMA_free(SDO->NodeID);
5649    if (SDO->cxyz) SUMA_free(SDO->cxyz);
5650    if (SDO->idcode_str) SUMA_free(SDO->idcode_str);
5651    if (SDO->Label) SUMA_free(SDO->Label);
5652    if (SDO->sphobj) gluDeleteQuadric(SDO->sphobj);
5653    if (SDO->radv) SUMA_free(SDO->radv);
5654    if (SDO->colv) SUMA_free(SDO->colv);
5655    if (SDO->stylev) SUMA_free(SDO->stylev);
5656 
5657    if (SDO) SUMA_free(SDO);
5658 
5659    SUMA_RETURNe;
5660 
5661 }
5662 
5663 
SUMA_Alloc_TractDO(char * Label,char * Parent_idcode_str)5664 SUMA_TractDO * SUMA_Alloc_TractDO (  char *Label,
5665                                      char *Parent_idcode_str)
5666 {
5667    static char FuncName[]={"SUMA_Alloc_TractDO"};
5668    SUMA_TractDO* TDO;
5669    char *hs = NULL;
5670 
5671    SUMA_ENTRY;
5672 
5673    TDO = (SUMA_TractDO*)SUMA_calloc(1,sizeof (SUMA_TractDO));
5674    if (TDO == NULL) {
5675       fprintf(stderr,"SUMA_Alloc_TractDO Error: Failed to allocate TDO\n");
5676       SUMA_RETURN (NULL);
5677    }
5678    TDO->do_type = TRACT_type;
5679 
5680 
5681    if (!Parent_idcode_str) {
5682       TDO->Parent_idcode_str = NULL;
5683    } else {
5684       TDO->Parent_idcode_str = SUMA_copy_string(Parent_idcode_str);
5685    }
5686 
5687    /* create a string to hash an idcode */
5688    if (Label) hs = SUMA_copy_string(Label);
5689    else hs = SUMA_copy_string("NULL_");
5690    if (Parent_idcode_str)
5691       hs = SUMA_append_replace_string(hs,Parent_idcode_str,"_",1);
5692    else hs = SUMA_append_replace_string(hs,"NULL","",1);
5693    TDO->idcode_str = UNIQ_hashcode(hs);
5694    SUMA_free(hs); hs = NULL;
5695 
5696 
5697    if (Label) {
5698       TDO->Label = (char *)SUMA_calloc (strlen(Label)+1, sizeof(char));
5699       TDO->Label = strcpy (TDO->Label, Label);
5700    } else {
5701       TDO->Label = NULL;
5702    }
5703 
5704    TDO->LineWidth = 1.0;
5705    TDO->LineCol[0] = 1.0;
5706    TDO->colv = NULL;
5707    TDO->thickv = NULL;
5708 
5709    TDO->Stipple = SUMA_SOLID_LINE;
5710 
5711    if (!SUMA_AddTractSaux(TDO)) {
5712       SUMA_S_Err("Failed to add Tract Saux");
5713    }
5714 
5715    TDO->N_datum = -2; /* unitialized, -1 means init failed */
5716 
5717    TDO->MaskStateID = -1;
5718    TDO->N_tmask = 0;
5719    TDO->tmask = NULL;
5720    TDO->tcols = NULL;
5721    TDO->usetcols = 0;
5722 
5723    TDO->mep = SUMA_AllocMaskEval_Params();
5724 
5725    SUMA_RETURN (TDO);
5726 }
5727 
SUMA_free_TractDO(SUMA_TractDO * TDO)5728 void SUMA_free_TractDO (SUMA_TractDO * TDO)
5729 {
5730    static char FuncName[]={"SUMA_free_TractDO"};
5731 
5732    SUMA_ENTRY;
5733 
5734    if (!TDO) SUMA_RETURNe;
5735 
5736    if (TDO->Parent_idcode_str) SUMA_free(TDO->Parent_idcode_str);
5737    if (TDO->Label) SUMA_free(TDO->Label);
5738    if (TDO->idcode_str) SUMA_free(TDO->idcode_str);
5739    if (TDO->net) Free_Network(TDO->net);
5740 
5741    if (TDO->Saux) { /* free SUMA auxiliary data */
5742       if (!TDO->FreeSaux) {
5743          SUMA_S_Err("You're leaky, you're leaky");
5744       } else TDO->FreeSaux(TDO->Saux);
5745       TDO->Saux=NULL; /* pointer freed in freeing function */
5746    }
5747 
5748    SUMA_ifree(TDO->tmask); SUMA_free(TDO->tcols);
5749    TDO->N_tmask = 0; TDO->MaskStateID = -1;
5750 
5751    TDO->colv = NULL; /* It is copied from the overlay colorlist */
5752    TDO->mep = SUMA_FreeMaskEval_Params(TDO->mep);
5753    if (TDO) SUMA_free(TDO);
5754 
5755    SUMA_RETURNe;
5756 
5757 }
5758 
SUMA_Alloc_GraphLinkDO(char * variant,SUMA_DSET * ParentGraph)5759 SUMA_GraphLinkDO * SUMA_Alloc_GraphLinkDO (  char *variant,
5760                                              SUMA_DSET *ParentGraph)
5761 {
5762    static char FuncName[]={"SUMA_Alloc_GraphLinkDO"};
5763    SUMA_GraphLinkDO* GLDO=NULL;
5764    char *hs = NULL, *pgi, *pgl;
5765 
5766    SUMA_ENTRY;
5767 
5768    if (!ParentGraph || !(pgi = SDSET_ID(ParentGraph))) {
5769       SUMA_S_Err("Get your parents");
5770       SUMA_RETURN (NULL);
5771    }
5772    if (!variant) { variant = "default"; }
5773 
5774    GLDO = (SUMA_GraphLinkDO*)SUMA_calloc(1,sizeof (SUMA_GraphLinkDO));
5775    if (GLDO == NULL) {
5776       SUMA_S_Err("Failed to allocate GLDO\n");
5777       SUMA_RETURN (NULL);
5778    }
5779    GLDO->do_type = GRAPH_LINK_type;
5780    GLDO->variant = SUMA_copy_string(variant);
5781    GLDO->Parent_idcode_str = SUMA_copy_string(pgi);
5782 
5783    /* create a string to hash an idcode */
5784    pgl = SDSET_LABEL(ParentGraph);
5785    hs = SUMA_append_replace_string(variant,
5786                   pgl?pgl:pgi,"_DOlink_",0);
5787 
5788    if (strcmp(variant,"TheShadow")) {
5789       GLDO->idcode_str = UNIQ_hashcode(hs);
5790    } else {
5791       GLDO->idcode_str = SUMA_copy_string(SDSET_ID(ParentGraph));
5792    }
5793    GLDO->Label = hs; hs = NULL;
5794 
5795 
5796    SUMA_RETURN (GLDO);
5797 }
5798 
SUMA_free_GraphLinkDO(SUMA_GraphLinkDO * GLDO)5799 void SUMA_free_GraphLinkDO (SUMA_GraphLinkDO * GLDO)
5800 {
5801    static char FuncName[]={"SUMA_free_GraphLinkDO"};
5802 
5803    SUMA_ENTRY;
5804 
5805    if (!GLDO) SUMA_RETURNe;
5806 
5807    if (GLDO->Parent_idcode_str) SUMA_free(GLDO->Parent_idcode_str);
5808    if (GLDO->Label) SUMA_free(GLDO->Label);
5809    if (GLDO->idcode_str) SUMA_free(GLDO->idcode_str);
5810    if (GLDO->variant) SUMA_free(GLDO->variant);
5811 
5812    if (GLDO) SUMA_free(GLDO);
5813 
5814    SUMA_RETURNe;
5815 }
5816 
5817 
SUMA_CreatePlaneQuads(SUMA_PlaneDO * SDO)5818 SUMA_Boolean SUMA_CreatePlaneQuads(SUMA_PlaneDO *SDO)
5819 {
5820    static char FuncName[]={"SUMA_CreatePlaneQuads"};
5821    int i, j, N_n3, i3, n, k;
5822    GLfloat *boxdimv, xlim[2], ylim[2], zlim[2],
5823             xtmp[4], ytmp[4], ztmp[4], eqn[3], *eq, a;
5824    SUMA_Boolean LocalHead = NOPE;
5825 
5826    SUMA_ENTRY;
5827 
5828    if (!SDO->boxdimv) boxdimv = SDO->CommonBoxDims;
5829    else boxdimv = NULL;
5830 
5831    if (SDO->NodeList) SUMA_free(SDO->NodeList); SDO->NodeList=NULL;
5832    if (SDO->FaceSetList) SUMA_free(SDO->FaceSetList); SDO->FaceSetList=NULL;
5833    if (SDO->nodecol) SUMA_free(SDO->nodecol); SDO->nodecol=NULL;
5834    if (SDO->NodeNormList) SUMA_free(SDO->NodeNormList); SDO->NodeNormList=NULL;
5835 
5836    SDO->N_Node = 4*SDO->N_n;
5837    SDO->NodeList = (GLfloat *)SUMA_calloc(SDO->N_Node*3, sizeof(GLfloat));
5838    SDO->NodeNormList = (GLfloat *)SUMA_calloc(SDO->N_Node*3, sizeof(GLfloat));
5839    SDO->N_FaceSet = SDO->N_n;
5840    SDO->FaceSetList = (GLint *)SUMA_calloc(4*SDO->N_FaceSet, sizeof(GLint));
5841    SDO->nodecol = (GLfloat *)SUMA_calloc(SDO->N_Node*4, sizeof(GLfloat));
5842    if (!SDO->NodeList || !SDO->NodeNormList ||
5843        !SDO->FaceSetList || !SDO->nodecol) {
5844       SUMA_S_Crit("Failed to allocate");
5845       SUMA_RETURN(NOPE);
5846    }
5847 
5848    for (i=0; i<SDO->N_n;++i) {
5849       i3 = 3*i; n = 4*i;
5850       if (SDO->boxdimv) boxdimv = &(SDO->boxdimv[i3]);
5851       /* calcuate limits of box limiting plane */
5852       xlim[0] = SDO->cxyz[0] - boxdimv[0];
5853       xlim[1] = SDO->cxyz[0] + boxdimv[0];
5854       ylim[0] = SDO->cxyz[1] - boxdimv[1];
5855       ylim[1] = SDO->cxyz[1] + boxdimv[1];
5856       zlim[0] = SDO->cxyz[2] - boxdimv[2];
5857       zlim[1] = SDO->cxyz[2] + boxdimv[2];
5858 
5859       SUMA_LHv("Box dims:\n[%3.2f %3.2f]\n[%3.2f %3.2f]\n[%3.2f %3.2f]\n",
5860                xlim[0], xlim[1], ylim[0], ylim[1], zlim[0], zlim[1]);
5861 
5862 	   /*using the limits, find the corrsponding 4 corners*/
5863       eq = &(SDO->pleq[4*i]);
5864       /* recalculate the plane's d parameter to go though center */
5865       eq[3] = -(eq[0]*SDO->cxyz[0]+eq[1]*SDO->cxyz[1]+eq[2]*SDO->cxyz[2]);
5866       SUMA_LHv("Plane: %f %f %f %f, through %f %f %f\n",
5867                eq[0], eq[1], eq[2], eq[3],
5868                SDO->cxyz[0], SDO->cxyz[1], SDO->cxyz[2]);
5869       if (eq[2] != 0.0f) {
5870          ztmp[0] = (-eq[3] -eq[0]*xlim[0] - eq[1]*ylim[0]) / eq[2];
5871          ztmp[1] = (-eq[3] -eq[0]*xlim[1] - eq[1]*ylim[0]) / eq[2];
5872          ztmp[2] = (-eq[3] -eq[0]*xlim[1] - eq[1]*ylim[1]) / eq[2];
5873          ztmp[3] = (-eq[3] -eq[0]*xlim[0] - eq[1]*ylim[1]) / eq[2];
5874          SDO->NodeList[3*(n  )  ] = xlim[0];
5875          SDO->NodeList[3*(n  )+1] = ylim[0];
5876          SDO->NodeList[3*(n  )+2] = ztmp[0]; /* Point 0 */
5877          SDO->NodeList[3*(n+1)  ] = xlim[1];
5878          SDO->NodeList[3*(n+1)+1] = ylim[0];
5879          SDO->NodeList[3*(n+1)+2] = ztmp[1]; /* Point 1 */
5880          SDO->NodeList[3*(n+2)  ] = xlim[1];
5881          SDO->NodeList[3*(n+2)+1] = ylim[1];
5882          SDO->NodeList[3*(n+2)+2] = ztmp[2]; /* Point 2 */
5883          SDO->NodeList[3*(n+3)  ] = xlim[0];
5884          SDO->NodeList[3*(n+3)+1] = ylim[1];
5885          SDO->NodeList[3*(n+3)+2] = ztmp[3]; /* Point 3 */
5886       } else if (eq[1] != 0.0f) {
5887          ytmp[0] = (-eq[3] -eq[0]*xlim[0] - eq[2]*zlim[0]) / eq[1];
5888          ytmp[1] = (-eq[3] -eq[0]*xlim[1] - eq[2]*zlim[0]) / eq[1];
5889          ytmp[2] = (-eq[3] -eq[0]*xlim[1] - eq[2]*zlim[1]) / eq[1];
5890          ytmp[3] = (-eq[3] -eq[0]*xlim[0] - eq[2]*zlim[1]) / eq[1];
5891          SDO->NodeList[3*(n  )  ] = xlim[0];
5892          SDO->NodeList[3*(n  )+1] = ytmp[0];
5893          SDO->NodeList[3*(n  )+2] = zlim[0]; /* Point 0 */
5894          SDO->NodeList[3*(n+1)  ] = xlim[1];
5895          SDO->NodeList[3*(n+1)+1] = ytmp[1];
5896          SDO->NodeList[3*(n+1)+2] = zlim[0]; /* Point 1 */
5897          SDO->NodeList[3*(n+2)  ] = xlim[1];
5898          SDO->NodeList[3*(n+2)+1] = ytmp[2];
5899          SDO->NodeList[3*(n+2)+2] = zlim[1]; /* Point 2 */
5900          SDO->NodeList[3*(n+3)  ] = xlim[0];
5901          SDO->NodeList[3*(n+3)+1] = ytmp[3];
5902          SDO->NodeList[3*(n+3)+2] = zlim[1]; /* Point 3 */
5903       } else if (eq[0] != 0.0f) {
5904          xtmp[0] = (-eq[3] -eq[1]*ylim[0] - eq[2]*zlim[0]) / eq[0];
5905          xtmp[1] = (-eq[3] -eq[1]*ylim[1] - eq[2]*zlim[0]) / eq[0];
5906          xtmp[2] = (-eq[3] -eq[1]*ylim[1] - eq[2]*zlim[1]) / eq[0];
5907          xtmp[3] = (-eq[3] -eq[1]*ylim[0] - eq[2]*zlim[1]) / eq[0];
5908          SDO->NodeList[3*(n  )  ] = xtmp[0];
5909          SDO->NodeList[3*(n  )+1] = ylim[0];
5910          SDO->NodeList[3*(n  )+2] = zlim[0]; /* Point 0 */
5911          SDO->NodeList[3*(n+1)  ] = xtmp[1];
5912          SDO->NodeList[3*(n+1)+1] = ylim[1];
5913          SDO->NodeList[3*(n+1)+2] = zlim[0]; /* Point 1 */
5914          SDO->NodeList[3*(n+2)  ] = xtmp[2];
5915          SDO->NodeList[3*(n+2)+1] = ylim[1];
5916          SDO->NodeList[3*(n+2)+2] = zlim[1]; /* Point 2 */
5917          SDO->NodeList[3*(n+3)  ] = xtmp[3];
5918          SDO->NodeList[3*(n+3)+1] = ylim[0];
5919          SDO->NodeList[3*(n+3)+2] = zlim[1]; /* Point 3 */
5920       } else {
5921          SUMA_S_Err("All zero plane?");
5922       }
5923 
5924       SUMA_LHv("4 points:\n"
5925                "[%3.2f %3.2f %3.2f]\n"
5926                "[%3.2f %3.2f %3.2f]\n"
5927                "[%3.2f %3.2f %3.2f]\n"
5928                "[%3.2f %3.2f %3.2f]\n",
5929                SDO->NodeList[3*(n  )  ],
5930                   SDO->NodeList[3*(n  )+1], SDO->NodeList[3*(n  )+2],
5931                SDO->NodeList[3*(n+1)  ],
5932                   SDO->NodeList[3*(n+1)+1], SDO->NodeList[3*(n+1)+2],
5933                SDO->NodeList[3*(n+2)  ],
5934                   SDO->NodeList[3*(n+2)+1], SDO->NodeList[3*(n+2)+2],
5935                SDO->NodeList[3*(n+3)  ],
5936                   SDO->NodeList[3*(n+3)+1], SDO->NodeList[3*(n+3)+2]
5937                );
5938 
5939       /* Normals at each node */
5940       SUMA_NORM_VEC(eq, 3, a);
5941       if (a) {
5942          eqn[0] = eq[0] / a; eqn[1] = eq[1] / a; eqn[2] = eq[2] / a;
5943       }else {
5944          eqn[0] = eqn[1] = eqn[2] = 0.0;
5945       }
5946 
5947       SDO->NodeNormList[3*(n  )  ]    = eqn[0];
5948          SDO->NodeNormList[3*(n  )+1] = eqn[1];
5949          SDO->NodeNormList[3*(n  )+2] = eqn[2];
5950       SDO->NodeNormList[3*(n+1)  ]    = eqn[0];
5951          SDO->NodeNormList[3*(n+1)+1] = eqn[1];
5952          SDO->NodeNormList[3*(n+1)+2] = eqn[2];
5953       SDO->NodeNormList[3*(n+2)  ]    = eqn[0];
5954          SDO->NodeNormList[3*(n+2)+1] = eqn[1];
5955          SDO->NodeNormList[3*(n+2)+2] = eqn[2];
5956       SDO->NodeNormList[3*(n+3)  ]    = eqn[0];
5957       SDO->NodeNormList[3*(n+3)+1]    = eqn[1];
5958       SDO->NodeNormList[3*(n+3)+2]    = eqn[2];
5959 
5960       /* Each quad representing a plane would be formed by nodes
5961          n, n+1, n+2 and n+3 */
5962       SDO->FaceSetList[4*i  ] = i  ;
5963       SDO->FaceSetList[4*i+1] = i+1;
5964       SDO->FaceSetList[4*i+2] = i+2;
5965       SDO->FaceSetList[4*i+3] = i+3;
5966 
5967       /* form the stupid color vector */
5968       if (!SDO->colv) {
5969          for (k=0; k<4; ++k) {
5970             SDO->nodecol[4*(n+k)  ] = SDO->CommonCol[0];
5971             SDO->nodecol[4*(n+k)+1] = SDO->CommonCol[1];
5972             SDO->nodecol[4*(n+k)+2] = SDO->CommonCol[2];
5973             SDO->nodecol[4*(n+k)+3] = SDO->CommonCol[3];
5974          }
5975       } else {
5976          for (k=0; k<4; ++k) {
5977             SDO->nodecol[4*(n+k)  ] = SDO->colv[4*i  ];
5978             SDO->nodecol[4*(n+k)+1] = SDO->colv[4*i+1];
5979             SDO->nodecol[4*(n+k)+2] = SDO->colv[4*i+2];
5980             SDO->nodecol[4*(n+k)+3] = SDO->colv[4*i+3];
5981          }
5982       }
5983    }
5984    SUMA_RETURN(YUP);
5985 }
5986 
SUMA_DrawPlanes(float ** PlEq,float ** cen,float * sz,int N_pl,SUMA_SurfaceViewer * sv)5987 SUMA_Boolean SUMA_DrawPlanes( float **PlEq, float **cen, float *sz,
5988                               int N_pl, SUMA_SurfaceViewer *sv)
5989 {
5990    static char FuncName[]={"SUMA_DrawPlane"};
5991    SUMA_PlaneDO *SDO=NULL;
5992    int itmp, itmp2;
5993 
5994    SUMA_ENTRY;
5995 
5996    SDO = SUMA_Alloc_PlaneDO(N_pl, FuncName, PL_type);
5997 
5998    /* fill up equations */
5999    itmp = 0;
6000    while (itmp < SDO->N_n) {
6001       itmp2 = 4*itmp;
6002       SDO->pleq[itmp2]     = PlEq[itmp][0];
6003       SDO->pleq[itmp2+1]   = PlEq[itmp][1];
6004       SDO->pleq[itmp2+2]   = PlEq[itmp][2];
6005       SDO->pleq[itmp2+3]   = PlEq[itmp][3];
6006       ++itmp;
6007    }
6008 
6009    /* fill up centers */
6010    itmp = 0;
6011    while (itmp < SDO->N_n) {
6012       itmp2 = 3*itmp;
6013       SDO->cxyz[itmp2]   = cen[itmp][0];
6014       SDO->cxyz[itmp2+1] = cen[itmp][1];
6015       SDO->cxyz[itmp2+2] = cen[itmp][2];
6016       ++itmp;
6017    }
6018 
6019    SDO->boxdimv = (float *)SUMA_calloc(3*SDO->N_n, sizeof(float));
6020    if (sz) {
6021       itmp = 0;
6022       while (itmp < SDO->N_n) {
6023          itmp2 = 3*itmp;
6024          SDO->boxdimv[itmp2] = sz[itmp];
6025          SDO->boxdimv[itmp2+1] = sz[itmp];
6026          SDO->boxdimv[itmp2+2] = sz[itmp];
6027          ++itmp;
6028       }
6029    } else {
6030       itmp = 0;
6031       while (itmp < SDO->N_n) {
6032          itmp2 = 3*itmp;
6033          SDO->boxdimv[itmp2] = 100;
6034          SDO->boxdimv[itmp2+1] = 100;
6035          SDO->boxdimv[itmp2+2] = 100;
6036          ++itmp;
6037       }
6038    }
6039 
6040    SUMA_DrawPlaneDO(SDO, sv);
6041    SUMA_free_PlaneDO(SDO);
6042 
6043    SUMA_RETURN(YUP);
6044 }
6045 
SUMA_DrawPlaneDO(SUMA_PlaneDO * SDO,SUMA_SurfaceViewer * sv)6046 SUMA_Boolean SUMA_DrawPlaneDO (SUMA_PlaneDO *SDO, SUMA_SurfaceViewer *sv)
6047 {
6048    static char FuncName[]={"SUMA_DrawPlaneDO"};
6049    // DEBUG static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0}, comcol[4];
6050    static GLfloat NoColor[] = {1.0, 1.0, 0.0, 0.0}, comcol[4] = {1.0, 1.0, 0.0, 0.0};
6051    int i, N_n3, i3, rendmet;
6052    GLfloat boxdimv[3] = {3.0, 3.0, 3.0};
6053    float origwidth=0.0;
6054    SUMA_Boolean LocalHead = NOPE;
6055 
6056    SUMA_ENTRY;
6057 
6058    if (!SDO) {
6059       fprintf(stderr,"Error %s: NULL pointer.\n", FuncName);
6060       SUMA_RETURN (NOPE);
6061    }
6062    if (SDO->PolyMode == SRM_Hide || sv->PolyMode == SRM_Hide) {
6063       SUMA_RETURN(YUP);
6064    }
6065    /* check on rendering mode */
6066    if (SDO->PolyMode != SRM_ViewerDefault) {
6067      /* not the default, do the deed */
6068      SUMA_SET_GL_RENDER_MODE(SDO->PolyMode);
6069    }
6070 
6071    SUMA_CullOption(sv, "Hold");
6072 
6073    glGetFloatv(GL_LINE_WIDTH, &origwidth);
6074    glLineWidth(SDO->LineWidth);
6075 
6076    if (!SDO->NodeList) {
6077       if (!SUMA_CreatePlaneQuads(SDO)) {
6078          SUMA_S_Err("Failed to create plane nodes");
6079          SUMA_RETURN(NOPE);
6080       }
6081    }
6082 
6083 
6084    /* This allows each node to follow the color specified when it was drawn
6085       (in case you'll want to color corners differently someday) */
6086    glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE);
6087    glEnable(GL_COLOR_MATERIAL);
6088 
6089    /*Now setup various pointers*/
6090    glEnableClientState (GL_COLOR_ARRAY);
6091    glEnableClientState (GL_VERTEX_ARRAY);
6092    glEnableClientState (GL_NORMAL_ARRAY);
6093 
6094    glColorPointer (4, GL_FLOAT, 0, SDO->nodecol);
6095    glVertexPointer (3, GL_FLOAT, 0, SDO->NodeList);
6096    glNormalPointer (GL_FLOAT, 0, SDO->NodeNormList);
6097    if (LocalHead) fprintf(stdout, "Ready to draw Elements %d\n", SDO->N_FaceSet);
6098 
6099    rendmet = 0;
6100    switch (rendmet) {
6101       case 0:
6102             glDrawElements (GL_QUADS, (GLsizei)SDO->N_FaceSet*4,
6103                             GL_UNSIGNED_INT, SDO->FaceSetList);
6104             break;
6105       case 1:
6106             glPointSize(4.0); /* keep outside of glBegin */
6107             /* it is inefficient to draw points using the
6108                glar_FaceSetList because nodes are listed more
6109                than once. You are better off creating an index vector
6110                into glar_NodeList to place all the points, just once*/
6111             glDrawElements (GL_POINTS, (GLsizei)SDO->N_FaceSet*4,
6112                             GL_UNSIGNED_INT, SDO->FaceSetList);
6113             break;
6114    } /* switch RENDER_METHOD */
6115 
6116 
6117    /*fprintf(stdout, "Disabling clients\n");*/
6118    glDisableClientState (GL_COLOR_ARRAY);
6119    glDisableClientState (GL_VERTEX_ARRAY);
6120    glDisableClientState (GL_NORMAL_ARRAY);
6121 
6122    glDisable(GL_COLOR_MATERIAL);
6123 
6124    glLineWidth(origwidth);
6125 
6126    /* reset viewer default rendering modes */
6127    if (SDO->PolyMode != SRM_ViewerDefault) {
6128      /* not the default, do the deed */
6129      SUMA_SET_GL_RENDER_MODE(SDO->PolyMode);
6130    }
6131 
6132    SUMA_CullOption(sv, "Restore");
6133 
6134    SUMA_RETURN (YUP);
6135 
6136 }
6137 
SUMA_Alloc_PlaneDO(int N_n,char * Label,SUMA_DO_Types type)6138 SUMA_PlaneDO * SUMA_Alloc_PlaneDO (int N_n, char *Label, SUMA_DO_Types type)
6139 {
6140    static char FuncName[]={"SUMA_Alloc_PlaneDO"};
6141    SUMA_PlaneDO* SDO;
6142    char *hs=NULL;
6143 
6144    SUMA_ENTRY;
6145 
6146    SDO = (SUMA_PlaneDO*)SUMA_calloc(1,sizeof (SUMA_PlaneDO));
6147    if (SDO == NULL) {
6148       fprintf(stderr,"SUMA_Alloc_PlaneDO Error: Failed to allocate SDO\n");
6149       SUMA_RETURN (NULL);
6150    }
6151    SDO->do_type = type;
6152 
6153    if (N_n > 0) {
6154       SDO->cxyz = (GLfloat *) SUMA_calloc (3*N_n, sizeof(GLfloat));
6155 
6156       if (!SDO->cxyz) {
6157          fprintf(stderr,"Error %s: Failed to allocate for SDO->cxyz\n", FuncName);
6158          if (SDO) SUMA_free (SDO);
6159          SUMA_RETURN (NULL);
6160       }
6161       SDO->N_n = N_n;
6162    } else {
6163       SDO->cxyz = NULL;
6164       SDO->N_n = 0;
6165    }
6166 
6167    /* create a string to hash an idcode */
6168    if (Label) hs = SUMA_copy_string(Label);
6169    else hs = SUMA_copy_string("NULL_");
6170    /*if (Parent_idcode_str) hs = SUMA_append_replace_string(hs,Parent_idcode_str,"_",1);
6171    else hs = SUMA_append_replace_string(hs,"NULL","",1);*/
6172    SDO->idcode_str = UNIQ_hashcode(hs);
6173    SUMA_free(hs); hs = NULL;
6174 
6175    if (Label) {
6176       SDO->Label = (char *)SUMA_calloc (strlen(Label)+1, sizeof(char));
6177       SDO->Label = strcpy (SDO->Label, Label);
6178    } else {
6179       SDO->Label = NULL;
6180    }
6181 
6182    /* create the ball object*/
6183    SDO->pleq = (GLfloat*)SUMA_calloc(SDO->N_n*4, sizeof(GLfloat));
6184    if (!SDO->cxyz) {
6185          SUMA_S_Err("Failed to allocate for SDO->pleq\n");
6186          SUMA_free_PlaneDO (SDO);
6187          SUMA_RETURN (NULL);
6188    }
6189 
6190    /* setup some default values */
6191    SDO->LineWidth = 4.0;
6192    SDO->CommonCol[0] = 1.0; SDO->CommonCol[1] = 1.0;
6193       SDO->CommonCol[2] = 1.0; SDO->CommonCol[3] = 1.0;
6194    SDO->CommonBoxDims[0] = SDO->CommonBoxDims[1] = SDO->CommonBoxDims[2] = 10.0;
6195    SDO->boxdimv=NULL;
6196    SDO->colv=NULL;
6197    SDO->NodeList = NULL;
6198    SDO->NodeNormList = NULL;
6199    SDO->nodecol = NULL;
6200    SDO->FaceSetList = NULL;
6201    SDO->N_Node = 0;
6202    SDO->N_FaceSet = 0;
6203    SDO->PolyMode = SRM_ViewerDefault;
6204    SUMA_RETURN (SDO);
6205 }
6206 
SUMA_free_PlaneDO(SUMA_PlaneDO * SDO)6207 void SUMA_free_PlaneDO (SUMA_PlaneDO * SDO)
6208 {
6209    static char FuncName[]={"SUMA_free_PlaneDO"};
6210 
6211    SUMA_ENTRY;
6212 
6213    if (!SDO) SUMA_RETURNe;
6214 
6215    if (SDO->cxyz) SUMA_free(SDO->cxyz);
6216    if (SDO->idcode_str) SUMA_free(SDO->idcode_str);
6217    if (SDO->Label) SUMA_free(SDO->Label);
6218    if (SDO->pleq) SUMA_free(SDO->pleq);
6219    if (SDO->boxdimv) SUMA_free(SDO->boxdimv);
6220    if (SDO->colv) SUMA_free(SDO->colv);
6221    if (SDO->NodeList) SUMA_free(SDO->NodeList);
6222    if (SDO->NodeNormList) SUMA_free(SDO->NodeNormList);
6223    if (SDO->nodecol) SUMA_free(SDO->nodecol);
6224    if (SDO->FaceSetList) SUMA_free(SDO->FaceSetList);
6225    if (SDO) SUMA_free(SDO);
6226 
6227    SUMA_RETURNe;
6228 
6229 }
6230 
SUMA_DrawMaskDO(SUMA_MaskDO * MDO,SUMA_SurfaceViewer * sv)6231 SUMA_Boolean SUMA_DrawMaskDO(SUMA_MaskDO *MDO, SUMA_SurfaceViewer *sv)
6232 {
6233    static char FuncName[]={"SUMA_DrawMaskDO"};
6234    GLint      qFaces[6][4] = {  {0 , 1 , 2 , 3},
6235                                 {1 , 5 , 6 , 2},
6236                                 {4 , 7,  6 , 5},
6237                                 {3 , 2 , 6 , 7},
6238                                 {0 , 3 , 7 , 4},
6239                                 {0 , 4 , 5 , 1} };
6240    GLint *tFaceSet=NULL;
6241    SUMA_Boolean LocalHead = NOPE;
6242 
6243    SUMA_ENTRY;
6244 
6245    if (!sv || !MDO) {
6246       SUMA_S_Err("Null input %p %p", sv, MDO);
6247       SUMA_RETURN(NOPE);
6248    }
6249 
6250    if (MDO_IS_SHADOW(MDO)) {
6251       SUMA_LH("Do not draw the shadow");
6252       SUMA_RETURN(YUP);
6253    }
6254 
6255    SUMA_LH("Drawing %s", ADO_LABEL((SUMA_ALL_DO *)MDO));
6256    if (!MDO->SO) {
6257       SUMA_S_Err("Null SO");
6258       SUMA_RETURN(NOPE);
6259    }
6260 
6261    if (MASK_MANIP_MODE(sv) &&
6262        !strcmp(MDO->idcode_str, sv->MouseMode_ado_idcode_str)) {
6263       MDO->SO->PolyMode = SRM_Line;
6264    } else {
6265       MDO->SO->PolyMode = SRM_Fill;
6266    }
6267 
6268    if (MDO_IS_BOX(MDO)) {
6269       /* Mess with SO to make it quads for display */
6270       tFaceSet = MDO->SO->glar_FaceSetList;
6271       MDO->SO->glar_FaceSetList = (GLint *)qFaces;
6272       MDO->SO->N_FaceSet = 6;
6273       MDO->SO->FaceSetDim = 4;
6274    }
6275    SUMA_SimpleDrawMesh(MDO->SO,NULL,sv);
6276 
6277    /* Any doppleganger ? */
6278    if (MDO->Parent_idcode_str && MDO->dodop && SV_IN_PRYING(sv)) {
6279       float delta[3], psize, *xyz, *ffv=NULL;
6280       int pmode;
6281       SUMA_ALL_DO *ado=NULL;
6282       ado = SUMA_whichADOg(MDO->Parent_idcode_str);
6283       xyz = MDO->dopxyz;
6284       if (ado->do_type == SO_type) {
6285          SUMA_SurfaceObject *SO = (SUMA_SurfaceObject *)ado;
6286          if (MDO->Parent_datum_index >= 0 &&
6287              MDO->Parent_datum_index < SO->N_Node) {
6288             ffv = SUMA_VisX_CoordPointer(SO);
6289             if (ffv) xyz = ffv+SO->NodeDim*MDO->Parent_datum_index;
6290          }
6291       }
6292       delta[0] = MDO->cen[0]-xyz[0];
6293       delta[1] = MDO->cen[1]-xyz[1];
6294       delta[2] = MDO->cen[2]-xyz[2];
6295 
6296       glPushMatrix();
6297       glTranslatef(-delta[0], -delta[1], -delta[2]);
6298       pmode = MDO->SO->PolyMode;
6299       psize = MDO->SO->PointSize;
6300       MDO->SO->PolyMode = SRM_Points;
6301       MDO->SO->PointSize = 2.0;
6302       SUMA_SimpleDrawMesh(MDO->SO,NULL,sv);
6303       MDO->SO->PolyMode = pmode;
6304       MDO->SO->PointSize = psize;
6305       glPopMatrix();
6306    }
6307 
6308    if (MDO_IS_BOX(MDO)) {
6309       /* Return SO to triangles */
6310       MDO->SO->glar_FaceSetList = tFaceSet;
6311       MDO->SO->N_FaceSet = 12;
6312       MDO->SO->FaceSetDim = 3;
6313    }
6314 
6315 
6316    SUMA_RETURN(YUP);
6317 }
6318 
SUMA_DrawTractDO_basic(SUMA_TractDO * TDO,SUMA_SurfaceViewer * sv)6319 SUMA_Boolean SUMA_DrawTractDO_basic (SUMA_TractDO *TDO, SUMA_SurfaceViewer *sv)
6320 {
6321    static char FuncName[]={"SUMA_DrawTractDO_basic"};
6322    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
6323    int i, i3a, i3b, n, N_pts, knet=0, n4, P, speedup = 1, N_tmask=0, ido;
6324    float origwidth=0.0, Un, U[4]={0.0, 0.0, 0.0, 1.0}, *pa=NULL, *pb=NULL;
6325    TAYLOR_TRACT *tt=NULL;
6326    TAYLOR_BUNDLE *tb=NULL;
6327    GLubyte *colid=NULL;
6328    byte *mask=NULL;
6329    byte *tmask=NULL;
6330    byte color_by_mid = 0; /* this one should be interactively set ... */
6331    GLboolean gl_sm=FALSE;
6332    DO_PICK_VARS;
6333    SUMA_Boolean ans = YUP;
6334    static int mgray_alloc=0;
6335    static GLubyte *mgrayvec=NULL;
6336    SUMA_TRACT_SAUX *TSaux=NULL;
6337    SUMA_OVERLAYS *Sover=NULL;
6338    SUMA_ALL_DO *ado = (SUMA_ALL_DO *)TDO;
6339    SUMA_Boolean LocalHead = NOPE;
6340 
6341    SUMA_ENTRY;
6342 
6343    if (!TDO || !sv || !(TSaux = SUMA_ADO_TSaux(ado))) {
6344       fprintf(stderr,"Error %s: NULL pointer.\n", FuncName);
6345       SUMA_RETURN (NOPE);
6346    }
6347 
6348    if (!TDO->net) SUMA_RETURN(YUP);
6349    {
6350       static int ncnt=0;
6351       if (!ncnt) {
6352    SUMA_S_Warn("Sover->EdgeStip not in use yet, though it is set ...\n"
6353                "Still need to trim the option listing a little, no need \n"
6354                "for val based stippling. Pickmode is %d", sv->DO_PickMode);
6355          ++ncnt;
6356       }
6357    }
6358    if (!sv->DO_PickMode) {
6359       switch (TDO->Stipple) {
6360          case SUMA_DASHED_LINE:
6361             glEnable(GL_LINE_STIPPLE);
6362             glLineStipple (1, 0x00FF);/* dashed */
6363             break;
6364          case SUMA_SOLID_LINE:
6365             if (0) {
6366                glEnable (GL_LINE_SMOOTH); /* makes lines fat, can't go too low
6367                                              in thickness, fughetaboutit */
6368                if (0) glDepthMask(FALSE); /* Disabling depth masking makes lines
6369                               coplanar with polygons
6370                               render without stitching, bleeding, or Z fighting.
6371                               Problem is, that it need to be turned on for proper
6372                               rendering of remaing objects, and that brings the
6373                               artifact back. */
6374                glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
6375             } else {
6376                glDisable(GL_LINE_SMOOTH);
6377             }
6378             break;
6379          default:
6380             fprintf(stderr,"Error %s: Unrecognized Stipple option\n", FuncName);
6381             ans = NOPE; goto GETOUT;
6382       }
6383       Sover = SUMA_ADO_CurColPlane(ado);
6384       #if 1
6385       if (Sover)  TDO->colv = SUMA_GetColorList(sv, ADO_ID((SUMA_ALL_DO *)TDO));
6386       if (!TDO->colv) {
6387          SUMA_S_Warn("Colv not found for %s\n", ADO_LABEL((SUMA_ALL_DO *)TDO));
6388       }
6389       #else /* Compute colors on the fly */
6390       TDO->colv = NULL;
6391       #endif
6392    } else {
6393       if (!(colid = SUMA_DO_get_pick_colid((SUMA_ALL_DO *)TDO, TDO->idcode_str,
6394                            "tracts", "default",
6395                            TDO->idcode_str, TRACT_type,
6396                            sv) )) {
6397          SUMA_S_Err("Failed to create colid for picking.");
6398          SUMA_RETURN(NOPE);
6399       }
6400       /* in pick mode, we enable little */
6401       DO_PICK_DISABLES;
6402    }
6403 
6404    N_tmask = 0;
6405    if (!sv->DO_PickMode || (sv->DO_PickMode && !(MASK_MANIP_MODE(sv)))) {
6406       /* Apply masking if not picking or picking while in mask moving mode */
6407       for (ido=0; ido<SUMAg_N_DOv; ++ido) {
6408          ado = (SUMA_ALL_DO *)SUMAg_DOv[ido].OP;
6409          if (ado->do_type == MASK_type &&
6410              !MDO_IS_SHADOW((SUMA_MaskDO *)ado)) {
6411             SUMA_LH("Computing intersection with %s", ADO_LABEL(ado));
6412             N_tmask += SUMA_TractMaskIntersect(TDO, (SUMA_MaskDO *)ado, &tmask);
6413             SUMA_LH("Now have %d tracts in mask", N_tmask);
6414          }
6415       }
6416    }
6417 
6418    glGetFloatv(GL_LINE_WIDTH, &origwidth);
6419    gl_sm = glIsEnabled(GL_LINE_SMOOTH);
6420    if (!TDO->thickv) glLineWidth(0.1);
6421 
6422    if (TDO->thickv) {/* slow slow slow */
6423       SUMA_S_Err("Not ready for thickness business");
6424       #if 0
6425       SUMA_LH("Drawing xyz to xyz with thickness ");
6426       if (!TDO->colv) glMaterialfv(GL_FRONT, GL_EMISSION, TDO->LineCol);
6427       glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor);
6428          /* turn off ambient and diffuse components */
6429       glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
6430       i = 0;
6431       N_n3 = 3*SDO->N_n;
6432       while (i < N_n3) {
6433          if (TDO->thickv) glLineWidth(TDO->thickv[i/3]);
6434          glBegin(GL_LINES);
6435          if (TDO->colv)
6436             glMaterialfv(GL_FRONT, GL_EMISSION, &(TDO->colv[4*(i/3)]));
6437          glVertex3f(SDO->n0[i], SDO->n0[i+1], SDO->n0[i+2]);
6438          glVertex3f(SDO->n1[i], SDO->n1[i+1], SDO->n1[i+2]);
6439          i += 3;
6440          glEnd();
6441       }
6442       #endif
6443    } else {
6444       if (speedup == 0) { /* 474764 tracts, 15462760 points = 0.8 dps! */
6445          SUMA_LH("Drawing xyz to xyz, slow");
6446          glBegin(GL_LINES);
6447          if (!TDO->colv && !colid)
6448             glMaterialfv(GL_FRONT, GL_EMISSION, TDO->LineCol);
6449                   /*turn on emissivity  */
6450          glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor);
6451                   /* turn off ambient and diffuse components */
6452          glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
6453 
6454          P = 0;
6455          for (knet=0; knet<TDO->net->N_tbv; ++knet) {
6456             tb = TDO->net->tbv[knet];
6457             for (n=0; tb && n<tb->N_tracts; ++n) {
6458                n4 = 4*Network_TB_to_1T(TDO->net, n, knet);
6459                tt = tb->tracts+n;
6460                N_pts = TRACT_NPTS(tt);
6461                if (!TDO->colv && N_pts>2 && color_by_mid) {
6462                   /* set color based on mid point */
6463                   pa = tt->pts+(tt->N_pts3/2);
6464                   pb = pa - 3;
6465                   SUMA_SEG_DELTA_COL(pa,pb,U, Un);
6466                   glMaterialfv(GL_FRONT, GL_EMISSION, U);
6467                }
6468                i = 1; ++P;
6469                while (i < N_pts) {
6470                   i3a = 3*i; i3b = 3*(i-1);
6471                   pa = tt->pts+i3a; pb = tt->pts+i3b;
6472                   if (!colid) {
6473                      if (TDO->colv) {
6474                         glMaterialfv(GL_FRONT, GL_EMISSION, &(TDO->colv[4*P]));
6475                         #if 0
6476                         SUMA_LH("colv Bundle %d, Tract %d, pt %d, P=%d/%d, "
6477                                     "[%f %f %f] --> [%f %f %f], U=[%f %f %f %f]",
6478                                     knet, n, i, P, Network_N_points(TDO->net),
6479                                     pa[0], pa[1], pa[2], pb[0], pb[1], pb[2],
6480                                     TDO->colv[4*P], TDO->colv[4*P+1],
6481                                     TDO->colv[4*P+2], TDO->colv[4*P+3]);
6482                         #endif
6483                      } else if (!color_by_mid) {
6484                         SUMA_SEG_DELTA_COL(pa,pb,U, Un);
6485                         glMaterialfv(GL_FRONT, GL_EMISSION, U);
6486                      }
6487                   } else {
6488                      glColor4ub(colid[n4], colid[n4+1],
6489                                 colid[n4+2], colid[n4+3]);
6490                      #if 0
6491                      SUMA_LHv("colid for bundle %d         %d %d %d %d\n",
6492                               knet, colid[n4], colid[n4+1],
6493                               colid[n4+2], colid[n4+3]);
6494                      #endif
6495                   }
6496                   glVertex3f(pa[0], pa[1], pa[2]);
6497                   glVertex3f(pb[0], pb[1], pb[2]);
6498                   ++i; ++P;
6499                }
6500             }
6501          }
6502          glEnd();
6503       } else if (speedup == 1) { /* 474764 tracts, 15462760 points = 3.45 dps */
6504          static GLuint *rampind=NULL;
6505          static int N_rampind = 0;
6506          if (N_rampind < Network_Max_tract_length(TDO->net, 0, NULL, NULL)) {
6507             N_rampind = Network_Max_tract_length(TDO->net, 0, NULL, NULL);
6508             rampind = (GLuint *)SUMA_realloc(rampind,sizeof(GLuint)*N_rampind);
6509             for (i=0; i<N_rampind; ++i) rampind[i]= i;
6510          }
6511          SUMA_LH("Drawing xyz to xyz, strips, colid = %p, colv=%p",
6512                  colid, TDO->colv);
6513          /*Now setup various pointers*/
6514                   /* turn off ambient and diffuse components */
6515          glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor);
6516          glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
6517          glColorMaterial(GL_FRONT, GL_EMISSION);
6518          glEnable(GL_COLOR_MATERIAL);
6519          glEnableClientState (GL_COLOR_ARRAY);
6520          glEnableClientState (GL_VERTEX_ARRAY);
6521          if (!TDO->colv || colid) { /* no color list,
6522                                        or in picking mode */
6523             glDisableClientState (GL_COLOR_ARRAY);
6524             if (!colid) glColor4f(0.0, 0.0, 1.0, 1.0); /* go blue if desparate */
6525          }
6526 
6527          /* This complicated next block is probably overkill.
6528          I decided to create a (static) constant color vector
6529          so that I can still stay in GL_COLOR_ARRAY,
6530          otherwise I would have to switch back and forth in
6531          a rather annoying manner. So memory is being sacrificed
6532          for code simplicity here */
6533          if (TSaux->TractMask ==  SW_SurfCont_TractMaskDim ||
6534              TSaux->TractMask ==  SW_SurfCont_TractMaskHair) {
6535             TSaux->TractMask = SW_SurfCont_TractMaskGray;
6536             SUMA_S_Warn("No support for SW_SurfCont_TractMaskDim or"
6537                         " SW_SurfCont_TractMaskHair for basic drawing."
6538                         "Gone gray. Interface not updated.");
6539          }
6540 
6541          if (TSaux->TractMask == SW_SurfCont_TractMaskGray) {
6542             if (SUMA_TDO_Max_N_tracts(TDO) > mgray_alloc) {
6543                mgray_alloc = SUMA_TDO_Max_N_tracts(TDO);
6544                if (!(mgrayvec = (GLubyte *)SUMA_realloc(
6545                         mgrayvec, 4*sizeof(GLubyte)*mgray_alloc))) {
6546                   SUMA_S_Err("Failed to allocate for %d, mgray off ",
6547                               mgray_alloc);
6548                   TSaux->TractMask = SW_SurfCont_TractMaskHide;
6549                }
6550             }
6551             if ((byte)(TSaux->MaskGray*2.55) != mgrayvec[0]) {
6552                memset(mgrayvec, (byte)(TSaux->MaskGray*2.55),
6553                                  4*mgray_alloc*sizeof(byte));
6554             }
6555          }
6556 
6557          switch (TSaux->TractMask) {
6558             case SW_SurfCont_TractMaskHide:
6559                P = 0;
6560                for (knet=0; knet<TDO->net->N_tbv; ++knet) {
6561                   tb = TDO->net->tbv[knet];
6562                   for (n=0; tb && n<tb->N_tracts; ++n) {
6563                      if (colid) { /* Pick mode */
6564                         n4 = 4*Network_TB_to_1T(TDO->net, n, knet);
6565                         glColor4ub(colid[n4], colid[n4+1],
6566                                    colid[n4+2], colid[n4+3]);
6567                      }
6568                      tt = tb->tracts+n;
6569                      N_pts = tt->N_pts3/3;
6570                      if (!tmask || tmask[Network_TB_to_1T(TDO->net, n, knet)]) {
6571                         if (!colid && TDO->colv) {
6572                            glColorPointer (4, GL_FLOAT, 0, TDO->colv+4*P);
6573                         }
6574                         glVertexPointer (3, GL_FLOAT, 0, tt->pts);
6575                         glDrawElements ( GL_LINE_STRIP, (GLsizei)N_pts,
6576                                          GL_UNSIGNED_INT, rampind);
6577                      }
6578                      P += N_pts;
6579                   }
6580                }
6581                break;
6582             case SW_SurfCont_TractMaskGray:
6583                P = 0;
6584                for (knet=0; knet<TDO->net->N_tbv; ++knet) {
6585                   tb = TDO->net->tbv[knet];
6586                   for (n=0; tb && n<tb->N_tracts; ++n) {
6587                      if (colid) { /* Pick mode */
6588                         n4 = 4*Network_TB_to_1T(TDO->net, n, knet);
6589                         glColor4ub(colid[n4], colid[n4+1],
6590                                    colid[n4+2], colid[n4+3]);
6591                      }
6592                      tt = tb->tracts+n;
6593                      N_pts = tt->N_pts3/3;
6594                      if (!tmask || tmask[Network_TB_to_1T(TDO->net, n, knet)]) {
6595                         if (!colid && TDO->colv) {
6596                            glColorPointer (4, GL_FLOAT, 0, TDO->colv+4*P);
6597                         }
6598                      } else {
6599                         if (!colid && TDO->colv) {
6600                            glColorPointer (4, GL_UNSIGNED_BYTE, 0, mgrayvec);
6601                         }
6602                      }
6603                      glVertexPointer (3, GL_FLOAT, 0, tt->pts);
6604                      glDrawElements ( GL_LINE_STRIP, (GLsizei)N_pts,
6605                                       GL_UNSIGNED_INT, rampind);
6606                      P += N_pts;
6607                   }
6608                }
6609                break;
6610             case SW_SurfCont_TractMaskIgnore:
6611                P = 0;
6612                for (knet=0; knet<TDO->net->N_tbv; ++knet) {
6613                   tb = TDO->net->tbv[knet];
6614                   for (n=0; tb && n<tb->N_tracts; ++n) {
6615                      if (colid) { /* Pick mode */
6616                         n4 = 4*Network_TB_to_1T(TDO->net, n, knet);
6617                         glColor4ub(colid[n4], colid[n4+1],
6618                                    colid[n4+2], colid[n4+3]);
6619                      }
6620                      tt = tb->tracts+n;
6621                      N_pts = tt->N_pts3/3;
6622                      if (!colid && TDO->colv) {
6623                         glColorPointer (4, GL_FLOAT, 0, TDO->colv+4*P);
6624                      }
6625                      glVertexPointer (3, GL_FLOAT, 0, tt->pts);
6626                      glDrawElements ( GL_LINE_STRIP, (GLsizei)N_pts,
6627                                       GL_UNSIGNED_INT, rampind);
6628                      P += N_pts;
6629                   }
6630                }
6631                break;
6632             default:
6633                SUMA_S_Err("Should not be here");
6634                break;
6635          }
6636          glDisableClientState (GL_COLOR_ARRAY);
6637          glDisableClientState (GL_VERTEX_ARRAY);
6638          glDisable(GL_COLOR_MATERIAL);
6639       } else if (speedup == 2) {/* 474764 tracts, 15462760 points = 2.65 dps. */
6640          static GLuint *inds=NULL;
6641          static int N_inds=0;
6642          static GLfloat *verts = NULL;
6643          SUMA_S_Note("Drawing xyz to xyz, sppedup == %d", speedup);
6644          SUMA_S_Warn("This option is for testing only.\n"
6645                      "It allocates verts and inds once for a network and will \n"
6646                      "not update if new networks are presented or that network\n"
6647                      "is changed. If one were to use this, one would need to \n"
6648                      "keep verts and inds pointers with the network, \n"
6649                      "a royal pain and memory drain. All for a method slower\n"
6650                      "that speedup == 1!\n"
6651                      "Also, the colors do not look correct. \n"
6652             "And hey, did I mention that picking (colid) is not implemented?\n"
6653             "No masking implemented either");
6654          glColorMaterial(GL_FRONT, GL_EMISSION);
6655          glEnable(GL_COLOR_MATERIAL);
6656          glEnableClientState (GL_COLOR_ARRAY);
6657          glEnableClientState (GL_VERTEX_ARRAY);
6658          if (!TDO->colv) { /* no color list, go blue for now */
6659             glDisableClientState (GL_COLOR_ARRAY);
6660             glColor4f(0.0, 0.0, 1.0, 1.0);
6661          }
6662          if (!inds) {
6663             inds = (GLuint*)SUMA_malloc(2*Network_N_points(TDO->net,0)
6664                                          *sizeof(GLuint));
6665             verts = (GLfloat*)SUMA_malloc(Network_N_points(TDO->net,0)
6666                                          *sizeof(GLfloat)*3);
6667             /* Fill up the monster, each segment needs an entry */
6668             N_inds = 0; P = 0;
6669             for (knet=0; knet<TDO->net->N_tbv; ++knet) {
6670                tb = TDO->net->tbv[knet];
6671                for (n=0; tb && n<tb->N_tracts; ++n) {
6672                   tt = tb->tracts+n;
6673                   N_pts = tt->N_pts3/3;
6674                   if (N_pts) {
6675                      memcpy(verts+3*P, tt->pts, tt->N_pts3*sizeof(float));
6676                      ++P;
6677                      for (i=1; i<N_pts-1; ++i) {
6678                         inds[N_inds++] = P-1; inds[N_inds++] = P; ++P;
6679                      }
6680                   }
6681                }
6682             }
6683          }
6684          if (TDO->colv) glColorPointer (4, GL_FLOAT, 0, TDO->colv);
6685          glVertexPointer (3, GL_FLOAT, 0, verts);
6686          glDrawElements ( GL_LINES, (GLsizei)N_inds,
6687                           GL_UNSIGNED_INT, inds);
6688          glDisableClientState (GL_COLOR_ARRAY);
6689          glDisableClientState (GL_VERTEX_ARRAY);
6690          glDisable(GL_COLOR_MATERIAL);
6691       }
6692    }
6693 
6694    switch (TDO->Stipple) {
6695       case SUMA_DASHED_LINE:
6696          glDisable(GL_LINE_STIPPLE);
6697          break;
6698       case SUMA_SOLID_LINE:
6699          glDisable(GL_LINE_SMOOTH);
6700          break;
6701    }
6702 
6703 
6704    GETOUT:
6705    glMaterialfv(GL_FRONT, GL_EMISSION, NoColor); /*turn off emissivity */
6706    glLineWidth(origwidth);
6707    if (sv->DO_PickMode) DO_PICK_RESTORE;
6708    if (gl_sm) glEnable(GL_LINE_SMOOTH); else glDisable(GL_LINE_SMOOTH);
6709    if (mask) SUMA_free(mask); mask=NULL;
6710    SUMA_ifree(colid);
6711    if (tmask) SUMA_free(tmask); tmask=NULL;
6712 
6713    SUMA_RETURN(ans);
6714 }
6715 
SUMA_DrawTractDO(SUMA_TractDO * TDO,SUMA_SurfaceViewer * sv)6716 SUMA_Boolean SUMA_DrawTractDO (SUMA_TractDO *TDO, SUMA_SurfaceViewer *sv)
6717 {
6718    static char FuncName[]={"SUMA_DrawTractDO"};
6719    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
6720    int i, i3a, i3b, n, N_pts, knet=0, n4, P, speedup = 1, ido;
6721    int usetcol=0;
6722    float origwidth=0.0, Un, U[4]={0.0, 0.0, 0.0, 1.0}, *pa=NULL, *pb=NULL;
6723    TAYLOR_TRACT *tt=NULL;
6724    TAYLOR_BUNDLE *tb=NULL;
6725    GLubyte *colid=NULL;
6726    byte *mask=NULL;
6727    byte color_by_mid = 0; /* this one should be interactively set ... */
6728    GLboolean gl_sm=FALSE, gllsm=FALSE;
6729    DO_PICK_VARS;
6730    SUMA_Boolean ans = YUP;
6731    static int mgray_alloc=0;
6732    static GLubyte *mgrayvec=NULL;
6733    byte *tmask_cp=NULL;
6734    int use_lmask=0, T1=0;
6735    static int LastTractMask=-1;
6736    float lrange[2];
6737    SUMA_TRACT_SAUX *TSaux=NULL;
6738    SUMA_OVERLAYS *Sover=NULL;
6739    SUMA_X_SurfCont *SurfCont = NULL;
6740    SUMA_ALL_DO *ado = (SUMA_ALL_DO *)TDO;
6741    SUMA_Boolean LocalHead = NOPE;
6742 
6743    SUMA_ENTRY;
6744 
6745    if (!TDO || !sv || !(TSaux = SUMA_ADO_TSaux(ado))) {
6746       fprintf(stderr,"Error %s: NULL pointer.\n", FuncName);
6747       SUMA_RETURN (NOPE);
6748    }
6749 
6750    SurfCont = SUMAg_CF->X->AllMaskCont;
6751    if (!TDO->net) SUMA_RETURN(YUP);
6752 
6753    if (speedup != 1) {
6754       static int ncnt=0;
6755       if (!ncnt) {
6756          SUMA_S_Warn("Two pass rendering only enabled for speedup == 1");
6757          ++ncnt;
6758       }
6759    }
6760 
6761    Sover = SUMA_ADO_CurColPlane(ado);
6762 
6763    if (Sover->EdgeStip == SW_SurfCont_TractStyleHIDE) {
6764       SUMA_LH("Tract %s hidden", ADO_LABEL(ado));
6765       SUMA_RETURN(YUP);
6766    }
6767 
6768    if (!sv->DO_PickMode) {
6769       SUMA_LHv("Stippling %d (XXX=%d, Val=%d, 01=%d)\n",
6770                    Sover->EdgeStip, SW_SurfCont_TractStyleSOLID,
6771                    SW_SurfCont_TractStyleHIDE, SW_SurfCont_TractStyleST1);
6772       if (Sover->EdgeStip == SW_SurfCont_TractStyleSOLID ||
6773           Sover->EdgeStip < 0) {
6774          TDO->Stipple = SUMA_SOLID_LINE;
6775       } else {
6776          TDO->Stipple = SUMA_DASHED_LINE;
6777       }
6778       switch (TDO->Stipple) {
6779          case SUMA_DASHED_LINE:
6780             glEnable(GL_LINE_STIPPLE);
6781             glLineStipple (1, SUMA_StippleLineMask_rand(
6782                           Sover->EdgeStip-SW_SurfCont_TractStyleHIDE, 1, 0));
6783             break;
6784          case SUMA_SOLID_LINE:
6785             if ((gllsm = glIsEnabled(GL_LINE_SMOOTH))) glDisable(GL_LINE_SMOOTH);
6786                                  /* otherwise lines are too fat */
6787             break;
6788          default:
6789             fprintf(stderr,"Error %s: Unrecognized Stipple option\n", FuncName);
6790             ans = NOPE; goto GETOUT;
6791       }
6792       #if 1
6793       if (Sover)  TDO->colv = SUMA_GetColorList(sv, ADO_ID((SUMA_ALL_DO *)TDO));
6794       if (!TDO->colv) {
6795          SUMA_S_Warn("Colv not found for %s\n", ADO_LABEL((SUMA_ALL_DO *)TDO));
6796       }
6797       #else /* Compute colors on the fly */
6798       TDO->colv = NULL;
6799       #endif
6800    } else {
6801       if (!(colid = SUMA_DO_get_pick_colid((SUMA_ALL_DO *)TDO, TDO->idcode_str,
6802                            "tracts", "default",
6803                            TDO->idcode_str, TRACT_type,
6804                            sv) )) {
6805          SUMA_S_Err("Failed to create colid for picking.");
6806          SUMA_RETURN(NOPE);
6807       }
6808       /* in pick mode, we enable little */
6809       DO_PICK_DISABLES;
6810    }
6811 
6812    if (!sv->DO_PickMode || (sv->DO_PickMode && !(MASK_MANIP_MODE(sv)))) {
6813       /* Apply masking if not picking or picking while not in mask moving mode */
6814       SUMA_TractMasksIntersect(TDO, SUMA_GetMaskEvalExpr());
6815    }
6816 
6817    /* Do we want to abide by TDO->tmask ? */
6818    if (SUMA_VisibleMDOs(sv, SUMAg_DOv, NULL)) {
6819       tmask_cp = TDO->tmask;
6820    } else {
6821       tmask_cp = NULL;
6822    }
6823 
6824    if (SurfCont && SurfCont->UseMaskLen &&
6825        SurfCont->tract_length_mask[1]>=SurfCont->tract_length_mask[0]) {
6826       use_lmask=1;
6827       lrange[0] = SurfCont->tract_length_mask[0];
6828       lrange[1] = SurfCont->tract_length_mask[1];
6829       SUMA_LH("Length range is %f %f", lrange[0], lrange[1]);
6830    } else {
6831       use_lmask=0;
6832       lrange[0] = lrange[1] = -123;
6833    }
6834 
6835    if (use_lmask) {
6836       SUMA_TDO_tract_length(TDO, -1);
6837       if (!TSaux->tract_lengths) {
6838          SUMA_S_Err("Failed to compute lengths");
6839          use_lmask = 0;
6840       }
6841    }
6842 
6843    SUMA_LH("use_lmask=%d, lrange=[%f %f] TSaux->TractMask=%d",
6844                use_lmask, lrange[0], lrange[1], TSaux->TractMask);
6845 
6846    glGetFloatv(GL_LINE_WIDTH, &origwidth);
6847    gl_sm = glIsEnabled(GL_LINE_SMOOTH);
6848    if (!TDO->thickv) glLineWidth(0.1);
6849 
6850    if (TDO->thickv) {/* slow slow slow */
6851       SUMA_S_Err("Not ready for thickness business");
6852    } else {
6853       if (speedup == 0) { /* 474764 tracts, 15462760 points = 0.8 dps! */
6854          SUMA_LH("Drawing xyz to xyz, slow");
6855          glBegin(GL_LINES);
6856          if (!TDO->colv && !colid)
6857             glMaterialfv(GL_FRONT, GL_EMISSION, TDO->LineCol);
6858                   /*turn on emissivity  */
6859          glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor);
6860                   /* turn off ambient and diffuse components */
6861          glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
6862 
6863          P = 0;
6864          for (knet=0; knet<TDO->net->N_tbv; ++knet) {
6865             tb = TDO->net->tbv[knet];
6866             for (n=0; tb && n<tb->N_tracts; ++n) {
6867                n4 = 4*Network_TB_to_1T(TDO->net, n, knet);
6868                tt = tb->tracts+n;
6869                N_pts = TRACT_NPTS(tt);
6870                if (!TDO->colv && N_pts>2 && color_by_mid) {
6871                   /* set color based on mid point */
6872                   pa = tt->pts+(tt->N_pts3/2);
6873                   pb = pa - 3;
6874                   SUMA_SEG_DELTA_COL(pa,pb,U, Un);
6875                   glMaterialfv(GL_FRONT, GL_EMISSION, U);
6876                }
6877                i = 1; ++P;
6878                while (i < N_pts) {
6879                   i3a = 3*i; i3b = 3*(i-1);
6880                   pa = tt->pts+i3a; pb = tt->pts+i3b;
6881                   if (!colid) {
6882                      if (TDO->colv) {
6883                         glMaterialfv(GL_FRONT, GL_EMISSION, &(TDO->colv[4*P]));
6884                         #if 0
6885                         SUMA_LH("colv Bundle %d, Tract %d, pt %d, P=%d/%d, "
6886                                     "[%f %f %f] --> [%f %f %f], U=[%f %f %f %f]",
6887                                     knet, n, i, P, Network_N_points(TDO->net),
6888                                     pa[0], pa[1], pa[2], pb[0], pb[1], pb[2],
6889                                     TDO->colv[4*P], TDO->colv[4*P+1],
6890                                     TDO->colv[4*P+2], TDO->colv[4*P+3]);
6891                         #endif
6892                      } else if (!color_by_mid) {
6893                         SUMA_SEG_DELTA_COL(pa,pb,U, Un);
6894                         glMaterialfv(GL_FRONT, GL_EMISSION, U);
6895                      }
6896                   } else {
6897                      glColor4ub(colid[n4], colid[n4+1],
6898                                 colid[n4+2], colid[n4+3]);
6899                      #if 0
6900                      SUMA_LHv("colid for bundle %d         %d %d %d %d\n",
6901                               knet, colid[n4], colid[n4+1],
6902                               colid[n4+2], colid[n4+3]);
6903                      #endif
6904                   }
6905                   glVertex3f(pa[0], pa[1], pa[2]);
6906                   glVertex3f(pb[0], pb[1], pb[2]);
6907                   ++i; ++P;
6908                }
6909             }
6910          }
6911          glEnd();
6912       } else if (speedup == 1) { /* 474764 tracts, 15462760 points = 3.45 dps */
6913          static GLuint *rampind=NULL;
6914          static int N_rampind = 0;
6915          if (N_rampind < Network_Max_tract_length(TDO->net, 0, NULL, NULL)) {
6916             N_rampind = Network_Max_tract_length(TDO->net, 0, NULL, NULL);
6917             rampind = (GLuint *)SUMA_realloc(rampind,sizeof(GLuint)*N_rampind);
6918             for (i=0; i<N_rampind; ++i) rampind[i]= i;
6919          }
6920          SUMA_LH("Drawing xyz to xyz, strips, colid = %p, colv=%p",
6921                  colid, TDO->colv);
6922          /*Now setup various pointers*/
6923                   /* turn off ambient and diffuse components */
6924          glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor);
6925          glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
6926          glColorMaterial(GL_FRONT, GL_EMISSION);
6927          glEnable(GL_COLOR_MATERIAL);
6928          glEnableClientState (GL_COLOR_ARRAY);
6929          glEnableClientState (GL_VERTEX_ARRAY);
6930          if (!TDO->colv || colid ||
6931              (TDO->tcols && TDO->usetcols)) { /* no color list,
6932                                        or in picking mode,
6933                                        or using per tract color */
6934             glDisableClientState (GL_COLOR_ARRAY);
6935             if (!colid) glColor4f(0.0, 0.0, 1.0, 1.0); /* go blue if desparate */
6936          }
6937 
6938          /* This complicated next block is probably overkill.
6939          I decided to create a (static) constant color vector
6940          so that I can still stay in GL_COLOR_ARRAY,
6941          otherwise I would have to switch back and forth in
6942          a rather annoying manner. So memory is being sacrificed
6943          for code simplicity here */
6944          if (TSaux->TractMask == SW_SurfCont_TractMaskGray ||
6945              TSaux->TractMask == SW_SurfCont_TractMaskDim ||
6946              TSaux->TractMask == SW_SurfCont_TractMaskHair) {
6947             if (SUMA_TDO_Max_N_tracts(TDO) > mgray_alloc) {
6948                mgray_alloc = SUMA_TDO_Max_N_tracts(TDO);
6949                if (!(mgrayvec = (GLubyte *)SUMA_realloc(
6950                         mgrayvec, 4*sizeof(GLubyte)*mgray_alloc))) {
6951                   SUMA_S_Err("Failed to allocate for %d, mgray off ",
6952                               mgray_alloc);
6953                   TSaux->TractMask = SW_SurfCont_TractMaskHide;
6954                }
6955             }
6956             if ((byte)(TSaux->MaskGray*2.55) != mgrayvec[3] ||
6957                 TSaux->TractMask != LastTractMask) {
6958                LastTractMask = TSaux->TractMask;
6959                switch (TSaux->TractMask) {
6960                   default:
6961                      break;
6962                   case SW_SurfCont_TractMaskGray: /* go gray */
6963                      memset(mgrayvec, (byte)(TSaux->MaskGray*2.55),
6964                                     4*mgray_alloc*sizeof(byte));
6965                      break;
6966                   case SW_SurfCont_TractMaskHair:  { /* bad hair */
6967                      /* pretty random coloring, PT seems to like it.
6968                         Here each tract to be grayed is getting the
6969                         color of the ith point of the entire TDO.
6970                         So the assignment is hair brained but it looks cool */
6971                      for (i=0; i<mgray_alloc; ++i) {
6972                         mgrayvec[4*i] =
6973                             (byte)((TSaux->MaskGray*TDO->colv[4*i  ]*255)/100.0);
6974                         mgrayvec[4*i+1] =
6975                             (byte)((TSaux->MaskGray*TDO->colv[4*i+1]*255)/100.0);
6976                         mgrayvec[4*i+2] =
6977                             (byte)((TSaux->MaskGray*TDO->colv[4*i+2]*255)/100.0);
6978                         mgrayvec[4*i+3] = (byte)(TSaux->MaskGray*2.55);
6979                      }
6980                      break; }
6981                }
6982             }
6983          }
6984 
6985          switch (TSaux->TractMask) {
6986             case SW_SurfCont_TractMaskHide:
6987                P = 0;
6988                for (knet=0; knet<TDO->net->N_tbv; ++knet) {
6989                   tb = TDO->net->tbv[knet];
6990                   for (n=0; tb && n<tb->N_tracts; ++n) {
6991                      usetcol=0; T1 = -1;
6992                      if (colid) { /* Pick mode */
6993                         T1 = Network_TB_to_1T(TDO->net, n, knet);
6994                         n4 = 4*T1;
6995                         glColor4ub(colid[n4], colid[n4+1],
6996                                    colid[n4+2], colid[n4+3]);
6997                      } else if (TDO->usetcols && TDO->tcols) {
6998                         /* All this enabling and disabling will
6999                         slow things down. Consider two passes
7000                         once for those with GL_COLOR_ARRAY ON
7001                         and once for those with it OFF.
7002                         Alternately, consider using the gray
7003                         color vector as is done for viewing the
7004                         hidden bundles*/
7005                         T1 = Network_TB_to_1T(TDO->net, n, knet);
7006                         n4 = 4*T1;
7007                         if (!TDO->tcols[n4+3]) {
7008                             usetcol = 0; /* use original coloring */
7009                             glEnableClientState (GL_COLOR_ARRAY);
7010                         } else {
7011                            usetcol = 1;
7012                            glDisableClientState (GL_COLOR_ARRAY);
7013                            glColor4ub(TDO->tcols[n4], TDO->tcols[n4+1],
7014                                       TDO->tcols[n4+2], TDO->tcols[n4+3]);
7015                         }
7016                      } else if (tmask_cp || use_lmask) {/* need T1 */
7017                         T1 = Network_TB_to_1T(TDO->net, n, knet);
7018                      }
7019                      tt = tb->tracts+n;
7020                      N_pts = tt->N_pts3/3;
7021                      if (!tmask_cp ||
7022                           tmask_cp[T1]) {
7023                         if (!use_lmask ||
7024                             (TSaux->tract_lengths[T1] >= lrange[0] &&
7025                              TSaux->tract_lengths[T1] <= lrange[1])) {
7026                            if (!colid && TDO->colv && !usetcol) {
7027                               glColorPointer (4, GL_FLOAT, 0, TDO->colv+4*P);
7028                            }
7029                            glVertexPointer (3, GL_FLOAT, 0, tt->pts);
7030                            glDrawElements ( GL_LINE_STRIP, (GLsizei)N_pts,
7031                                             GL_UNSIGNED_INT, rampind);
7032                         }
7033                      }
7034                      P += N_pts;
7035                   }
7036                }
7037                break;
7038             case SW_SurfCont_TractMaskGray:
7039             case SW_SurfCont_TractMaskHair:
7040             case SW_SurfCont_TractMaskDim:
7041                if (LocalHead) {
7042                   SUMA_CHECK_GL_ERROR(
7043                      "Loop 1, note that when selecting, one should not bother\n"
7044                      "with stencil rendering perhaps...");
7045                }
7046                /* Loop 1, draw everything in mask and set the stencil buffer */
7047                glEnable(GL_STENCIL_TEST);
7048                glStencilMask(0xFF); /* enable write to stencil buffer, no mask */
7049                glClearStencil(0); /* reset with 0 */
7050                glStencilFunc(GL_ALWAYS, 1, 0xFF);
7051                glStencilOp(GL_REPLACE, GL_REPLACE, GL_REPLACE); /* will set to 1
7052                                                              stencil buffer each
7053                                                              time we draw */
7054                glClear(GL_STENCIL_BUFFER_BIT); /* Clear the buffer */
7055                P = 0;
7056                for (knet=0; knet<TDO->net->N_tbv; ++knet) {
7057                   tb = TDO->net->tbv[knet];
7058                   for (n=0; tb && n<tb->N_tracts; ++n) {
7059                      usetcol=0; T1=-1;
7060                      if (colid) { /* Pick mode */
7061                         T1 = Network_TB_to_1T(TDO->net, n, knet);
7062                         n4 = 4*T1;
7063                         glColor4ub(colid[n4], colid[n4+1],
7064                                    colid[n4+2], colid[n4+3]);
7065                      } else if (TDO->usetcols && TDO->tcols) {
7066                         /* All this enabling and disabling will
7067                         slow things down. Consider two passes
7068                         once for those with GL_COLOR_ARRAY ON
7069                         and once for those with it OFF. */
7070                         T1 = Network_TB_to_1T(TDO->net, n, knet);
7071                         n4 = 4*T1;
7072                         if (!TDO->tcols[n4+3]) {
7073                             usetcol = 0; /* use original coloring */
7074                             glEnableClientState (GL_COLOR_ARRAY);
7075                         } else {
7076                            usetcol = 1;
7077                            glDisableClientState (GL_COLOR_ARRAY);
7078                            glColor4ub(TDO->tcols[n4], TDO->tcols[n4+1],
7079                                       TDO->tcols[n4+2], TDO->tcols[n4+3]);
7080                         }
7081                      } else if (tmask_cp || use_lmask) {/* need T1 */
7082                         T1 = Network_TB_to_1T(TDO->net, n, knet);
7083                      }
7084                      tt = tb->tracts+n;
7085                      N_pts = tt->N_pts3/3;
7086                      if (!tmask_cp ||
7087                           tmask_cp[T1]) {
7088                          if (!use_lmask ||
7089                              (TSaux->tract_lengths[T1] >= lrange[0] &&
7090                               TSaux->tract_lengths[T1] <= lrange[1])) {
7091                            if (!colid && TDO->colv && !usetcol) {
7092                               glColorPointer (4, GL_FLOAT, 0, TDO->colv+4*P);
7093                            }
7094                            glVertexPointer (3, GL_FLOAT, 0, tt->pts);
7095                            glDrawElements ( GL_LINE_STRIP, (GLsizei)N_pts,
7096                                             GL_UNSIGNED_INT, rampind);
7097                         }
7098                      }
7099                      P += N_pts;
7100                   }
7101                }
7102 
7103                if (LocalHead && !colid) {
7104                   GLvoid *sbuf;
7105                   sbuf =
7106                      SUMA_grabPixels(GL_STENCIL_INDEX,
7107                                      sv->X->aWIDTH, sv->X->aHEIGHT);
7108                   SUMA_CHECK_GL_ERROR("Just read stencil 1");
7109                   SUMA_PixelsToDisk(sv, sv->X->aWIDTH, sv->X->aHEIGHT,
7110                                     sbuf, SUMA_F, 1, "dsten1.jpg", 1, 1);
7111                   SUMA_ifree(sbuf);
7112                }
7113                glEnableClientState (GL_COLOR_ARRAY); /* put things back */
7114                /* Loop 2, draw everything not in the mask and not in stencil */
7115                glStencilMask(0x00); /* Don't modify stencil buffer anymore */
7116                                     /* Only draw where stencil is clear */
7117                glStencilFunc(GL_EQUAL, 0, 0xFF);
7118                P = 0;
7119                for (knet=0; knet<TDO->net->N_tbv; ++knet) {
7120                   tb = TDO->net->tbv[knet];
7121                   for (n=0; tb && n<tb->N_tracts; ++n) {
7122                      T1=-1;
7123                      if (colid) { /* Pick mode */
7124                         T1 = Network_TB_to_1T(TDO->net, n, knet);
7125                         n4 = 4*T1;
7126                         glColor4ub(colid[n4], colid[n4+1],
7127                                    colid[n4+2], colid[n4+3]);
7128                      } else if (tmask_cp || use_lmask) {/* need T1 */
7129                         T1 = Network_TB_to_1T(TDO->net, n, knet);
7130                      }
7131                      tt = tb->tracts+n;
7132                      N_pts = tt->N_pts3/3;
7133                      if ( tmask_cp &&
7134                          !tmask_cp[T1]) {
7135                         if (!use_lmask ||
7136                             (TSaux->tract_lengths[T1] >= lrange[0] &&
7137                              TSaux->tract_lengths[T1] <= lrange[1]) ) {
7138                            if (!colid && TDO->colv) {
7139                               if (TSaux->TractMask == SW_SurfCont_TractMaskDim) {
7140                                  int N4, icl; float fac = TSaux->MaskGray*2.55;
7141                                  icl = 4*P;
7142                                  i = 0; N4 = 4*N_pts;
7143                                  while (i<N4) {
7144                                     mgrayvec[i++] =
7145                                                    (byte)(fac*TDO->colv[icl++]);
7146                                     mgrayvec[i++] =
7147                                                    (byte)(fac*TDO->colv[icl++]);
7148                                     mgrayvec[i++] =
7149                                                    (byte)(fac*TDO->colv[icl++]);
7150                                     mgrayvec[i++] =
7151                                              (byte)(fac); ++icl;
7152                                  }
7153                               }
7154                               glColorPointer (4, GL_UNSIGNED_BYTE, 0, mgrayvec);
7155                            }
7156                            glVertexPointer (3, GL_FLOAT, 0, tt->pts);
7157                            glDrawElements ( GL_LINE_STRIP, (GLsizei)N_pts,
7158                                             GL_UNSIGNED_INT, rampind);
7159                        }
7160                     }
7161                     P += N_pts;
7162                   }
7163                }
7164                glDisable(GL_STENCIL_TEST);
7165                break;
7166             case SW_SurfCont_TractMaskIgnore:
7167                P = 0;
7168                for (knet=0; knet<TDO->net->N_tbv; ++knet) {
7169                   tb = TDO->net->tbv[knet];
7170                   for (n=0; tb && n<tb->N_tracts; ++n) {
7171                      T1 = -1;
7172                      if (colid) { /* Pick mode */
7173                         T1 = Network_TB_to_1T(TDO->net, n, knet);
7174                         n4 = 4*T1;
7175                         glColor4ub(colid[n4], colid[n4+1],
7176                                    colid[n4+2], colid[n4+3]);
7177                      } else if (use_lmask) {/* need T1 */
7178                         T1 = Network_TB_to_1T(TDO->net, n, knet);
7179                      }
7180                      tt = tb->tracts+n;
7181                      N_pts = tt->N_pts3/3;
7182                      if (!use_lmask ||
7183                           (TSaux->tract_lengths[T1] >= lrange[0] &&
7184                            TSaux->tract_lengths[T1] <= lrange[1])) {
7185                         if (!colid && TDO->colv) {
7186                            glColorPointer (4, GL_FLOAT, 0, TDO->colv+4*P);
7187                         }
7188                         glVertexPointer (3, GL_FLOAT, 0, tt->pts);
7189                         glDrawElements ( GL_LINE_STRIP, (GLsizei)N_pts,
7190                                          GL_UNSIGNED_INT, rampind);
7191                      }
7192                      P += N_pts;
7193                   }
7194                }
7195                break;
7196             default:
7197                SUMA_S_Err("Should not be here");
7198                break;
7199          }
7200          glDisableClientState (GL_COLOR_ARRAY);
7201          glDisableClientState (GL_VERTEX_ARRAY);
7202          glDisable(GL_COLOR_MATERIAL);
7203       } else if (speedup == 2) {/* 474764 tracts, 15462760 points = 2.65 dps. */
7204          static GLuint *inds=NULL;
7205          static int N_inds=0;
7206          static GLfloat *verts = NULL;
7207          SUMA_S_Note("Drawing xyz to xyz, sppedup == %d", speedup);
7208          SUMA_S_Warn("This option is for testing only.\n"
7209                      "It allocates verts and inds once for a network and will \n"
7210                      "not update if new networks are presented or that network\n"
7211                      "is changed. If one were to use this, one would need to \n"
7212                      "keep verts and inds pointers with the network, \n"
7213                      "a royal pain and memory drain. All for a method slower\n"
7214                      "that speedup == 1!\n"
7215                      "Also, the colors do not look correct. \n"
7216             "And hey, did I mention that picking (colid) is not implemented?\n"
7217             "No masking implemented either");
7218          glColorMaterial(GL_FRONT, GL_EMISSION);
7219          glEnable(GL_COLOR_MATERIAL);
7220          glEnableClientState (GL_COLOR_ARRAY);
7221          glEnableClientState (GL_VERTEX_ARRAY);
7222          if (!TDO->colv) { /* no color list, go blue for now */
7223             glDisableClientState (GL_COLOR_ARRAY);
7224             glColor4f(0.0, 0.0, 1.0, 1.0);
7225          }
7226          if (!inds) {
7227             inds = (GLuint*)SUMA_malloc(2*Network_N_points(TDO->net,0)
7228                                          *sizeof(GLuint));
7229             verts = (GLfloat*)SUMA_malloc(Network_N_points(TDO->net,0)
7230                                          *sizeof(GLfloat)*3);
7231             /* Fill up the monster, each segment needs an entry */
7232             N_inds = 0; P = 0;
7233             for (knet=0; knet<TDO->net->N_tbv; ++knet) {
7234                tb = TDO->net->tbv[knet];
7235                for (n=0; tb && n<tb->N_tracts; ++n) {
7236                   tt = tb->tracts+n;
7237                   N_pts = tt->N_pts3/3;
7238                   if (N_pts) {
7239                      memcpy(verts+3*P, tt->pts, tt->N_pts3*sizeof(float));
7240                      ++P;
7241                      for (i=1; i<N_pts-1; ++i) {
7242                         inds[N_inds++] = P-1; inds[N_inds++] = P; ++P;
7243                      }
7244                   }
7245                }
7246             }
7247          }
7248          if (TDO->colv) glColorPointer (4, GL_FLOAT, 0, TDO->colv);
7249          glVertexPointer (3, GL_FLOAT, 0, verts);
7250          glDrawElements ( GL_LINES, (GLsizei)N_inds,
7251                           GL_UNSIGNED_INT, inds);
7252          glDisableClientState (GL_COLOR_ARRAY);
7253          glDisableClientState (GL_VERTEX_ARRAY);
7254          glDisable(GL_COLOR_MATERIAL);
7255       }
7256    }
7257 
7258    switch (TDO->Stipple) {
7259       case SUMA_DASHED_LINE:
7260          glDisable(GL_LINE_STIPPLE);
7261          break;
7262       case SUMA_SOLID_LINE:
7263          glDisable(GL_LINE_SMOOTH);
7264          break;
7265    }
7266 
7267 
7268    GETOUT:
7269    glMaterialfv(GL_FRONT, GL_EMISSION, NoColor); /*turn off emissivity */
7270    glLineWidth(origwidth);
7271    if (sv->DO_PickMode) DO_PICK_RESTORE;
7272    if (gl_sm) glEnable(GL_LINE_SMOOTH); else glDisable(GL_LINE_SMOOTH);
7273    if (mask) SUMA_free(mask); mask=NULL;
7274    SUMA_ifree(colid);
7275    if (!sv->DO_PickMode &&
7276        TDO->Stipple == SUMA_SOLID_LINE &&
7277        gllsm) glEnable(GL_LINE_SMOOTH); /* Put things back */
7278 
7279    SUMA_RETURN(ans);
7280 }
7281 
7282 /*!
7283    Create DOs for a graph dset
7284 */
SUMA_CreateGraphDOs(SUMA_DSET * dset)7285 SUMA_Boolean SUMA_CreateGraphDOs(SUMA_DSET *dset)
7286 {
7287    static char FuncName[]={"SUMA_CreateGraphDOs"};
7288    SUMA_GraphLinkDO *GLDO=NULL;
7289 
7290    SUMA_ENTRY;
7291 
7292    if (!dset || !SUMA_isGraphDset(dset) || !dset->Aux) {
7293       SUMA_S_Errv("NULL or non Graph input: %p %d %p\n",
7294          dset, SUMA_isGraphDset(dset), dset->Aux);
7295       SUMA_RETURN(NOPE);
7296    }
7297 
7298    /* Need a place holder for the dataset as displayable object
7299       because you just don't want to copy the dataset's pointer
7300       into DOv given the the dset pointers are actively managed
7301       elsewhere. TheShadow will never get displayed, and its
7302       idcode_str is the same as the dataset's.
7303       I just might live long enough to regret this.
7304       TheShadow is a code word recognized by SUMA_Alloc_GraphLinkDO
7305       and other functions. Don't mess with it lightly*/
7306    if (!(GLDO = SUMA_Alloc_GraphLinkDO("TheShadow", dset))) {
7307       SUMA_S_Err("Failed to create TheShadow");
7308    } else { /* Add it to DOv */
7309       if (!SUMA_AddDO (SUMAg_DOv, &SUMAg_N_DOv, (void *)GLDO,
7310                        GRAPH_LINK_type, SUMA_WORLD)) {
7311          SUMA_S_Err("Failed to Add TheShadow");
7312          SUMA_free_GraphLinkDO(GLDO); GLDO=NULL;
7313       }
7314    }
7315 
7316    /* Now create a bunch of displayable DO links */
7317 
7318    if (!(GLDO = SUMA_Alloc_GraphLinkDO("G3D", dset))) {
7319       SUMA_S_Err("Failed to create G3D");
7320    } else { /* Add it to DOv */
7321       if (!SUMA_AddDO (SUMAg_DOv, &SUMAg_N_DOv, (void *)GLDO,
7322                        GRAPH_LINK_type, SUMA_WORLD)) {
7323          SUMA_S_Err("Failed to Add G3D");
7324          SUMA_free_GraphLinkDO(GLDO); GLDO=NULL;
7325       }
7326    }
7327 
7328    if (!(GLDO = SUMA_Alloc_GraphLinkDO("GMATRIX", dset))) {
7329       SUMA_S_Err("Failed to create GMATRIX");
7330    } else { /* Add it to DOv */
7331       if (!SUMA_AddDO (SUMAg_DOv, &SUMAg_N_DOv, (void *)GLDO,
7332                        GRAPH_LINK_type, SUMA_WORLD)) {
7333          SUMA_S_Err("Failed to Add GMATRIX");
7334          SUMA_free_GraphLinkDO(GLDO); GLDO=NULL;
7335       }
7336    }
7337 
7338    #if 0 /* Just a place holder, nothing is done for this type of display yet */
7339    if (!(GLDO = SUMA_Alloc_GraphLinkDO("GRELIEF", dset))) {
7340       SUMA_S_Err("Failed to create GRELIEF");
7341    } else { /* Add it to DOv */
7342       if (!SUMA_AddDO (SUMAg_DOv, &SUMAg_N_DOv, (void *)GLDO,
7343                        GRAPH_LINK_type, SUMA_WORLD)) {
7344          SUMA_S_Err("Failed to Add GMATRIX");
7345          SUMA_free_GraphLinkDO(GLDO); GLDO=NULL;
7346       }
7347    }
7348    #endif
7349 
7350    SUMA_RETURN(YUP);
7351 }
7352 
SUMA_find_Dset_GLDO(SUMA_DSET * dset,char * variant,int * ifound)7353 SUMA_GraphLinkDO *SUMA_find_Dset_GLDO(SUMA_DSET *dset, char *variant,
7354                                       int *ifound)
7355 {
7356    static char FuncName[]={"SUMA_find_Dset_GLDO"};
7357    SUMA_GraphLinkDO *GLDO=NULL;
7358    int ii;
7359 
7360    SUMA_ENTRY;
7361 
7362    if (ifound) *ifound = -1;
7363 
7364    for (ii=0; ii<SUMAg_N_DOv; ++ii) {
7365       if (SUMAg_DOv[ii].ObjectType == GRAPH_LINK_type) {
7366          GLDO = (SUMA_GraphLinkDO *)SUMAg_DOv[ii].OP;
7367          if (!strcmp(GLDO->variant, variant) &&
7368              !strcmp(GLDO->Parent_idcode_str, SDSET_ID(dset))) {
7369             if (ifound) *ifound = ii;
7370             SUMA_RETURN(GLDO);
7371          }
7372       }
7373    }
7374    SUMA_RETURN(NULL);
7375 }
7376 
SUMA_find_GLDO_Dset(SUMA_GraphLinkDO * GLDO)7377 SUMA_DSET *SUMA_find_GLDO_Dset(SUMA_GraphLinkDO *GLDO)
7378 {
7379    static char FuncName[]={"SUMA_find_GLDO_Dset"};
7380    SUMA_DSET *dset=NULL;
7381 
7382    SUMA_ENTRY;
7383 
7384    if (!GLDO) SUMA_RETURN(dset);
7385 
7386    dset = SUMA_FindDset_s(GLDO->Parent_idcode_str, SUMAg_CF->DsetList);
7387 
7388    SUMA_RETURN(dset);
7389 }
7390 
SUMA_Picked_DO_ID(SUMA_COLID_OFFSET_DATUM * codf)7391 int SUMA_Picked_DO_ID(SUMA_COLID_OFFSET_DATUM *codf)
7392 {
7393    static char FuncName[]={"SUMA_Picked_DO_ID"};
7394    int ido=-1;
7395    void *PP=NULL;
7396 
7397    SUMA_ENTRY;
7398 
7399    if (!codf) SUMA_RETURN(-1);
7400 
7401    switch (codf->ref_do_type) {
7402       case GDSET_type:
7403          #if 0
7404          if (!(PP = SUMA_FindDset_s(codf->ref_idcode_str,
7405                                      SUMAg_CF->DsetList))) {
7406             SUMA_S_Err("Could not find reference dset");
7407          }
7408          SUMA_find_Dset_GLDO((SUMA_DSET *)PP, codf->variant,&ido);
7409          #else
7410          SUMA_S_Warn("I should not be picking from DO that cannot\n"
7411                      "be displayed without a variant");
7412          #endif
7413          SUMA_RETURN(ido);
7414       case GRAPH_LINK_type:
7415          if ((ido = SUMA_whichDO(codf->ref_idcode_str,
7416                                  SUMAg_DOv, SUMAg_N_DOv)) < 0) {
7417             SUMA_S_Err("Could not find reference GRAPH_LINK");
7418          }
7419          SUMA_RETURN(ido);
7420          break;
7421       case CDOM_type:
7422          SUMA_S_Err("Not ready for CIFTI yet");
7423          SUMA_RETURN(ido);
7424          break;
7425       case SO_type:
7426          if ((ido = SUMA_findSO_inDOv (codf->ref_idcode_str,
7427                                        SUMAg_DOv, SUMAg_N_DOv)) < 0) {
7428             SUMA_S_Err("Could not find reference SO");
7429          }
7430          SUMA_RETURN(ido);
7431          break;
7432       case TRACT_type:
7433          if ((ido = SUMA_whichDO (codf->ref_idcode_str,
7434                                   SUMAg_DOv, SUMAg_N_DOv)) < 0) {
7435             SUMA_S_Err("Could not find tract");
7436          }
7437          SUMA_RETURN(ido);
7438          break;
7439       case VO_type:
7440          if ((ido = SUMA_whichDO (codf->ref_idcode_str,
7441                                   SUMAg_DOv, SUMAg_N_DOv)) < 0) {
7442             SUMA_S_Err("Could not find Volume");
7443          }
7444          SUMA_RETURN(ido);
7445       case MASK_type:
7446          if ((ido = SUMA_whichDO (codf->ref_idcode_str,
7447                                   SUMAg_DOv, SUMAg_N_DOv)) < 0) {
7448             SUMA_S_Err("Could not find mask");
7449          }
7450          SUMA_RETURN(ido);
7451          break;
7452       default:
7453          SUMA_S_Errv("Not equiped for type %d (%s) yet\n", codf->ref_do_type,
7454                      SUMA_ObjectTypeCode2ObjectTypeName(codf->ref_do_type));
7455          SUMA_RETURN(ido);
7456          break;
7457    }
7458    return(ido);
7459 }
7460 
SUMA_Picked_reference_object(SUMA_COLID_OFFSET_DATUM * cod,SUMA_DO_Types * do_type)7461 void *SUMA_Picked_reference_object(SUMA_COLID_OFFSET_DATUM *cod,
7462                                SUMA_DO_Types *do_type)
7463 {
7464    static char FuncName[]={"SUMA_Picked_reference_object"};
7465    void *PP=NULL;
7466    SUMA_DO_Types dd=NOT_SET_type;
7467 
7468    SUMA_ENTRY;
7469 
7470    if (do_type) *do_type = NOT_SET_type;
7471 
7472    if (!cod) SUMA_RETURN(PP);
7473 
7474    if (cod->ref_do_type == GDSET_type) {
7475       SUMA_S_Warn("Should not happen");
7476       if (!(PP = SUMA_FindDset_s(cod->ref_idcode_str,
7477                                      SUMAg_CF->DsetList))) {
7478          SUMA_S_Err("Could not find reference dset");
7479       }
7480       if (do_type) *do_type = GDSET_type;
7481    } else if (cod->ref_do_type == CDOM_type) {
7482       SUMA_S_Warn("Not sure this is ready for this");
7483       if (!(PP = (void *)SUMA_whichADOg(cod->ref_idcode_str))) {
7484          SUMA_S_Err("Could not find reference DO");
7485       }
7486       if (do_type) *do_type = CDOM_type;
7487    } else if (cod->ref_do_type == ANY_DSET_type) {
7488       SUMA_S_Warn("Should not happen");
7489       if (!(PP = SUMA_FindDset_s(cod->ref_idcode_str,
7490                                      SUMAg_CF->DsetList))) {
7491          SUMA_S_Err("Could not find reference dset");
7492       }
7493       if (do_type) *do_type = ANY_DSET_type;
7494    } else if (cod->ref_do_type == MD_DSET_type) {
7495       SUMA_S_Warn("Should not happen either");
7496       if (!(PP = SUMA_FindDset_s(cod->ref_idcode_str,
7497                                      SUMAg_CF->DsetList))) {
7498          SUMA_S_Err("Could not find reference dset");
7499       }
7500       if (do_type) *do_type = MD_DSET_type;
7501    } else if (cod->ref_do_type == GRAPH_LINK_type) {
7502       PP = (void *)SUMA_whichADOg(cod->ref_idcode_str);
7503       if (do_type) *do_type = GRAPH_LINK_type;
7504    } else if (cod->ref_do_type == SO_type) {
7505       if (!(PP = SUMA_findSOp_inDOv (cod->ref_idcode_str,
7506                                               SUMAg_DOv, SUMAg_N_DOv))) {
7507          SUMA_S_Err("Could not find reference SO");
7508       }
7509       if (do_type) *do_type = SO_type;
7510    } else if (cod->ref_do_type == TRACT_type) {
7511       PP = (void *)SUMA_whichADOg(cod->ref_idcode_str);
7512       if (do_type) *do_type = TRACT_type;
7513    } else if (cod->ref_do_type == VO_type) {
7514       PP = (void *)SUMA_whichADOg(cod->ref_idcode_str);
7515       if (do_type) *do_type = VO_type;
7516    } else if (cod->ref_do_type == MASK_type) {
7517       PP = (void *)SUMA_whichADOg(cod->ref_idcode_str);
7518       if (do_type) *do_type = MASK_type;
7519    } else {
7520       SUMA_S_Warnv("Ref do_type %d (%s) is unexpected. "
7521                    "Trying to guess...\n",
7522             cod->ref_do_type,
7523             SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
7524       if ((PP = SUMA_FindDset_s(cod->ref_idcode_str,
7525                                         SUMAg_CF->DsetList))) {
7526          if (do_type) {
7527             if (SUMA_isGraphDset((SUMA_DSET *)PP)) *do_type = GDSET_type;
7528             else if (SUMA_isMD_Dset((SUMA_DSET *)PP)) *do_type = MD_DSET_type  ;
7529 	    else *do_type = ANY_DSET_type;
7530          }
7531       } else if ((PP = SUMA_findSOp_inDOv (cod->ref_idcode_str,
7532                                                  SUMAg_DOv, SUMAg_N_DOv))){
7533          if (do_type) *do_type = SO_type;
7534       }
7535    }
7536 
7537    /* ref_do_type recognized but object not found, see if you can guess, just
7538       for debugging */
7539    if (!PP) {
7540       if (SUMA_find_any_object(cod->ref_idcode_str, &dd)) {
7541          SUMA_S_Errv("Found reference object but its type is %s, not %s\n",
7542                      SUMA_ObjectTypeCode2ObjectTypeName(dd),
7543                      SUMA_ObjectTypeCode2ObjectTypeName(cod->ref_do_type));
7544       }
7545    }
7546 
7547    SUMA_RETURN(PP);
7548 }
7549 
SUMA_RegisterGraphDOs(SUMA_DSET * dset,SUMA_SurfaceViewer * sv)7550 SUMA_Boolean SUMA_RegisterGraphDOs(SUMA_DSET *dset, SUMA_SurfaceViewer *sv)
7551 {
7552    static char FuncName[]={"SUMA_RegisterGraphDOs"};
7553    SUMA_GraphLinkDO *GLDO=NULL;
7554    int ifound=-1;
7555 
7556    SUMA_ENTRY;
7557 
7558 
7559    if (!dset || !SUMA_isGraphDset(dset) || !dset->Aux) {
7560       SUMA_S_Errv("NULL or non Graph input: %p %d %p\n",
7561          dset, SUMA_isGraphDset(dset), dset->Aux);
7562       SUMA_RETURN(NOPE);
7563    }
7564    if ((GLDO =  SUMA_find_Dset_GLDO(dset, "TheShadow", &ifound))) {
7565       if (!SUMA_RegisterDO(ifound, sv)) {
7566          SUMA_S_Err("Failed to register TheShadow.\n");
7567       }
7568    }
7569    if ((GLDO =  SUMA_find_Dset_GLDO(dset, "G3D", &ifound))) {
7570       if (!SUMA_RegisterDO(ifound, sv)) {
7571          SUMA_S_Err("Failed to register G3D.\n");
7572       }
7573    }
7574    if ((GLDO =  SUMA_find_Dset_GLDO(dset, "GMATRIX", &ifound))) {
7575       if (!SUMA_RegisterDO(ifound, sv)) {
7576          SUMA_S_Err("Failed to register GMATRIX.\n");
7577       }
7578    }
7579    if ((GLDO =  SUMA_find_Dset_GLDO(dset, "GRELIEF", &ifound))) {
7580       if (!SUMA_RegisterDO(ifound, sv)) {
7581          SUMA_S_Err("Failed to register GRELEIF.\n");
7582       }
7583    }
7584    SUMA_RETURN(YUP);
7585 }
7586 
SUMA_DrawGraphLinkDO(SUMA_GraphLinkDO * GLDO,SUMA_SurfaceViewer * sv)7587 SUMA_Boolean SUMA_DrawGraphLinkDO (SUMA_GraphLinkDO *GLDO,
7588                                    SUMA_SurfaceViewer *sv)
7589 {
7590    static char FuncName[]={"SUMA_DrawGraphLinkDO"};
7591    SUMA_DSET *dset=NULL;
7592    SUMA_Boolean ans = NOPE;
7593    int ifound=0;
7594    SUMA_Boolean LocalHead = NOPE;
7595 
7596    SUMA_ENTRY;
7597 
7598    if (!GLDO || !sv) {
7599       fprintf(stderr,"Error %s: NULL pointer.\n", FuncName);
7600       SUMA_RETURN (NOPE);
7601    }
7602 
7603    dset = SUMA_find_GLDO_Dset(GLDO);
7604 
7605    if (!dset) { /* remove soft link and return politely */
7606     SUMA_LHv("Removing soft link %s for its object is no longer with us\n",
7607              GLDO->Label);
7608     if (!SUMA_UnRegisterDO_idcode(GLDO->idcode_str, sv)) {
7609       SUMA_S_Err("Una furtiva lagrima");
7610     }
7611     SUMA_S_Warn("Not sure how to handle this yet. Deletion without making sure\n"
7612                 "widgets are killed is asking for bad bad trouble.\n"
7613                 "Deal with this when this comes up.\n");
7614     #if 0
7615     if (!SUMA_RemoveDO(SUMAg_DOv, &SUMAg_N_DOv, (void *)GLDO,1)) {
7616       SUMA_S_Err("Alors la, bravo!");
7617       SUMA_RETURN(NOPE);
7618     }
7619     #endif
7620     SUMA_RETURN(YUP);
7621    }
7622 
7623    ans = SUMA_DrawGraphDO (GLDO, sv, NULL);
7624 
7625    SUMA_RETURN(ans);
7626 }
7627 
7628 /*! What's the group of a DO? Return ANY if nothing is available*/
SUMA_iDO_group(int i)7629 char *SUMA_iDO_group(int i)
7630 {
7631    if (i >0 && i <SUMAg_N_DOv) {
7632       return(SUMA_DO_group(&(SUMAg_DOv[i])));
7633    }
7634    return(NULL);
7635 }
SUMA_DO_group(SUMA_DO * DO)7636 char *SUMA_DO_group(SUMA_DO *DO)
7637 {
7638    static char FuncName[]={"SUMA_DO_group"};
7639    static char gret[64]={"ANY"};
7640    SUMA_SurfaceObject *SO=NULL;
7641 
7642    SUMA_ENTRY;
7643    if (!DO) SUMA_RETURN(NULL);
7644    switch (DO->ObjectType) {
7645       case SO_type:
7646          SO = (SUMA_SurfaceObject *)(DO->OP);
7647          SUMA_RETURN(SO->Group);
7648          break;
7649       default: /* any group for now */
7650          sprintf(gret,"ANY");
7651          SUMA_RETURN(gret);
7652          break;
7653    }
7654    SUMA_RETURN(gret);
7655 }
7656 
7657 
7658 /*! What's the state of a DO?
7659     Return ANY_ANATOMICAL for a special case of those states
7660     that can be displayed in an AnatCorrect environment         */
SUMA_iDO_state(int i)7661 char *SUMA_iDO_state(int i)
7662 {
7663    if (i >0 && i <SUMAg_N_DOv) {
7664       return(SUMA_DO_state(&(SUMAg_DOv[i])));
7665    }
7666    return(NULL);
7667 }
7668 
SUMA_DO_state(SUMA_DO * DO)7669 char *SUMA_DO_state(SUMA_DO *DO)
7670 {
7671    static char FuncName[]={"SUMA_DO_state"};
7672    SUMA_SurfaceObject *SO;
7673    SUMA_GraphLinkDO *GLDO;
7674    SUMA_VOL_SAUX *VSaux=NULL;
7675    static char gret[256]={"ANY_ANATOMICAL"};
7676 
7677    SUMA_ENTRY;
7678    if (!DO) SUMA_RETURN(NULL);
7679    switch (DO->ObjectType) {
7680       case SO_type:
7681          SO = (SUMA_SurfaceObject *)(DO->OP);
7682          SUMA_RETURN(SO->State);
7683          break;
7684       case GRAPH_LINK_type:
7685          GLDO = (SUMA_GraphLinkDO *)(DO->OP);
7686          if (SUMA_isGLDO_AnatCorrect(GLDO)) {
7687             sprintf(gret,"ANY_ANATOMICAL");
7688             SUMA_RETURN(gret);
7689          } else {
7690             snprintf(gret, 255*sizeof(char),"%s_%s",
7691                         GLDO->variant, GLDO->Label);
7692             SUMA_RETURN(gret);
7693          }
7694          break;
7695       case VO_type:
7696          VSaux = SUMA_ADO_VSaux((SUMA_ALL_DO*)DO->OP);
7697 	 if (VSaux) {
7698 	    snprintf(gret, 255*sizeof(char), "%s", VSaux->State);
7699 	 } else {
7700 	    SUMA_S_Err("Volumes must now have states, defaulting to old style");
7701 	    sprintf(gret,"ANY_ANATOMICAL");
7702 	 }
7703          SUMA_RETURN(gret);
7704          break;
7705       case TRACT_type:
7706          sprintf(gret,"ANY_ANATOMICAL");
7707          SUMA_RETURN(gret);
7708          break;
7709       case MASK_type:
7710          sprintf(gret,"ANY_ANATOMICAL");
7711          SUMA_RETURN(gret);
7712          break;
7713       case CDOM_type:
7714       	 sprintf(gret,"ANY_ANATOMICAL");
7715          SUMA_RETURN(gret);
7716          break;
7717       default: /* any group for now */
7718          sprintf(gret,"ANY");
7719          SUMA_RETURN(gret);
7720          break;
7721    }
7722    sprintf(gret,"ANY");
7723    SUMA_RETURN(gret);
7724 }
7725 
7726 /*! Is a displayable object anatomically correct?
7727    \sa SUMA_isDO_AnatCorrect
7728 */
SUMA_is_iDO_AnatCorrect(int dov_id)7729 int  SUMA_is_iDO_AnatCorrect(int dov_id)
7730 {
7731    static char FuncName[]={"SUMA_is_iDO_AnatCorrect"};
7732    SUMA_ENTRY;
7733    if (dov_id < 0 || dov_id>=SUMAg_N_DOv) {
7734       SUMA_S_Errv("Bad do_id %d, not in [%d %d[ returning 0\n",
7735                   dov_id, 0, SUMAg_N_DOv);
7736       SUMA_RETURN(0);
7737    }
7738    SUMA_RETURN(SUMA_isDO_AnatCorrect(&(SUMAg_DOv[dov_id])));
7739 }
7740 
SUMA_isDO_AnatCorrect(SUMA_DO * DO)7741 int SUMA_isDO_AnatCorrect(SUMA_DO *DO)
7742 {
7743    static char FuncName[]={"SUMA_isDO_AnatCorrect"};
7744    if (!DO) return(0);
7745    return(SUMA_ADO_is_AnatCorrect((SUMA_ALL_DO*)DO->OP));
7746 }
7747 
7748 /*! Is a displayable object anatomically correct?
7749    \sa SUMA_is_iDO_AnatCorrect
7750 */
SUMA_ADO_is_AnatCorrect(SUMA_ALL_DO * ado)7751 int SUMA_ADO_is_AnatCorrect(SUMA_ALL_DO *ado)
7752 {
7753    static char FuncName[]={"SUMA_ADO_is_AnatCorrect"};
7754    SUMA_SurfaceObject *SO;
7755    SUMA_GraphLinkDO *GLDO;
7756    SUMA_ENTRY;
7757 
7758    if (!ado) SUMA_RETURN(0);
7759    switch (ado->do_type) {
7760       case SO_type:
7761          SO = (SUMA_SurfaceObject *)ado;
7762          SUMA_RETURN(SO->AnatCorrect);
7763          break;
7764       case GRAPH_LINK_type:
7765          GLDO = (SUMA_GraphLinkDO*)ado;
7766          SUMA_RETURN(SUMA_isGLDO_AnatCorrect(GLDO));
7767          break;
7768       case VO_type:
7769       case MASK_type:
7770       case CDOM_type:
7771       case TRACT_type:
7772          SUMA_RETURN(1);
7773          break;
7774       default:
7775          SUMA_RETURN(0);
7776          break;
7777    }
7778    SUMA_RETURN(0);
7779 }
7780 
7781 
SUMA_isGLDO_AnatCorrect(SUMA_GraphLinkDO * GLDO)7782 SUMA_Boolean SUMA_isGLDO_AnatCorrect(SUMA_GraphLinkDO *GLDO)
7783 {
7784    if (!GLDO) return(NOPE);
7785 
7786    if (!GLDO->variant) return(NOPE);
7787         if (!strcmp(GLDO->variant,"default")) return(NOPE);
7788    else if (!strcmp(GLDO->variant,"GMATRIX")) return(NOPE);
7789    else if (!strcmp(GLDO->variant,"G3D")) {
7790       /* for now, just return YES, you'll stil need a
7791          flag in the header to say if coordinate
7792          of nodes are anatomically correct or not */
7793       return(YUP);
7794    } else if (!strcmp(GLDO->variant,"GRELIEF")) return(NOPE);
7795    return(NOPE);
7796 }
7797 
SUMA_DrawGraphDO(SUMA_GraphLinkDO * gldo,SUMA_SurfaceViewer * sv,char * this_variant)7798 SUMA_Boolean SUMA_DrawGraphDO (SUMA_GraphLinkDO *gldo, SUMA_SurfaceViewer *sv,
7799                                char *this_variant)
7800 {
7801    static char FuncName[]={"SUMA_DrawGraphDO"};
7802    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
7803    int i, i3a, i3b, n, N_pts, mode = 0;
7804    float origwidth=0.0, Un, U[4]={0.0, 0.0, 0.0, 1.0}, *pa=NULL, *pb=NULL;
7805    GLboolean gl_sm=FALSE;
7806    SUMA_Boolean ans = YUP;
7807    SUMA_DSET *dset=NULL;
7808    char *variant=NULL;
7809    SUMA_ALL_DO *ado = (SUMA_ALL_DO *)gldo;
7810    SUMA_Boolean LocalHead = NOPE;
7811 
7812    SUMA_ENTRY;
7813 
7814    if (!(dset=SUMA_find_GLDO_Dset(gldo)) || !sv || !SUMA_isGraphDset(dset)) {
7815       fprintf(stderr,"Error %s: NULL or bad pointers.\n", FuncName);
7816       SUMA_RETURN (NOPE);
7817    }
7818 
7819    if (!this_variant) {
7820       variant = SUMA_ADO_variant(ado);
7821    } else {
7822       variant = this_variant;
7823    }
7824    if (!strcmp(variant,"default") || variant[0]=='\0') {
7825       variant = "GMATRIX";
7826    }
7827 
7828    if (this_variant && strcmp(variant,SUMA_ADO_variant(ado))){/* desired variant
7829                                                  not what the doc sent us */
7830       gldo = SUMA_find_Dset_GLDO(dset, variant, NULL);
7831       if (!gldo) {
7832          SUMA_S_Errv("Could not find variant %s of dset %s\n",
7833                      variant, SDSET_LABEL(dset));
7834          SUMA_RETURN(NOPE);
7835       }
7836       ado = (SUMA_ALL_DO *)gldo;
7837    }
7838 
7839    if (!strcmp(variant,"GMATRIX")) {
7840       SUMA_DrawGraphDO_GMATRIX (gldo, sv);
7841    } else if (!strcmp(variant,"G3D")) {
7842       SUMA_DrawGraphDO_G3D (gldo, sv);
7843    } else if (!strcmp(variant,"GRELIEF")) {
7844       SUMA_DrawGraphDO_GRELIEF (gldo, sv);
7845    } else if (!strcmp(variant,"TheShadow")) {
7846       SUMA_LH("Never draw TheShadow!!!");
7847       SUMA_RETURN(YUP);
7848    } else {
7849       SUMA_S_Errv("Don't know about variant %s\n", variant);
7850       SUMA_RETURN(NOPE);
7851    }
7852 
7853    SUMA_RETURN(YUP);
7854 }
SUMA_BordFrac_to_GB(int BF,int * G,int * B)7855 SUMA_Boolean SUMA_BordFrac_to_GB(int BF, int *G, int *B)
7856 {
7857    static char FuncName[]={"SUMA_BordFrac_to_GB"};
7858 
7859    SUMA_ENTRY;
7860 
7861    if (!G || !B) SUMA_RETURN(NOPE);
7862 
7863    switch (BF) {
7864       default:
7865       case SW_SurfCont_DsetGmatBord0:
7866          *G=1; *B=0;
7867          break;
7868       case SW_SurfCont_DsetGmatBord5:
7869          *G=5; *B=1;
7870          break;
7871       case SW_SurfCont_DsetGmatBord10:
7872          *G=10; *B=1;
7873          break;
7874       case SW_SurfCont_DsetGmatBord20:
7875          *G=20; *B=1;
7876          break;
7877       case SW_SurfCont_DsetGmatBord40:
7878          *G=40; *B=1;
7879          break;
7880    }
7881 
7882    SUMA_RETURN(YUP);
7883 }
7884 
SUMA_GDSET_clear_matrix_nido(SUMA_DSET * dset,int clear_SO)7885 SUMA_Boolean SUMA_GDSET_clear_matrix_nido(SUMA_DSET *dset, int clear_SO)
7886 {
7887    static char FuncName[]={"SUMA_GDSET_clear_matrix_nido"};
7888    SUMA_GRAPH_SAUX *GSaux = NULL;
7889 
7890    SUMA_ENTRY;
7891 
7892    if (!dset || !SUMA_isGraphDset(dset) || !(GSaux=SDSET_GSAUX(dset))) {
7893       fprintf(stderr,"Error %s: NULL or bad pointers.\n", FuncName);
7894       SUMA_RETURN (NOPE);
7895    }
7896 
7897    if (GSaux->nido) SUMA_free_NIDO(GSaux->nido);
7898    GSaux->nido = NULL;
7899 
7900    if (clear_SO) {
7901       if (GSaux->FrameSO) SUMA_Free_Surface_Object(GSaux->FrameSO);
7902       GSaux->FrameSO = NULL;
7903    }
7904    SUMA_RETURN(YUP);
7905 }
7906 
SUMA_GDSET_refresh_matrix_nido(SUMA_DSET * dset,int also_SO)7907 SUMA_Boolean SUMA_GDSET_refresh_matrix_nido(SUMA_DSET *dset, int also_SO)
7908 {
7909    static char FuncName[]={"SUMA_GDSET_refresh_matrix_nido"};
7910    SUMA_GRAPH_SAUX *GSaux = NULL;
7911 
7912    SUMA_ENTRY;
7913 
7914    if (!SUMA_GDSET_clear_matrix_nido(dset, also_SO)) {
7915       SUMA_S_Err("Unclear!");
7916       SUMA_RETURN (NOPE);
7917    }
7918 
7919    /* recreate matrix_nido */
7920    if (!SUMA_GDSET_matrix_nido(dset)) {
7921       SUMA_S_Err("Failed to recreate matrix_nido");
7922       SUMA_RETURN(NOPE);
7923    }
7924 
7925    if (also_SO) {
7926       if (!(GSaux=SDSET_GSAUX(dset)) || GSaux->FrameSO) {
7927          SUMA_S_Err("This should not be, you just cleared it!");
7928       } else {
7929          GSaux->FrameSO =
7930                      SUMA_Surface_Of_NIDO_Matrix(GSaux->nido);
7931       }
7932    }
7933 
7934    SUMA_RETURN(YUP);
7935 }
7936 
SUMA_GDSET_matrix_nido(SUMA_DSET * dset)7937 SUMA_NIDO * SUMA_GDSET_matrix_nido(SUMA_DSET *dset)
7938 {
7939    static char FuncName[]={"SUMA_GDSET_matrix_nido"};
7940    int G[3], B[3], N[3], M[3], g, b;
7941    SUMA_GRAPH_SAUX *GSaux = NULL;
7942    SUMA_OVERLAYS *curcol = NULL;
7943    char Label[64]={""};
7944    float MaxSize, fac=1.0;
7945    double Aff[4][4], V[12];
7946    NI_element *nini=NULL;
7947    SUMA_Boolean LocalHead = NOPE;
7948 
7949    SUMA_ENTRY;
7950 
7951    if (!dset || !SUMA_isGraphDset(dset) || !(GSaux=SDSET_GSAUX(dset))) {
7952       fprintf(stderr,"Error %s: NULL or bad pointers.\n", FuncName);
7953       SUMA_RETURN (NULL);
7954    }
7955 
7956    if (GSaux->nido) SUMA_RETURN(GSaux->nido);
7957 
7958    if (!(curcol = SUMA_ADO_CurColPlane((SUMA_ALL_DO *)dset))) {
7959       SUMA_S_Err("Could not find current col plane!");
7960       SUMA_RETURN (NULL);
7961    }
7962 
7963    SUMA_LHv("Creating new NIDO for %s matrix\n", SDSET_LABEL(dset));
7964    if (!(GSaux->nido = SUMA_BlankNIDO (NULL, Label, NULL, "mobile", NULL))) {
7965          SUMA_S_Errv("Failed to allocate for GSaux->nido %s (%d)\n",
7966                      Label, SDSET_VECLEN(dset));
7967          SUMA_RETURN(NULL);
7968    }
7969    NI_set_attribute(GSaux->nido->ngr,"parent_dset_id", SDSET_ID(dset));
7970 
7971    /* fill in all the parameters per the controller settings */
7972    SUMA_BordFrac_to_GB(curcol->BordFrac , &g, &b);
7973    G[0] = g; G[1] = g; G[2] = 1; /* Pixels per matrix val */
7974                      NI_SET_INTv(GSaux->nido->ngr, "PixPerVal", G, 3);
7975    B[0] = b; B[1] = b;  B[2] = 0; /* Border width */
7976                      NI_SET_INTv(GSaux->nido->ngr, "BorWid", B, 3);
7977    /* add a slice image nel */
7978    nini = NI_new_data_element("Slice", 2); /* symbolic tiny size */
7979    NI_SET_INT(nini,"k",0); /* 0th slice, always */
7980    NI_add_column (nini, NI_BYTE, NULL);
7981 
7982    /* number of values in matrix */
7983    N[0] = SDSET_MATRIX_SZ0(dset); N[1] = SDSET_MATRIX_SZ1(dset); N[2]=1;
7984    NI_SET_INTv(GSaux->nido->ngr, "Nijk", N, 3);
7985 
7986    /* number of pixels in resultant image */
7987    M[0] = G[0]*N[0] + B[0]*(N[0]+1);
7988    M[1] = G[1]*N[1] + B[1]*(N[1]+1);
7989    M[2] = 1;
7990    NI_SET_INTv(GSaux->nido->ngr, "PixCount", M, 3);
7991 
7992    SUMA_LH("Coords matrix");
7993    /* Note that X coord is for the 2nd matrix dimension,
7994       and Y coord is for the 1st (i) dimension */
7995    if (M[0]<M[1]) fac = 1.0/M[1];
7996    else fac = 1.0/M[0];
7997    MaxSize = 240.0; /* size in mm of displayed matrix */
7998    AFF44_LOAD(Aff,
7999               0.0      ,  MaxSize*fac,  0.0      ,  0.0      ,
8000              -MaxSize*fac,  0.0      ,  0.0      ,  0.0      ,
8001               0.0      ,  0.0      ,  MaxSize*fac,  0.0      );
8002    AFF44_TO_V12(V, Aff);
8003    NI_SET_DOUBLEv(GSaux->nido->ngr, "ijk_to_dicom_real", V, 12);
8004    /* and put in the inverse for good measure */
8005    SUMA_INV_V12MATRIX(V);
8006    NI_SET_DOUBLEv(GSaux->nido->ngr, "dicom_real_to_ijk", V, 12);
8007 
8008    NI_add_to_group(GSaux->nido->ngr, nini);
8009 
8010    SUMA_RETURN(GSaux->nido);
8011 }
8012 
SUMA_DrawGraphDO_GMATRIX(SUMA_GraphLinkDO * gldo,SUMA_SurfaceViewer * sv)8013 SUMA_Boolean SUMA_DrawGraphDO_GMATRIX (SUMA_GraphLinkDO *gldo,
8014                                        SUMA_SurfaceViewer *sv)
8015 {
8016    static char FuncName[]={"SUMA_DrawGraphDO_GMATRIX"};
8017    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
8018    static float txcol[4] = {1, 1, 1, 1};
8019    int iseg, N_seg, usedel=0, M4, ii, jj, iim, jjm, si, pof = 0, rid,
8020        *ui, *uj, cc, ee, eem, *GNI=NULL, *GNG=NULL, iname=0;
8021    int M[3], G[3], B[3], GB[3], N[3], is4, ii4, iipix, jjpix, iipixMax, jjpixMax;
8022    int iisel, jjsel;
8023    double Aff[4][4], I[3];
8024    DListElmt *el=NULL, *eln=NULL;
8025    NI_element *nini=NULL;
8026    GLfloat *colv=NULL, *texcoord=NULL;
8027    static GLuint texName;
8028    byte *bb=NULL;
8029    char Label[64]={""};
8030    SUMA_Boolean ans = YUP;
8031    SUMA_ALL_DO *ado = (SUMA_ALL_DO *)gldo;
8032    SUMA_DSET *dset=NULL;
8033    SUMA_GRAPH_SAUX *GSaux = NULL;
8034    SUMA_SurfaceObject *SO=NULL;
8035    SUMA_COLORLIST_STRUCT *colstr=NULL;
8036    float XYZ[27], *GNr=NULL, *GNg=NULL, *GNb=NULL;
8037    GLfloat sq_col[] = {1, 1, 1, 1.0};
8038    GLfloat per_col[] = {0.5, 0.5, 0.5, 1.0};
8039    GLboolean valid;
8040    GLfloat rpos[4];
8041    NI_element *nelxyz = NULL;
8042    char **names = NULL;
8043    SUMA_OVERLAYS *curcol = NULL;
8044    void *fontGL=NULL;
8045    SUMA_Boolean LocalHead = NOPE;
8046 
8047    SUMA_ENTRY;
8048 
8049    if (!gldo || !(dset=SUMA_find_GLDO_Dset(gldo)) || !sv
8050          || !SUMA_isGraphDset(dset) || !(GSaux=SDSET_GSAUX(dset))) {
8051       fprintf(stderr,"Error %s: NULL or bad pointers.\n", FuncName);
8052       SUMA_RETURN (NOPE);
8053    }
8054 
8055    if (sv->DO_PickMode) {
8056       SUMA_LH("In picking mode!");
8057    }
8058 
8059    if (!(curcol = SUMA_ADO_CurColPlane((SUMA_ALL_DO *)dset))) {
8060       SUMA_S_Err("Could not find current col plane!");
8061       SUMA_RETURN (NOPE);
8062    }
8063 
8064    #if USE_SER
8065    SUMA_RecordEnablingState(&(sv->SER)); /* Lazy, consider SUMA_GLStateTrack ,
8066                                          Also, why record it if it is already
8067                                          well preserved. */
8068    #endif
8069 
8070    /* Form empty NIDO*/
8071    snprintf(Label, 63*sizeof(char), "Image_%s_GMATRIX", SDSET_LABEL(dset));
8072    if (!GSaux->nido && ! (GSaux->nido = SUMA_GDSET_matrix_nido(dset))) {
8073       SUMA_S_Err("Failed to create nido");
8074       goto BUGOUT;
8075    } else {
8076       if (!(nini = SUMA_FindNgrNamedElement(GSaux->nido->ngr,"Slice"))) {
8077          SUMA_S_Err("Could not find Slice");
8078          goto BUGOUT;
8079       }
8080       NI_GET_INTv(GSaux->nido->ngr, "PixPerVal", G, 3, LocalHead);
8081       NI_GET_INTv(GSaux->nido->ngr, "BorWid", B, 3, LocalHead);
8082    }
8083 
8084    /* number of values in matrix */
8085    N[0] = SDSET_MATRIX_SZ0(dset); N[1] = SDSET_MATRIX_SZ1(dset); N[2] = 1;
8086 
8087    /* total num of pixels per value */
8088    GB[0] = G[0]+B[0];
8089    GB[1] = G[1]+B[1];
8090    GB[2] = G[2]+B[2];
8091 
8092    /* number of pixels in resultant image */
8093    M[0] = G[0]*N[0] + B[0]*(N[0]+1);
8094    M[1] = G[1]*N[1] + B[1]*(N[1]+1);
8095    M[2] = G[2]*N[2] + B[2]*(N[2]+1);
8096    NI_SET_INTv(GSaux->nido->ngr, "PixCount", M, 3);
8097 
8098    M4 = M[0]*M[1]*4;
8099 
8100    /* check on sufficient size in nini */
8101    if (nini->vec_len != M4) {
8102       NI_alter_veclen(nini, M4);
8103    }
8104    if (!(bb = (byte *)nini->vec[0])) {
8105       SUMA_S_Err("No bb to be had");
8106       goto BUGOUT;
8107    }
8108 
8109    SUMA_LHv("G=[%d %d], B=[%d %d], GB=[%d %d], M=[%d %d], M4=%d\n",
8110             G[0], G[1], B[0], B[1], GB[0], GB[1], M[0], M[1], M4);
8111 
8112    if (!(colstr = SUMA_GetColorListStruct (sv, SDSET_ID(dset)))) {
8113       SUMA_S_Errv("No col struct for %s ???\n", SDSET_LABEL(dset));
8114       goto BUGOUT;
8115    }
8116 
8117    /* Do we have a new remix ID? */
8118    NI_GET_INT(nini, "RemixID", rid);
8119    if (!NI_GOT || rid != colstr->RemixID) {
8120       SUMA_DrawDO_UL_Add(GSaux->DisplayUpdates, "nido_MapColors", 1);
8121       NI_SET_INT(nini, "RemixID", colstr->RemixID);
8122    }
8123 
8124    /* what kind of monstrosity is this ? */
8125    ui = uj = NULL;
8126    switch (dset->Aux->matrix_shape) {
8127       case MAT_FULL:
8128       case MAT_TRI:
8129       case MAT_TRI_DIAG:
8130          SUMA_LH("Direct indexing between edge points and matrix row/columns");
8131          break;
8132       case MAT_SPARSE:
8133          if (!dset->inel) {
8134             SUMA_S_Err("Don't have inel, badly shaped dataset");
8135             goto BUGOUT;
8136          }
8137          if (  !(ui = SUMA_GetUniqueIndicesVec(dset,1)) ||
8138                !(uj = SUMA_GetUniqueIndicesVec(dset,2))    ) {
8139             SUMA_S_Err("Failed to get unique indices");
8140            goto BUGOUT;
8141          }
8142          break;
8143       default:
8144          SUMA_S_Err("Congrats");
8145          break;
8146    }
8147 
8148    SUMA_LH("ui = %p, N[0]=%d, uj = %p, N[1]=%d", ui, N[0], uj, N[1]);
8149 
8150    if (dlist_size(GSaux->DisplayUpdates)) {/* GSaux->nido needs updating */
8151       el = dlist_head(GSaux->DisplayUpdates);
8152       do {
8153          usedel = 1; /* assume will consumate this element */
8154          if (!strcmp((char *)el->data,"nido_MapColors")) {
8155             /* blank out all values bb is ROW major, unlike the way
8156                MAT_full is stored. i* vars are for 1st matrix dim,
8157                j* vars are for the second*/
8158             memset(bb, 0, sizeof(byte)*M4);
8159             /* get the color vector */
8160             if (!(colv = SUMA_GetColorListPtr(colstr))) {
8161                SUMA_S_Errv("No colv for %s?\n", SDSET_LABEL(dset));
8162                goto BUGOUT;
8163             }
8164             N_seg = SDSET_VECLEN(dset);
8165 
8166             /* Fillup background grays */
8167             for (ii=0; ii<N[0]+1; ++ii) { /* 1st the rows */
8168                iipix = ii*GB[0]; iipixMax = iipix+B[0];
8169                while (iipix < iipixMax) {
8170                   jjpix = 0;
8171                   while (jjpix < M[1]) {
8172                      ii4 = (iipix*M[1]+jjpix)*4;
8173                            /* Texture image is filled in row major, so
8174                               image in bb is transposed */
8175                      bb[ii4] = 128; ++ii4;
8176                      bb[ii4] = 128; ++ii4;
8177                      bb[ii4] = 128; ++ii4;
8178                      bb[ii4] = 255;
8179                      ++jjpix;
8180                   }
8181                   ++iipix;
8182                }
8183             }
8184             for (jj=0; jj<N[1]+1; ++jj) { /* now the cols */
8185                jjpix = jj*(GB[1]); jjpixMax = jjpix+B[1];
8186                while (jjpix < jjpixMax) {
8187                   iipix = 0;
8188                   while (iipix < M[0]) {
8189                      ii4 = (iipix*M[1]+jjpix)*4;
8190                            /* Texture image is filled in row major, so
8191                               image in bb is transposed */
8192                      bb[ii4] = 128; ++ii4;
8193                      bb[ii4] = 128; ++ii4;
8194                      bb[ii4] = 128; ++ii4;
8195                      bb[ii4] = 255;
8196                      ++iipix;
8197                   }
8198                   ++jjpix;
8199                }
8200             }
8201 
8202             /* Fillup where you have segments */
8203             if (curcol->ShowMode > 0) {
8204                SUMA_LHv("Filling up image for %d cells\n", N_seg);
8205                for(iseg=0; iseg<N_seg; ++iseg) {
8206                   if (!SUMA_GDSET_SegRowToPoints(dset, iseg,
8207                                                    &ii,
8208                                                    &jj,
8209                                                    NULL)){
8210                      SUMA_S_Errv("Failed for edge %d\n", iseg);
8211                   }
8212                   si = SUMA_GDSET_EdgeRow_To_Index(dset, iseg);
8213                   if (!ui) {
8214                      iim = ii; jjm = jj;
8215                   } else {
8216                      iim = SUMA_ibinFind(ui, N[0], ii);
8217                      jjm = SUMA_ibinFind(uj, N[1], jj);
8218                   }
8219                   #if 0
8220                   SUMA_LHv(
8221                      "Edge %d [%d %d] in %dx%d mat [%d %d], "
8222                      "col [%d %d %d] (%d)\n",
8223                         si, ii, jj, N[0], N[1], iim, jjm, (byte)(255*colv[4*si]),
8224                               (byte)(255*colv[4*si+1]), (byte)(255*colv[4*si+2]),
8225                               GSaux->isColored[si]);
8226                   #endif
8227                   if (GSaux->isColored[si]) {
8228                      /* fill foreground */
8229                      iipix = iim*(GB[0])+B[0]; iipixMax = iipix+G[0];
8230                      while (iipix < iipixMax) {
8231                         jjpix = jjm*(GB[1])+B[1]; jjpixMax = jjpix+G[1];
8232                         while (jjpix < jjpixMax) {
8233                            ii4 = (iipix*M[1]+jjpix)*4;
8234                               /* Texture image is filled in row major, so
8235                                  image in bb is transposed */
8236                            is4 = 4*si;
8237                            bb[ii4] = (byte)(255*colv[is4++]); ++ii4;
8238                            bb[ii4] = (byte)(255*colv[is4++]); ++ii4;
8239                            bb[ii4] = (byte)(255*colv[is4++]); ++ii4;
8240                            bb[ii4] = (byte)(255*colv[is4  ]);
8241                            ++jjpix;
8242                         }
8243                         ++iipix;
8244                      }
8245                   }
8246                }
8247             }
8248             #if 0
8249             for (iipix=0; iipix<M[0]; ++iipix) {
8250                for (jjpix=0; jjpix<M[1]; ++jjpix) {
8251                      ii4 = (iipix*M[1]+jjpix)*4;
8252                            /* Texture image is filled in row major, so
8253                               image in bb is transposed */
8254                   fprintf(stderr,"(%d %d %d %d)   ",
8255                            bb[ii4], bb[ii4+1], bb[ii4+2], bb[ii4+3]);
8256                }
8257                fprintf(stderr,"\n");
8258             }
8259             #endif
8260          } else {
8261             usedel = 0;
8262             /* this may not need to be an error condition, you might just skip
8263             this update if it is irrelevant ?*/
8264             SUMA_LHv("DisplayUpdates command %s not relevant here\n",
8265                         (char *)el->data);
8266          }
8267 
8268          if (el != dlist_tail(GSaux->DisplayUpdates)) eln = dlist_next(el);
8269          else eln = NULL;
8270          if (usedel) {
8271             /* delete used element */
8272             SUMA_DrawDO_UL_EmptyList(GSaux->DisplayUpdates, el);
8273             el = NULL;
8274          }
8275          el = eln;
8276       } while (el);
8277    }
8278 
8279    if (LocalHead) {
8280       /* Write the matrix to an image width is M[1], height is M[0] */
8281       if (!SUMA_PixelsToDisk(NULL, M[1], M[0], (GLvoid *)bb, 4, 1,
8282                              "mat.ppm", 0, 1)) {
8283          SUMA_S_Err("Failed to save matrix to disk");
8284       } else {
8285          SUMA_LHv("Saved %dx%d matrix to %s\n", M[1], M[0], "mat.ppm");
8286       }
8287    }
8288 
8289    /* and draw the GSaux */
8290    #if 0
8291    SUMA_ShowNel(GSaux->nido->ngr);
8292    #endif
8293 
8294    /* form the SO and draw it, if you must*/
8295    if (!GSaux->FrameSO) GSaux->FrameSO =
8296                      SUMA_Surface_Of_NIDO_Matrix(GSaux->nido);
8297    if (LocalHead) SUMA_SimpleDrawMesh(GSaux->FrameSO, NULL, NULL);
8298 
8299    /* See SUMA_DrawTextureNIDOnel() for more tests
8300       before drawing 2D textures */
8301    if ((pof = glIsEnabled(GL_POLYGON_OFFSET_FILL)))
8302                      glDisable (GL_POLYGON_OFFSET_FILL);
8303 
8304    /* Now put in the texture */
8305    glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
8306    NI_GET_INT(nini,"texName",texName);
8307    if (!NI_GOT) {
8308       /* Need to generate texture */
8309       glGenTextures(1, &texName);
8310       /* Now store it */
8311       NI_SET_INT(nini,"texName",texName);
8312    }
8313    glBindTexture(GL_TEXTURE_2D, texName);
8314    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT);
8315    glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT);
8316    glTexParameteri(  GL_TEXTURE_2D,
8317                      GL_TEXTURE_MAG_FILTER, GL_NEAREST);
8318    glTexParameteri(  GL_TEXTURE_2D,
8319                      GL_TEXTURE_MIN_FILTER, GL_NEAREST);
8320          /* width is M[1], height is M[0] */
8321    glTexImage2D(  GL_TEXTURE_2D, 0, GL_RGBA,
8322                   M[1], M[0], 0, GL_RGBA,
8323                   GL_UNSIGNED_BYTE, bb);
8324    glEnable(GL_TEXTURE_2D);
8325    glTexEnvf(  GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
8326                GL_REPLACE);
8327          /* GL_DECAL, GL_REPLACE, GL_MODULATE, GL_BLEND */
8328    glBindTexture(GL_TEXTURE_2D, texName);
8329    texcoord = GSaux->FrameSO->NodeList;
8330    SUMA_LHv("Texture as image, texName=%d, filename=%s\n"
8331              "coords:\n"
8332              "%.3f %.3f %.3f\n%.3f %.3f %.3f\n"
8333              "%.3f %.3f %.3f\n%.3f %.3f %.3f\n",
8334              texName, "CoorMat",
8335              texcoord[0], texcoord[1], texcoord[2],
8336              texcoord[3], texcoord[4], texcoord[5],
8337              texcoord[6], texcoord[7], texcoord[8],
8338              texcoord[9], texcoord[10], texcoord[11]);
8339    glBegin(GL_QUADS);
8340                         /* Transpose image in bb, because matrix is column major
8341                            stored in a transposed image in row major order
8342             Image corners: A-B    Surface points forming square: 0-1
8343                            | |                                   | |
8344                            D-C                                   3-2
8345                                 Mapping: A-->0, B-->3, C-->*/
8346    glTexCoord2f(0.0, 0.0); /* A */
8347                    /* 0 */ glVertex3f(texcoord[0], texcoord[1], texcoord[2]);
8348    glTexCoord2f(0.0, 1.0); /* B */
8349                    /* 3 */ glVertex3f(texcoord[9], texcoord[10], texcoord[11]);
8350    glTexCoord2f(1.0, 1.0); /* C */
8351                    /* 2 */ glVertex3f(texcoord[6], texcoord[7], texcoord[8]);
8352    glTexCoord2f(1.0, 0.0); /* D */
8353                    /* 1 */ glVertex3f(texcoord[3], texcoord[4], texcoord[5]);
8354    glEnd();
8355    glFlush();
8356    glDisable(GL_TEXTURE_2D);
8357    if (pof) glEnable (GL_POLYGON_OFFSET_FILL); /* April 2011  */
8358 
8359    /* Put a frame around the matrix */
8360    glLineWidth(2);
8361    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, per_col );
8362             /* Add 1 to the Z coord to make the square float */
8363    texcoord = GSaux->FrameSO->NodeList;
8364    glBegin(GL_LINE_LOOP);
8365       glVertex3f(texcoord[0], texcoord[1], texcoord[2]  +0.5);
8366       glVertex3f(texcoord[3], texcoord[4], texcoord[5]  +0.5);
8367       glVertex3f(texcoord[6], texcoord[7], texcoord[8]  +0.5);
8368       glVertex3f(texcoord[9], texcoord[10], texcoord[11]+0.5);
8369    glEnd();
8370 
8371    /* Now for the selection */
8372    iisel=-1; jjsel=-1;
8373    if (SUMA_SV_GetShowSelectedDatum(sv)) {
8374       if (GSaux->PR->datum_index != -1) {
8375          /* Highlight cell */
8376          if (!SUMA_GDSET_SegIndexToPoints(dset, GSaux->PR->datum_index,
8377                                           &ii, &jj, NULL)) {
8378             SUMA_S_Err("What else?"); goto BUGOUT;
8379          }
8380          if (!ui) {
8381             iisel = ii; jjsel = jj;
8382          } else {
8383             iisel = SUMA_ibinFind(ui, N[0], ii);
8384             jjsel = SUMA_ibinFind(uj, N[1], jj);
8385          }
8386          SUMA_LH("Seg index %d is [%d %d] on matrix shape %s",
8387                  (int)GSaux->PR->datum_index, ii, jj,
8388               SUMA_matrix_shape_to_matrix_shape_name(dset->Aux->matrix_shape));
8389          if ((cc=SUMA_GDSET_edgeij_to_GMATRIX_XYZ(dset, ii, jj, XYZ, 1)) < 0) {
8390             SUMA_S_Err("Failed to get square"); goto BUGOUT;
8391          } else if (cc == 0) {
8392             SUMA_LH("Nothing to mark?");
8393             goto GETOUT;
8394          }
8395          if (cc>=4) {
8396             SUMA_LHv("Cell Loop (cc=%d)\n", cc);
8397             glLineWidth(2);
8398             glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, sq_col );
8399                      /* Add 1 to the Z coord to make the square float */
8400             glBegin(GL_LINE_LOOP);
8401                glVertex3f(XYZ[3],  XYZ[4],  XYZ[5] +1.0);
8402                glVertex3f(XYZ[6],  XYZ[7],  XYZ[8] +1.0);
8403                glVertex3f(XYZ[9],  XYZ[10], XYZ[11]+1.0);
8404                glVertex3f(XYZ[12], XYZ[13], XYZ[14]+1.0);
8405             glEnd();
8406          }
8407       } else if (GSaux->PR->iAltSel[SUMA_ENODE_0] != -1 ) {
8408          if ((cc=SUMA_GDSET_edgeij_to_GMATRIX_XYZ(dset,
8409                            GSaux->PR->iAltSel[SUMA_ENODE_0], -1, XYZ, 1)) < 0) {
8410             SUMA_S_Err("Failed to get square"); goto BUGOUT;
8411          } else if (cc == 0) {
8412             SUMA_LH("Nothing to mark?");
8413             goto GETOUT;
8414          }
8415          if (!ui) {
8416             iisel = jjsel = GSaux->PR->iAltSel[SUMA_ENODE_0];
8417          } else {
8418             iisel = jjsel =
8419                SUMA_ibinFind(ui, N[0], GSaux->PR->iAltSel[SUMA_ENODE_0]);
8420          }
8421          if (cc>=4) {
8422             SUMA_LHv("Loop1 (cc=%d)\n", cc);
8423             glLineWidth(2);
8424             glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, sq_col );
8425                      /* Add 1 to the Z coord to make the square float */
8426             glBegin(GL_LINE_LOOP);
8427                glVertex3f(XYZ[3],  XYZ[4],  XYZ[5] +1.0);
8428                glVertex3f(XYZ[6],  XYZ[7],  XYZ[8] +1.0);
8429                glVertex3f(XYZ[9],  XYZ[10], XYZ[11]+1.0);
8430                glVertex3f(XYZ[12], XYZ[13], XYZ[14]+1.0);
8431             glEnd();
8432          }
8433          if (cc>=8) {
8434             SUMA_LHv("Loop2 (cc=%d)\n", cc);
8435             glLineWidth(2);
8436             glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, sq_col );
8437                      /* Add 1 to the Z coord to make the square float */
8438             glBegin(GL_LINE_LOOP);
8439                glVertex3f(XYZ[15],  XYZ[16],  XYZ[17] +1.0);
8440                glVertex3f(XYZ[18],  XYZ[19],  XYZ[20] +1.0);
8441                glVertex3f(XYZ[21],  XYZ[22],  XYZ[23]+1.0);
8442                glVertex3f(XYZ[24],  XYZ[25],  XYZ[26]+1.0);
8443             glEnd();
8444          }
8445 
8446       }
8447    }
8448 
8449    /* Show the text ? */
8450    if ((fontGL = SUMA_Font2GLFont(curcol->Font))) {
8451       int nl, tw, th, bh, bw, skpv, skph, iioff, jjoff,
8452           lh = SUMA_glutBitmapFontHeight(fontGL), kkk=0, SGN=-1;
8453       float off = -lh, vrat, hrat;
8454       float Sz[3]={0.001, 0.001, 0.001};
8455 
8456       bh = SUMA_glutBitmapFontHeight(fontGL); /* Height of font, in pixels */
8457       bw = glutBitmapWidth(fontGL, 'M'); /* M's a fat letter, width in pixels*/
8458       SUMA_GDSET_GMATRIX_CellPixSize(dset, sv, Sz);
8459       if (Sz[1] < 0.01) Sz[1] = 0.01;
8460       if (Sz[0] < 0.01) Sz[0] = 0.01;
8461       vrat = Sz[1]/(float)bh;
8462       hrat = Sz[0]/(float)bw;
8463       skpv = (int)(1.0/vrat);
8464       skph = (int)(1.0/hrat);
8465       if (skpv < 0 || skpv > 1000000) skpv = 1000000; /* safety valve */
8466       if (skph < 0 || skph > 1000000) skph = 1000000; /* in case denom is <=0 */
8467       SUMA_LHv("Height %.2f pixels/cell, Font height %d, Rat:%f, skip %d\n"
8468                "Width  %.2f pixels/cell, Font Width  %d, Rat:%f, skip %d\n"
8469                "  GB = [%d %d]\n",
8470                Sz[1], bh, vrat, skpv,
8471                Sz[0], bw, hrat, skph,
8472                GB[0], GB[1]);
8473 
8474       /* Determine the offset in order to get the selection name displayed */
8475       iioff = jjoff = 0;
8476       if (iisel > 0 && skpv>0) {
8477          iioff = iisel;
8478          while (iioff > skpv) iioff = iioff-skpv-1;
8479       }
8480       if (jjsel > 0 && skph>0) {
8481          jjoff = jjsel;
8482          while (jjoff > skph) jjoff = jjoff-skph-1;
8483       }
8484 
8485       if (!(names = SUMA_GDSET_GetPointNamesColumn(dset, &ii, &nelxyz))) {
8486          SUMA_LH("No names!"); /* No need to weep */
8487          goto GETOUT;
8488       }
8489       if (!(GNI = SUMA_GDSET_GetPointIndexColumn(dset, &ii, NULL))) {
8490          if (ii == -2) {
8491             SUMA_S_Err("Bad news for indices!!");
8492             goto BUGOUT;
8493          }
8494       }
8495       if (!(GNG = SUMA_GDSET_GetPointGroupColumn(dset, &ii, NULL))) {
8496          SUMA_LH("No Group!"); /* No need to weep */
8497       }
8498       if (!(GNr = SUMA_GDSET_GetPointColumn_f(dset, &ii, NULL, "Gnode R"))) {
8499          SUMA_LH("No R!"); /* No need to weep */
8500       } else {
8501          if (!(GNg = SUMA_GDSET_GetPointColumn_f(dset, &ii, NULL, "Gnode G"))) {
8502             SUMA_S_Err("What? Have R but not G?");
8503             SUMA_RETURN(NOPE);
8504          }
8505          if (!(GNb = SUMA_GDSET_GetPointColumn_f(dset, &ii, NULL, "Gnode B"))) {
8506             SUMA_S_Err("What? Have R but not B?");
8507             SUMA_RETURN(NOPE);
8508          }
8509       }
8510 
8511       if (!(SUMA_GDSET_GMATRIX_Aff(dset, Aff, 1))) {
8512          SUMA_S_Err("No Aff!!");
8513          goto BUGOUT;
8514       }
8515       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, NoColor);
8516       glMaterialfv(GL_FRONT, GL_EMISSION, txcol); /*turn on emissidity for text*/
8517       /* Do the column side */
8518       ee = iioff;
8519       while (ee < N[0]) {
8520          if (!ui) {
8521             eem = ee;
8522          } else {
8523             eem = ui[ee];
8524          }
8525          if (!GNI) iname = eem;
8526          else if ((iname = SUMA_ibinFind(GNI, nelxyz->vec_len, eem)) < 0){
8527             SUMA_S_Err("Index not %d found!", eem);
8528             goto BUGOUT;
8529          }
8530 
8531          I[0] = (ee+0.5)*GB[0]-0.5; /* center of cell at row ee in pixels */
8532          I[1] = -0.15*GB[1]-0.5; /* offset to the left for where text will end */
8533          I[2] = 0.0;
8534          AFF44_MULT_I(XYZ, Aff,I);
8535          glRasterPos3d(XYZ[0], XYZ[1], XYZ[2]);
8536          glGetFloatv(GL_CURRENT_RASTER_POSITION, rpos);
8537          glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
8538          SUMA_TextBoxSize (names[iname], &tw, &th, &nl, fontGL);
8539          SUMA_LHv("For XYZ %f %f %f, name %s, width %d, height %d\n"
8540                   "Raster position (%g,%g, %g) is %s\n",
8541                   XYZ[0], XYZ[1], XYZ[2], names[iname], tw, th,
8542                   rpos[0], rpos[1], rpos[2],
8543                   valid ? "valid" : "INVALID");
8544 
8545          /* do some text action */
8546          if (valid) {
8547             if (0 && /* Not ready for prime time */
8548                 GNG && GNr && curcol->NodeCol == SW_SurfCont_DsetNodeColGrp &&
8549                 iname >=0) {
8550                   txcol[0] = GNr[iname];
8551                   txcol[1] = GNg[iname];
8552                   txcol[2] = GNb[iname];
8553                   txcol[3] = 1.0;
8554                SUMA_S_Note("%f %f %f %f",
8555                            txcol[0], txcol[1], txcol[2], txcol[3]);
8556             }
8557             glColor3fv(txcol);
8558                /* offset for right align */
8559             glBitmap( 0, 0, 0, 0,  -(float)tw, -(float)th/4.0,  NULL );
8560             for (ii=0; names[iname][ii] != '\0'; ii++) {
8561                glutBitmapCharacter(fontGL, names[iname][ii]);
8562             }
8563          }
8564          /* A little notch? Just modify I[1] (matrix column index)*/
8565          glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, per_col );
8566          glBegin(GL_LINES);
8567          I[1] = -0.10*GB[1]-0.5; AFF44_MULT_I(XYZ, Aff,I);
8568          glVertex3f(XYZ[0],  XYZ[1],  XYZ[2] +1.5);
8569          I[1] = 0.05*GB[1]-0.5; AFF44_MULT_I(XYZ, Aff,I);
8570          glVertex3f(XYZ[0],  XYZ[1],  XYZ[2] +1.5);
8571          glEnd();
8572          glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, NoColor);
8573 
8574          ee = ee+1+skpv;
8575       }
8576       ee = jjoff;
8577       while (ee < N[1]) {
8578          if (!uj) {
8579             eem = ee;
8580          } else {
8581             eem = uj[ee];
8582          }
8583          if (!GNI) iname = eem; /* implicit */
8584          else if ((iname = SUMA_ibinFind(GNI, nelxyz->vec_len, eem)) < 0){
8585             SUMA_LH("Index not found!");
8586             goto BUGOUT;
8587          }
8588          I[0] = (N[0]+ 0.15)*GB[0]-0.5; I[1] = (ee+0.5)*GB[1]-0.5; I[2] = 0.0;
8589          AFF44_MULT_I(XYZ, Aff,I);
8590          glRasterPos3d(XYZ[0], XYZ[1], XYZ[2]);
8591          glGetFloatv(GL_CURRENT_RASTER_POSITION, rpos);
8592          glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
8593          SUMA_TextBoxSize (names[iname], &tw, &th, &nl, fontGL);
8594          SUMA_LHv("For XYZ %f %f %f, name %s, text width %d\n"
8595                   "Raster position (%g,%g, %g) is %s\n",
8596                   XYZ[0], XYZ[1], XYZ[2], names[iname], tw,
8597                   rpos[0], rpos[1], rpos[2],
8598                   valid ? "valid" : "INVALID");
8599          /* do some text action, go vert.*/
8600          off = 0;
8601          if (valid) {
8602             glColor3fv(txcol);
8603             /* offset for varying horizontal center align
8604                This should be done based on necessity or user
8605                input. Perhaps just offset those whose width
8606                exceeds a cell's width in screen pixels...
8607                Deal with this later.*/
8608             /* center on 1st character */
8609                tw = glutBitmapWidth(fontGL,names[iname][0]);
8610                th = SUMA_glutBitmapFontHeight(fontGL);
8611                glBitmap( 0, 0, 0, 0,
8612                          -(float)tw/2.0, -th,  NULL );
8613             for (ii=0; names[iname][ii] != '\0'; ii++) {
8614                tw = glutBitmapWidth(fontGL,names[iname][ii]);
8615                glutBitmapCharacter(fontGL, names[iname][ii]);
8616                /* Backup width, go down for vertical offset */
8617                glBitmap( 0, 0, 0, 0,
8618                          -tw, -0.8*th,  NULL );
8619             }
8620          }
8621          /* A little vertical notch? Just modify I[0] (matrix row index)*/
8622          glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, per_col );
8623          glBegin(GL_LINES);
8624          I[0] = (N[0]+0.15)*GB[0]-0.5; AFF44_MULT_I(XYZ, Aff,I);
8625          glVertex3f(XYZ[0],  XYZ[1],  XYZ[2] +1.5);
8626          I[0] = (N[0]-0.0)*GB[0]-0.5; AFF44_MULT_I(XYZ, Aff,I);
8627          glVertex3f(XYZ[0],  XYZ[1],  XYZ[2] +1.5);
8628          glEnd();
8629          glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, NoColor);
8630 
8631          ee = ee+1+skph;
8632       }
8633 
8634       glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
8635          /*turn off emissidity for text*/
8636    }
8637 
8638 
8639    goto GETOUT;
8640 
8641    BUGOUT:
8642    ans = NOPE;
8643 
8644    GETOUT:
8645    if (pof) glEnable (GL_POLYGON_OFFSET_FILL); /* April 2011  */
8646 
8647 #if USE_SER
8648    /* Use in concert with SUMA_RecordEnablingState above */
8649    SUMA_RestoreEnablingState(&(sv->SER));
8650 #endif
8651 
8652    SUMA_RETURN(ans);
8653 }
8654 
8655 /*
8656    If you change how coordinates of framing surface relate
8657    to matrix pixel indices and matrix cells you should also
8658    update SUMA_WhatWasPicked_FrameSO(), SUMA_GDSET_edgeij_to_GMATRIX_XYZ(),
8659    and SUMA_DrawGraphDO_GMATRIX() at the very least
8660 */
SUMA_Surface_Of_NIDO_Matrix(SUMA_NIDO * nido)8661 SUMA_SurfaceObject *SUMA_Surface_Of_NIDO_Matrix(SUMA_NIDO *nido)
8662 {
8663    static char FuncName[]={"SUMA_Surface_Of_NIDO_Matrix"};
8664    SUMA_SurfaceObject *SO=NULL;
8665    SUMA_NEW_SO_OPT *nsoopt=NULL;
8666    NI_element *nini = NULL;
8667    float *NodeList=NULL, Eoff[2];
8668    double Aff[4][4], I[3], V[12], X[3];
8669    int M[2], Mf[2], GB[2], G[2], B[2], k, N_Node, N_FaceSet,
8670        *FaceSetList=NULL, i, i3;
8671 
8672    SUMA_Boolean LocalHead = NOPE;
8673 
8674    SUMA_ENTRY;
8675 
8676    if (!nido || !(nini = SUMA_FindNgrNamedElement(nido->ngr,"Slice"))) {
8677       SUMA_S_Err("Could not find Slice");
8678       SUMA_RETURN(SO);
8679    }
8680 
8681    NI_GET_INTv(nido->ngr, "PixCount", M, 2, LocalHead);
8682    if (!NI_GOT) {
8683       SUMA_S_Err("No pixel dims!");
8684       SUMA_RETURN(SO);
8685    }
8686 
8687    /* total num of pixels per value */
8688    NI_GET_INTv(nido->ngr, "PixPerVal", G, 2, LocalHead);
8689    if (!NI_GOT) {
8690       SUMA_S_Err("No PixPerVal!");
8691       SUMA_RETURN(SO);
8692    }
8693    NI_GET_INTv(nido->ngr, "BorWid", B, 2, LocalHead);
8694    if (!NI_GOT) {
8695       SUMA_S_Err("No BorWid!");
8696       SUMA_RETURN(SO);
8697    }
8698    GB[0] = G[0]+B[0];
8699    GB[1] = G[1]+B[1];
8700 
8701    NI_GET_DOUBLEv(nido->ngr, "ijk_to_dicom_real", V, 12, LocalHead);
8702    if (!NI_GOT) {
8703       SUMA_S_Err("No ijk_to_dicom_real!");
8704       SUMA_RETURN(SO);
8705    } else {
8706       V12_TO_AFF44(Aff, V);
8707    }
8708 
8709 
8710    NI_GET_INT(nini, "k", k);
8711    if (!NI_GOT) {
8712       SUMA_S_Warn("No k, setting to 0");
8713       k = 0;
8714    }
8715 
8716    /* Prepare the grid (see labbook NIH-6, pp 243*/
8717    N_Node = 12;
8718    N_FaceSet = 10;
8719    NodeList = (float *)SUMA_calloc(3*N_Node, sizeof(float));
8720    FaceSetList = (int *)SUMA_calloc(3*N_FaceSet, sizeof(int));
8721    I[2] = k;
8722 
8723    /* load the coordinates of the corners (not voxel/cell centers) */
8724    Mf[0] = M[0]-1; Mf[1] = M[1]-1; /* -1 because you want the max
8725                                  to be the last index, not number of voxels*/
8726     /* Offset size for row/col selection, keep it generous in size, no
8727        harm in that.  */
8728    Eoff[0] = SUMA_MAX_PAIR(1, Mf[0]/2.0);
8729    Eoff[1] = SUMA_MAX_PAIR(1, Mf[1]/2.0);
8730 
8731    /* Oh just use the same dimension from the surround select region */
8732    Eoff[0] = SUMA_MAX_PAIR(Eoff[0], Eoff[1]);
8733    Eoff[1] = Eoff[0];
8734 
8735    i = 0; i3 = 3*i;  I[0] = -0.5; I[1] = -0.5;
8736                                                          AFF44_MULT_I(X, Aff,I);
8737    NodeList[i3++] = X[0]; NodeList[i3++] = X[1]; NodeList[i3++] = X[2];
8738 
8739    i = 1; i3 = 3*i;  I[0] = -0.5; I[1] = Mf[1]+0.5;
8740                                                          AFF44_MULT_I(X, Aff,I);
8741    NodeList[i3++] = X[0]; NodeList[i3++] = X[1]; NodeList[i3++] = X[2];
8742 
8743    i = 2; i3 = 3*i;  I[0] = Mf[0]+0.5; I[1] = Mf[1]+0.5;
8744                                                          AFF44_MULT_I(X, Aff,I);
8745    NodeList[i3++] = X[0]; NodeList[i3++] = X[1]; NodeList[i3++] = X[2];
8746 
8747    i = 3; i3 = 3*i;  I[0] = Mf[0]+0.5; I[1] = -0.5;
8748                                                          AFF44_MULT_I(X, Aff,I);
8749    NodeList[i3++] = X[0]; NodeList[i3++] = X[1]; NodeList[i3++] = X[2];
8750 
8751    i = 4; i3 = 3*i;  I[0] = -Eoff[0]-0.5; I[1] = -0.5;
8752                                                          AFF44_MULT_I(X, Aff,I);
8753    NodeList[i3++] = X[0]; NodeList[i3++] = X[1]; NodeList[i3++] = X[2];
8754 
8755    i = 5; i3 = 3*i;  I[0] = -Eoff[0]-0.5; I[1] = Mf[1]+0.5;
8756                                                          AFF44_MULT_I(X, Aff,I);
8757    NodeList[i3++] = X[0]; NodeList[i3++] = X[1]; NodeList[i3++] = X[2];
8758 
8759    i = 6; i3 = 3*i;  I[0] = -0.5; I[1] = Mf[1]+Eoff[1]+0.5;
8760                                                          AFF44_MULT_I(X, Aff,I);
8761    NodeList[i3++] = X[0]; NodeList[i3++] = X[1]; NodeList[i3++] = X[2];
8762 
8763    i = 7; i3 = 3*i;  I[0] = Mf[0]+0.5; I[1] = Mf[1]+Eoff[1]+0.5;
8764                                                          AFF44_MULT_I(X, Aff,I);
8765    NodeList[i3++] = X[0]; NodeList[i3++] = X[1]; NodeList[i3++] = X[2];
8766 
8767    i = 8; i3 = 3*i;  I[0] = Mf[0]+Eoff[0]+0.5; I[1] = Mf[1]+0.5;
8768                                                          AFF44_MULT_I(X, Aff,I);
8769    NodeList[i3++] = X[0]; NodeList[i3++] = X[1]; NodeList[i3++] = X[2];
8770 
8771    i = 9; i3 = 3*i;  I[0] = Mf[0]+Eoff[0]+0.5; I[1] = -0.5;
8772                                                          AFF44_MULT_I(X, Aff,I);
8773    NodeList[i3++] = X[0]; NodeList[i3++] = X[1]; NodeList[i3++] = X[2];
8774 
8775    i = 10; i3 = 3*i;  I[0] = Mf[0]+0.5; I[1] = -Eoff[1]-0.5;
8776                                                          AFF44_MULT_I(X, Aff,I);
8777    NodeList[i3++] = X[0]; NodeList[i3++] = X[1]; NodeList[i3++] = X[2];
8778 
8779    i = 11; i3 = 3*i;  I[0] = -0.5; I[1] = -Eoff[1]-0.5;
8780                                                          AFF44_MULT_I(X, Aff,I);
8781    NodeList[i3++] = X[0]; NodeList[i3++] = X[1]; NodeList[i3++] = X[2];
8782 
8783    /* form the triangles */
8784    i = 0; i3 = 3*i;
8785    FaceSetList[i3++] = 0; FaceSetList[i3++] = 1; FaceSetList[i3++] = 2;
8786 
8787    i = 1; i3 = 3*i;
8788    FaceSetList[i3++] = 0; FaceSetList[i3++] = 2; FaceSetList[i3++] = 3;
8789 
8790    i = 2; i3 = 3*i;
8791    FaceSetList[i3++] = 4; FaceSetList[i3++] = 5; FaceSetList[i3++] = 1;
8792 
8793    i = 3; i3 = 3*i;
8794    FaceSetList[i3++] = 4; FaceSetList[i3++] = 1; FaceSetList[i3++] = 0;
8795 
8796    i = 4; i3 = 3*i;
8797    FaceSetList[i3++] = 6; FaceSetList[i3++] = 7; FaceSetList[i3++] = 2;
8798 
8799    i = 5; i3 = 3*i;
8800    FaceSetList[i3++] = 6; FaceSetList[i3++] = 2; FaceSetList[i3++] = 1;
8801 
8802    i = 6; i3 = 3*i;
8803    FaceSetList[i3++] = 8; FaceSetList[i3++] = 9; FaceSetList[i3++] = 3;
8804 
8805    i = 7; i3 = 3*i;
8806    FaceSetList[i3++] = 8; FaceSetList[i3++] = 3; FaceSetList[i3++] = 2;
8807 
8808    i = 8; i3 = 3*i;
8809    FaceSetList[i3++] = 10; FaceSetList[i3++] = 11; FaceSetList[i3++] = 0;
8810 
8811    i = 9; i3 = 3*i;
8812    FaceSetList[i3++] = 10; FaceSetList[i3++] = 0; FaceSetList[i3++] = 3;
8813 
8814    nsoopt = SUMA_NewNewSOOpt();
8815    SO = SUMA_NewSO( &NodeList, N_Node, &FaceSetList, N_FaceSet, nsoopt );
8816    nsoopt = SUMA_FreeNewSOOpt(nsoopt);
8817 
8818    if (LocalHead) {
8819       char *ss = SUMA_SurfaceObject_Info(SO, NULL);
8820       fprintf(SUMA_STDERR,"La Surface\n%s\n", ss);
8821       SUMA_ifree(ss);
8822    }
8823 
8824    SUMA_RETURN(SO);
8825 }
8826 
SUMA_DrawGraphDO_GRELIEF(SUMA_GraphLinkDO * gldo,SUMA_SurfaceViewer * sv)8827 SUMA_Boolean SUMA_DrawGraphDO_GRELIEF (SUMA_GraphLinkDO *gldo,
8828                                        SUMA_SurfaceViewer *sv)
8829 {
8830    static char FuncName[]={"SUMA_DrawGraphDO_GRELIEF"};
8831    SUMA_ENTRY;
8832 
8833    SUMA_S_Err("Fill me up");
8834 
8835    SUMA_RETURN(YUP);
8836 }
8837 
8838 /* Fillup the Updates list to recreate everything */
SUMA_DrawDO_UL_FullMonty(DList * dl)8839 SUMA_Boolean SUMA_DrawDO_UL_FullMonty(DList *dl)
8840 {
8841    static char FuncName[]={"SUMA_DrawDO_UL_FullMonty"};
8842    char *eldata=NULL;
8843    DListElmt *el = NULL;
8844    SUMA_ENTRY;
8845    if (!dl) {
8846       SUMA_S_Err("NULL input");
8847       SUMA_RETURN(NOPE);
8848    }
8849    if (dlist_size(dl)) {
8850       SUMA_S_Warn("Update List not empty, emptying it now");
8851       SUMA_DrawDO_UL_EmptyList(dl, NULL);
8852    }
8853    dlist_ins_next(dl, dlist_tail(dl), SUMA_copy_string("SDO_NodeList"));
8854    dlist_ins_next(dl, dlist_tail(dl), SUMA_copy_string("SDO_MapColors"));
8855    dlist_ins_next(dl, dlist_tail(dl), SUMA_copy_string("SDO_SetStippling"));
8856 
8857    dlist_ins_next(dl, dlist_tail(dl), SUMA_copy_string("nido_MapColors"));
8858 
8859    SUMA_RETURN(YUP);
8860 }
8861 
8862 
8863 /* Add an update */
SUMA_ADO_UL_Add(SUMA_ALL_DO * ado,char * com,int replace)8864 SUMA_Boolean SUMA_ADO_UL_Add(SUMA_ALL_DO *ado, char *com, int replace)
8865 {
8866    static char FuncName[]={"SUMA_ADO_UL_Add"};
8867    SUMA_GRAPH_SAUX *GSaux = NULL;
8868 
8869    SUMA_ENTRY;
8870 
8871    if (!(GSaux = SUMA_ADO_GSaux(ado))) SUMA_RETURN(NOPE);
8872 
8873    SUMA_RETURN(SUMA_DrawDO_UL_Add(GSaux->DisplayUpdates, com, replace));
8874 }
8875 
SUMA_DrawDO_UL_Add(DList * dl,char * com,int replace)8876 SUMA_Boolean SUMA_DrawDO_UL_Add(DList *dl, char *com, int replace)
8877 {
8878    static char FuncName[]={"SUMA_DrawDO_UL_Add"};
8879    void *eldata=NULL;
8880    DListElmt *el = NULL;
8881 
8882    SUMA_ENTRY;
8883 
8884    if (!dl || !com || com[0]=='\0') {
8885       SUMA_S_Err("NULL input");
8886       SUMA_RETURN(NOPE);
8887    }
8888 
8889    if (replace) {
8890       if ((el = SUMA_DrawDO_UL_Find(dl, com))) {
8891          dlist_remove(dl, el, (void **)&eldata);
8892          SUMA_Free_Saux_DisplayUpdates_datum(eldata);
8893       }
8894    }
8895    dlist_ins_next(dl, dlist_tail(dl), SUMA_copy_string(com));
8896    SUMA_RETURN(YUP);
8897 }
8898 
8899 
SUMA_DrawDO_UL_Find(DList * dl,char * com)8900 DListElmt *SUMA_DrawDO_UL_Find(DList *dl, char *com)
8901 {
8902    static char FuncName[]={"SUMA_DrawDO_UL_Find"};
8903    char *eldata=NULL;
8904    DListElmt *el = NULL, *eli=NULL;
8905 
8906    SUMA_ENTRY;
8907 
8908    if (!dl || !dlist_size(dl) || !com) {
8909       SUMA_RETURN(el);
8910    }
8911 
8912    el = eli = NULL;
8913    do {
8914       if (!eli) eli = dlist_head(dl);
8915       else eli = dlist_next(eli);
8916       if (!strcmp(com, (char *)(eli->data))) el = eli;
8917    } while (!el && eli != dlist_tail(dl));
8918 
8919    SUMA_RETURN(el);
8920 }
8921 
8922 /* empty updates element del, or the whole list if del=NULL*/
SUMA_DrawDO_UL_EmptyList(DList * dl,DListElmt * del)8923 SUMA_Boolean SUMA_DrawDO_UL_EmptyList(DList *dl, DListElmt *del)
8924 {
8925    static char FuncName[]={"SUMA_DrawDO_UL_EmptyList"};
8926    void *eldata=NULL;
8927    DListElmt *el = NULL;
8928 
8929    SUMA_ENTRY;
8930    if (!dl) {
8931       SUMA_S_Err("NULL input");
8932       SUMA_RETURN(NOPE);
8933    }
8934    if (!dlist_size(dl)) SUMA_RETURN(YUP);
8935    if (del) {
8936       dlist_remove(dl, del, &eldata);
8937       SUMA_Free_Saux_DisplayUpdates_datum(eldata);
8938    } else {
8939       while((el = dlist_head(dl))) {
8940          dlist_remove(dl, el, &eldata);
8941          SUMA_Free_Saux_DisplayUpdates_datum(eldata);
8942       }
8943    }
8944    SUMA_RETURN(YUP);
8945 }
8946 
8947 #define USE_SER 0
SUMA_DrawGraphDO_G3D(SUMA_GraphLinkDO * gldo,SUMA_SurfaceViewer * sv)8948 SUMA_Boolean SUMA_DrawGraphDO_G3D (SUMA_GraphLinkDO *gldo,
8949                                    SUMA_SurfaceViewer *sv)
8950 {
8951    static char FuncName[]={"SUMA_DrawGraphDO_G3D"};
8952    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
8953    int iseg, N_seg, usedel=0;
8954    DListElmt *el=NULL, *eln=NULL;
8955    float origwidth=0.0;
8956    GLboolean gl_sm=FALSE;
8957    char Label[64]={""};
8958    SUMA_Boolean ans = YUP;
8959    SUMA_ALL_DO *ado = (SUMA_ALL_DO *)gldo;
8960    SUMA_DSET *dset=NULL;
8961    SUMA_GRAPH_SAUX *GSaux = NULL;
8962    SUMA_Boolean LocalHead = NOPE;
8963 
8964    SUMA_ENTRY;
8965 
8966    if (!gldo || !(dset=SUMA_find_GLDO_Dset(gldo)) || !sv
8967          || !SUMA_isGraphDset(dset) || !(GSaux=SDSET_GSAUX(dset))) {
8968       fprintf(stderr,"Error %s: NULL or bad pointers.\n", FuncName);
8969       SUMA_RETURN (NOPE);
8970    }
8971 
8972    if (sv->DO_PickMode) {
8973       SUMA_LH("In picking mode!");
8974    }
8975 
8976 
8977    #if USE_SER
8978    SUMA_RecordEnablingState(&(sv->SER)); /* Lazy, consider SUMA_GLStateTrack ,
8979                                          Also, why record it if it is already
8980                                          well preserved. */
8981    #endif
8982 
8983    glGetFloatv(GL_LINE_WIDTH, &origwidth);
8984    /* Form segment DO*/
8985    snprintf(Label, 63*sizeof(char), "Edges_%s_G3D", SDSET_LABEL(dset));
8986    if (!GSaux->SDO) {
8987       if (!(GSaux->SDO = SUMA_Alloc_SegmentDO(SDSET_VECLEN(dset), Label, 1,
8988                                  SUMA_ADO_idcode(ado), 2,
8989                                  NBOLS_type, ado->do_type,
8990                                  SUMA_ADO_variant(ado)))) {
8991          SUMA_S_Errv("Failed to allocate for GSaux->SDO %s (%d)\n",
8992                      Label, SDSET_VECLEN(dset));
8993          goto BUGOUT;
8994       }
8995    }
8996    /* fill in all the parameters per the controller settings */
8997    GSaux->SDO->Stipple = SUMA_SOLID_LINE;
8998    GSaux->SDO->LineWidth = 3;
8999    GSaux->SDO->LineCol[0] = 0.4; GSaux->SDO->LineCol[1] = 0.8;
9000            GSaux->SDO->LineCol[2] = 0.1; GSaux->SDO->LineCol[3] = 1.0;
9001 
9002    if (dlist_size(GSaux->DisplayUpdates)) {/* GSaux->SDO needs updating */
9003       el = dlist_head(GSaux->DisplayUpdates);
9004       do {
9005          usedel = 1; /* assume will consumate this element */
9006                 if (!strcmp((char *)el->data,"SDO_NodeList")) {
9007                SUMA_GDSET_NodeList(dset, NULL, 1, NULL, SUMA_ADO_variant(ado));
9008          } else if (!strcmp((char *)el->data,"SDO_MapColors")) {
9009             SUMA_LH("Here is where you decide what needs coloring, \n"
9010                          "showing, etc. etc. For now we show all.\n");
9011             N_seg = SDSET_VECLEN(dset);
9012             if (!GSaux->SDO->NodeID)
9013                GSaux->SDO->NodeID = (int *)SUMA_calloc(N_seg, sizeof(int));
9014             if (!GSaux->SDO->NodeID1)
9015                GSaux->SDO->NodeID1 = (int *)SUMA_calloc(N_seg, sizeof(int));
9016             if (!GSaux->SDO->NodeID || !GSaux->SDO->NodeID1) {
9017                SUMA_S_Errv("Failed to allocate for %d segment indices\n",
9018                            N_seg);
9019                goto BUGOUT;
9020             }
9021             /* Fillup node segments */
9022             for(iseg=0; iseg<N_seg; ++iseg) {
9023                if (!SUMA_GDSET_SegRowToPoints(dset, iseg,
9024                                                 GSaux->SDO->NodeID+iseg,
9025                                                 GSaux->SDO->NodeID1+iseg,
9026                                                 NULL)){
9027                   SUMA_S_Errv("Failed for edge %d\n", iseg);
9028                }
9029                #if 0
9030                SUMA_LHv("Edge row %d: %d %d\n",
9031                         iseg, GSaux->SDO->NodeID[iseg],
9032                               GSaux->SDO->NodeID1[iseg]);
9033                #endif
9034             }
9035             /* Colors? */
9036             GSaux->SDO->colv = SUMA_GetColorList(sv, SDSET_ID(dset));
9037             /* thickness? */
9038             GSaux->SDO->thickv = NULL;
9039             /* number of points making up segments*/
9040             SUMA_Set_N_SegNodes_SegmentDO(GSaux->SDO, GDSET_N_SEG_POINTS(dset));
9041             SUMA_Set_N_AllNodes_SegmentDO(GSaux->SDO, GDSET_N_ALL_POINTS(dset));
9042          } else if (!strcmp((char *)el->data,"SDO_SetStippling")) {
9043             SUMA_LH("stippling set");
9044          }else {
9045             usedel = 0;
9046             /* this may not need to be an error condition, you might just skip
9047             this update if it is irrelevant ?*/
9048             SUMA_LHv("DisplayUpdates command %s not relevant here\n",
9049                         (char *)el->data);
9050          }
9051 
9052          if (el != dlist_tail(GSaux->DisplayUpdates)) eln = dlist_next(el);
9053          else eln = NULL;
9054          if (usedel) {
9055             /* delete used element */
9056             SUMA_DrawDO_UL_EmptyList(GSaux->DisplayUpdates, el);
9057             el = NULL;
9058          }
9059          el = eln;
9060       } while (el);
9061    }
9062 
9063    /* colv is just a pointer copy for segment DOs of graph
9064    links. You must always fetch them because they can
9065    be deleted and recreated as you change states.
9066    It would be best to create a new class of segment DOs that
9067    are just for graph links and never store colv inside SDO.
9068    See SUMA_free_SegmentDO for special treatment of colv */
9069    GSaux->SDO->colv = SUMA_GetColorList(sv, SDSET_ID(dset));
9070    SUMA_LH("Colv for %s is %p", ADO_LABEL(ado), GSaux->SDO->colv);
9071    /* and draw the GSaux */
9072    if (!SUMA_DrawGSegmentDO(GSaux, sv)) {
9073       SUMA_S_Err("Failed to draw Segment DO!");
9074       goto BUGOUT;
9075    }
9076 
9077    goto GETOUT;
9078 
9079    BUGOUT:
9080    ans = NOPE;
9081 
9082    GETOUT:
9083 
9084 #if USE_SER
9085    /* Use in concert with SUMA_RecordEnablingState above */
9086    SUMA_RestoreEnablingState(&(sv->SER));
9087 #else
9088    glMaterialfv(GL_FRONT, GL_EMISSION, NoColor); /*turn off emissivity */
9089    glLineWidth(origwidth);
9090 #endif
9091 
9092    SUMA_RETURN(ans);
9093 }
9094 
9095 
9096 /*!
9097    Be careful not to access more than do_type in ado before
9098    you verify that the pointer is indeed for a DO */
SUMA_Load_Dumb_DO(SUMA_ALL_DO * ado,SUMA_DUMB_DO * DDO)9099 SUMA_Boolean SUMA_Load_Dumb_DO(SUMA_ALL_DO *ado, SUMA_DUMB_DO *DDO)
9100 {
9101    static char FuncName[]={"SUMA_Load_Dumb_DO"};
9102 
9103    SUMA_ENTRY;
9104 
9105    if (!ado || !DDO) SUMA_RETURN(NOPE);
9106 
9107    memset(DDO,0,sizeof(SUMA_DUMB_DO));
9108    DDO->err = 2; /* = not filled properly */
9109 
9110    switch (ado->do_type) {
9111       case SO_type: {
9112          SUMA_SurfaceObject *SO=(SUMA_SurfaceObject *)ado;
9113          DDO->idcode_str = SO->idcode_str;
9114          DDO->NodeList = SO->NodeList;
9115          DDO->N_Node = SO->N_Node;
9116          DDO->NodeIndex = NULL;
9117          if (SO->EL) DDO->AvgLe = SO->EL->AvgLe;
9118 
9119          DDO->err = 0;
9120          break; }
9121       case GDSET_type: {
9122          SUMA_S_Err("Bad idea, no nodelist possible without variant");
9123          break; }
9124       case GRAPH_LINK_type:{
9125          DDO->idcode_str = SUMA_ADO_idcode(ado);
9126          DDO->NodeList = SUMA_GDSET_NodeList(
9127                               SUMA_find_GLDO_Dset((SUMA_GraphLinkDO *)ado),
9128                               &(DDO->N_Node), 0, &(DDO->NodeIndex),
9129                               SUMA_ADO_variant(ado));
9130          DDO->AvgLe = 4;
9131          DDO->err = 0;
9132          break; }
9133       case CDOM_type: {
9134          DDO->idcode_str = SUMA_ADO_idcode(ado);
9135          DDO->NodeList = SUMA_CDOM_NodeList(
9136                               (SUMA_CIFTI_DO*)ado,
9137                               &(DDO->N_Node), 0, &(DDO->NodeIndex));
9138          DDO->AvgLe = 4;
9139          DDO->err = 0;
9140          break; }
9141       default:
9142          SUMA_S_Errv("Not used to filling type %d\n", ado->do_type);
9143          SUMA_RETURN(!DDO->err);
9144 
9145    }
9146 
9147    SUMA_RETURN(!DDO->err);
9148 }
9149 
SUMA_Free_Saux_DisplayUpdates_datum(void * ddd)9150 void SUMA_Free_Saux_DisplayUpdates_datum(void *ddd)
9151 {
9152    char *upd = (char *)ddd;
9153 
9154    SUMA_ifree(ddd);
9155 
9156    return;
9157 }
9158 
SUMA_AddDsetSaux(SUMA_DSET * dset)9159 SUMA_Boolean SUMA_AddDsetSaux(SUMA_DSET *dset)
9160 {
9161    static char FuncName[]={"SUMA_AddDsetSaux"};
9162 
9163    SUMA_ENTRY;
9164 
9165    if (!dset || !dset->Aux) {
9166       SUMA_S_Err("NULL input");
9167       SUMA_RETURN(NOPE);
9168    }
9169 
9170    if (SUMA_isGraphDset(dset)) {
9171       SUMA_GRAPH_SAUX *GSaux;
9172       if (dset->Aux->Saux) {
9173          GSaux = (SUMA_GRAPH_SAUX *)dset->Aux->Saux;
9174          /* empty old updates list */
9175          SUMA_DrawDO_UL_EmptyList(GSaux->DisplayUpdates, NULL);
9176 
9177          if (GSaux->SDO) {/* Free segment DO */
9178             /* remove this object from the colid list */
9179             SUMA_Remove_From_Pick_Colid_list(NULL,GSaux->SDO->idcode_str);
9180             SUMA_free_SegmentDO(GSaux->SDO); GSaux->SDO = NULL;
9181          }
9182 
9183          if (GSaux->nido) {/* Free segment DO */
9184             GSaux->nido = SUMA_free_NIDO(GSaux->nido);
9185          }
9186          if (GSaux->Overlay) {
9187             SUMA_S_Warn("Have overlay already, will remove it. Revisit later.");
9188             SUMA_FreeOverlayPointer(GSaux->Overlay);
9189             GSaux->Overlay = NULL;
9190          }
9191 
9192          if (GSaux->net) GSaux->net = NULL; /* pointer copy, do not free */
9193          if (GSaux->thd) SUMA_DestroyNgrHashDatum(GSaux->thd); GSaux->thd = NULL;
9194 
9195          if (GSaux->DOCont) {
9196             SUMA_S_Warn("Have controller already. Keep it.");
9197          } else {
9198             GSaux->DOCont = SUMA_CreateSurfContStruct(SDSET_ID(dset),
9199                                                       GRAPH_LINK_type);
9200          }
9201          SUMA_ifree(GSaux->Center_G3D);
9202          SUMA_ifree(GSaux->Range_G3D);
9203          SUMA_ifree(GSaux->Center_GMATRIX);
9204          SUMA_ifree(GSaux->Range_GMATRIX);
9205       } else {
9206          dset->Aux->FreeSaux = SUMA_Free_GSaux;
9207          dset->Aux->Saux = (void *)SUMA_calloc(1,sizeof(SUMA_GRAPH_SAUX));
9208          GSaux = (SUMA_GRAPH_SAUX *)dset->Aux->Saux;
9209 
9210          GSaux->DisplayUpdates = (DList *)SUMA_malloc(sizeof(DList));
9211          dlist_init(GSaux->DisplayUpdates, SUMA_Free_Saux_DisplayUpdates_datum);
9212 
9213          GSaux->SDO = NULL;
9214          GSaux->nido = NULL;
9215          GSaux->Overlay = NULL;
9216          GSaux->DOCont = SUMA_CreateSurfContStruct(SDSET_ID(dset),
9217                                                    GRAPH_LINK_type);
9218          GSaux->PR = SUMA_New_Pick_Result(NULL);
9219          GSaux->thd = NULL;
9220          GSaux->net = NULL;
9221          GSaux->ShowBundles = 0;
9222          GSaux->ShowUncon = 0;
9223 
9224          GSaux->Center_G3D = NULL;
9225          GSaux->Range_G3D = NULL;
9226          GSaux->Center_GMATRIX = NULL;
9227          GSaux->Range_GMATRIX = NULL;
9228          GSaux->IgnoreSelection = 0;
9229       }
9230 
9231       SUMA_DrawDO_UL_FullMonty(GSaux->DisplayUpdates);
9232    }
9233 
9234 
9235    SUMA_RETURN(YUP);
9236 }
9237 
9238 /* This function will need to be maintained should we end up
9239 sticking with CIFTI_DO as a full fledged DO, rather than
9240 a DO made up of a bunch of elementary DOs much like the
9241 CIFTI dataset. In the current incarnation, a CIFTI DO will
9242 not have its own controller for instance. */
SUMA_AddCIFTISaux(SUMA_CIFTI_DO * cdo)9243 SUMA_Boolean SUMA_AddCIFTISaux(SUMA_CIFTI_DO *cdo)
9244 {
9245    static char FuncName[]={"SUMA_AddCIFTISaux"};
9246    SUMA_CIFTI_SAUX *CSaux;
9247    int j;
9248    SUMA_Boolean LocalHead = NOPE;
9249 
9250    SUMA_ENTRY;
9251 
9252    if (!cdo) {
9253       SUMA_S_Err("NULL input");
9254       SUMA_RETURN(NOPE);
9255    }
9256 
9257    if (cdo->Saux) {
9258       CSaux = (SUMA_CIFTI_SAUX *)cdo->Saux;
9259       /* empty old updates list */
9260       SUMA_DrawDO_UL_EmptyList(CSaux->DisplayUpdates, NULL);
9261 
9262       if (CSaux->Overlays) {
9263          SUMA_S_Warn("Have overlay already, leaving them.");
9264       } else {
9265          CSaux->Overlays =
9266          (SUMA_OVERLAYS **)
9267             SUMA_malloc(sizeof(SUMA_OVERLAYS *) * SUMA_MAX_OVERLAYS);
9268          for (j=0; j < SUMA_MAX_OVERLAYS; ++j) {
9269             CSaux->Overlays[j] = NULL;
9270          }
9271          CSaux->N_Overlays = 0;
9272       }
9273 
9274       if (CSaux->DOCont) {
9275          SUMA_S_Warn("Have controller already. Keep it.");
9276       } else {
9277          CSaux->DOCont =
9278          SUMA_CreateSurfContStruct(SUMA_ADO_idcode((SUMA_ALL_DO *)cdo),
9279                                    CDOM_type);
9280       }
9281 
9282       if (!CSaux->PR) {
9283          CSaux->PR = SUMA_New_Pick_Result(NULL);
9284       }
9285       SUMA_ifree(CSaux->Center);
9286       SUMA_ifree(CSaux->Range);
9287    } else {
9288       cdo->FreeSaux = SUMA_Free_CSaux;
9289       cdo->Saux = (void *)SUMA_calloc(1,sizeof(SUMA_CIFTI_SAUX));
9290 
9291       CSaux = (SUMA_CIFTI_SAUX *)cdo->Saux;
9292       CSaux->DisplayUpdates = (DList *)SUMA_malloc(sizeof(DList));
9293       dlist_init(CSaux->DisplayUpdates, SUMA_Free_Saux_DisplayUpdates_datum);
9294 
9295       CSaux->Overlays =
9296          (SUMA_OVERLAYS **)
9297             SUMA_malloc(sizeof(SUMA_OVERLAYS *) * SUMA_MAX_OVERLAYS);
9298       for (j=0; j < SUMA_MAX_OVERLAYS; ++j) {
9299          CSaux->Overlays[j] = NULL;
9300       }
9301       CSaux->N_Overlays = 0;
9302       CSaux->DOCont =
9303          SUMA_CreateSurfContStruct(SUMA_ADO_idcode((SUMA_ALL_DO *)cdo),
9304                                    CDOM_type);
9305       CSaux->PR = SUMA_New_Pick_Result(NULL);
9306 
9307       SUMA_ifree(CSaux->Center);
9308       SUMA_ifree(CSaux->Range);
9309    }
9310 
9311    SUMA_LH("CSaux %p %p %p", CSaux->Overlays, CSaux->PR, CSaux->DOCont);
9312 
9313    /* Do we need this or its ilk for CIFTI? */
9314    SUMA_LH("Try without me...");
9315       SUMA_DrawDO_UL_FullMonty(CSaux->DisplayUpdates);
9316 
9317    SUMA_RETURN(YUP);
9318 }
9319 
SUMA_AddTractSaux(SUMA_TractDO * tdo)9320 SUMA_Boolean SUMA_AddTractSaux(SUMA_TractDO *tdo)
9321 {
9322    static char FuncName[]={"SUMA_AddTractSaux"};
9323    SUMA_TRACT_SAUX *TSaux;
9324    int j;
9325    SUMA_Boolean LocalHead = NOPE;
9326 
9327    SUMA_ENTRY;
9328 
9329    if (!tdo) {
9330       SUMA_S_Err("NULL input");
9331       SUMA_RETURN(NOPE);
9332    }
9333 
9334    if (tdo->Saux) {
9335       TSaux = (SUMA_TRACT_SAUX *)tdo->Saux;
9336       /* empty old updates list */
9337       SUMA_DrawDO_UL_EmptyList(TSaux->DisplayUpdates, NULL);
9338 
9339       if (TSaux->Overlays) {
9340          SUMA_S_Warn("Have overlay already, leaving them.");
9341       } else {
9342          SUMA_S_Note("Hmm, this should not be necessary."
9343                      "Check logic before approving. Also check"
9344                      "!DOCont and !PR in same block");
9345          TSaux->Overlays =
9346          (SUMA_OVERLAYS **)
9347             SUMA_malloc(sizeof(SUMA_OVERLAYS *) * SUMA_MAX_OVERLAYS);
9348          for (j=0; j < SUMA_MAX_OVERLAYS; ++j) {
9349             TSaux->Overlays[j] = NULL;
9350          }
9351          TSaux->N_Overlays = 0;
9352       }
9353 
9354       if (TSaux->DOCont) {
9355          SUMA_S_Warn("Have controller already. Keep it.");
9356       } else {
9357          TSaux->DOCont =
9358          SUMA_CreateSurfContStruct(SUMA_ADO_idcode((SUMA_ALL_DO *)tdo),
9359                                    TRACT_type);
9360       }
9361 
9362       if (!TSaux->PR) {
9363          TSaux->PR = SUMA_New_Pick_Result(NULL);
9364       }
9365       SUMA_ifree(TSaux->tract_lengths);
9366       SUMA_ifree(TSaux->Center);
9367       SUMA_ifree(TSaux->Range);
9368    } else {
9369       tdo->FreeSaux = SUMA_Free_TSaux;
9370       tdo->Saux = (void *)SUMA_calloc(1,sizeof(SUMA_TRACT_SAUX));
9371 
9372       TSaux = (SUMA_TRACT_SAUX *)tdo->Saux;
9373       TSaux->MaskGray = 20;
9374       TSaux->TractMask = SW_SurfCont_TractMaskHide;
9375       TSaux->DisplayUpdates = (DList *)SUMA_malloc(sizeof(DList));
9376       dlist_init(TSaux->DisplayUpdates, SUMA_Free_Saux_DisplayUpdates_datum);
9377 
9378       TSaux->Overlays =
9379          (SUMA_OVERLAYS **)
9380             SUMA_malloc(sizeof(SUMA_OVERLAYS *) * SUMA_MAX_OVERLAYS);
9381       for (j=0; j < SUMA_MAX_OVERLAYS; ++j) {
9382          TSaux->Overlays[j] = NULL;
9383       }
9384       TSaux->N_Overlays = 0;
9385       TSaux->DOCont =
9386          SUMA_CreateSurfContStruct(SUMA_ADO_idcode((SUMA_ALL_DO *)tdo),
9387                                    TRACT_type);
9388       TSaux->PR = SUMA_New_Pick_Result(NULL);
9389 
9390       SUMA_ifree(TSaux->Center);
9391       SUMA_ifree(TSaux->tract_lengths);
9392       SUMA_ifree(TSaux->Range);
9393    }
9394 
9395    SUMA_LH("TSaux %p %p %p", TSaux->Overlays, TSaux->PR, TSaux->DOCont);
9396 
9397    #if 0 /* not used for tracts */
9398       SUMA_DrawDO_UL_FullMonty(TSaux->DisplayUpdates);
9399    #endif
9400 
9401    SUMA_RETURN(YUP);
9402 }
9403 
9404 /* Return a tract's length, recompute all if necessary:
9405    tt is the tract number for which the length is to be returned.
9406    if tt == -1, then just make sure tract_lengths is not
9407                 null and return. If null, allocate and recompute
9408       tt == -2, free tract_lengths and recompute all
9409 
9410 */
SUMA_TDO_tract_length(SUMA_TractDO * tdo,int tt)9411 float SUMA_TDO_tract_length(SUMA_TractDO *tdo, int tt)
9412 {
9413    static char FuncName[]={"SUMA_TDO_tract_length"};
9414    SUMA_TRACT_SAUX *TSaux;
9415    float l;
9416    int doall = 0.0;
9417 
9418    SUMA_ENTRY;
9419 
9420    if (!tdo || !(TSaux = TDO_TSAUX(tdo))) {
9421       SUMA_S_Err("NULL input");
9422       SUMA_RETURN(-1.0);
9423    }
9424 
9425    doall = 0;
9426    if (tt < -1 && TSaux->tract_lengths) {
9427       /* Recompute for sure*/
9428       SUMA_ifree(TSaux->tract_lengths);
9429       doall = 1;
9430    }
9431    if (!TSaux->tract_lengths) {
9432       TSaux->tract_lengths = (float *)SUMA_calloc(TDO_N_TRACTS(tdo),
9433                                                    sizeof(float));
9434       doall = 1;
9435    }
9436 
9437    if (tt == -1 && !doall) SUMA_RETURN(0.0);
9438 
9439    if (doall) {
9440       int ib=0, it, TT = 0;
9441       if (!tdo->net) SUMA_RETURN(-1.0);
9442       for (ib=0; ib<tdo->net->N_tbv; ++ib) {
9443          if (tdo->net->tbv[ib]) {
9444             for (it=0; it<tdo->net->tbv[ib]->N_tracts; ++it) {
9445                TSaux->tract_lengths[TT++] =
9446                      Tract_Length(tdo->net->tbv[ib]->tracts+it);
9447             }
9448          }
9449       }
9450    }
9451 
9452    if (tt >= 0) {
9453       if (tt < TDO_N_TRACTS(tdo))
9454             SUMA_RETURN(TSaux->tract_lengths[tt]);
9455       else SUMA_RETURN(-2.0);
9456    } else  SUMA_RETURN(0.0);
9457 
9458 }
9459 
9460 
SUMA_AddMaskSaux(SUMA_MaskDO * mdo)9461 SUMA_Boolean SUMA_AddMaskSaux(SUMA_MaskDO *mdo)
9462 {
9463    static char FuncName[]={"SUMA_AddMaskSaux"};
9464    SUMA_MASK_SAUX *MSaux;
9465    int j;
9466    SUMA_Boolean LocalHead = NOPE;
9467    SUMA_ENTRY;
9468 
9469    if (!mdo) {
9470       SUMA_S_Err("NULL input");
9471       SUMA_RETURN(NOPE);
9472    }
9473 
9474    if (mdo->Saux) {
9475       MSaux = (SUMA_MASK_SAUX *)mdo->Saux;
9476       /* empty old updates list */
9477       SUMA_DrawDO_UL_EmptyList(MSaux->DisplayUpdates, NULL);
9478 
9479       if (MSaux->Overlays) {
9480          SUMA_S_Warn("Have overlay already, leaving them.");
9481       } else {
9482          SUMA_S_Note("Hmm, this should not be necessary."
9483                      "Check logic before approving. Also check"
9484                      "!DOCont and !PR in same block");
9485          MSaux->Overlays =
9486          (SUMA_OVERLAYS **)
9487             SUMA_malloc(sizeof(SUMA_OVERLAYS *) * SUMA_MAX_OVERLAYS);
9488          for (j=0; j < SUMA_MAX_OVERLAYS; ++j) {
9489             MSaux->Overlays[j] = NULL;
9490          }
9491          MSaux->N_Overlays = 0;
9492       }
9493 
9494       if (MSaux->DOCont) {
9495          SUMA_S_Warn("Have controller already. Keep it.");
9496       } else {
9497          MSaux->DOCont =
9498             SUMA_GlobalMaskContStruct(SUMA_ADO_idcode((SUMA_ALL_DO *)mdo));
9499       }
9500       if (!MSaux->PR) {
9501          MSaux->PR = SUMA_New_Pick_Result(NULL);
9502       }
9503    } else {
9504       mdo->FreeSaux = SUMA_Free_MSaux;
9505       mdo->Saux = (void *)SUMA_calloc(1,sizeof(SUMA_MASK_SAUX));
9506       MSaux = (SUMA_MASK_SAUX *)mdo->Saux;
9507 
9508       MSaux->DisplayUpdates = (DList *)SUMA_malloc(sizeof(DList));
9509       dlist_init(MSaux->DisplayUpdates, SUMA_Free_Saux_DisplayUpdates_datum);
9510 
9511       MSaux->Overlays =
9512          (SUMA_OVERLAYS **)
9513             SUMA_malloc(sizeof(SUMA_OVERLAYS *) * SUMA_MAX_OVERLAYS);
9514       for (j=0; j < SUMA_MAX_OVERLAYS; ++j) {
9515          MSaux->Overlays[j] = NULL;
9516       }
9517       MSaux->N_Overlays = 0;
9518       MSaux->DOCont =
9519             SUMA_GlobalMaskContStruct(SUMA_ADO_idcode((SUMA_ALL_DO *)mdo));
9520       MSaux->PR = SUMA_New_Pick_Result(NULL);
9521    }
9522 
9523    SUMA_LH("MSaux %p %p %p", MSaux->Overlays, MSaux->PR, MSaux->DOCont);
9524 
9525    #if 0 /* Not used for tracts */
9526    if (!MDO_IS_SHADOW(mdo))
9527       SUMA_DrawDO_UL_FullMonty(MSaux->DisplayUpdates);
9528    #endif
9529 
9530    SUMA_RETURN(YUP);
9531 }
9532 
SUMA_AddVolSaux(SUMA_VolumeObject * vo)9533 SUMA_Boolean SUMA_AddVolSaux(SUMA_VolumeObject *vo)
9534 {
9535    static char FuncName[]={"SUMA_AddVolSaux"};
9536    SUMA_VOL_SAUX *VSaux;
9537    int j;
9538    SUMA_Boolean LocalHead = NOPE;
9539 
9540    SUMA_ENTRY;
9541 
9542    if (!vo) {
9543       SUMA_S_Err("NULL input");
9544       SUMA_RETURN(NOPE);
9545    }
9546 
9547    if (vo->Saux) {
9548       SUMA_LH("Recycling");
9549       VSaux = (SUMA_VOL_SAUX *)vo->Saux;
9550       /* empty old updates list */
9551       SUMA_DrawDO_UL_EmptyList(VSaux->DisplayUpdates, NULL);
9552 
9553       if (VSaux->Overlays) {
9554          SUMA_S_Warn("Have overlay already, leaving them.");
9555       } else {
9556          VSaux->Overlays =
9557          (SUMA_OVERLAYS **)
9558             SUMA_malloc(sizeof(SUMA_OVERLAYS *) * SUMA_MAX_OVERLAYS);
9559          for (j=0; j < SUMA_MAX_OVERLAYS; ++j) {
9560             VSaux->Overlays[j] = NULL;
9561          }
9562          VSaux->N_Overlays = 0;
9563       }
9564 
9565       if (VSaux->DOCont) {
9566          SUMA_S_Warn("Have controller already. Keep it.");
9567       } else {
9568          VSaux->DOCont =
9569             SUMA_CreateSurfContStruct(SUMA_ADO_idcode((SUMA_ALL_DO *)vo),
9570                                       VO_type);
9571       }
9572 
9573       if (!VSaux->PR) {
9574          VSaux->PR = SUMA_New_Pick_Result(NULL);
9575       }
9576       if (!VSaux->PRc) {
9577          VSaux->PRc = SUMA_New_Pick_Result(NULL);
9578       }
9579 
9580       if (!VSaux->slcl) {
9581          dlist_init(VSaux->slcl, SUMA_Free_SliceListDatum);
9582       }
9583       if (!VSaux->vrslcl) {
9584          dlist_init(VSaux->vrslcl, SUMA_Free_SliceListDatum);
9585       }
9586       if (!VSaux->State) {
9587       	 VSaux->State = SUMA_copy_string("ANY_ANATOMICAL");
9588       }
9589    } else {
9590       SUMA_LH("Fresh");
9591       vo->FreeSaux = SUMA_Free_VSaux;
9592       vo->Saux = (void *)SUMA_calloc(1,sizeof(SUMA_VOL_SAUX));
9593       VSaux = (SUMA_VOL_SAUX *)vo->Saux;
9594 
9595       VSaux->DisplayUpdates = (DList *)SUMA_malloc(sizeof(DList));
9596       dlist_init(VSaux->DisplayUpdates, SUMA_Free_Saux_DisplayUpdates_datum);
9597 
9598       VSaux->slcl = (DList *)SUMA_malloc(sizeof(DList));
9599       dlist_init(VSaux->slcl, SUMA_Free_SliceListDatum);
9600 
9601       VSaux->vrslcl = (DList *)SUMA_malloc(sizeof(DList));
9602       dlist_init(VSaux->vrslcl, SUMA_Free_SliceListDatum);
9603 
9604       VSaux->State = SUMA_copy_string("ANY_ANATOMICAL");
9605 
9606       VSaux->Overlays =
9607          (SUMA_OVERLAYS **)
9608             SUMA_malloc(sizeof(SUMA_OVERLAYS *) * SUMA_MAX_OVERLAYS);
9609       for (j=0; j < SUMA_MAX_OVERLAYS; ++j) {
9610          VSaux->Overlays[j] = NULL;
9611       }
9612       VSaux->N_Overlays = 0;
9613       VSaux->DOCont =
9614          SUMA_CreateSurfContStruct(SUMA_ADO_idcode((SUMA_ALL_DO *)vo),
9615                                    VO_type);
9616       VSaux->PR = SUMA_New_Pick_Result(NULL);
9617       VSaux->PRc = SUMA_New_Pick_Result(NULL);
9618 
9619       VSaux->TransMode = SATM_ViewerDefault;
9620    }
9621 
9622    #if 0 /* not in use for Volumes yet */
9623    SUMA_DrawDO_UL_FullMonty(VSaux->DisplayUpdates);
9624    #endif
9625 
9626    SUMA_RETURN(YUP);
9627 }
9628 
SUMA_AddSurfSaux(SUMA_SurfaceObject * so)9629 SUMA_Boolean SUMA_AddSurfSaux(SUMA_SurfaceObject *so)
9630 {
9631    static char FuncName[]={"SUMA_AddSurfSaux"};
9632    SUMA_SURF_SAUX *SSaux;
9633    int j;
9634    SUMA_Boolean LocalHead = NOPE;
9635 
9636    SUMA_ENTRY;
9637 
9638    if (!so) {
9639       SUMA_S_Err("NULL input");
9640       SUMA_RETURN(NOPE);
9641    }
9642 
9643    if (so->Saux) {
9644       SUMA_LH("Recycling");
9645       SSaux = (SUMA_SURF_SAUX *)so->Saux;
9646       #if 0 /* Not in use yet */
9647       /* empty old updates list */
9648       SUMA_DrawDO_UL_EmptyList(SSaux->DisplayUpdates, NULL);
9649 
9650       if (SSaux->Overlays) {
9651          SUMA_S_Warn("Have overlay already, leaving them.");
9652       } else {
9653          SSaux->Overlays =
9654          (SUMA_OVERLAYS **)
9655             SUMA_malloc(sizeof(SUMA_OVERLAYS *) * SUMA_MAX_OVERLAYS);
9656          for (j=0; j < SUMA_MAX_OVERLAYS; ++j) {
9657             SSaux->Overlays[j] = NULL;
9658          }
9659          SSaux->N_Overlays = 0;
9660       }
9661 
9662       if (SSaux->DOCont) {
9663          SUMA_S_Warn("Have controller already. Keep it.");
9664       } else {
9665          SSaux->DOCont =
9666          SUMA_CreateSurfContStruct(SUMA_ADO_idcode((SUMA_ALL_DO *)so),
9667                                    SO_type);
9668       }
9669       #endif
9670       if (!SSaux->PR) {
9671          SSaux->PR = SUMA_New_Pick_Result(NULL);
9672       }
9673    } else {
9674       SUMA_LH("Fresh");
9675       so->FreeSaux = SUMA_Free_SSaux;
9676       so->Saux = (void *)SUMA_calloc(1,sizeof(SUMA_SURF_SAUX));
9677       SSaux = (SUMA_SURF_SAUX *)so->Saux;
9678       #if 0 /* Not in use yet */
9679       SSaux->DisplayUpdates = (DList *)SUMA_malloc(sizeof(DList));
9680       dlist_init(SSaux->DisplayUpdates, SUMA_Free_Saux_DisplayUpdates_datum);
9681 
9682       SSaux->Overlays =
9683          (SUMA_OVERLAYS **)
9684             SUMA_malloc(sizeof(SUMA_OVERLAYS *) * SUMA_MAX_OVERLAYS);
9685       for (j=0; j < SUMA_MAX_OVERLAYS; ++j) {
9686          SSaux->Overlays[j] = NULL;
9687       }
9688       SSaux->N_Overlays = 0;
9689       SSaux->DOCont =
9690          SUMA_CreateSurfContStruct(SUMA_ADO_idcode((SUMA_ALL_DO *)so),
9691                                    SO_type);
9692       #endif
9693       SSaux->PR = SUMA_New_Pick_Result(NULL);
9694    }
9695 
9696 
9697    #if 0
9698    SUMA_S_Note("SSaux %p %p %p", SSaux->Overlays, SSaux->PR, SSaux->DOCont);
9699    SUMA_DrawDO_UL_FullMonty(SSaux->DisplayUpdates);
9700    #endif
9701 
9702    SUMA_RETURN(YUP);
9703 }
9704 
SUMA_Free_SliceListDatum(void * data)9705 void SUMA_Free_SliceListDatum(void *data)
9706 {
9707    static char FuncName[]={"SUMA_Free_SliceListDatum"};
9708    SUMA_RENDERED_SLICE *rslc = (SUMA_RENDERED_SLICE *)data;
9709 
9710    SUMA_ENTRY;
9711 
9712    SUMA_ifree(rslc);
9713 
9714    SUMA_RETURNe;
9715 }
9716 
9717 /* destroy the hash table of the tract paths */
SUMA_DestroyNgrHashDatum(SUMA_NGR_INDEX_HASH_DATUM * thd)9718 SUMA_Boolean SUMA_DestroyNgrHashDatum(SUMA_NGR_INDEX_HASH_DATUM *thd)
9719 {
9720    static char FuncName[]={"SUMA_DestroyNgrHashDatum"};
9721    SUMA_NGR_INDEX_HASH_DATUM *hd=NULL;
9722 
9723    SUMA_ENTRY;
9724 
9725    if (!thd) SUMA_RETURN(YUP);
9726 
9727    /* destroy all of the hash table */
9728    while (thd) {
9729       hd = thd;  /* will delete the head of the hash table list */
9730       HASH_DEL( thd, hd); /* remove the head from the list, after
9731                                  this macro, thd points to the next
9732                                  item in the list; the new head */
9733       SUMA_free(hd); hd = NULL; /* free hd, no longer needed */
9734    }
9735 
9736    SUMA_RETURN(YUP);
9737 }
9738 
SUMA_Free_GSaux(void * vSaux)9739 void SUMA_Free_GSaux(void *vSaux)
9740 {
9741    static char FuncName[]={"SUMA_Free_GSaux"};
9742 
9743    SUMA_GRAPH_SAUX *Saux;
9744 
9745    if (!vSaux) return;
9746    Saux = (SUMA_GRAPH_SAUX *)vSaux;
9747 
9748    if (Saux->DisplayUpdates) {
9749       dlist_destroy(Saux->DisplayUpdates);
9750       SUMA_free(Saux->DisplayUpdates);
9751    }
9752    if (Saux->SDO) {
9753       SUMA_Remove_From_Pick_Colid_list(NULL,Saux->SDO->idcode_str);
9754       SUMA_free_SegmentDO(Saux->SDO); Saux->SDO = NULL;
9755    }
9756 
9757    if (Saux->FrameSO) SUMA_Free_Surface_Object(Saux->FrameSO);
9758    Saux->FrameSO = NULL;
9759    Saux->nido = SUMA_free_NIDO(Saux->nido);
9760 
9761    if (Saux->Overlay) {
9762       SUMA_FreeOverlayPointer(Saux->Overlay);
9763       Saux->Overlay = NULL;
9764    }
9765 
9766    SUMA_ifree(Saux->isColored);
9767 
9768    if (Saux->DOCont) SUMA_FreeSurfContStruct(Saux->DOCont);
9769    Saux->DOCont=NULL;
9770 
9771    if (Saux->PR) Saux->PR = SUMA_free_PickResult(Saux->PR);
9772 
9773    if (Saux->thd) SUMA_DestroyNgrHashDatum(Saux->thd); Saux->thd = NULL;
9774    if (Saux->net) Saux->net = NULL; /* never free this pointer copy */
9775 
9776    SUMA_ifree(Saux->Range_G3D);
9777    SUMA_ifree(Saux->Center_G3D);
9778    SUMA_ifree(Saux->Range_GMATRIX);
9779    SUMA_ifree(Saux->Center_GMATRIX);
9780 
9781    SUMA_ifree(Saux);
9782    return;
9783 }
9784 
SUMA_Free_TSaux(void * vSaux)9785 void SUMA_Free_TSaux(void *vSaux)
9786 {
9787    static char FuncName[]={"SUMA_Free_TSaux"};
9788    int i;
9789    SUMA_TRACT_SAUX *Saux;
9790 
9791    if (!vSaux) return;
9792    Saux = (SUMA_TRACT_SAUX *)vSaux;
9793 
9794    if (Saux->DisplayUpdates) {
9795       dlist_destroy(Saux->DisplayUpdates);
9796       SUMA_free(Saux->DisplayUpdates);
9797    }
9798 
9799    if (Saux->Overlays) {
9800       for (i=0; i<Saux->N_Overlays; ++i) {
9801          SUMA_FreeOverlayPointer(Saux->Overlays[i]);
9802       }
9803       SUMA_ifree(Saux->Overlays);
9804       Saux->N_Overlays = 0;
9805    }
9806 
9807    SUMA_ifree(Saux->isColored);
9808 
9809    if (Saux->DOCont) SUMA_FreeSurfContStruct(Saux->DOCont);
9810    Saux->DOCont=NULL;
9811 
9812    if (Saux->PR) Saux->PR = SUMA_free_PickResult(Saux->PR);
9813 
9814    SUMA_ifree(Saux->Center);
9815    SUMA_ifree(Saux->Range);
9816    SUMA_ifree(Saux->tract_lengths);
9817 
9818    SUMA_ifree(Saux);
9819    return;
9820 }
9821 
SUMA_Free_CSaux(void * vSaux)9822 void SUMA_Free_CSaux(void *vSaux)
9823 {
9824    static char FuncName[]={"SUMA_Free_CSaux"};
9825    int i;
9826    SUMA_CIFTI_SAUX *Saux;
9827 
9828    if (!vSaux) return;
9829    Saux = (SUMA_CIFTI_SAUX *)vSaux;
9830 
9831    if (Saux->DisplayUpdates) {
9832       dlist_destroy(Saux->DisplayUpdates);
9833       SUMA_free(Saux->DisplayUpdates);
9834    }
9835 
9836    if (Saux->Overlays) {
9837       for (i=0; i<Saux->N_Overlays; ++i) {
9838          SUMA_FreeOverlayPointer(Saux->Overlays[i]);
9839       }
9840       SUMA_ifree(Saux->Overlays);
9841       Saux->N_Overlays = 0;
9842    }
9843 
9844    SUMA_ifree(Saux->isColored);
9845 
9846    if (Saux->DOCont) SUMA_FreeSurfContStruct(Saux->DOCont);
9847    Saux->DOCont=NULL;
9848 
9849    if (Saux->PR) Saux->PR = SUMA_free_PickResult(Saux->PR);
9850 
9851    SUMA_ifree(Saux->Center);
9852    SUMA_ifree(Saux->Range);
9853 
9854    SUMA_ifree(Saux);
9855    return;
9856 }
9857 
SUMA_Free_MSaux(void * vSaux)9858 void SUMA_Free_MSaux(void *vSaux)
9859 {
9860    static char FuncName[]={"SUMA_Free_MSaux"};
9861    int i;
9862    SUMA_MASK_SAUX *Saux;
9863 
9864    if (!vSaux) return;
9865    Saux = (SUMA_MASK_SAUX *)vSaux;
9866 
9867    if (Saux->DisplayUpdates) {
9868       dlist_destroy(Saux->DisplayUpdates);
9869       SUMA_free(Saux->DisplayUpdates);
9870    }
9871 
9872    if (Saux->Overlays) {
9873       for (i=0; i<Saux->N_Overlays; ++i) {
9874          SUMA_FreeOverlayPointer(Saux->Overlays[i]);
9875       }
9876       SUMA_ifree(Saux->Overlays);
9877       Saux->N_Overlays = 0;
9878    }
9879 
9880    SUMA_ifree(Saux->isColored);
9881 
9882    if (Saux->DOCont) SUMA_FreeSurfContStruct(Saux->DOCont);
9883    Saux->DOCont=NULL;
9884 
9885    if (Saux->PR) Saux->PR = SUMA_free_PickResult(Saux->PR);
9886 
9887    SUMA_ifree(Saux);
9888    return;
9889 }
9890 
SUMA_Free_SSaux(void * sSaux)9891 void SUMA_Free_SSaux(void *sSaux)
9892 {
9893    static char FuncName[]={"SUMA_Free_SSaux"};
9894    int i;
9895    SUMA_SURF_SAUX *Saux;
9896 
9897    if (!sSaux) return;
9898    Saux = (SUMA_SURF_SAUX *)sSaux;
9899 
9900    #if 0 /* Not in use yet */
9901    if (Saux->DisplayUpdates) {
9902       dlist_destroy(Saux->DisplayUpdates);
9903       SUMA_free(Saux->DisplayUpdates);
9904    }
9905 
9906    if (Saux->Overlays) {
9907       for (i=0; i<Saux->N_Overlays; ++i) {
9908          SUMA_FreeOverlayPointer(Saux->Overlays[i]);
9909       }
9910       SUMA_ifree(Saux->Overlays);
9911       Saux->N_Overlays = 0;
9912    }
9913 
9914    SUMA_ifree(Saux->isColored);
9915 
9916    if (Saux->DOCont) SUMA_FreeSurfContStruct(Saux->DOCont);
9917    Saux->DOCont=NULL;
9918    #endif
9919 
9920    if (Saux->PR) Saux->PR = SUMA_free_PickResult(Saux->PR);
9921 
9922    SUMA_ifree(Saux);
9923    return;
9924 }
9925 
SUMA_Free_VSaux(void * vSaux)9926 void SUMA_Free_VSaux(void *vSaux)
9927 {
9928    static char FuncName[]={"SUMA_Free_VSaux"};
9929    int i;
9930    SUMA_VOL_SAUX *Saux;
9931 
9932    if (!vSaux) return;
9933    Saux = (SUMA_VOL_SAUX *)vSaux;
9934 
9935    if (Saux->DisplayUpdates) {
9936       dlist_destroy(Saux->DisplayUpdates);
9937       SUMA_free(Saux->DisplayUpdates);
9938    }
9939 
9940    if (Saux->slcl) {
9941       dlist_destroy(Saux->slcl);
9942       SUMA_free(Saux->slcl);
9943    }
9944 
9945    SUMA_ifree(Saux->State);
9946 
9947    if (Saux->vrslcl) {
9948       dlist_destroy(Saux->vrslcl);
9949       SUMA_free(Saux->vrslcl);
9950    }
9951 
9952    if (Saux->Overlays) {
9953       for (i=0; i<Saux->N_Overlays; ++i) {
9954          SUMA_FreeOverlayPointer(Saux->Overlays[i]);
9955       }
9956       SUMA_ifree(Saux->Overlays);
9957       Saux->N_Overlays = 0;
9958    }
9959 
9960    SUMA_ifree(Saux->isColored);
9961 
9962    if (Saux->DOCont) SUMA_FreeSurfContStruct(Saux->DOCont);
9963    Saux->DOCont=NULL;
9964 
9965    if (Saux->PR) Saux->PR = SUMA_free_PickResult(Saux->PR);
9966    if (Saux->PRc) Saux->PRc = SUMA_free_PickResult(Saux->PRc);
9967 
9968    SUMA_ifree(Saux);
9969    return;
9970 }
9971 
9972 /* From the indices of two nodes that form an edge,
9973 find the XYZ coordinates of the center of the regions
9974 where it would displayed in its frame surface
9975 \sa the function where picking is done on a GMATRIX
9976 and function that create FrameSO
9977 
9978 Caution, XYZ may contain as many as 9 XYZ triplets (27 floats)
9979 
9980 The function returns the number of triplets stored in XYZ
9981 -1 to flag an error
9982 
9983 For more coordinate translations see also:
9984 SUMA_WhatWasPicked_FrameSO(), SUMA_Surface_Of_NIDO_Matrix(), SUMA_GDSET_edgeij_to_GMATRIX_XYZ() and SUMA_DrawGraphDO_GMATRIX()
9985 */
SUMA_GDSET_edgeij_to_GMATRIX_XYZ(SUMA_DSET * dset,int ei,int ej,float * XYZ,int FourCorners)9986 int SUMA_GDSET_edgeij_to_GMATRIX_XYZ(SUMA_DSET *dset,
9987                                         int ei, int ej, float *XYZ,
9988                                         int FourCorners)
9989 {
9990    static char FuncName[]={"SUMA_GDSET_edgeij_to_GMATRIX_XYZ"};
9991    SUMA_GRAPH_SAUX *GSaux=NULL;
9992    double V[12], Aff[4][4];
9993    int iim, jjm, cc = 0, eemi, eemj, ee, *ui, *uj, N[3], G[3], B[3], GB[3], M[3];
9994    float I[3], Ic[3], xxx[3];
9995    SUMA_Boolean LocalHead = NOPE;
9996 
9997    SUMA_ENTRY;
9998 
9999    if (!dset || !XYZ || (ei < 0 && ej < 0)) SUMA_RETURN(-1);
10000 
10001    GSaux = SDSET_GSAUX(dset);
10002    if (!GSaux || !GSaux->FrameSO) {
10003       SUMA_RETURN(-1);
10004    }
10005 
10006    /* number of values in matrix */
10007    N[0] = SDSET_MATRIX_SZ0(dset); N[1] = SDSET_MATRIX_SZ1(dset);
10008 
10009    NI_GET_DOUBLEv(GSaux->nido->ngr, "ijk_to_dicom_real", V, 12, LocalHead);
10010    if (!NI_GOT) {
10011       SUMA_S_Err("No ijk_to_dicom_real");
10012       SUMA_RETURN(-1);
10013    }
10014    V12_TO_AFF44(Aff, V);
10015 
10016    /* total num of pixels per value */
10017    NI_GET_INTv(GSaux->nido->ngr, "PixPerVal", G, 3, LocalHead);
10018    if (!NI_GOT) {
10019       SUMA_S_Err("No PixPerVal!");
10020       SUMA_RETURN(-1);
10021    }
10022    NI_GET_INTv(GSaux->nido->ngr, "BorWid", B, 3, LocalHead);
10023    if (!NI_GOT) {
10024       SUMA_S_Err("No BorWid!");
10025       SUMA_RETURN(-1);
10026    }
10027    GB[0] = G[0]+B[0];
10028    GB[1] = G[1]+B[1];
10029 
10030    NI_GET_INTv(GSaux->nido->ngr, "PixCount", M, 3, LocalHead);
10031    if (!NI_GOT) {
10032       SUMA_S_Err("No PixCount!");
10033       SUMA_RETURN(-1);
10034    }
10035    ui = uj = NULL;
10036    switch (dset->Aux->matrix_shape) {
10037       case MAT_FULL:
10038       case MAT_TRI:
10039       case MAT_TRI_DIAG:
10040          SUMA_LH("Direct indexing between edge points and matrix row/col");
10041          break;
10042       case MAT_SPARSE:
10043          if (!dset->inel) {
10044             SUMA_S_Err("Don't have inel, badly shaped dataset");
10045             SUMA_RETURN(-1);
10046          }
10047          if (  !(ui = SUMA_GetUniqueIndicesVec(dset,1)) ||
10048                !(uj = SUMA_GetUniqueIndicesVec(dset,2))    ) {
10049             SUMA_S_Err("Failed to get unique indices");
10050             SUMA_RETURN(-1);
10051          }
10052          break;
10053       default:
10054          SUMA_S_Err("Rats");
10055          SUMA_RETURN(-1);
10056          break;
10057    }
10058 
10059    SUMA_LH("[ei,ej]=[%d %d]", ei, ej);
10060    if (ei >= 0 && ej >= 0) {
10061       if (!ui) {
10062          iim = ei; jjm = ej;
10063       } else {
10064          iim = SUMA_ibinFind(ui, N[0], ei);
10065          jjm = SUMA_ibinFind(uj, N[1], ej);
10066       }
10067       /* CENTROID pixel coord in displayed matrix of cell(iim, jjm) */
10068       Ic[0] = (int)((iim+0.5)*GB[0]);
10069       Ic[1] = (int)((jjm+0.5)*GB[1]);
10070       Ic[2] = 0.0;
10071       SUMA_LHv("Matrix indices %d %d to Display indices of %d %d \n"
10072                    "    to Pixels %f %f (GB %d %d) to XYZ:\n",
10073                    ei, ej, iim, jjm, Ic[0], Ic[1], GB[0], GB[1]);
10074 
10075       AFF44_MULT_I(XYZ, Aff,Ic); cc = 3;
10076 
10077       /* Now fill the coords of the 4 corners forming the square
10078          around the cell */
10079       if (FourCorners) {
10080          I[0] = Ic[0]-GB[0]/2.0; I[1] = Ic[1]-GB[1]/2.0; I[2] = 0.0;
10081             AFF44_MULT_I((XYZ+cc), Aff,I); cc += 3; /* A */
10082          I[0] = Ic[0]-GB[0]/2.0; I[1] = Ic[1]+GB[1]/2.0; I[2] = 0.0;
10083             AFF44_MULT_I((XYZ+cc), Aff,I); cc += 3; /* B */
10084          I[0] = Ic[0]+GB[0]/2.0; I[1] = Ic[1]+GB[1]/2.0; I[2] = 0.0;
10085             AFF44_MULT_I((XYZ+cc), Aff,I); cc += 3; /* C */
10086          I[0] = Ic[0]+GB[0]/2.0; I[1] = Ic[1]-GB[1]/2.0; I[2] = 0.0;
10087             AFF44_MULT_I((XYZ+cc), Aff,I); cc += 3; /* D */
10088       }
10089    } else {
10090       if (ei >= 0) ee = ei;
10091       else ee = ej;
10092 
10093       if (!ui) {
10094          eemi = ee; eemj = ee;
10095       } else {
10096          eemi = SUMA_ibinFind(ui, N[0], ee);
10097          eemj = SUMA_ibinFind(uj, N[1], ee);
10098       }
10099 
10100 
10101       cc = 0;/* Not sure what to do for a center location, leave blank */
10102       XYZ[0] = XYZ[1] = XYZ[2] = 0.0; /* all zeros means nothing was found */
10103       if (eemi >= 0) { /* exists as row, set its Y coordinate only */
10104          I[0] = (eemi+0.5)*GB[0]; I[1] = 0; I[2] = 0.0;
10105          AFF44_MULT_I(xxx, Aff,I); cc = 3;
10106          XYZ[0] = XYZ[2] = 0.0; XYZ[1] = xxx[1];
10107       }
10108       if (eemj >= 0) { /* exists as column, set its X coordinate only*/
10109          I[0] = 0; I[1] = (eemj+0.5)*GB[1]; I[2] = 0.0;
10110          AFF44_MULT_I(xxx, Aff,I); cc = 3;
10111          XYZ[0] = xxx[0]; XYZ[1] = XYZ[2] = 0.0;
10112       }
10113 
10114       /* Now fill the coords of the 4 corners forming the rectangle
10115          around the the whole row and the whole column whenever
10116          applicable*/
10117       if (FourCorners) {
10118          cc=3;
10119          if (eemi >=0) { /* Point exists as row */
10120             SUMA_LHv("Marking row %d for edge point %d\n", eemi, ee);
10121                            /* The + B[k]/2.0 offset is to make the
10122                            rectangle highlight sit over where the
10123                            user expects the boundary between cells
10124                            to be, and to match how the cell selection
10125                            square is drawn. In reality only the top and left
10126                            boundaries belong to a cell */
10127             I[0] = eemi*GB[0]-0.5 + B[0]/2.0; I[1] = -0.5 + B[1]/2.0;
10128                                                                   I[2] = 0.0;
10129                AFF44_MULT_I((XYZ+cc), Aff,I); cc += 3; /* A */
10130             I[0] = eemi*GB[0]-0.5 + B[0]/2.0; I[1] = M[1]-0.5 - B[1]/2.0;
10131                                                                   I[2] = 0.0;
10132                AFF44_MULT_I((XYZ+cc), Aff,I); cc += 3; /* B */
10133             I[0] = (eemi+1)*GB[0]-0.5+ B[0]/2.0; I[1] = M[1]-0.5 - B[1]/2.0;
10134                                                                   I[2] = 0.0;
10135                AFF44_MULT_I((XYZ+cc), Aff,I); cc += 3; /* C */
10136             I[0] = (eemi+1)*GB[0]-0.5+ B[0]/2.0; I[1] = -0.5 + B[1]/2.0;
10137                                                                   I[2] = 0.0;
10138                AFF44_MULT_I((XYZ+cc), Aff,I); cc += 3; /* D */
10139           }
10140           if (eemj >=0) { /* Point exists as column */
10141             SUMA_LHv("Marking col %d for edge point %d\n", eemj, ee);
10142              I[0] = -0.5 + B[1]/2.0; I[1] = (eemj)*GB[1]-0.5 + B[1]/2.0;
10143                                                                   I[2] = 0.0;
10144                AFF44_MULT_I((XYZ+cc), Aff,I); cc += 3; /* A */
10145              I[0] = -0.5 + B[1]/2.0; I[1] = (eemj+1)*GB[1]-0.5 + B[1]/2.0;
10146                                                                   I[2] = 0.0;
10147                AFF44_MULT_I((XYZ+cc), Aff,I); cc += 3; /* B */
10148              I[0] = M[0]-0.5 - B[1]/2.0; I[1] = (eemj+1)*GB[1]-0.5 + B[1]/2.0;
10149                                                                   I[2] = 0.0;
10150                AFF44_MULT_I((XYZ+cc), Aff,I); cc += 3; /* C */
10151              I[0] = M[0]-0.5 - B[1]/2.0; I[1] = (eemj)*GB[1]-0.5 + B[1]/2.0;
10152                                                                   I[2] = 0.0;
10153                AFF44_MULT_I((XYZ+cc), Aff,I); cc += 3; /* D */
10154           }
10155       }
10156 
10157    }
10158 
10159    SUMA_RETURN((cc/3)); /* Return the number of XYZ triplets filled */
10160 }
10161 
10162 /*
10163    Get the size of a matrix cell in screen pixels
10164 */
SUMA_GDSET_GMATRIX_CellPixSize(SUMA_DSET * dset,SUMA_SurfaceViewer * sv,float * Szc)10165 int SUMA_GDSET_GMATRIX_CellPixSize(SUMA_DSET *dset, SUMA_SurfaceViewer *sv,
10166                                    float *Szc)
10167 {
10168    static char FuncName[]={"SUMA_GDSET_GMATRIX_CellPixSize"};
10169    SUMA_GRAPH_SAUX *GSaux=NULL;
10170    float S[12], V[3],  Sz[3];
10171    int N[3];
10172    SUMA_Boolean LocalHead = NOPE;
10173 
10174    SUMA_ENTRY;
10175 
10176    /* Sz -> Szc   [22 Jun 2021 rickr] */
10177    if (!dset || !Szc || !sv) SUMA_RETURN(0);
10178 
10179    GSaux = SDSET_GSAUX(dset);
10180    if (!GSaux || !GSaux->FrameSO) {
10181       SUMA_RETURN(0);
10182    }
10183 
10184    /* number of values in matrix */
10185    N[0] = SDSET_MATRIX_SZ0(dset); N[1] = SDSET_MATRIX_SZ1(dset);
10186 
10187    /* Get the width of the square in which the matrix is displayed */
10188    V[0] = SUMA_ABS(  GSaux->FrameSO->NodeList[1*3+0] -
10189                      GSaux->FrameSO->NodeList[0*3+0] );
10190    /* Get the height of the square in which the matrix is displayed */
10191    V[1] = SUMA_ABS(  GSaux->FrameSO->NodeList[3*3+1] -
10192                      GSaux->FrameSO->NodeList[0*3+1] );
10193    /* And something for the Z */
10194    V[2] = GSaux->FrameSO->NodeList[0*3+2];
10195 
10196    /* Now go to pixels */
10197    if (!SUMA_World2ScreenCoordsF(sv, 4, GSaux->FrameSO->NodeList, S,
10198                                  NULL, YUP, YUP)) {
10199       SUMA_S_Err("Failed to project?");
10200    }
10201    Sz[0] = SUMA_ABS(S[1*3+0] - S[0*3+0]);
10202    Sz[1] = SUMA_ABS(S[3*3+1] - S[0*3+1]);
10203    Sz[2] = SUMA_ABS(S[0*3+2]);
10204 
10205    Szc[0] = Sz[0]/(float)N[1]; /* width, horizontal */
10206    Szc[1] = Sz[1]/(float)N[0]; /* height */
10207 
10208    SUMA_LHv("Width  of %f mm --> %f pixels, %f pixels/Cell, \n"
10209             "Height of %f mm --> %f pixels, %f pixels/Cell\n",
10210             V[0], Sz[0], Szc[0], V[1], Sz[1], Szc[1]);
10211 
10212    SUMA_RETURN(1);
10213 }
10214 
10215 /* Return a pointer copy of a graph dset's node coordinates,
10216    *ind is a copy of the node index pointer */
SUMA_GDSET_NodeList(SUMA_DSET * dset,int * N_Node,int recompute,int ** ind,char * this_variant)10217 float *SUMA_GDSET_NodeList(SUMA_DSET *dset, int *N_Node, int recompute,
10218                            int **ind, char *this_variant)
10219 {
10220    static char FuncName[]={"SUMA_GDSET_NodeList"};
10221    NI_element *nel=NULL, *nelxyz=NULL;
10222    float *NodeList=NULL, *X=NULL, *Y=NULL, *Z=NULL;
10223    int ii, ii3, iicoord;
10224     char *cs = NULL;
10225    SUMA_Boolean LocalHead = NOPE;
10226 
10227    SUMA_ENTRY;
10228 
10229    if (N_Node) *N_Node = -1;
10230    if (!this_variant || this_variant[0]=='\0') this_variant = "GMATRIX";
10231    if (!SUMA_IS_REAL_VARIANT(this_variant)) SUMA_RETURN(NULL);
10232 
10233    /* Check the drawing variant */
10234    if (!strcmp(this_variant,"G3D")) {
10235       if (!(nelxyz = SUMA_FindGDsetNodeListElement(dset))) {
10236          SUMA_S_Errv("Failed to find Dset %s's NodeListElement\n",
10237                            SDSET_LABEL(dset));
10238          SUMA_RETURN(NULL);
10239       }
10240       if (!(cs = NI_get_attribute(nelxyz,"COLMS_LABS"))) {
10241          SUMA_S_Err("What can I say?");
10242          SUMA_RETURN(NULL);
10243       }
10244       if (ind) {
10245          if ((iicoord=SUMA_NI_find_in_cs_string(cs, SUMA_NI_CSS,
10246                                                 "Gnode Index"))<0) {
10247             SUMA_LH("Failed to find I, assuming we have a full list");
10248          } else {
10249             *ind = (int *)nelxyz->vec[iicoord];
10250          }
10251       }
10252       if (!(nel = SUMA_FindNgrNamedElement(dset->ngr, "disp_NodeList"))) {
10253          SUMA_LHv("Need new disp_NodeList element, %d floats long\n",
10254                   nelxyz->vec_len);
10255          if (!(nel = NI_new_data_element("disp_NodeList",
10256                                           3*nelxyz->vec_len))) {
10257             SUMA_S_Err("Failed to create disp_NodeList");
10258             SUMA_RETURN(NULL);
10259          }
10260          NI_add_to_group(dset->ngr, nel);
10261          NI_add_column( nel, NI_FLOAT, NULL);
10262          recompute = 1;
10263       }
10264       if (N_Node) *N_Node = nelxyz->vec_len;
10265       if (recompute) {
10266          SUMA_LHv("Recomputing XYZ of %d nodes\n", nelxyz->vec_len);
10267 
10268          /* Fill the node list */
10269          NodeList = (float *)nel->vec[0];
10270 
10271          if ((iicoord=SUMA_NI_find_in_cs_string(cs, SUMA_NI_CSS, "Gnode X"))<0) {
10272             SUMA_S_Err("Failed to find X");
10273             SUMA_RETURN(NULL);
10274          }
10275          X = (float *)nelxyz->vec[iicoord];
10276          if ((iicoord=SUMA_NI_find_in_cs_string(cs, SUMA_NI_CSS, "Gnode Y"))<0){
10277             SUMA_S_Err("Failed to find Y");
10278             SUMA_RETURN(NULL);
10279          }
10280          Y = (float *)nelxyz->vec[iicoord];
10281          if ((iicoord=SUMA_NI_find_in_cs_string(cs, SUMA_NI_CSS, "Gnode Z"))<0){
10282             SUMA_S_Err("Failed to find Z");
10283             SUMA_RETURN(NULL);
10284          }
10285          Z = (float *)nelxyz->vec[iicoord];
10286          for (ii=0, ii3=0; ii< nelxyz->vec_len; ++ii) {
10287             NodeList[ii3++] = X[ii]; NodeList[ii3++] = Y[ii];
10288             NodeList[ii3++] = Z[ii];
10289          }
10290       } else {
10291          SUMA_LH("Reusing XYZ from disp_NodeList");
10292          NodeList = (float *)nel->vec[0];
10293       }
10294       SUMA_RETURN(NodeList);
10295    } else if (!strcmp(this_variant,"GMATRIX")) {
10296       SUMA_LH("Nothing to return for GMATRIX, potentially one could return"
10297               "the NodeList from the G3D version ...");
10298       if (ind) *ind=NULL;
10299       SUMA_RETURN(NodeList);
10300    } else if (!strcmp(this_variant,"GRELIEF")) {
10301       SUMA_S_Err("Not ready yet for GMATRIX");
10302       if (ind) *ind=NULL;
10303       SUMA_RETURN(NodeList);
10304    } else {
10305       SUMA_S_Errv("Bad draw variant >%s< for %s\n",
10306                   this_variant, SDSET_LABEL(dset));
10307       SUMA_DUMP_TRACE("Bad draw variant");
10308       if (ind) *ind=NULL;
10309       SUMA_RETURN(NULL);
10310    }
10311    SUMA_RETURN(NULL);
10312 }
10313 
10314 /* Return a pointer copy of a CIFTI dset's domain node coordinates,
10315    *ind is a copy of the node index pointer
10316 */
SUMA_CDOM_NodeList(SUMA_CIFTI_DO * CO,int * N_Node,int recompute,int ** ind)10317 float *SUMA_CDOM_NodeList(SUMA_CIFTI_DO *CO, int *N_Node, int recompute,
10318                            int **ind)
10319 {
10320    static char FuncName[]={"SUMA_CDOM_NodeList"};
10321    NI_element *nel=NULL, *nelxyz=NULL;
10322    float *NodeList=NULL, *X=NULL, *Y=NULL, *Z=NULL;
10323    int ii, ii3, iicoord;
10324     char *cs = NULL;
10325    SUMA_Boolean LocalHead = NOPE;
10326 
10327    SUMA_ENTRY;
10328 
10329    SUMA_S_Err("Not ready yet. Whos is calling? What would this be?");
10330    /* Now how should this be implemented? One vector for all?
10331       If so, then what for? Decide in context of application.
10332       Consider SUMA_GDSET_NodeList, */
10333 
10334 
10335    SUMA_RETURN(NULL);
10336 }
10337 
SUMA_free_colid_offset_datum(void * vv)10338 void SUMA_free_colid_offset_datum (void *vv)
10339 {
10340    SUMA_COLID_OFFSET_DATUM *cod = (SUMA_COLID_OFFSET_DATUM *)vv;
10341    if (cod) {
10342       SUMA_ifree(cod->Label);
10343       SUMA_ifree(cod->idcode_str);
10344       SUMA_ifree(cod->ref_idcode_str);
10345       SUMA_ifree(cod->variant);
10346       SUMA_ifree(cod->primitive);
10347       SUMA_free(cod);
10348    }
10349 }
10350 
10351 /*!
10352    Remove an entry from colid list. Usually you do this when a
10353    particular DO with entries here gets chopped.
10354 
10355    At some point you will need to deal with the problem of segmentation
10356    in the colid map as you repeatedly delete intermediate chunks.
10357 
10358    You could flush the whole thing with:
10359       dlist_destroy(csv->pick_colid_list); csv->pick_colid_list = NULL;
10360    and regenerate as needed a more solid  block, but for that you need to also
10361    wipe out the DOs for wich the colorids are being destroyed.
10362    Or simply, you need to mark those DOs as needing to be fully update/redrawn
10363    with new colids. Not a big deal...
10364 */
SUMA_Remove_From_Pick_Colid_list(SUMA_SurfaceViewer * svu,char * idcode_str)10365 SUMA_Boolean SUMA_Remove_From_Pick_Colid_list(SUMA_SurfaceViewer *svu,
10366                                               char *idcode_str)
10367 {
10368    static char FuncName[]={"SUMA_Remove_From_Pick_Colid_list"};
10369    SUMA_COLID_OFFSET_DATUM *cod=NULL;
10370    DListElmt *el=NULL, *eld=NULL;
10371    SUMA_SurfaceViewer *sv;
10372    int isv, isv0, isv1;
10373    SUMA_Boolean LocalHead = NOPE;
10374 
10375    SUMA_ENTRY;
10376 
10377    if (!svu) { isv0=0; isv1=SUMAg_N_SVv; }
10378    else { isv0 = SUMA_WhichSV(svu, SUMAg_SVv, SUMAg_N_SVv);  isv1 = isv0+1;}
10379 
10380    if (isv0 < 0) {
10381       SUMA_S_Err("Failed to identify sv");
10382       SUMA_RETURN(NOPE);
10383    }
10384 
10385    for (isv = isv0; isv < isv1; ++isv) {
10386       sv = &(SUMAg_SVv[isv]);
10387       if (!sv || !sv->pick_colid_list || !idcode_str
10388               || !dlist_size(sv->pick_colid_list) ) continue;
10389 
10390       do {
10391          if (!el) el = dlist_head(sv->pick_colid_list);
10392          else el = dlist_next(el);
10393          eld = NULL;
10394          if ((cod = (SUMA_COLID_OFFSET_DATUM *)el->data)) {
10395             if (!strcmp(cod->idcode_str, idcode_str)) {
10396                eld = el; /* mark for removal */
10397                /* backup el */
10398                if (el != dlist_head(sv->pick_colid_list)) el = dlist_prev(el);
10399                else el = NULL; /* nothing left */
10400                SUMA_LHv("Removing colid for %s, %s\n",
10401                         cod->Label, cod->primitive);
10402                dlist_remove(sv->pick_colid_list, eld, (void **)&cod); eld = NULL;
10403                SUMA_free_colid_offset_datum(cod); cod = NULL;
10404             }
10405          }
10406       } while (dlist_size(sv->pick_colid_list) &&
10407                el && el != dlist_tail(sv->pick_colid_list));
10408    }
10409 
10410    SUMA_RETURN(YUP);
10411 }
10412 
SUMA_Find_In_Pick_Colid_list(SUMA_SurfaceViewer * sv,char * idcode_str,char * primitive)10413 DListElmt * SUMA_Find_In_Pick_Colid_list(SUMA_SurfaceViewer *sv,
10414                                          char *idcode_str, char *primitive)
10415 {
10416    static char FuncName[]={"SUMA_Find_In_Pick_Colid_list"};
10417    DListElmt *el=NULL;
10418    SUMA_COLID_OFFSET_DATUM *cod;
10419    SUMA_Boolean LocalHead = NOPE;
10420 
10421    SUMA_ENTRY;
10422 
10423    if (!sv || !idcode_str || !primitive) { /* INSIST on all three
10424            otherwise you will have  partial matches, and returning
10425            just one can cause trouble in  calling functions */
10426       SUMA_S_Err("NULL input");
10427       SUMA_RETURN(NULL);
10428    }
10429 
10430    SUMA_LHv("Seeking %s and %s in pick_colid_list\n", idcode_str, primitive);
10431    if (!sv->pick_colid_list || !dlist_size(sv->pick_colid_list))
10432       SUMA_RETURN(NULL);
10433 
10434    do {
10435       if (!el) el = dlist_head(sv->pick_colid_list);
10436       else el = dlist_next(el);
10437       if ((cod = (SUMA_COLID_OFFSET_DATUM *)el->data)) {
10438          if (!strcmp(cod->idcode_str, idcode_str) &&
10439              !strcmp(cod->primitive, primitive)) {
10440             SUMA_RETURN(el);
10441          }
10442       }
10443    } while (el != dlist_tail(sv->pick_colid_list));
10444 
10445    SUMA_RETURN(NULL);
10446 }
10447 
10448 
10449 /* This function does not check for uniqueness of
10450    object for which new colid is requested.
10451    Not sure if that is necessary or not at the moment.
10452 */
SUMA_New_colid(SUMA_SurfaceViewer * sv,char * Label,char * idcode_str,char * primitive,char * variant,char * reference_idcode_str,SUMA_DO_Types ref_do_type,int N_n)10453 GLubyte *SUMA_New_colid(SUMA_SurfaceViewer *sv,
10454                 char *Label, char *idcode_str, char *primitive, char *variant,
10455                 char *reference_idcode_str, SUMA_DO_Types ref_do_type,
10456                 int N_n)
10457 {
10458    static char FuncName[]={"SUMA_New_colid"};
10459    GLubyte *colid=NULL;
10460    long int r, g, b, a, n4, n4l;
10461    SUMA_COLID_OFFSET_DATUM *cod, *codlt=NULL;
10462    DListElmt *elt=NULL;
10463    DListElmt *elf=NULL;
10464    int nwarn=0;
10465    SUMA_Boolean LocalHead = NOPE;
10466 
10467    SUMA_ENTRY;
10468 
10469    if (!sv || !Label || !reference_idcode_str || N_n <=0 || !primitive) {
10470       SUMA_S_Errv("Don't be lazy %p %p %p %d %p\n",
10471                   sv, Label, reference_idcode_str, N_n, primitive);
10472       SUMA_RETURN(colid);
10473    }
10474    if (!sv->pick_colid_list) {
10475       SUMA_S_Err("Pick_list is not initialized");
10476       SUMA_RETURN(colid);
10477    }
10478    if (!sv->DO_PickMode) { /* nothing to do if not in pick mode */
10479       SUMA_RETURN(NULL);
10480    }
10481 
10482    if (!(colid = (GLubyte *)SUMA_calloc(4*N_n,
10483                                        sizeof(GLubyte)))) {
10484       SUMA_S_Errv("Failed to allocate for 4x%d colid entries\n",N_n);
10485       SUMA_RETURN(NULL);
10486    }
10487 
10488    /* Do we have this thing in already ? */
10489    cod = NULL;
10490    if ((elf = SUMA_Find_In_Pick_Colid_list(sv, idcode_str, primitive))) {
10491       cod = (SUMA_COLID_OFFSET_DATUM *)elf->data;
10492 
10493       if (cod->i1-cod->i0+1 == N_n &&
10494           !strcmp(cod->ref_idcode_str, reference_idcode_str) &&
10495           cod->ref_do_type == ref_do_type) { /* keep the faith */
10496 
10497       } else { /* Remove from list and recreate below */
10498          dlist_remove(sv->pick_colid_list, elf, (void **)&(cod));
10499          SUMA_free_colid_offset_datum(cod); cod = NULL;
10500       }
10501    }
10502 
10503    if (!cod) { /* need new one */
10504       cod = (SUMA_COLID_OFFSET_DATUM *)SUMA_malloc(
10505                            sizeof(SUMA_COLID_OFFSET_DATUM));
10506       cod->Label = SUMA_copy_string(Label);
10507       cod->idcode_str = SUMA_copy_string(idcode_str);
10508       cod->primitive = SUMA_copy_string(primitive);
10509       cod->variant = SUMA_copy_string(variant);
10510       cod->ref_idcode_str = SUMA_copy_string(reference_idcode_str);
10511       cod->ref_do_type = ref_do_type;
10512       if (dlist_size(sv->pick_colid_list) &&
10513          (elt = dlist_tail(sv->pick_colid_list))) {
10514          codlt = (SUMA_COLID_OFFSET_DATUM *)(elt->data);
10515          cod->i0 = codlt->i1+1;
10516       } else {
10517          cod->i0 = 100;   /* reserve 0 0 0 0 (== 0) for background,
10518                             starting at 100 to help with debugging
10519                             start at 1 when comfortable with this */
10520       }
10521       cod->i1 = cod->i0+N_n-1;
10522       dlist_ins_next(sv->pick_colid_list, dlist_tail(sv->pick_colid_list), cod);
10523    }
10524 
10525 
10526    /* now fill colid, see Vox1D2Vox3D*/
10527    SUMA_COLID_N2RGBA(cod->i0,r,g,b,a);
10528    colid[0] = r; colid[1] = g; colid[2] = b; colid[3] = a;
10529    n4=4; n4l=4*(cod->i1-cod->i0+1);
10530    while (n4<n4l) {
10531       /* fprintf(stderr,"%ld/%d: ",n4/4,N_n); */
10532       if (r<255) {
10533          ++r;
10534       } else {
10535          r = 0;
10536          if (g < 255) {
10537             ++g;
10538          } else {
10539             g = 0;
10540             if (b<255) {
10541                ++b;
10542             } else {
10543                b=0;
10544                if (a < 255) {
10545                   ++a;
10546                } else {
10547                   if (!nwarn) {
10548                      SUMA_S_Err("Exceeding 32 bit color id. Clobbering");
10549                      ++nwarn;
10550                   }
10551                }
10552             }
10553          }
10554       }
10555       colid[n4++]=r;
10556       colid[n4++]=g;
10557       colid[n4++]=b;
10558       colid[n4++]=a;
10559       /* fprintf(stderr,"  %ld %ld %ld %ld\n", r, g, b, a); */
10560    }
10561    SUMA_RETURN(colid);
10562 }
10563 
10564 
10565 /*!
10566    Return a vector of picking colors for a certain DO
10567    The reference idcode string is important because
10568    although all DOs have an idcode string, some of them
10569    are not persistent and may not present when it comes
10570    to a selection choice. The reference_idcode_str would
10571    then be for a permanent object associated with DO
10572 */
SUMA_DO_get_pick_colid(SUMA_ALL_DO * DO,char * idcode_str,char * DO_primitive,char * DO_variant,char * ref_idcode_str,SUMA_DO_Types ref_do_type,SUMA_SurfaceViewer * sv)10573 GLubyte *SUMA_DO_get_pick_colid(SUMA_ALL_DO *DO, char *idcode_str,
10574                            char *DO_primitive, char *DO_variant,
10575                            char *ref_idcode_str,SUMA_DO_Types ref_do_type,
10576                                    SUMA_SurfaceViewer *sv)
10577 {
10578    static char FuncName[]={"SUMA_DO_get_pick_colid"};
10579    GLubyte *colv=NULL;
10580    SUMA_Boolean LocalHead = NOPE;
10581 
10582    SUMA_ENTRY;
10583 
10584    if (!sv || !sv->DO_PickMode) {
10585       SUMA_LH("Not in picking mode, leave in peace");
10586       SUMA_RETURN(colv);
10587    }
10588    if (!ref_idcode_str) {
10589       SUMA_S_Err("You must give me a reference_idcode_str");
10590       SUMA_RETURN(colv);
10591    }
10592    if (!DO_primitive) DO_primitive = "Not Set";
10593 
10594    switch (DO->do_type) {
10595       case SO_type: {
10596          SUMA_S_Warn("I do not intend this picking type for surfaces. Go away");
10597          SUMA_RETURN(NULL);
10598          break; }
10599       case MASK_type: {
10600          SUMA_S_Warn("I do not intend this picking type for masks. Go away");
10601          SUMA_RETURN(NULL);
10602          break; }
10603       case NBLS_type:
10604       case OLS_type:
10605       case NBOLS_type:
10606       case NBV_type:
10607       case ONBV_type:
10608       case DIR_type:
10609       case ODIR_type:
10610       case PNT_type:
10611       case LS_type: {
10612          SUMA_SegmentDO *SDO = (SUMA_SegmentDO *)DO;
10613          SUMA_LHv("Creating ids for %d segments in %s\n",
10614                   SDO->N_n, SDO->Label);
10615          if (!strcmp(DO_primitive,"segments")) {
10616             if (!(colv = SUMA_New_colid(sv, SDO->Label, SDO->idcode_str,
10617                                  DO_primitive, DO_variant,
10618                                  ref_idcode_str, ref_do_type, SDO->N_n))) {
10619                SUMA_S_Errv("Failed to get colid for %s\n",
10620                            SDO->Label);
10621                SUMA_RETURN(NULL);
10622             }
10623             SUMA_RETURN(colv);
10624          } else if (!strcmp(DO_primitive,"balls")) {
10625              if (SDO->N_AllNodes < 0) {
10626                if (SDO->N_AllNodes == -1) {
10627                   SUMA_S_Err("Looks like N_AllNodes was not initialized.\n"
10628                         "I can do it here with SUMA_Set_N_AllNodes_SegmentDO()\n"
10629                         "But for now I prefer to complain and return NULL");
10630                   SUMA_RETURN(NULL);
10631                } else {
10632                   SUMA_LHv("Have SDO->N_AllNodes = %d, nothing to do here\n",
10633                            SDO->N_AllNodes);
10634                   SUMA_RETURN(NULL);
10635                }
10636              }
10637              if (!(colv = SUMA_New_colid(sv, SDO->Label, SDO->idcode_str,
10638                                  DO_primitive, DO_variant, ref_idcode_str,
10639                                  ref_do_type, SDO->N_AllNodes))) {
10640                SUMA_S_Errv("Failed to get colid for %s\n",
10641                            SDO->Label);
10642                SUMA_RETURN(NULL);
10643             }
10644             SUMA_RETURN(colv);
10645          } else if (!strcmp(DO_primitive,"seg_balls")) {
10646                               /* For generic segments, not those of graph DOs! */
10647              if (!(colv = SUMA_New_colid(sv, SDO->Label, SDO->idcode_str,
10648                                  DO_primitive, DO_variant, ref_idcode_str,
10649                                  ref_do_type, SDO->N_n))) {
10650                SUMA_S_Errv("Failed to get colid for %s\n",
10651                            SDO->Label);
10652                SUMA_RETURN(NULL);
10653             }
10654             SUMA_RETURN(colv);
10655          } else {
10656             SUMA_S_Errv("Bad primitive %s for type %d, (%s)\n",
10657                            DO_primitive, DO->do_type,
10658                            SUMA_ObjectTypeCode2ObjectTypeName (DO->do_type));
10659             SUMA_RETURN(colv);
10660          }
10661          break; }
10662       case TRACT_type: {
10663          SUMA_TractDO *TDO = (SUMA_TractDO *)DO;
10664          if (!strcmp(DO_primitive,"bundles")) {
10665             SUMA_LHv("Creating ids for %d bundles in %s\n",
10666                      TDO_N_BUNDLES(TDO), DO_label(DO));
10667             if (!(colv = SUMA_New_colid(sv, TDO->Label, TDO->idcode_str,
10668                                  DO_primitive, DO_variant,
10669                            ref_idcode_str, ref_do_type, TDO_N_BUNDLES(TDO)))) {
10670                SUMA_S_Errv("Failed to get colid for %s\n",
10671                            TDO->Label);
10672                SUMA_RETURN(NULL);
10673             }
10674             SUMA_RETURN(colv);
10675          } if (!strcmp(DO_primitive,"tracts")) {
10676             SUMA_LHv("Creating ids for %d tracts in %s\n",
10677                      TDO_N_TRACTS(TDO), DO_label(DO));
10678             if (!(colv = SUMA_New_colid(sv, TDO->Label, TDO->idcode_str,
10679                                  DO_primitive, DO_variant,
10680                            ref_idcode_str, ref_do_type, TDO_N_TRACTS(TDO)))) {
10681                SUMA_S_Errv("Failed to get colid for %s\n",
10682                            TDO->Label);
10683                SUMA_RETURN(NULL);
10684             }
10685             SUMA_RETURN(colv);
10686          } else {
10687             SUMA_S_Errv("Bad primitive %s for type %d, (%s)\n",
10688                            DO_primitive, DO->do_type,
10689                            SUMA_ObjectTypeCode2ObjectTypeName (DO->do_type));
10690             SUMA_RETURN(colv);
10691          }
10692          break; }
10693       case ANY_DSET_type:
10694       case MD_DSET_type:
10695       case GDSET_type: {
10696          SUMA_S_Warn("I do not intend this picking type for dsets. Go away");
10697          SUMA_RETURN(NULL);
10698          break; }
10699       case CDOM_type:
10700          SUMA_S_Err("Have not implemented picking on this composite domain yet");
10701          SUMA_RETURN(NULL);
10702          break;
10703       default:
10704          SUMA_S_Errv("Not supported for types %d (%s)\n",
10705                      DO->do_type,
10706                      SUMA_ObjectTypeCode2ObjectTypeName (DO->do_type));
10707          SUMA_RETURN(NULL);
10708 
10709    }
10710 
10711    SUMA_S_Warn("Take care of the cleanup after you get back!!!!");
10712    SUMA_RETURN(colv);
10713 }
10714 
SUMA_DrawSegmentDO(SUMA_SegmentDO * SDO,SUMA_SurfaceViewer * sv)10715 SUMA_Boolean SUMA_DrawSegmentDO (SUMA_SegmentDO *SDO, SUMA_SurfaceViewer *sv)
10716 {
10717    static char FuncName[]={"SUMA_DrawSegmentDO"};
10718    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
10719    int i, N_n3, i3, n3, n, n1=0, n13=0, ncross=-1, ndraw=-1;
10720    long int n4;
10721    int gllst=0, gllsm=0;
10722    byte *msk=NULL;
10723    float origwidth=0.0, rad = 0.0, gain = 1.0;
10724    GLboolean ble=FALSE, dmsk=TRUE, gl_dt=TRUE;
10725    byte *mask=NULL;
10726    GLubyte *colid=NULL, *colidballs=NULL;
10727    SUMA_SurfaceObject *SO1 = NULL;
10728    SUMA_DSET *dset=NULL;
10729    SUMA_DUMB_DO DDO;
10730    DO_PICK_VARS;
10731    SUMA_Boolean LocalHead = NOPE;
10732 
10733    SUMA_ENTRY;
10734 
10735    if (!SDO || !sv) {
10736       fprintf(stderr,"Error %s: NULL pointer.\n", FuncName);
10737       SUMA_RETURN (NOPE);
10738    }
10739 
10740    if (SDO->NodeBased) { /* Locate the surface in question */
10741       SUMA_LH("Node-based vectors");
10742       if (!SDO->Parent_idcode_str) {
10743          SUMA_SL_Err("Object's parent idcode_str not specified.");
10744          SUMA_RETURN (NOPE);
10745       }
10746       DDO.err = 1; /* not set */
10747       if ((SO1 = SUMA_findSOp_inDOv(SDO->Parent_idcode_str,
10748                                     SUMAg_DOv, SUMAg_N_DOv))) {
10749          SUMA_Load_Dumb_DO((SUMA_ALL_DO *)SO1, &DDO);
10750          /* masking? */
10751          if ((ndraw = SUMA_ProcessDODrawMask(sv, SO1, &mask, &ncross)) < 0) {
10752             SUMA_RETURN (NOPE);
10753          }
10754          if (!ndraw) SUMA_RETURN(YUP);/* nothing to draw, nothing wrong */
10755          SUMA_LHv("ncross=%d\n", ncross);
10756       } else if ((dset = SUMA_find_GLDO_Dset(
10757                   (SUMA_GraphLinkDO *)SUMA_whichADOg(SDO->Parent_idcode_str)))) {
10758          SUMA_Load_Dumb_DO(SUMA_whichADOg(SDO->Parent_idcode_str), &DDO);
10759       }
10760       if (DDO.err) {
10761          if (DDO.err==1) {
10762             SUMA_SL_Err("Object's parent surface/graph set not found.");
10763          } else if (DDO.err==2) {
10764             SUMA_SL_Err("Could not fill DDO");
10765          } else {
10766             SUMA_SL_Err("Weird error.");
10767          }
10768          SUMA_RETURN (NOPE);
10769       }
10770       if (!DDO.NodeList) {
10771          SUMA_S_Err("SDO is node based but could not get a NodeList");
10772          SUMA_RETURN (NOPE);
10773       }
10774       SUMA_LHv("Got DDO.err=%d, N_Node=%d, NodeList=[%f %f %f...], "
10775                "NodeIndex=[%d...]\n",
10776                DDO.err, DDO.N_Node,
10777                         DDO.N_Node ? DDO.NodeList[0]:0.0,
10778                         DDO.N_Node ? DDO.NodeList[1]:0.0,
10779                         DDO.N_Node ? DDO.NodeList[2]:0.0,
10780                         DDO.NodeIndex ? DDO.NodeIndex[0]:-1);
10781    } else {
10782       SUMA_LH("Segments ");
10783    }
10784 
10785    glGetFloatv(GL_LINE_WIDTH, &origwidth);
10786    if (!SDO->thickv || SDO->NodeBased) glLineWidth(SDO->LineWidth);
10787 
10788    if (!sv->DO_PickMode) {
10789       switch (SDO->Stipple) {
10790          case SUMA_DASHED_LINE:
10791             if (!(gllst = glIsEnabled(GL_LINE_STIPPLE)))
10792                                  glEnable(GL_LINE_STIPPLE);
10793             if (!SDO->stipv) {
10794                glLineStipple (SDO->Mstip, SDO->stip);
10795             }
10796             break;
10797          case SUMA_SOLID_LINE:
10798             if (!(gllsm = glIsEnabled(GL_LINE_SMOOTH))) glEnable(GL_LINE_SMOOTH);
10799             if (0) glDepthMask(FALSE); /* Disabling depth masking makes lines
10800                               coplanar with polygons
10801                               render without stitching, bleeding, or Z fighting.
10802                               Problem is, that it need to be turned on for proper
10803                               rendering of remaing objects, and that brings the
10804                               artifact back. */
10805             glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
10806             break;
10807          default:
10808             SUMA_S_Errv("Unrecognized Stipple option %d\n", SDO->Stipple);
10809             if (mask) SUMA_free(mask); SUMA_RETURN(NOPE);
10810       }
10811    } else {
10812       if (!(colid = SUMA_DO_get_pick_colid((SUMA_ALL_DO *)SDO, SDO->idcode_str,
10813                            "segments", SDO->DrawnDO_variant,
10814                            SDO->Parent_idcode_str, SDO->Parent_do_type,
10815                            sv) )) {
10816          SUMA_S_Err("Failed to create colid for picking.");
10817          SUMA_RETURN(NOPE);
10818       }
10819       /* in pick mode, we enable little */
10820       DO_PICK_DISABLES;
10821    }
10822 
10823    if (SDO->NodeBased == 0) {
10824       if (SDO->thickv || SDO->stipv) {/* slow slow slow */
10825          SUMA_LH("Drawing xyz to xyz with thickness ");
10826          if (!sv->DO_PickMode) {
10827             if (!SDO->colv) glMaterialfv(GL_FRONT, GL_EMISSION, SDO->LineCol);
10828                /* turn off ambient and diffuse components */
10829             glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor);
10830             glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
10831          }
10832          i = 0; n4=0;
10833          N_n3 = 3*SDO->N_n;
10834          while (i < N_n3) {
10835             if (SDO->thickv) glLineWidth(SDO->thickv[i/3]);
10836             if (!sv->DO_PickMode && SDO->stipv)
10837                glLineStipple (SDO->Mstip, SDO->stipv[i/3]);
10838             glBegin(GL_LINES);
10839             if (colid) {
10840                n4 = 4*i; /* Always keep indexing tied to arrays of objects */
10841                glColor4ub(colid[n4], colid[n4+1], colid[n4+2], colid[n4+3]);
10842             } else if (SDO->colv)
10843                glMaterialfv(GL_FRONT, GL_EMISSION, &(SDO->colv[4*(i/3)]));
10844             glVertex3f(SDO->n0[i], SDO->n0[i+1], SDO->n0[i+2]);
10845             glVertex3f(SDO->n1[i], SDO->n1[i+1], SDO->n1[i+2]);
10846             i += 3;
10847             glEnd();
10848          }
10849       } else {
10850          SUMA_LH("Drawing xyz to xyz ");
10851          glBegin(GL_LINES);
10852          if (!sv->DO_PickMode) {
10853             if (!SDO->colv)
10854                glMaterialfv(GL_FRONT, GL_EMISSION, SDO->LineCol);
10855                      /*turn on emissivity  */
10856             glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor);
10857                      /* turn off ambient and diffuse components */
10858             glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
10859          }
10860          if (!SDO->NodeBased) {
10861             i = 0; n4=0;
10862             N_n3 = 3*SDO->N_n;
10863             while (i < N_n3) {
10864                if (colid) {
10865                   n4 = 4*i; /* Always keep indexing tied to arrays of objects */
10866                   glColor4ub(colid[n4], colid[n4+1], colid[n4+2], colid[n4+3]);
10867                } else if (SDO->colv)
10868                   glMaterialfv(GL_FRONT, GL_EMISSION, &(SDO->colv[4*(i/3)]));
10869                glVertex3f(SDO->n0[i], SDO->n0[i+1], SDO->n0[i+2]);
10870                glVertex3f(SDO->n1[i], SDO->n1[i+1], SDO->n1[i+2]);
10871                i += 3;
10872             }
10873          }
10874          glEnd();
10875       }
10876    } else if (  SDO->NodeBased == 1 ) {
10877       glBegin(GL_LINES);
10878       if (!sv->DO_PickMode) {
10879          if (!SDO->colv)
10880             glMaterialfv(GL_FRONT, GL_EMISSION, SDO->LineCol);
10881                   /*turn on emissivity  */
10882          glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor);
10883                   /* turn off ambient and diffuse components */
10884          glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
10885       }
10886       SUMA_LH("Drawing vectors ");
10887       i = 0; n4=0;
10888       gain = 1.0;
10889       while (i < SDO->N_n) {
10890          n = SDO->NodeID[i]; n3 = 3*n;
10891          if (LocalHead)
10892             fprintf(SUMA_STDERR,"%s: %d/%d, %d\n", FuncName, i, SDO->N_n, n);
10893          if (n<DDO.N_Node && DO_DRAW(mask,n,ncross)) {
10894             i3 = 3*i;
10895             if (SDO->thickv) {
10896                gain = SDO->thickv[i];
10897             } else {
10898                /* gain = 1.0; no need, set above */
10899             }
10900             if (colid) {
10901                n4 = 4*i; /* Always keep indexing tied to arrays of objects */
10902                glColor4ub(colid[n4], colid[n4+1], colid[n4+2], colid[n4+3]);
10903             } else if (SDO->colv)
10904                glMaterialfv(GL_FRONT, GL_EMISSION, &(SDO->colv[4*(i)]));
10905             if (LocalHead)
10906                fprintf(SUMA_STDERR,"%s: SDO->n1 = [%f %f %f]\n",
10907                      FuncName, SDO->n1[i3  ], SDO->n1[i3+1],SDO->n1[i3+2]);
10908             /* SPARSE LIST NOTICE:
10909             This coordinate lookup assumes you have a full node
10910             list. DDO.NodeIndex is ignored. If you start using DDO.NodeIndex,
10911             change n<DDO.N_Node condition above since a node index can exceed
10912             the number of nodes in a sparse list */
10913             glVertex3f( DDO.NodeList[n3], DDO.NodeList[n3+1],
10914                         DDO.NodeList[n3+2]);
10915             glVertex3f( DDO.NodeList[n3]  +(gain * SDO->n1[i3  ]),
10916                         DDO.NodeList[n3+1]+(gain * SDO->n1[i3+1]),
10917                         DDO.NodeList[n3+2]+(gain * SDO->n1[i3+2]));
10918          }
10919          i += 1;
10920       }
10921       glEnd();
10922    } else if (  SDO->NodeBased == 2 ) {
10923       if (!SDO->thickv) {
10924          glBegin(GL_LINES);
10925          if (!sv->DO_PickMode) {
10926             if (!SDO->colv)
10927                glMaterialfv(GL_FRONT, GL_EMISSION, SDO->LineCol);
10928                      /*turn on emissivity  */
10929             glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor);
10930                      /* turn off ambient and diffuse components */
10931             glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
10932          }
10933          SUMA_LH("two-node vectors ");
10934          i = 0;
10935          gain = 1.0; n4=0;
10936          while (i < SDO->N_n) {
10937             n = SDO->NodeID[i]; n3 = 3*n;
10938             n1 = SDO->NodeID1[i]; n13 = 3*n1;
10939             if (LocalHead)
10940                fprintf(SUMA_STDERR,"%s: %d/%d, %d,%d\n",
10941                         FuncName, i, SDO->N_n, n, n1);
10942             if (n<DDO.N_Node && n1 < DDO.N_Node && DO_DRAW(mask,n,ncross)) {
10943                i3 = 3*i;
10944 
10945                if (colid){
10946                   n4 = 4*i; /* Always keep indexing tied to arrays of objects */
10947                   glColor4ub(colid[n4], colid[n4+1], colid[n4+2], colid[n4+3]);
10948                   if (LocalHead)
10949                fprintf(SUMA_STDERR,"%s:         %d %d %d %d\n",
10950                         FuncName, colid[n4], colid[n4+1],
10951                                   colid[n4+2], colid[n4+3]);
10952                } else if (SDO->colv)
10953                   glMaterialfv(GL_FRONT, GL_EMISSION, &(SDO->colv[4*(i)]));
10954                /* SEE "SPARSE LIST NOTICE" above */
10955                glVertex3f( DDO.NodeList[n3], DDO.NodeList[n3+1],
10956                            DDO.NodeList[n3+2]);
10957                glVertex3f( DDO.NodeList[n13  ],
10958                            DDO.NodeList[n13+1],
10959                            DDO.NodeList[n13+2]);
10960             }
10961             i += 1;
10962          }
10963          glEnd();
10964       } else {/* slow slow slow */
10965          if (!sv->DO_PickMode) {
10966             if (!SDO->colv) glMaterialfv(GL_FRONT, GL_EMISSION, SDO->LineCol);
10967             glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor);
10968                /* turn off ambient and diffuse components */
10969             glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
10970          }
10971          SUMA_LH("two-node vectors, with thickness ");
10972          i = 0; n4=0;
10973          while (i < SDO->N_n) {
10974             n = SDO->NodeID[i]; n3 = 3*n;
10975             n1 = SDO->NodeID1[i]; n13 = 3*n1;
10976             if (LocalHead)
10977                fprintf(SUMA_STDERR,"%s: %d/%d, %d,%d\n",
10978                         FuncName, i, SDO->N_n, n, n1);
10979             if (n<DDO.N_Node && n1 < DDO.N_Node && DO_DRAW(mask,n,ncross)) {
10980                i3 = 3*i;
10981                if (SDO->thickv) glLineWidth(SDO->thickv[i]);
10982                glBegin(GL_LINES);
10983                if (colid){
10984                   n4 = 4*i; /* Always keep indexing tied to arrays of objects */
10985                   glColor4ub(colid[n4], colid[n4+1], colid[n4+2], colid[n4+3]);
10986                } else if (SDO->colv)
10987                   glMaterialfv(GL_FRONT, GL_EMISSION, &(SDO->colv[4*(i)]));
10988 
10989                /* SEE "SPARSE LIST NOTICE" above */
10990                glVertex3f( DDO.NodeList[n3], DDO.NodeList[n3+1],
10991                            DDO.NodeList[n3+2]);
10992                glVertex3f( DDO.NodeList[n13  ],
10993                            DDO.NodeList[n13+1],
10994                            DDO.NodeList[n13+2]);
10995                glEnd();
10996             }
10997             i += 1;
10998          }
10999       }
11000    } else {
11001       SUMA_S_Err("Oh no. Bad logic");
11002       goto GETOUT;
11003    }
11004 
11005    if (!sv->DO_PickMode) {
11006       switch (SDO->Stipple) {
11007          case SUMA_DASHED_LINE:
11008             if (!gllst) glDisable(GL_LINE_STIPPLE);
11009             break;
11010          case SUMA_SOLID_LINE:
11011             if (!gllsm) glDisable(GL_LINE_SMOOTH);
11012             break;
11013       }
11014    }
11015 
11016    /* draw the bottom object */
11017    if (SDO->botobj) {
11018       SUMA_LH("Drawing bottom");
11019       glLineWidth(0.5);
11020       if (!SDO->colv) {
11021          glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, SDO->LineCol);
11022       }
11023 
11024       if (!SDO->NodeBased) {
11025          if (!SDO->thickv)
11026             rad = SDO->LineWidth*0.5*sv->FOV[sv->iState]/FOV_INITIAL;
11027       } else {
11028          if (DDO.AvgLe != 0.0f) rad = DDO.AvgLe/4.0;
11029          else rad = 1.0/4.0;
11030       }
11031       gluQuadricDrawStyle (SDO->botobj, GLU_FILL);
11032       gluQuadricNormals (SDO->botobj , GLU_SMOOTH);
11033 
11034       if (!SDO->NodeBased) {
11035          n4=0;
11036          for (i=0; i<SDO->N_n;++i) {
11037             i3 = 3*i;
11038             if (colid) {
11039                n4 = 4*i; /* Always keep indexing tied to arrays of objects */
11040                glColor4ub(colid[n4], colid[n4+1], colid[n4+2], colid[n4+3]);
11041             } else {
11042                if (SDO->colv) {
11043                   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
11044                                  &(SDO->colv[i*4]));
11045                   glMaterialfv(GL_FRONT, GL_EMISSION, &(SDO->colv[i*4]));
11046                }
11047             }
11048             if (SDO->thickv)
11049                rad = SDO->thickv[i]*0.5*sv->FOV[sv->iState]/FOV_INITIAL;
11050             /* fprintf(SUMA_STDERR,
11051                       "thickv[i] = %f, FOV %f, "
11052                       "FOV_INITIAL %f, radinit=%f, radcomp=%f\n",
11053                         SDO->thickv[i], sv->FOV[sv->iState], FOV_INITIAL,
11054                         rad,  rad *SUMA_MAX_PAIR(sv->ZoomCompensate, 0.06)); */
11055             glTranslatef (SDO->n0[i3], SDO->n0[i3+1], SDO->n0[i3+2]);
11056             gluSphere(SDO->botobj, SUMA_MAX_PAIR(rad, 0.005)
11057                            /* *SUMA_MAX_PAIR(sv->ZoomCompensate, 0.06) */ ,
11058                       10, 10);
11059             glTranslatef (-SDO->n0[i3], -SDO->n0[i3+1], -SDO->n0[i3+2]);
11060          }
11061       } else { /* Node based vector */
11062          /* create a mask for those spheres already drawn,
11063             multiple vectors per node possible...*/
11064          msk = (byte *)SUMA_calloc(DDO.N_Node, sizeof(byte));
11065          if (!msk) {
11066             SUMA_SL_Crit("Failed to allocate!\n");
11067             glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, NoColor);
11068             goto GETOUT;
11069          }
11070          if (sv->DO_PickMode) {
11071             if (!(colidballs = SUMA_DO_get_pick_colid(
11072                                  (SUMA_ALL_DO *)SDO, SDO->idcode_str,
11073                                  "seg_balls", SDO->DrawnDO_variant,
11074                                  SDO->Parent_idcode_str, SDO->Parent_do_type,
11075                                  sv) )) {
11076                SUMA_S_Err("Failed to create colid for ball picking.");
11077             }
11078          }
11079          n4=0;
11080          for (i=0; i<SDO->N_n;++i) {
11081             i3 = 3*i;
11082             n = SDO->NodeID[i]; n3 = 3*n;
11083             if (LocalHead)
11084                fprintf(SUMA_STDERR,"%s: %d/%d, %d\n", FuncName, i, SDO->N_n, n);
11085             if (n<DDO.N_Node && DO_DRAW(mask,n,ncross)) {
11086                if (!msk[n]) {
11087                   if (colidballs) {
11088                      n4 = 4*i; /* Keep indexing tied to arrays of objects */
11089                      glColor4ub( colidballs[n4  ], colidballs[n4+1],
11090                                  colidballs[n4+2], colidballs[n4+3]);
11091                   } else   if (SDO->colv) {
11092                      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
11093                                     &(SDO->colv[i*4]));
11094                      glMaterialfv(GL_FRONT, GL_EMISSION, &(SDO->colv[i*4]));
11095                   }
11096                   /* SEE "SPARSE LIST NOTICE" above */
11097                   glTranslatef ( DDO.NodeList[n3]  ,
11098                                  DDO.NodeList[n3+1]  , DDO.NodeList[n3+2]  );
11099                   gluSphere(SDO->botobj, SUMA_MAX_PAIR(rad, 0.005)
11100                               /* *SUMA_MAX_PAIR(sv->ZoomCompensate, 0.06) */ ,
11101                               10, 10);
11102                   glTranslatef (-DDO.NodeList[n3]  ,
11103                                 -DDO.NodeList[n3+1]  , -DDO.NodeList[n3+2]  );
11104                   msk[n] = 1;
11105                } else {
11106                   SUMA_LH("Sphere already drawn");
11107                }
11108             }
11109          }
11110          if (msk) SUMA_free(msk); msk = NULL;
11111       }
11112       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, NoColor);
11113    }
11114 
11115    GETOUT:
11116    if (sv->DO_PickMode) DO_PICK_RESTORE;
11117 
11118    SUMA_ifree(colid); SUMA_ifree(colidballs);
11119    glMaterialfv(GL_FRONT, GL_EMISSION, NoColor); /*turn off emissivity */
11120    glLineWidth(origwidth);
11121    if (mask) SUMA_free(mask); mask=NULL;
11122 
11123    SUMA_RETURN (YUP);
11124 
11125 }
11126 
SUMA_GDSET_Edge_Bundle(SUMA_DSET * gset,SUMA_GRAPH_SAUX * GSaux,int edge_id,int alt_edge_id)11127 NI_element *SUMA_GDSET_Edge_Bundle(SUMA_DSET *gset, SUMA_GRAPH_SAUX *GSaux,
11128                                    int edge_id, int alt_edge_id)
11129 {
11130    static char FuncName[]={"SUMA_GDSET_Edge_Bundle"};
11131    NI_element *nel=NULL;
11132    SUMA_NGR_INDEX_HASH_DATUM *hd=NULL;
11133 
11134    if (edge_id < 0 || !gset || !GSaux || !GSaux->thd) return(NULL);
11135 
11136    /* Get the ngr part number for the nel from the hash table */
11137    HASH_FIND_INT(GSaux->thd, &edge_id, hd);
11138    if (!hd) {
11139       if (alt_edge_id < 0) return(NULL);
11140       else {
11141          HASH_FIND_INT(GSaux->thd, &alt_edge_id, hd);
11142          if (!hd) return(NULL);
11143       }
11144    }
11145 
11146    /* Have index, work it */
11147    if (GSaux->net) return((NI_element *)GSaux->net->part[hd->ngrindex]);
11148    else return((NI_element *)gset->ngr->part[hd->ngrindex]); /* old style */
11149 
11150    return(NULL);
11151 }
11152 
11153 #define SUMA_EDGEINDEX_TO_NELNUM(key,thd,hdbuf) { \
11154    HASH_FIND_INT(thd, &key, hdbuf); \
11155    if (hdbuf) key = hdbuf->ngrindex; else  key = -1; \
11156 }
11157 
11158 #define SUMA_GDSET_TRACK_NEL(dset, GSaux, itp) ( \
11159          GSaux->net ? (NI_element *)GSaux->net->part[itp]: \
11160                       (NI_element *)dset->ngr->part[itp] );
11161 
11162 #define SUMA_DRAW_GRAPH_EDGE(DDO, cna3, cnb3, nelitp) {    \
11163    if (!nelitp) { /* good ole fashioned segment */                   \
11164       glVertex3f( DDO.NodeList[cna3], DDO.NodeList[cna3+1],          \
11165                   DDO.NodeList[cna3+2]);                             \
11166       glVertex3f( DDO.NodeList[cnb3  ],                              \
11167                   DDO.NodeList[cnb3+1],                              \
11168                   DDO.NodeList[cnb3+2]);                             \
11169    } else {     /* bundle mode */                                    \
11170       int nn, mm;                                                    \
11171       TAYLOR_TRACT *ttn=NULL;                                        \
11172       for (nn=0; nn<nelitp->vec_len; ++nn) {                         \
11173          ttn = (TAYLOR_TRACT *)(nelitp->vec[0])+nn;                  \
11174          mm=0;                                                       \
11175          while (mm < ttn->N_pts3-3) {                                \
11176       glVertex3f(ttn->pts[mm  ], ttn->pts[mm+1], ttn->pts[mm+2] );   \
11177       glVertex3f(ttn->pts[mm+3], ttn->pts[mm+4], ttn->pts[mm+5] );   \
11178             mm += 3;                                                 \
11179          }                                                           \
11180       }                                                              \
11181    }                                                                 \
11182 }
11183 
11184 /* A variant on DrawSegmentDO that is tailored to the drawing needs
11185 of a graph dataset. Eventually, I might create a new DO type, but for
11186 now we piggy back on the good old SegmentDO */
SUMA_DrawGSegmentDO(SUMA_GRAPH_SAUX * GSaux,SUMA_SurfaceViewer * sv)11187 SUMA_Boolean SUMA_DrawGSegmentDO (SUMA_GRAPH_SAUX *GSaux, SUMA_SurfaceViewer *sv)
11188 {
11189    static char FuncName[]={"SUMA_DrawGSegmentDO"};
11190    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
11191    GLfloat  textcolor[4] = {1.0, 1.0, 1.0, 1.0},
11192             textshadcolor[4] = {0.0, 1.0, 1.0, 1.0};
11193    int i, iii, si, N_n3, i3, i4, cn3, cn, n, cn1=0, n1=0,
11194        cn13=0, ncross=-1, ndraw=-1, tw=0, th=0, nl=0, istip=0;
11195    GLfloat rpos[4], col1[4], col2[4], clw=0.1, cbw=0.1;
11196    long int n4;
11197    /* long int NodeIndRange[2]; */
11198    char **names=NULL;
11199    GLboolean valid;
11200    int gllst=0, gllsm=0, OnlyThroughNode = -1;
11201    byte *bbox=NULL, *NodeMask=NULL, *NodeMaskr=NULL;
11202    NI_element *nelitp = NULL;
11203    float origwidth=0.0, radconst = 0.0, rad = 0.0, radgain = 0.0,
11204          gain = 1.0, constcol[4], edgeconst=1.0, group_col[4],
11205          vmin=1.0, vmax=1.0, Wfac=1.0, Sfac=1.0, cdim=1/3.0,
11206          *GNr=NULL, *GNg=NULL, *GNb=NULL, dimmer = 1.0, radgaing = 0.0,
11207          Rfac = 1.0, Rrange[2]={0.1, 10};
11208    GLboolean ble=FALSE, dmsk=TRUE, gl_dt=TRUE;
11209    byte *mask=NULL, *wmask=NULL, showword = 0;
11210    GLubyte *colid=NULL, *colidballs=NULL, *colballpick=NULL;
11211    GLubyte green[4] = {0, 1, 0, 1};
11212    SUMA_SurfaceObject *SO1 = NULL;
11213    SUMA_DSET *dset=NULL;
11214    SUMA_DUMB_DO DDO;
11215    SUMA_SegmentDO *SDO = NULL;
11216    DO_PICK_VARS;
11217    GLfloat selcol[4], Wrange[2], ghostcol[4];
11218    SUMA_OVERLAYS *curcol = NULL;
11219    void *fontGL=NULL;
11220    int ic0, ic1, s0, r0, s1, r1, TxtShadeMode=1, okind, ri,
11221        *dsrt=NULL, *dsrt_ind=NULL, *GNI=NULL, wbox=0, *GNG=NULL,
11222        NoEdges=0;
11223    int stipsel = 0; /* flag for stippling of selected edge */
11224    int depthsort = 1; /* Sort text and draw from farthest to closest */
11225    byte ShadeBalls = 1;
11226    int PickAsShown = 1; /* 1 = Pick only from what is displayed.
11227                            0 = Pick from entire graph */
11228    int OverThr = 210; /* Maximum overlap of text allowed. 255 = 100% overlap */
11229    SUMA_Boolean LocalHead = NOPE;
11230 
11231    SUMA_ENTRY;
11232 
11233    if (!GSaux || !sv || !(SDO=GSaux->SDO)) {
11234       fprintf(stderr,"Error %s: NULL pointer.\n", FuncName);
11235       SUMA_RETURN (NOPE);
11236    }
11237 
11238    gl_dt = glIsEnabled(GL_DEPTH_TEST);
11239 
11240    if (stipsel) {
11241       SUMA_S_Warn("This option is no good at this moment when segment stippling"
11242                   "\n is turned on for all segments. Easy to fix though ...");
11243    }
11244 
11245    if (SDO->NodeBased == 2) {
11246       SUMA_LH("Node-based vectors");
11247       if (!SDO->Parent_idcode_str) {
11248          SUMA_SL_Err("Object's parent idcode_str not specified.");
11249          SUMA_RETURN (NOPE);
11250       }
11251 
11252       if (!(dset = SUMA_find_GLDO_Dset(
11253                   (SUMA_GraphLinkDO *)SUMA_whichADOg(SDO->Parent_idcode_str)))) {
11254          SUMA_S_Err("Could not find dset for GLDO!");
11255          SUMA_RETURN (NOPE);
11256       }
11257       if (!(curcol = SUMA_ADO_CurColPlane((SUMA_ALL_DO *)dset))) {
11258          SUMA_S_Err("Could not find current col plane!");
11259          SUMA_RETURN (NOPE);
11260       }
11261 
11262       fontGL = SUMA_Font2GLFont(curcol->Font);
11263       SUMA_NodeCol2Col(curcol->NodeCol, constcol);
11264 
11265       TxtShadeMode = curcol->TxtShad;
11266 
11267       edgeconst = 1 * curcol->EdgeThickGain;
11268 
11269       glGetFloatv(GL_LINE_WIDTH, &origwidth);
11270       if (curcol->EdgeThick == SW_SurfCont_DsetEdgeThickConst) {
11271          SDO->LineWidth = 1.0*curcol->EdgeThickGain;
11272          clw = SDO->LineWidth;
11273          glLineWidth(clw);
11274       }
11275 
11276       if (curcol->EdgeThick == SW_SurfCont_DsetEdgeThickVal ||
11277           curcol->EdgeStip == SW_SurfCont_DsetEdgeStipVal   ||
11278           curcol->Through == SW_SurfCont_DsetThroughRad ||
11279           curcol->Through == SW_SurfCont_DsetThroughCaR) {
11280          /* compute width / stippling scaling params */
11281          if (SUMA_ABS(curcol->OptScl->IntRange[0]) <
11282              SUMA_ABS(curcol->OptScl->IntRange[1])) {
11283             vmin = SUMA_ABS(curcol->OptScl->IntRange[0]);
11284             vmax = SUMA_ABS(curcol->OptScl->IntRange[1]);
11285          } else {
11286             vmin = SUMA_ABS(curcol->OptScl->IntRange[1]);
11287             vmax = SUMA_ABS(curcol->OptScl->IntRange[0]);
11288          }
11289          if (vmin == vmax) { vmin = 0; vmax = 1.0; }
11290          /* Will need to fix this should you unalias segment drawing... */
11291          glGetFloatv(GL_ALIASED_LINE_WIDTH_RANGE, Wrange);
11292          if (vmax > vmin) {
11293             if ((Wfac = (Wrange[1]-Wrange[0])/(vmax)) <= 0.0) Wfac = 1.0;
11294          } else {
11295             if ((Wfac = (Wrange[1]-Wrange[0])/(vmin)) <= 0.0) Wfac = 1.0;
11296          }
11297          /* For stippling */
11298          if (vmax > vmin) {
11299             if ((Sfac = 15/(vmax)) <= 0.0) Sfac = 1.0;
11300          } else {
11301             if ((Sfac = 15/(vmin)) <= 0.0) Sfac = 1.0;
11302          }
11303          /* For dynamic radius */
11304          Rrange[0] = 0.1;
11305          Rrange[1] = 10;
11306          if (vmax > vmin) {
11307             if ((Rfac = (Rrange[1]-Rrange[0])/(vmax)) <= 0.0) Rfac = 1.0;
11308          } else {
11309             if ((Rfac = (Rrange[1]-Rrange[0])/(vmin)) <= 0.0) Rfac = 1.0;
11310          }
11311 
11312       }
11313 
11314       DDO.err = 1; /* not set */
11315       SUMA_Load_Dumb_DO(SUMA_whichADOg(SDO->Parent_idcode_str), &DDO);
11316       if (DDO.err) {
11317          if (DDO.err==1) {
11318             SUMA_SL_Err("Object's parent graph set not found.");
11319          } else if (DDO.err==2) {
11320             SUMA_SL_Err("Could not fill DDO");
11321          } else {
11322             SUMA_SL_Err("Weird error.");
11323          }
11324          SUMA_RETURN (NOPE);
11325       }
11326       if (!DDO.NodeList) {
11327          SUMA_S_Err("SDO is node based but could not get a NodeList");
11328          SUMA_RETURN (NOPE);
11329       }
11330       SUMA_LHv("Got DDO.err=%d, N_Node=%d, NodeList=[%f %f %f...], "
11331                "NodeIndex=[%d...]\n",
11332                DDO.err, DDO.N_Node,
11333                         DDO.N_Node ? DDO.NodeList[0]:0.0,
11334                         DDO.N_Node ? DDO.NodeList[1]:0.0,
11335                         DDO.N_Node ? DDO.NodeList[2]:0.0,
11336                         DDO.NodeIndex ? DDO.NodeIndex[0]:-1);
11337    } else {
11338       SUMA_S_Err("For graph dsets, Segment DO must be node based on both ends");
11339       SUMA_RETURN (NOPE);
11340    }
11341 
11342    if (!(names = SUMA_GDSET_GetPointNamesColumn(dset, &iii, NULL))) {
11343       SUMA_LH("No names!"); /* No need to weep */
11344    }
11345    if (!(GNI = SUMA_GDSET_GetPointIndexColumn(dset, &iii, NULL))) {
11346       if (iii == -2) {
11347          SUMA_S_Err("Bad news for indices!!");
11348          SUMA_RETURN(NOPE);
11349       }
11350    }
11351    if (!(GNG = SUMA_GDSET_GetPointGroupColumn(dset, &iii, NULL))) {
11352       SUMA_LH("No Group!"); /* No need to weep */
11353    }
11354    if (!(GNr = SUMA_GDSET_GetPointColumn_f(dset, &iii, NULL, "Gnode R"))) {
11355       SUMA_LH("No R!"); /* No need to weep */
11356    } else {
11357       if (!(GNg = SUMA_GDSET_GetPointColumn_f(dset, &iii, NULL, "Gnode G"))) {
11358          SUMA_S_Err("What? Have R but not G?");
11359          SUMA_RETURN(NOPE);
11360       }
11361       if (!(GNb = SUMA_GDSET_GetPointColumn_f(dset, &iii, NULL, "Gnode B"))) {
11362          SUMA_S_Err("What? Have R but not B?");
11363          SUMA_RETURN(NOPE);
11364       }
11365    }
11366 
11367    /* Copy the range of node indices */
11368    #if 0
11369    NodeIndRange[0] = dset->Aux->range_node_index[0];
11370    NodeIndRange[1] = dset->Aux->range_node_index[1];
11371    if (NodeIndRange[1] < NodeIndRange[0] || NodeIndRange[1] < 1) {
11372       SUMA_S_Err("Bad node index range %ld %ld %d",
11373                   NodeIndRange[0], NodeIndRange[1], DDO.N_Node);
11374       SUMA_RETURN(NOPE);
11375    }
11376    #endif
11377    if (ShadeBalls) {
11378       /* Dim the colors a little and turn off the emissivity to get a 3D effect
11379          on the rendered balls */
11380       dimmer = 2.0;
11381       for (n=0; n<3; ++n) {
11382          constcol[n] /= dimmer;
11383       }
11384    }
11385 
11386    if ((PickAsShown || !sv->DO_PickMode) && !GSaux->ShowUncon) {
11387       SUMA_LH("Masking unconnected nodes");
11388       NodeMask = (byte *)SUMA_calloc(DDO.N_Node, sizeof(byte));
11389    } else {
11390       SUMA_LH("No Masking unused");
11391    }
11392    for (i=0;i<3;++i) {
11393       textcolor[i] = 1.0 - sv->clear_color[i];
11394       textshadcolor[i] = sv->clear_color[i];
11395    }
11396    if (textcolor[0]+textcolor[1]+textcolor[2] > 1.5) {
11397       wbox = 0;
11398       cdim = 1/3.0;
11399    } else {
11400       wbox = 1;
11401       cdim = 3.0;
11402    }
11403 
11404    if (curcol->ShowMode < 0) { /* No connectivity information to display */
11405       /* Show all nodes, just no edges */
11406       if (NodeMask) memset(NodeMask, 1, DDO.N_Node*sizeof(byte));
11407       goto BOTTOM;
11408    }
11409 
11410    SUMA_LHv("Stippling %d (XXX=%d, Val=%d, 01=%d) wbox=%d\n, IgnoreSelection=%d",
11411                 curcol->EdgeStip, SW_SurfCont_DsetEdgeStipXXX,
11412                 SW_SurfCont_DsetEdgeStipVal, SW_SurfCont_DsetEdgeStip1, wbox,
11413                 GSaux->IgnoreSelection);
11414    if (curcol->EdgeStip == SW_SurfCont_DsetEdgeStipXXX ||
11415        curcol->EdgeStip < 0) {
11416       SDO->Stipple = SUMA_SOLID_LINE;
11417    } else {
11418       SDO->Stipple = SUMA_DASHED_LINE;
11419    }
11420    if (!sv->DO_PickMode) {
11421       switch (SDO->Stipple) {
11422          case SUMA_DASHED_LINE:
11423             if (!(gllst = glIsEnabled(GL_LINE_STIPPLE)))
11424                                  glEnable(GL_LINE_STIPPLE);
11425             if (curcol->EdgeStip != SW_SurfCont_DsetEdgeStipVal) {
11426                glLineStipple (1, SUMA_StippleLineMask_rand(
11427                           curcol->EdgeStip-SW_SurfCont_DsetEdgeStipVal, 1, 0));
11428             }
11429             break;
11430          case SUMA_SOLID_LINE:
11431             if (!(gllsm = glIsEnabled(GL_LINE_SMOOTH))) glEnable(GL_LINE_SMOOTH);
11432             if (0) glDepthMask(FALSE); /* Disabling depth masking makes lines
11433                               coplanar with polygons
11434                               render without stitching, bleeding, or Z fighting.
11435                               Problem is, that it need to be turned on for proper
11436                               rendering of remaing objects, and that brings the
11437                               artifact back. */
11438             glHint (GL_LINE_SMOOTH_HINT, GL_NICEST);
11439             break;
11440          default:
11441             SUMA_S_Errv("Unrecognized Stipple option %d\n", SDO->Stipple);
11442             if (mask) SUMA_free(mask); SUMA_RETURN(NOPE);
11443       }
11444    } else {
11445       /* Note that this colid is for all the elements in the object
11446          to be drawn. If you show only connections through a node
11447          or something there will be a mismatch between what is drawn
11448          and what is being selected. */
11449       if (!(colid = SUMA_DO_get_pick_colid((SUMA_ALL_DO *)SDO, SDO->idcode_str,
11450                            "segments", SDO->DrawnDO_variant,
11451                            SDO->Parent_idcode_str, SDO->Parent_do_type,
11452                            sv) )) {
11453          SUMA_S_Err("Failed to create colid for picking.");
11454          SUMA_RETURN(NOPE);
11455       }
11456       /* in pick mode, we enable little */
11457       DO_PICK_DISABLES;
11458    }
11459 
11460    NoEdges = 0;
11461    if ((PickAsShown || !sv->DO_PickMode) && !GSaux->IgnoreSelection &&
11462        curcol->Through >= 0 &&
11463        GSaux->PR->datum_index == -1 && GSaux->PR->iAltSel[SUMA_ENODE_0] != -1) {
11464       OnlyThroughNode = GSaux->PR->iAltSel[SUMA_ENODE_0];
11465 
11466       if (curcol->Through != SW_SurfCont_DsetThroughEdge) {
11467          NoEdges = 1;
11468       }
11469       if (NodeMask && OnlyThroughNode >=0) {
11470          if ((cn = SUMA_NodeIndex_To_Index(DDO.NodeIndex,
11471                                        DDO.N_Node, OnlyThroughNode))>=0) {
11472             NodeMask[cn] = 1;
11473          } else {
11474             SUMA_S_Warn("Hmm, node %d not in nodelist?", OnlyThroughNode);
11475          }
11476       }
11477    } else OnlyThroughNode = -1;
11478 
11479    ic0 = -1; ic1=-1; r0 = -1; r1 = -1; s0 = -1; s1 = -1;
11480    if (!sv->DO_PickMode && (s0=GSaux->PR->datum_index) >=0 &&
11481        SUMA_SV_GetShowSelectedDatum(sv)) { /* Have selection to highlight,
11482                                               Need to avoid it being masked
11483                                               by one of the edges if depth buffer
11484                                               is enabled. For this reason we
11485                                               will mask all the edges between
11486                                               the points of the selected edge */
11487       r0 = SUMA_GDSET_EdgeIndex_To_Row(dset,s0);
11488       if (GSaux->isColored &&
11489          GSaux->isColored[s0]) {/* Don't show it if thresholded */
11490          ic0 = GSaux->isColored[s0];
11491          GSaux->isColored[s0] = 0;
11492          n = SDO->NodeID[r0];
11493          n1 = SDO->NodeID1[r0];
11494          SUMA_GDSET_PointsToSegRow(dset, n1, n, &r1);/* get the n1-->n edge */
11495          s1 = SUMA_GDSET_EdgeRow_To_Index(dset, r1);
11496          ic1 = GSaux->isColored[s1];
11497          GSaux->isColored[s1] = 0;
11498             /* Now do the highlight for edge s0, why wait till the end ?*/
11499          n = SDO->NodeID[r0];
11500          n1 = SDO->NodeID1[r0];
11501          SUMA_LHv("Highlight: edge row %d/%d edge index %d, [%d,%d] (%d nodes)\n"
11502                   "Reverse edge: row %d, index %d\n",
11503                   r0, SDO->N_n, s0, n, n1, DDO.N_Node,
11504                   r1, s1);
11505 
11506          /* get position of node n in NodeList */
11507          cn  = SUMA_NodeIndex_To_Index(DDO.NodeIndex, DDO.N_Node, n);
11508             cn3 = 3*cn;
11509          cn1 = SUMA_NodeIndex_To_Index(DDO.NodeIndex, DDO.N_Node, n1);
11510             cn13 = 3*cn1;
11511 
11512          if (cn<DDO.N_Node && cn1 < DDO.N_Node && cn>-1 && cn1>-1) {
11513             if ( NodeMask &&
11514                  (cn != cn1)) { /* Only draw points touched by an edge
11515                                    between different points (off diagonal)*/
11516                NodeMask[cn] = 1; NodeMask[cn1] = 1;
11517             }
11518             if (stipsel) {
11519                if(!(gllst = glIsEnabled(GL_LINE_STIPPLE)))
11520                                     glEnable(GL_LINE_STIPPLE);
11521                glLineStipple (1, SUMA_int_to_stipplemask(stipsel-1));
11522             }
11523             if (curcol->EdgeThick == SW_SurfCont_DsetEdgeThickVal) {
11524                clw = ((SUMA_ABS(curcol->V[r0]))*Wfac+Wrange[0])
11525                                            *curcol->EdgeThickGain;
11526                glLineWidth(clw);
11527             }
11528             selcol[0] = 1-sv->clear_color[0];
11529             selcol[1] = 1-sv->clear_color[1];
11530             selcol[2] = 1-sv->clear_color[2];
11531             selcol[3] = 1-sv->clear_color[3];
11532             if (GSaux->ShowBundles)
11533                nelitp = SUMA_GDSET_Edge_Bundle(dset, GSaux, s0, s1);
11534             else nelitp = NULL;
11535 
11536             SUMA_LHv("Col:[%f %f %f %f]\n",
11537                selcol[0], selcol[1], selcol[2], selcol[3]);
11538 
11539             glBegin(GL_LINES);
11540             glMaterialfv(GL_FRONT, GL_EMISSION, selcol);
11541 
11542             SUMA_DRAW_GRAPH_EDGE(DDO, cn3, cn13, nelitp);
11543 
11544             glEnd();
11545             if (stipsel && !gllst) glDisable(GL_LINE_STIPPLE);
11546          }
11547       }
11548    }
11549 
11550    if (  SDO->NodeBased == 2 ) {
11551       if (LocalHead) SUMA_CHECK_GL_ERROR("Pre Edges\n");
11552       if (curcol->EdgeThick != SW_SurfCont_DsetEdgeThickVal &&
11553           curcol->EdgeStip != SW_SurfCont_DsetEdgeStipVal) {
11554          glBegin(GL_LINES);
11555          if (!sv->DO_PickMode) {
11556             if (!SDO->colv)
11557                glMaterialfv(GL_FRONT, GL_EMISSION, SDO->LineCol);
11558                      /*turn on emissivity  */
11559             glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor);
11560                      /* turn off ambient and diffuse components */
11561             glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
11562          }
11563          SUMA_LHv("two-node vectors\n"
11564                   "    DDO.NodeIndex %p, DDO.N_Node %d\n"
11565                   "    GSaux->isColored %p, OnlyThroughNode=%d\n",
11566                   DDO.NodeIndex, DDO.N_Node,  GSaux->isColored,
11567                   OnlyThroughNode);
11568          i = 0;
11569          gain = 1.0; n4=0;
11570          while (i < SDO->N_n) {
11571             n = SDO->NodeID[i];
11572             n1 = SDO->NodeID1[i];
11573             si = SUMA_GDSET_EdgeRow_To_Index(dset,i);
11574             /*
11575                if (n==79 || n1==79) LocalHead=YUP;
11576                else LocalHead = NOPE;
11577             */
11578             /* Do we have a tract for this monster ? */
11579             if (GSaux->ShowBundles)
11580                nelitp = SUMA_GDSET_Edge_Bundle(dset, GSaux, si, -1);
11581             else nelitp = NULL;
11582 
11583             if (LocalHead) {
11584                fprintf(SUMA_STDERR,
11585                     "%s: segment row %d/%d, index %d, nodes [%d,%d], MASK %d\n",
11586                         FuncName, i, SDO->N_n,
11587                         si, n, n1, IN_MASK(GSaux->isColored,si));
11588                if (nelitp) {
11589                   fprintf(SUMA_STDERR,
11590                      "   Have special tract of segment %d at '%s %s'\n",
11591                      si, nelitp ? nelitp->name:"nothing",
11592                      nelitp ? SUMA_CHECK_NULL_STR(
11593                               NI_get_attribute(nelitp, "Edge_Index")):"NULL");
11594                }
11595                #if 0
11596                if (i==0) {
11597                   char *ss;
11598                   ss=SUMA_ShowMeSome(DDO.NodeIndex, SUMA_int,
11599                                      DDO.N_Node, 5, NULL);
11600                   fprintf(SUMA_STDERR,"DDO.NodeIndex=%s\n", ss);
11601                   SUMA_ifree(ss);
11602                }
11603                #endif
11604             }
11605             if (OnlyThroughNode>=0 &&
11606                   (OnlyThroughNode != n)) {
11607                   /* See comment dated April 21 2014 for change to
11608                      condition above. */
11609                      ++i; continue;
11610             }
11611             /* get position of node n in NodeList */
11612             if ((cn = SUMA_NodeIndex_To_Index(DDO.NodeIndex,DDO.N_Node,n))< 0){
11613                SUMA_LH("Failed to get index of node %d",n);
11614                ++i; continue;
11615             }
11616                cn3 = 3*cn;
11617             if ((cn1 = SUMA_NodeIndex_To_Index(DDO.NodeIndex,DDO.N_Node,n1))< 0){
11618                SUMA_LH("Failed to get index of node %d",n1);
11619                ++i; continue;
11620             }
11621                cn13 = 3*cn1;
11622             #if 0
11623                SUMA_LHv("Rows of nodes [%d %d] are [%d %d]\n",
11624                      n, n1, cn, cn1);
11625             #endif
11626 
11627             if (cn<DDO.N_Node && cn1 < DDO.N_Node &&
11628                 IN_MASK(GSaux->isColored,si)) {
11629                i3 = 3*i;
11630                if ( NodeMask &&
11631                    (cn != cn1)) { /* Only draw points touched by an edge
11632                                    between different points (off diagonal)*/
11633                    NodeMask[cn] = 1; NodeMask[cn1] = 1;
11634                }
11635 
11636                if (NoEdges) { /* Don't draw the edge, just continue */
11637                   ++i; continue;
11638                }
11639 
11640                if (colid){
11641                   n4 = 4*i; /* Always keep indexing tied to arrays of objects */
11642                   glColor4ub(colid[n4], colid[n4+1], colid[n4+2], colid[n4+3]);
11643                   SUMA_LH("colid for segment row %d         %d %d %d %d\n",
11644                           i, colid[n4], colid[n4+1],
11645                                   colid[n4+2], colid[n4+3]);
11646                } else if (SDO->colv) { /* Colv is index by datum index */
11647                   glMaterialfv(GL_FRONT, GL_EMISSION, &(SDO->colv[4*(si)]));
11648                }
11649                SUMA_LHv("Seg row %d between [%d,%d]: [%f %f %f --> %f %f %f]\n",
11650                  i, cn, cn1,
11651                  DDO.NodeList[cn3   ],DDO.NodeList[cn3 +1],DDO.NodeList[cn3 +2],
11652                  DDO.NodeList[cn13  ],DDO.NodeList[cn13+1],DDO.NodeList[cn13+2]);
11653                SUMA_DRAW_GRAPH_EDGE(DDO, cn3, cn13, nelitp);
11654             } else {
11655                if (LocalHead)
11656                   fprintf(SUMA_STDERR, "masked segment %d?\n", i);
11657             }
11658             i += 1;
11659          }
11660          glEnd();
11661          if (LocalHead) SUMA_CHECK_GL_ERROR("Post End\n");
11662       } else {/* variable stippling, edge thickness, or both */
11663          if (!sv->DO_PickMode) {
11664             if (!SDO->colv) glMaterialfv(GL_FRONT, GL_EMISSION, SDO->LineCol);
11665             glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor);
11666                /* turn off ambient and diffuse components */
11667             glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
11668          }
11669          SUMA_LH("two-node vectors, with thickness ");
11670          i = 0;
11671          gain = 1.0; n4=0;
11672          while (i < SDO->N_n) {
11673             n = SDO->NodeID[i];
11674             n1 = SDO->NodeID1[i];
11675             si = SUMA_GDSET_EdgeRow_To_Index(dset,i);
11676 
11677             /* Tracts are not compatible with variable edge width */
11678             nelitp = NULL;
11679 
11680             if (LocalHead)
11681                fprintf(SUMA_STDERR,"%s: %d/%d, edge index %d [%d,%d]\n",
11682                         FuncName, i, SDO->N_n, si, n, n1);
11683             if (OnlyThroughNode>=0 &&
11684                   (OnlyThroughNode != n)) {
11685                /* Condition "OnlyThroughNode != n" used to be
11686                   "OnlyThroughNode != n &&  OnlyThroughNode != n1" ,
11687                The change was done so that only edges starting at
11688                node OnlyThroughNode are shown. Including the second
11689                half would also show edges terminating at node OnlyThroughNode.
11690 
11691                This change was done for clarity of usage. Showing edges
11692                that emanate or terminate at a node can be confusing, especially
11693                when replacing edges with a coloring of the target node. For non
11694                symmetrical matrices the results can be confusing under the
11695                current implementation where non-equal reciprocal edges overlap
11696                with no particular order.
11697                Also, when no drawing edges and colorizing nodes instead, both
11698                NodeMask[cn] and NodeMask[cn1] get set to 1 if either of cn-->cn1
11699                or cn1--cn exists and the corresponding balls do get drawn with
11700                the default color.
11701                All of this can be fixed if one truly wants 'through node'
11702                connections, rather than the current 'from node' implementation.
11703                Should you decide to do this, put that second condition back in
11704                at the two locations in this function (search for April 21 2014).
11705                And make sure that NodeMask[cn1] does not get set if
11706                cn1 == OnlyThroughNode
11707                                                    ZSS April 21 2014
11708                */
11709                      ++i; continue;
11710             }
11711 
11712             /* get position of node n in NodeList */
11713             if ((cn = SUMA_NodeIndex_To_Index(DDO.NodeIndex, DDO.N_Node, n))< 0){
11714                SUMA_LH("Failed to get index of node %d",n);
11715                ++i; continue;
11716             }
11717                cn3 = 3*cn;
11718             if ((cn1=SUMA_NodeIndex_To_Index(DDO.NodeIndex, DDO.N_Node, n1))< 0){
11719                SUMA_LH("Failed to get index of node %d",n1);
11720                ++i; continue;
11721             }
11722                cn13 = 3*cn1;
11723 
11724             if (cn<DDO.N_Node && cn1 < DDO.N_Node &&
11725                 IN_MASK(GSaux->isColored,si)) {
11726                i3 = 3*i;
11727                if (NodeMask &&
11728                    (cn != cn1)) { NodeMask[cn] = 1; NodeMask[cn1] = 1; }
11729 
11730                if (NoEdges) { /* Don't draw the edge, just continue */
11731                   ++i; continue;
11732                }
11733 
11734                if (curcol->EdgeStip == SW_SurfCont_DsetEdgeStipVal) {
11735                   istip = 16-(int)((SUMA_ABS(curcol->V[i]))*Sfac);
11736 
11737                   if (istip == 16) --istip; /* Not nice to avoid displaying
11738                                                min edge ... */
11739                   glLineStipple (1, SUMA_StippleLineMask_rand(istip, 1, 0));
11740                }
11741                if (curcol->EdgeThick == SW_SurfCont_DsetEdgeThickVal) {
11742                   clw = ((SUMA_ABS(curcol->V[i]))*Wfac+Wrange[0])
11743                                                    *curcol->EdgeThickGain;
11744                   glLineWidth(clw);
11745                }
11746                glBegin(GL_LINES);
11747                if (colid){
11748                   n4 = 4*i; /* Always keep indexing tied to arrays of objects */
11749                   glColor4ub(colid[n4], colid[n4+1], colid[n4+2], colid[n4+3]);
11750                } else if (SDO->colv) { /* Colv is index by datum index */
11751                   glMaterialfv(GL_FRONT, GL_EMISSION, &(SDO->colv[4*(si)]));
11752                }
11753                SUMA_DRAW_GRAPH_EDGE(DDO, cn3, cn13, nelitp);
11754 
11755                glEnd();
11756             }
11757             i += 1;
11758          }
11759       }
11760    } else {
11761       SUMA_S_Err("Oh no. Bad logic");
11762       goto GETOUT;
11763    }
11764 
11765    if (GSaux->isColored) { /* undo the mask disturbance for selection highlight*/
11766       if (ic0 >= 0) GSaux->isColored[s0] = ic0;
11767       if (ic1 >= 0) GSaux->isColored[s1] = ic1;                                      }
11768 
11769    /* Highlight selected Datum, ONLY if we did not go the mask route */
11770    if (!sv->DO_PickMode && (si=GSaux->PR->datum_index) >=0 &&
11771        SUMA_SV_GetShowSelectedDatum(sv) && !GSaux->isColored) {
11772       r0 = SUMA_GDSET_EdgeIndex_To_Row(dset,si);
11773       n = SDO->NodeID[i];
11774       n1 = SDO->NodeID1[i];
11775             /* if (n==79 || n1==79) LocalHead=YUP;
11776                else LocalHead = NOPE; */
11777       SUMA_LHv("Highlight: i = %d edge row %d/%d, edge index %d [%d,%d] (%d)\n",
11778                i, r0, SDO->N_n, si, n, n1, DDO.N_Node);
11779       /* get position of node n in NodeList */
11780       cn  = SUMA_NodeIndex_To_Index(DDO.NodeIndex, DDO.N_Node, n);
11781          cn3 = 3*cn;
11782       cn1 = SUMA_NodeIndex_To_Index(DDO.NodeIndex, DDO.N_Node, n1);
11783          cn13 = 3*cn1;
11784 
11785       if (cn<DDO.N_Node && cn1 < DDO.N_Node && cn > -1 && cn1 > -1) {
11786          if ( NodeMask &&
11787               (cn != cn1)) { /* Only draw points touched by an edge
11788                                       between different points (off diagonal)*/
11789             NodeMask[cn] = 1; NodeMask[cn1] = 1;
11790          }
11791          /* Kill depth test or you could get burried under two way edges
11792             There is a problem though in that the edge wil ride over
11793             other objects that otherwise would obscure it, so that might
11794             be ugly. To get around that, one would need to avid drawing
11795             any edge that is between the two nodes. Not a bad idea I guess,
11796             and then we can make do without the disabling of the depth test*/
11797          if (gl_dt) glDisable(GL_DEPTH_TEST);
11798          if (stipsel) {
11799             if (!(gllst = glIsEnabled(GL_LINE_STIPPLE)))
11800                                     glEnable(GL_LINE_STIPPLE);
11801             glLineStipple (1, SUMA_int_to_stipplemask(stipsel-1));
11802          }
11803          if (curcol->EdgeThick == SW_SurfCont_DsetEdgeThickVal)
11804                      glLineWidth(((SUMA_ABS(curcol->V[i]))*Wfac+Wrange[0])
11805                                                          *curcol->EdgeThickGain);
11806          selcol[0] = 1-sv->clear_color[0];
11807          selcol[1] = 1-sv->clear_color[1];
11808          selcol[2] = 1-sv->clear_color[2];
11809          selcol[3] = 1-sv->clear_color[3];
11810          SUMA_LHv("Col:[%f %f %f %f]\n",
11811             selcol[0], selcol[1], selcol[2], selcol[3]);
11812          glBegin(GL_LINES);
11813          glMaterialfv(GL_FRONT, GL_EMISSION, selcol);
11814 
11815          glVertex3f( DDO.NodeList[cn3], DDO.NodeList[cn3+1],
11816                      DDO.NodeList[cn3+2]);
11817          glVertex3f( DDO.NodeList[cn13  ],
11818                      DDO.NodeList[cn13+1],
11819                      DDO.NodeList[cn13+2]);
11820          glEnd();
11821          if (gl_dt) glEnable(GL_DEPTH_TEST);
11822          if (stipsel && !gllst) glDisable(GL_LINE_STIPPLE);
11823       }
11824    }
11825 
11826    if (!sv->DO_PickMode) {
11827       switch (SDO->Stipple) {
11828          case SUMA_DASHED_LINE:
11829             if (!gllst) glDisable(GL_LINE_STIPPLE);
11830             break;
11831          case SUMA_SOLID_LINE:
11832             if (!gllsm) glDisable(GL_LINE_SMOOTH);
11833             break;
11834       }
11835    }
11836 
11837 
11838    BOTTOM:
11839    /* draw the bottom object */
11840    if (SDO->botobj) {
11841       float *xyz=(float *)SUMA_malloc(3*SDO->N_AllNodes*sizeof(float));
11842       float *xyzr=NULL, toff = 0.0;
11843       int *GNIr=NULL;
11844       int NoEdges_DynamicRadius = 0;
11845       int NoEdges_DynamicColor = 0;
11846       char **namesr=NULL;
11847       SUMA_LH("Drawing bottom");
11848       if (LocalHead) SUMA_CHECK_GL_ERROR("Pre bottom\n");
11849       glLineWidth(0.5);
11850       if (!SDO->colv) {
11851          glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, SDO->LineCol);
11852       }
11853 
11854       NoEdges_DynamicRadius = 0;
11855       NoEdges_DynamicColor = 0;
11856       if (curcol->Through >= 0) {
11857          switch (curcol->Through) {
11858             case SW_SurfCont_DsetThroughEdge:
11859                NoEdges_DynamicRadius = 0;
11860                NoEdges_DynamicColor = 0;
11861                break;
11862             case SW_SurfCont_DsetThroughCol:
11863                NoEdges_DynamicRadius = 0;
11864                NoEdges_DynamicColor = 1;
11865                break;
11866             case SW_SurfCont_DsetThroughRad:
11867                NoEdges_DynamicRadius = 1;
11868                NoEdges_DynamicColor = 0;
11869                break;
11870             case SW_SurfCont_DsetThroughCaR:
11871                NoEdges_DynamicRadius = 1;
11872                NoEdges_DynamicColor = 1;
11873                break;
11874             default:
11875                NoEdges_DynamicRadius = 0;
11876                NoEdges_DynamicColor = 0;
11877                break;
11878          }
11879       }
11880 
11881       radgain = curcol->NodeRadGain;
11882       if (DDO.AvgLe != 0.0f) {
11883          radconst = DDO.AvgLe/4.0;
11884       } else {
11885          radconst = 1.0/4.0;
11886       }
11887       gluQuadricDrawStyle (SDO->botobj, GLU_FILL);
11888       gluQuadricNormals (SDO->botobj , GLU_SMOOTH);
11889 
11890       /* create a mask for those spheres already drawn,
11891          multiple vectors per node possible...*/
11892 
11893       if (sv->DO_PickMode) {
11894          colballpick = green; /* just to be safe, to simplify debugging
11895                                  instead of having NULL */
11896          if (!(colidballs = SUMA_DO_get_pick_colid(
11897                               (SUMA_ALL_DO *)SDO, SDO->idcode_str,
11898                               "balls", SDO->DrawnDO_variant,
11899                               SDO->Parent_idcode_str, SDO->Parent_do_type,
11900                               sv) )) {
11901             SUMA_S_Err("Failed to create colid for ball picking.");
11902          }
11903       }
11904 
11905       /* Get the coords of the nodes to represent */
11906       for (i=0; i<SDO->N_AllNodes;++i) {
11907          cn  = SUMA_NodeIndex_To_Index(DDO.NodeIndex,
11908                                        DDO.N_Node, GNI ? GNI[i]:i);
11909          cn3 = 3*cn;
11910          xyz[3*i  ] = DDO.NodeList[cn3  ];
11911          xyz[3*i+1] = DDO.NodeList[cn3+1];
11912          xyz[3*i+2] = DDO.NodeList[cn3+2];
11913       }
11914 
11915       if (fontGL && names && depthsort) {
11916          float *xyzsc= SUMA_malloc(3*SDO->N_AllNodes*sizeof(float)),
11917                *xyzscr=NULL;
11918          dsrt = SUMA_DepthSort(xyz, SDO->N_AllNodes, names, 0, xyzsc);
11919          xyzr = SUMA_freorder_triplets(xyz, dsrt, SDO->N_AllNodes);
11920          xyzscr = SUMA_freorder_triplets(xyzsc, dsrt, SDO->N_AllNodes);
11921          GNIr = SUMA_reorder(GNI, dsrt, SDO->N_AllNodes);
11922          namesr = SUMA_sreorder(names, dsrt, SDO->N_AllNodes);
11923          if (NodeMask) NodeMaskr =SUMA_breorder(NodeMask, dsrt, SDO->N_AllNodes);
11924          #if 0
11925          fprintf(stderr,"Sorting from farthest to closest:\n");
11926          for (i=0; i<SDO->N_AllNodes;++i) {
11927             fprintf(stderr,"dsrt[%d]=%d, namesr[%d] = %s @[%.2f %.2f %.2f],"
11928                            " names[%d]= %s @ [%.2f %.2f %.2f]\n",
11929                            i, dsrt[i], i, namesr[i],
11930                            xyzr[3*i], xyzr[3*i+1], xyzr[3*i+2], i, names[i],
11931                            xyz[3*i], xyz[3*i+1], xyz[3*i+2]);
11932          }
11933          #endif
11934          wmask = SUMA_WordOverlapMask(sv->X->aWIDTH, sv->X->aHEIGHT,
11935                                       SDO->N_AllNodes,
11936                                       namesr, fontGL, xyzscr, -1, NodeMaskr);
11937          SUMA_ifree(xyzsc); SUMA_ifree(xyzscr); SUMA_ifree(NodeMaskr);
11938       } else {
11939          xyzr = xyz;
11940          GNIr = GNI;
11941          namesr = names;
11942          wmask = NodeMask;
11943       }
11944 
11945       if (SDO->N_SegNodes == 1) {
11946          static int nwarn=0;
11947          /* Just one node!!!, make drawing exception */
11948          if (!nwarn) {
11949             SUMA_S_Warn("Graph %s has one node!\n"
11950                  "This node will be displayed regardless of thresholding, etc.\n"
11951                         "Further such warnings will be muted.\n",
11952                         ADO_LABEL((SUMA_ALL_DO*)SDO));
11953             ++nwarn;
11954          }
11955          if (wmask) wmask[0] = 1;
11956       }
11957       n4=0;
11958       for (i=0; i<SDO->N_AllNodes;++i) {
11959          i3 = 3*i; i4 = 4*i;
11960          if (GNIr) {
11961             n = GNIr[i];
11962          } else {
11963             n = i;
11964          }
11965          /*
11966             if (n==79 || n==2 || n==7) LocalHead=YUP;
11967             else LocalHead = NOPE;
11968          */
11969          if (wmask) showword = wmask[i];
11970          else showword = 255;
11971 
11972          SUMA_LHv("%d/%d, %d, showword %d\n",
11973                   i, SDO->N_AllNodes, n, showword);
11974          okind=-2;
11975          if (curcol->NodeRad >= 0) {
11976             if (curcol->NodeRad == SW_SurfCont_DsetNodeRadVal) {
11977                if (okind == -2) {
11978                   if (!SUMA_GDSET_PointToDiagSegRowIndex(dset,n,&ri,&si)){
11979                      okind = -1;
11980                   } else okind = 1;
11981                }
11982                if (okind>0)
11983                   rad = SUMA_ABS(curcol->V[ri]);
11984             } else {
11985                rad = radconst;
11986             }
11987             r1 = -1;
11988             if (NoEdges && OnlyThroughNode != n ) {
11989                SUMA_GDSET_PointsToSegRow(dset, OnlyThroughNode, n, &r1);
11990                                        /* get the n1-->n edge to get its value*/
11991 
11992                if (NoEdges_DynamicRadius) {
11993                   if (r1>=0) {
11994                      rad = (SUMA_ABS(curcol->V[r1]))*Rfac+Rrange[0];
11995                   } else rad = 2.0;
11996                }
11997                #if 0
11998                SUMA_LH(
11999                      "%d-->%d: row=%d, rad %f, V[%d]=%f, Rfac=%f, radgain %f",
12000                            OnlyThroughNode, n, r1, rad, r1,
12001                            curcol->V[r1], Rfac, radgain);
12002                #endif
12003             }
12004             if (OnlyThroughNode == n) {
12005                if (colidballs) {
12006                   if (dsrt) {
12007                      i4 = 4*dsrt[i];
12008                   } else i4 = 4*i;
12009                   colballpick = colidballs+i4;
12010                   glColor4ub( colidballs[i4  ], colidballs[i4+1],
12011                               colidballs[i4+2], colidballs[i4+3]);
12012                } else {
12013                   selcol[0] = (1-sv->clear_color[0])/dimmer;
12014                   selcol[1] = (1-sv->clear_color[1])/dimmer;
12015                   selcol[2] = (1-sv->clear_color[2])/dimmer;
12016                   selcol[3] = 1-sv->clear_color[3];
12017                   if (!ShadeBalls) {
12018                      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, selcol);
12019                      glMaterialfv(GL_FRONT, GL_EMISSION, selcol);
12020                   } else {
12021                      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, selcol);
12022                      glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
12023                   }
12024                }
12025             } else {
12026                if (colidballs) {
12027                   if (dsrt) {
12028                      i4 = 4*dsrt[i];
12029                   } else i4 = 4*i;
12030                   colballpick = colidballs+i4;
12031                   glColor4ub( colidballs[i4  ], colidballs[i4+1],
12032                               colidballs[i4+2], colidballs[i4+3]);
12033                } else if (NoEdges && NoEdges_DynamicColor) {
12034                   if (r1>=0) {
12035                      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
12036                                                       &(SDO->colv[r1*4]));
12037                      if (!ShadeBalls) {
12038                        glMaterialfv(GL_FRONT, GL_EMISSION,
12039                                                       &(SDO->colv[r1*4]));
12040                      } else {
12041                         glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
12042                      }
12043                   } else {
12044                      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
12045                                                          constcol);
12046                      if (!ShadeBalls) {
12047                         glMaterialfv(GL_FRONT, GL_EMISSION, constcol);
12048                      } else {
12049                         glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
12050                      }
12051                   }
12052                } else if (GNG && curcol->NodeCol == SW_SurfCont_DsetNodeColGrp) {
12053                   if (n>=0) {
12054                      if (GNr) {
12055                         group_col[0] = GNr[n]/dimmer;
12056                         group_col[1] = GNg[n]/dimmer;
12057                         group_col[2] = GNb[n]/dimmer;
12058                         group_col[3] = 1.0;
12059                         SUMA_LH("Point %d group %d: %f %f %f\n",
12060                               n, GNG[n],
12061                               group_col[0], group_col[1],  group_col[2]);
12062                      } else {
12063                         SUMA_a_good_col("ROI_i256", GNG[n], group_col);
12064                         if (ShadeBalls) {
12065                            group_col[0] /= dimmer;
12066                            group_col[1] /= dimmer;
12067                            group_col[2] /= dimmer;
12068                         }
12069                      }
12070                      if (!ShadeBalls) {
12071                         glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, NoColor);
12072                         glMaterialfv(GL_FRONT, GL_EMISSION, group_col);
12073                      } else {
12074                         glMaterialfv(GL_FRONT,GL_AMBIENT_AND_DIFFUSE, group_col);
12075                         glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
12076                      }
12077                   } else {
12078                      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
12079                                                          constcol);
12080                      if (!ShadeBalls) {
12081                         glMaterialfv(GL_FRONT, GL_EMISSION, constcol);
12082                      } else {
12083                         glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
12084                      }
12085                   }
12086                } else if (SDO->colv &&
12087                           curcol->NodeCol == SW_SurfCont_DsetNodeColVal) {
12088                   if (okind == -2) {
12089                      if (!SUMA_GDSET_PointToDiagSegRowIndex(
12090                                                       dset,n,&ri,&si)){
12091                         okind = -1;
12092                      } else okind = 1;
12093                   }
12094                   if (okind>0) {
12095                      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
12096                                                       &(SDO->colv[si*4]));
12097                      if (!ShadeBalls) {
12098                        glMaterialfv(GL_FRONT, GL_EMISSION,
12099                                                       &(SDO->colv[si*4]));
12100                      } else {
12101                         glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
12102                      }
12103                   } else {
12104                      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
12105                                                          constcol);
12106                      if (!ShadeBalls) {
12107                         glMaterialfv(GL_FRONT, GL_EMISSION, constcol);
12108                      } else {
12109                         glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
12110                      }
12111                   }
12112                } else {
12113                   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, constcol);
12114                   if (!ShadeBalls) {
12115                      glMaterialfv(GL_FRONT, GL_EMISSION, constcol);
12116                   } else {
12117                      glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
12118                   }
12119                }
12120             }
12121             glTranslatef ( xyzr[i3]  , xyzr[i3+1]  , xyzr[i3+2]  );
12122             if (showword) {
12123                gluSphere(SDO->botobj,
12124                                     SUMA_MAX_PAIR(rad*radgain, 0.005), 10, 10);
12125             } else if (NoEdges){
12126                if (GSaux->ShowUncon) {
12127                   ghostcol[0] = (1-sv->clear_color[0])/2.0/dimmer;
12128                   ghostcol[1] = (1-sv->clear_color[1])/2.0/dimmer;
12129                   ghostcol[2] = (1-sv->clear_color[2])/2.0/dimmer;
12130                   ghostcol[3] = 1-sv->clear_color[3];
12131                   if (!ShadeBalls) {
12132                      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, ghostcol);
12133                      glMaterialfv(GL_FRONT, GL_EMISSION, ghostcol);
12134                   } else {
12135                      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, ghostcol);
12136                      glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
12137                   }
12138                   /* Show ghosts, for clickability */
12139                   if (NoEdges_DynamicRadius) radgaing = 0.25*radgain;
12140                   else radgaing = 1.0*radgain;
12141                   gluSphere(SDO->botobj, SUMA_MAX_PAIR(rad*radgaing,0.005),
12142                             10, 10);
12143                }
12144             }
12145             glTranslatef (-xyzr[i3]  ,  -xyzr[i3+1]  , -xyzr[i3+2]  );
12146          }
12147          if (fontGL && names) {
12148             #if 0 /* Not working. I am not sure why
12149                      this is failing. Without writing
12150                      into the depth buffer, the text
12151                      will get obscured by objects such as slices
12152                      that are rendered later. The solution
12153                      for now is to make sure graphs are rendered
12154                      last and to disable GL_DEPTH_TEST for this
12155                      step altogether. */
12156             if (!gl_dt) glEnable(GL_DEPTH_TEST);
12157             glDepthFunc(GL_ALWAYS); /* Need to write into depth buffer or risk
12158                                  getting text overshadowed by other objects.
12159                                  Disabling the text would render text OK
12160                                  without aliasing from shadow but will
12161                                  not update the depth buffer. */
12162             #else
12163             if (gl_dt) glDisable(GL_DEPTH_TEST);
12164             #endif
12165             if (colidballs) {
12166                SUMA_COPY_VEC(colballpick, col1, 4, GLbyte, GLfloat);
12167                SUMA_COPY_VEC(colballpick, col2, 4, GLbyte, GLfloat);
12168             } else {
12169                if (TxtShadeMode) {
12170                   SUMA_COPY_VEC(textshadcolor, col1, 4, GLfloat, GLfloat);
12171                   SUMA_COPY_VEC(textcolor, col2, 4, GLfloat, GLfloat);
12172                } else {
12173                   SUMA_COPY_VEC(textcolor, col1, 4, GLfloat, GLfloat);
12174                }
12175             }
12176             SUMA_LHv("namesr[%d] %s at %f %f %f, shad = %d, fontGL=%p"
12177                      "col1 [%.3f %.3f %.3f] col2 [%.3f %.3f %.3f] \n"
12178                      "size(GLbyte) %ld, size(byte) %ld\n",
12179                      i, names ? namesr[i]:"NULL"
12180                      , xyzr[i3], xyzr[i3+1], xyzr[i3+2],
12181                      TxtShadeMode, fontGL, col1[0], col1[1], col1[2],
12182                      col2[0], col2[1], col2[2], sizeof(GLbyte), sizeof(byte));
12183             toff = rad*radgain;
12184             if (colidballs) { /* No need to allow selection with different
12185                                  shadow modes, just put a box where the
12186                                  text is to go and let the picking be based
12187                                  on that. If you want to see the text
12188                                  for debugging the pick buffer, block
12189                                  this if statement and let function
12190                                  proceed below */
12191                if (PickAsShown) {
12192                    switch(TxtShadeMode) { /* See same switch below */
12193                      case SW_SurfCont_DsetTxtShad1:
12194                      case SW_SurfCont_DsetTxtShad5:
12195                         if (!(showword > OverThr || TxtShadeMode == 5)) continue;
12196                         break;
12197                      case SW_SurfCont_DsetTxtShad2:
12198                         break;
12199                      case SW_SurfCont_DsetTxtShad6:
12200                      case SW_SurfCont_DsetTxtShad3:
12201                         if (!(showword > OverThr || TxtShadeMode == 6)) continue;
12202                         break;
12203                      case SW_SurfCont_DsetTxtShad4:
12204                         break;
12205                      default:
12206                         break;
12207                   }
12208                }
12209                glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col1);
12210                glMaterialfv(GL_FRONT, GL_EMISSION, col1);
12211                glRasterPos3d(xyzr[i3]  +toff ,
12212                        xyzr[i3+1]+toff ,
12213                        xyzr[i3+2] +toff );
12214                glGetFloatv(GL_CURRENT_RASTER_POSITION, rpos);
12215                glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
12216                if (!valid) continue;
12217                SUMA_TextBoxSize (namesr[i], &tw, &th, &nl, fontGL);
12218                bbox = (byte*)SUMA_calloc(4*(tw+2)*(th+2), sizeof(byte));
12219                /* Turn box white? Someday you'll need to set the
12220                   box colors to be that of the background exactly... */
12221                iii=0;
12222                while (iii<4*(tw+2)*(th+2)) {
12223                   bbox[iii++] = colballpick[0];
12224                   bbox[iii++] = colballpick[1];
12225                   bbox[iii++] = colballpick[2];
12226                   bbox[iii++] = colballpick[3];
12227                }
12228                glBitmap( 0, 0, 0, 0,
12229                          0.0, -th/4.0,  NULL );
12230                glDrawPixels(tw, th, GL_RGBA, GL_UNSIGNED_BYTE, bbox);
12231                SUMA_ifree(bbox);
12232                continue; /* On to the next point */
12233             }
12234             /* do some text action */
12235             switch(TxtShadeMode) { /* Make sure you mirror conditions in
12236                                     similar switch above */
12237                case SW_SurfCont_DsetTxtShad1:
12238                case SW_SurfCont_DsetTxtShad5:
12239                   if (showword > OverThr || TxtShadeMode == 5) {
12240                      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col1);
12241                      glMaterialfv(GL_FRONT, GL_EMISSION, col1);
12242                      glRasterPos3d( xyzr[i3]  +toff ,
12243                                     xyzr[i3+1]+toff ,
12244                                     xyzr[i3+2]+toff );
12245                      glGetFloatv(GL_CURRENT_RASTER_POSITION, rpos);
12246                      glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
12247                      if (!valid) break;
12248                      /* Black font behind white font */
12249                      for (iii=0; namesr[i][iii] != '\0'; iii++) {
12250                         glutBitmapCharacter(fontGL, namesr[i][iii]);
12251                      }
12252                      /* Change the current raster color
12253                      (can't set glMaterialfv(), alone, need
12254                      call to glRasterPos3d which will also set the
12255                      current raster color (GL_CURRENT_RASTER_COLOR)
12256                      Note that we draw the shadow first, to avoid
12257                      aliasing artifacts from the shadow*/
12258                      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
12259                                                          col2);
12260                      glMaterialfv(GL_FRONT, GL_EMISSION, col2);
12261                      glRasterPos3d(xyzr[i3]  +toff ,
12262                                    xyzr[i3+1]+toff ,
12263                                    xyzr[i3+2]+toff );
12264                      /* offset rel. to  shadow */
12265                      glBitmap( 0, 0, 0, 0,
12266                                -1.0, -1.0,  NULL );
12267                      for (iii=0; namesr[i][iii] != '\0'; iii++) {
12268                         glutBitmapCharacter(fontGL, namesr[i][iii]);
12269                      }
12270                   }
12271                   break;
12272                case SW_SurfCont_DsetTxtShad2:
12273                   if (showword < 250) {
12274                      /* dim the colors */
12275                      col2[0] = col2[0]*cdim;
12276                      col2[1] = col2[1]*cdim;
12277                      col2[2] = col2[2]*cdim;
12278                   }
12279                   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col1);
12280                   glMaterialfv(GL_FRONT, GL_EMISSION, col1);
12281                      /* Must come AFTER glMaterialfv */
12282                   glRasterPos3d( xyzr[i3]  +toff ,
12283                                  xyzr[i3+1]+toff ,
12284                                  xyzr[i3+2]+toff );
12285                   glGetFloatv(GL_CURRENT_RASTER_POSITION, rpos);
12286                   glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
12287                   if (!valid) break;
12288                   /* Black font behind white font */
12289                   for (iii=0; names[i][iii] != '\0'; iii++) {
12290                      glutBitmapCharacter(fontGL, namesr[i][iii]);
12291                   }
12292                   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
12293                                                       col2);
12294                   glMaterialfv(GL_FRONT, GL_EMISSION, col2);
12295                   glRasterPos3d(xyzr[i3]  +toff ,
12296                                 xyzr[i3+1]+toff ,
12297                                 xyzr[i3+2]+toff );
12298                   SUMA_TextBoxSize (namesr[i], &tw, &th, &nl, fontGL);
12299                   /* offset rel. to  shadow */
12300                   glBitmap( 0, 0, 0, 0,
12301                             -1.0, -1.0,  NULL );
12302                   for (iii=0; namesr[i][iii] != '\0'; iii++) {
12303                      glutBitmapCharacter(fontGL, namesr[i][iii]);
12304                   }
12305                   break;
12306                case SW_SurfCont_DsetTxtShad6:
12307                case SW_SurfCont_DsetTxtShad3:
12308                   /* Black box behind white font, hide if more than
12309                      half is masked */
12310                   if (showword > OverThr || TxtShadeMode == 6) {
12311                      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col1);
12312                      glMaterialfv(GL_FRONT, GL_EMISSION, col1);
12313                      /* Must come AFTER glMaterialfv */
12314                      glRasterPos3d( xyzr[i3]  +toff ,
12315                                     xyzr[i3+1]+toff ,
12316                                     xyzr[i3+2]+toff );
12317                      glGetFloatv(GL_CURRENT_RASTER_POSITION, rpos);
12318                      glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
12319                      if (!valid) break;
12320                      SUMA_TextBoxSize (namesr[i], &tw, &th, &nl, fontGL);
12321                      SUMA_LHv("namesr[%d]=%s %d %d %d\n",
12322                               i, namesr[i], tw, th, nl);
12323                      /* Had to add the +2 in calloc and memset to get rid
12324                      of a strange one pixel wide black line that showed
12325                      up on the top right corner of the box. It is only
12326                      noticeable when wbox is set. Not sure what causes this*/
12327                      bbox = (byte*)SUMA_calloc(4*(tw+2)*(th+2), sizeof(byte));
12328                      /* Turn box white? Someday you'll need to set the
12329                         box colors to be that of the background exactly... */
12330                      if (wbox) memset(bbox, 255, 4*(tw+2)*(th+2)*sizeof(byte));
12331                      glBitmap( 0, 0, 0, 0,
12332                                0.0, -th/4.0,  NULL );
12333                      glDrawPixels(tw+1, th+1, GL_RGBA, GL_UNSIGNED_BYTE, bbox);
12334                      SUMA_ifree(bbox);
12335                      /* Now draw the text */
12336                      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
12337                                                          col2);
12338                      glMaterialfv(GL_FRONT, GL_EMISSION, col2);
12339                      glRasterPos3d(xyzr[i3]  +toff ,
12340                                    xyzr[i3+1]+toff ,
12341                                    xyzr[i3+2]+toff );
12342                      for (iii=0; namesr[i][iii] != '\0'; iii++) {
12343                         glutBitmapCharacter(fontGL, namesr[i][iii]);
12344                      }
12345                   }
12346                   break;
12347                case SW_SurfCont_DsetTxtShad4:
12348                   /* Black box behind white font for unobstructed
12349                      text. Obstructed text has no black background
12350                      and is dimmed by overlap. Tried variable dimming
12351                      but it gets confusing. Note that obstruction
12352                      is only computed for text with text, not text
12353                      with objects */
12354                   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col1);
12355                   glMaterialfv(GL_FRONT, GL_EMISSION, col1);
12356                   /* Must come AFTER glMaterialfv */
12357                   glRasterPos3d( xyzr[i3]  +toff ,
12358                                  xyzr[i3+1]+toff ,
12359                                  xyzr[i3+2]+toff );
12360                   glGetFloatv(GL_CURRENT_RASTER_POSITION, rpos);
12361                   glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
12362                   if (!valid) break;
12363                   SUMA_TextBoxSize (namesr[i], &tw, &th, &nl, fontGL);
12364                   SUMA_LHv("namesr[%d]=%s %d %d %d\n",
12365                            i, namesr[i], tw, th, nl);
12366                   if (showword > 250) { /* Practically fully exposed
12367                                           Show word proudly, with background*/
12368                      bbox = (byte*)SUMA_calloc(4*(tw+2)*(th+2), sizeof(byte));
12369                      if (wbox) memset(bbox, 255, 4*(tw+2)*(th+2)*sizeof(byte));
12370 
12371                      glBitmap( 0, 0, 0, 0,
12372                                0.0, -th/4.0,  NULL );
12373                      glDrawPixels(tw+1, th+1, GL_RGBA, GL_UNSIGNED_BYTE, bbox);
12374                      SUMA_ifree(bbox);
12375                   } else { /* dim the text to reduce clutter */
12376                      col2[0] = col2[0]*cdim;
12377                      col2[1] = col2[1]*cdim;
12378                      col2[2] = col2[2]*cdim;
12379                   }
12380                   /* Now draw the text */
12381                   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
12382                                                       col2);
12383                   glMaterialfv(GL_FRONT, GL_EMISSION, col2);
12384                   glRasterPos3d(xyzr[i3]  +toff ,
12385                                 xyzr[i3+1]+toff ,
12386                                 xyzr[i3+2]+toff );
12387                   for (iii=0; namesr[i][iii] != '\0'; iii++) {
12388                      glutBitmapCharacter(fontGL, namesr[i][iii]);
12389                   }
12390                   break;
12391                default:
12392                   SUMA_S_Warnv("Bad shadow val of %d, using simplest case\n",
12393                                TxtShadeMode);
12394 
12395                   glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, textcolor);
12396                   glMaterialfv(GL_FRONT, GL_EMISSION, textcolor);
12397                   glRasterPos3d( xyzr[i3]  +toff ,
12398                                  xyzr[i3+1]+toff ,
12399                                  xyzr[i3+2]+toff );
12400                   glGetFloatv(GL_CURRENT_RASTER_POSITION, rpos);
12401                   glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
12402                   if (!valid) break;
12403                   for (iii=0; namesr[i][iii] != '\0'; iii++) {
12404                      glutBitmapCharacter(fontGL, namesr[i][iii]);
12405                   }
12406                   break;
12407             }
12408             #if 0 /* Not working, see comment above */
12409             glDepthFunc(GL_LESS);
12410             if (!gl_dt) glDisable(GL_DEPTH_TEST);
12411             #else
12412             if (gl_dt) glEnable(GL_DEPTH_TEST);
12413             #endif
12414          }
12415       }
12416       if (LocalHead) SUMA_CHECK_GL_ERROR("Pre bottom\n");
12417       if (xyzr != xyz) SUMA_ifree(xyzr); xyzr=NULL;
12418       if (namesr != names) SUMA_ifree(namesr); namesr=NULL;
12419       if (GNIr != GNI) SUMA_ifree(GNIr); GNIr = NULL;
12420       SUMA_ifree(xyz);
12421       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, NoColor);
12422    }
12423 
12424    GETOUT:
12425    if (wmask && wmask != NodeMask) SUMA_free(wmask); wmask = NULL;
12426    SUMA_ifree(NodeMask);
12427    SUMA_ifree(dsrt);
12428    if (sv->DO_PickMode) DO_PICK_RESTORE;
12429 
12430    SUMA_ifree(colid); SUMA_ifree(colidballs);
12431    glMaterialfv(GL_FRONT, GL_EMISSION, NoColor); /*turn off emissivity */
12432    glLineWidth(origwidth);
12433    if (mask) SUMA_free(mask); mask=NULL;
12434    if (gl_dt) glEnable(GL_DEPTH_TEST);
12435    else glDisable(GL_DEPTH_TEST);
12436 
12437    SUMA_RETURN (YUP);
12438 }
12439 
12440 /* A function to find out which words would overlap when displayed in OpenGL
12441    Nwidth (int) width of viewport in pixels
12442    Nheight (int) height of viewport in pixels
12443    N_n (int) number of words
12444    names (char **) the words (spaces OK, just not multiple lines).
12445                    words in names should be sorted from the farthest
12446                    to the closest
12447    fontGL (void *) the font in use
12448    xyzr (float *) XYZ triplets specifying position of each word in
12449                  SCREEN coordinates.
12450    maxoverlap (float ) a number between 0 and 1:
12451                   0 means a word will be let in if it does not overlap with
12452                     the boundaries of another
12453                   1 means all words will be allowed to show.
12454                   -1 means no thresholding in applied, get a continous
12455                      overlap mask
12456    \ret mask (byte *) A byte mask with '1' where a word should be shown,
12457                       0 otherwise. A NULL could signal an error, but also
12458                       that all words should be displayed.
12459 */
SUMA_WordOverlapMask(int Nwidth,int Nheight,int N_n,char ** names,void * fontGL,float * xyzr,float maxoverlap,byte * usethesewords)12460 byte *SUMA_WordOverlapMask(int Nwidth, int Nheight, int N_n,
12461                            char **names, void *fontGL, float *xyzr,
12462                            float maxoverlap, byte *usethesewords)
12463 {
12464    static char FuncName[]={"SUMA_WordOverlapMask"};
12465    byte **overbuf=NULL, *mask=NULL;
12466    int i, ibuf, jbuf, empt, wh, *ww=NULL, nn, mm, offh, offw;
12467    float pempt;
12468    SUMA_Boolean LocalHead = NOPE;
12469 
12470    SUMA_ENTRY;
12471    SUMA_LHv("Nwidth %d, Nheight %d maxoverlap %f\n"
12472             " Words from CLOSEST to farthest\n",
12473             Nwidth, Nheight, maxoverlap);
12474    overbuf = (byte **)SUMA_allocate2D(Nwidth, Nheight, sizeof(byte));
12475    ww = (int *)SUMA_malloc(N_n*sizeof(int));
12476    mask = (byte *)SUMA_calloc(N_n, sizeof(byte));
12477    wh = SUMA_WordBoxSize(names, N_n, ww, fontGL);
12478    for (i = N_n-1; i>-1; --i) {
12479       if (!(IN_MASK(usethesewords, i))) {
12480          mask[i] = 0.0; continue;
12481       }
12482       ibuf = (int)xyzr[3*i]; jbuf = (int)xyzr[3*i+1];
12483       if (ibuf < 0) ibuf = 0;
12484       if (jbuf < 0) jbuf = 0;
12485       if (ibuf+ww[i]>Nwidth) offw = Nwidth-ibuf;
12486       else offw = ww[i];
12487       if (jbuf+wh>Nheight) offh = Nheight-jbuf;
12488       else offh = wh;
12489       empt = 0;
12490       for (nn=0; nn<offw; ++nn) {
12491          for (mm=0; mm<offh; ++mm) {
12492             if (!overbuf[nn+ibuf][mm+jbuf]) {
12493                ++empt;
12494             }
12495          }
12496       }
12497       pempt = (float)empt/(ww[i]*wh);
12498       if (maxoverlap >= 0.0) {
12499          if (pempt >= 1.0-maxoverlap) { /* deserves keeping, so mark it */
12500             mask[i] = (byte)(pempt*255.0);
12501             for (nn=0; nn<offw; ++nn) {
12502                for (mm=0; mm<offh; ++mm) {
12503                   if (overbuf[nn+ibuf][mm+jbuf] < 255)
12504                         ++overbuf[nn+ibuf][mm+jbuf];
12505                }
12506             }
12507          } else {
12508             mask[i] = 0.0;
12509          }
12510       } else { /* continous marking */
12511          mask[i] = (byte)(pempt*255.0);
12512          for (nn=0; nn<offw; ++nn) {
12513             for (mm=0; mm<offh; ++mm) {
12514                if (overbuf[nn+ibuf][mm+jbuf] < 255)
12515                         ++overbuf[nn+ibuf][mm+jbuf];
12516             }
12517          }
12518       }
12519       SUMA_LHv("%s pempt[%d] %f, mask[%d]=%d bloc=[%d %d], off [%d %d]\n",
12520                names[i], i, pempt, i, mask[i], ibuf,jbuf, offw, offh);
12521 
12522    }
12523 
12524    if (LocalHead) {
12525       FILE *fid = fopen(FuncName,"w");
12526       for (mm=0; mm<Nheight; ++mm) {
12527          for (nn=0; nn<Nwidth; ++nn) {
12528             fprintf(fid,"%d ", overbuf[nn][mm]);
12529          }
12530          fprintf(fid,"\n");
12531       }
12532       fclose(fid); fid = NULL;
12533       SUMA_LHv("To view debugging image:\n"
12534                "  aiv %s\n", FuncName);
12535    }
12536 
12537    SUMA_ifree(ww);
12538    SUMA_free2D((char **)overbuf, Nwidth); overbuf=NULL;
12539 
12540    SUMA_RETURN(mask);
12541 }
12542 
SUMA_LoadImageNIDOnel(NI_element * nel)12543 SUMA_Boolean SUMA_LoadImageNIDOnel(NI_element *nel)
12544 {
12545    static char FuncName[]={"SUMA_LoadImageNIDOnel"};
12546    MRI_IMAGE *im=NULL;
12547    int ir, ic, i1d, i1df, imx, i1d3, i1d4;
12548    byte *rgb = NULL, *imar=NULL;
12549    float alf = 0.0;
12550    char *fname=NULL;
12551    SUMA_Boolean LocalHead = NOPE;
12552 
12553    SUMA_ENTRY;
12554 
12555    if (  !nel ||
12556          (  strcmp(nel->name,"I") &&
12557             strcmp(nel->name,"Tex" ) ) )
12558       SUMA_RETURN(NOPE);
12559 
12560    if (NI_IS_STR_ATTR_EQUAL(nel, "read_status", "read")) SUMA_RETURN(YUP);
12561 
12562    NI_set_attribute(nel,"read_status","fail");
12563 
12564    if (! (fname = SUMA_copy_string(NI_get_attribute(nel,"filename"))) )
12565       SUMA_RETURN(NOPE);
12566    if (!SUMA_search_file(&fname, NULL)) { /* can't find it */
12567       SUMA_free(fname); fname = NULL;
12568       SUMA_RETURN(NOPE);
12569    }
12570    if (!(im = mri_read_just_one(fname))) {
12571       SUMA_S_Errv("Failed to read image %s (READ from %s)\n",
12572                   NI_get_attribute(nel,"filename"),
12573                   fname);
12574       SUMA_free(fname); fname = NULL;
12575       SUMA_RETURN(NOPE);
12576    }
12577 
12578    rgb = MRI_BYTE_PTR(im) ;
12579    NI_SET_INT(nel,"height",im->ny);
12580    NI_SET_INT(nel,"width", im->nx);
12581 
12582    if (im->kind != MRI_rgb && im->kind != MRI_byte) {
12583       SUMA_S_Errv("Image %s (read from %s) must be RGB or byte type.\n",
12584                   NI_get_attribute(nel,"filename"),
12585                   fname);
12586       mri_free(im) ;
12587       SUMA_free(fname); fname = NULL;
12588       SUMA_RETURN(NOPE);
12589    }
12590 
12591    if (LocalHead)
12592       fprintf (SUMA_STDERR,
12593                "%s:\nNx (width) = %d, Ny (height) = %d\n",
12594                FuncName, im->nx, im->ny);
12595 
12596    /* Now you can call  NI_alter_veclen, although all it does
12597    here is set vec_len to the new number ... */
12598    NI_alter_veclen(nel, (int)(im->nx * im->ny * 4));
12599    if (LocalHead) {
12600       SUMA_LH("veclen altered");
12601       SUMA_ShowNel(nel);
12602    }
12603    NI_add_column (nel, NI_BYTE, NULL);
12604    if (!nel->vec[0]) {
12605       SUMA_SL_Crit("Failed to allocate.");
12606       mri_free(im) ;
12607       SUMA_free(fname); fname = NULL;
12608       SUMA_RETURN(NOPE);
12609    }
12610    SUMA_LH("Filling");
12611    imar = (byte *)nel->vec[0];
12612    if (im->kind == MRI_rgb) {
12613       SUMA_LH("RGB");
12614       for (ir = 0; ir < im->ny; ++ir) {
12615          for (ic = 0; ic < im->nx; ++ic) {
12616             i1d = ic + ir * im->nx; /* equivalent 1d index into row
12617                                        major image data */
12618             i1df = ic + (im->ny - ir - 1) * im->nx; /* column flipped index */
12619             i1d4 = 4 * i1d; i1d3 = 3*i1df;
12620             imar[i1d4] = rgb[i1d3];    alf  = (float)imar[i1d4];
12621                   ++i1d3; ++i1d4;
12622             imar[i1d4] = rgb[i1d3];    alf += (float)imar[i1d4];
12623                   ++i1d3; ++i1d4;
12624             imar[i1d4] = rgb[i1d3];    alf += (float)imar[i1d4];                                      ++i1d4;
12625             imar[i1d4] = 200; /* got no alpha to work with*/
12626          }
12627       }
12628    } else if (im->kind == MRI_byte) {  /* inefficient, but easy for now */
12629       SUMA_LH("BYTE");
12630       for (ir = 0; ir < im->ny; ++ir) {
12631          for (ic = 0; ic < im->nx; ++ic) {
12632             i1d = ic + ir * im->nx; /* equivalent 1d index into row
12633                                        major image data */
12634             i1df = ic + (im->ny - ir - 1) * im->nx; /* column flipped index */
12635             i1d4 = 4 * i1d;
12636             imar[i1d4] = (byte)rgb[i1df];
12637                           ++i1d4;
12638             imar[i1d4] = (byte)rgb[i1df];
12639                           ++i1d4;
12640             imar[i1d4] = (byte)rgb[i1df];                                                                   ++i1d4;
12641             imar[i1d4] = (byte)rgb[i1df];
12642          }
12643       }
12644    } else {
12645       SUMA_S_Err("Image must be RGB or byte type.\nShould not be here!");
12646       mri_free(im) ;
12647       SUMA_free(fname); fname = NULL;
12648       SUMA_RETURN(NOPE);
12649    }
12650    if (LocalHead) {
12651       FILE *fid=NULL;
12652       fid = fopen("junk2.img", "w");
12653       SUMA_disp_vecbytemat ( imar, im->nx*im->ny,
12654                            4, 1, SUMA_ROW_MAJOR, fid, NOPE);
12655       fclose(fid);
12656    }
12657 
12658    SUMA_LH("Freedom");
12659    mri_free(im) ; im = NULL;
12660    SUMA_free(fname); fname = NULL;
12661 
12662    NI_set_attribute(nel,"read_status","read");
12663 
12664    SUMA_RETURN(YUP);
12665 }
12666 
12667 #define UseAlphaAndBlend 0   /* to hide calls that would be useful
12668                               for alpha testing and/or blending */
SUMA_DrawImageNIDOnel(NI_element * nel,SUMA_SurfaceObject * default_SO,SUMA_DO_CoordUnits default_coord_units,float * default_color,void * default_font,int default_node,SUMA_SurfaceViewer * sv)12669 SUMA_Boolean SUMA_DrawImageNIDOnel( NI_element *nel,
12670                                     SUMA_SurfaceObject *default_SO,
12671                                     SUMA_DO_CoordUnits default_coord_units,
12672                                     float *default_color,
12673                                     void *default_font, int default_node,
12674                                     SUMA_SurfaceViewer *sv)
12675 {
12676    static char FuncName[]={"SUMA_DrawImageNIDOnel"};
12677    float txloc[3] = {0.0, 0.0, 0.0};
12678    char  *string=NULL, *atr=NULL;
12679    GLfloat rpos[4];
12680    float Dx = 0.0;
12681    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
12682    GLdouble pfront[3] = {0.0, 0.0, 0.0}, pback[3]= {0.0, 0.0, 0.0};
12683    GLboolean valid;
12684    GLint viewport[4];
12685    int orthoreset = 0;
12686    int id=0, is = 0, sz[2]={0, 0};
12687    GLboolean TexOn2D=0, TexOnGenT=0, TexOnGenS=0;
12688    SUMA_SurfaceObject *SO=NULL;
12689    SUMA_DO_CoordUnits coord_units = default_coord_units;
12690 
12691    SUMA_Boolean LocalHead=NOPE;
12692 
12693    SUMA_ENTRY;
12694 
12695    if (!nel || strcmp(nel->name,"I")) SUMA_RETURN(NOPE);
12696 
12697    if (NI_IS_STR_ATTR_EQUAL(nel,"read_status","fail")) {
12698       /* can't be read */
12699       SUMA_RETURN(NOPE);
12700    }
12701 
12702    if (!NI_IS_STR_ATTR_EQUAL(nel,"read_status","read")) { /* read it */
12703       if (!SUMA_LoadImageNIDOnel(nel)) {
12704          SUMA_RETURN(NOPE);
12705       }
12706    }
12707 
12708 
12709    /* has the box size been determined ?*/
12710    NI_GET_INTv(nel,"box_size", sz, 2, LocalHead);
12711    if (!NI_GOT) {
12712       NI_GET_INT(nel,"width", sz[0]);
12713       NI_GET_INT(nel,"height", sz[1]);
12714       NI_SET_INTv(nel,"box_size", sz, 2);
12715    }
12716 
12717    /* set up projection conditions and coordinates */
12718    if (!SUMA_PrepForNIDOnelPlacement(sv, nel, default_SO, default_node,
12719                                      txloc, NULL, sz,
12720                                      &orthoreset, coord_units, NULL, NULL)) {
12721       SUMA_RETURN(NOPE);
12722    }
12723 
12724    /* how about that rendering mode ? */
12725    if (sv->PolyMode != SRM_Fill) {
12726       /* fill it up */
12727       glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
12728    }
12729 
12730    /* texture's on? */
12731    if ((TexOn2D = glIsEnabled(GL_TEXTURE_2D))) {
12732       /* turn off or affect image drawing */
12733       glDisable(GL_TEXTURE_2D);
12734    }
12735    if ((TexOnGenT = glIsEnabled(GL_TEXTURE_GEN_T))) glDisable(GL_TEXTURE_GEN_T);
12736    if ((TexOnGenS = glIsEnabled(GL_TEXTURE_GEN_S)))  glDisable(GL_TEXTURE_GEN_S);
12737 
12738    /* have image, go for it */
12739    SUMA_LHv("Drawing the image for %s at raster pos: %f %f %f\n",
12740             CHECK_NULL_STR(NI_get_attribute(nel, "filename")),
12741             txloc[0], txloc[1], txloc[2]);
12742 
12743    glRasterPos3f( txloc[0], txloc[1], txloc[2]);
12744 
12745    #if UseAlphaAndBlend
12746       initTest = glIsEnabled(GL_ALPHA_TEST);
12747       initBlend = glIsEnabled(GL_BLEND);
12748 
12749       /* here you set up your alpha testing, problem
12750       at the moment, is that image reading routines
12751       provide no alpha. But nel->vec[0] does contain
12752       alpha and thus can be used eventually for that.
12753       Note that parameters for ALPHA_TEST and BLEND
12754       can easily be added to nel in the future*/
12755 
12756       glAlphaFunc(GL_GEQUAL, 0.25); /* this only needs to be called
12757                if it is changed elsewhere. If it is set differently
12758                per image, then we'll need to call it everytime.
12759                I think it is easiest to call it repeatedly...
12760               to set GL_ALPHA_TEST's behaviour. Choose from:
12761               GL_NEVER, GL_LESS, GL_EQUAL, GL_LEQUAL, GL_GREATER, GL_NOTEQUAL,
12762               GL_GEQUAL, and GL_ALWAYS */
12763       glEnable(GL_ALPHA_TEST);
12764 
12765       glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
12766       glEnable(GL_BLEND);
12767    #endif
12768 
12769 
12770    glDrawPixels(sz[0], sz[1], GL_RGBA,
12771                 GL_UNSIGNED_BYTE, nel->vec[0]);
12772 
12773    #if UseAlphaAndBlend
12774       if (initTest == GL_FALSE) glDisable(GL_ALPHA_TEST);
12775       else {
12776          /* need to spend time, putting restoring
12777          glBlendFunc and glAlphaFunc settings before
12778          this function altered them*/
12779       }
12780       if (initBlend == GL_FALSE) glDisable(GL_BLEND);
12781       else {
12782          /* need to spend time, putting restoring
12783          glBlendFunc and glAlphaFunc settings before
12784          this function altered them*/
12785       }
12786    #endif
12787 
12788    if (orthoreset) {/* return value */
12789       /* and just pop what you'd pushed in */
12790       glPopMatrix();
12791    }
12792 
12793    if (sv->PolyMode != SRM_Fill) {/* set fill mode back */
12794       SUMA_SET_GL_RENDER_MODE(sv->PolyMode);
12795    }
12796 
12797    if (TexOn2D) {   /* put it back on if needed */
12798       glEnable(GL_TEXTURE_2D);
12799    }
12800    if (TexOnGenT) glEnable(GL_TEXTURE_GEN_T);
12801    if (TexOnGenS) glEnable(GL_TEXTURE_GEN_S);
12802 
12803    SUMA_RETURN(YUP);
12804 }
12805 
12806 /* Returns parameter that controls what happens when texture
12807   falls on top of vertex with color:
12808    GL_DECAL, GL_REPLACE, GL_MODULATE, GL_BLENDGL_REPLACE, GL_MODULATE */
SUMA_NIDO_TexEnvMode(NI_element * nel,int def)12809 int SUMA_NIDO_TexEnvMode(NI_element *nel, int def)
12810 {
12811    char *atr=NI_get_attribute(nel,"mix_mode");
12812    if (!atr) return(def);
12813    if (!strcmp(atr,"decal")) return(GL_DECAL);
12814    else if (!strcmp(atr,"blend")) return(GL_BLEND);
12815    else if (!strcmp(atr,"replace")) return(GL_REPLACE);
12816    else if (!strcmp(atr,"modulate")) return(GL_MODULATE);
12817    else return(def);
12818 }
SUMA_NIDO_TexCoordGen(NI_element * nel)12819 int SUMA_NIDO_TexCoordGen(NI_element *nel)
12820 {
12821    char *atr=NI_get_attribute(nel,"coord_gen");
12822    if (!atr) return(GL_SPHERE_MAP);
12823    if (!strcmp(atr,"object")) return(GL_OBJECT_LINEAR);
12824    else if (!strcmp(atr,"eye")) return(GL_EYE_LINEAR);
12825    else if (!strcmp(atr,"sphere")) return(GL_SPHERE_MAP);
12826    else return(GL_SPHERE_MAP);
12827 }
SUMA_NIDO_QuadricStyle(NI_element * nel)12828 int SUMA_NIDO_QuadricStyle(NI_element *nel)
12829 {
12830    char *atr=NI_get_attribute(nel,"style");
12831    if (!atr) return(GLU_FILL);
12832    if (!strcmp(atr,"fill")) return(GLU_FILL);
12833    else if (!strcmp(atr,"line")) return(GLU_LINE);
12834    else if (!strcmp(atr,"silhouette")) return(GLU_SILHOUETTE);
12835    else if (!strcmp(atr,"point")) return(GLU_POINT);
12836    else return(GLU_FILL);
12837 }
12838 
SUMA_DrawTextureNIDOnel(NI_element * nel,SUMA_SurfaceObject * default_SO,SUMA_DO_CoordUnits default_coord_units,float * default_color,void * default_font,int default_node,SUMA_SurfaceViewer * sv)12839 SUMA_Boolean SUMA_DrawTextureNIDOnel( NI_element *nel,
12840                                     SUMA_SurfaceObject *default_SO,
12841                                     SUMA_DO_CoordUnits default_coord_units,
12842                                     float *default_color,
12843                                     void *default_font, int default_node,
12844                                     SUMA_SurfaceViewer *sv)
12845 {
12846    static char FuncName[]={"SUMA_DrawTextureNIDOnel"};
12847    float txloc[3] = {0.0, 0.0, 0.0};
12848    float texcoord[12] = {0.0, 0.0, 0.0,
12849                          0.0, 1.0, 0.0,
12850                          1.0, 1.0, 0.0,
12851                          1.0, 0.0, 0.0};
12852    char  *string=NULL, *atr=NULL, *target = NULL;
12853    GLfloat rpos[4];
12854    float Dx = 0.0;
12855    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
12856    GLdouble pfront[3] = {0.0, 0.0, 0.0}, pback[3]= {0.0, 0.0, 0.0};
12857    GLboolean valid;
12858    GLint viewport[4];
12859    int orthoreset = 0;
12860    int id=0, ii = 0, sz[3]={0, 0, 0}, dt = 0, pof=0;
12861    int N_SOlist, SOlist[SUMA_MAX_DISPLAYABLE_OBJECTS];
12862    SUMA_SurfaceObject *SOt=NULL;
12863    static GLuint texName;
12864    SUMA_SurfaceObject *SO=NULL;
12865    SUMA_DO_CoordUnits coord_units = default_coord_units;
12866 
12867    SUMA_Boolean LocalHead=NOPE;
12868 
12869    SUMA_ENTRY;
12870 
12871    if (!nel || strcmp(nel->name,"Tex")) SUMA_RETURN(NOPE);
12872 
12873    if (NI_IS_STR_ATTR_EQUAL(nel,"read_status","fail")) {
12874       /* can't be read */
12875       SUMA_RETURN(NOPE);
12876    }
12877 
12878    if (!NI_IS_STR_ATTR_EQUAL(nel,"read_status","read")) { /* read it */
12879       if (!SUMA_LoadImageNIDOnel(nel)) {
12880          SUMA_RETURN(NOPE);
12881       }
12882    }
12883 
12884 
12885    /* has the box size been determined (only 2 dimensions needed)?*/
12886    NI_GET_INTv(nel,"box_size", sz, 2, LocalHead);
12887    if (!NI_GOT) {
12888       NI_GET_INT(nel,"width", sz[0]);
12889       NI_GET_INT(nel,"height", sz[1]);
12890       NI_SET_INTv(nel,"box_size", sz, 2);
12891    }
12892 
12893    /* set up projection conditions and coordinates */
12894    if (!SUMA_PrepForNIDOnelPlacement(sv, nel, default_SO, default_node,
12895                                      txloc, texcoord, sz,
12896                                      &orthoreset, coord_units, NULL, NULL)) {
12897       SUMA_RETURN(NOPE);
12898    }
12899 
12900    /* how about that rendering mode ? */
12901    if (sv->PolyMode != SRM_Fill) {
12902       /* fill it up */
12903       glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
12904    } else {
12905       /* If you don't turn offset off, FRAME bound texture (afniman.jpg)
12906          won't show ...  ZSS April 2011 */
12907       /* afniman.jpg (in @DO.examples) now does not show up unless
12908       view is in orthographic mode. Behavior might change whether or
12909       not one is in ortho mode. See comment below about turning off
12910       depth test.
12911                                           ZSS Jan 2012 */
12912       if ((pof = glIsEnabled(GL_POLYGON_OFFSET_FILL)))
12913                         glDisable (GL_POLYGON_OFFSET_FILL);
12914    }
12915 
12916 
12917    /* does this have its own coordinates ? */
12918    target = NI_get_attribute(nel,"target");
12919    if (target && strcmp(target, "FRAME")==0) {
12920       SUMA_LH(  "Creating texture, see init pp 359 in \n"
12921                 "OpenGL programming guide, 3rd ed.");
12922       #if 0 /* Not needed anymore, March 2013 */
12923                           /* Frame texture (afniman.jpg in @DO.examples
12924                              had been obscuring meshes no matter where
12925                              it was placed in the Z direction. Not sure
12926                              why but since it is only to be used as
12927                              a background display, undoing GL_DEPTH_TEST
12928                              seemed to do the trick. Jan 2012 */
12929       if ((dt = glIsEnabled(GL_DEPTH_TEST))) glDisable(GL_DEPTH_TEST);
12930       #endif
12931 
12932       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
12933       NI_GET_INT(nel,"texName",texName);
12934       if (!NI_GOT) {
12935          /* Need to generate texture */
12936          glGenTextures(1, &texName);
12937          /* Now store it */
12938          NI_SET_INT(nel,"texName",texName);
12939       }
12940       glBindTexture(GL_TEXTURE_2D, texName);
12941       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT);
12942       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT);
12943       glTexParameteri(  GL_TEXTURE_2D,
12944                         GL_TEXTURE_MAG_FILTER, GL_LINEAR);
12945       glTexParameteri(  GL_TEXTURE_2D,
12946                         GL_TEXTURE_MIN_FILTER, GL_LINEAR);
12947       glTexImage2D(  GL_TEXTURE_2D, 0, GL_RGBA,
12948                      sz[0], sz[1], 0, GL_RGBA,
12949                      GL_UNSIGNED_BYTE, nel->vec[0]);
12950       glEnable(GL_TEXTURE_2D);
12951       glTexEnvf(  GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
12952                   SUMA_NIDO_TexEnvMode(nel, GL_REPLACE));
12953          /* GL_DECAL, GL_REPLACE, GL_MODULATE, GL_BLEND */
12954       glBindTexture(GL_TEXTURE_2D, texName);
12955       SUMA_LHv("Texture as image, texName=%d, filename=%s\n"
12956                    "coords:\n"
12957                    "%.3f %.3f %.3f\n%.3f %.3f %.3f\n"
12958                    "%.3f %.3f %.3f\n%.3f %.3f %.3f\n",
12959                    texName, CHECK_NULL_STR(NI_get_attribute(nel,"filename")),
12960                    texcoord[0], texcoord[1], texcoord[2],
12961                    texcoord[3], texcoord[4], texcoord[5],
12962                    texcoord[6], texcoord[7], texcoord[8],
12963                    texcoord[9], texcoord[10], texcoord[11]);
12964       /* Texture does not belong to surface to be rendered later,
12965       manually generate coordinates*/
12966       glBegin(GL_QUADS);
12967       glTexCoord2f(0.0, 0.0);glVertex3f(texcoord[0], texcoord[1], texcoord[2]);
12968       glTexCoord2f(0.0, 1.0);glVertex3f(texcoord[3], texcoord[4], texcoord[5]);
12969       glTexCoord2f(1.0, 1.0);glVertex3f(texcoord[6], texcoord[7], texcoord[8]);
12970       glTexCoord2f(1.0, 0.0);glVertex3f(texcoord[9], texcoord[10], texcoord[11]);
12971       glEnd();
12972       glFlush();
12973       glDisable(GL_TEXTURE_2D);
12974    } else {
12975       SUMA_LH("Nodebased textures must be set up before the mesh is\n"
12976                "drawn. This is done early in SUMA_DrawMesh() in function\n"
12977                "SUMA_SO_NIDO_Node_Texture()\n");
12978    }
12979 
12980    if (orthoreset) {/* return value */
12981       /* and just pop what you'd pushed in */
12982       glPopMatrix();
12983    }
12984 
12985    if (sv->PolyMode != SRM_Fill) {/* set fill mode back */
12986       SUMA_SET_GL_RENDER_MODE(sv->PolyMode);
12987    } else {
12988       if (pof) glEnable (GL_POLYGON_OFFSET_FILL); /* April 2011  */
12989    }
12990 
12991    if (dt) glEnable(GL_DEPTH_TEST); /* Jan 2012 */
12992 
12993    SUMA_RETURN(YUP);
12994 }
12995 
SUMA_PrepForNIDOnelPlacement(SUMA_SurfaceViewer * sv,NI_element * nel,SUMA_SurfaceObject * default_SO,int default_node,float * txloc,float * texcoord,int * sz,int * orthoreset,SUMA_DO_CoordUnits coord_units,float * xyzoffset,int * jaggedwidths)12996 SUMA_Boolean SUMA_PrepForNIDOnelPlacement (  SUMA_SurfaceViewer *sv,
12997                                              NI_element *nel,
12998                                              SUMA_SurfaceObject *default_SO,
12999                                              int default_node,
13000                                              float *txloc, float *texcoord,
13001                                              int *sz,
13002                                              int *orthoreset,
13003                                              SUMA_DO_CoordUnits coord_units,
13004                                              float *xyzoffset,
13005                                              int *jaggedwidths)
13006 {
13007    static char FuncName[]={"SUMA_PrepForNIDOnelPlacement"};
13008    int id = 0, id3=0, k=0;
13009    char *atr=NULL, *atr_ha=NULL, *atr_va=NULL;
13010    SUMA_SurfaceObject *SO = NULL;
13011    float Ex=0.0, hln=0.0;
13012    GLdouble pfront[3] = {0.0, 0.0, 0.0}, pback[3]= {0.0, 0.0, 0.0};
13013    GLint viewport[4];
13014    static int iwarn=0;
13015    int N_texcoord = 4;
13016    SUMA_Boolean LocalHead = NOPE;
13017 
13018    SUMA_ENTRY;
13019 
13020    *orthoreset = 0;
13021    /* is this node based ?*/
13022    NI_GET_INT(nel, "node", id);
13023    if (!NI_GOT) id = default_node;
13024    if (id >= 0) {
13025       if (coord_units == SUMA_NORM_SCREEN_UNIT && !(iwarn)) {
13026          SUMA_S_Note("It makes litle sense to specify node\n"
13027                      "attribute when coord_type is 'fixed'.\n"
13028                      "This notice will not be issued again.\n");
13029          ++iwarn;
13030       }
13031       /* special surface? */
13032       if ((atr=NI_get_attribute(nel,"SO_label"))) {
13033          SO = SUMA_findSOp_inDOv(
13034                   SUMA_find_SOidcode_from_label(atr,
13035                                  SUMAg_DOv, SUMAg_N_DOv),
13036                                  SUMAg_DOv, SUMAg_N_DOv);
13037       } else { SO = default_SO; }
13038       if (!SO) {
13039          if (atr) {
13040             SUMA_S_Errv("Could not find surface called %s\n",
13041                               atr);
13042          } else {
13043             SUMA_S_Err("Got no daddy");
13044          }
13045          SUMA_RETURN(NOPE);
13046       }
13047       txloc[0] = SO->NodeList[3*id];
13048       txloc[1] = SO->NodeList[3*id+1];
13049       txloc[2] = SO->NodeList[3*id+2];
13050       SUMA_LHv(  "Have surface %s for node %d.\n"
13051                      "[%.3f   %.3f  %.3f]\n",
13052                      SO->Label, id,
13053                      txloc[0], txloc[1], txloc[2]);
13054    } else {
13055       if ((atr =  NI_get_attribute(nel,"p"))) {
13056          int natr = strlen(atr), i=0;
13057          if (natr > 1 && !SUMA_IS_DIGIT(atr[0])) {
13058             for (i=0; i<natr; ++i) {
13059                switch(SUMA_TO_LOWER_C((atr[i]))) {
13060                   case 't':
13061                      txloc[1]=1.0;
13062                      atr_va = "top";
13063                      break;
13064                   case 'b':
13065                      txloc[1]=0.0;
13066                      atr_va = "bot";
13067                      break;
13068                   case 'm':
13069                   case 'c':
13070                      if (i==0) {
13071                         txloc[1]=0.5;
13072                         atr_va = "center";
13073                      } else if (i==1) {
13074                         txloc[0]=0.5;
13075                         atr_ha = "center";
13076                      } else if (i==2) {
13077                         txloc[2]=0.5;
13078                      }
13079                      break;
13080                   case 'l':
13081                      txloc[0]=0.0;
13082                      atr_ha = "left";
13083                      break;
13084                   case 'r':
13085                      if (i<2) {
13086                         txloc[0]=1.0;/* right */
13087                         atr_ha = "right";
13088                      } else  txloc[2]=1.0; /* rear */
13089                      break;
13090                   case 'f': /* front */
13091                      txloc[2]=0.0;
13092                      break;
13093                }
13094             }
13095          } else {
13096             NI_GET_FLOATv(nel,"coord",txloc,3, LocalHead);
13097             atr_va = NI_get_attribute(nel,"v_align");
13098             atr_ha = NI_get_attribute(nel,"h_align");
13099          }
13100       } else {
13101          NI_GET_FLOATv(nel,"coord",txloc,3, LocalHead);
13102          atr_va = NI_get_attribute(nel,"v_align");
13103          atr_ha = NI_get_attribute(nel,"h_align");
13104       }
13105       if (texcoord && NI_get_attribute(nel, "frame_coords")) {
13106          N_texcoord = 4;
13107          NI_GET_FLOATv( nel, "frame_coords",
13108                         texcoord, 3*N_texcoord, LocalHead);
13109          if (!NI_GOT) N_texcoord = 0;
13110       }
13111 
13112       /* If this is screen-based coordinate, do the change,
13113       the function SUMA_NormScreenToWorld assumes that the OpenGL
13114       matrices are set appropriately already */
13115       /* justify */
13116       {
13117          glGetIntegerv(GL_VIEWPORT, viewport);
13118       SUMA_LHv("sz=[%d, %d, %d]\nviewport=[%d %d %d]\natr_ha=%s, atr_va=%s\n",
13119                sz[0], sz[1], sz[2], viewport[0], viewport[1],viewport[2],
13120                atr_ha, atr_va);
13121 
13122          if (xyzoffset) {
13123             xyzoffset[0]=txloc[0];
13124             xyzoffset[1]=txloc[1];
13125             xyzoffset[2]=txloc[2];
13126          }
13127          if ((atr = atr_ha)) {
13128             if (atr[0] == 'c' || atr[0] == 'C') { /* center */
13129                if (!jaggedwidths) {
13130                   txloc[0] = txloc[0] - ((float)sz[0]/2.0 / (float)viewport[2]);
13131                } else { /* align based for first line only,
13132                            not widest part of box */
13133                   txloc[0] = txloc[0] -
13134                            ((float)jaggedwidths[0]/2.0 / (float)viewport[2]);
13135                }
13136             } else if (atr[0] == 'r' || atr[0] == 'R') { /* right */
13137                txloc[0] = txloc[0] - ((float)sz[0] / (float)viewport[2]);
13138             }
13139          }
13140          if (nel->name[0] == 'T') { /* special treatment for text */
13141             if ((atr = atr_va)) {
13142                hln = sz[1]/sz[2]; /* height of one line, recalculated!*/
13143                Ex = (1-sz[2])*hln;  /* shift for text of more than one line */
13144                if (atr[0] == 'c' || atr[0] == 'C') { /* center */
13145                   txloc[1] = txloc[1] *
13146                               (1.0 - ( ((float)hln/2.0 + Ex)  /
13147                                        (float)viewport[3]));
13148                } else if (atr[0] == 't' || atr[0] == 'T') { /* top */
13149                   txloc[1] = txloc[1] *
13150                               (1.0 - ((float)hln / (float)viewport[3]));
13151                } else if ( sz[2] && /* needs work for multiline case*/
13152                      (atr[0] == 'b' || atr[0] == 'B')) {
13153                   txloc[1] = txloc[1] - ( Ex / (float)viewport[3]);
13154                }
13155             }
13156          } else {
13157             if ((atr = atr_va)) {
13158                if (atr[0] == 'c' || atr[0] == 'C') { /* center */
13159                   txloc[1] = txloc[1] - ((float)sz[1]/2.0 / (float)viewport[3]);
13160                } else if (atr[0] == 't' || atr[0] == 'T') { /* top */
13161                   txloc[1] = txloc[1] - ((float)sz[1] / (float)viewport[3]);
13162                }
13163             }
13164          }
13165       }
13166       if (coord_units == SUMA_NORM_SCREEN_UNIT) {
13167          SUMA_LHv("initial coords: [%f %f %f]\n",
13168                   txloc[0], txloc[1], txloc[2]);
13169          for (id=0; id<3;++id) {
13170             if (txloc[id] >= 0.999) txloc[id] = 0.999;
13171                /*else it can get clipped*/
13172             else if (txloc[id] <= 0.001) txloc[id] = 0.001;
13173          }
13174          if (!sv->ortho) {/*  for screen-based drawing,
13175                               you do not want perspective. But no need to do
13176                               this if in ortho mode already since for this
13177                               type of coordinate (SUMA_SCREEN) drawing
13178                               is done before any translation and rotation.
13179                               All one needs is to be sure projection is
13180                               orthographic.
13181                               It is not efficient to keep changing this
13182                               for each text being displayed. But I do not expect
13183                               a lot of those to be displayed. Will see ...
13184                               I could make the calling function send a list of
13185                               nels that ought to be displayed with the same
13186                               projection settings. */
13187             glMatrixMode (GL_PROJECTION);
13188             glPushMatrix();/* start fresh to avoid messing up current setting */
13189             *orthoreset = 1; /* keep track in order to pop matrix later */
13190             SUMA_SET_GL_PROJECTION(sv, 1);
13191          }
13192 
13193          SUMA_NormScreenToWorld(NULL, (double)txloc[0], (double)txloc[1],
13194                              pfront, pback, 0);
13195 
13196          txloc[0] = (float)( pfront[0] +
13197                             (double)txloc[0]*( pback[0] - pfront[0] ) );
13198          txloc[1] = (float)( pfront[1] +
13199                             (double)txloc[1]*( pback[1] - pfront[1] ) );
13200          txloc[2] = (float)( pfront[2] +
13201                             (double)txloc[2]*( pback[2] - pfront[2] ) );
13202 
13203          SUMA_LHv("pfront coords: [%f %f %f]\n"
13204                   "pback  coords: [%f %f %f]\n"
13205                   "txloc  coords: [%f %f %f]\n",
13206                   pfront[0], pfront[1], pfront[2],
13207                   pback[0], pback[1], pback[2],
13208                   txloc[0], txloc[1], txloc[2]);
13209 
13210          /* do the same if you have a list of texture image coordinates */
13211          if (texcoord) {
13212             for (id=0; id<N_texcoord; ++id) {
13213                id3=3*id;
13214                for (k=0;k<3;++k) {
13215                   if       (texcoord[id3+k] > 0.999)
13216                      texcoord[id3+k] = 0.999;
13217                   else if  (texcoord[id3+k] < 0.001)
13218                      texcoord[id3+k] = 0.001;
13219                }
13220                SUMA_NormScreenToWorld( NULL,
13221                                        (double)texcoord[id3  ],
13222                                        (double)texcoord[id3+1],
13223                                        pfront, pback, 0);
13224                texcoord[id3  ]= (float)( pfront[0] +
13225                             (double)texcoord[id3  ]*(pback[0] - pfront[0]) );
13226                texcoord[id3+1]= (float)( pfront[1] +
13227                             (double)texcoord[id3+1]*(pback[1] - pfront[1]) );
13228                texcoord[id3+2]= (float)( pfront[2] +
13229                             (double)texcoord[id3+2]*(pback[2] - pfront[2]) );
13230             }
13231          }
13232       }
13233    }
13234    SUMA_RETURN(YUP);
13235 }
13236 
13237 
13238 /*!
13239    See also SUMA_TextBoxSize
13240 */
SUMA_NIDOtext_LineWidth(char * string,void * font,int * N_lines)13241 int *SUMA_NIDOtext_LineWidth(char *string, void *font, int *N_lines)
13242 {
13243    int is = 0, il=0, *iwidth=NULL;
13244    int Dx=0;
13245 
13246    if (N_lines) *N_lines = 0;
13247    if (!font || !string || !N_lines) return(NULL);
13248 
13249    for (is=0; string && string[is] != '\0'; is++) {
13250       if (string[is] == '\n') *N_lines=*N_lines+1;
13251    }
13252    if (is > 0) *N_lines=*N_lines+1;
13253    if (*N_lines) {
13254       iwidth = (int *)SUMA_calloc(*N_lines, sizeof(int));
13255       Dx = 0; il=0;
13256       for (is=0; string[is] != '\0'; is++) {
13257          if (string[is] == '\n') {
13258             iwidth[il] = Dx;
13259             /*fprintf(stderr,"ZSS: line[%d]=%d\n", il, iwidth[il]);*/
13260             Dx = 0; ++il;
13261          } else {
13262             Dx = Dx+glutBitmapWidth(font, string[is]);
13263          }
13264       }
13265       if (is > 0) {
13266          iwidth[il] = Dx;
13267          /*fprintf(stderr,"ZSS: line[%d]=%d\n", il, iwidth[il]);*/
13268       }
13269    }
13270    return(iwidth);
13271 }
13272 
SUMA_DrawTextNIDOnel(NI_element * nel,SUMA_SurfaceObject * default_SO,SUMA_DO_CoordUnits default_coord_units,float * default_color,void * default_font,int default_node,SUMA_SurfaceViewer * sv)13273 SUMA_Boolean SUMA_DrawTextNIDOnel(  NI_element *nel,
13274                                     SUMA_SurfaceObject *default_SO,
13275                                     SUMA_DO_CoordUnits default_coord_units,
13276                                     float *default_color,
13277                                     void *default_font, int default_node,
13278                                     SUMA_SurfaceViewer *sv)
13279 {
13280    static char FuncName[]={"SUMA_DrawTextNIDOnel"};
13281    char  *string=NULL, *atr=NULL;
13282    GLfloat rpos[4];
13283    float Dx = 0.0;
13284    void *font=NULL;
13285    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
13286    float txloc[3] = {0.0, 0.0, 0.0}, xyzoffset[3]={0.0, 0.0, 0.0};
13287    GLfloat txcol[4], col1[4], col2[4], *col=NULL;
13288    GLboolean valid;
13289    int orthoreset = 0, il=0, *lwidth=NULL, N_lines=0, pass=0,
13290        gl_dt = -1, gl_df = GL_LESS;
13291    int id=0, is = 0, sz[3]={0, 0,0}, newlineopen=0, mmode, TxtShadeMode=0;
13292    SUMA_SurfaceObject *SO=NULL;
13293    SUMA_DO_CoordUnits coord_units = default_coord_units;
13294    SUMA_Boolean LocalHead=NOPE;
13295 
13296    SUMA_ENTRY;
13297 
13298    SUMA_LHv("Called %p\n", nel);
13299 
13300 
13301    if (!nel || strcmp(nel->name,"T")) SUMA_RETURN(NOPE);
13302 
13303    SUMA_LHv(  "default_coord_units %d\n", default_coord_units);
13304 
13305    string = NI_get_attribute(nel,"text");
13306    if (!string || string[0]=='\0') {
13307       /* nothing to write */
13308       SUMA_RETURN(YUP);
13309    }
13310    if ((atr = NI_get_attribute(nel, "font"))) {
13311       if (!(font = SUMA_glutBitmapFont(atr))) {
13312          SUMA_S_Errv("Bad font %s, using default for group\n",
13313                      atr);
13314          font = default_font;
13315       }
13316    } else {
13317       font = default_font;
13318    }
13319 
13320    NI_GET_FLOATv(nel,"col", txcol, 4, LocalHead);
13321 
13322    if (!NI_GOT) {
13323       txcol[0] = default_color[0];
13324       txcol[1] = default_color[1];
13325       txcol[2] = default_color[2];
13326       txcol[3] = default_color[3];
13327    }
13328    if ((atr=NI_get_attribute(nel,"shadow")) && !strcmp(atr,"yes")) {
13329       TxtShadeMode = 1;
13330       if (!(gl_dt = glIsEnabled(GL_DEPTH_TEST))) glEnable(GL_DEPTH_TEST);
13331       glGetIntegerv(GL_DEPTH_FUNC, &gl_df);
13332       glDepthFunc(GL_ALWAYS); /* Need to write into depth buffer or risk
13333                                  getting text overshadowed by other objects.
13334                                  Disabling the text would render text OK
13335                                  without aliasing from shadow but will
13336                                  not update the depth buffer. */
13337       SUMA_LH("SHADE MODE");
13338    } else {
13339       TxtShadeMode = 0;
13340       SUMA_LH("NO SHADE MODE");
13341    }
13342    if (TxtShadeMode) {
13343       SUMA_COPY_VEC(txcol, col1, 4, GLfloat, GLfloat);
13344                   for (is=0;is<3;++is) col1[is] = 1-col1[is];
13345       SUMA_COPY_VEC(txcol, col2, 4, GLfloat, GLfloat);
13346    } else {
13347       SUMA_COPY_VEC(txcol, col1, 4, GLfloat, GLfloat);
13348    }
13349    col1[3]=1.0; col2[3]=1.0;
13350 
13351    /* get the width of each line. Note redundancy with TextBoxSize. */
13352    if (!(lwidth = SUMA_NIDOtext_LineWidth(string, font, &N_lines))) {
13353       SUMA_S_Warn("Could not get linewidths\n");
13354    }
13355 
13356    /* has the box size been determined , 3rd dim is number of lines */
13357    NI_GET_INTv(nel,"box_size", sz, 3, LocalHead);
13358    if (!NI_GOT) {
13359       SUMA_TextBoxSize(NI_get_attribute(nel,"text"), sz, sz+1, sz+2, font);
13360       NI_SET_INTv(nel,"box_size", sz, 3);
13361    }
13362 
13363    glGetIntegerv(GL_MATRIX_MODE, &mmode);
13364    /* set up projection conditions and coordinates */
13365    if (!SUMA_PrepForNIDOnelPlacement(sv, nel, default_SO, default_node,
13366                                      txloc, NULL, sz,
13367                                      &orthoreset, coord_units, xyzoffset,
13368                                      lwidth)) {
13369       SUMA_RETURN(NOPE);
13370    }
13371    pass=0;
13372    do {
13373       if (pass == 0) {
13374          col = col1;
13375       } else {
13376          col = col2;
13377       }
13378    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, col);
13379    glMaterialfv(GL_FRONT, GL_EMISSION, col);
13380       /*turn on emissivity for text*/
13381 
13382    /* Recall: This next call will still subject txloc to the projection
13383       and the modelview matrices! */
13384    glRasterPos3f( txloc[0], txloc[1], txloc[2]);
13385    glGetFloatv(GL_CURRENT_RASTER_POSITION, rpos);
13386    glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
13387    SUMA_LHv("%s: Raster position (%.3f,%.3f, %3f) is %s\n",
13388             FuncName, rpos[0], rpos[1], rpos[2],
13389             valid ? "valid" : "INVALID");
13390 
13391    /* do some text action */
13392    glColor3fv(col);
13393    SUMA_LHv(  "pass %d, col %f %f %f %f text:\n"
13394               ">>>%s<<<\n", pass, col[0], col[1], col[2], col[3], string);
13395 
13396    /* The first line is not properly centered, that should be done
13397       in the PrepForNIDO placement function using lwidth */
13398    il=0;Dx = 0;
13399    for (is=0; string && string[is] != '\0'; is++) {
13400       if (string[is] == '\n') {
13401          if (lwidth) { /* use precomputed distance
13402 			 Problems still occur when going across states, don't know why yet */
13403             Dx = lwidth[il];
13404             if (xyzoffset[0]==0.5 && il<N_lines-1) { /* center next line too */
13405                Dx = (float)(lwidth[il]+lwidth[il+1])/2.0;
13406             }
13407             /*fprintf(stderr,"lwidth[%d]=%d, Dx=%f", il, lwidth[il], Dx);*/
13408          }
13409          glBitmap( 0, 0, 0, 0,
13410                -(float)Dx, -(float) SUMA_glutBitmapFontHeight(font),
13411                   NULL );
13412          Dx = 0; ++il;
13413          newlineopen=0;
13414       } else {
13415          if (pass==1 && !newlineopen) { /* offset for shade */
13416             glBitmap( 0, 0, 0, 0, -1.0, -1.0,  NULL );
13417          }
13418          newlineopen=1;
13419          glutBitmapCharacter(font, string[is]);
13420          if (!lwidth) Dx = Dx+glutBitmapWidth(font, string[is]);
13421       }
13422    }
13423          ++pass; newlineopen=0;
13424    } while (pass<2 && TxtShadeMode);
13425 
13426    #if 0 /* Reset position after last line if it did not
13427             end with \n . Useless for now, but kept here just in case */
13428    if (newlineopen) {
13429       glBitmap( 0, 0, 0, 0,
13430                -(float)Dx, -(float) SUMA_glutBitmapFontHeight(font),
13431                   NULL );
13432    }
13433    #endif
13434    glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
13435       /*turn off emissidity for text*/
13436 
13437    if (orthoreset) {/* return value */
13438       /* and just pop what you'd pushed in */
13439       glPopMatrix();
13440       glMatrixMode(mmode);
13441    }
13442 
13443    glDepthFunc(gl_df);
13444    if (gl_dt == 0) glDisable(GL_DEPTH_TEST);
13445 
13446    if (lwidth) SUMA_free(lwidth); lwidth=NULL;
13447    SUMA_RETURN(YUP);
13448 }
13449 
SUMA_DrawSphereNIDOnel(NI_element * nel,SUMA_SurfaceObject * default_SO,SUMA_DO_CoordUnits default_coord_units,float * default_color,int default_node,SUMA_SurfaceViewer * sv)13450 SUMA_Boolean SUMA_DrawSphereNIDOnel(  NI_element *nel,
13451                                     SUMA_SurfaceObject *default_SO,
13452                                     SUMA_DO_CoordUnits default_coord_units,
13453                                     float *default_color, int default_node,
13454                                     SUMA_SurfaceViewer *sv)
13455 {
13456    static char FuncName[]={"SUMA_DrawSphereNIDOnel"};
13457    char  *string=NULL, *atr=NULL;
13458    GLfloat rpos[4];
13459    float Dx = 0.0;
13460    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
13461    float txloc[3] = {0.0, 0.0, 0.0};
13462    GLfloat txcol[4];
13463    GLfloat rad = 0.0;
13464    int orthoreset = 0;
13465    int id=0, is = 0, sz[3]={0, 0,0}, slices, stacks;
13466    GLfloat origwidth=0.0, LineWidth=2.0;
13467    SUMA_SurfaceObject *SO=NULL;
13468    SUMA_DO_CoordUnits coord_units = default_coord_units;
13469    static GLUquadricObj *sphobj=NULL;
13470    GLenum style=GLU_FILL;
13471    byte AmbDiff = 0; /* Do not turn on ambient and diffuse coloring */
13472    SUMA_Boolean LocalHead=NOPE;
13473 
13474    SUMA_ENTRY;
13475 
13476    if (!nel || strcmp(nel->name,"S")) SUMA_RETURN(NOPE);
13477 
13478    SUMA_LHv(  "default_coord_units %d\n", default_coord_units);
13479 
13480    if (!sphobj) sphobj = gluNewQuadric(); /* This is created once
13481                                              BUT NEVER freed. So technically
13482                                              it is a memory leak */
13483 
13484 
13485    NI_GET_FLOATv(nel,"col", txcol, 4, LocalHead);
13486 
13487    if (!NI_GOT) {
13488       txcol[0] = default_color[0];
13489       txcol[1] = default_color[1];
13490       txcol[2] = default_color[2];
13491       txcol[3] = default_color[3];
13492    } else {
13493       SUMA_LH("Have own color");
13494    }
13495 
13496    /* set up projection conditions and coordinates */
13497    if (!SUMA_PrepForNIDOnelPlacement(sv, nel, default_SO, default_node,
13498                                      txloc, NULL, sz,
13499                                      &orthoreset, coord_units, NULL, NULL)) {
13500       SUMA_RETURN(NOPE);
13501    }
13502 
13503    glGetFloatv(GL_LINE_WIDTH, &origwidth);
13504    NI_GET_FLOAT(nel,"line_width", LineWidth);
13505    if (!NI_GOT) LineWidth = 2;
13506    glLineWidth(LineWidth);
13507 
13508    if (AmbDiff) { /* If this is on, a sphere's color would not match well
13509                      because the mixing of ambient light. Keeping it off
13510                      makes the colors much more consistent.
13511                      Modified thanks to complaint by MSB */
13512       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, txcol);
13513    }  else { /* lights out */
13514       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, NoColor);
13515    }
13516    glMaterialfv(GL_FRONT, GL_EMISSION, txcol);
13517    glColor3fv(txcol);
13518 
13519    SO=default_SO;
13520    NI_GET_FLOAT(nel,"rad", rad);
13521    if (!NI_GOT) {
13522       NI_GET_FLOAT(nel,"rad.ef", rad);
13523       if (!NI_GOT) {
13524          rad = 10;
13525       } else {
13526          if (!SO) {
13527             SUMA_S_Err("Have no surface from which to get avg edge length");
13528             SUMA_RETURN(NOPE);
13529          }
13530          if (!SO->EL) {
13531             if (!SUMA_SurfaceMetrics(SO, "EdgeList", NULL)){
13532                SUMA_S_Err("Failed to create EdgeList. Can't set radius");
13533                SUMA_RETURN(NOPE);
13534             }
13535          }
13536 
13537          rad = rad*SO->EL->AvgLe;
13538       }
13539    }
13540 
13541    NI_GET_INT(nel,"slices", slices);
13542    if (!NI_GOT) slices = 10;
13543    NI_GET_INT(nel,"stacks", stacks);
13544    if (!NI_GOT) stacks = 10;
13545 
13546    style = SUMA_NIDO_QuadricStyle(nel);
13547    gluQuadricDrawStyle (sphobj, style);
13548    if (style == GLU_FILL)
13549       gluQuadricNormals (sphobj , GLU_SMOOTH);
13550    else
13551       gluQuadricNormals (sphobj , GLU_NONE);
13552 
13553    glTranslatef (txloc[0], txloc[1], txloc[2]);
13554    gluSphere(sphobj, rad/* *SUMA_MAX_PAIR(sv->ZoomCompensate, 0.06)
13555                   User set values, not cool to play with dimensions! */,
13556              slices, stacks);
13557    glTranslatef (-txloc[0], -txloc[1], -txloc[2]);
13558 
13559    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, NoColor);
13560    glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
13561    glLineWidth(origwidth);
13562 
13563    glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
13564       /*turn off emissidity */
13565 
13566    if (orthoreset) {/* return value */
13567       /* and just pop what you'd pushed in */
13568       glPopMatrix();
13569    }
13570 
13571    SUMA_RETURN(YUP);
13572 }
13573 
SUMA_Default_SO_4_NIDO(SUMA_NIDO * SDO,SUMA_SurfaceViewer * sv)13574 SUMA_SurfaceObject *SUMA_Default_SO_4_NIDO(SUMA_NIDO *SDO,
13575                                            SUMA_SurfaceViewer *sv)
13576 {
13577    static char FuncName[]={"SUMA_Default_SO_4_NIDO"};
13578    char *atr=NULL, *SOid=NULL;
13579    SUMA_SurfaceObject *default_SO=NULL;
13580    SUMA_Boolean LocalHead = NOPE;
13581 
13582    SUMA_ENTRY;
13583 
13584    if (!SDO) {
13585       fprintf(stderr,"Error %s: NULL pointer.\n", FuncName);
13586       SUMA_RETURN (NULL);
13587    }
13588 
13589 
13590    /* setup defaults based on group settings */
13591    default_SO = NULL;
13592    /* is there a surface in question or could we find a crutch? */
13593    default_SO = SUMA_findSOp_inDOv(
13594                NI_get_attribute(SDO->ngr, "Parent_idcode_str"),
13595                SUMAg_DOv, SUMAg_N_DOv);
13596    SUMA_LHv("default_SO is now %p\n", default_SO);
13597    if (!default_SO) { /* keep trying */
13598       if ((atr = NI_get_attribute(SDO->ngr,"default_SO_label"))) {
13599          if (!strcmp(atr,"CURRENT")) {
13600             SUMA_LH("Getting current SO");
13601             default_SO = SUMA_SV_Focus_SO(sv);
13602             /* last ditch */
13603             if (!default_SO) {
13604                SUMA_LH("No current SO, trying any");
13605                default_SO = SUMA_findanySOp_inDOv(SUMAg_DOv, SUMAg_N_DOv, NULL);
13606             }
13607             if (!default_SO) {
13608                SUMA_S_Err("Could not find any surface to work with \n");
13609                SUMA_RETURN (NOPE);
13610             }
13611          } else {
13612             char *SOid = SUMA_find_SOidcode_from_label(
13613                               atr, SUMAg_DOv, SUMAg_N_DOv);
13614             if (SOid) {
13615                default_SO = SUMA_findSOp_inDOv (SOid, SUMAg_DOv, SUMAg_N_DOv);
13616             }
13617             if (!default_SO) {
13618                SUMA_S_Errv("Could not find surface labeled %s\n", atr);
13619                SUMA_RETURN (NOPE);
13620             }
13621          }
13622       }  else {
13623          SUMA_LH("No default_label, finding Any...");
13624          default_SO = SUMA_findanySOp_inDOv(SUMAg_DOv, SUMAg_N_DOv, NULL);
13625          /* OK if you fail here ... */
13626       }
13627    }
13628 
13629    SUMA_LHv("Default_SO %p\n", default_SO);
13630 
13631    SUMA_RETURN(default_SO);
13632 }
13633 
SUMA_DrawNIDO(SUMA_NIDO * SDO,SUMA_SurfaceViewer * sv)13634 SUMA_Boolean SUMA_DrawNIDO (SUMA_NIDO *SDO, SUMA_SurfaceViewer *sv)
13635 {
13636    static char FuncName[]={"SUMA_DrawNIDO"};
13637    int ip=0;
13638    int is, default_node=-1;
13639    byte *msk=NULL;
13640    SUMA_SurfaceObject *default_SO = NULL;
13641    NI_element *nel=NULL;
13642    NI_group *ngr = NULL;
13643    void * default_font=GLUT_BITMAP_9_BY_15;
13644    float txcol[4] = {0.2, 0.5, 1, 1.0};
13645    float default_color[4] = {0.2, 0.5, 1, 1.0};
13646    SUMA_DO_CoordType coord_type = SUMA_WORLD;
13647    SUMA_DO_CoordUnits default_coord_units = SUMA_WORLD_UNIT;
13648    char *atr=NULL, *eee=NULL;
13649    GLfloat polymode[4]= {-1.0, 0.0, 0.0, 0.0};
13650    static int iwarn=0;
13651    SUMA_Boolean LocalHead = NOPE;
13652 
13653    SUMA_ENTRY;
13654 
13655    if (!SDO) {
13656       fprintf(stderr,"Error %s: NULL pointer.\n", FuncName);
13657       SUMA_RETURN (NOPE);
13658    }
13659 
13660    if (sv && sv->DO_PickMode) {
13661       if (SUMA_ADO_isLabel((SUMA_ALL_DO *)SDO,"AHorseWithNoName")) {
13662          /* viewer label, do not complain */
13663          SUMA_RETURN(YUP);
13664       } else {
13665          SUMA_S_Warnv(
13666             "Function not ready for picking mode on '%s', should be fixed.\n",
13667             SUMA_ADO_sLabel((SUMA_ALL_DO *)SDO));
13668          SUMA_RETURN(YUP);
13669       }
13670    }
13671 
13672 
13673    default_SO = SUMA_Default_SO_4_NIDO(SDO, sv);
13674 
13675    if (SUMA_isNIDO_SurfBased(SDO) && !default_SO) {
13676          SUMA_SL_Err("Object's parent surface not found.");
13677          SUMA_RETURN (NOPE);
13678    }
13679 
13680 
13681    ngr = SDO->ngr;
13682    {
13683 
13684       /* set up group defaults */
13685          polymode[0] = (GLfloat)-1.0;
13686          if ((atr = NI_get_attribute(ngr, "render_mode"))) {
13687             if (!strcmp(atr,"Fill")) {
13688                glGetFloatv(GL_POLYGON_MODE, polymode);
13689                SUMA_SET_GL_RENDER_MODE(SRM_Fill);
13690             } else if (!strcmp(atr,"Line")) {
13691                glGetFloatv(GL_POLYGON_MODE, polymode);
13692                SUMA_SET_GL_RENDER_MODE(SRM_Line);
13693             } else if (!strcmp(atr,"Points")) {
13694                glGetFloatv(GL_POLYGON_MODE, polymode);
13695                SUMA_SET_GL_RENDER_MODE(SRM_Points);
13696             } else if (!strcmp(atr,"Hide")) {
13697                /* I *think* YUP is better than NULL/NOPE 21 Apr 2021 [rickr] */
13698                SUMA_RETURN(YUP);
13699             } else if (!strcmp(atr,"Viewer")) {
13700                glGetFloatv(GL_POLYGON_MODE, polymode);
13701                SUMA_SET_GL_RENDER_MODE(sv->PolyMode);
13702             } else if (atr[0] == '\0' || !strcmp(atr,"Default")) {
13703                /* nothing to do */
13704             } else {
13705                SUMA_S_Warn("Bad render_mode value");
13706             }
13707          }
13708 
13709 
13710          if ((atr = NI_get_attribute(ngr, "default_font"))) {
13711             if (!(default_font = SUMA_glutBitmapFont(atr))) {
13712                SUMA_S_Errv("Bad font %s, using default %s",
13713                            atr,
13714                   SUMA_glutBitmapFontName(SUMA_glutBitmapFont(NULL)));
13715                default_font=SUMA_glutBitmapFont(NULL);
13716             }
13717          }
13718          NI_GET_INT(ngr,"default_node", default_node);
13719          if (!NI_GOT) default_node = -1;
13720 
13721          NI_GET_FLOATv(ngr,"default_color", txcol, 4,LocalHead);
13722          if (NI_GOT) {
13723             default_color[0] = txcol[0];
13724             default_color[1] = txcol[1];
13725             default_color[2] = txcol[2];
13726             default_color[3] = txcol[3];
13727             SUMA_LHv("default_color: [%f %f %f %f]\n",
13728                      default_color[0], default_color[1],
13729                      default_color[2], default_color[3]);
13730          }
13731          if ((atr = NI_get_attribute(ngr, "coord_type"))) {
13732             if ((coord_type = SUMA_CoordType(atr))
13733                  == SUMA_COORD_TYPE_ERROR) {
13734                SUMA_S_Errv("Bad coord_type %s,"
13735                            "using default %s",
13736                            atr,
13737                            SUMA_CoordTypeName(SUMA_CoordType(NULL)));
13738                coord_type = SUMA_CoordType(NULL);
13739             }
13740          }
13741          /* Now set default coordinate units */
13742          if (coord_type == SUMA_WORLD) {
13743             /* if users want object to move, then odds ar
13744             coords are in world units (rotating objects units */
13745             default_coord_units = SUMA_WORLD_UNIT;
13746          } else if (coord_type == SUMA_SCREEN) {
13747             /* If users want object to remain fixed relative to
13748             screen, then odds are coords are in normalized screen
13749             units */
13750             default_coord_units = SUMA_NORM_SCREEN_UNIT;
13751          }
13752          SUMA_LHv("Have coord_type %d and default_coord_units %d\n"
13753                   "default_color = %f %f %f %f\n"
13754                   "Group has %d parts in it.\n",
13755                 coord_type, default_coord_units,
13756                 default_color[0], default_color[1],
13757                 default_color[2], default_color[3],
13758                 SDO->ngr->part_num);
13759    }
13760 
13761    /* loop through the elements */
13762    for( ip=0 ; ip < SDO->ngr->part_num ; ip++ ){
13763       nel = NULL;
13764       switch( SDO->ngr->part_typ[ip] ){
13765          /*-- a sub-group ==> recursion! --*/
13766          case NI_GROUP_TYPE:
13767             break ;
13768          case NI_ELEMENT_TYPE:
13769             nel = (NI_element *)SDO->ngr->part[ip] ;
13770             if (0 && LocalHead)  {
13771                SUMA_ShowNel(nel);
13772             }
13773             break;
13774          default:
13775             SUMA_S_Errv(
13776                "Don't know what to make of this group element %d, ignoring.",
13777                SDO->ngr->part_typ[ip]);
13778             if (LocalHead || !iwarn) {SUMA_ShowNel(SDO->ngr); ++iwarn;}
13779             break;
13780       }
13781       if (nel) { /* something to display */
13782          SUMA_LHv("Attempting to draw %s\n", nel->name);
13783          if (! strcmp(nel->name,"T")) {
13784             if (!SUMA_DrawTextNIDOnel( nel, default_SO,
13785                                        default_coord_units,
13786                                        default_color,
13787                                        default_font, default_node,
13788                                        sv)) {
13789                SUMA_S_Warnv("Failed to draw %s\n", nel->name);
13790             }
13791          } else if (! strcmp(nel->name,"S")) {
13792             if (!SUMA_DrawSphereNIDOnel( nel, default_SO,
13793                                        default_coord_units,
13794                                        default_color,  default_node,
13795                                        sv)) {
13796                SUMA_S_Warnv("Failed to draw %s\n", nel->name);
13797             }
13798          } else if (! strcmp(nel->name,"I")) {
13799             if (!SUMA_DrawImageNIDOnel(nel, default_SO,
13800                                        default_coord_units,
13801                                        default_color,
13802                                        default_font, default_node,
13803                                        sv)) {
13804                SUMA_S_Warnv("Failed to draw %s\n", nel->name);
13805             }
13806          } else if (! strcmp(nel->name,"Tex")) {
13807             if (!SUMA_DrawTextureNIDOnel(nel, default_SO,
13808                                        default_coord_units,
13809                                        default_color,
13810                                        default_font, default_node,
13811                                        sv)) {
13812                SUMA_S_Warnv("Failed to draw %s\n", nel->name);
13813             }
13814          } else if (! strcmp(nel->name,"3DTex")) {
13815             if (SUMAg_CF->Dev) {
13816                SUMA_LH("Going to draw 3DTexture");
13817                if (!SUMA_Draw3DTextureNIDOnel(nel, default_SO,
13818                                           default_coord_units,
13819                                           default_color,
13820                                           default_font, default_node,
13821                                           sv)) {
13822                   SUMA_S_Warnv("Failed to draw %s\n", nel->name);
13823                }
13824                SUMA_LH("Done drawing 3DTexture");
13825             } else {
13826                SUMA_S_Note("3DTex available in developer mode "
13827                            "(suma -dev) mode only.\n");
13828             }
13829          } else if (strcmp(nel->name,"nido_head")) {
13830             if (nel->name[0] != '#') {
13831                SUMA_S_Errv("Not ready for nel->name %s\n", nel->name);
13832             } else {
13833                if (LocalHead)
13834                   SUMA_LHv("Skipping element %s\n", nel->name);
13835             }
13836          }
13837       }
13838 
13839    }
13840 
13841    if (polymode[0]>-1.0) {
13842       glPolygonMode(GL_FRONT_AND_BACK, (GLenum)polymode[0]);
13843    }
13844 
13845    SUMA_RETURN (YUP);
13846 
13847 }
13848 
13849 
13850 /*!
13851    A macro to be inserted into SUMA_SortedAxisSegmentList's switch statement
13852 */
13853 #define SUMA_SORTED_AXIS_WORKS { \
13854             ASIp->Quad[0] = Q[ASIp->PointIndex[0]];   \
13855             ASIp->Quad[1] = Q[ASIp->PointIndex[1]];   \
13856             for (i=0;i<3;++i) d[i] = \
13857                ( P[ASIp->PointIndex[1]][i] - P[ASIp->PointIndex[0]][i] ); \
13858             SUMA_NORM_VEC (d, 3, ASIp->world_length); \
13859             for (i=0; i<3;++i) { /* projection direction along screen */ \
13860                ASIp->ScreenProj[i] = S[ASIp->PointIndex[1]*3+i] -   \
13861                                     S[ASIp->PointIndex[0]*3+i];    \
13862                if (i<2) { /* Don't want to use screen z depth */\
13863                   ASIp->ScreenProj_xy_length = ASIp->ScreenProj_xy_length + \
13864                                     ASIp->ScreenProj[i]*ASIp->ScreenProj[i]; \
13865                }  \
13866             }  \
13867             ASIp->ScreenProj_xy_length = sqrt(ASIp->ScreenProj_xy_length);  \
13868             for (i=0;i<3;++i) d[i] = \
13869                ( ( P[ASIp->PointIndex[0]][i] + P[ASIp->PointIndex[1]][i] ) \
13870                         / 2.0 - sv->Pcenter_close[i] ); \
13871             SUMA_NORM_VEC (d, 3, ASIp->MidSegDist);   \
13872             for (i=0;i<2;++i) d[i] = ( S[ASIp->PointIndex[0]*3+i] - LLC[i] );  \
13873             SUMA_NORM_VEC (d, 2, d1);  \
13874             for (i=0;i<2;++i) d[i] = ( S[ASIp->PointIndex[1]*3+i] - LLC[i] );  \
13875             SUMA_NORM_VEC (d, 2, d2);  \
13876             if (d1 < d2) { \
13877                ASIp->LLCclosestDist = d1; ASIp->LLCclosestPoint = 0; \
13878             }  \
13879             else { ASIp->LLCclosestDist = d2; ASIp->LLCclosestPoint = 1; } \
13880             for (i=0;i<3;++i) d[i] = \
13881                   ( C[ASIp->FaceIndex[0]][i] - sv->Pcenter_close[i] ); \
13882             SUMA_NORM_VEC (d, 3, d1);  \
13883             for (i=0;i<3;++i) d[i] = \
13884                   ( C[ASIp->FaceIndex[1]][i] - sv->Pcenter_close[i] ); \
13885             SUMA_NORM_VEC (d, 3, d2); \
13886             if (d1 < d2) ASIp->MidFaceDist = d1; else ASIp->MidFaceDist = d2;  \
13887             SUMA_COPY_VEC(P[ASIp->PointIndex[0]], ASIp->P1, 3, double, double); \
13888             SUMA_COPY_VEC(P[ASIp->PointIndex[1]], ASIp->P2, 3, double, double); \
13889             ASIp->TxOff[0] = (-ASIp->tick2_dir[0] - ASIp->tick1_dir[0]);   \
13890             ASIp->TxOff[1] = (-ASIp->tick2_dir[1] - ASIp->tick1_dir[1]);   \
13891             ASIp->TxOff[2] = (-ASIp->tick2_dir[2] - ASIp->tick1_dir[2]);   \
13892             SUMA_NORM_VEC (ASIp->TxOff, 3, d1); /* DON'T USE /= in next line! */\
13893             ASIp->TxOff[0] = ASIp->TxOff[0] / d1; \
13894             ASIp->TxOff[1] = ASIp->TxOff[1] / d1; \
13895             ASIp->TxOff[2] = ASIp->TxOff[2] / d1; \
13896 }
13897 
13898 
13899 /*!
13900 
13901    \param opt (SUMA_SORT_BOX_AXIS_OPTION) Specifies how sorting of segments is done in the list.
13902 
13903    Creates the various segments needed to form a box axis.
13904 
13905    - Your job is to free DList's elements and destroy and free DList after the function returns.
13906 
13907    \sa Labbook NIH-4 page 21 for annotation of Box Axis ....
13908 */
SUMA_SortedAxisSegmentList(SUMA_SurfaceViewer * sv,SUMA_Axis * Ax,SUMA_SORT_BOX_AXIS_OPTION opt)13909 DList *SUMA_SortedAxisSegmentList (SUMA_SurfaceViewer *sv,
13910                                    SUMA_Axis *Ax, SUMA_SORT_BOX_AXIS_OPTION opt)
13911 {
13912    static char FuncName[]={"SUMA_SortedAxisSegmentList"};
13913    double P[8][3], C[6][3], d[3], d1, d2, S[24],
13914           world_length;
13915    int Q[8];
13916    static double xAx[3] = {1, 0, 0}, yAx[3] = { 0, 1, 0 }, zAx[3] = {0, 0, 1},
13917                  LLC[3] = {0, 0, 0};
13918    static double mxAx[3] = {-1, 0, 0}, myAx[3] = { 0, -1, 0 },
13919                  mzAx[3] = {0, 0, -1};
13920    DList *list = NULL;
13921    DListElmt *Elm = NULL;
13922    SUMA_Boolean Found = NOPE;
13923    SUMA_AxisSegmentInfo **ASI = NULL, *ASIp=NULL, *ASIptmp=NULL;
13924    int i=0, j=0;
13925    SUMA_Boolean LocalHead = NOPE;
13926 
13927    SUMA_ENTRY;
13928 
13929    LLC[1] = (double)sv->X->aHEIGHT;
13930    if (Ax->atype != SUMA_SCALE_BOX) {
13931       SUMA_S_Err("Nothing to be done here.\nFor Scale Box type axis only.");
13932       SUMA_RETURN(NULL);
13933    }
13934 
13935    /* form box corner points */
13936    SUMA_BOX_CORNER_POINTS_FROM_AXIS(Ax, P);
13937 
13938    /* figure out equivalent screen coords */
13939    SUMA_World2ScreenCoords (sv, 8, (double *)P, S, Q, 0, YUP);
13940 
13941    /* form plane centers */
13942    for (i=0; i<3; ++i) { /* Plane a, b, f, e*/
13943       C[0][i] = ( P[0][i] + P[1][i] + P[5][i] + P[4][i] ) / 4.0;
13944    }
13945    for (i=0; i<3; ++i) {  /* Plane a, b, d, c*/
13946       C[1][i] = ( P[0][i] + P[1][i] + P[3][i] + P[2][i] ) / 4.0;
13947    }
13948    for (i=0; i<3; ++i) {  /* Plane a, c, g, e*/
13949       C[2][i] = ( P[0][i] + P[2][i] + P[6][i] + P[4][i] ) / 4.0;
13950    }
13951    for (i=0; i<3; ++i) {  /* Plane e, f, h, g*/
13952       C[3][i] = ( P[4][i] + P[5][i] + P[7][i] + P[6][i] ) / 4.0;
13953    }
13954    for (i=0; i<3; ++i) {  /* Plane b, d, h, f*/
13955       C[4][i] = ( P[1][i] + P[3][i] + P[7][i] + P[5][i] ) / 4.0;
13956    }
13957    for (i=0; i<3; ++i) {  /* Plane c, d, h, g*/
13958       C[5][i] = ( P[2][i] + P[3][i] + P[7][i] + P[6][i] ) / 4.0;
13959    }
13960 
13961    /* for (i=0; i<3; ++i) sv->Ch->c[i] = sv->Plist_close[i];  */
13962    if (LocalHead) {
13963       fprintf (SUMA_STDERR,"%s: sv->Pcenter_close = [%f %f %f]\n",
13964                            FuncName, sv->Pcenter_close[0], sv->Pcenter_close[1],
13965                            sv->Pcenter_close[2]); }
13966    ASI = (SUMA_AxisSegmentInfo **)
13967       SUMA_calloc(12, sizeof(SUMA_AxisSegmentInfo *));
13968 
13969    for (j=0; j<12; ++j) {
13970       ASI[j] = (SUMA_AxisSegmentInfo *)
13971                   SUMA_calloc(1,sizeof(SUMA_AxisSegmentInfo ));
13972       ASIp = ASI[j];
13973       ASIp->SegIndex = j;
13974       switch (j) {
13975          case 0: /* seg, 1 */
13976             ASIp->AxisDim = 0; /* X axis */
13977             ASIp->PointIndex[0] = 0; /* a */
13978             ASIp->PointIndex[1] = 1; /* b */
13979             ASIp->FaceIndex[0] = 0; /* Plane a, b, f, e */
13980             ASIp->FaceIndex[1] = 1; /* Plane a, b, d, c */
13981             SUMA_COPY_VEC(zAx, ASIp->tick1_dir, 3, double, double);
13982             SUMA_COPY_VEC(yAx, ASIp->tick2_dir, 3, double, double);
13983             SUMA_SORTED_AXIS_WORKS;
13984             break;
13985          case 1: /* Seg 2 */
13986             ASIp->AxisDim = 0;  /* X axis */
13987             ASIp->PointIndex[0] = 2; /* c */
13988             ASIp->PointIndex[1] = 3; /* d */
13989             ASIp->FaceIndex[0] = 1; /* Plane a, b, d, c */
13990             ASIp->FaceIndex[1] = 5; /* Plane c, d, h, g */
13991             SUMA_COPY_VEC(zAx, ASIp->tick1_dir, 3, double, double);
13992             SUMA_COPY_VEC(myAx, ASIp->tick2_dir, 3, double, double);
13993             SUMA_SORTED_AXIS_WORKS;
13994             break;
13995          case 2: /* Seg 3 */
13996             ASIp->AxisDim = 0;  /* X axis */
13997             ASIp->PointIndex[0] = 4; /* e */
13998             ASIp->PointIndex[1] = 5; /* f */
13999             ASIp->FaceIndex[0] = 0; /* Plane a, b, f, e*/
14000             ASIp->FaceIndex[1] = 3; /* Plane e, f, h, g*/
14001             SUMA_COPY_VEC(mzAx, ASIp->tick1_dir, 3, double, double);
14002             SUMA_COPY_VEC(yAx, ASIp->tick2_dir, 3, double, double);
14003             SUMA_SORTED_AXIS_WORKS;
14004             break;
14005          case 3: /* Seg 4 */
14006             ASIp->AxisDim = 0;  /* X axis */
14007             ASIp->PointIndex[0] = 6; /* g */
14008             ASIp->PointIndex[1] = 7; /* h */
14009             ASIp->FaceIndex[0] = 5; /* Plane c, d, h, g*/
14010             ASIp->FaceIndex[1] = 3; /* Plane e, f, h, g*/
14011             SUMA_COPY_VEC(mzAx, ASIp->tick1_dir, 3, double, double);
14012             SUMA_COPY_VEC(myAx, ASIp->tick2_dir, 3, double, double);
14013             SUMA_SORTED_AXIS_WORKS;
14014             break;
14015          case 4: /* seg 5*/
14016             ASIp->AxisDim = 1; /* Y axis */
14017             ASIp->PointIndex[0] = 0; /* a */
14018             ASIp->PointIndex[1] = 2; /* c */
14019             ASIp->FaceIndex[0] = 1; /* Plane a, b, d, c*/
14020             ASIp->FaceIndex[1] = 2; /* Plane a, c, g, e*/
14021             SUMA_COPY_VEC(xAx, ASIp->tick1_dir, 3, double, double);
14022             SUMA_COPY_VEC(zAx, ASIp->tick2_dir, 3, double, double);
14023             SUMA_SORTED_AXIS_WORKS;
14024             break;
14025          case 5: /* seg 6*/
14026             ASIp->AxisDim = 1; /* Y axis */
14027             ASIp->PointIndex[0] = 1; /* b */
14028             ASIp->PointIndex[1] = 3; /* d */
14029             ASIp->FaceIndex[0] = 1; /* Plane a, b, d, c*/
14030             ASIp->FaceIndex[1] = 4; /* Plane b, d, h, f*/
14031             SUMA_COPY_VEC(mxAx, ASIp->tick1_dir, 3, double, double);
14032             SUMA_COPY_VEC(zAx, ASIp->tick2_dir, 3, double, double);
14033             SUMA_SORTED_AXIS_WORKS;
14034             break;
14035          case 6: /* seg 7*/
14036             ASIp->AxisDim = 1; /* Y axis */
14037             ASIp->PointIndex[0] = 4; /* e */
14038             ASIp->PointIndex[1] = 6; /* g */
14039             ASIp->FaceIndex[0] = 2; /* Plane a, c, g, e*/
14040             ASIp->FaceIndex[1] = 3; /* Plane e, f, h, g*/
14041             SUMA_COPY_VEC(xAx, ASIp->tick1_dir, 3, double, double);
14042             SUMA_COPY_VEC(mzAx, ASIp->tick2_dir, 3, double, double);
14043             SUMA_SORTED_AXIS_WORKS;
14044             break;
14045          case 7: /* seg 8*/
14046             ASIp->AxisDim = 1; /* Y axis */
14047             ASIp->PointIndex[0] = 5; /* f */
14048             ASIp->PointIndex[1] = 7; /* h */
14049             ASIp->FaceIndex[0] = 3; /* Plane e, f, h, g*/
14050             ASIp->FaceIndex[1] = 4; /* Plane b, d, h, f*/
14051             SUMA_COPY_VEC(mxAx, ASIp->tick1_dir, 3, double, double);
14052             SUMA_COPY_VEC(mzAx, ASIp->tick2_dir, 3, double, double);
14053             SUMA_SORTED_AXIS_WORKS;
14054             break;
14055          case 8: /* seg 9*/
14056             ASIp->AxisDim = 2; /* Z axis */
14057             ASIp->PointIndex[0] = 0; /* a */
14058             ASIp->PointIndex[1] = 4; /* e */
14059             ASIp->FaceIndex[0] = 0; /* Plane a, b, f, e */
14060             ASIp->FaceIndex[1] = 2; /* Plane a, c, g, e */
14061             SUMA_COPY_VEC(xAx, ASIp->tick1_dir, 3, double, double);
14062             SUMA_COPY_VEC(yAx, ASIp->tick2_dir, 3, double, double);
14063             SUMA_SORTED_AXIS_WORKS;
14064             break;
14065          case 9: /* seg 10*/
14066             ASIp->AxisDim = 2; /* Z axis */
14067             ASIp->PointIndex[0] = 1; /* b */
14068             ASIp->PointIndex[1] = 5; /* f */
14069             ASIp->FaceIndex[0] = 0; /* Plane a, b, f, e*/
14070             ASIp->FaceIndex[1] = 4; /* Plane b, d, h, f*/
14071             SUMA_COPY_VEC(mxAx, ASIp->tick1_dir, 3, double, double);
14072             SUMA_COPY_VEC(yAx, ASIp->tick2_dir, 3, double, double);
14073             SUMA_SORTED_AXIS_WORKS;
14074             break;
14075          case 10: /* seg 11*/
14076             ASIp->AxisDim = 2; /* Z axis */
14077             ASIp->PointIndex[0] = 2; /* c */
14078             ASIp->PointIndex[1] = 6; /* g */
14079             ASIp->FaceIndex[0] = 5; /* Plane c, d, h, g*/
14080             ASIp->FaceIndex[1] = 2; /* Plane a, c, g, e*/
14081             SUMA_COPY_VEC(xAx, ASIp->tick1_dir, 3, double, double);
14082             SUMA_COPY_VEC(myAx, ASIp->tick2_dir, 3, double, double);
14083             SUMA_SORTED_AXIS_WORKS;
14084             break;
14085          case 11: /* seg 12*/
14086             ASIp->AxisDim = 2; /* Z axis */
14087             ASIp->PointIndex[0] = 3; /* d */
14088             ASIp->PointIndex[1] = 7; /* h */
14089             ASIp->FaceIndex[0] = 5; /* Plane c, d, h, g*/
14090             ASIp->FaceIndex[1] = 4; /* Plane b, d, h, f*/
14091             SUMA_COPY_VEC(mxAx, ASIp->tick1_dir, 3, double, double);
14092             SUMA_COPY_VEC(myAx, ASIp->tick2_dir, 3, double, double);
14093             SUMA_SORTED_AXIS_WORKS;
14094             break;
14095       }
14096    }
14097 
14098    list = (DList *)SUMA_calloc(1,sizeof(DList));
14099    dlist_init(list, NULL);
14100    for (i=0; i<12; ++i) {
14101       ASIp = ASI[i];
14102       if (!list->size) {
14103          dlist_ins_next(list, dlist_tail(list), (void*)ASIp);
14104       } else {
14105          Elm = NULL;
14106          do {
14107             Found = NOPE;
14108             if (!Elm) {
14109                Elm = dlist_head(list);
14110             } else {
14111                Elm = dlist_next(Elm);
14112             }
14113 
14114             ASIptmp = (SUMA_AxisSegmentInfo *)Elm->data;
14115                switch (opt) {
14116                   case SUMA_BY_SEGMENT_DISTANCE:
14117                      if (ASIp->MidSegDist < ASIptmp->MidSegDist) {
14118                         dlist_ins_prev(list, Elm, (void *)ASIp);
14119                         Found = YUP;
14120                      }
14121                      break;
14122                   case SUMA_BY_PLANE_DISTANCE:
14123                      if (ASIp->MidFaceDist < ASIptmp->MidFaceDist) {
14124                         dlist_ins_prev(list, Elm, (void *)ASIp);
14125                         Found = YUP;
14126                      }
14127                      break;
14128                   case SUMA_SORT_BY_LLC_DISTANCE:
14129                      if (ASIp->LLCclosestDist < ASIptmp->LLCclosestDist) {
14130                         dlist_ins_prev(list, Elm, (void *)ASIp);
14131                         Found = YUP;
14132                      }
14133                      break;
14134                   case SUMA_SORT_BY_LL_QUAD:
14135                      if (ASIp->Quad[0] == SUMA_LOWER_LEFT_SCREEN ||
14136                          ASIp->Quad[1] == SUMA_LOWER_LEFT_SCREEN) {
14137                         SUMA_LH("Found a LLS");
14138                         dlist_ins_prev(list, dlist_head(list), (void *)ASIp);
14139                         Found = YUP;
14140                      }else {
14141                         dlist_ins_next(list, dlist_tail(list), (void *)ASIp);
14142                         Found = YUP;
14143                      }
14144                      break;
14145                   case SUMA_NO_SORT:
14146                      dlist_ins_next(list, Elm, (void *)ASIp);
14147                      Found = YUP;
14148                      break;
14149                   default:
14150                      SUMA_S_Err("Whatchyoutalkingboutwillis?\n"
14151                                 "Bad, bad bad bad.");
14152                      SUMA_RETURN(NULL);
14153                }
14154                if (!Found && Elm == dlist_tail(list)) {
14155                   dlist_ins_next(list, Elm, (void *)ASIp);
14156                   Found = YUP;
14157                }
14158             } while (!Found);
14159       }
14160 
14161    }
14162    if (LocalHead) {
14163       Elm = NULL;
14164       i = 0;
14165       fprintf (SUMA_STDERR,"%s: Sorting by %d order\n", FuncName, opt);
14166       do {
14167          if (!Elm) {
14168             Elm = dlist_head(list);
14169          } else {
14170             Elm = dlist_next(Elm);
14171          }
14172          ASIp = (SUMA_AxisSegmentInfo *)Elm->data;
14173          if (LocalHead) fprintf (SUMA_STDERR,"%s:\ni %d\ttype %d\tMidSegDist %f\tMidFaceDist %f\tQuads[%d, %d]\t world_length, screen_length_x, screen_length_y = [%.2f %.2f %.2f]\n",
14174                      FuncName, i, ASIp->AxisDim, ASIp->MidSegDist, ASIp->MidFaceDist, ASIp->Quad[0], ASIp->Quad[1], ASIp->world_length, ASIp->ScreenProj[0], ASIp->ScreenProj[1]);
14175          ++i;
14176       } while(Elm != dlist_tail(list));
14177    }
14178    SUMA_free(ASI); ASI = NULL;
14179    SUMA_LH("Returning");
14180    SUMA_RETURN(list);
14181 }
14182 
SUMA_ScreenProjAngle(SUMA_AxisSegmentInfo * asi0,SUMA_AxisSegmentInfo * asi1)14183 double SUMA_ScreenProjAngle(SUMA_AxisSegmentInfo *asi0,
14184                             SUMA_AxisSegmentInfo *asi1)
14185 {
14186    int i=0;
14187    double u[2], dotdot=0.0;
14188    if (!asi0 || !asi1) return(dotdot);
14189    for (i=0; i<2; ++i) {
14190         dotdot += asi1->ScreenProj[i]/asi1->ScreenProj_xy_length*
14191                   asi0->ScreenProj[i]/asi0->ScreenProj_xy_length;                   }
14192    return(fabs(dotdot));
14193 }
14194 
14195 /*!
14196    \sa Labbook NIH-4 page 21 for annotation of Box Axis ....
14197 */
SUMA_DrawAxis(SUMA_Axis * Ax,SUMA_SurfaceViewer * sv)14198 SUMA_Boolean SUMA_DrawAxis (SUMA_Axis* Ax, SUMA_SurfaceViewer *sv)
14199 {
14200    static char FuncName[]={"SUMA_DrawAxis"};
14201    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
14202    double P1[3], P2[3], cP[8][3], SC[12][3], d[12];
14203    int i, N_Ax, fst=-1, sec=-1, thr=-1;
14204    DList *slist=NULL;
14205    DListElmt *Elm=NULL;
14206    SUMA_AxisSegmentInfo *ASI = NULL;
14207    SUMA_AxisSegmentInfo *ASIv[3] = { NULL, NULL, NULL };
14208    SUMA_Boolean ShowTxt[3];
14209    float coslim = 0.9;
14210    SUMA_Boolean LocalHead = NOPE;
14211 
14212    SUMA_ENTRY;
14213 
14214    if (sv && sv->DO_PickMode) {
14215       SUMA_LH("DrawAxis not for do picking mode");
14216       SUMA_RETURN(YUP); /* this condition is never fatal */
14217    }
14218 
14219    if (!Ax) {
14220       SUMA_SL_Err("Null Axis!");
14221       SUMA_RETURN(NOPE);
14222    }
14223 
14224    glLineWidth(Ax->LineWidth);
14225    switch (Ax->Stipple) {
14226       case SUMA_DASHED_LINE:
14227          glEnable(GL_LINE_STIPPLE);
14228          glLineStipple (1, 0x00FF); /* dashed, see OpenGL Prog guide, page 55 */
14229          break;
14230       case SUMA_SOLID_LINE:
14231          break;
14232       default:
14233          fprintf(stderr,"Error SUMA_DrawAxis: Unrecognized Stipple option\n");
14234          SUMA_RETURN(NOPE);
14235    }
14236 
14237    switch (Ax->atype) {
14238       case SUMA_STD_ZERO_CENTERED:
14239          SUMA_LHv("SUMA_STD_ZERO_CENTERED at %f %f %f\n",
14240                   Ax->Center[0], Ax->Center[1], Ax->Center[2]);
14241          glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor);
14242             /* turn off ambient and diffuse components */
14243          glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
14244 
14245          glMaterialfv(GL_FRONT, GL_EMISSION, Ax->XaxisColor);
14246             /*turn on emissivity for axis*/
14247          glBegin(GL_LINES);
14248          glVertex3f(-Ax->XYZspan[0]+Ax->Center[0], Ax->Center[1], Ax->Center[2]);
14249          glVertex3f(Ax->XYZspan[0]+Ax->Center[0], Ax->Center[1], Ax->Center[2]);
14250          glEnd();
14251 
14252          glMaterialfv(GL_FRONT, GL_EMISSION, Ax->YaxisColor);
14253             /*turn on emissivity for axis*/
14254          glBegin(GL_LINES);
14255          glVertex3f(Ax->Center[0], -Ax->XYZspan[1]+Ax->Center[1], Ax->Center[2]);
14256          glVertex3f(Ax->Center[0], +Ax->XYZspan[1]+Ax->Center[1], Ax->Center[2]);
14257          glEnd();
14258 
14259          glMaterialfv(GL_FRONT, GL_EMISSION, Ax->ZaxisColor);
14260             /*turn on emissivity for axis*/
14261          glBegin(GL_LINES);
14262          glVertex3f(Ax->Center[0], Ax->Center[1], -Ax->XYZspan[2]+Ax->Center[2]);
14263          glVertex3f(Ax->Center[0], Ax->Center[1], Ax->XYZspan[2]+Ax->Center[2]);
14264          glEnd();
14265 
14266          glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, NoColor);
14267             /*turn off emissivity for axis*/
14268 
14269          break;
14270       case SUMA_SCALE_BOX:
14271          /* Sort segments by distance from screen center*/
14272          slist = SUMA_SortedAxisSegmentList (sv , Ax, SUMA_SORT_BY_LLC_DISTANCE);
14273             /* - when using SUMA_BY_PLANE_DISTANCE, it makes sense to show
14274                the first 4 segments, but you have no perception of the depth
14275                - when using SUMA_NO_SORT, show all 12 segments so you'll see
14276                  the box
14277                - The world distance thingy does not quite work because because
14278                  the plane you want to hide is the one opposite to the one
14279                  closest to your face. That plane is not necessarily the farthest
14280                  from sv->Pcenter_close, perhaps what you need to do is
14281                  define the lower left point of the box and allow for either a
14282                  boxed axis or a 3d axis from the lower left corner....
14283                - So I am now using the screen coordinates
14284                   SUMA_SORT_BY_LLC_DISTANCE and SUMA_SORT_BY_LL_QUAD,
14285                  and sorting by SUMA_SORT_BY_LLC_DISTANCE works best.
14286                  You can just show the first 3 axis and you're cool, for most
14287                  angles.
14288                - You also need a pixels/mm number to decide on where to put the
14289                  text.*/
14290 
14291          if (sv->ShowWorldAxis == SUMA_THREE_WAX ||
14292              sv->ShowWorldAxis == SUMA_THREE_TEXT_WAX) N_Ax = 3;
14293          else N_Ax = slist->size;
14294 
14295          /* go through list first and decide which get text */
14296          ShowTxt[0]=NOPE; ShowTxt[1]=NOPE; ShowTxt[2]=NOPE;
14297          if (sv->ShowWorldAxis == SUMA_THREE_TEXT_WAX ||
14298              sv->ShowWorldAxis == SUMA_BOX_TEXT_WAX) {
14299             Elm = dlist_head(slist); i = 0;
14300             do {
14301                if (!(ASIv[i]=(SUMA_AxisSegmentInfo *)Elm->data)) {
14302                   SUMA_S_Errv("Unexpected nullity at i=%d\n",i);
14303                   SUMA_RETURN(NOPE);
14304                }
14305                if (Elm != dlist_tail(slist)) {
14306                   Elm = dlist_next(Elm);
14307                } else {
14308                   Elm = NULL;
14309                }
14310                ++i;
14311             } while (i < 3 && Elm);
14312             if (i < 3) {
14313                SUMA_S_Errv("Unexpected i = %d\n", i);
14314                SUMA_RETURN(NOPE);
14315             }
14316             if (ASIv[0]->ScreenProj_xy_length >= ASIv[1]->ScreenProj_xy_length &&
14317                 ASIv[0]->ScreenProj_xy_length >= ASIv[2]->ScreenProj_xy_length) {
14318                fst = 0;
14319                if (ASIv[1]->ScreenProj_xy_length >
14320                                           ASIv[2]->ScreenProj_xy_length){
14321                   sec = 1; thr = 2;
14322                } else {
14323                   sec = 2; thr = 1;
14324                }
14325             }
14326             if (ASIv[1]->ScreenProj_xy_length >= ASIv[0]->ScreenProj_xy_length &&
14327                 ASIv[1]->ScreenProj_xy_length >= ASIv[2]->ScreenProj_xy_length) {
14328                fst = 1;
14329                if (ASIv[0]->ScreenProj_xy_length >
14330                                           ASIv[2]->ScreenProj_xy_length){
14331                   sec = 0; thr = 2;
14332                } else {
14333                   sec = 2; thr = 0;
14334                }
14335             }
14336             if (ASIv[2]->ScreenProj_xy_length >= ASIv[0]->ScreenProj_xy_length &&
14337                 ASIv[2]->ScreenProj_xy_length >= ASIv[1]->ScreenProj_xy_length) {
14338                fst = 2;
14339                if (ASIv[0]->ScreenProj_xy_length >
14340                                           ASIv[1]->ScreenProj_xy_length){
14341                   sec = 0; thr = 1;
14342                } else {
14343                   sec = 1; thr = 0;
14344                }
14345             }
14346             /* always show first */
14347             ShowTxt[fst]=YUP;
14348             /* if second does not overlap with 1st show it too */
14349             if (SUMA_ScreenProjAngle(ASIv[fst], ASIv[sec]) < coslim) {
14350                ShowTxt[sec]=YUP;
14351             }
14352             /* if the third does not overlap with the 1st,
14353                AND with the second if it is showing */
14354             SUMA_LHv("Dot 1 3 = %f, Dot 2 3 = %f\n",
14355                SUMA_ScreenProjAngle(ASIv[fst], ASIv[thr]),
14356                SUMA_ScreenProjAngle(ASIv[sec], ASIv[thr]));
14357 
14358             if (SUMA_ScreenProjAngle(ASIv[fst], ASIv[thr]) < coslim &&
14359                 (!ShowTxt[sec] ||
14360                   SUMA_ScreenProjAngle(ASIv[sec], ASIv[thr]) < coslim) ) {
14361                ShowTxt[thr]=YUP;
14362             }
14363          }
14364          SUMA_LHv("fst, sec, thr: %d %d %d\n"
14365                       "Show flags[0,1,2]   : %d, %d, %d\n",
14366                       fst, sec, thr,
14367                       ShowTxt[0], ShowTxt[1], ShowTxt[2]);
14368 
14369          Elm = dlist_head(slist); i = 0;
14370          do {
14371             ASI = (SUMA_AxisSegmentInfo *)Elm->data;
14372             if (ASI->AxisDim == 0) {
14373                SUMA_LHv("X axis, i = %d, SegIndex = %d, "
14374                         "world, Sx, Sy = %.2f,%.2f,%.2f, off = %f, %f %f\n",
14375                          i, ASI->SegIndex, ASI->world_length,
14376                          ASI->ScreenProj[0], ASI->ScreenProj[1],
14377                          ASI->TxOff[0], ASI->TxOff[1],ASI->TxOff[2]);
14378             } else if (ASI->AxisDim == 1) {
14379                SUMA_LHv("Y axis, i = %d, SegIndex = %d, "
14380                         "world, Sx, Sy = %.2f,%.2f,%.2f, off = %f, %f %f\n",
14381                         i, ASI->SegIndex, ASI->world_length,
14382                         ASI->ScreenProj[0], ASI->ScreenProj[1],
14383                         ASI->TxOff[0], ASI->TxOff[1],ASI->TxOff[2]);
14384             } else if (ASI->AxisDim == 2) {
14385                SUMA_LHv("Z axis, i = %d, SegIndex = %d, "
14386                         "world, Sx, Sy = %.2f,%.2f,%.2f, off = %f, %f %f\n",
14387                         i, ASI->SegIndex, ASI->world_length,
14388                         ASI->ScreenProj[0], ASI->ScreenProj[1],
14389                         ASI->TxOff[0], ASI->TxOff[1],ASI->TxOff[2]);
14390             } else { SUMA_S_Err("Major bobo."); SUMA_RETURN(NOPE); }
14391 
14392             if (i < 3 && ShowTxt[i]) {
14393                SUMA_LHv("Axis %d, ScrLen=[%f %f], ScrVec=[%f %f %f]\n",
14394                      i, ASI->ScreenProj[0], ASI->ScreenProj[1],
14395                      ASI->ScreenProj[0], ASI->ScreenProj[1], ASI->ScreenProj[2]);
14396 
14397                SUMA_DrawLineAxis (ASI, Ax, YUP);
14398             } else {
14399                SUMA_DrawLineAxis (ASI, Ax, NOPE);
14400             }
14401             SUMA_free(ASI); ASI = NULL;
14402             if (Elm != dlist_tail(slist)) {
14403                Elm = dlist_next(Elm);
14404             } else {
14405                Elm = NULL;
14406             }
14407             ++i;
14408          } while (i < N_Ax && Elm);
14409 
14410          /* destroy list */
14411          dlist_destroy(slist);SUMA_free(slist); slist = NULL;
14412 
14413          break;
14414       default:
14415          SUMA_S_Err("Should not be here.");
14416          SUMA_RETURN(NOPE);
14417          break;
14418    }
14419    switch (Ax->Stipple) {
14420       case SUMA_DASHED_LINE:
14421          glDisable(GL_LINE_STIPPLE);
14422          break;
14423       case SUMA_SOLID_LINE:
14424          break;
14425    }
14426    SUMA_RETURN (YUP);
14427 }
14428 
14429 /*!
14430    \brief writes axis text
14431 */
SUMA_AxisText(SUMA_AxisSegmentInfo * ASIp,double * Ps)14432 SUMA_Boolean SUMA_AxisText(SUMA_AxisSegmentInfo *ASIp, double *Ps)
14433 {
14434    static char FuncName[]={"SUMA_AxisText"};
14435    GLboolean valid;
14436    GLfloat rpos[4];
14437    char txt[20]={"What the hell?"};
14438    int is;
14439    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
14440    static float txcol[3] = {1, 1, 1};
14441    static int width, height;
14442    SUMA_Boolean LocalHead = NOPE;
14443 
14444    SUMA_ENTRY;
14445 
14446 
14447    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, NoColor);
14448    glMaterialfv(GL_FRONT, GL_EMISSION, txcol); /*turn on emissidity for text*/
14449    glRasterPos3d(Ps[0], Ps[1], Ps[2]);
14450    glGetFloatv(GL_CURRENT_RASTER_POSITION, rpos);
14451    glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
14452    if (LocalHead) fprintf(SUMA_STDERR, "%s: Raster position (%g,%g, %g) is %s\n",
14453       FuncName, rpos[0], rpos[1], rpos[2], valid ? "valid" : "INVALID");
14454 
14455    /* do some text action */
14456    if (valid) {
14457       glColor3fv(txcol);
14458       sprintf(txt,"%.1f", Ps[ASIp->AxisDim]);
14459       /* sprintf(txt,"%s", MV_format_fval2(Ps[ASIp->AxisDim], 5)); */
14460       for (is=0; txt[is] != '\0'; is++) {
14461          glutBitmapCharacter(GLUT_BITMAP_9_BY_15, txt[is]);
14462       }
14463    }
14464    glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
14465       /*turn off emissidity for text*/
14466 
14467    SUMA_RETURN(YUP);
14468 }
14469 
14470 
14471 /*!
14472    \brief glutBitmapLength does not work, so here is a local version
14473    string length in pixels.
14474 */
SUMA_glutBitmapLength(void * font,char * txt,char * txte)14475 int SUMA_glutBitmapLength(void *font, char *txt, char *txte)
14476 {
14477    int l=0;
14478    if (!txt) return(0);
14479    if (!txte) txte=txt+strlen(txt);
14480    for (; *txt!='\0' && txt < txte; ++txt) {
14481       l = l + glutBitmapWidth(font, *txt);
14482    }
14483    return (l);
14484 }
14485 
14486 /*!
14487    \brief Font height in pixels
14488 */
SUMA_glutBitmapFontHeight(void * font)14489 int SUMA_glutBitmapFontHeight(void *font)
14490 {
14491    if (!font) return(0);
14492    if (font == GLUT_BITMAP_9_BY_15)
14493          return(15);
14494    else if (font == GLUT_BITMAP_8_BY_13)
14495          return(13);
14496    else if (font == GLUT_BITMAP_TIMES_ROMAN_10)
14497          return(10);
14498    else if (font == GLUT_BITMAP_TIMES_ROMAN_24)
14499          return(24);
14500    else if (font == GLUT_BITMAP_HELVETICA_10)
14501          return(10);
14502    else if (font == GLUT_BITMAP_HELVETICA_12)
14503          return(12);
14504    else if (font == GLUT_BITMAP_HELVETICA_18)
14505          return(18);
14506    else
14507          return(0);
14508 
14509 }
14510 
SUMA_glutBitmapFont(char * fontname)14511 void * SUMA_glutBitmapFont(char *fontname)
14512 {
14513    if (!fontname) return(GLUT_BITMAP_9_BY_15); /* default*/
14514    else if (strcmp(fontname,"f8") == 0 ||
14515        strcmp(fontname,"font8") == 0 ) return(GLUT_BITMAP_8_BY_13);
14516    else if (strcmp(fontname,"f9") == 0 ||
14517        strcmp(fontname,"font9") == 0 ) return(GLUT_BITMAP_9_BY_15);
14518    else if (strcmp(fontname,"tr10") == 0 ||
14519        strcmp(fontname,"times_roman10") == 0 )
14520          return(GLUT_BITMAP_TIMES_ROMAN_10);
14521    else if (strcmp(fontname,"tr24") == 0 ||
14522        strcmp(fontname,"times_roman24") == 0 )
14523          return(GLUT_BITMAP_TIMES_ROMAN_24);
14524    else if (strcmp(fontname,"he10") == 0 ||
14525        strcmp(fontname,"helvetica10") == 0 )
14526          return(GLUT_BITMAP_HELVETICA_10);
14527    else if (strcmp(fontname,"he12") == 0 ||
14528        strcmp(fontname,"helvetica12") == 0 )
14529          return(GLUT_BITMAP_HELVETICA_12);
14530    else if (strcmp(fontname,"he18") == 0 ||
14531        strcmp(fontname,"helvetica18") == 0 )
14532          return(GLUT_BITMAP_HELVETICA_18);
14533    else return(NULL);
14534 }
14535 
SUMA_glutBitmapFontName(void * font)14536 char * SUMA_glutBitmapFontName(void * font)
14537 {
14538       if (!font) {
14539          return("NULL font");
14540       } else if (font == GLUT_BITMAP_8_BY_13) {
14541          return("font8");
14542       } else if (font == GLUT_BITMAP_9_BY_15) {
14543          return("font9");
14544       } else if (font == GLUT_BITMAP_TIMES_ROMAN_10) {
14545          return("times_roman10");
14546       } else if (font == GLUT_BITMAP_TIMES_ROMAN_24) {
14547          return("times_roman24");
14548       } else if (font == GLUT_BITMAP_HELVETICA_10) {
14549          return("helvetica10");
14550       } else if (font == GLUT_BITMAP_HELVETICA_12) {
14551          return("helvetica12");
14552       } else if (font == GLUT_BITMAP_HELVETICA_18) {
14553          return("helvetica18");
14554       } else {
14555          return("bad font pointer");
14556       }
14557 }
14558 
SUMA_CoordTypeName(SUMA_DO_CoordType tp)14559 char *SUMA_CoordTypeName (SUMA_DO_CoordType tp)
14560 {
14561    switch(tp) {
14562       case SUMA_SCREEN:
14563          return("fixed");
14564       case SUMA_WORLD:
14565          return("mobile");
14566       case SUMA_COORD_TYPE_ERROR:
14567          return("Bad coordinate type");
14568       default:
14569          return("What is this?");
14570    }
14571 }
SUMA_CoordType(char * atr)14572 SUMA_DO_CoordType SUMA_CoordType (char *atr)
14573 {
14574    if (!atr) return(SUMA_WORLD);
14575    if (  !strcmp(atr,"mobile") ||
14576          !strcmp(atr,"world") ) {
14577       return(SUMA_WORLD);
14578    }  else if (!strcmp(atr,"fixed") ||
14579                !strcmp(atr,"screen")) {
14580       return(SUMA_SCREEN);
14581    }else {
14582       return(SUMA_COORD_TYPE_ERROR);
14583    }
14584 }
14585 
14586 
14587 /*!
14588    \brief Figures out box size for some text
14589    if font is NULL, box sizes are in character units
14590    You can use glutBitmapLength
14591                glutBitmapWidth
14592    (some good tips here: http://www.lighthouse3d.com/opengl/glut )
14593    See also  SUMA_NIDOtext_LineWidth
14594 
14595    Note that w will contain the size of the largest line in a multi-line object
14596 */
SUMA_TextBoxSize(char * txt,int * w,int * h,int * nl,void * font)14597 SUMA_Boolean SUMA_TextBoxSize (char *txt, int *w, int *h, int *nl, void *font)
14598 {
14599    static char FuncName[]={"SUMA_TextBoxSize"};
14600    char *op=NULL, *ops=NULL, *OPE=NULL;
14601    int nc=0;
14602    SUMA_Boolean LocalHead = NOPE;
14603 
14604    SUMA_ENTRY;
14605 
14606    *w = 0;
14607    *h = 0;
14608    *nl = 0;
14609    if (!txt || !strlen(txt)) SUMA_RETURN(YUP);
14610 
14611 
14612 
14613    op = txt;
14614    OPE = txt+strlen(txt);
14615    /* One line at time */
14616    ops = op;
14617    do {
14618       SUMA_SKIP_LINE(op,OPE);
14619       if (op > ops) {
14620          if (!font) {
14621             ++(*h);
14622             nc = op-ops;
14623             if (nc > *w) *w = nc;
14624          } else {
14625             *h = *h + SUMA_glutBitmapFontHeight(font);
14626             if (*op == '\0') {
14627                nc = SUMA_glutBitmapLength(font, ops, op);
14628             } else {
14629                nc = SUMA_glutBitmapLength(font, ops, op-1);
14630             }
14631             if (nc > *w) *w = nc;
14632          }
14633          ++(*nl);
14634       }
14635       ops = op;
14636    } while (op < OPE);
14637 
14638    if (!font) {
14639       SUMA_LHv("For >>>%s<<<\nNeed %d lines with a max of %d chars on one line\n"
14640                "number of lines: %d\n",
14641             txt, *h,*w, *nl);
14642    } else {
14643       SUMA_LHv("For >>>%s<<<\n"
14644                "Need %d pixels high with a max of %d pixels on one line\n"
14645                "number of lines: %d\n",
14646             txt, *h,*w, *nl);
14647    }
14648 
14649 
14650    SUMA_RETURN(YUP);
14651 }
14652 
14653 /*!
14654    Get widths for each single-line string in txt
14655    The function returns the height of one line, a constant for all single line
14656    texts. -1 is returned in error
14657 */
SUMA_WordBoxSize(char ** txt,int N_txt,int * w,void * font)14658 int SUMA_WordBoxSize (char **txt, int N_txt, int *w, void *font)
14659 {
14660    static char FuncName[]={"SUMA_WordBoxSize"};
14661    char *s=NULL;
14662    int nc=0, ii;
14663    SUMA_Boolean LocalHead = NOPE;
14664 
14665    SUMA_ENTRY;
14666 
14667    if (!txt || N_txt < 1) SUMA_RETURN(-1);
14668 
14669 
14670    for (ii=0; ii<N_txt; ++ii) {
14671       if (!(s = txt[ii]) || *s=='\0') w[ii]=0;
14672       else {
14673          nc = 0;
14674          while (s[nc++]!='\0');
14675          if (!font) w[ii]=nc;
14676          else {
14677             nc=0; w[ii]=0;
14678             while (s[nc] != '\0') w[ii]+=glutBitmapWidth(font,s[nc++]);
14679          }
14680       }
14681    }
14682 
14683 
14684    if (LocalHead) {
14685       for (ii=0; ii<N_txt; ++ii) {
14686          fprintf(stderr,"%d width %d height for %s\n",
14687                   w[ii], SUMA_glutBitmapFontHeight(font), txt[ii]);
14688       }
14689    }
14690    SUMA_RETURN(SUMA_glutBitmapFontHeight(font));
14691 }
14692 
14693 /*!
14694    \brief Draws a scale line.
14695 
14696    \param ASIp (SUMA_AxisSegmentInfo *) structure containing segment info
14697    \param Ax (SUMA_Axis *)
14698 */
SUMA_DrawLineAxis(SUMA_AxisSegmentInfo * ASIp,SUMA_Axis * Ax,SUMA_Boolean AddText)14699 SUMA_Boolean SUMA_DrawLineAxis ( SUMA_AxisSegmentInfo *ASIp,
14700                                  SUMA_Axis *Ax, SUMA_Boolean AddText)
14701 {
14702    static char FuncName[]={"SUMA_DrawLineAxis"};
14703    double u3[3],nu, nu3, txofffac, size[2], space[2];
14704    double Pt[3], Ps[3];
14705    int prec = 1000, NmT;
14706    int i, jj, nTick[2];
14707    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
14708    SUMA_Boolean LocalHead = NOPE;
14709 
14710    SUMA_ENTRY;
14711 
14712    glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor);
14713                            /* turn off ambient and diffuse components */
14714    glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
14715 
14716    if (ASIp->AxisDim == 0) {
14717       glMaterialfv(GL_FRONT, GL_EMISSION, Ax->XaxisColor);
14718                                        /*turn on emissivity for X axis*/
14719       if (LocalHead) fprintf(SUMA_STDERR,"%s: X axis\n", FuncName);
14720    } else if (ASIp->AxisDim == 1) {
14721       glMaterialfv(GL_FRONT, GL_EMISSION, Ax->YaxisColor);
14722                                        /*turn on emissivity for Y axis*/
14723       if (LocalHead) fprintf(SUMA_STDERR,"%s: Y axis\n", FuncName);
14724    } else if (ASIp->AxisDim == 2) {
14725       glMaterialfv(GL_FRONT, GL_EMISSION, Ax->ZaxisColor);
14726                                        /*turn on emissivity for Z axis*/
14727       if (LocalHead) fprintf(SUMA_STDERR,"%s: Z axis\n", FuncName);
14728    }
14729 
14730    glBegin(GL_LINES);
14731    /* draw the line */
14732    glVertex3d(ASIp->P1[0], ASIp->P1[1], ASIp->P1[2]);
14733    glVertex3d(ASIp->P2[0], ASIp->P2[1], ASIp->P2[2]);
14734 
14735    /* work the ticks */
14736    /* unit vector */
14737    SUMA_UNIT_VEC(ASIp->P1, ASIp->P2, u3, nu3);
14738    for (jj=0; jj<2; ++jj) {
14739       if (jj == 0) {
14740          space[0] = Ax->mTspace;
14741          size[0] = Ax->mTsize;
14742       } else {
14743          space[1] = Ax->MTspace;
14744          size[1] = Ax->MTsize;
14745       }
14746 
14747       /* starting point */
14748       /* is ASIp->P1 an OK point ?*/
14749       SUMA_NORM_VEC(ASIp->P1, 3, nu);
14750       if (! ( (int)(prec * nu) % (int)(prec * space[jj]) ) ) {
14751          /* a good starting point */
14752          SUMA_COPY_VEC(ASIp->P1, Pt, 3, float, float);
14753          SUMA_LH("Using ASIp->P1 as starting tick point");
14754       } else {
14755           NmT = (int)(prec * nu) / (int)(prec * space[jj]); NmT /= prec;
14756           Pt[0] = NmT * space[jj] * u3[0] +ASIp->P1[0];
14757           Pt[1] = NmT * space[jj] * u3[1]+ASIp->P1[1];
14758           Pt[2] = NmT * space[jj] * u3[2]+ASIp->P1[2];
14759       }
14760       SUMA_LHv("Starting ticks at [%f %f %f]\nnu3 = %f\n",
14761                Pt[0], Pt[1], Pt[2], nu3);
14762 
14763 
14764       /* draw the ticks */
14765       i = 0;
14766       if (LocalHead)
14767          fprintf(SUMA_STDERR,
14768             "%s:\nspace = %f\nsize = %f\n", FuncName, space[jj], size[jj]);
14769       if (Ax->DoCross) {
14770          size[jj] /= 2.0;
14771          while (i*space[jj] < nu3) {
14772             Ps[0] = i*space[jj]*u3[0] + Pt[0];
14773             Ps[1] = i*space[jj]*u3[1] + Pt[1];
14774             Ps[2] = i*space[jj]*u3[2] + Pt[2]; /* center */
14775             #if 0
14776                if (LocalHead)
14777                   fprintf( SUMA_STDERR,
14778                            "%s:\nPs = [%f %f %f]; \n",
14779                            FuncName, Ps[0], Ps[1], Ps[2]);
14780             #endif
14781             glVertex3d( Ps[0]-ASIp->tick1_dir[0]*size[jj],
14782                         Ps[1]-ASIp->tick1_dir[1]*size[jj],
14783                         Ps[2]-ASIp->tick1_dir[2]*size[jj]);
14784             glVertex3d( Ps[0]+ASIp->tick1_dir[0]*size[jj],
14785                         Ps[1]+ASIp->tick1_dir[1]*size[jj],
14786                         Ps[2]+ASIp->tick1_dir[2]*size[jj]);
14787             glVertex3d( Ps[0]-ASIp->tick2_dir[0]*size[jj],
14788                         Ps[1]-ASIp->tick2_dir[1]*size[jj],
14789                         Ps[2]-ASIp->tick2_dir[2]*size[jj]);
14790             glVertex3d( Ps[0]+ASIp->tick2_dir[0]*size[jj],
14791                         Ps[1]+ASIp->tick2_dir[1]*size[jj],
14792                         Ps[2]+ASIp->tick2_dir[2]*size[jj]);
14793             ++i;
14794          }
14795       } else {
14796          while (i*space[jj] < nu3) {
14797             Ps[0] = i*space[jj]*u3[0] + Pt[0];
14798             Ps[1] = i*space[jj]*u3[1] + Pt[1];
14799             Ps[2] = i*space[jj]*u3[2] + Pt[2]; /* center */
14800             #if 0
14801               if (LocalHead)
14802                   fprintf( SUMA_STDERR,
14803                            "%s:\nPs = [%f %f %f]; \n",
14804                            FuncName, Ps[0], Ps[1], Ps[2]);
14805             #endif
14806             glVertex3d( Ps[0], Ps[1], Ps[2]);
14807             glVertex3d( Ps[0]+ASIp->tick1_dir[0]*size[jj],
14808                         Ps[1]+ASIp->tick1_dir[1]*size[jj],
14809                         Ps[2]+ASIp->tick1_dir[2]*size[jj]);
14810             glVertex3d( Ps[0], Ps[1], Ps[2]);
14811             glVertex3d( Ps[0]+ASIp->tick2_dir[0]*size[jj],
14812                         Ps[1]+ASIp->tick2_dir[1]*size[jj],
14813                         Ps[2]+ASIp->tick2_dir[2]*size[jj]);
14814                #if 0 /* for a little debug */
14815                if (jj==1) {
14816                   glVertex3d(Ps[0], Ps[1], Ps[2]);
14817                   txofffac = 1.0 * size[1];
14818                   Ps[0] = i*space[1]*u3[0] + Pt[0] + txofffac * ASIp->TxOff[0];
14819                   Ps[1] = i*space[1]*u3[1] + Pt[1] + txofffac * ASIp->TxOff[1];
14820                   Ps[2] = i*space[1]*u3[2] + Pt[2] + txofffac * ASIp->TxOff[2];
14821                   glVertex3d(Ps[0], Ps[1], Ps[2]);
14822                }
14823                #endif
14824             ++i;
14825          }
14826       }
14827       nTick[jj] = i-1;
14828 
14829 
14830    }
14831 
14832    glEnd();
14833 
14834    glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, NoColor);
14835       /*turn off emissivity for axis*/
14836 
14837 
14838 
14839    if (AddText) { /* do the text for major ticks only */
14840       float MinYstep, MinXstep, dSxT, dSyT, curXstep, curYstep;
14841       int OKnext;
14842       int DoZero = 0; /* skip zero label, they get all bunched up */
14843       dSxT = (float)fabs(ASIp->ScreenProj[0]) / (float)nTick[1];
14844       dSyT = (float)fabs(ASIp->ScreenProj[1]) / (float)nTick[1];
14845       MinYstep = 15 ; /* height of letters in pixels
14846                         (using GLUT_BITMAP_9_BY_15)
14847                         Might want to use SUMA_glutBitmapFontHeight
14848                         if you're using differing fonts*/
14849       MinXstep = 9 * 5; /* length of string in pixels
14850                            (around 5 chars, including sign, using %.1f )*/
14851       if (LocalHead)
14852          fprintf (SUMA_STDERR,"%s:\ndS = %f, %f\n", FuncName, dSxT, dSyT);
14853       i = 0;
14854       if (Ax->DoCross) { /* size has already been modified above ... */
14855          /* perhaps add a factor to the shift below, we'll see .. */
14856          txofffac = 2.0 * size[1];
14857       } else {
14858          txofffac = 1.0 * size[1];
14859       }
14860 
14861       OKnext = 1;
14862       curXstep =0; curYstep=0;
14863       while (i*space[1] < nu3) {
14864          if(OKnext) {
14865             Ps[0] = i*space[1]*u3[0] + Pt[0] + txofffac * ASIp->TxOff[0];
14866             Ps[1] = i*space[1]*u3[1] + Pt[1] + txofffac * ASIp->TxOff[1];
14867             Ps[2] = i*space[1]*u3[2] + Pt[2] + txofffac * ASIp->TxOff[2];
14868             if (DoZero || i > 0) {
14869                SUMA_AxisText(ASIp, Ps);
14870                SUMA_LHv("txofffac = %f, ASIp->TxOff=[%f %f %f]\n",
14871                   txofffac, ASIp->TxOff[0], ASIp->TxOff[1], ASIp->TxOff[2]);
14872             }
14873          }
14874          curXstep += dSxT; curYstep += dSyT;
14875          if (curXstep > MinXstep || curYstep > MinYstep) {
14876             OKnext = 1;
14877             curXstep =0; curYstep=0;
14878          } else {
14879             OKnext = 0;
14880          }
14881          ++i;
14882       }
14883    }
14884 
14885    SUMA_RETURN(YUP);
14886 }
14887 
14888 /*!
14889    \brief find ROIs created on SO. ROIs created on a relative of SO will not be
14890    returned.
14891    \param SO (SUMA_SurfaceObject *)SO
14892    \param dov (SUMA_DO*) displayable objects vector
14893    \param N_do (int) number of displayable objects
14894    \param N_ROI (int *) to hold the number of DrawnROIs found
14895    \return ROIv (SUMA_DRAWN_ROI **) vector of SUMA_DRAWN_ROI *
14896       such that ROIv[i]->Parent_idcode_str = SO->idcode_str
14897 
14898    - free  ROIv with SUMA_free(ROIv);
14899 
14900    \sa SUMA_Find_ROIrelatedtoSO
14901 */
SUMA_Find_ROIonSO(SUMA_SurfaceObject * SO,SUMA_DO * dov,int N_do,int * N_ROI)14902 SUMA_DRAWN_ROI **SUMA_Find_ROIonSO (SUMA_SurfaceObject *SO, SUMA_DO* dov,
14903                                     int N_do, int *N_ROI)
14904 {
14905    static char FuncName[]={"SUMA_Find_ROIonSO"};
14906    SUMA_DRAWN_ROI **ROIv=NULL;
14907    SUMA_DRAWN_ROI *D_ROI = NULL;
14908    int i, roi_cnt=0;
14909    SUMA_Boolean LocalHead = NOPE;
14910 
14911    SUMA_ENTRY;
14912 
14913    *N_ROI = -1;
14914 
14915    /* allocate for maximum */
14916    ROIv = (SUMA_DRAWN_ROI **)SUMA_calloc(N_do, sizeof(SUMA_DRAWN_ROI *));
14917    if (!ROIv) {
14918       SUMA_SL_Crit("Failed to allocate for ROIv");
14919       SUMA_RETURN(NULL);
14920    }
14921 
14922    roi_cnt=0;
14923    for (i=0; i < N_do; ++i) {
14924       if (dov[i].ObjectType == ROIdO_type) {
14925          D_ROI = (SUMA_DRAWN_ROI *)dov[i].OP;
14926          if (!strncmp(D_ROI->Parent_idcode_str, SO->idcode_str,
14927                       strlen(SO->idcode_str))) {
14928             SUMA_LH("Found an ROI");
14929             ROIv[roi_cnt] = D_ROI;
14930             ++roi_cnt;
14931          }
14932       }
14933       if (dov[i].ObjectType == ROIO_type) {
14934          SUMA_SL_Warn("ROIO_types are being ignored.");
14935       }
14936    }
14937 
14938    /* realloc */
14939    ROIv = (SUMA_DRAWN_ROI **)
14940                SUMA_realloc(ROIv, sizeof(SUMA_DRAWN_ROI *)*roi_cnt);
14941    if (!ROIv) {
14942       SUMA_SL_Crit("Failed to reallocate for ROIv");
14943       SUMA_RETURN(NULL);
14944    }
14945    *N_ROI = roi_cnt;
14946 
14947    SUMA_RETURN(ROIv);
14948 }
14949 
14950 /*!
14951    \brief find ROIs related to SO. ROIs created on a relative of SO will be returned.
14952    \param SO (SUMA_SurfaceObject *)SO
14953    \param dov (SUMA_DO*) displayable objects vector
14954    \param N_do (int) number of displayable objects
14955    \param N_ROI (int *) to hold the number of DrawnROIs found
14956    \return ROIv (SUMA_DRAWN_ROI **) vector of SUMA_DRAWN_ROI *
14957       such that ROIv[i]->Parent_idcode_str = SO->idcode_str
14958 
14959    - free  ROIv with SUMA_free(ROIv);
14960 
14961    \sa SUMA_Find_ROIonSO
14962 */
SUMA_Find_ROIrelatedtoSO(SUMA_SurfaceObject * SO,SUMA_DO * dov,int N_do,int * N_ROI)14963 SUMA_DRAWN_ROI **SUMA_Find_ROIrelatedtoSO (SUMA_SurfaceObject *SO, SUMA_DO* dov,
14964                                            int N_do, int *N_ROI)
14965 {
14966    static char FuncName[]={"SUMA_Find_ROIrelatedtoSO"};
14967    SUMA_DRAWN_ROI **ROIv=NULL;
14968    SUMA_DRAWN_ROI *D_ROI = NULL;
14969    int i, roi_cnt=0;
14970    SUMA_Boolean LocalHead = NOPE;
14971 
14972    SUMA_ENTRY;
14973 
14974    *N_ROI = -1;
14975 
14976    /* allocate for maximum */
14977    ROIv = (SUMA_DRAWN_ROI **)SUMA_calloc(N_do,sizeof(SUMA_DRAWN_ROI *));
14978    if (!ROIv) {
14979       SUMA_SL_Crit("Failed to allocate for ROIv");
14980       SUMA_RETURN(NULL);
14981    }
14982 
14983    roi_cnt=0;
14984    for (i=0; i < N_do; ++i) {
14985       if (dov[i].ObjectType == ROIdO_type) {
14986          D_ROI = (SUMA_DRAWN_ROI *)dov[i].OP;
14987          if (SUMA_isdROIrelated (D_ROI, (SUMA_ALL_DO *)SO)) {
14988             SUMA_LH("Found an ROI");
14989             ROIv[roi_cnt] = D_ROI;
14990             ++roi_cnt;
14991          }
14992       }
14993       if (dov[i].ObjectType == ROIO_type) {
14994          SUMA_SL_Warn("ROIO_types are being ignored.");
14995       }
14996    }
14997 
14998    /* realloc */
14999    ROIv = (SUMA_DRAWN_ROI **)SUMA_realloc(ROIv,
15000                                           sizeof(SUMA_DRAWN_ROI *)*roi_cnt);
15001    if (!ROIv) {
15002       SUMA_SL_Crit("Failed to reallocate for ROIv");
15003       SUMA_RETURN(NULL);
15004    }
15005    *N_ROI = roi_cnt;
15006 
15007    SUMA_RETURN(ROIv);
15008 }
15009 
15010 /*! Create Node-based spheres for a particular surface */
SUMA_Draw_SO_NBSP(SUMA_SurfaceObject * SO,SUMA_DO * dov,int N_do,SUMA_SurfaceViewer * sv)15011 SUMA_Boolean SUMA_Draw_SO_NBSP (SUMA_SurfaceObject *SO, SUMA_DO* dov,
15012                                     int N_do, SUMA_SurfaceViewer *sv)
15013 {
15014    static char FuncName[]={"SUMA_Draw_SO_NBSP"};
15015    int i;
15016    SUMA_SphereDO *SDO = NULL;
15017    SUMA_Boolean LocalHead = NOPE;
15018 
15019    SUMA_ENTRY;
15020 
15021    for (i=0; i < N_do; ++i) {
15022       switch (dov[i].ObjectType) { /* case Object Type */
15023          case NBSP_type:
15024             SDO = (SUMA_SphereDO *)dov[i].OP;
15025             if (SUMA_isNBDOrelated ((SUMA_NB_DO *)SDO, SO)) { /* draw it */
15026                if (LocalHead)
15027                   fprintf(SUMA_STDERR, "%s: Drawing spheres \n", FuncName);
15028                if (!SUMA_DrawSphereDO (SDO, sv)) {
15029                   fprintf( SUMA_STDERR,
15030                            "Error %s: Failed in SUMA_DrawSphereDO.\n",
15031                            FuncName);
15032                }
15033             }
15034          default:
15035             break;
15036       }
15037    }
15038 
15039    SUMA_RETURN(YUP);
15040 }
15041 
15042 /*! Create Node-based vectors for a particular surface */
SUMA_Draw_SO_NBV(SUMA_SurfaceObject * SO,SUMA_DO * dov,int N_do,SUMA_SurfaceViewer * sv)15043 SUMA_Boolean SUMA_Draw_SO_NBV (  SUMA_SurfaceObject *SO, SUMA_DO* dov,
15044                                  int N_do, SUMA_SurfaceViewer *sv)
15045 {
15046    static char FuncName[]={"SUMA_Draw_SO_NBV"};
15047    int i;
15048    SUMA_SegmentDO *SDO = NULL;
15049    SUMA_Boolean LocalHead = NOPE;
15050 
15051    SUMA_ENTRY;
15052    for (i=0; i < N_do; ++i) {
15053       switch (dov[i].ObjectType) { /* case Object Type */
15054          case ONBV_type:
15055          case NBV_type:
15056          case NBOLS_type:
15057          case NBLS_type:
15058             SDO = (SUMA_SegmentDO *)dov[i].OP;
15059             if (SUMA_isNBDOrelated ((SUMA_NB_DO *)SDO, SO)) { /* draw it */
15060                if (LocalHead)
15061                   fprintf(SUMA_STDERR, "%s: Drawing vec field \n", FuncName);
15062                if (!SUMA_DrawSegmentDO (SDO, sv)) {
15063                   fprintf(SUMA_STDERR,
15064                      "Error %s: Failed in SUMA_DrawSegmentDO.\n", FuncName);
15065                }
15066             }
15067          default:
15068             break;
15069       }
15070    }
15071 
15072    SUMA_RETURN(YUP);
15073 }
15074 
15075 /*! Create NIML DOs that are attached to a surface */
SUMA_Draw_SO_NIDO(SUMA_SurfaceObject * SO,SUMA_DO * dov,int N_do,SUMA_SurfaceViewer * sv)15076 SUMA_Boolean SUMA_Draw_SO_NIDO (  SUMA_SurfaceObject *SO, SUMA_DO* dov,
15077                                   int N_do, SUMA_SurfaceViewer *sv)
15078 {
15079    static char FuncName[]={"SUMA_Draw_SO_NIDO"};
15080    int i;
15081    SUMA_NIDO *SDO = NULL;
15082    SUMA_Boolean LocalHead = NOPE;
15083 
15084    SUMA_ENTRY;
15085    for (i=0; i < N_do; ++i) {
15086       switch (dov[i].ObjectType) { /* case Object Type */
15087          case NIDO_type:
15088             SDO = (SUMA_NIDO *)dov[i].OP;
15089             SUMA_LHv("Testing NIDO\n"
15090                       "isSurfBased: %d\n"
15091                       "isNIDOrelated: %d\n",
15092                       SUMA_isNIDO_SurfBased(SDO),
15093                       SUMA_isNIDOrelated (SDO, SO));
15094             if (  SUMA_isNIDO_SurfBased(SDO) &&
15095                   SUMA_isNIDOrelated (SDO, SO)) { /* draw it */
15096                if (!SUMA_DrawNIDO (SDO, sv)) {
15097                   fprintf(SUMA_STDERR,
15098                      "Error %s: Failed in SUMA_DrawNIDO.\n", FuncName);
15099                }
15100             } else {
15101             }
15102          default:
15103             break;
15104       }
15105    }
15106 
15107    SUMA_RETURN(YUP);
15108 }
15109 
15110 /*!
15111    Get node-based texture for a certain surface
15112 */
SUMA_SO_NIDO_Node_Texture(SUMA_SurfaceObject * SO,SUMA_DO * dov,int N_do,SUMA_SurfaceViewer * sv)15113 NI_element * SUMA_SO_NIDO_Node_Texture (  SUMA_SurfaceObject *SO, SUMA_DO* dov,
15114                                           int N_do, SUMA_SurfaceViewer *sv )
15115 {
15116    static char FuncName[]={"SUMA_SO_NIDO_Node_Texture"};
15117    int i, ip, sz[2]={0, 0};
15118    float txloc[4]={0,0,0,0};
15119    char *target=NULL;
15120    NI_element *nel=NULL, *nelo=NULL;
15121    SUMA_NIDO *SDO = NULL;
15122    SUMA_SurfaceObject *default_SO=NULL;
15123    SUMA_Boolean LocalHead = NOPE;
15124 
15125    SUMA_ENTRY;
15126 
15127    nelo=NULL;
15128    for (i=0; i < N_do; ++i) {
15129       switch (dov[i].ObjectType) { /* case Object Type */
15130          case NIDO_type:
15131             SDO = (SUMA_NIDO *)dov[i].OP;
15132             SUMA_LHv("Testing NIDO\n"
15133                       "isSurfBased: %d\n"
15134                       "isNIDOrelated: %d\n",
15135                       SUMA_isNIDO_SurfBased(SDO),
15136                       SUMA_isNIDOrelated (SDO, SO));
15137             if (  SUMA_isNIDO_SurfBased(SDO) &&
15138                   SUMA_isNIDOrelated (SDO, SO)) {
15139                /* loop through the elements only grabbing
15140                   node-based texture */
15141                for( ip=0 ; ip < SDO->ngr->part_num ; ip++ ){
15142                   nel = NULL;
15143                   switch( SDO->ngr->part_typ[ip] ){
15144                      /*-- a sub-group ==> recursion! --*/
15145                      case NI_GROUP_TYPE:
15146                         break ;
15147                      case NI_ELEMENT_TYPE:
15148                         nel = (NI_element *)SDO->ngr->part[ip] ;
15149                         target = NI_get_attribute(nel,"target");
15150                         if ( ! strcmp(nel->name,"Tex") ) {
15151                            if (!target || strncmp(target, "ALL_SURF",8)==0
15152                                || SUMA_iswordin(SO->Label,target)) {
15153                               nelo = nel;
15154                               goto SET_TEX;
15155                            }
15156                         }
15157                         break;
15158                      default:
15159                         break;
15160                   }
15161                }
15162             }
15163          default:
15164             break;
15165       }
15166    }
15167 
15168    SET_TEX:
15169 
15170 
15171    SUMA_RETURN(nelo);
15172 
15173 }
15174 
SUMA_Draw_SO_Dset_Contours(SUMA_SurfaceObject * SO,SUMA_SurfaceViewer * sv)15175 SUMA_Boolean SUMA_Draw_SO_Dset_Contours(SUMA_SurfaceObject *SO,
15176                                SUMA_SurfaceViewer *sv)
15177 {
15178    static char FuncName[]={"SUMA_Draw_SO_Dset_Contours"};
15179    SUMA_DSET *dd=NULL;
15180    SUMA_OVERLAYS *colplane=NULL;
15181    DListElmt *el=NULL;
15182    SUMA_DRAWN_ROI *D_ROI=NULL;
15183    int OverInd = -1, id2cont=0, id1cont=0, icont=0, ic, i2last=0;
15184    float off[3];
15185    SUMA_Boolean LocalHead = NOPE;
15186 
15187    SUMA_ENTRY;
15188 
15189    el = dlist_head(SUMAg_CF->DsetList);
15190    while (el) {
15191       dd = (SUMA_DSET*)el->data;
15192       if (SUMA_isDsetRelated(dd,SO)) {
15193          SUMA_LHv("Have Dset %s related to SO\n", SDSET_LABEL(dd));
15194          if (!(colplane = SUMA_Fetch_OverlayPointerByDset (
15195                            (SUMA_ALL_DO *)SO, dd, &OverInd))) {
15196                SUMA_S_Errv(
15197                   "Failed to fetch existing %s dset's overlay pointer\n",
15198                   SDSET_LABEL(dd));
15199                SUMA_RETURN(NOPE);
15200          }
15201          /* any contours? */
15202          if ( (colplane->ShowMode == SW_SurfCont_DsetViewCon ||
15203                colplane->ShowMode == SW_SurfCont_DsetViewCaC ) &&
15204               colplane->Contours && colplane->N_Contours) {
15205             /* draw them */
15206             for (ic=0; ic<colplane->N_Contours; ++ic) {
15207                D_ROI = (SUMA_DRAWN_ROI *)colplane->Contours[ic];
15208                SUMA_LHv("Dset Contouring %d\n", ic);
15209 
15210                if (D_ROI->CE && D_ROI->N_CE) {
15211                   /* Draw the contour */
15212                   if (!SO->patchNodeMask) {
15213                      glLineWidth(sv->ContThick); /* Changed from horrible '6'
15214                                  now that glPolygonOffset is used to
15215                                  allow for proper coplanar line and
15216                                  polygon rendering.  July 8th 2010 */
15217                      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
15218                                   D_ROI->FillColor);
15219                      SUMA_LH("Drawing contour ...");
15220 
15221                      #if 1 /* Should be a little faster */
15222                      /* initialize first point down */
15223                      glBegin(GL_LINE_STRIP);
15224                      id1cont = 3 * D_ROI->CE[0].n1;
15225                      glVertex3f(SO->NodeList[id1cont],
15226                                 SO->NodeList[id1cont+1],
15227                                 SO->NodeList[id1cont+2]);
15228                      i2last = D_ROI->CE[0].n1;
15229                      for (icont = 0; icont < D_ROI->N_CE; ++icont) {
15230                         id2cont = 3 * D_ROI->CE[icont].n2;
15231                         if (i2last != D_ROI->CE[icont].n1) {
15232                            /* break in loop*/
15233                            glEnd(); /* end lines */
15234                            glBegin(GL_LINE_STRIP); /* begin again */
15235                            id1cont = 3 * D_ROI->CE[icont].n1;
15236                            glVertex3f(SO->NodeList[id1cont],
15237                                       SO->NodeList[id1cont+1],
15238                                       SO->NodeList[id1cont+2]);
15239                         }
15240                         /* put down next vertex */
15241                         glVertex3f(SO->NodeList[id2cont],
15242                                    SO->NodeList[id2cont+1],
15243                                    SO->NodeList[id2cont+2]);
15244                         i2last = D_ROI->CE[icont].n2;
15245                      }
15246                      glEnd();
15247                      #else /* old simpler way */
15248                      for (icont = 0; icont < D_ROI->N_CE; ++icont) {
15249                         id1cont = 3 * D_ROI->CE[icont].n1;
15250                         id2cont = 3 * D_ROI->CE[icont].n2;
15251                         glBegin(GL_LINES);
15252                         glVertex3f(SO->NodeList[id1cont],
15253                                    SO->NodeList[id1cont+1],
15254                                    SO->NodeList[id1cont+2]);
15255                         glVertex3f(SO->NodeList[id2cont],
15256                                    SO->NodeList[id2cont+1],
15257                                    SO->NodeList[id2cont+2]);
15258                         glEnd();
15259 
15260                      }
15261                      #endif
15262                   } else {
15263                      if (SO->EmbedDim == 2) {
15264                         glLineWidth(sv->ContThick);
15265                         glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
15266                                      D_ROI->FillColor);
15267                      } else {
15268                         glLineWidth(sv->ContThick);
15269                         glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
15270                                      D_ROI->FillColor);
15271                      }
15272                      SUMA_LHv("Drawing contour on patch (%p)...",
15273                               SO->NodeNormList);
15274                               /* set default offset to nothing*/
15275                      off[0]=0.0; off[1]=0.0; off[2]=0.0;
15276                      if (SO->EmbedDim == 2) {
15277                         if (SO->NodeNormList && D_ROI->CE) {
15278                            /* just take a node in the ROI */
15279                            icont = 0;
15280                            while (  icont < D_ROI->N_CE &&
15281                                     ( (D_ROI->CE[icont].n1 >= SO->N_Node ||
15282                                        D_ROI->CE[icont].n2 >= SO->N_Node)  ||
15283                                   (!SO->patchNodeMask[D_ROI->CE[icont].n1] &&
15284                                    !SO->patchNodeMask[D_ROI->CE[icont].n2]) ) )
15285                               ++icont;
15286                            if (icont < D_ROI->N_CE &&
15287                                  D_ROI->CE[icont].n1 < SO->N_Node &&
15288                                  D_ROI->CE[icont].n2 < SO->N_Node )    {
15289                               id2cont = 3 * D_ROI->CE[icont].n2;
15290                               off[0] = 3*SO->NodeNormList[id2cont];
15291                               off[1] = 3*SO->NodeNormList[id2cont+1];
15292                               off[2] = 3*SO->NodeNormList[id2cont+2];
15293                            } else {
15294                               off[0] = off[1] = off[2] = 0.0;
15295                            }
15296                         }
15297                      }
15298                      #if 1 /* faster but more complicated */
15299                      icont = 0;
15300                      while (  icont < D_ROI->N_CE &&
15301                               ( (D_ROI->CE[icont].n1 >= SO->N_Node ||
15302                                  D_ROI->CE[icont].n2 >= SO->N_Node)  ||
15303                             (!SO->patchNodeMask[D_ROI->CE[icont].n1] &&
15304                              !SO->patchNodeMask[D_ROI->CE[icont].n2]) ) )
15305                         ++icont; /* skip if n1 or n2 exceed N_Node,
15306                                     or neither of them is in the patch.
15307                                     For patches, it is possible that
15308                                     SOpatch->N_Node < SOLDP->Parent */
15309                      if (icont < D_ROI->N_CE &&
15310                            D_ROI->CE[icont].n1 < SO->N_Node &&
15311                            D_ROI->CE[icont].n2 < SO->N_Node ) {
15312                         glBegin(GL_LINE_STRIP);
15313                         id1cont = 3 * D_ROI->CE[icont].n1;
15314                         glVertex3f(SO->NodeList[id1cont]+off[0],
15315                                    SO->NodeList[id1cont+1]+off[1],
15316                                    SO->NodeList[id1cont+2]+off[2]);
15317                         i2last = D_ROI->CE[icont].n1;
15318                         while (icont < D_ROI->N_CE) {
15319                            if (D_ROI->CE[icont].n1 < SO->N_Node &&
15320                                D_ROI->CE[icont].n2 < SO->N_Node &&
15321                                SO->patchNodeMask[D_ROI->CE[icont].n1] &&
15322                                SO->patchNodeMask[D_ROI->CE[icont].n2] ) {
15323                               id2cont = 3 * D_ROI->CE[icont].n2;
15324                               if (i2last != D_ROI->CE[icont].n1) {
15325                                  /* break in loop*/
15326                                  glEnd(); /* end lines */
15327                                  glBegin(GL_LINE_STRIP); /* begin again */
15328                                  id1cont = 3 * D_ROI->CE[icont].n1;
15329                                  glVertex3f(SO->NodeList[id1cont]+off[0],
15330                                             SO->NodeList[id1cont+1]+off[1],
15331                                             SO->NodeList[id1cont+2]+off[2]);
15332                               }
15333                               /* put down next vertex */
15334                               glVertex3f(SO->NodeList[id2cont]+off[0],
15335                                          SO->NodeList[id2cont+1]+off[1],
15336                                          SO->NodeList[id2cont+2]+off[2]);
15337                               i2last = D_ROI->CE[icont].n2;
15338                            }
15339                            ++icont;
15340                         }
15341                         glEnd();
15342                      }
15343                      #else /* slower way */
15344                      for (icont = 0; icont < D_ROI->N_CE; ++icont) {
15345                         id1cont = 3 * D_ROI->CE[icont].n1;
15346                         id2cont = 3 * D_ROI->CE[icont].n2;
15347                         if (D_ROI->CE[icont].n1 < SO->N_Node &&
15348                             D_ROI->CE[icont].n2 < SO->N_Node &&
15349                             SO->patchNodeMask[D_ROI->CE[icont].n1] &&
15350                             SO->patchNodeMask[D_ROI->CE[icont].n2]) {
15351 
15352                            glBegin(GL_LINES);
15353                            glVertex3f(SO->NodeList[id2cont]+off[0],
15354                                       SO->NodeList[id2cont+1]+off[1],
15355                                       SO->NodeList[id2cont+2]+off[2]);
15356                            glVertex3f(SO->NodeList[id1cont]+off[0],
15357                                       SO->NodeList[id1cont+1]+off[1],
15358                                       SO->NodeList[id1cont+2]+off[2]);
15359                            glEnd();
15360                         }
15361                      }
15362                      #endif
15363                   }
15364                }
15365 
15366             }
15367          }
15368       }
15369       el = dlist_next(el);
15370    }
15371 
15372    SUMA_RETURN(YUP);
15373 }
15374 
15375 /*! Create the ROIs for a particular surface */
SUMA_Draw_SO_ROI(SUMA_SurfaceObject * SO,SUMA_DO * dov,int N_do,SUMA_SurfaceViewer * sv)15376 SUMA_Boolean SUMA_Draw_SO_ROI (SUMA_SurfaceObject *SO,
15377                                SUMA_DO* dov, int N_do,
15378                                SUMA_SurfaceViewer *sv)
15379 {
15380    static char FuncName[]={"SUMA_Draw_SO_ROI"};
15381    GLfloat ROI_SphCol[] = {1.0, 0.0, 0.0, 1.0};
15382    GLfloat ROI_SphCol_frst[] = {1.0, 0.0, 0.0, 1.0};
15383    GLfloat ROI_FaceGroup[] = {0.8, 0.3, 1.0, 1.0 };
15384    GLfloat ROI_NodeGroup[] = {0.8, 0.3, 0.5, 1.0 };
15385    GLfloat ROI_EdgeGroup[] = {0.8, 0.8, 0.1, 1.0 };
15386    GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
15387    GLfloat NoCol[4] = {0.0, 0.0, 0.0, 0.0};
15388    GLfloat Red[4] = {1.0, 0.0, 0.0, 1.0};
15389    GLfloat Green[4] = {0.0, 1.0, 0.0, 1.0};
15390    GLfloat Blue[4] = {0.0, 0.0, 1.0, 1.0};
15391    GLfloat Yellow[4] = {1.0, 1.0, 0.0, 1.0};
15392    GLfloat Cyan[4] = {0.0, 1.0, 1.0, 1.0};
15393    GLfloat Pink[4] = {1.0, 0.0, 1.0, 1.0};
15394    int  i, id, ii, id1,id2, id3, EdgeIndex, FaceIndex,
15395          Node1, Node2, Node3, N_ROId=0, idFirst=0,
15396          *nodemask=NULL;
15397    float dx, dy, dz = 0.0;
15398    SUMA_DRAWN_ROI *D_ROI = NULL;
15399    SUMA_ROI_DATUM *ROId=NULL;
15400    SUMA_ROI *ROI = NULL;
15401    DListElmt *NextElm=NULL;
15402    float off[3];
15403    byte AmbDiff = 0;
15404    SUMA_Boolean LocalHead = NOPE;
15405 
15406    SUMA_ENTRY;
15407 
15408 
15409    for (i=0; i < N_do; ++i) {
15410       switch (dov[i].ObjectType) { /* case Object Type */
15411          case ROIdO_type:
15412             D_ROI = (SUMA_DRAWN_ROI *)dov[i].OP;
15413             if (!D_ROI->ROIstrokelist) {
15414                fprintf (SUMA_STDERR,
15415                         "Error %s: NULL ROIstrokeList.\n", FuncName);
15416                SUMA_RETURN (NOPE);
15417             }else if (!dlist_size(D_ROI->ROIstrokelist)) {
15418                if (LocalHead)
15419                   fprintf (SUMA_STDERR, "%s: Empty ROIstrokelist.\n", FuncName);
15420                break;
15421             }
15422             if (SUMA_isdROIrelated (D_ROI, (SUMA_ALL_DO *)SO)) { /* draw it */
15423                if (LocalHead)
15424                   fprintf(SUMA_STDERR, "%s: Drawing Drawn ROI %s (Status %d)\n",
15425                           FuncName, D_ROI->Label, D_ROI->DrawStatus);
15426                if (D_ROI->DrawStatus == SUMA_ROI_InCreation) {
15427                   switch (D_ROI->Type) {
15428                      case SUMA_ROI_OpenPath:
15429                         SUMA_LH("Red first, Green next");
15430                         SUMA_COPY_VEC(Red, ROI_SphCol_frst, 4, GLfloat, GLfloat);
15431                         SUMA_COPY_VEC(Green, ROI_SphCol, 4, GLfloat, GLfloat);
15432                         break;
15433                      case SUMA_ROI_ClosedPath:
15434                         SUMA_LH("Yellow first, Cyan next");
15435                         SUMA_COPY_VEC( Yellow, ROI_SphCol_frst, 4,
15436                                        GLfloat, GLfloat);
15437                         SUMA_COPY_VEC(Cyan, ROI_SphCol, 4, GLfloat, GLfloat);
15438                         break;
15439                      case SUMA_ROI_FilledArea:
15440                         SUMA_LH("Pink First, Yellow Next");
15441                         SUMA_COPY_VEC(Pink, ROI_SphCol_frst, 4,
15442                                       GLfloat, GLfloat);
15443                         SUMA_COPY_VEC(Cyan, ROI_SphCol, 4, GLfloat, GLfloat);
15444                         break;
15445                      default:
15446                         SUMA_LH("Default");
15447                         ROI_SphCol_frst[0] = 1.0;
15448                         ROI_SphCol_frst[1] = 0.3;
15449                         ROI_SphCol_frst[2] = 1.0;
15450                         ROI_SphCol_frst[3] = 1.0;
15451                         ROI_SphCol[0] = 1.0;
15452                         ROI_SphCol[1] = 1.0;
15453                         ROI_SphCol[2] = 0.0;
15454                         ROI_SphCol[3] = 1.0;
15455                         break;
15456 
15457                   }
15458                   /* start with the first element */
15459                   NextElm = NULL;
15460                   N_ROId = 0;
15461                   do {
15462                      if (!NextElm) {
15463                         NextElm = dlist_head(D_ROI->ROIstrokelist);
15464                      }else {
15465                         NextElm = dlist_next(NextElm);
15466                      }
15467                      ROId = (SUMA_ROI_DATUM *)NextElm->data;
15468                      if (ROId->Type == SUMA_ROI_NodeSegment) {
15469                         if (ROId->N_n) {
15470                            if (!N_ROId) {
15471                               /* draw 1st sphere */
15472                               SUMA_LH("First sphere");
15473                               if (AmbDiff) {
15474                                  glMaterialfv(GL_FRONT,
15475                                               GL_AMBIENT_AND_DIFFUSE,
15476                                               ROI_SphCol_frst);
15477                               }  else { /* AmbDiff lights out */
15478                                  glMaterialfv(GL_FRONT,
15479                                               GL_AMBIENT_AND_DIFFUSE, NoColor);
15480                                  glMaterialfv(GL_FRONT, GL_EMISSION,
15481                                              ROI_SphCol_frst);
15482                               }
15483                               idFirst = 3 * ROId->nPath[0];
15484                               glTranslatef ( SO->NodeList[idFirst],
15485                                              SO->NodeList[idFirst+1],
15486                                              SO->NodeList[idFirst+2]);
15487                               gluSphere(
15488                                  SO->NodeMarker->sphobj,
15489                                  SO->NodeMarker->sphrad*
15490                                     SUMA_MAX_PAIR(sv->ZoomCompensate, 0.06),
15491                                  SO->NodeMarker->slices,
15492                                  SO->NodeMarker->stacks);
15493                               glTranslatef (-SO->NodeList[idFirst],
15494                                             -SO->NodeList[idFirst+1],
15495                                             -SO->NodeList[idFirst+2]);
15496                            }
15497 
15498                            glLineWidth(6);
15499                            if (AmbDiff) {
15500                               glMaterialfv(GL_FRONT,
15501                                            GL_AMBIENT_AND_DIFFUSE,
15502                                            ROI_SphCol);
15503                            }  else { /* AmbDiff lights out */
15504                               glMaterialfv(GL_FRONT,
15505                                            GL_AMBIENT_AND_DIFFUSE, NoColor);
15506                               glMaterialfv(GL_FRONT, GL_EMISSION,
15507                                           ROI_SphCol);
15508                            }
15509                            /* always start at 1 since the 0th node was
15510                               drawn at the end of the previous ROId */
15511                            for (ii = 1; ii < ROId->N_n; ++ii) {
15512                               id = 3 * ROId->nPath[ii];
15513                               id2 = 3 * ROId->nPath[ii-1];
15514 
15515                               /* draw lines connecting spheres */
15516                               glBegin(GL_LINES);
15517                               glVertex3f(SO->NodeList[id2], SO->NodeList[id2+1],
15518                                          SO->NodeList[id2+2]);
15519                               glVertex3f(SO->NodeList[id], SO->NodeList[id+1],
15520                                          SO->NodeList[id+2]);
15521                               glEnd();
15522 
15523                               glTranslatef (SO->NodeList[id], SO->NodeList[id+1],                                             SO->NodeList[id+2]);
15524                               gluSphere(
15525                                  SO->NodeMarker->sphobj,
15526                                  SO->NodeMarker->sphrad*
15527                                     SUMA_MAX_PAIR(sv->ZoomCompensate, 0.06),
15528                                  SO->NodeMarker->slices, SO->NodeMarker->stacks);
15529                               glTranslatef (-SO->NodeList[id],
15530                                             -SO->NodeList[id+1],
15531                                             -SO->NodeList[id+2]);
15532                            }
15533 
15534 
15535                            ++N_ROId;
15536                         }
15537                      } else { /* non segment type Drawn ROI */
15538                            #if 0
15539                               /* it is too much to fill with spheres... */
15540                               glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,
15541                                            ROI_NodeGroup);
15542                               for (ii=0; ii < ROId->N_n; ++ii) {
15543                                  id = 3 * ROId->nPath[ii];
15544                                  glTranslatef (SO->NodeList[id],
15545                                                SO->NodeList[id+1],
15546                                                SO->NodeList[id+2]);
15547                                  gluSphere(SO->NodeMarker->sphobj,
15548                                            SO->NodeMarker->sphrad,
15549                                            SO->NodeMarker->slices,
15550                                            SO->NodeMarker->stacks);
15551                                  glTranslatef (-SO->NodeList[id],
15552                                                -SO->NodeList[id+1],
15553                                                -SO->NodeList[id+2]);
15554                               }
15555                            #endif
15556                      }
15557                   } while (NextElm != dlist_tail(D_ROI->ROIstrokelist));
15558                } else if (SUMAg_CF->ROI_contmode) {
15559                   /* finished, draw contour */
15560                   SUMA_LH("Finished DROI");
15561                   ROI_SphCol_frst[0] = 1.0;
15562                   ROI_SphCol_frst[1] = 0.3;
15563                   ROI_SphCol_frst[2] = 1.0;
15564                   ROI_SphCol_frst[3] = 1.0;
15565                   ROI_SphCol[0] = 1.0;
15566                   ROI_SphCol[1] = 1.0;
15567                   ROI_SphCol[2] = 0.0;
15568                   ROI_SphCol[3] = 1.0;
15569 
15570 
15571                   if (D_ROI->CE) {
15572                      int id1cont, id2cont, icont;
15573                      /* Draw the contour */
15574 
15575                      if (!SO->patchNodeMask) {
15576                         glLineWidth(2);
15577                         if (AmbDiff) {
15578                            glMaterialfv(GL_FRONT,
15579                                         GL_AMBIENT_AND_DIFFUSE,
15580                                         D_ROI->FillColor);
15581                         }  else { /* AmbDiff lights out */
15582                            glMaterialfv(GL_FRONT,
15583                                         GL_AMBIENT_AND_DIFFUSE, NoColor);
15584                            glMaterialfv(GL_FRONT, GL_EMISSION,
15585                                        D_ROI->FillColor);
15586                         }
15587                         SUMA_LH("Drawing contour ...");
15588                         for (icont = 0; icont < D_ROI->N_CE; ++icont) {
15589                            id1cont = 3 * D_ROI->CE[icont].n1;
15590                            id2cont = 3 * D_ROI->CE[icont].n2;
15591                            glBegin(GL_LINES);
15592                            glVertex3f(SO->NodeList[id2cont],
15593                                       SO->NodeList[id2cont+1],
15594                                       SO->NodeList[id2cont+2]);
15595                            glVertex3f(SO->NodeList[id1cont],
15596                                       SO->NodeList[id1cont+1],
15597                                       SO->NodeList[id1cont+2]);
15598                            glEnd();
15599                         }
15600                      } else {
15601                         if (SO->EmbedDim == 2) {
15602                            glLineWidth(1);
15603                         } else {
15604                            glLineWidth(2);
15605                         }
15606                         if (AmbDiff) {
15607                            glMaterialfv(GL_FRONT,
15608                                         GL_AMBIENT_AND_DIFFUSE,
15609                                         D_ROI->FillColor);
15610                         }  else { /* AmbDiff lights out */
15611                            glMaterialfv(GL_FRONT,
15612                                         GL_AMBIENT_AND_DIFFUSE, NoColor);
15613                            glMaterialfv(GL_FRONT, GL_EMISSION,
15614                                        D_ROI->FillColor);
15615                         }
15616 
15617                         SUMA_LHv("Drawing contour on patch (%p)...",
15618                                  SO->NodeNormList);
15619                                  /* set default offset to nothing*/
15620                         off[0]=0.0; off[1]=0.0; off[2]=0.0;
15621                         if (SO->EmbedDim == 2) {
15622                            if (SO->NodeNormList && D_ROI->CE) {
15623                               /* just take a node in the ROI */
15624                               id2cont = 3 * D_ROI->CE[0].n2;
15625                               off[0] = 3*SO->NodeNormList[id2cont];
15626                               off[1] = 3*SO->NodeNormList[id2cont+1];
15627                               off[2] = 3*SO->NodeNormList[id2cont+2];
15628                            }
15629                         }
15630                         for (icont = 0; icont < D_ROI->N_CE; ++icont) {
15631                            id1cont = 3 * D_ROI->CE[icont].n1;
15632                            id2cont = 3 * D_ROI->CE[icont].n2;
15633                            if (SO->patchNodeMask[D_ROI->CE[icont].n1] &&
15634                                SO->patchNodeMask[D_ROI->CE[icont].n2]) {
15635 
15636                               glBegin(GL_LINES);
15637                               glVertex3f(SO->NodeList[id2cont]+off[0],
15638                                          SO->NodeList[id2cont+1]+off[1],
15639                                          SO->NodeList[id2cont+2]+off[2]);
15640                               glVertex3f(SO->NodeList[id1cont]+off[0],
15641                                          SO->NodeList[id1cont+1]+off[1],
15642                                          SO->NodeList[id1cont+2]+off[2]);
15643                               glEnd();
15644                            }
15645                         }
15646                      }
15647                   }
15648 
15649                }
15650 
15651             }
15652             break;
15653 
15654          case ROIO_type:
15655             /* hopefully he distinction between drawn
15656                and not drawn will no longer be needed .... */
15657             ROI = (SUMA_ROI *)dov[i].OP;
15658             if (SUMA_isROIrelated (ROI, SO)) { /* draw it */
15659                if (LocalHead)
15660                   fprintf(SUMA_STDERR,
15661                            "%s: Drawing ROI %s \n", FuncName, ROI->Label);
15662                switch (ROI->Type) { /* ROI types */
15663                   case SUMA_ROI_EdgeGroup:
15664                      if (AmbDiff) {
15665                         glMaterialfv(GL_FRONT,
15666                                      GL_AMBIENT_AND_DIFFUSE,
15667                                      ROI_EdgeGroup);
15668                      }  else { /* AmbDiff lights out */
15669                         glMaterialfv(GL_FRONT,
15670                                      GL_AMBIENT_AND_DIFFUSE, NoColor);
15671                         glMaterialfv(GL_FRONT, GL_EMISSION,
15672                                     ROI_EdgeGroup);
15673                      }
15674                      for (ii=0; ii < ROI->N_ElInd; ++ii) {
15675                         EdgeIndex = ROI->ElInd[ii];
15676                         Node1 = SO->EL->EL[EdgeIndex][0];
15677                         Node2 = SO->EL->EL[EdgeIndex][1];
15678                         id = 3 * Node1;
15679                         id2 = 3 * Node2;
15680 
15681                         glLineWidth(3);
15682 
15683                         glBegin(GL_LINES);
15684                         glVertex3f( SO->NodeList[id2], SO->NodeList[id2+1],
15685                                     SO->NodeList[id2+2]);
15686                         glVertex3f( SO->NodeList[id], SO->NodeList[id+1],
15687                                     SO->NodeList[id+2]);
15688                         glEnd();
15689                      }
15690                      break;
15691                   case SUMA_ROI_NodeGroup:
15692                      if (AmbDiff) {
15693                         glMaterialfv(GL_FRONT,
15694                                      GL_AMBIENT_AND_DIFFUSE,
15695                                      ROI_NodeGroup);
15696                      }  else { /* AmbDiff lights out */
15697                         glMaterialfv(GL_FRONT,
15698                                      GL_AMBIENT_AND_DIFFUSE, NoColor);
15699                         glMaterialfv(GL_FRONT, GL_EMISSION,
15700                                     ROI_NodeGroup);
15701                      }
15702                      for (ii=0; ii < ROI->N_ElInd; ++ii) {
15703                         id = 3 * ROI->ElInd[ii];
15704                         glTranslatef (SO->NodeList[id], SO->NodeList[id+1],
15705                                       SO->NodeList[id+2]);
15706                         gluSphere(SO->NodeMarker->sphobj,
15707                                     SO->NodeMarker->sphrad*
15708                                     SUMA_MAX_PAIR(sv->ZoomCompensate, 0.06),
15709                            SO->NodeMarker->slices, SO->NodeMarker->stacks);
15710                         glTranslatef (-SO->NodeList[id], -SO->NodeList[id+1],
15711                                       -SO->NodeList[id+2]);
15712                      }
15713                      break;
15714                   case SUMA_ROI_FaceGroup:
15715                      if (AmbDiff) {
15716                         glMaterialfv(GL_FRONT,
15717                                      GL_AMBIENT_AND_DIFFUSE,
15718                                      ROI_FaceGroup);
15719                      }  else { /* AmbDiff lights out */
15720                         glMaterialfv(GL_FRONT,
15721                                      GL_AMBIENT_AND_DIFFUSE, NoColor);
15722                         glMaterialfv(GL_FRONT, GL_EMISSION,
15723                                     ROI_FaceGroup);
15724                      }
15725 
15726                      for (ii=0; ii < ROI->N_ElInd; ++ii) {
15727                            FaceIndex = ROI->ElInd[ii];
15728                            id = FaceIndex * 3;
15729 
15730                            Node1 = SO->FaceSetList[id];
15731                            Node2 = SO->FaceSetList[id+1];
15732                            Node3 = SO->FaceSetList[id+2];
15733 
15734                            id1 = 3 * Node1;
15735                            id2 = 3 * Node2;
15736                            id3 = 3 * Node3;
15737 
15738                            glLineWidth(6);
15739 
15740                            #if 0 /* no need for that one, most likely */
15741 
15742                               dx = SUMA_SELECTED_FACESET_OFFSET_FACTOR *
15743                                     SO->FaceNormList[id];
15744                               dy = SUMA_SELECTED_FACESET_OFFSET_FACTOR *
15745                                     SO->FaceNormList[id+1];
15746                               dz = SUMA_SELECTED_FACESET_OFFSET_FACTOR *
15747                                     SO->FaceNormList[id+2];
15748 
15749 
15750                               glBegin(GL_LINE_LOOP);
15751                                  glVertex3f( SO->NodeList[id1]+dx,
15752                                              SO->NodeList[id1+1]+dy,
15753                                              SO->NodeList[id1+2]+dz);
15754                                  glVertex3f( SO->NodeList[id2]+dx,
15755                                              SO->NodeList[id2+1]+dy,
15756                                              SO->NodeList[id2+2]+dz);
15757                                  glVertex3f( SO->NodeList[id3]+dx,
15758                                              SO->NodeList[id3+1]+dy,
15759                                              SO->NodeList[id3+2]+dz);
15760                               glEnd();
15761 
15762 
15763                               glBegin(GL_LINE_LOOP);
15764                                  glVertex3f( SO->NodeList[id1]-dx,
15765                                              SO->NodeList[id1+1]-dy,
15766                                              SO->NodeList[id1+2]-dz);
15767                                  glVertex3f( SO->NodeList[id2]-dx,
15768                                              SO->NodeList[id2+1]-dy,
15769                                              SO->NodeList[id2+2]-dz);
15770                                  glVertex3f( SO->NodeList[id3]-dx,
15771                                              SO->NodeList[id3+1]-dy,
15772                                              SO->NodeList[id3+2]-dz);
15773                               glEnd();
15774                            #endif
15775 
15776                            glBegin(GL_LINE_LOOP);
15777                               glVertex3f( SO->NodeList[id1],
15778                                           SO->NodeList[id1+1],
15779                                           SO->NodeList[id1+2]);
15780                               glVertex3f( SO->NodeList[id2],
15781                                           SO->NodeList[id2+1],
15782                                           SO->NodeList[id2+2]);
15783                               glVertex3f( SO->NodeList[id3],
15784                                           SO->NodeList[id3+1],
15785                                           SO->NodeList[id3+2]);
15786                            glEnd();
15787 
15788                      }
15789                      break;
15790                   default:
15791                      fprintf( SUMA_STDERR,
15792                               "Error %s: Not ready to drawn this type of ROI.\n",                               FuncName);
15793                      break;
15794                } /* ROI types */
15795             } /* draw it */
15796             break;
15797          default:
15798             /* not an ROI */
15799             break;
15800       }/* case Object Type */
15801 
15802    }
15803 
15804    /* lights out */
15805    if (AmbDiff) {
15806       glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE,  NoColor);
15807    }  else {
15808       glMaterialfv(GL_FRONT,
15809                    GL_AMBIENT_AND_DIFFUSE, NoColor);
15810       glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
15811    }
15812 
15813    SUMA_RETURN (YUP);
15814 }
15815 
15816 /*!
15817    \brief A wrapper for SUMA_Paint_SO_ROIplanes
15818 
15819    Notification of afni is done if requested
15820 */
SUMA_Paint_SO_ROIplanes_w(SUMA_SurfaceObject * SO,SUMA_DO * dov,int N_do)15821 SUMA_Boolean SUMA_Paint_SO_ROIplanes_w (SUMA_SurfaceObject *SO,
15822                                        SUMA_DO* dov, int N_do)
15823 {
15824    static char FuncName[]={"SUMA_Paint_SO_ROIplanes_w"};
15825    NI_element **nelv=NULL;
15826    int N_nelv = 0, ii=0;
15827    SUMA_Boolean CreateNel, LocalHead = NOPE;
15828 
15829    SUMA_ENTRY;
15830 
15831    SUMA_LH("Called");
15832 
15833    CreateNel = SUMAg_CF->ROI2afni;
15834    if (!SUMA_Paint_SO_ROIplanes (SO, SUMAg_DOv, SUMAg_N_DOv,
15835                                  &CreateNel,
15836                                  &nelv, &N_nelv)) {
15837       SUMA_SLP_Err("Failed in SUMA_Paint_SO_ROIplanes.");
15838       SUMA_RETURN(NOPE);
15839    }
15840 
15841    if (SUMAg_CF->ROI2afni != CreateNel) {
15842       /* it was turned off in the function */
15843       SUMAg_CF->ROI2afni = CreateNel;
15844       if (SUMAg_CF->X->DrawROI) {
15845          XmToggleButtonSetState (SUMAg_CF->X->DrawROI->AfniLink_tb,
15846                                  SUMAg_CF->ROI2afni, NOPE);
15847       }
15848    }
15849 
15850    if (SUMAg_CF->ROI2afni) {
15851       SUMA_LH("Should send nels to AFNI...");
15852       if (N_nelv) {
15853          for (ii=0; ii < N_nelv; ++ii) {
15854             SUMA_LH("Send this nel to AFNI.");
15855             /* SUMA_ShowNel((void*)nelv[ii]);*/
15856             /* Here you should write elements to SUMA_TO_MATLAB_STREAM
15857             Also, you should have a variable saying how encoding should
15858             be done for each of the streams */
15859             if (NI_write_element( SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] ,
15860                                   nelv[ii] , NI_BINARY_MODE ) < 0) {
15861                SUMA_SLP_Err("NI_write_element failed.");
15862             }
15863             SUMA_LH("Free this nel.");
15864             NI_free_element(nelv[ii]) ; nelv[ii] = NULL;
15865          }
15866          SUMA_LH("Now free nelv");
15867          SUMA_free(nelv);nelv = NULL;
15868       }
15869    }
15870 
15871    SUMA_RETURN(YUP);
15872 
15873 }
15874 
15875 /*!
15876    \brief Where real men draw their ROIs
15877 
15878    - First the function creates a list
15879    of the various ROI planes on SO
15880    - For each plane
15881       - Fill them up with ROIs nodes, do mixing if necessary
15882       - If CreateNel is YUP, a NI data set of the type
15883        SUMA_NODE_ROI is created for each color plane.
15884        These data sets are meant to be sent to AFNI in realtime.
15885        You will have to free nelvp
15886 
15887 
15888 */
SUMA_Paint_SO_ROIplanes(SUMA_SurfaceObject * SO,SUMA_DO * dov,int N_do,SUMA_Boolean * CreateNel,NI_element *** nelvp,int * N_nelvp)15889 SUMA_Boolean SUMA_Paint_SO_ROIplanes ( SUMA_SurfaceObject *SO,
15890                                        SUMA_DO* dov, int N_do,
15891                                        SUMA_Boolean *CreateNel,
15892                                        NI_element ***nelvp, int *N_nelvp)
15893 {
15894    static char FuncName[]={"SUMA_Paint_SO_ROIplanes"};
15895    DList * ROIPlaneList = NULL;
15896    SUMA_ROI_PLANE *Plane = NULL;
15897    int *N_ColHist = NULL, *ivect = NULL, *Nodes=NULL, *ilab=NULL, *labvect=NULL;
15898    float *r=NULL, *g=NULL, *b=NULL, *rvect=NULL, *gvect=NULL, *bvect=NULL;
15899    float FillColor[4]={0.0, 0.0, 0.0, 1.0};
15900    int i= 0, ii= 0, N_NewNode = 0, istore= 0, OverInd=-1,
15901       inode= 0, i_D_ROI= 0, LastOfPreSeg= 0, N_Nodes=0;
15902    SUMA_OVERLAY_PLANE_DATA sopd;
15903    DListElmt *NextPlaneElm = NULL, *NextROIElm = NULL, *NextElm=NULL;
15904    SUMA_DRAWN_ROI *D_ROI = NULL;
15905    SUMA_ROI_DATUM *ROId=NULL;
15906    NI_element **nelv = NULL;
15907    char *mapname=NULL;
15908    char *eee = NULL;
15909    DList *list=NULL;
15910    static int iwarn=0;
15911    SUMA_EngineData *ED = NULL;
15912    SUMA_Boolean Unique = NOPE;
15913    static int iwarn2=0;
15914    SUMA_Boolean LocalHead = NOPE;
15915 
15916    SUMA_ENTRY;
15917 
15918    memset(&sopd, 0, sizeof(SUMA_OVERLAY_PLANE_DATA));
15919    SUMA_LH("Called");
15920    /* select the color map */
15921    {
15922       eee = getenv("SUMA_ROIColorMap");
15923       if (eee) {
15924          if (!strcmp(eee, "roi256")) {
15925             mapname = "ROI_i256";
15926             if (!iwarn) SUMA_S_Note( "roi256 colormap is now ROI_i256\n"
15927                            "To use old roi256, use ygbrp256");
15928             ++iwarn;
15929          }else if (!strcmp(eee, "roi128")) {
15930             mapname = "ROI_i128";
15931             if (!iwarn) SUMA_S_Note( "roi128 colormap is now ROI_i128\n"
15932                            "To use old roi128, use ygbrp128");
15933             ++iwarn;
15934          }else if (!strcmp(eee, "roi64")) {
15935             mapname = "ROI_i64";
15936             if (!iwarn) SUMA_S_Note( "roi64 colormap is now ROI_i64\n"
15937                            "To use old roi64, use ygbrp64");
15938             ++iwarn;
15939          }else if (SUMA_StandardMapIndex(eee) >= 0) {
15940             mapname = eee;
15941          } else {
15942             mapname = "ROI_i64";
15943             if (LocalHead)
15944                fprintf(SUMA_STDERR, "%s: Unrecognized colormap %s.\n"
15945                                     " Using %s instead.\n",
15946                                     FuncName, eee, mapname);
15947          }
15948       } else {
15949          mapname = "ROI_i64";
15950          if (LocalHead)
15951             fprintf(SUMA_STDERR,
15952                "%s: Undefined environment. Using default ROI colormap %s\n",
15953                FuncName, mapname);
15954       }
15955    }
15956    if (LocalHead) {
15957       int N_tmp;
15958       char *nm_tmp =
15959          SUMA_StandardMapName (SUMA_StandardMapIndex(mapname), &N_tmp);
15960          fprintf(SUMA_STDERR,
15961             "%s: mapcode = %d, named %s %d cols\n",
15962             FuncName, SUMA_StandardMapIndex(mapname), nm_tmp, N_tmp);
15963    }
15964    /* intilialize list */
15965    ROIPlaneList = SUMA_Addto_ROIplane_List (NULL, NULL, 0);
15966    /* go through all ROIs and place each under its ROI plane */
15967    for (i=0; i < N_do; ++i) {
15968       switch (dov[i].ObjectType) { /* case Object Type */
15969          case ROIdO_type:
15970             D_ROI = (SUMA_DRAWN_ROI *)dov[i].OP;
15971             break;
15972          default:
15973             D_ROI = NULL;
15974             break;
15975       }
15976       if (D_ROI && SUMA_isdROIrelated (D_ROI, (SUMA_ALL_DO *)SO)) {
15977          /* found one, put it in list if useful */
15978          if (D_ROI->ROIstrokelist) {
15979                SUMA_LH("Adding plane");
15980                /* add it to plane list */
15981                /* Add the plane, even if it has no strokes in it.
15982                Otherwise, the last undo will have no effect on the
15983                paint job. Bug fix Wed Jun 11 11:04:08 EDT 2003*/
15984                ROIPlaneList = SUMA_Addto_ROIplane_List ( ROIPlaneList,
15985                                                          dov, i);
15986 
15987          }
15988 
15989       }
15990    }
15991 
15992    if (*CreateNel && !nelvp) {
15993       SUMA_SLP_Err("nelvp is null!\n"
15994                    "Turning ROIlink Off.");
15995       *CreateNel = NOPE;
15996    }
15997    /* Deal with SUMA_TO_MATLAB_STREAM_INDEX here too */
15998    if (*CreateNel && !SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX]) {
15999       SUMA_SLP_Err(  "You are not connected\n"
16000                      "to AFNI. Turning \n"
16001                      "ROIlink Off.");
16002       *CreateNel = NOPE;
16003    }
16004 
16005    if (*CreateNel) {
16006       /* user wants ni elements to sent to AFNI */
16007       nelv = (NI_element **)
16008          SUMA_calloc(dlist_size(ROIPlaneList), sizeof(NI_element *));
16009       if (!nelv) {
16010          SUMA_SLP_Err("Failed to allocate\nfor nelv.");
16011          SUMA_RETURN(NOPE);
16012       }
16013       *N_nelvp = dlist_size(ROIPlaneList);
16014    }
16015 
16016    /* For each ROI plane */
16017    NextPlaneElm = NULL;
16018    for (i=0; i < dlist_size(ROIPlaneList); ++i) {
16019       if (!NextPlaneElm) NextPlaneElm = dlist_head(ROIPlaneList);
16020       else NextPlaneElm = NextPlaneElm->next;
16021 
16022       Plane = (SUMA_ROI_PLANE *)NextPlaneElm->data;
16023 
16024       if (LocalHead)
16025          fprintf (SUMA_STDERR,
16026                   "%s: Processing plane %s\n",
16027                   FuncName, Plane->name);
16028 
16029       if (!dlist_size(Plane->ROI_index_lst)) continue;
16030 
16031       /* allocate for node color history and all node colors */
16032       N_ColHist = (int *) SUMA_calloc(SO->N_Node, sizeof (int));
16033       r = (float *)SUMA_malloc (SO->N_Node*sizeof(float));
16034       g = (float *)SUMA_malloc (SO->N_Node*sizeof(float));
16035       b = (float *)SUMA_malloc (SO->N_Node*sizeof(float));
16036       if (*CreateNel) ilab = (int *) SUMA_calloc(SO->N_Node, sizeof (int));
16037       if (!N_ColHist || !r || !g || !b || (*CreateNel && !ilab)) {
16038          SUMA_SLP_Crit( "Failed to allocate.\n"
16039                         "for N_ColHist, r, g or b.");
16040          SUMA_RETURN(NOPE);
16041       }
16042 
16043       N_NewNode = 0; /* keep track of the total number of colored nodes */
16044       /* now go through each ROI in that plane and merge the colors */
16045       NextROIElm = NULL;
16046       do {
16047          SUMA_LH("New NextROIElm");
16048          if (!NextROIElm) NextROIElm = dlist_head(Plane->ROI_index_lst);
16049          else NextROIElm = NextROIElm->next;
16050          i_D_ROI = (INT_CAST)(NextROIElm->data);
16051          if (LocalHead) fprintf (SUMA_STDERR,
16052                                  "%s: Working with DO %d/%d.\n",
16053                                  FuncName,  i_D_ROI, N_do);
16054          D_ROI = (SUMA_DRAWN_ROI *) dov[i_D_ROI].OP;
16055 
16056          /* Set the fillcolor */
16057          if (D_ROI->ColorByLabel) {
16058             SUMA_LHv("Color by label %d (iLabel=%d)\n",
16059                      D_ROI->ColorByLabel, D_ROI->iLabel);
16060 
16061             if (!SUMAg_CF->ROI_CM) {
16062                if (!(SUMAg_CF->ROI_CM = SUMA_FindNamedColMap (mapname))) {
16063                   if (!iwarn2) {
16064                      SUMA_SLP_Err( "Failed to create\n"
16065                                  "color map. Reverting\n"
16066                                  "to FillColors\n This message is shown once.");
16067                      ++iwarn2;
16068                   }
16069                   D_ROI->ColorByLabel = NOPE;
16070                }
16071                if (LocalHead) {
16072                   fprintf (SUMA_STDERR,
16073                            "%s:\nHave colormap of code %d, %dx%d colors.\n",
16074                            FuncName, SUMA_StandardMapIndex(mapname),
16075                            SUMAg_CF->ROI_CM->N_M[0], SUMAg_CF->ROI_CM->N_M[1]);
16076                }
16077 
16078                /* if connected to AFNI, send color map */
16079                /* Need to add handling for SUMA_TO_MATLAB_STREAM_INDEX */
16080                if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] &&
16081                    SUMAg_CF->ROI2afni) {
16082                   int mapcode = -1;
16083                   list = SUMA_CreateList();
16084                   ED = SUMA_InitializeEngineListData (SE_SendColorMapToAfni);
16085                   mapcode = SUMA_StandardMapIndex(mapname);
16086                   if (!SUMA_RegisterEngineListCommand (
16087                                                    list, ED,
16088                                                    SEF_i, (void*)&mapcode,
16089                                                    SES_SumaWidget, NULL, NOPE,
16090                                                    SEI_Head, NULL )) {
16091                      fprintf(SUMA_STDERR,
16092                               "Error %s: Failed to register command\n",
16093                               FuncName);
16094                      SUMA_RETURN(NOPE);
16095                   }
16096                   if (!SUMA_Engine (&list)) {
16097                      fprintf( stderr,
16098                               "Error %s: SUMA_Engine call failed.\n",
16099                               FuncName);
16100                      SUMA_RETURN(NOPE);
16101                   }
16102 
16103                }
16104             }
16105          } else {
16106             SUMA_LHv("Not color by label %d (iLabel=%d)\n",
16107                      D_ROI->ColorByLabel, D_ROI->iLabel);
16108          }
16109 
16110          /* make sure Color ByLabel is possible */
16111          if (D_ROI->ColorByLabel) {
16112             if (D_ROI->iLabel < 0 || D_ROI->iLabel >= SUMAg_CF->ROI_CM->N_M[0]) {
16113                SUMA_SLP_Err(  "ROI iLabel < 0 or \n"
16114                               "higher than the number\n"
16115                               "of colors in the map.\n"
16116                               "Reverting to FillColors");
16117                D_ROI->ColorByLabel = NOPE;
16118             }
16119          }
16120 
16121          if (D_ROI->ColorByLabel) {
16122             if (D_ROI->iLabel < 0 || D_ROI->iLabel >= SUMAg_CF->ROI_CM->N_M[0]) {
16123                SUMA_SLP_Err(  "ROI iLabel < 0 or \n"
16124                               "higher than the number\n"
16125                               "of colors in the map.\n"
16126                               "Reverting to FillColors");
16127                D_ROI->ColorByLabel = NOPE;
16128             }
16129             /* coloring for ROIs is straight forward, index based */
16130             D_ROI->FillColor[0] = SUMAg_CF->ROI_CM->M[D_ROI->iLabel][0];
16131             D_ROI->FillColor[1] = SUMAg_CF->ROI_CM->M[D_ROI->iLabel][1];
16132             D_ROI->FillColor[2] = SUMAg_CF->ROI_CM->M[D_ROI->iLabel][2];
16133             if (SUMAg_CF->ROI_CM->N_M[1] == 4)
16134                D_ROI->FillColor[3] = SUMAg_CF->ROI_CM->M[D_ROI->iLabel][3];
16135             else D_ROI->FillColor[3] = 1.0;
16136          } else {
16137             SUMA_COPY_VEC (D_ROI->FillColor, FillColor, 4,float, float);
16138          }
16139 
16140          /* now for each node in the DrawnROI, add its color */
16141          N_Nodes = 0;
16142          Unique = YUP; /* This is to eliminate redundant nodes
16143                         that can legally occur when the path loops
16144                         over itself. As a result, nodes
16145                         that are visited multiple times appear
16146                         brighter than the surrounding. */
16147          Nodes = SUMA_NodesInROI (D_ROI, &N_Nodes, Unique);
16148          if (Nodes) {
16149             for (ii=0; ii < N_Nodes; ++ii) {
16150                inode = Nodes[ii];
16151                if (inode >= SO->N_Node) {
16152                   SUMA_S_Errv("Have node %d, SO->N_Node = %d\n"
16153                      "Make sure ROI loaded belongs to this surface.\n",
16154                               inode , SO->N_Node) ;
16155                               SUMA_RETURN(NOPE);
16156                }
16157                if (!N_ColHist[inode]) {
16158                   r[inode] = D_ROI->FillColor[0]*D_ROI->FillColor[3];
16159                   g[inode] = D_ROI->FillColor[1]*D_ROI->FillColor[3];
16160                   b[inode] = D_ROI->FillColor[2]*D_ROI->FillColor[3];
16161                   if (*CreateNel) ilab[inode] = D_ROI->iLabel;
16162                   ++N_NewNode;
16163                } else { /* already used up color, add new color */
16164                   SUMA_LH("Revisiting Color");
16165                   r[inode] = r[inode] + D_ROI->FillColor[0]*D_ROI->FillColor[3];
16166                   g[inode] = g[inode] + D_ROI->FillColor[1]*D_ROI->FillColor[3];
16167                   b[inode] = b[inode] + D_ROI->FillColor[2]*D_ROI->FillColor[3];
16168                   if (*CreateNel) {
16169                      /* IGNORE repeats for the same node for now */
16170                   }
16171                }
16172                ++N_ColHist[inode];
16173             }
16174 
16175             SUMA_free(Nodes);
16176          }
16177       } while (NextROIElm != dlist_tail(Plane->ROI_index_lst));
16178 
16179       SUMA_LH("Scaling and storing ");
16180       /* create a conveninent list of the colors that goes into */
16181       ivect = (int *)SUMA_malloc(N_NewNode * sizeof(int));
16182       rvect = (float *)SUMA_malloc(N_NewNode * sizeof(float));
16183       gvect = (float *)SUMA_malloc(N_NewNode * sizeof(float));
16184       bvect = (float *)SUMA_malloc(N_NewNode * sizeof(float));
16185       if (*CreateNel) labvect = (int *)SUMA_malloc(N_NewNode * sizeof(int));
16186       if (!ivect || !rvect || !gvect || !bvect || (*CreateNel && !labvect)) {
16187          SUMA_SLP_Crit( "Failed to allocate.\n"
16188                         "for *vect family");
16189          SUMA_RETURN(NOPE);
16190       }
16191 
16192       istore = 0;
16193       for (ii=0; ii < SO->N_Node; ++ii) {
16194          if (N_ColHist[ii]) {
16195             #if 0
16196                /* You do not want to average the colors after summing them
16197                because that will have the effect of dimming them.
16198                Say you had 0 0 1 and 0 1 0
16199                You'll end up with 0 0.5 0.5 which does not have the
16200                same brightness as the original colors.
16201                You might want to make the brightness uniform but
16202                we leave that for posterity ...
16203                */
16204                if (N_ColHist[ii] > 1) {
16205                   /* scale the summed colors for that plane */
16206 
16207                   r[ii] /= N_ColHist[ii];
16208                   g[ii] /= N_ColHist[ii];
16209                   b[ii] /= N_ColHist[ii];
16210                }
16211             #endif
16212             /* put the colors in the short vectors */
16213             ivect[istore] = ii;
16214             rvect[istore] = r[ii];
16215             gvect[istore] = g[ii];
16216             bvect[istore] = b[ii];
16217             if (*CreateNel) labvect[istore] = ilab[ii];
16218             ++istore;
16219          }
16220       }
16221 
16222       if (LocalHead) fprintf (SUMA_STDERR,"%s: N_NewNode = %d, istore = %d.\n",
16223                                     FuncName, N_NewNode, istore);
16224       SUMA_LH("Freedom");
16225       /* free the big ones */
16226       if (N_ColHist) SUMA_free(N_ColHist); N_ColHist = NULL;
16227       if (r) SUMA_free(r); r = NULL;
16228       if (g) SUMA_free(g); g = NULL;
16229       if (b) SUMA_free(b); b = NULL;
16230       if (ilab) SUMA_free(ilab); ilab = NULL;
16231 
16232       /* put the colors in a color plane */
16233       memset(&sopd, 0, sizeof(SUMA_OVERLAY_PLANE_DATA));
16234       sopd.N = N_NewNode;
16235       sopd.Type = SOPT_ifff;
16236       sopd.Source = SES_Suma;
16237       sopd.GlobalOpacity = 0.3;
16238       sopd.isBackGrnd = NOPE;
16239       sopd.Show = YUP;
16240       sopd.DimFact = 0.5;
16241       sopd.i = (void *)ivect;
16242       sopd.r = (void *)rvect;
16243       sopd.g = (void *)gvect;
16244       sopd.b = (void *)bvect;
16245       sopd.a = NULL;
16246       sopd.dtlvl = SUMA_ELEM_DAT;
16247 
16248       SUMA_LH("Calling SUMA_iRGB_to_SO_OverlayPointer");
16249       if (!SUMA_iRGB_to_SO_OverlayPointer (SO, Plane->name,
16250                                           &sopd, &OverInd,
16251                                           dov, N_do, SUMAg_CF->DsetList)) {
16252          SUMA_SLP_Err("Failed to fetch or create overlay pointer.");
16253          SUMA_RETURN(NOPE);
16254       }
16255       SUMA_LH("Returned SUMA_iRGB_to_SO_OverlayPointer");
16256 
16257       if (*CreateNel) {
16258          NI_element *nel = NULL;
16259          char *TargetVol=NULL;
16260 
16261          /* form the nel for this plane */
16262          SUMA_allow_nel_use(1);
16263          nel = SUMA_NewNel ( SUMA_NODE_ROI, /* one of SUMA_DSET_TYPE */
16264                        SO->LocalDomainParentID, /* idcode of Domain Parent */
16265                        NULL, /* idcode of geometry parent, not useful here*/
16266                        N_NewNode,
16267                        NULL,
16268                        NULL); /* Number of elements */
16269 
16270          if (!nel) {
16271             SUMA_SLP_Err("Failed in SUMA_NewNel");
16272             SUMA_RETURN(NOPE);
16273          }
16274 
16275          if (N_NewNode) {
16276             /* Add the index column */
16277             SUMA_LH("Adding index column...");
16278             SUMA_allow_nel_use(1);
16279             if (!SUMA_AddNelCol (nel, "node index",
16280                                  SUMA_NODE_INDEX, (void *)ivect, NULL, 1)) {
16281                SUMA_SL_Err("Failed in SUMA_AddNelCol");
16282                SUMA_RETURN(NOPE);
16283             }
16284 
16285             /* Add the label column */
16286             SUMA_LH("Adding label column...");
16287             SUMA_allow_nel_use(1);
16288             if (!SUMA_AddNelCol (nel, "integer label",
16289                                  SUMA_NODE_ILABEL, (void *)labvect, NULL, 1)) {
16290                SUMA_SL_Err("Failed in SUMA_AddNelCol");
16291                SUMA_RETURN(NOPE);
16292             }
16293          }
16294 
16295          /* What is the target volume for this nel */
16296          TargetVol = SUMA_append_replace_string(SO->Group, Plane->name, "-", 0);
16297          NI_set_attribute (nel, "target_volume", TargetVol);
16298          SUMA_free(TargetVol);
16299 
16300          /* which colormap was used */
16301          NI_set_attribute (nel, "color_map", SUMAg_CF->ROI_CM->Name);
16302 
16303          /* what is the volume parent ? This one will act as a gridparent
16304             for the functional data set*/
16305          NI_set_attribute (nel, "volume_idcode", SO->VolPar->vol_idcode_str);
16306          NI_set_attribute (nel, "volume_filecode", SO->VolPar->filecode);
16307          NI_set_attribute (nel, "volume_headname", SO->VolPar->headname);
16308          NI_set_attribute (nel, "volume_dirname", SO->VolPar->dirname);
16309 
16310          nelv[i] = nel; nel = NULL;
16311 
16312          /* DO NOT FREE ivect, it is used in sopd */
16313          SUMA_free(labvect);labvect=NULL;
16314       }
16315 
16316    }
16317 
16318    if (!dlist_size(ROIPlaneList)) {
16319       /*
16320       SUMA_SLP_Err(  "Flow error\n"
16321                      "You are not expected\n"
16322                      "to land here." );
16323       Do not complain, you can get here if you
16324       are connected to SUMA.
16325       Aint nothing wrong with this.
16326       */
16327       N_NewNode = 0;
16328       ivect = NULL;
16329       rvect = NULL;
16330       gvect = NULL;
16331       bvect = NULL;
16332       if (*CreateNel && labvect) SUMA_free(labvect); labvect = NULL;
16333    }
16334 
16335 
16336    SUMA_LH("Destroying list");
16337    /* destroy plane list */
16338    dlist_destroy (ROIPlaneList); SUMA_free(ROIPlaneList); ROIPlaneList = NULL;
16339 
16340    /* Set the remix flag for that surface */
16341    if(!SUMA_SetRemixFlag (SO->idcode_str, SUMAg_SVv, SUMAg_N_SVv)) {
16342       fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_SetRemixFlag.\n", FuncName);
16343       SUMA_RETURN(NOPE);
16344    }
16345 
16346    if (*CreateNel) {
16347       *nelvp = nelv;
16348    }
16349 
16350    /* should be cool, now return */
16351    SUMA_RETURN(YUP);
16352 }
16353 
16354 /*!
16355    \brief int * SUMA_NodesInROI (SUMA_DRAWN_ROI *D_ROI, int *N_Nodes, SUMA_Boolean Unique)
16356    Returns a vector containing the number of nodes making up an ROI
16357 
16358    \param D_ROI (SUMA_DRAWN_ROI *)
16359    \param N_Nodes (int *) updated with the total number of nodes in Nodes
16360    \param Unique (SUMA_Boolean) Remove repeated node occurences
16361    \return Nodes (int *) N_Nodesx1 vector of nodes forming ROI
16362 
16363    - Nodes (and N_Nodes) might have duplicate node entries, unless you set Unique
16364 */
SUMA_NodesInROI(SUMA_DRAWN_ROI * D_ROI,int * N_Nodes,SUMA_Boolean Unique)16365 int * SUMA_NodesInROI (SUMA_DRAWN_ROI *D_ROI, int *N_Nodes, SUMA_Boolean Unique)
16366 {
16367    static char FuncName[]={"SUMA_NodesInROI"};
16368    int *Nodes = NULL, LastOfPreSeg, N_max = -1, ii;
16369    DListElmt *NextElm = NULL;
16370    SUMA_ROI_DATUM *ROId=NULL;
16371 
16372    SUMA_ENTRY;
16373 
16374    if (!dlist_size(D_ROI->ROIstrokelist)) {
16375       *N_Nodes = 0;
16376       SUMA_RETURN (NULL);
16377    }
16378 
16379    /* a quick count of number of nodes */
16380    SUMA_ROI_CRUDE_COUNT_NODES(D_ROI, N_max);
16381 
16382    if (!N_max) {
16383       *N_Nodes = 0;
16384       SUMA_RETURN (NULL);
16385    }
16386 
16387    Nodes = (int*)SUMA_calloc(N_max,sizeof(int));
16388    if (!Nodes) {
16389       SUMA_SLP_Crit("Failed to allocate for Nodes.");
16390       *N_Nodes = -1;
16391       SUMA_RETURN(NULL);
16392    }
16393 
16394    /* Fill 'er up */
16395    *N_Nodes = 0;
16396    LastOfPreSeg = -1; /* index of last node in previous segment */
16397    NextElm = NULL;
16398    do {
16399       if (!NextElm) NextElm = dlist_head(D_ROI->ROIstrokelist);
16400       else NextElm = dlist_next(NextElm);
16401 
16402       ROId = (SUMA_ROI_DATUM *)NextElm->data;
16403 
16404       for (ii=0; ii < ROId->N_n; ++ii) {
16405          if (ROId->nPath[ii] != LastOfPreSeg) {
16406             Nodes[*N_Nodes] = ROId->nPath[ii];
16407             ++ *N_Nodes;
16408          }
16409       }
16410       if (ROId->N_n) { /* store last node of segment */
16411          LastOfPreSeg = ROId->nPath[ROId->N_n - 1];
16412       } else {
16413          LastOfPreSeg = -1;
16414       }
16415    } while (NextElm != dlist_tail(D_ROI->ROIstrokelist));
16416 
16417    /* user wants sorting ? */
16418    if (Unique) {
16419       int *Nodes_Unq = NULL;
16420       int N_Nodes_Unq = -1;
16421       Nodes_Unq = SUMA_UniqueInt (Nodes, *N_Nodes, &N_Nodes_Unq, 0);
16422       if (Nodes) SUMA_free(Nodes);  Nodes = NULL;
16423       *N_Nodes = N_Nodes_Unq;
16424       Nodes = Nodes_Unq;
16425    }
16426 
16427    SUMA_RETURN(Nodes);
16428 
16429 }
16430 
SUMA_MinMaxNodesInROI(SUMA_DRAWN_ROI * D_ROI,int MinMax[])16431 SUMA_Boolean SUMA_MinMaxNodesInROI (SUMA_DRAWN_ROI *D_ROI,
16432                                     int MinMax[])
16433 {
16434    static char FuncName[]={"SUMA_MinMaxNodesInROI"};
16435    int LastOfPreSeg, N_max = -1, ii;
16436    DListElmt *NextElm = NULL;
16437    SUMA_ROI_DATUM *ROId=NULL;
16438 
16439    SUMA_ENTRY;
16440 
16441    MinMax[0] = -1; MinMax[1] = -1;
16442 
16443    if (!D_ROI || !dlist_size(D_ROI->ROIstrokelist)) {
16444       SUMA_RETURN (NOPE);
16445    }
16446 
16447    /* a quick count of number of nodes */
16448    SUMA_ROI_CRUDE_COUNT_NODES(D_ROI, N_max);
16449 
16450    if (!N_max) {
16451       SUMA_RETURN (NOPE);
16452    }
16453 
16454    MinMax[0] = 10e8;
16455    NextElm = NULL;
16456    do {
16457       if (!NextElm) NextElm = dlist_head(D_ROI->ROIstrokelist);
16458       else NextElm = dlist_next(NextElm);
16459 
16460       ROId = (SUMA_ROI_DATUM *)NextElm->data;
16461 
16462       for (ii=0; ii < ROId->N_n; ++ii) {
16463          if (ROId->nPath[ii] > MinMax[1]) MinMax[1] = ROId->nPath[ii];
16464          else if (ROId->nPath[ii] < MinMax[0]) MinMax[0] = ROId->nPath[ii];
16465       }
16466    } while (NextElm != dlist_tail(D_ROI->ROIstrokelist));
16467 
16468    SUMA_RETURN(YUP);
16469 }
16470 
SUMA_Free_ROI_PlaneData(void * da)16471 void SUMA_Free_ROI_PlaneData (void *da)
16472 {
16473    static char FuncName[]={"SUMA_Free_ROI_PlaneData"};
16474    SUMA_ROI_PLANE *pl = NULL;
16475 
16476    SUMA_ENTRY;
16477 
16478    pl = (SUMA_ROI_PLANE *)da;
16479 
16480    if (!pl) SUMA_RETURNe;
16481 
16482    /* destroy the list containing ROIs belonging to plane */
16483    if (pl->ROI_index_lst) {
16484       dlist_destroy (pl->ROI_index_lst);
16485       SUMA_free(pl->ROI_index_lst); pl->ROI_index_lst = NULL;
16486    }
16487    if (pl->name) SUMA_free(pl->name);
16488 
16489    /* now free the structure */
16490    SUMA_free(pl);
16491 
16492    SUMA_RETURNe;
16493 }
16494 
16495 /*!
16496    \brief Adds and ROI in the list of ROI planes
16497 
16498    ROIplaneList = SUMA_Addto_ROIplane_List (ROIplaneListIn,
16499                                              dov, idov);
16500 
16501    \param ROIplaneListIn (DList *) the list of
16502       ROI planes
16503    \param dov (SUMA_DO *) vector of displayable objects
16504    \param idov (int) index into dov of DrawnROI object
16505    \return ROIplaneList DList *) the updated
16506       list of ROI planes
16507 
16508    - If the ROI is part of a new plane,
16509    the plane is added to the list and the ROI
16510    is placed under that plane.
16511    - If the ROI is part of a plane in the list
16512    then the ROI is placed under that plane
16513    - The first time you call the function,
16514    send in NULL for ROIplaneListIn to initialize
16515    the list.
16516    - The subsequent times you call the function
16517    use the returned ROIplaneList for ROIplaneListIn
16518 
16519 */
SUMA_Addto_ROIplane_List(DList * ROIplaneListIn,SUMA_DO * dov,int idov)16520 DList * SUMA_Addto_ROIplane_List (DList *ROIplaneListIn, SUMA_DO *dov, int idov)
16521 {
16522    static char FuncName[]={"SUMA_Addto_ROIplane_List"};
16523    DList *ROIplaneList = NULL;
16524    DListElmt *NextElm = NULL;
16525    SUMA_DRAWN_ROI *D_ROI = NULL;
16526    char *UsedName = NULL;
16527    SUMA_DO *doel = NULL;
16528    SUMA_ROI_PLANE *Plane=NULL;
16529    int i=0;
16530    SUMA_Boolean found = NOPE;
16531    SUMA_Boolean LocalHead = NOPE;
16532 
16533    SUMA_ENTRY;
16534 
16535    if (!ROIplaneListIn) { /* initialization land */
16536       ROIplaneList = (DList *)SUMA_calloc(1,sizeof(DList));
16537       dlist_init (ROIplaneList, SUMA_Free_ROI_PlaneData);
16538       SUMA_RETURN(ROIplaneList);
16539    } else {
16540       ROIplaneList = ROIplaneListIn;
16541    }
16542 
16543    doel = &(dov[idov]);
16544 
16545    if (doel->ObjectType != ROIdO_type) {
16546       SUMA_SLP_Crit("Only planning to deal\n"
16547                    "with ROIdO_type type");
16548       dlist_destroy(ROIplaneList); SUMA_free(ROIplaneList); ROIplaneList=NULL;
16549       SUMA_RETURN(NULL);
16550    }
16551 
16552    D_ROI = (SUMA_DRAWN_ROI *)doel->OP;
16553 
16554    /* What is the name of this ROI's plane ?*/
16555    if (!D_ROI->ColPlaneName) {
16556       /* Bad, no color plane name, give it a fake one */
16557       UsedName = SUMA_copy_string("DefROIpl");
16558    }else {
16559       UsedName = SUMA_copy_string(D_ROI->ColPlaneName);
16560    }
16561 
16562    /* search for the plane name in the list */
16563    i = 0;
16564    found = NOPE;
16565    Plane = NULL;
16566    while (!found && i < ROIplaneList->size) {
16567       if (i == 0) NextElm = dlist_head(ROIplaneList);
16568       else NextElm = dlist_next(NextElm);
16569       Plane = (SUMA_ROI_PLANE *)NextElm->data;
16570       if (strcmp (UsedName,Plane->name) == 0) {
16571          SUMA_LH("PlaneFound");
16572          found = YUP;
16573          SUMA_free(UsedName); /* no longer needed */
16574       }
16575       ++i;
16576    }
16577 
16578    if (!found) { /* must create this plane */
16579       Plane = (SUMA_ROI_PLANE *)SUMA_calloc(1,sizeof(SUMA_ROI_PLANE));
16580       Plane->name = UsedName; /* preserved, don't go freeing UsedName later! */
16581       Plane->ROI_index_lst = (DList *) SUMA_calloc(1,sizeof(DList));
16582       dlist_init(Plane->ROI_index_lst, NULL);
16583       dlist_ins_next(ROIplaneList, dlist_tail(ROIplaneList), (void *)Plane);
16584    }
16585 
16586    /* now put the ROI in question in that list,
16587       easiest is to store its index into dov */
16588    dlist_ins_next(Plane->ROI_index_lst,
16589                   dlist_tail(Plane->ROI_index_lst), (VOID_CAST)idov);
16590 
16591    /* OK, done, now return */
16592    SUMA_RETURN(ROIplaneList);
16593 }
16594 
16595 /*! Create the cross hair */
SUMA_DrawCrossHair(SUMA_SurfaceViewer * sv)16596 SUMA_Boolean SUMA_DrawCrossHair (SUMA_SurfaceViewer *sv)
16597 {
16598    static char FuncName[]={"SUMA_DrawCrossHair"};
16599    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
16600    static GLdouble radsph, fac;
16601    static GLfloat gapch, radch;
16602    GLboolean gl_dt;
16603    float origwidth = 0.0, off[3]={0.0, 0.0, 0.0}, *xyz=NULL;
16604    int scl = 0;
16605    SUMA_CrossHair* Ch = sv->Ch;
16606    SUMA_CLUST_DATUM *cd = NULL;
16607    SUMA_SurfaceObject *SO=NULL;
16608 
16609    SUMA_ENTRY;
16610 
16611    SO = SUMA_SV_Focus_SO(sv);
16612 
16613    if (sv->DO_PickMode) { /* nothing to draw in this mode */
16614       SUMA_RETURN(YUP);
16615    }
16616 
16617    scl = 0;
16618    if (SO) {
16619       if (SO->PolyMode == SRM_ViewerDefault && sv->PolyMode != SRM_Fill) {
16620          scl = 1;
16621       } else if (SO->PolyMode != SRM_ViewerDefault && SO->PolyMode != SRM_Fill) {
16622          scl = 1;
16623       }
16624       /* is this a flatty ? */
16625       if (Ch->datumID >= 0 && Ch->datumID < SO->N_Node
16626           && SO->NodeNormList && SO->NodeDim == 3 &&
16627           SO->EmbedDim == 2) {
16628          off[0] = SO->NodeNormList[Ch->datumID*3];
16629          off[1] = SO->NodeNormList[Ch->datumID*3+1];
16630          off[2] = SO->NodeNormList[Ch->datumID*3+2];
16631       }
16632    } else {
16633       if (sv->PolyMode != SRM_Fill) {
16634          scl = 1;
16635       }
16636    }
16637 
16638    Ch->c[0] = Ch->c[0]+off[0];
16639    Ch->c[1] = Ch->c[1]+off[1];
16640    Ch->c[2] = Ch->c[2]+off[2];
16641 
16642    if (scl) {
16643       if (SO && SO->EL && SO->EL->AvgLe > 0) {
16644          fac = SO->EL->AvgLe/15.0;
16645          radsph = fac;
16646          gapch = fac;
16647          radch = SO->EL->AvgLe/2.0;
16648       } else {
16649          fac = SUMA_MAX_PAIR(sv->ZoomCompensate, 0.03);
16650          radsph = Ch->sphrad*fac*(SUMA_sv_auto_fov(sv)/FOV_INITIAL);
16651          gapch = Ch->g*fac*(SUMA_sv_auto_fov(sv)/FOV_INITIAL);
16652          radch = Ch->r*fac*(SUMA_sv_auto_fov(sv)/FOV_INITIAL);
16653       }
16654    } else {
16655       if (SO && SO->EL && SO->EL->AvgLe > 0) {
16656          fac = SO->EL->AvgLe/10.0;
16657          radsph = fac;
16658          gapch = fac;
16659          radch = SO->EL->AvgLe;
16660       } else {
16661          fac = (SUMA_sv_auto_fov(sv)/FOV_INITIAL);
16662          radsph = Ch->sphrad*fac;
16663          gapch = Ch->g*fac;
16664          radch = Ch->r*fac;
16665       }
16666    }
16667    if (!(gl_dt = glIsEnabled(GL_DEPTH_TEST)))
16668       glEnable(GL_DEPTH_TEST);   /* To hide cross hair as it gets hidden
16669                                     by surfaces */
16670    glGetFloatv(GL_LINE_WIDTH, &origwidth);
16671    glLineWidth(Ch->LineWidth);
16672    /*fprintf(SUMA_STDOUT, "Center: %f, %f, %f. Gap %f, Radius: %f\n",\
16673       Ch->c[0], Ch->c[2], Ch->c[2], gapch, radch);*/
16674                         /* turn off ambient and diffuse components */
16675       glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor);
16676       glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
16677       if (gapch) { /* gap */
16678                            /*turn on emissivity for axis*/
16679          glMaterialfv(GL_FRONT, GL_EMISSION, Ch->XaxisColor);
16680          glBegin(GL_LINES);
16681          glVertex3f(Ch->c[0] - radch, Ch->c[1], Ch->c[2]);
16682          glVertex3f(Ch->c[0] - gapch, Ch->c[1], Ch->c[2]);
16683          glVertex3f(Ch->c[0] + radch, Ch->c[1], Ch->c[2]);
16684          glVertex3f(Ch->c[0] + gapch, Ch->c[1], Ch->c[2]);
16685          glEnd();
16686                            /*turn on emissivity for axis*/
16687          glMaterialfv(GL_FRONT, GL_EMISSION, Ch->YaxisColor);
16688          glBegin(GL_LINES);
16689          glVertex3f(Ch->c[0], Ch->c[1] - radch, Ch->c[2]);
16690          glVertex3f(Ch->c[0], Ch->c[1] - gapch, Ch->c[2]);
16691          glVertex3f(Ch->c[0], Ch->c[1] + radch, Ch->c[2]);
16692          glVertex3f(Ch->c[0], Ch->c[1] + gapch, Ch->c[2]);
16693          glEnd();
16694                            /*turn on emissivity for axis*/
16695          glMaterialfv(GL_FRONT, GL_EMISSION, Ch->ZaxisColor);
16696          glBegin(GL_LINES);
16697          glVertex3f(Ch->c[0], Ch->c[1], Ch->c[2] - radch);
16698          glVertex3f(Ch->c[0], Ch->c[1], Ch->c[2] - gapch);
16699          glVertex3f(Ch->c[0], Ch->c[1], Ch->c[2] + radch);
16700          glVertex3f(Ch->c[0], Ch->c[1], Ch->c[2] + gapch);
16701          glEnd();
16702 
16703       }/*gap */ else {/*no gap */
16704                            /*turn on emissivity for axis*/
16705          glMaterialfv(GL_FRONT, GL_EMISSION, Ch->XaxisColor);
16706          glBegin(GL_LINES);
16707          glVertex3f(Ch->c[0] - radch, Ch->c[1], Ch->c[2]);
16708          glVertex3f(Ch->c[0] + radch, Ch->c[1], Ch->c[2]);
16709          glEnd();
16710                            /*turn on emissivity for axis*/
16711          glMaterialfv(GL_FRONT, GL_EMISSION, Ch->YaxisColor);
16712          glBegin(GL_LINES);
16713          glVertex3f(Ch->c[0], Ch->c[1] - radch, Ch->c[2]);
16714          glVertex3f(Ch->c[0], Ch->c[1] + radch, Ch->c[2]);
16715          glEnd();
16716                            /*turn on emissivity for axis*/
16717          glMaterialfv(GL_FRONT, GL_EMISSION, Ch->ZaxisColor);
16718          glBegin(GL_LINES);
16719          glVertex3f(Ch->c[0], Ch->c[1], Ch->c[2] - radch);
16720          glVertex3f(Ch->c[0], Ch->c[1], Ch->c[2] + radch);
16721          glEnd();
16722       }
16723                            /*turn off emissivity for axis*/
16724       glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
16725 
16726 
16727    if (Ch->ShowSphere) {
16728       /*fprintf(SUMA_STDOUT, "SHOWING SPHERE\n");*/
16729                         /*turn on emissivity for sphere */
16730       glMaterialfv(GL_FRONT, GL_EMISSION, Ch->sphcol);
16731       glTranslatef (Ch->c[0], Ch->c[1],Ch->c[2]);
16732       gluSphere(Ch->sphobj, radsph, Ch->slices, Ch->stacks);
16733       glTranslatef (-Ch->c[0], -Ch->c[1],-Ch->c[2]);
16734                         /*turn off emissivity for axis*/
16735       glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
16736    }
16737 
16738    if (SO && SO->SurfCont &&
16739        SUMA_NodeClustNumber(SO->SurfCont->curColPlane, Ch->datumID,
16740                             SO, &cd)) {
16741             /* Mark node with maximum value in cluster where you just
16742                clicked, if possible. The Dale Stephens Option */
16743 
16744       if (cd->maxabsnode >=0) {
16745          xyz = SO->NodeList+SO->NodeDim*cd->maxabsnode;
16746          glMaterialfv(GL_FRONT, GL_EMISSION, Ch->sphcolCmax);
16747          glTranslatef (xyz[0], xyz[1],xyz[2]);
16748          gluSphere(Ch->sphobjCmax, radsph, 4, 4);
16749          glTranslatef (-xyz[0], -xyz[1],-xyz[2]);
16750                            /*turn off emissivity for axis*/
16751          glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
16752       }
16753    }
16754 
16755    glLineWidth(origwidth);
16756 
16757    /* DEPTH_TEST is on for this function, turn it off
16758       if that was the case entering the function */
16759    if (!gl_dt) glDisable(GL_DEPTH_TEST);
16760 
16761    Ch->c[0] = Ch->c[0]-off[0];
16762    Ch->c[1] = Ch->c[1]-off[1];
16763    Ch->c[2] = Ch->c[2]-off[2];
16764 
16765    SUMA_RETURN (YUP);
16766 }
16767 
16768 /* Allocate for a CrossHair object */
SUMA_Alloc_CrossHair(void)16769 SUMA_CrossHair* SUMA_Alloc_CrossHair (void)
16770 {
16771    static char FuncName[]={"SUMA_Alloc_CrossHair"};
16772    SUMA_CrossHair* Ch;
16773 
16774    SUMA_ENTRY;
16775 
16776    Ch = SUMA_calloc(1,sizeof (SUMA_CrossHair));
16777    if (Ch == NULL) {
16778       fprintf(stderr,"SUMA_Alloc_CrossHair Error: Failed to allocate Ch\n");
16779       SUMA_RETURN (NULL);
16780    }
16781 
16782    /* setup some default values */
16783    Ch->XaxisColor[0] = 1.0;
16784    Ch->XaxisColor[1] = 0.0;
16785    Ch->XaxisColor[2] = 0.0;
16786    Ch->XaxisColor[3] = 1.0;
16787 
16788    Ch->YaxisColor[0] = 0.0;
16789    Ch->YaxisColor[1] = 1.0;
16790    Ch->YaxisColor[2] = 0.0;
16791    Ch->YaxisColor[3] = 1.0;
16792 
16793    Ch->ZaxisColor[0] = 0.0;
16794    Ch->ZaxisColor[1] = 0.0;
16795    Ch->ZaxisColor[2] = 1.0;
16796    Ch->ZaxisColor[3] = 1.0;
16797 
16798    Ch->LineWidth = SUMA_CROSS_HAIR_LINE_WIDTH;
16799    Ch->Stipple = SUMA_SOLID_LINE;
16800    Ch->c[0] = Ch->c[1] = Ch->c[2] = 0.0;
16801 
16802    /* Ch->g, and Ch->r setting is currently overriden if SO->EL->AvgLe > 0.0) */
16803    Ch->g = SUMA_CROSS_HAIR_GAP/SUMA_DimSclFac(NULL, NULL);
16804    Ch->r = SUMA_CROSS_HAIR_RADIUS/SUMA_DimSclFac(NULL, NULL);
16805 
16806    /* create the ball object*/
16807    Ch->ShowSphere   = YUP;
16808    Ch->sphobj = gluNewQuadric();
16809    /* for wire frame  use GLU_LINE with GLU_NONE */
16810    /* for solid, use GLU_FILL and GLU_SMOOTH */
16811    #ifdef SUMA_SOLID_LOCAL
16812       gluQuadricDrawStyle (Ch->sphobj, GLU_FILL);
16813       gluQuadricNormals (Ch->sphobj , GLU_SMOOTH);
16814    #else
16815       gluQuadricDrawStyle (Ch->sphobj, GLU_LINE);
16816       gluQuadricNormals (Ch->sphobj , GLU_NONE);
16817    #endif
16818 
16819    Ch->sphcol[0] = 1.0; Ch->sphcol[1] = 1.0;
16820    Ch->sphcol[2] = 0.0; Ch->sphcol[3] = 0.0;
16821    /* Ch->sphrad setting is currently overriden if SO->EL->AvgLe > 0.0) */
16822    Ch->sphrad = SUMA_CROSS_HAIR_SPHERE_RADIUS/SUMA_DimSclFac(NULL, NULL);
16823    Ch->slices = 10;
16824    Ch->stacks = 10;
16825 
16826    Ch->adoID = -1;
16827    Ch->datumID = -1;
16828    Ch->secID = -1;
16829 
16830    Ch->sphobjCmax = gluNewQuadric();
16831    Ch->sphcolCmax[0] = 0.0; Ch->sphcolCmax[1] = 0.0;
16832    Ch->sphcolCmax[2] = 0.0; Ch->sphcolCmax[3] = 0.0;
16833    #ifdef SUMA_SOLID_LOCAL
16834       gluQuadricDrawStyle (Ch->sphobjCmax, GLU_FILL);
16835       gluQuadricNormals (Ch->sphobjCmax , GLU_SMOOTH);
16836    #else
16837       gluQuadricDrawStyle (Ch->sphobjCmax, GLU_LINE);
16838       gluQuadricNormals (Ch->sphobjCmax , GLU_NONE);
16839    #endif
16840    SUMA_RETURN (Ch);
16841 }
16842 
16843 /*! Free a CrossHair object */
SUMA_Free_CrossHair(SUMA_CrossHair * Ch)16844 void SUMA_Free_CrossHair (SUMA_CrossHair *Ch)
16845 {
16846    static char FuncName[]={"SUMA_Free_CrossHair"};
16847 
16848    SUMA_ENTRY;
16849 
16850    if (Ch->sphobj) gluDeleteQuadric(Ch->sphobj);
16851    if (Ch->sphobjCmax) gluDeleteQuadric(Ch->sphobjCmax);
16852    if (Ch) SUMA_free(Ch);
16853    SUMA_RETURNe;
16854 }
16855 
16856 
16857 /* Allocate for a SphereMarker object */
SUMA_Alloc_SphereMarker(void)16858 SUMA_SphereMarker* SUMA_Alloc_SphereMarker (void)
16859 {
16860    static char FuncName[]={"SUMA_Alloc_SphereMarker"};
16861    SUMA_SphereMarker* SM;
16862 
16863    SUMA_ENTRY;
16864 
16865    SM = (SUMA_SphereMarker*)SUMA_calloc(1,sizeof (SUMA_SphereMarker));
16866    if (SM == NULL) {
16867       fprintf(stderr,"SUMA_Alloc_SphereMarker Error: Failed to allocate SM\n");
16868       SUMA_RETURN (NULL);
16869    }
16870 
16871    /* create the ball object*/
16872    SM->sphobj = gluNewQuadric();
16873    /* for wire frame  use GLU_LINE with GLU_NONE */
16874    /* for solid, use GLU_FILL and GLU_SMOOTH */
16875    #ifdef SUMA_SOLID_LOCAL
16876       gluQuadricDrawStyle (SM->sphobj, GLU_FILL);
16877       gluQuadricNormals (SM->sphobj , GLU_SMOOTH);
16878    #else
16879       gluQuadricDrawStyle (SM->sphobj, GLU_LINE);
16880       gluQuadricNormals (SM->sphobj , GLU_NONE);
16881    #endif
16882    SM->sphcol[0] = 0.50; SM->sphcol[1] = 0.5; SM->sphcol[2] = 1.0;
16883                                               SM->sphcol[3] = 1.0;
16884    SM->sphrad = SUMA_SELECTED_NODE_SPHERE_RADIUS/SUMA_DimSclFac(NULL, NULL);
16885    SM->slices = 10;
16886    SM->stacks = 10;
16887    SM->c[0] = SM->c[1] = SM->c[2] = 0.0;
16888 
16889    SUMA_RETURN (SM);
16890 }
16891 
16892 /*! Free a SphereMarker object */
SUMA_Free_SphereMarker(SUMA_SphereMarker * SM)16893 void SUMA_Free_SphereMarker (SUMA_SphereMarker *SM)
16894 {
16895    static char FuncName[]={"SUMA_Free_SphereMarker"};
16896 
16897    SUMA_ENTRY;
16898 
16899    if (SM->sphobj) gluDeleteQuadric(SM->sphobj);
16900    if (SM) SUMA_free(SM);
16901    SUMA_RETURNe;
16902 }
16903 
16904 /*! Create the highlighted faceset  marker */
SUMA_DrawFaceSetMarker(SUMA_FaceSetMarker * FM,SUMA_SurfaceViewer * sv)16905 SUMA_Boolean SUMA_DrawFaceSetMarker (SUMA_FaceSetMarker* FM,
16906                                      SUMA_SurfaceViewer *sv)
16907 {
16908    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0}, dx, dy, dz, fac;
16909    static char FuncName[]={"SUMA_DrawFaceSetMarker"};
16910 
16911    SUMA_ENTRY;
16912 
16913    fac = (SUMA_SELECTED_FACESET_OFFSET_FACTOR);
16914    dx = fac * FM->NormVect[0];
16915    dy = fac * FM->NormVect[1];
16916    dz = fac * FM->NormVect[2];
16917 
16918    glLineWidth(FM->LineWidth);
16919    glDisable(GL_LINE_STIPPLE);
16920 
16921    glMaterialfv(GL_FRONT, GL_EMISSION, FM->LineCol); /*turn on emissivity for triangle*/
16922    glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor); /* turn off ambient and diffuse components */
16923    glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
16924 
16925    glBegin(GL_LINE_LOOP);
16926       glVertex3f(FM->n0[0]+dx, FM->n0[1]+dy, FM->n0[2]+dz);
16927       glVertex3f(FM->n1[0]+dx, FM->n1[1]+dy, FM->n1[2]+dz);
16928       glVertex3f(FM->n2[0]+dx, FM->n2[1]+dy, FM->n2[2]+dz);
16929    glEnd();
16930    glBegin(GL_LINE_LOOP);
16931       glVertex3f(FM->n0[0]-dx, FM->n0[1]-dy, FM->n0[2]-dz);
16932       glVertex3f(FM->n1[0]-dx, FM->n1[1]-dy, FM->n1[2]-dz);
16933       glVertex3f(FM->n2[0]-dx, FM->n2[1]-dy, FM->n2[2]-dz);
16934    glEnd();
16935    glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
16936    SUMA_RETURN (YUP);
16937 }
16938 
16939 /* Allocate for a faceset mrker */
SUMA_Alloc_FaceSetMarker(void)16940 SUMA_FaceSetMarker* SUMA_Alloc_FaceSetMarker (void)
16941 {
16942    SUMA_FaceSetMarker* FM;
16943    static char FuncName[]={"SUMA_Alloc_FaceSetMarker"};
16944 
16945    SUMA_ENTRY;
16946 
16947    FM = SUMA_calloc(1,sizeof (SUMA_FaceSetMarker));
16948    if (FM == NULL) {
16949       fprintf(stderr,"SUMA_Alloc_FaceSetMarker Error: Failed to allocate FM\n");
16950       SUMA_RETURN (NULL);
16951    }
16952 
16953    /* setup some default values */
16954    FM->LineWidth = SUMA_SELECTED_FACESET_LINE_WIDTH;
16955    FM->LineCol[0] = FM->LineCol[1] = FM->LineCol[2] = SUMA_SELECTED_FACESET_LINE_INTENSITY; FM->LineCol[3] = 1;
16956 
16957    SUMA_RETURN (FM);
16958 }
16959 /*! Free a FaceSetMarker object */
SUMA_Free_FaceSetMarker(SUMA_FaceSetMarker * FM)16960 void SUMA_Free_FaceSetMarker (SUMA_FaceSetMarker* FM)
16961 {
16962    static char FuncName[]={"SUMA_Free_FaceSetMarker"};
16963 
16964    SUMA_ENTRY;
16965 
16966    if (FM) SUMA_free(FM);
16967    SUMA_RETURNe;
16968 }
16969 
16970 /*!
16971    Modify the attributes of node objects, based on the data
16972 */
SUMA_ApplyDataToNodeObjects(SUMA_SurfaceObject * SurfObj,SUMA_SurfaceViewer * sv)16973 SUMA_Boolean SUMA_ApplyDataToNodeObjects(
16974             SUMA_SurfaceObject *SurfObj, SUMA_SurfaceViewer *sv)
16975 {
16976    static char FuncName[]={"SUMA_ApplyDataToNodeObjects"};
16977    GLfloat *colp = NULL;
16978    SUMA_NIDO *nido=NULL;
16979    int ip, i, node, node4;
16980    float colv[4];
16981    NI_element *nel=NULL;
16982    SUMA_Boolean LocalHead = NOPE;
16983 
16984    SUMA_ENTRY;
16985 
16986    if (!(colp = SUMA_GetColorList (sv, SurfObj->idcode_str))) SUMA_RETURN(NOPE);
16987 
16988    if (! (SurfObj->NodeObjects &&
16989           SurfObj->NodeObjects->ObjectType == NIDO_type) ) {
16990       SUMA_RETURN(NOPE);
16991    }
16992 
16993    if (!(nido = SurfObj->NodeObjects->OP)) SUMA_RETURN(NOPE);
16994 
16995    for( ip=0 ; ip < nido->ngr->part_num ; ip++ ){
16996       nel = NULL;
16997       switch( nido->ngr->part_typ[ip] ){
16998          /*-- a sub-group ==> recursion! --*/
16999          case NI_GROUP_TYPE:
17000             SUMA_SL_Err(
17001                "Don't know what to do with a group element, ignoring.");
17002             break ;
17003          case NI_ELEMENT_TYPE:
17004             nel = (NI_element *)nido->ngr->part[ip] ;
17005             if (0 && LocalHead)  {
17006                SUMA_ShowNel(nel);
17007             }
17008             NI_GET_INT(nel, "node", node);
17009             if (!NI_GOT) break;
17010             node4=4*node;
17011             for (i=0; i<4; ++i) colv[i]=colp[node4+i];
17012 
17013             /* assign the color at that node */
17014             NI_SET_FLOATv(nel, "col", colv, 4);
17015 
17016             /* there are many more things to do depending on the type
17017             of nel, but for now, leave as is */
17018 
17019             break;
17020          default:
17021             SUMA_SL_Err(
17022                "Don't know what to make of this group element, ignoring.");
17023             break;
17024       }
17025    }
17026    SUMA_RETURN(YUP);
17027 }
17028 /*!
17029    Modify the attributes of node objects, based on the data
17030 */
SUMA_ApplyDataToNodeNIDOObjects(SUMA_SurfaceObject * SurfObj,SUMA_SurfaceViewer * sv)17031 SUMA_Boolean SUMA_ApplyDataToNodeNIDOObjects(
17032             SUMA_SurfaceObject *SurfObj, SUMA_SurfaceViewer *sv)
17033 {
17034    static char FuncName[]={"SUMA_ApplyDataToNodeNIDOObjects"};
17035    GLfloat *colp = NULL;
17036    SUMA_NIDO *nido=NULL;
17037    int ip, i, node, node4;
17038    float colv[4];
17039    NI_element *nel=NULL;
17040    SUMA_Boolean LocalHead = NOPE;
17041 
17042    SUMA_ENTRY;
17043 
17044    if (!(colp = SUMA_GetColorList (sv, SurfObj->idcode_str))) SUMA_RETURN(NOPE);
17045 
17046    if (! (SurfObj->NodeNIDOObjects) ) {
17047       SUMA_RETURN(NOPE);
17048    }
17049 
17050    for( ip=0 ; ip < SurfObj->N_Node ; ip++ ){
17051       nido = SurfObj->NodeNIDOObjects[ip];
17052       if (nido) {
17053          node4=4*ip; for (i=0; i<4; ++i) colv[i]=colp[node4+i];
17054          NI_SET_FLOATv(nido->ngr, "default_color", colv, 4);
17055          if (LocalHead && ip==0) {
17056             SUMA_LHv("Node 0 markre has [%f %f %f %f]\n",
17057                         colv[0], colv[1], colv[2], colv[3]);
17058          }
17059       }
17060    }
17061    SUMA_RETURN(YUP);
17062 }
17063 
17064 /*
17065    Return the equation of the screen's plane in world coordinates.
17066    cen is a point through which the plane should pass (leave NULL for 0 0 0)
17067    PlEq is a float vector to contain the 4 params for the plane's equation
17068 */
SUMA_ScreenPlane_WorldSpace(SUMA_SurfaceViewer * sv,float * cen,float * PlEq)17069 SUMA_Boolean SUMA_ScreenPlane_WorldSpace(SUMA_SurfaceViewer *sv, float *cen,
17070                                          float *PlEq)
17071 {
17072    static char FuncName[]={"SUMA_ScreenPlane_WorldSpace"};
17073    int orthoreset = 0;
17074    double  mvmat[16], prmat[16], d0[3], d1[3];
17075    int view[4];
17076    int mmode;
17077    SUMA_Boolean LocalHead = NOPE;
17078 
17079    SUMA_ENTRY;
17080 
17081    if (!sv) SUMA_RETURN(NOPE);
17082 
17083    glGetDoublev (GL_MODELVIEW_MATRIX , mvmat);
17084    glGetIntegerv(GL_VIEWPORT         , view);
17085 
17086    if (!sv->ortho) {  /*  Need to be in ortho mode */
17087       orthoreset = 1; /* keep track in order to pop matrix later */
17088                       /* Trach which mode we were in */
17089       glGetIntegerv(GL_MATRIX_MODE, &mmode);
17090       glMatrixMode (GL_PROJECTION); glPushMatrix();
17091       SUMA_SET_GL_PROJECTION(sv, 1);
17092    }
17093    glGetDoublev (GL_PROJECTION_MATRIX, prmat);
17094 
17095    if (orthoreset) { /* pop the forced projection */
17096       glPopMatrix();
17097       glMatrixMode (mmode); /* go back to initial matrix mode */
17098    }
17099 
17100    /* Get equivalent direction to Z in screen space from mid point */
17101    gluUnProject(  view[0]/2, view[1]/2, -0.5,
17102                   mvmat, prmat, view,
17103                   d0, d0+1, d0+2 );
17104    gluUnProject(  view[0]/2, view[1]/2, 0.5,
17105                   mvmat, prmat, view,
17106                   d1, d1+1, d1+2 );
17107    d1[0] = d1[0] - d0[0];
17108    d1[1] = d1[1] - d0[1];
17109    d1[2] = d1[2] - d0[2];
17110 
17111    SUMA_LH("Norm: %f %f %f", d1[0], d1[1], d1[2]);
17112    SUMA_UNITIZE_VEC(d1,3); /* why not, be nice */
17113 
17114    if (cen) {/* move plane to pass by cen */
17115       SUMA_PLANE_NORMAL_POINT(d1, cen, PlEq);
17116    } else { /* just go through 0 0 0 */
17117       PlEq[0] = d1[0]; PlEq[1] = d1[1]; PlEq[2] = d1[2]; PlEq[3] = 0.0;
17118    }
17119 
17120    SUMA_RETURN(YUP);
17121 }
17122 
17123 /*!< Given a byte mask of nodes, return a mask of the facesets involved */
SUMA_NodeMask_to_FaceMask(SUMA_SurfaceObject * SO,byte * nodemask,int N_nz_nodemask,int * triblock,byte ** facemask,int minhits)17124 int SUMA_NodeMask_to_FaceMask(SUMA_SurfaceObject *SO, byte *nodemask,
17125                               int N_nz_nodemask,
17126                               int *triblock, byte **facemask,
17127                               int minhits)
17128 {
17129    static char FuncName[]={"SUMA_NodeMask_to_FaceMask"};
17130    byte *fm=NULL;
17131    int N_fm=-1, i, j, i0, k;
17132    SUMA_Boolean LocalHead = NOPE;
17133 
17134    SUMA_ENTRY;
17135 
17136    if (!SO) {
17137       SUMA_S_Err("NULL input");
17138       SUMA_RETURN(-1);
17139    }
17140    if (triblock) triblock[0] = -1;
17141 
17142    if (!nodemask || N_nz_nodemask == 0) {
17143       /* The whole thing */
17144       if (triblock) {
17145          triblock[0] = 0;
17146          triblock[1] = SO->N_FaceSet-1;
17147          SUMA_RETURN(SO->N_FaceSet);
17148       } else if (facemask) {
17149          if (!*facemask) {
17150             if (!(*facemask = (byte *)SUMA_malloc(SO->N_FaceSet*sizeof(byte)))){
17151                SUMA_S_Crit("Failed to allocate for %d bytes", SO->N_FaceSet);
17152                SUMA_RETURN(-1);
17153             }
17154          }
17155          memset(*facemask, 1, SO->N_FaceSet*sizeof(byte));
17156          SUMA_RETURN(SO->N_FaceSet);
17157       }
17158    } else if (nodemask) {
17159       SUMA_LH("Nodemask based %d nodes to consider", SO->N_Node);
17160          if (!SO->MF) {
17161             SUMA_S_Err("Need SO->MF for this one");
17162             SUMA_RETURN(-1);
17163          }
17164          N_fm = 0;
17165          if (!(fm = (byte *)SUMA_calloc(SO->N_FaceSet, sizeof(byte)))){
17166             SUMA_S_Err("FAiled to allocate for %d bytes", SO->N_FaceSet);
17167             SUMA_RETURN(-1);
17168          }
17169          for (i=0; i < SO->N_Node; ++i) {
17170             if (nodemask[i]) {
17171                for (j=0; j < SO->MF->N_Memb[i]; ++j) {
17172                   ++ fm[SO->MF->NodeMemberOfFaceSet[i][j]];
17173                }
17174             }
17175          }
17176          i0 = -1;
17177          for (i=0; i < SO->N_FaceSet; ++i) {
17178             if (fm[i] < minhits) fm[i] = 0;
17179             else {
17180                if (i0 < 0) i0 = i;
17181                fm[i] = 1;
17182                ++N_fm;
17183             }
17184          }
17185 
17186          if (triblock) {
17187             /* is this one whole block? */
17188             for (k=0,i=i0; i<SO->N_FaceSet; ++i) {
17189                if (!fm[i]) break;
17190                else ++k;
17191             }
17192             if (k == N_fm) {
17193                triblock[0] = i0;
17194                triblock[1] = i0+N_fm-1;
17195                SUMA_ifree(fm); /* no need for mask */
17196             }
17197          }
17198 
17199          if (facemask) {
17200             if (*facemask) SUMA_free(*facemask);
17201             *facemask = fm; fm = NULL;
17202          }
17203 
17204          SUMA_ifree(fm);
17205    }
17206 
17207    SUMA_LH("Returning with %d triangles, *facemask=%p, triblock %p[%d %d]",
17208           N_fm, facemask? *facemask:NULL, triblock,
17209             triblock ? triblock[0]:-1, triblock ? triblock[1]:-1);
17210 
17211    SUMA_RETURN(N_fm);
17212 }
17213 
SUMA_Prep_SO_DrawPatches(SUMA_SurfaceObject * SO,SUMA_SurfaceViewer * sv)17214 int SUMA_Prep_SO_DrawPatches(SUMA_SurfaceObject *SO, SUMA_SurfaceViewer *sv)
17215 {
17216    static char FuncName[]={"SUMA_Prep_SO_DrawPatches"};
17217    int N_patches = -1;
17218    byte *fm=NULL;
17219    int N_fm = -1, tb[2];
17220    SUMA_DrawPatch *ptch=NULL;
17221    SUMA_Boolean LocalHead = NOPE;
17222 
17223    SUMA_ENTRY;
17224 
17225    if (!SO || !SO->DW) {
17226       SUMA_S_Err("NULL input");
17227       SUMA_RETURN(-1);
17228    }
17229 
17230    if (!SO->DW->DrwPtchs) {
17231       SO->DW->DrwPtchs = (DList *)SUMA_calloc(1,sizeof(DList));
17232       dlist_init(SO->DW->DrwPtchs, SUMA_Free_DrawPatchDatum);
17233    }
17234    SUMA_LH("Init: %d, %d, %d, %p\n",
17235       SO->DW->PatchGenID, SO->DW->PatchRegenID,
17236       dlist_size(SO->DW->DrwPtchs), SO->DW->nodemask);
17237    if (SO->DW->PatchGenID != SO->DW->PatchRegenID ||
17238        dlist_size(SO->DW->DrwPtchs) == 0) {
17239        dlist_empty(SO->DW->DrwPtchs);
17240       SUMA_LH("Regenerating patches");
17241       if (!SO->DW->nodemask || SO->DW->N_nz_nodemask == 0) {
17242          SUMA_LH("Default - whole surface");
17243          #if 1
17244          if (!(ptch = SUMA_New_DrawPatchDatum(SO, NULL, 0, NULL))) {
17245             SUMA_S_Err("Nullination, skipping");
17246          } else {
17247             dlist_ins_next(SO->DW->DrwPtchs, dlist_head(SO->DW->DrwPtchs), ptch);
17248          }
17249          #else
17250          SUMA_LH( "Here is an example of how you would display in two chunks\n"
17251                   "The setting of tb (or facemask) of course should be done\n"
17252                   "in SUMA_NodeMask_to_FaceMask, and not here...");
17253          SUMA_S_Warn("TEST Fix Me, Fix ME!"); tb[0]=0; tb[1]=1000;
17254          if (!(ptch = SUMA_New_DrawPatchDatum(SO, tb, 0, NULL))) {
17255             SUMA_S_Err("Nullination, skipping");
17256          } else {
17257             dlist_ins_next(SO->DW->DrwPtchs, dlist_head(SO->DW->DrwPtchs), ptch);
17258          }
17259          SUMA_S_Warn("TEST Fix Me, Fix ME!"); tb[0]=10000; tb[1]=15000;
17260          if (!(ptch = SUMA_New_DrawPatchDatum(SO, tb, 0, NULL))) {
17261             SUMA_S_Err("Nullination, skipping");
17262          } else {
17263             dlist_ins_next(SO->DW->DrwPtchs, dlist_head(SO->DW->DrwPtchs), ptch);
17264          }
17265          #endif
17266       } else {
17267          if ((N_fm = SUMA_NodeMask_to_FaceMask(SO, SO->DW->nodemask,
17268                         SO->DW->N_nz_nodemask, tb, &fm, 1))<0){
17269             SUMA_S_Err("Failed to change node mask to face mask");
17270          } else {
17271             SUMA_DrawPatch *ptch0=NULL, *ptch1=NULL;
17272             SUMA_LH("Creating patch tb=[%d,%d], fm=%p\n",
17273                      tb[0], tb[1], fm);
17274             if (!(ptch = SUMA_New_DrawPatchDatum(SO, tb, N_fm, fm))) {
17275                   SUMA_S_Err("Nullination 2, skipping");
17276             } else {
17277               dlist_ins_next(SO->DW->DrwPtchs,
17278                              dlist_head(SO->DW->DrwPtchs), ptch);
17279             }
17280 
17281             /* Also draw complimentary patches, need an option
17282             for this too, naturally. I would need a mechanism
17283             for an if (cmask) then ACTION
17284                    else ALT_ACTION
17285             At the moment, only cmask is controllable, there
17286             is no way for the user to setup ACTION and ALT_ACTION
17287             Those ACTIONS can be specified using the syntax of DriveSuma...
17288             */
17289             if (SUMA_ComplimentaryPatches(SO, tb, N_fm, fm,
17290                                       &ptch0, &ptch1)) {
17291                if (ptch0) {
17292                   /* toying with transp. and poly modes
17293                      need controllers for all this.
17294                      PolyMode overrides TransMode */
17295                   if (SUMA_EnvVal("SUMA_TEMP_NODE_CMASK_EXPR_POLYMODE")) {
17296                      ptch0->PolyMode = SRM_Line;
17297                   } else {
17298                      ptch0->TransMode = STM_12;
17299                   }
17300                   dlist_ins_next(SO->DW->DrwPtchs,
17301                               dlist_head(SO->DW->DrwPtchs), ptch0);
17302                }
17303                if (ptch1) {
17304                   if (SUMA_EnvVal("SUMA_TEMP_NODE_CMASK_EXPR_POLYMODE")) {
17305                      ptch1->PolyMode = SRM_Line;
17306                   } else {
17307                      ptch1->TransMode = STM_12;
17308                   }
17309                   dlist_ins_next(SO->DW->DrwPtchs,
17310                               dlist_head(SO->DW->DrwPtchs), ptch1);
17311                }
17312             }
17313             SUMA_ifree(fm);/* dump fm */
17314          }
17315       }
17316       SO->DW->PatchGenID = SO->DW->PatchRegenID;
17317    }
17318 
17319    SUMA_LH("Going home");
17320    SUMA_RETURN(dlist_size(SO->DW->DrwPtchs));
17321 }
17322 
17323 /*! Create a drawing patch for surface SO */
SUMA_New_DrawPatchDatum(SUMA_SurfaceObject * SO,int * triblock,int N_Faces,byte * facemask)17324 SUMA_DrawPatch *SUMA_New_DrawPatchDatum(SUMA_SurfaceObject *SO, int *triblock,
17325                                         int N_Faces, byte *facemask)
17326 {
17327    static char FuncName[]={"SUMA_New_DrawPatchDatum"};
17328    SUMA_DrawPatch *ptch=NULL;
17329    int lb2[2], ii, i, pp, k;
17330    SUMA_Boolean LocalHead = NOPE;
17331 
17332    SUMA_ENTRY;
17333 
17334    if (!SO) {
17335       SUMA_S_Err("NULL SO YO!");
17336       SUMA_RETURN(NULL);
17337    }
17338 
17339    if ((triblock && triblock[0] >=0) && facemask) { /* prioritize */
17340       SUMA_LH("Using triblock, not facemask");
17341    }
17342 
17343    if ( (!triblock && !facemask) ||
17344         (triblock && triblock[0] == 0 && triblock[1] ==-1)){/* whole surface */
17345       triblock = (int *)lb2;
17346       triblock[0] = 0;
17347       triblock[1] = SO->N_FaceSet-1;
17348    }
17349 
17350    if (triblock && triblock[0]>=0) {
17351       if (triblock[1]>=SO->N_FaceSet) {
17352          SUMA_S_Err("triblock of [%d %d] outside of [%d %d]",
17353                      triblock[0], triblock[1], 0, SO->N_FaceSet-1);
17354          SUMA_RETURN(NULL);
17355       }
17356       if (triblock[0] > triblock[1]) {
17357          SUMA_S_Err("triblock of [%d %d] uninterpretable",
17358                      triblock[0], triblock[1]);
17359          SUMA_RETURN(NULL);
17360       }
17361    }
17362 
17363    ptch = (SUMA_DrawPatch *)SUMA_calloc(1, sizeof(SUMA_DrawPatch));
17364 
17365    if (triblock && triblock[0] >= 0) { /* the easy way */
17366       SUMA_LH("Triblock %d %d", triblock[0], triblock[1]);
17367       ptch->FreeFaceSetList = NOPE; /* pointer copy bro */
17368       ptch->FaceSetList = SO->FaceSetList+triblock[0]*SO->FaceSetDim;
17369       ptch->N_FaceSet = triblock[1]-triblock[0]+1;
17370    } else {
17371       SUMA_LH("facemask of %d triangles in mask", N_Faces);
17372       ptch->FreeFaceSetList = YUP;
17373       if (!(ptch->FaceSetList = (int *)SUMA_calloc(N_Faces*SO->FaceSetDim,
17374                                                    sizeof(int)))) {
17375          SUMA_S_Crit("Hippocampus full, no space for %d ints", N_Faces);
17376          SUMA_Free_DrawPatchDatum((void *)ptch);
17377          SUMA_RETURN(NULL);
17378       }
17379       ptch->N_FaceSet = N_Faces;
17380       pp = 0;
17381       for (i=0; i<SO->N_FaceSet; ++i) {
17382          if (IN_MASK(facemask,i)) {
17383             ii = i*SO->FaceSetDim;
17384             for (k=0; k<SO->FaceSetDim; ++k) {
17385                ptch->FaceSetList[pp++] = SO->FaceSetList[ii++];
17386             }
17387          }
17388       }
17389       /* sanity check */
17390       if (N_Faces != pp/SO->FaceSetDim) {
17391          SUMA_S_Err( "The probability of seeing this assuming "
17392                      "you're sane is p<1e-8");
17393          SUMA_Free_DrawPatchDatum((void *)ptch);
17394          SUMA_RETURN(NULL);
17395       }
17396    }
17397 
17398    ptch->Show = SO->Show;
17399    ptch->PolyMode = SO->PolyMode;
17400    ptch->TransMode = SO->TransMode;
17401 
17402    SUMA_RETURN(ptch);
17403 }
17404 
17405 /*!< Complimentary patches */
SUMA_ComplimentaryPatches(SUMA_SurfaceObject * SO,int * triblock,int N_Faces,byte * facemask,SUMA_DrawPatch ** ptch0,SUMA_DrawPatch ** ptch1)17406 int SUMA_ComplimentaryPatches(SUMA_SurfaceObject *SO, int *triblock,
17407                               int N_Faces, byte *facemask,
17408                               SUMA_DrawPatch **ptch0,
17409                               SUMA_DrawPatch **ptch1)
17410 {
17411    static char FuncName[]={"SUMA_ComplimentaryPatches"};
17412    int N_patches=0;
17413    int lb2[2], ii, i, pp, k;
17414    SUMA_Boolean LocalHead = YUP;
17415 
17416    SUMA_ENTRY;
17417 
17418    if (!SO) {
17419       SUMA_S_Err("NULL SO YO!");
17420       SUMA_RETURN(-1);
17421    }
17422 
17423    if ((triblock && triblock[0] >=0) && facemask) { /* prioritize */
17424       SUMA_LH("Using triblock, not facemask");
17425    }
17426 
17427    if (!ptch0 || !ptch1 || *ptch0 || *ptch1) {
17428       SUMA_S_Err("Init error");
17429       SUMA_RETURN(-1);
17430    }
17431 
17432    if ( (!triblock && !facemask) ||
17433         (triblock && triblock[0] == 0 && triblock[1] == -1)){/* whole surface */
17434       triblock = (int *)lb2;
17435       triblock[0] = 0;
17436       triblock[1] = SO->N_FaceSet-1;
17437    }
17438    if (triblock && triblock[0] >= 0) {
17439       if (triblock[1]>=SO->N_FaceSet) {
17440          SUMA_S_Err("triblock of [%d %d] outside of [%d %d]",
17441                      triblock[0], triblock[1], 0, SO->N_FaceSet-1);
17442          SUMA_RETURN(-1);
17443       }
17444       if (triblock[0] > triblock[1]) {
17445          SUMA_S_Err("triblock of [%d %d] uninterpretable",
17446                      triblock[0], triblock[1]);
17447          SUMA_RETURN(-1);
17448       }
17449    }
17450 
17451 
17452    if (triblock && triblock[0] >= 0) { /* first part */
17453       SUMA_LH("Triblock [%d %d]", triblock[0], triblock[1]);
17454       if (triblock[0] > 0) {
17455          *ptch0 = (SUMA_DrawPatch *)SUMA_calloc(1, sizeof(SUMA_DrawPatch));
17456          (*ptch0)->FreeFaceSetList = NOPE; /* pointer copy bro */
17457          (*ptch0)->FaceSetList = SO->FaceSetList;
17458          (*ptch0)->N_FaceSet = triblock[0];
17459 
17460          if (triblock[1] < SO->N_FaceSet -1) {
17461             *ptch1 = (SUMA_DrawPatch *)SUMA_calloc(1, sizeof(SUMA_DrawPatch));
17462             (*ptch1)->FreeFaceSetList = NOPE; /* pointer copy bro */
17463             (*ptch1)->FaceSetList =
17464                SO->FaceSetList+(triblock[1]+1)*SO->FaceSetDim;
17465             (*ptch1)->N_FaceSet = SO->N_FaceSet - (triblock[1]+1);
17466          }
17467       } else if (triblock[0] == 0) {
17468          *ptch0 = (SUMA_DrawPatch *)SUMA_calloc(1, sizeof(SUMA_DrawPatch));
17469          (*ptch0)->FreeFaceSetList = NOPE; /* pointer copy bro */
17470          (*ptch0)->FaceSetList = SO->FaceSetList+(triblock[1]+1)*SO->FaceSetDim;
17471          (*ptch0)->N_FaceSet = SO->N_FaceSet - (triblock[1]+1);
17472       }
17473    } else {
17474       SUMA_LH("facemask of %d triangles to be drawn", SO->N_FaceSet-N_Faces);
17475       *ptch0 = (SUMA_DrawPatch *)SUMA_calloc(1, sizeof(SUMA_DrawPatch));
17476       (*ptch0)->FreeFaceSetList = YUP;
17477       if (!((*ptch0)->FaceSetList =  (int *)
17478             SUMA_calloc((SO->N_FaceSet-N_Faces)*SO->FaceSetDim, sizeof(int)))) {
17479          SUMA_S_Crit("Hippocampus full, no space for %d ints",
17480                      SO->N_FaceSet-N_Faces);
17481          SUMA_Free_DrawPatchDatum((void *)(*ptch0));
17482          SUMA_RETURN(-1);
17483       }
17484       (*ptch0)->N_FaceSet = SO->N_FaceSet-N_Faces;
17485       pp = 0;
17486       for (i=0; i<SO->N_FaceSet; ++i) {
17487          if (!IN_MASK(facemask,i)) {
17488             ii = i*SO->FaceSetDim;
17489             for (k=0; k<SO->FaceSetDim; ++k) {
17490                (*ptch0)->FaceSetList[pp++] = SO->FaceSetList[ii++];
17491             }
17492          }
17493       }
17494       /* sanity check */
17495       if ((*ptch0)->N_FaceSet != pp/SO->FaceSetDim) {
17496          SUMA_S_Err( "The probability of seeing this assuming "
17497                      "you're sane is p<1e-8");
17498          SUMA_Free_DrawPatchDatum((void *)*ptch0);
17499          SUMA_RETURN(-1);
17500       }
17501    }
17502 
17503 SUMA_LH("3");
17504    N_patches = 0;
17505    if (*ptch0) {
17506       N_patches = 1;
17507       (*ptch0)->Show = SO->Show;
17508       (*ptch0)->PolyMode = SO->PolyMode;
17509       (*ptch0)->TransMode = STM_8;
17510    }
17511    if (*ptch1) {
17512       N_patches = 2;
17513       (*ptch1)->Show = SO->Show;
17514       (*ptch1)->PolyMode = SO->PolyMode;
17515       (*ptch1)->TransMode = STM_8;
17516    }
17517    SUMA_RETURN(N_patches);
17518 }
17519 
SUMA_Free_DrawPatchDatum(void * data)17520 void SUMA_Free_DrawPatchDatum(void *data)
17521 {
17522    static char FuncName[]={"SUMA_Free_DrawPatchDatum"};
17523    SUMA_DrawPatch *ptch = (SUMA_DrawPatch *) data;
17524    SUMA_ENTRY;
17525    if (ptch) {
17526       if (ptch->FreeFaceSetList) { SUMA_ifree(ptch->FaceSetList); }
17527       SUMA_free(ptch);
17528    }
17529    SUMA_RETURNe;
17530 }
17531 
17532 /*! A new function for drawing surface with masking potential */
SUMA_DrawMesh_mask(SUMA_SurfaceObject * SurfObj,SUMA_SurfaceViewer * sv)17533 void SUMA_DrawMesh_mask(SUMA_SurfaceObject *SurfObj, SUMA_SurfaceViewer *sv)
17534 {
17535    static char FuncName[]={"SUMA_DrawMesh_mask"};
17536    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
17537    GLfloat *colp = NULL;
17538    int i, ii, ND, id, ip, NP, PolyMode, sz[2]={0, 0},
17539         N_patches =0;
17540    SUMA_DRAWN_ROI *DrawnROI = NULL;
17541    static GLuint texName;
17542    GLfloat rotationMatrix[4][4];
17543    GLenum Face=GL_FRONT;
17544    GLint *glar_FaceSetList=NULL;
17545    NI_element *texnel=NULL;
17546    DList *st=NULL;
17547    SUMA_TRANS_MODES trmode;
17548    SUMA_DrawPatch *ptch=NULL;
17549    DListElmt *el=NULL;
17550    SUMA_Boolean LocalHead = NOPE;
17551 
17552    SUMA_ENTRY;
17553 
17554    SUMA_LH("Entered");
17555 
17556    if (LocalHead) {
17557       SUMA_EnablingRecord SER;
17558       SUMA_RecordEnablingState(&SER, SurfObj->Label);
17559       SUMA_DiffEnablingState(&SER, NULL, NULL, NULL);
17560    }
17561 
17562    if ( (N_patches = SUMA_Prep_SO_DrawPatches(SurfObj, sv)) < 0 ) {
17563       SUMA_S_Err("Failed to prep SO patches");
17564       SUMA_RETURNe;
17565    }
17566 
17567    SUMA_LH("Have %d patches", N_patches);
17568 
17569    if ( N_patches == 0 ) {
17570       SUMA_LH("Nothing to do, returning");
17571       SUMA_RETURNe;
17572    }
17573 
17574    if (!SurfObj->DW->DrwPtchs) {
17575       SUMA_S_Err("Should not have null DrwPtchs at this point");
17576       SUMA_RETURNe;
17577    }
17578 
17579    if (sv->DO_PickMode) {
17580       SUMA_LH("No need to DrawMesh in DO picking mode");
17581       SUMA_RETURNe;
17582    }
17583 
17584    SUMA_LH("Might need to swap coords from the VisX transformed data");
17585    SUMA_VisX_Pointers4Display(SurfObj, 1);
17586 
17587    do { /* begin for each patch */
17588       if (!el) el = dlist_head(SurfObj->DW->DrwPtchs);
17589       else el = dlist_next(el);
17590       ptch = (SUMA_DrawPatch *)el->data;
17591       glar_FaceSetList = (GLint *)ptch->FaceSetList;
17592       if (  ptch->PolyMode == SRM_Hide ||
17593             sv->PolyMode == SRM_Hide ||
17594             ptch->TransMode == STM_16 ||
17595             sv->TransMode == STM_16) {
17596          SUMA_LH("Hiding surface");
17597          continue;
17598       }
17599 
17600       if (!SUMA_GLStateTrack( "new", &st, FuncName, NULL, NULL)) {
17601          SUMA_S_Err("Failed to create tracking list");
17602          SUMA_RETURNe;
17603       }
17604       /* check on rendering mode */
17605       if (ptch->PolyMode != SRM_ViewerDefault) {
17606         SUMA_LHv("Poly Mode %d\n", ptch->PolyMode);
17607         /* not the default, do the deed */
17608         #if 0 /* Need to start using MACRO below, but it is not working yet */
17609         SUMA_SET_GL_RENDER_MODE_TRACK(ptch->PolyMode, st);
17610         #else
17611         SUMA_SET_GL_RENDER_MODE(ptch->PolyMode);
17612         #endif
17613       }
17614 
17615       SUMA_LH("TransMode = %d, N_FaceSet = %d",
17616                ptch->TransMode, ptch->N_FaceSet);
17617 
17618       /* check on rendering mode */
17619       if (ptch->TransMode == STM_ViewerDefault) {
17620          trmode = sv->TransMode;
17621       } else if (ptch->TransMode > STM_0) {
17622          trmode = ptch->TransMode;
17623       } else trmode = STM_0;
17624 
17625       if (trmode != STM_0) {
17626         /* not the default, do the deed */
17627         SUMA_LHv("Trans Mode %d\n", trmode);
17628         SUMA_SET_GL_TRANS_MODE(trmode, st, SO_type);
17629       }
17630 
17631       /* any texture for this surface? */
17632       texnel = SUMA_SO_NIDO_Node_Texture ( SurfObj, SUMAg_DOv, SUMAg_N_DOv, sv );
17633       if (texnel) {
17634          SUMA_LH(  "Creating texture, see init pp 415 in \n"
17635                    "OpenGL programming guide, 3rd ed.");
17636          if (NI_IS_STR_ATTR_EQUAL(texnel,"read_status","fail")) {
17637             /* can't be read */
17638             SUMA_RETURNe;
17639          }
17640 
17641          if (!NI_IS_STR_ATTR_EQUAL(texnel,"read_status","read")) { /* read it */
17642             if (!SUMA_LoadImageNIDOnel(texnel)) {
17643                SUMA_RETURNe;
17644             }
17645             /* has the box size been determined (only 2 dimensions needed)?*/
17646             NI_GET_INTv(texnel,"box_size", sz, 2, LocalHead);
17647             if (!NI_GOT) {
17648                NI_GET_INT(texnel,"width", sz[0]);
17649                NI_GET_INT(texnel,"height", sz[1]);
17650                NI_SET_INTv(texnel,"box_size", sz, 2);
17651             }
17652 
17653          }
17654 
17655          NI_GET_INTv(texnel,"box_size", sz, 2, LocalHead);
17656 
17657          /* For cool textures, see
17658             http://www.filterforge.com/filters/category42-page1.html */
17659          glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
17660          NI_GET_INT(texnel,"texName",texName);
17661          if (!NI_GOT) {
17662             /* Need to generate texture */
17663             glGenTextures(1, &texName);
17664             /* Now store it */
17665             NI_SET_INT(texnel,"texName",texName);
17666          }
17667          glBindTexture(GL_TEXTURE_2D, texName);
17668          glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT);
17669                   /* GL_REPEAT, GL_CLAMP */
17670          glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT);
17671          glTexParameteri(  GL_TEXTURE_2D,
17672                            GL_TEXTURE_MAG_FILTER, GL_LINEAR);
17673          glTexParameteri(  GL_TEXTURE_2D,
17674                            GL_TEXTURE_MIN_FILTER, GL_LINEAR);
17675             /* cotnrols interpolation of zoomed in/out texture,
17676             GL_LINEAR, GL_NEAREST, ... */
17677          glTexImage2D(  GL_TEXTURE_2D, 0, GL_RGBA,
17678                         sz[0], sz[1], 0, GL_RGBA,
17679                         GL_UNSIGNED_BYTE, texnel->vec[0]);
17680          glTexEnvf(  GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
17681                      SUMA_NIDO_TexEnvMode(texnel, GL_MODULATE));
17682 
17683          /* texture goes on surface which will be drawn later,
17684             Set automatic texture coordinate generation */
17685          glTexGeni(GL_S, GL_TEXTURE_GEN_MODE,
17686                      SUMA_NIDO_TexCoordGen(texnel));
17687                /* GL_SPHERE_MAP, GL_EYE_LINEAR, GL_OBJECT_LINEAR */
17688          glTexGeni(GL_T, GL_TEXTURE_GEN_MODE,
17689                      SUMA_NIDO_TexCoordGen(texnel));
17690          glEnable(GL_TEXTURE_GEN_S);
17691          glEnable(GL_TEXTURE_GEN_T);
17692          glEnable(GL_TEXTURE_2D);
17693                         #if 0
17694                         SUMA_S_Note("I do not need all this");
17695                         glEnable(GL_CULL_FACE);
17696                         glEnable(GL_LIGHTING);
17697                         glEnable(GL_LIGHT0);
17698                         glEnable(GL_AUTO_NORMAL);
17699                         glEnable(GL_NORMALIZE);
17700                         glMaterialf(Face, GL_SHININESS, 64.0);
17701                         #endif
17702       }
17703 
17704       SUMA_LH("Draw Method");
17705       ND = SurfObj->NodeDim;
17706       NP = SurfObj->FaceSetDim;
17707       if (NP == 4) {
17708          SUMA_S_Warn("Quads have not been tested here");
17709       }
17710 
17711 
17712       switch (DRAW_METHOD) {
17713          case STRAIGHT:
17714             switch (RENDER_METHOD) {
17715                case TRIANGLES:
17716                   if (NP == 4) glBegin (GL_QUADS);
17717                   else if (NP == 3) glBegin (GL_TRIANGLES);
17718                   else { SUMA_S_Err("Badness"); SUMA_RETURNe;}
17719                   break;
17720                case POINTS:
17721                   glPointSize(4.0); /* keep outside of glBegin */
17722                   glBegin (GL_POINTS);
17723                   break;
17724             } /* switch RENDER_METHOD */
17725             fprintf(stderr, "1: glColor4f(NODE_COLOR_R, NODE_COLOR_G, NODE_COLOR_B, SUMA_NODE_ALPHA)\n");
17726             glColor4f(NODE_COLOR_R, NODE_COLOR_G, NODE_COLOR_B, SUMA_NODE_ALPHA);
17727             for (i=0; i < ptch->N_FaceSet; i++)
17728             {
17729                ip = NP * i;
17730                id = ND * glar_FaceSetList[ip];
17731                glNormal3fv(&SurfObj->NodeNormList[id]);
17732                glVertex3fv(&SurfObj->NodeList[id]);
17733 
17734                id = ND * glar_FaceSetList[ip+1];
17735                glNormal3fv(&SurfObj->NodeNormList[id]);
17736                glVertex3fv(&SurfObj->NodeList[id]);
17737 
17738                id = ND * glar_FaceSetList[ip+2];
17739                glNormal3fv(&SurfObj->NodeNormList[id]);
17740                glVertex3fv(&SurfObj->NodeList[id]);
17741 
17742                if (NP==4) {
17743                   id = ND * glar_FaceSetList[ip+3];
17744                   glNormal3fv(&SurfObj->NodeNormList[id]);
17745                   glVertex3fv(&SurfObj->NodeList[id]);
17746                }
17747             }
17748             glEnd();
17749             break;
17750 
17751          case ARRAY:
17752             /* This allows each node to follow the color
17753                specified when it was drawn */
17754             glColorMaterial(Face, GL_AMBIENT_AND_DIFFUSE);
17755             glEnable(GL_COLOR_MATERIAL);
17756 
17757             /*Now setup various pointers*/
17758             glEnableClientState (GL_COLOR_ARRAY);
17759             glEnableClientState (GL_VERTEX_ARRAY);
17760             glEnableClientState (GL_NORMAL_ARRAY);
17761             colp = SUMA_GetColorList (sv, SurfObj->idcode_str);
17762             if (!colp) { /* no color list, try  PermCol */
17763                if (SurfObj->PermCol) {
17764                   glColorPointer (4, GL_FLOAT, 0, SurfObj->PermCol);
17765                } else {
17766                   SUMA_SL_Err("Null Color Pointer.");
17767                }
17768             } else {
17769                glColorPointer (4, GL_FLOAT, 0, colp);
17770 
17771             }
17772             glVertexPointer (3, GL_FLOAT, 0, SurfObj->glar_NodeList);
17773             glNormalPointer (GL_FLOAT, 0, SurfObj->glar_NodeNormList);
17774             if (LocalHead)
17775                fprintf(stdout, "Ready to draw Elements %d\n", ptch->N_FaceSet);
17776             switch (RENDER_METHOD) {
17777                case TRIANGLES:
17778                   if (NP==3) {
17779                      glDrawElements (  GL_TRIANGLES, (GLsizei)ptch->N_FaceSet*3,
17780                                        GL_UNSIGNED_INT, glar_FaceSetList);
17781                   } else if (NP==4) {
17782                      glDrawElements (  GL_QUADS, (GLsizei)ptch->N_FaceSet*4,
17783                                        GL_UNSIGNED_INT, glar_FaceSetList);
17784                   } else {
17785                      SUMA_S_Err("Oh no you don't"); SUMA_RETURNe;
17786                   }
17787                   break;
17788                case POINTS:
17789                   glPointSize(4.0); /* keep outside of glBegin */
17790                   /* it is inefficient to draw points using the
17791                      glar_FaceSetList because nodes are listed more
17792                      than once. You are better off creating an index
17793                      vector into glar_NodeList to place all the points,
17794                      just once*/
17795                   if (NP == 3) {
17796                      glDrawElements (  GL_POINTS, (GLsizei)ptch->N_FaceSet*3,
17797                                        GL_UNSIGNED_INT, glar_FaceSetList);
17798                   } else if (NP == 4) {
17799                      glDrawElements (  GL_POINTS, (GLsizei)ptch->N_FaceSet*4,
17800                                        GL_UNSIGNED_INT, glar_FaceSetList);
17801                   }
17802                   break;
17803             } /* switch RENDER_METHOD */
17804 
17805 
17806             if (texnel) {
17807                /* kill baby kill */
17808                texnel = NULL; /* don't leave this function
17809                                           with pointer copy */
17810                glDisable(GL_TEXTURE_2D);
17811                glDisable(GL_TEXTURE_GEN_T);
17812                glDisable(GL_TEXTURE_GEN_S);
17813             }
17814 
17815             /*fprintf(stdout, "Disabling clients\n");*/
17816             glDisableClientState (GL_COLOR_ARRAY);
17817             glDisableClientState (GL_VERTEX_ARRAY);
17818             glDisableClientState (GL_NORMAL_ARRAY);
17819             /*fprintf(stdout, "Out SUMA_DrawMesh, ARRAY mode\n");*/
17820 
17821             glDisable(GL_COLOR_MATERIAL);
17822 
17823             if (el != dlist_tail(SurfObj->DW->DrwPtchs)) {
17824                SUMA_LH("Skipping until last patch");
17825                break;
17826             }
17827             /* draw dset contours (only label dset for now) */
17828             SUMA_LH("Dset contours ");
17829             if (!SUMA_Draw_SO_Dset_Contours (SurfObj,  sv)) {
17830                fprintf (SUMA_STDERR,
17831                         "Error %s: Failed in drawing Dset Contour objects.\n",
17832                         FuncName);
17833             }
17834             /* draw surface ROIs */
17835             SUMA_LH("ROIs");
17836             if (!SUMA_Draw_SO_ROI (SurfObj, SUMAg_DOv, SUMAg_N_DOv, sv)) {
17837                fprintf (SUMA_STDERR,
17838                         "Error %s: Failed in drawing ROI objects.\n", FuncName);
17839             }
17840             /* Draw Axis */
17841             SUMA_LH("Axis");
17842             if (SurfObj->MeshAxis && SurfObj->ShowMeshAxis)   {
17843                if (!SUMA_DrawAxis (SurfObj->MeshAxis, sv)) {
17844                   fprintf( stderr,
17845                            "Error SUMA_DrawAxis: Unrecognized Stipple option\n");
17846                }
17847             }
17848             /* Draw node-based vectors */
17849             SUMA_LH("NBV");
17850             if (!SUMA_Draw_SO_NBV (SurfObj, SUMAg_DOv, SUMAg_N_DOv, sv)) {
17851                fprintf (SUMA_STDERR,
17852                         "Error %s: Failed in drawing NBV objects.\n", FuncName);
17853             }
17854 
17855             /* Draw node-based spheres */
17856             SUMA_LH("NBSP");
17857             if (!SUMA_Draw_SO_NBSP (SurfObj, SUMAg_DOv, SUMAg_N_DOv, sv)) {
17858                fprintf (SUMA_STDERR,
17859                         "Error %s: Failed in drawing NBSP objects.\n", FuncName);
17860             }
17861 
17862             /* Draw node-based NIDOs */
17863             SUMA_LH("NIDO");
17864             if (!SUMA_Draw_SO_NIDO (SurfObj, SUMAg_DOv, SUMAg_N_DOv, sv)) {
17865                fprintf (SUMA_STDERR,
17866                         "Error %s: Failed in drawing NIDO objects.\n", FuncName);
17867             }
17868 
17869             /* Draw Selected Node Highlight */
17870             SUMA_LH("Highlight");
17871             if (SUMA_SV_GetShowSelectedDatum(sv) && SurfObj->SelectedNode >= 0) {
17872                if (LocalHead) fprintf(SUMA_STDOUT,"Drawing Node Selection \n");
17873                id = ND * SurfObj->SelectedNode;
17874                glMaterialfv(Face, GL_EMISSION, SurfObj->NodeMarker->sphcol);
17875                      /*turn on emissidity for sphere */
17876                glMaterialfv(Face, GL_AMBIENT_AND_DIFFUSE, NoColor);
17877                glTranslatef ( SurfObj->NodeList[id],
17878                               SurfObj->NodeList[id+1],SurfObj->NodeList[id+2]);
17879                if (SurfObj->EL && SurfObj->EL->AvgLe > 0) {
17880                   gluSphere(  SurfObj->NodeMarker->sphobj,
17881                               SurfObj->EL->AvgLe/15,
17882                               SurfObj->NodeMarker->slices,
17883                               SurfObj->NodeMarker->stacks);
17884                } else {
17885                   gluSphere(  SurfObj->NodeMarker->sphobj,
17886                               SurfObj->NodeMarker->sphrad *
17887                                  (SUMA_sv_auto_fov(sv)/FOV_INITIAL) *
17888                                  SUMA_MAX_PAIR(sv->ZoomCompensate, 0.06),
17889                               SurfObj->NodeMarker->slices,
17890                               SurfObj->NodeMarker->stacks);
17891                }
17892                glTranslatef ( -SurfObj->NodeList[id],
17893                               -SurfObj->NodeList[id+1],
17894                               -SurfObj->NodeList[id+2]);
17895                glMaterialfv(Face, GL_EMISSION, NoColor);
17896                         /*turn off emissidity for axis*/
17897             }
17898 
17899             /* Draw Selected FaceSet Highlight */
17900             if (SUMA_SV_GetShowSelectedFaceSet(sv)
17901                                        && SurfObj->SelectedFaceSet >= 0) {
17902                SUMA_LH("Drawing FaceSet Selection");
17903                if (!SUMA_DrawFaceSetMarker (SurfObj->FaceSetMarker, sv)) {
17904                   fprintf(SUMA_STDERR,
17905                      "Error SUMA_DrawMesh: Failed in SUMA_DrawFaceSetMarker\b");
17906                }
17907             }
17908 
17909             /* Draw node based markers */
17910             if (SurfObj->NodeObjects &&
17911                 SurfObj->NodeObjects->ObjectType == NIDO_type) {
17912                if (!SUMA_ApplyDataToNodeObjects(SurfObj, sv)) {
17913                   SUMA_S_Err("Failed to apply data to node objects");
17914                }
17915                if (!(SUMA_DrawNIDO ((SUMA_NIDO*)SurfObj->NodeObjects->OP, sv))) {
17916                   SUMA_S_Err("Failed to draw NodeObjects");
17917                }
17918                SUMA_LH("Drew Node objects");
17919             } else {
17920                SUMA_LH("No Node objects");
17921             }
17922 
17923             /* Draw node based markers2 */
17924             if (SurfObj->NodeNIDOObjects) {
17925                if (!SUMA_ApplyDataToNodeNIDOObjects(SurfObj, sv)) {
17926                   SUMA_S_Err("Failed to apply data to node objects2");
17927                }
17928                for (i=0; i<SurfObj->N_Node; ++i) {
17929                   if (SurfObj->NodeNIDOObjects[i] &&
17930                       !(SUMA_DrawNIDO (SurfObj->NodeNIDOObjects[i], sv) ) ) {
17931                      SUMA_S_Err("Failed to draw NodeObjects");
17932                   }
17933                }
17934                SUMA_LH("Drew NodeNIDOObjects");
17935             } else {
17936                SUMA_LH("No NodeNIDOObjects");
17937             }
17938             break;
17939 
17940       } /* switch DRAW_METHOD */
17941 
17942       SUMA_LH("Undoing state changes");
17943       SUMA_GLStateTrack("r", &st, FuncName, NULL, NULL);
17944 
17945       if (ptch->PolyMode != sv->PolyMode)
17946                SUMA_SET_GL_RENDER_MODE(sv->PolyMode);
17947    } while (el != dlist_tail(SurfObj->DW->DrwPtchs));
17948 
17949    SUMA_LH("Bring the coords back where they ought to be");
17950    SUMA_VisX_Pointers4Display(SurfObj, 0);
17951 
17952 
17953 
17954    SUMA_LH("Done");
17955    SUMA_RETURNe;
17956 } /* SUMA_DrawMesh_mask */
17957 
17958 
17959 /*! Create a tesselated mesh */
SUMA_DrawMesh(SUMA_SurfaceObject * SurfObj,SUMA_SurfaceViewer * sv)17960 void SUMA_DrawMesh(SUMA_SurfaceObject *SurfObj, SUMA_SurfaceViewer *sv)
17961 {
17962    static char FuncName[]={"SUMA_DrawMesh"};
17963    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
17964    GLfloat *colp = NULL;
17965    int i, ii, ND, id, ip, NP, PolyMode, sz[2]={0, 0}, N_glar_FaceSet=0;
17966    SUMA_DRAWN_ROI *DrawnROI = NULL;
17967    static GLuint texName;
17968    GLfloat rotationMatrix[4][4];
17969    GLenum Face=GL_FRONT;
17970    NI_element *texnel=NULL;
17971    DList *st=NULL;
17972    SUMA_TRANS_MODES trmode;
17973    SUMA_Boolean LocalHead = NOPE;
17974 
17975    SUMA_ENTRY;
17976 
17977    SUMA_LH("Entered DrawMesh");
17978 
17979    if (LocalHead) {
17980       SUMA_EnablingRecord SER;
17981       SUMA_RecordEnablingState(&SER, SurfObj->Label);
17982       SUMA_DiffEnablingState(&SER, NULL, NULL, NULL);
17983    }
17984 
17985    if (  SurfObj->PolyMode == SRM_Hide ||
17986          sv->PolyMode == SRM_Hide ||
17987          SurfObj->TransMode == STM_16 ||
17988          sv->TransMode == STM_16) {
17989       SUMA_LH("Hiding surface");
17990       SUMA_RETURNe;
17991    }
17992 
17993    if (sv->DO_PickMode) {
17994       SUMA_LH("No need to DrawMesh in DO picking mode");
17995       SUMA_RETURNe;
17996    }
17997 
17998 
17999    SUMA_LH("Might need to swap coords from the VisX transformed data");
18000    SUMA_VisX_Pointers4Display(SurfObj, 1);
18001 
18002    if (!SUMA_GLStateTrack( "new", &st, FuncName, NULL, NULL)) {
18003       SUMA_S_Err("Failed to create tracking list");
18004       SUMA_RETURNe;
18005    }
18006    /* check on rendering mode */
18007    if (SurfObj->PolyMode != SRM_ViewerDefault) {
18008      SUMA_LHv("Poly Mode %d\n", SurfObj->PolyMode);
18009      /* not the default, do the deed */
18010      #if 0 /* Need to start using MACRO below, but it is not working yet */
18011      SUMA_SET_GL_RENDER_MODE_TRACK(SurfObj->PolyMode, st);
18012      #else
18013      SUMA_SET_GL_RENDER_MODE(SurfObj->PolyMode);
18014      #endif
18015    }
18016 
18017    /* check on rendering mode */
18018    if (SurfObj->TransMode == STM_ViewerDefault) {
18019       trmode = sv->TransMode;
18020    } else if (SurfObj->TransMode > STM_0) {
18021       trmode = SurfObj->TransMode;
18022    } else trmode = STM_0;
18023 
18024    if (trmode != STM_0) {
18025      /* not the default, do the deed */
18026      SUMA_LHv("Trans Mode %d\n", trmode);
18027      SUMA_SET_GL_TRANS_MODE(trmode, st, SO_type);
18028    }
18029 
18030    /* any texture for this surface? */
18031    texnel = SUMA_SO_NIDO_Node_Texture ( SurfObj, SUMAg_DOv, SUMAg_N_DOv, sv );
18032    if (texnel) {
18033       SUMA_LH(  "Creating texture, see init pp 415 in \n"
18034                 "OpenGL programming guide, 3rd ed.");
18035       if (NI_IS_STR_ATTR_EQUAL(texnel,"read_status","fail")) {
18036          /* can't be read */
18037          SUMA_RETURNe;
18038       }
18039 
18040       if (!NI_IS_STR_ATTR_EQUAL(texnel,"read_status","read")) { /* read it */
18041          if (!SUMA_LoadImageNIDOnel(texnel)) {
18042             SUMA_RETURNe;
18043          }
18044          /* has the box size been determined (only 2 dimensions needed)?*/
18045          NI_GET_INTv(texnel,"box_size", sz, 2, LocalHead);
18046          if (!NI_GOT) {
18047             NI_GET_INT(texnel,"width", sz[0]);
18048             NI_GET_INT(texnel,"height", sz[1]);
18049             NI_SET_INTv(texnel,"box_size", sz, 2);
18050          }
18051 
18052       }
18053 
18054       NI_GET_INTv(texnel,"box_size", sz, 2, LocalHead);
18055 
18056       /* For cool textures, see
18057          http://www.filterforge.com/filters/category42-page1.html */
18058       glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
18059       NI_GET_INT(texnel,"texName",texName);
18060       if (!NI_GOT) {
18061          /* Need to generate texture */
18062          glGenTextures(1, &texName);
18063          /* Now store it */
18064          NI_SET_INT(texnel,"texName",texName);
18065       }
18066       glBindTexture(GL_TEXTURE_2D, texName);
18067       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_REPEAT);
18068                /* GL_REPEAT, GL_CLAMP */
18069       glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_T, GL_REPEAT);
18070       glTexParameteri(  GL_TEXTURE_2D,
18071                         GL_TEXTURE_MAG_FILTER, GL_LINEAR);
18072       glTexParameteri(  GL_TEXTURE_2D,
18073                         GL_TEXTURE_MIN_FILTER, GL_LINEAR);
18074          /* cotnrols interpolation of zoomed in/out texture,
18075          GL_LINEAR, GL_NEAREST, ... */
18076       glTexImage2D(  GL_TEXTURE_2D, 0, GL_RGBA,
18077                      sz[0], sz[1], 0, GL_RGBA,
18078                      GL_UNSIGNED_BYTE, texnel->vec[0]);
18079       glTexEnvf(  GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE,
18080                   SUMA_NIDO_TexEnvMode(texnel, GL_MODULATE));
18081 
18082       /* texture goes on surface which will be drawn later,
18083          Set automatic texture coordinate generation */
18084       glTexGeni(GL_S, GL_TEXTURE_GEN_MODE,
18085                   SUMA_NIDO_TexCoordGen(texnel));
18086             /* GL_SPHERE_MAP, GL_EYE_LINEAR, GL_OBJECT_LINEAR */
18087       glTexGeni(GL_T, GL_TEXTURE_GEN_MODE,
18088                   SUMA_NIDO_TexCoordGen(texnel));
18089       glEnable(GL_TEXTURE_GEN_S);
18090       glEnable(GL_TEXTURE_GEN_T);
18091       glEnable(GL_TEXTURE_2D);
18092                      #if 0
18093                      SUMA_S_Note("I do not need all this");
18094                      glEnable(GL_CULL_FACE);
18095                      glEnable(GL_LIGHTING);
18096                      glEnable(GL_LIGHT0);
18097                      glEnable(GL_AUTO_NORMAL);
18098                      glEnable(GL_NORMALIZE);
18099                      glMaterialf(Face, GL_SHININESS, 64.0);
18100                      #endif
18101    }
18102 
18103    SUMA_LH("Draw Method");
18104    ND = SurfObj->NodeDim;
18105    NP = SurfObj->FaceSetDim;
18106    if (NP == 4) {
18107       SUMA_S_Warn("Quads have not been tested here");
18108    }
18109 
18110    N_glar_FaceSet = SurfObj->N_FaceSet;
18111 
18112    switch (DRAW_METHOD) {
18113       case STRAIGHT:
18114          switch (RENDER_METHOD) {
18115             case TRIANGLES:
18116                if (NP == 4) glBegin (GL_QUADS);
18117                else if (NP == 3) glBegin (GL_TRIANGLES);
18118                else { SUMA_S_Err("Badness"); SUMA_RETURNe;}
18119                break;
18120             case POINTS:
18121                glPointSize(4.0); /* keep outside of glBegin */
18122                glBegin (GL_POINTS);
18123                break;
18124          } /* switch RENDER_METHOD */
18125          fprintf(stderr, "2: glColor4f(NODE_COLOR_R, NODE_COLOR_G, NODE_COLOR_B, SUMA_NODE_ALPHA)\n");
18126          glColor4f(NODE_COLOR_R, NODE_COLOR_G, NODE_COLOR_B, SUMA_NODE_ALPHA);
18127          for (i=0; i < N_glar_FaceSet; i++)
18128          {
18129             ip = NP * i;
18130             id = ND * SurfObj->glar_FaceSetList[ip];
18131             glNormal3fv(&SurfObj->NodeNormList[id]);
18132             glVertex3fv(&SurfObj->NodeList[id]);
18133 
18134             id = ND * SurfObj->glar_FaceSetList[ip+1];
18135             glNormal3fv(&SurfObj->NodeNormList[id]);
18136             glVertex3fv(&SurfObj->NodeList[id]);
18137 
18138             id = ND * SurfObj->glar_FaceSetList[ip+2];
18139             glNormal3fv(&SurfObj->NodeNormList[id]);
18140             glVertex3fv(&SurfObj->NodeList[id]);
18141 
18142             if (NP==4) {
18143                id = ND * SurfObj->glar_FaceSetList[ip+3];
18144                glNormal3fv(&SurfObj->NodeNormList[id]);
18145                glVertex3fv(&SurfObj->NodeList[id]);
18146             }
18147          }
18148          glEnd();
18149          break;
18150 
18151       case ARRAY:
18152          /* This allows each node to follow the color
18153             specified when it was drawn */
18154          glColorMaterial(Face, GL_AMBIENT_AND_DIFFUSE);
18155          glEnable(GL_COLOR_MATERIAL);
18156 
18157          /*Now setup various pointers*/
18158          glEnableClientState (GL_COLOR_ARRAY);
18159          glEnableClientState (GL_VERTEX_ARRAY);
18160          glEnableClientState (GL_NORMAL_ARRAY);
18161          colp = SUMA_GetColorList (sv, SurfObj->idcode_str);
18162          if (!colp) { /* no color list, try  PermCol */
18163             if (SurfObj->PermCol) {
18164                glColorPointer (4, GL_FLOAT, 0, SurfObj->PermCol);
18165             } else {
18166                SUMA_SL_Err("Null Color Pointer, going pink");
18167 	       glDisableClientState (GL_COLOR_ARRAY);
18168 	       glColor4f(1.0, 0.0, 1.0, 1.0);
18169             }
18170          } else {
18171             glColorPointer (4, GL_FLOAT, 0, colp);
18172 
18173          }
18174          glVertexPointer (3, GL_FLOAT, 0, SurfObj->glar_NodeList);
18175          glNormalPointer (GL_FLOAT, 0, SurfObj->glar_NodeNormList);
18176          if (LocalHead)
18177             fprintf(stdout, "Ready to draw Elements %d from %s\n",
18178 	             N_glar_FaceSet, SurfObj->Label);
18179          switch (RENDER_METHOD) {
18180             case TRIANGLES:
18181                SUMA_LH("Tri %d %p",NP, SurfObj->glar_FaceSetList);
18182 	       if (NP==3) {
18183                   glDrawElements (  GL_TRIANGLES, (GLsizei)N_glar_FaceSet*3,
18184                                     GL_UNSIGNED_INT, SurfObj->glar_FaceSetList);
18185                } else if (NP==4) {
18186                   glDrawElements (  GL_QUADS, (GLsizei)N_glar_FaceSet*4,
18187                                     GL_UNSIGNED_INT, SurfObj->glar_FaceSetList);
18188                } else {
18189                   SUMA_S_Err("Oh no you don't"); SUMA_RETURNe;
18190                }
18191                break;
18192             case POINTS:
18193                glPointSize(4.0); /* keep outside of glBegin */
18194                /* it is inefficient to draw points using the
18195                   glar_FaceSetList because nodes are listed more
18196                   than once. You are better off creating an index
18197                   vector into glar_NodeList to place all the points, just once*/
18198                if (NP == 3) {
18199                   glDrawElements (  GL_POINTS, (GLsizei)N_glar_FaceSet*3,
18200                                     GL_UNSIGNED_INT, SurfObj->glar_FaceSetList);
18201                } else if (NP == 4) {
18202                   glDrawElements (  GL_POINTS, (GLsizei)N_glar_FaceSet*4,
18203                                     GL_UNSIGNED_INT, SurfObj->glar_FaceSetList);
18204                }
18205                break;
18206          } /* switch RENDER_METHOD */
18207 
18208 
18209          if (texnel) {
18210             /* kill baby kill */
18211             texnel = NULL; /* don't leave this function
18212                                        with pointer copy */
18213             glDisable(GL_TEXTURE_2D);
18214             glDisable(GL_TEXTURE_GEN_T);
18215             glDisable(GL_TEXTURE_GEN_S);
18216          }
18217 
18218          SUMA_LH("Disabling clients\n");
18219          glDisableClientState (GL_COLOR_ARRAY);
18220          glDisableClientState (GL_VERTEX_ARRAY);
18221          glDisableClientState (GL_NORMAL_ARRAY);
18222          /*fprintf(stdout, "Out SUMA_DrawMesh, ARRAY mode\n");*/
18223 
18224          glDisable(GL_COLOR_MATERIAL);
18225 
18226          /* draw dset contours (only label dset for now) */
18227          SUMA_LH("Dset contours ");
18228          if (!SUMA_Draw_SO_Dset_Contours (SurfObj,  sv)) {
18229             fprintf (SUMA_STDERR,
18230                      "Error %s: Failed in drawing Dset Contour objects.\n",
18231                      FuncName);
18232          }
18233          /* draw surface ROIs */
18234          SUMA_LH("ROIs");
18235          if (!SUMA_Draw_SO_ROI (SurfObj, SUMAg_DOv, SUMAg_N_DOv, sv)) {
18236             fprintf (SUMA_STDERR,
18237                      "Error %s: Failed in drawing ROI objects.\n", FuncName);
18238          }
18239          /* Draw Axis */
18240          SUMA_LH("Axis");
18241          if (SurfObj->MeshAxis && SurfObj->ShowMeshAxis)   {
18242             if (!SUMA_DrawAxis (SurfObj->MeshAxis, sv)) {
18243                fprintf( stderr,
18244                         "Error SUMA_DrawAxis: Unrecognized Stipple option\n");
18245             }
18246          }
18247          /* Draw node-based vectors */
18248          SUMA_LH("NBV");
18249          if (!SUMA_Draw_SO_NBV (SurfObj, SUMAg_DOv, SUMAg_N_DOv, sv)) {
18250             fprintf (SUMA_STDERR,
18251                      "Error %s: Failed in drawing NBV objects.\n", FuncName);
18252          }
18253 
18254          /* Draw node-based spheres */
18255          SUMA_LH("NBSP");
18256          if (!SUMA_Draw_SO_NBSP (SurfObj, SUMAg_DOv, SUMAg_N_DOv, sv)) {
18257             fprintf (SUMA_STDERR,
18258                      "Error %s: Failed in drawing NBSP objects.\n", FuncName);
18259          }
18260 
18261          /* Draw node-based NIDOs */
18262          SUMA_LH("NIDO");
18263          if (!SUMA_Draw_SO_NIDO (SurfObj, SUMAg_DOv, SUMAg_N_DOv, sv)) {
18264             fprintf (SUMA_STDERR,
18265                      "Error %s: Failed in drawing NIDO objects.\n", FuncName);
18266          }
18267 
18268          /* Draw Selected Node Highlight */
18269          SUMA_LH("Highlight");
18270          if (SUMA_SV_GetShowSelectedDatum(sv) && SurfObj->SelectedNode >= 0) {
18271             if (LocalHead) fprintf(SUMA_STDOUT,"Drawing Node Selection \n");
18272             id = ND * SurfObj->SelectedNode;
18273             glMaterialfv(Face, GL_EMISSION, SurfObj->NodeMarker->sphcol);
18274                   /*turn on emissidity for sphere */
18275             glMaterialfv(Face, GL_AMBIENT_AND_DIFFUSE, NoColor);
18276             glTranslatef ( SurfObj->NodeList[id],
18277                            SurfObj->NodeList[id+1],SurfObj->NodeList[id+2]);
18278             if (SurfObj->EL && SurfObj->EL->AvgLe > 0) {
18279                gluSphere(  SurfObj->NodeMarker->sphobj,
18280                            SurfObj->EL->AvgLe/15,
18281                            SurfObj->NodeMarker->slices,
18282                            SurfObj->NodeMarker->stacks);
18283             } else {
18284                gluSphere(  SurfObj->NodeMarker->sphobj,
18285                            SurfObj->NodeMarker->sphrad *
18286                               (SUMA_sv_auto_fov(sv)/FOV_INITIAL) *
18287                               SUMA_MAX_PAIR(sv->ZoomCompensate, 0.06),
18288                            SurfObj->NodeMarker->slices,
18289                            SurfObj->NodeMarker->stacks);
18290             }
18291             glTranslatef ( -SurfObj->NodeList[id],
18292                            -SurfObj->NodeList[id+1],
18293                            -SurfObj->NodeList[id+2]);
18294             glMaterialfv(Face, GL_EMISSION, NoColor);
18295                      /*turn off emissidity for axis*/
18296          }
18297 
18298          /* Draw Selected FaceSet Highlight */
18299          if (SUMA_SV_GetShowSelectedFaceSet(sv)
18300                                     && SurfObj->SelectedFaceSet >= 0) {
18301             if (LocalHead) fprintf(SUMA_STDOUT,"Drawing FaceSet Selection \n");
18302             if (!SUMA_DrawFaceSetMarker (SurfObj->FaceSetMarker, sv)) {
18303                fprintf(SUMA_STDERR,
18304                   "Error SUMA_DrawMesh: Failed in SUMA_DrawFaceSetMarker\b");
18305             }
18306          }
18307 
18308          /* Draw node based markers */
18309          if (SurfObj->NodeObjects &&
18310              SurfObj->NodeObjects->ObjectType == NIDO_type) {
18311             if (!SUMA_ApplyDataToNodeObjects(SurfObj, sv)) {
18312                SUMA_S_Err("Failed to apply data to node objects");
18313             }
18314             if (!(SUMA_DrawNIDO ((SUMA_NIDO*)SurfObj->NodeObjects->OP, sv) ) ) {
18315                SUMA_S_Err("Failed to draw NodeObjects");
18316             }
18317             SUMA_LH("Drew Node objects");
18318          } else {
18319             SUMA_LH("No Node objects");
18320          }
18321 
18322          /* Draw node based markers2 */
18323          if (SurfObj->NodeNIDOObjects) {
18324             if (!SUMA_ApplyDataToNodeNIDOObjects(SurfObj, sv)) {
18325                SUMA_S_Err("Failed to apply data to node objects2");
18326             }
18327             for (i=0; i<SurfObj->N_Node; ++i) {
18328                if (SurfObj->NodeNIDOObjects[i] &&
18329                    !(SUMA_DrawNIDO (SurfObj->NodeNIDOObjects[i], sv) ) ) {
18330                   SUMA_S_Err("Failed to draw NodeObjects");
18331                }
18332             }
18333             SUMA_LH("Drew NodeNIDOObjects");
18334          } else {
18335             SUMA_LH("No NodeNIDOObjects");
18336          }
18337          break;
18338 
18339    } /* switch DRAW_METHOD */
18340 
18341    #if 0
18342       /* For testing cube plane intersection ONLY
18343          launch suma with: suma -i cube.1D* after uncommenting #if section */
18344       /* take a plane cut each 20 displays to allow examination of cut
18345          Plane is in Z direction in screen coords */
18346       static float p[18], cen[3]={50, 50, 50}, PlEq[4], cam[3], plsz;
18347       static mcall = 0;
18348       static int ii, hits;
18349       float *ffp=NULL, *ffc=NULL;
18350       GLfloat comcol[4] = {1.0, 0.0, 0.0, 1.0};
18351 
18352       if (! (mcall % 20) ) { /* a new slicing */
18353          SUMA_S_Note("New prjection");
18354          SUMA_ScreenPlane_WorldSpace(sv, cen, PlEq);
18355          SUMA_LH("Hit time");
18356          hits = SUMA_PlaneBoxIntersect(sv->GVS[sv->StdView].ViewFrom,
18357                                         PlEq, SurfObj->NodeList, p);
18358       }
18359       ++mcall;
18360       plsz = 100;
18361       ffp = (float *)PlEq;
18362       ffc = (float *)cen;
18363 
18364       SUMA_DrawPlanes(&ffp, &ffc, &plsz, 1, sv);
18365       SUMA_S_Note("%d hits", hits);
18366       if (hits > 2) {
18367          glMaterialfv(GL_FRONT, GL_EMISSION, comcol);
18368          glColor4f(comcol[0], comcol[1], comcol[2], comcol[3]);
18369             glBegin(GL_LINE_LOOP);
18370          for (ii=0; ii<6; ++ii) {
18371             glVertex3fv(p+3*ii);
18372          }
18373             glEnd();
18374       }
18375    #endif
18376 
18377    if (SurfObj->PolyMode != sv->PolyMode) SUMA_SET_GL_RENDER_MODE(sv->PolyMode);
18378 
18379    SUMA_LH("Bring the coords back where they ought to be");
18380    SUMA_VisX_Pointers4Display(SurfObj, 0);
18381 
18382    SUMA_LH("Undoing state changes");
18383    SUMA_GLStateTrack("r", &st, FuncName, NULL, NULL);
18384 
18385 
18386    SUMA_LH("Done");
18387    SUMA_RETURNe;
18388 } /* SUMA_DrawMesh */
18389 
18390 /*! Create a simple tesselated mesh,
18391    You don't even need to pass sv for this function
18392    just simple surface drawing, node colors
18393    must be passed directly if desired */
SUMA_SimpleDrawMesh(SUMA_SurfaceObject * SurfObj,GLfloat * colp,SUMA_SurfaceViewer * sv)18394 void SUMA_SimpleDrawMesh(SUMA_SurfaceObject *SurfObj,
18395                          GLfloat *colp, SUMA_SurfaceViewer *sv)
18396 {
18397    static char FuncName[]={"SUMA_SimpleDrawMesh"};
18398    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
18399    static GLfloat PermCol[] = {0.0, 0.0, 1.0, 1.0};
18400    int i, ii, ND, id, ip, NP, PolyMode, sz[2]={0, 0};
18401    SUMA_DRAWN_ROI *DrawnROI = NULL;
18402    GLfloat rotationMatrix[4][4];
18403    GLenum Face=GL_FRONT;
18404    DList *st=NULL;
18405    SUMA_TRANS_MODES trmode;
18406    SUMA_Boolean LocalHead = NOPE;
18407 
18408    SUMA_ENTRY;
18409 
18410    SUMA_LH("Entered DrawMesh");
18411 
18412    if (  SurfObj->PolyMode == SRM_Hide ||
18413          (sv && sv->PolyMode == SRM_Hide) ||
18414          SurfObj->TransMode == STM_16 ||
18415          (sv && sv->TransMode == STM_16)) {
18416       SUMA_LH("Hiding surface");
18417       SUMA_RETURNe;
18418    }
18419 
18420    if (sv && sv->DO_PickMode) {
18421       SUMA_LH("No need to DrawMesh in DO picking mode");
18422       SUMA_RETURNe;
18423    }
18424 
18425 
18426    #if 0 /* Not sure this will ever be needed for a simple mesh */
18427    SUMA_LH("Might need to swap coords from the VisX transformed data");
18428    SUMA_VisX_Pointers4Display(SurfObj, 1);
18429    #endif
18430 
18431    if (!SUMA_GLStateTrack( "new", &st, FuncName, NULL, NULL)) {
18432       SUMA_S_Err("Failed to create tracking list");
18433       SUMA_RETURNe;
18434    }
18435 
18436    /* check on rendering mode */
18437    if (SurfObj->PolyMode != SRM_ViewerDefault) {
18438      SUMA_LHv("Poly Mode %d\n", SurfObj->PolyMode);
18439      /* not the default, do the deed */
18440      SUMA_SET_GL_RENDER_MODE(SurfObj->PolyMode);
18441    }
18442 
18443    /* check on rendering mode */
18444    if (SurfObj->TransMode == STM_ViewerDefault) {
18445       if (sv) trmode = sv->TransMode;
18446       else trmode = STM_0;
18447    } else if (SurfObj->TransMode > STM_0) {
18448       trmode = SurfObj->TransMode;
18449    } else trmode = STM_0;
18450 
18451    if (trmode != STM_0) {
18452      /* not the default, do the deed */
18453      SUMA_LHv("Trans Mode %d\n", trmode);
18454      SUMA_SET_GL_TRANS_MODE(trmode, st, -1);
18455    }
18456 
18457 
18458 
18459    SUMA_LH("Draw Method");
18460    ND = SurfObj->NodeDim;
18461    NP = SurfObj->FaceSetDim;
18462    switch (DRAW_METHOD) {
18463       case STRAIGHT:
18464          SUMA_LH("Straight");
18465          switch (RENDER_METHOD) {
18466             case TRIANGLES:
18467                if (NP == 3) glBegin (GL_TRIANGLES);
18468                else if (NP == 4) glBegin (GL_QUADS);
18469                else {
18470                   SUMA_S_Err("Badness"); SUMA_RETURNe;
18471                }
18472                break;
18473             case POINTS:
18474                glPointSize(4.0); /* keep outside of glBegin */
18475                glBegin (GL_POINTS);
18476                break;
18477          } /* switch RENDER_METHOD */
18478          fprintf(stderr, "3: glColor4f(NODE_COLOR_R, NODE_COLOR_G, NODE_COLOR_B, SUMA_NODE_ALPHA)\n");
18479          glColor4f(NODE_COLOR_R, NODE_COLOR_G, NODE_COLOR_B, SUMA_NODE_ALPHA);
18480          for (i=0; i < SurfObj->N_FaceSet; i++)
18481          {
18482             ip = NP * i;
18483             id = ND * SurfObj->FaceSetList[ip];
18484             glNormal3fv(&SurfObj->NodeNormList[id]);
18485             glVertex3fv(&SurfObj->NodeList[id]);
18486                /* glVertex3f(0.1, 0.9, 0.0); */
18487 
18488             id = ND * SurfObj->FaceSetList[ip+1];
18489             glNormal3fv(&SurfObj->NodeNormList[id]);
18490             glVertex3fv(&SurfObj->NodeList[id]);/* glVertex3f(0.1, 0.1, 0.0); */
18491 
18492             id = ND * SurfObj->FaceSetList[ip+2];
18493             glNormal3fv(&SurfObj->NodeNormList[id]);
18494             glVertex3fv(&SurfObj->NodeList[id]);/* glVertex3f(0.7, 0.5, 0.0); */
18495 
18496             if (NP==4) {
18497                id = ND * SurfObj->FaceSetList[ip+3];
18498                glNormal3fv(&SurfObj->NodeNormList[id]);
18499                glVertex3fv(&SurfObj->NodeList[id]);
18500             }
18501          }
18502          glEnd();
18503          break;
18504 
18505       case ARRAY:
18506          SUMA_LH("Array");
18507          /* This allows each node to follow the color
18508             specified when it was drawn */
18509          glColorMaterial(Face, GL_AMBIENT_AND_DIFFUSE);
18510          glEnable(GL_COLOR_MATERIAL);
18511 
18512          /*Now setup various pointers*/
18513          glEnableClientState (GL_COLOR_ARRAY);
18514          glEnableClientState (GL_VERTEX_ARRAY);
18515          glEnableClientState (GL_NORMAL_ARRAY);
18516          if (!colp) { /* no color list, try  PermCol */
18517             if (SurfObj->PermCol) {
18518                glColorPointer (4, GL_FLOAT, 0, SurfObj->PermCol);
18519             } else {
18520                glDisableClientState (GL_COLOR_ARRAY);
18521                glColor4f(PermCol[0], PermCol[1], PermCol[2], PermCol[3]);
18522             }
18523          } else {
18524             glColorPointer (4, GL_FLOAT, 0, colp);
18525          }
18526 
18527          glVertexPointer (3, GL_FLOAT, 0, SurfObj->glar_NodeList);
18528          glNormalPointer (GL_FLOAT, 0, SurfObj->glar_NodeNormList);
18529          SUMA_LH("Ready to draw Elements %d, %p, %p %p\n",
18530                   SurfObj->N_FaceSet, SurfObj->glar_NodeList,
18531                   SurfObj->glar_NodeNormList, SurfObj->glar_FaceSetList);                  if (SurfObj->PointSize >= 0.0) glPointSize(SurfObj->PointSize);
18532          switch (RENDER_METHOD) {
18533             case TRIANGLES:
18534                if (NP==3) {
18535                   glDrawElements (  GL_TRIANGLES, (GLsizei)SurfObj->N_FaceSet*3,
18536                                     GL_UNSIGNED_INT, SurfObj->glar_FaceSetList);
18537                } else if (NP==4) {
18538                   glDrawElements (  GL_QUADS, (GLsizei)SurfObj->N_FaceSet*4,
18539                                     GL_UNSIGNED_INT, SurfObj->glar_FaceSetList);
18540                } else {
18541                   SUMA_S_Err("Oh no you don't"); SUMA_RETURNe;
18542                }
18543                break;
18544             case POINTS:
18545                glPointSize(4.0); /* keep outside of glBegin */
18546                /* it is inefficient to draw points using the
18547                   glar_FaceSetList because nodes are listed more
18548                   than once. You are better off creating an index
18549                   vector into glar_NodeList to place all the points, just once*/
18550                if (NP == 3) {
18551                   glDrawElements (  GL_POINTS, (GLsizei)SurfObj->N_FaceSet*3,
18552                                     GL_UNSIGNED_INT, SurfObj->glar_FaceSetList);
18553                } else if (NP == 4) {
18554                   glDrawElements (  GL_POINTS, (GLsizei)SurfObj->N_FaceSet*4,
18555                                     GL_UNSIGNED_INT, SurfObj->glar_FaceSetList);
18556                }
18557                break;
18558          } /* switch RENDER_METHOD */
18559 
18560 
18561          /*fprintf(stdout, "Disabling clients\n");*/
18562          glDisableClientState (GL_COLOR_ARRAY);
18563          glDisableClientState (GL_VERTEX_ARRAY);
18564          glDisableClientState (GL_NORMAL_ARRAY);
18565          /*fprintf(stdout, "Out SUMA_DrawMesh, ARRAY mode\n");*/
18566 
18567          glDisable(GL_COLOR_MATERIAL);
18568 
18569          /* reset point size */
18570          if (SurfObj->PointSize >= 0.0) glPointSize(1.0);
18571 
18572          break;
18573 
18574    } /* switch DRAW_METHOD */
18575 
18576    #if 0 /* keep in sync with stuff above */
18577    SUMA_LH("Bring the coords back where they ought to be");
18578    SUMA_VisX_Pointers4Display(SurfObj, 0);
18579    #endif
18580 
18581    SUMA_LH("Undoing state changes");
18582    SUMA_GLStateTrack("r", &st, FuncName, NULL, NULL);
18583 
18584    if (SurfObj->PolyMode != sv->PolyMode) SUMA_SET_GL_RENDER_MODE(sv->PolyMode);
18585 
18586    SUMA_LH("Done");
18587    SUMA_RETURNe;
18588 } /* SUMA_SimpleDrawMesh */
18589 
18590 
SUMA_FreeVisXdatum(void * vxd)18591 void SUMA_FreeVisXdatum (void *vxd)
18592 {
18593    static char FuncName[]={"SUMA_FreeVisXdatum"};
18594    SUMA_VIS_XFORM_DATUM *xd = (SUMA_VIS_XFORM_DATUM*)vxd ;
18595 
18596    SUMA_ENTRY;
18597 
18598    if (xd) {
18599       if (xd->dxyz) SUMA_free(xd->dxyz); xd->dxyz = NULL;
18600       SUMA_free(xd); xd = NULL;
18601    }
18602 
18603    SUMA_RETURNe;
18604 }
18605 
SUMA_NewVisXdatum(char * label)18606 SUMA_VIS_XFORM_DATUM *SUMA_NewVisXdatum(char *label)
18607 {
18608    static char FuncName[]={"SUMA_NewVisXdatum "};
18609    SUMA_VIS_XFORM_DATUM *xd = NULL;
18610 
18611    SUMA_ENTRY;
18612 
18613    xd = (SUMA_VIS_XFORM_DATUM *)SUMA_calloc(1, sizeof(SUMA_VIS_XFORM_DATUM));
18614    if (!label) label = "unlabeled";
18615    strncpy(xd->label, label, 63*sizeof(char)); xd->label[63]='\0';
18616 
18617    /* no longer needed */
18618       #if 0
18619       memset(&(xd->Xform), 0, 16*sizeof(double));
18620       vx.XformType = ID;
18621       #endif
18622 
18623    SUMA_RETURN(xd);
18624 }
18625 
SUMA_EmptyVisXform(SUMA_VIS_XFORM * vx)18626 int SUMA_EmptyVisXform(SUMA_VIS_XFORM *vx)
18627 {
18628    static char FuncName[]={"SUMA_EmptyVisXform"};
18629 
18630    SUMA_ENTRY;
18631 
18632    if (vx->XformedCoords) {
18633       SUMA_free(vx->XformedCoords);
18634       vx->XformedCoords = NULL;
18635    }
18636    vx->Applied = 0;
18637    if (vx->Xchain) {
18638       dlist_destroy(vx->Xchain);
18639       SUMA_free(vx->Xchain); vx->Xchain = NULL;
18640    }
18641    vx->Xchain = (DList *)SUMA_calloc(1, sizeof(DList));
18642    dlist_init(vx->Xchain, SUMA_FreeVisXdatum);
18643 
18644    SUMA_RETURN(1);
18645 }
18646 
SUMA_ApplyVisXform(SUMA_SurfaceObject * SO,char * which,SUMA_VISX_XFORM_DIRECTIONS direction,int recompute_norm)18647 int SUMA_ApplyVisXform(SUMA_SurfaceObject *SO, char *which,
18648                        SUMA_VISX_XFORM_DIRECTIONS direction,
18649                        int recompute_norm)
18650 {
18651    static char FuncName[]={"SUMA_ApplyVisXform"};
18652    SUMA_VIS_XFORM *vx;
18653    float *xx=NULL;
18654    int n, nn, xform_orig=0;
18655    SUMA_Boolean LocalHead = NOPE;
18656 
18657    SUMA_ENTRY;
18658 
18659    if (!SO || !which) {
18660       SUMA_S_Errv("NULL input %p, %s\n", SO, CHECK_NULL_STR(which));
18661       SUMA_RETURN(0);
18662    }
18663    SUMA_LHv("SO %s, which %s, direction %d, recompute_norm %d\n",
18664             SO->Label, CHECK_NULL_STR(which), direction, recompute_norm);
18665    if (LocalHead) {
18666       SUMA_DUMP_TRACE("%s",FuncName);
18667    }
18668    /* select transform to apply */
18669    if (!strcmp(which,"VisX0")) {
18670       xform_orig = 1;
18671       vx = &(SO->VisX0);
18672       SUMA_LH("Transforms in VisX0 always apply to orig coordinates");
18673    } else if (!strcmp(which,"VisX")) {
18674       xform_orig = 0;
18675       vx = &(SO->VisX);
18676       SUMA_LH("Transforms in VisX never apply to orig coordinates\n");
18677    } else {
18678       SUMA_S_Errv("Bad string form which %s\n",which);
18679       SUMA_RETURN(0);
18680    }
18681 
18682    /* check if application is needed */
18683    if (direction == FORWARD_XFORM) { /* forward xform */
18684       SUMA_LHv("Going Forward, Applied=%d\n", vx->Applied);
18685       if(vx->Applied) { /* already done */
18686          SUMA_LH("Transform already applied, nothing to do");
18687          SUMA_RETURN(1);
18688       }
18689 
18690       if (!xform_orig) {
18691          if (!(vx->XformedCoords)) {
18692             if (!(vx->XformedCoords =
18693                      (float *)SUMA_calloc(SO->N_Node*SO->NodeDim,
18694                                           sizeof(float)))) {
18695                SUMA_S_Crit("Failed to allocate");
18696                SUMA_RETURN(0);
18697             }
18698          }
18699          memcpy(vx->XformedCoords, SO->NodeList,
18700                 SO->N_Node*SO->NodeDim*sizeof(float));
18701          xx = vx->XformedCoords;
18702       } else xx = SO->NodeList;
18703 
18704       SUMA_LHv("Applying VisX Chain xform, surf %s:\n"
18705                   "Nodelist[0] = %.3f %.3f, %.3f (%p)\n"
18706                   "xx      [0] = %.3f %.3f, %.3f (%p)\n",
18707                SO->Label,
18708                SO->NodeList[0], SO->NodeList[1], SO->NodeList[2], SO->NodeList,
18709                xx[0], xx[1], xx[2], xx);
18710       if (!SUMA_Apply_VisX_Chain(xx, SO->N_Node, vx->Xchain, 0)) {
18711          SUMA_S_Err("Mille millions de mille sabords!");
18712          SUMA_RETURN(0);
18713       }
18714       SUMA_LHv("Applied VisX Chain xform, surf %s:\n"
18715                   "Nodelist[0] = %.3f %.3f, %.3f (%p)\n"
18716                   "xx      [0] = %.3f %.3f, %.3f (%p)\n",
18717                SO->Label,
18718                SO->NodeList[0], SO->NodeList[1], SO->NodeList[2], SO->NodeList,
18719                xx[0], xx[1], xx[2], xx);
18720       vx->Applied = 1;
18721 
18722       /* recompute dimensions if any change was done to the original nodelist */
18723       if (xform_orig) {
18724          SUMA_SetSODims(SO);
18725          SUMA_MeshAxisStandard (SO->MeshAxis, (SUMA_ALL_DO *)SO);
18726       }
18727 
18728       if (!xform_orig) { /* switch to xformed coords before normals
18729                             are computed */
18730          SUMA_VisX_Pointers4Display(SO,1);
18731       }
18732          SUMA_LHv("Pre : SO->Center = [%f %f %f], Normal[0] = [%f %f %f]\n",
18733                SO->Center[0], SO->Center[1], SO->Center[2],
18734                SO->NodeNormList[0], SO->NodeNormList[1], SO->NodeNormList[2]);
18735          if (recompute_norm) { /* You'd want to do this all the time
18736                                   but it is too slow for interactive use */
18737             SUMA_RECOMPUTE_NORMALS(SO);
18738          }
18739          SUMA_LHv("Post: SO->Center = [%f %f %f], Normal[0] = [%f %f %f]\n",
18740                SO->Center[0], SO->Center[1], SO->Center[2],
18741                SO->NodeNormList[0], SO->NodeNormList[1], SO->NodeNormList[2]);
18742 
18743       if (!xform_orig) {
18744          SUMA_VisX_Pointers4Display(SO,0);
18745       }
18746 
18747       /* job is done */
18748       SUMA_LH("Appied xform");
18749       SUMA_RETURN(1);
18750    } else if (direction == UNDO_XFORM) {
18751                         /* undo xform, not just apply the reverse  */
18752       SUMA_LHv("Undoing Applied=%d\n", vx->Applied);
18753       if (!vx->Applied) { /* already not applied */
18754          SUMA_RETURN(1);
18755       }
18756       if (!vx->XformedCoords) { /* the transform was applied to original coords,
18757                                   undo it */
18758          xx = SO->NodeList;
18759          if (!SUMA_Apply_VisX_Chain(xx, SO->N_Node, vx->Xchain, 1)) {
18760             SUMA_S_Err("Tonnerre de Brest!");
18761             SUMA_RETURN(0);
18762          }
18763       } else { /*transfrom results were stored in vx->XformedCoords, just kill */
18764          SUMA_free(vx->XformedCoords); vx->XformedCoords = NULL;
18765       }
18766 
18767       /* recompute dimensions if any change was done to the original nodelist */
18768       if (xform_orig) {
18769          SUMA_SetSODims(SO);
18770          SUMA_MeshAxisStandard (SO->MeshAxis, (SUMA_ALL_DO *)SO);
18771       }
18772 
18773       if (!xform_orig) { /* switch to xformed coords before normals
18774                             are computed */
18775          SUMA_VisX_Pointers4Display(SO,1);
18776       }
18777       if (recompute_norm) { /* You'd want to do this all the time
18778                                but it is too slow for interactive use */
18779          SUMA_RECOMPUTE_NORMALS(SO);
18780       }
18781       if (!xform_orig) {
18782          SUMA_VisX_Pointers4Display(SO,0);
18783       }
18784 
18785       /* job is done */
18786       vx->Applied = 0;
18787 
18788       SUMA_RETURN(1);
18789    }
18790    SUMA_RETURN(1);
18791 }
18792 
18793 /* Get a pointer to the coordinates that ought to be displayed
18794    NEVER free this returned pointer! */
SUMA_VisX_CoordPointer(SUMA_SurfaceObject * SO)18795 float *SUMA_VisX_CoordPointer(SUMA_SurfaceObject *SO)
18796 {
18797    static char FuncName[]={"SUMA_VisX_CoordPointer"};
18798 
18799    SUMA_ENTRY;
18800 
18801    if (!SO) SUMA_RETURN(NULL);
18802    if (SO->VisX.XformedCoords && !SO->VisX.Applied) {
18803       SUMA_S_Warn("Weird case 1, should not happen.\n"
18804                   "Returning orig list to be safe");
18805       SUMA_RETURN(SO->NodeList);
18806    }
18807    if (SO->VisX0.XformedCoords) {
18808       SUMA_S_Warn("Weird case 2, should not happen.\n"
18809                   "VisX0 should not have coord copy.\n"
18810                   "Returning orig list to be safe");
18811       SUMA_RETURN(SO->NodeList);
18812    }
18813    if (SO->VisX.XformedCoords) SUMA_RETURN(SO->VisX.XformedCoords);
18814    else SUMA_RETURN(SO->NodeList);
18815 
18816    SUMA_RETURN(NULL);
18817 }
18818 
18819 /* Swap pointer copies from/to what needs to be displayed */
SUMA_VisX_Pointers4Display(SUMA_SurfaceObject * SO,int fordisp)18820 SUMA_Boolean SUMA_VisX_Pointers4Display(SUMA_SurfaceObject *SO, int fordisp)
18821 {
18822    static char FuncName[]={"SUMA_VisX_Pointers4Display"};
18823    SUMA_Boolean LocalHead = NOPE;
18824 
18825    SUMA_ENTRY;
18826 
18827    if (fordisp) {
18828       if (SO->NodeList_swp) {
18829          SUMA_S_Err("You should never have this. Coordinate swapping\n"
18830                     "should always be undone before returning here\n");
18831          SUMA_RETURN(NOPE);
18832       }
18833       SUMA_LHv("Applying swap (%d, %p)\n",
18834                SO->VisX.Applied, SO->VisX.XformedCoords);
18835       if (SO->VisX.Applied && SO->VisX.XformedCoords) {
18836          SO->NodeList_swp = SO->NodeList;
18837          SO->NodeList = SO->VisX.XformedCoords;
18838       }
18839    } else { /* undo swap */
18840       SUMA_LH("Undoing swap");
18841       if (SO->NodeList_swp) {
18842          SO->NodeList = SO->NodeList_swp; SO->NodeList_swp = NULL;
18843       }
18844    }
18845 
18846    /* and the stupid copies */
18847    SO->glar_NodeList = SO->NodeList;
18848    SO->glar_NodeNormList = SO->NodeNormList;
18849    SO->glar_FaceNormList = SO->FaceNormList;
18850 
18851    SUMA_RETURN(YUP);
18852 }
18853 
SUMA_AllowPrying(SUMA_SurfaceViewer * sv,int * RegSO)18854 int SUMA_AllowPrying(SUMA_SurfaceViewer *sv, int *RegSO)
18855 {
18856    static char FuncName[]={"SUMA_AllowPrying"};
18857    SUMA_SurfaceObject *SO1, *SO2;
18858    int N_RegSO, LoL, ir=-1, il=-1, ii=-1;
18859    SUMA_Boolean LocalHead = NOPE;
18860 
18861    SUMA_ENTRY;
18862 
18863    if (SUMAg_CF->ROI_mode) SUMA_RETURN(0);
18864 
18865    N_RegSO = SUMA_RegisteredSOs (sv, SUMAg_DOv, RegSO);
18866    if (N_RegSO != 2) {
18867       SUMA_LH( "Not set up to pry other than 2 surfaces.\n"
18868                "Deal with this when the need arises.\n");
18869       /* MSB, as usual, makes the need arise! */
18870       for (ii=0, il=-1, ir=-1; ii<N_RegSO && (il <0 || ir < 0); ++ii) {
18871          SO1 = (SUMA_SurfaceObject *)SUMAg_DOv[RegSO[ii]].OP;
18872          if (SO1->Side == SUMA_LEFT && il < 0) il = ii;
18873          if (SO1->Side == SUMA_RIGHT && ir < 0) ir = ii;
18874       }
18875       if (il >= 0 && ir >= 0) {
18876          SO1 = (SUMA_SurfaceObject *)SUMAg_DOv[RegSO[il]].OP;
18877          SO2 = (SUMA_SurfaceObject *)SUMAg_DOv[RegSO[ir]].OP;
18878          ii = RegSO[0];
18879          RegSO[0] = RegSO[il]; RegSO[il] = ii;
18880          ii = RegSO[1];
18881          RegSO[1] = RegSO[ir]; RegSO[ir] = ii;
18882       } else {
18883          SUMA_RETURN(0);
18884       }
18885    } else {
18886       /* Do Surfaces form left right pair? */
18887       SO1 = (SUMA_SurfaceObject *)SUMAg_DOv[RegSO[0]].OP;
18888       SO2 = (SUMA_SurfaceObject *)SUMAg_DOv[RegSO[1]].OP;
18889       if (  (SO1->Side != SUMA_LEFT && SO1->Side != SUMA_RIGHT) ||
18890             (SO2->Side != SUMA_LEFT && SO2->Side != SUMA_RIGHT) ||
18891             (SO1->Side == SO2->Side) ) {
18892          SUMA_LH("Only work with left / right surface pairs")
18893          SUMA_RETURN(0);
18894       }
18895    }
18896 
18897    LoL = SUMA_LeftShownOnLeft(sv, SO1, SO2, 1, 0);
18898    if (LoL == 0) { /* right surface on left of screen */
18899       SUMA_RETURN(-2);
18900    } else if (LoL == 1) { /* right surface on right of screen */
18901       SUMA_RETURN(2);
18902    } else if (LoL == -1) { /* Don't know, assume */
18903       SUMA_LH("Assuming left on left...");
18904       SUMA_RETURN(2);
18905    }
18906    /* Should not get here */
18907    SUMA_RETURN(2);
18908 }
18909 
SUMA_ApplyPrying(SUMA_SurfaceViewer * sv,float val[3],char * units,int recompute_norm)18910 SUMA_Boolean SUMA_ApplyPrying(SUMA_SurfaceViewer *sv, float val[3], char *units,
18911                               int recompute_norm)
18912 {
18913    static char FuncName[]={"SUMA_ApplyPrying"};
18914    int RegSO[SUMA_MAX_DISPLAYABLE_OBJECTS], N_RegSO, pr;
18915    SUMA_SurfaceObject *SO1=NULL, *SO2=NULL;
18916 
18917    SUMA_ENTRY;
18918 
18919    if (!sv) SUMA_RETURN(NOPE);
18920    if (units == NULL) units = "mouse";
18921 
18922    if ((pr = SUMA_AllowPrying(sv, RegSO))) {/* pry two surfaces */
18923          if (!sv->GVS[sv->StdView].LHlol) {
18924             sv->GVS[sv->StdView].LHlol = SUMA_SIGN(pr);
18925          }
18926       if (units[0] == 'm') { /* mouse movememt to degrees */
18927          sv->GVS[sv->StdView].vLHpry[0] = sv->GVS[sv->StdView].vLHpry0[0]+
18928                      sv->GVS[sv->StdView].LHlol*
18929                (90*2.5*val[0]/(float)(sv->X->aWIDTH+1.0)) ;
18930          /* instead of the 300, below, you want something related to the
18931             thickness along the LR axis of a hemisphere... */
18932          sv->GVS[sv->StdView].vLHpry[1] = sv->GVS[sv->StdView].vLHpry0[1]+
18933                      sv->GVS[sv->StdView].LHlol*
18934                (300*val[1]/(float)(sv->X->aWIDTH+1.0)) ;
18935 
18936          sv->GVS[sv->StdView].vLHpry[2] = val[2];
18937       } else { /* assume degrees */
18938          sv->GVS[sv->StdView].vLHpry[0] = val[0];
18939          sv->GVS[sv->StdView].vLHpry[1] = val[1];
18940          sv->GVS[sv->StdView].vLHpry[2] = val[2];
18941       }
18942 
18943       /* just to be safe */
18944            if (sv->GVS[sv->StdView].vLHpry[0] >  90)
18945          sv->GVS[sv->StdView].vLHpry[0] = 90;
18946       else if (sv->GVS[sv->StdView].vLHpry[0] < -90)
18947          sv->GVS[sv->StdView].vLHpry[0] = -90;
18948 
18949       /* clamp translation */
18950            if (sv->GVS[sv->StdView].vLHpry[1] > 150)
18951          sv->GVS[sv->StdView].vLHpry[1] = 150;
18952       else if (sv->GVS[sv->StdView].vLHpry[1] < 0)
18953          sv->GVS[sv->StdView].vLHpry[1] = 0;
18954 
18955       SO1 = (SUMA_SurfaceObject *)SUMAg_DOv[RegSO[0]].OP;
18956       SO2 = (SUMA_SurfaceObject *)SUMAg_DOv[RegSO[1]].OP;
18957       /* reset applied flag, then reapply transform*/
18958       if (!SUMA_ApplyVisXform(SO1, "VisX", UNDO_XFORM, recompute_norm)) {
18959          SUMA_S_Err("Failed to apply SUMA_ApplyVisXform");
18960          SUMA_RETURN(0);
18961       }
18962       if (!SUMA_ApplyVisXform(SO2, "VisX", UNDO_XFORM, recompute_norm)) {
18963          SUMA_S_Err("Failed to apply SUMA_ApplyVisXform");
18964          SUMA_RETURN(0);
18965       }
18966       if (!SUMA_ComputeVisX(SO1, SO2, sv, "VisX", recompute_norm)) {
18967          SUMA_S_Err("Failed to compute or apply prying xform");
18968       }
18969 
18970       SUMA_UpdateRotaCenter (sv, SUMAg_DOv, SUMAg_N_DOv);
18971       SUMA_UpdateViewPoint(sv, SUMAg_DOv, SUMAg_N_DOv, 0);
18972       if (SUMAg_CF->Home_After_Prying) SUMA_SetGLHome(sv);
18973    }
18974    SUMA_RETURN(YUP);
18975 }
18976 
SUMA_RecomputeNormsPrying(SUMA_SurfaceViewer * svu)18977 SUMA_Boolean SUMA_RecomputeNormsPrying(SUMA_SurfaceViewer *svu)
18978 {
18979    static char FuncName[]={"SUMA_RecomputeNormsPrying"};
18980    int RegSO[SUMA_MAX_DISPLAYABLE_OBJECTS], N_RegSO, n_sv, i, j;
18981    SUMA_SurfaceObject *SO=NULL;
18982    SUMA_SurfaceViewer *sv=NULL;
18983 
18984    SUMA_ENTRY;
18985 
18986    if (!svu) n_sv = SUMAg_N_SVv;
18987    else n_sv = 1;
18988    for (i=0; i<n_sv; ++i) {
18989       if (!svu) {
18990          sv = &(SUMAg_SVv[i]);
18991       } else {
18992          sv = svu;
18993       }
18994 
18995       if (sv->GVS[sv->StdView].vLHpry[0]  ||
18996           sv->GVS[sv->StdView].vLHpry0[0] ||
18997           sv->GVS[sv->StdView].vLHpry[1]  ||
18998           sv->GVS[sv->StdView].vLHpry0[1] ||
18999           sv->GVS[sv->StdView].vLHpry[2]  ||
19000           sv->GVS[sv->StdView].vLHpry0[2]) {/* just refresh normals */
19001          N_RegSO = SUMA_RegisteredSOs (sv, SUMAg_DOv, RegSO);
19002          for (j=0; j<N_RegSO; ++j) {
19003             SO = (SUMA_SurfaceObject *)SUMAg_DOv[RegSO[j]].OP;
19004             SUMA_VisX_Pointers4Display(SO,1);
19005             SUMA_RECOMPUTE_NORMALS(SO); /* a little slow, but not much
19006                                            to do if we're not keeping
19007                                            copy of orignal normals */
19008             SUMA_VisX_Pointers4Display(SO,0);
19009          }
19010       }
19011    }
19012    SUMA_RETURN(YUP);
19013 }
19014 
SUMA_ResetPrying(SUMA_SurfaceViewer * svu)19015 SUMA_Boolean SUMA_ResetPrying(SUMA_SurfaceViewer *svu)
19016 {
19017    static char FuncName[]={"SUMA_ResetPrying"};
19018    int RegSO[SUMA_MAX_DISPLAYABLE_OBJECTS], N_RegSO, n_sv, i;
19019    SUMA_SurfaceObject *SO1=NULL, *SO2=NULL;
19020    SUMA_SurfaceViewer *sv=NULL;
19021 
19022    SUMA_ENTRY;
19023 
19024    if (!svu) n_sv = SUMAg_N_SVv;
19025    else n_sv = 1;
19026    for (i=0; i<n_sv; ++i) {
19027       if (!svu) {
19028          sv = &(SUMAg_SVv[i]);
19029       } else {
19030          sv = svu;
19031       }
19032 
19033       if (sv->GVS[sv->StdView].vLHpry[0] ||
19034           sv->GVS[sv->StdView].vLHpry0[0]||
19035           sv->GVS[sv->StdView].vLHpry[1] ||
19036           sv->GVS[sv->StdView].vLHpry0[1]||
19037           sv->GVS[sv->StdView].vLHpry[2] ||
19038           sv->GVS[sv->StdView].vLHpry0[2]) {/* Cancel prying */
19039          N_RegSO = SUMA_RegisteredSOs (sv, SUMAg_DOv, RegSO);
19040          sv->GVS[sv->StdView].vLHpry[0] = 0.0;
19041          sv->GVS[sv->StdView].vLHpry0[0] = 0.0;
19042          sv->GVS[sv->StdView].vLHpry[1] = 0.0;
19043          sv->GVS[sv->StdView].vLHpry0[1] = 0.0;
19044          sv->GVS[sv->StdView].vLHpry[2] = 0.0;
19045          sv->GVS[sv->StdView].vLHpry0[2] = 0.0;
19046          sv->GVS[sv->StdView].LHlol = 0;
19047          SO1 = (SUMA_SurfaceObject *)SUMAg_DOv[RegSO[0]].OP;
19048          SO2 = (SUMA_SurfaceObject *)SUMAg_DOv[RegSO[1]].OP;
19049          /* reset applied flag, then reapply transform*/
19050          if (!SUMA_ApplyVisXform(SO1, "VisX", UNDO_XFORM, 1)) {
19051             SUMA_S_Err("Failed to apply SUMA_ApplyVisXform");
19052             SUMA_RETURN(0);
19053          }
19054          if (!SUMA_ApplyVisXform(SO2, "VisX", UNDO_XFORM, 1)) {
19055             SUMA_S_Err("Failed to apply SUMA_ApplyVisXform");
19056             SUMA_RETURN(0);
19057          }
19058          if (!SUMA_ComputeVisX(SO1, SO2, sv, "VisX", 1)) {
19059             SUMA_S_Err("Failed to compute or apply prying xform");
19060          }
19061 
19062          SUMA_UpdateRotaCenter (sv, SUMAg_DOv, SUMAg_N_DOv);
19063          SUMA_UpdateViewPoint(sv, SUMAg_DOv, SUMAg_N_DOv, 0);
19064          if (SUMAg_CF->Home_After_Prying) SUMA_SetGLHome(sv);
19065          SUMA_handleRedisplay((XtPointer)sv->X->GLXAREA);
19066       }
19067    }
19068    SUMA_RETURN(YUP);
19069 }
19070 
19071 /*! Determine when given one left and one right surface, whether or not
19072     the left hemisphere is shown on the left side of the viewer.
19073 
19074     If useParents then replace the surfaces by their local domain parents
19075     If applyViewingXform then apply the openGL viewing transformations
19076                          before returning the answer.
19077 
19078    0  --> Left on Right
19079    1  --> Left on Left
19080    -1 --> Can't tell / error
19081 */
SUMA_LeftShownOnLeft(SUMA_SurfaceViewer * sv,SUMA_SurfaceObject * SO1,SUMA_SurfaceObject * SO2,int useParents,int applyViewingXform)19082 int SUMA_LeftShownOnLeft(SUMA_SurfaceViewer *sv,
19083                          SUMA_SurfaceObject *SO1, SUMA_SurfaceObject *SO2,
19084                          int useParents, int applyViewingXform)
19085 {
19086    static char FuncName[]={"SUMA_LeftShownOnLeft"};
19087    SUMA_SurfaceObject *SO=NULL;
19088    double x[6], s[6];
19089    int q[2];
19090    SUMA_Boolean LocalHead = NOPE;
19091 
19092    SUMA_ENTRY;
19093 
19094    if (!sv || !SO1 || !SO2) SUMA_RETURN(-1);
19095 
19096    if (useParents) {
19097       SO1 = SUMA_findSOp_inDOv( SO1->LocalDomainParentID,
19098                                     SUMAg_DOv, SUMAg_N_DOv);
19099       SO2 = SUMA_findSOp_inDOv( SO2->LocalDomainParentID,
19100                                     SUMAg_DOv, SUMAg_N_DOv);
19101       if (!SO1 || !SO2) SUMA_RETURN(-1);
19102    }
19103 
19104    if (  (SO1->Side != SUMA_LEFT && SO1->Side != SUMA_RIGHT) ||
19105          (SO2->Side != SUMA_LEFT && SO2->Side != SUMA_RIGHT) ||
19106          (SO1->Side == SO2->Side) ) {
19107       SUMA_LH("Only work with left / right surface pairs")
19108       SUMA_RETURN(-1);
19109    }
19110 
19111    /* How about the arrangement of the surfaces? */
19112    if (SO2->Side == SUMA_LEFT) { SO = SO2; SO2 = SO1; SO1 = SO; SO=NULL; }
19113    x[0] = SO1->Center[0]; x[1] = SO1->Center[1]; x[2] = SO1->Center[2];
19114    x[3] = SO2->Center[0]; x[4] = SO2->Center[1]; x[5] = SO2->Center[2];
19115    SUMA_World2ScreenCoords (sv, 2, x, s, q, applyViewingXform, YUP);
19116    SUMA_LHv("Left  surface world  center: %f %f %f\n"
19117             "             screen center: %f %f %f\n"
19118             "Right surface world  center: %f %f %f\n"
19119             "             screen center: %f %f %f\n",
19120             x[0], x[1], x[2], s[0], s[1], s[2],
19121             x[3], x[4], x[5], s[3], s[4], s[5]);
19122    if (s[3] < s[0]) { /* right surface on left of screen */
19123       SUMA_RETURN(0);
19124    } else { /* left on left */
19125       SUMA_RETURN(1);
19126    }
19127 
19128    SUMA_RETURN(-1);
19129 }
19130 
19131 /*!
19132    Transform the parameters in the Axis structure by Xform
19133    Only  Center and BR are dealt with and the results stored
19134    in MAx if it is not NULL, otherwise MA's fields are modified
19135 */
SUMA_XformAxis(SUMA_Axis * MA,double Xform[4][4],int inv,SUMA_Axis * MAx)19136 SUMA_Boolean SUMA_XformAxis(SUMA_Axis *MA, double Xform[4][4], int inv,
19137                             SUMA_Axis *MAx)
19138 {
19139    static char FuncName[]={"SUMA_XformAxis"};
19140    float pnts[32][3];
19141    int i;
19142    SUMA_Boolean LocalHead = NOPE;
19143 
19144    SUMA_ENTRY;
19145 
19146    if (!MA ) SUMA_RETURN(NOPE);
19147 
19148    /* Create the corners, center, and transform them all */
19149    SUMA_LHv("Center at input: %f %f %f\n"
19150             "BR X: %f %f\n"
19151             "   Y: %f %f\n"
19152             "   Z: %f %f\n",
19153          MA->Center[0], MA->Center[1],MA->Center[2],
19154          MA->BR[0][0], MA->BR[0][1],
19155          MA->BR[1][0], MA->BR[1][1],
19156          MA->BR[2][0], MA->BR[2][1]);
19157    SUMA_BOX_CORNER_POINTS_FROM_AXIS(MA, pnts);
19158    SUMA_COPY_VEC(MA->Center, pnts[8], 3, float, float);
19159 
19160    /* transform the lot of them */
19161    SUMA_Apply_Coord_xform((float *)pnts,9,3, Xform, inv,NULL);
19162 
19163    /* put results in output */
19164    if (!MAx) MAx = MA;
19165    SUMA_COPY_VEC(pnts[8], MAx->Center, 3, float, float);
19166 
19167    for (i=0; i<3; ++i) {
19168       MAx->BR[i][0] = MAx->BR[i][1] = pnts[0][i];
19169    }
19170    for (i=1; i<8; ++i) {
19171             if (pnts[i][0] < MAx->BR[0][0]) MAx->BR[0][0]=pnts[i][0];
19172       else  if (pnts[i][0] > MAx->BR[0][1]) MAx->BR[0][1]=pnts[i][0];
19173       else  if (pnts[i][1] < MAx->BR[1][0]) MAx->BR[1][0]=pnts[i][1];
19174       else  if (pnts[i][1] > MAx->BR[1][1]) MAx->BR[1][1]=pnts[i][1];
19175       else  if (pnts[i][2] < MAx->BR[2][0]) MAx->BR[2][0]=pnts[i][2];
19176       else  if (pnts[i][2] > MAx->BR[2][1]) MAx->BR[2][1]=pnts[i][2];
19177    }
19178 
19179    SUMA_LHv("Center at output: %f %f %f\n"
19180             "BR X: %f %f\n"
19181             "   Y: %f %f\n"
19182             "   Z: %f %f\n",
19183          MAx->Center[0], MAx->Center[1],MAx->Center[2],
19184          MAx->BR[0][0], MAx->BR[0][1],
19185          MAx->BR[1][0], MAx->BR[1][1],
19186          MAx->BR[2][0], MAx->BR[2][1]);
19187 
19188    SUMA_RETURN(YUP);
19189 
19190 }
19191 
19192 /* Compute the transform needed to properly position two
19193    surfaces in the display */
SUMA_ComputeVisX(SUMA_SurfaceObject * SO1,SUMA_SurfaceObject * SO2,SUMA_SurfaceViewer * sv,char * which,int recompute_norm)19194 int SUMA_ComputeVisX(SUMA_SurfaceObject *SO1, SUMA_SurfaceObject *SO2,
19195                      SUMA_SurfaceViewer *sv, char *which, int recompute_norm)
19196 {
19197    static char FuncName[]={"SUMA_ComputeVisX"};
19198    SUMA_SurfaceObject *SOv[2];
19199    SUMA_VIS_XFORM_DATUM *x0=NULL, *x1=NULL;
19200    float dx=0.0, dx2;
19201    int splitx = 0, regdeal = 0;
19202    int i, state;
19203    double A[3], B[3], C[3], D[3], AC[3], AD[3], BC[3], BD[3];
19204    double dot1, dot2, doti, sgn=-1.0;
19205    double Pt[3], Pb[3], C1[3], rotax[3], rotmag, rot=25;
19206    SUMA_Boolean LocalHead = NOPE;
19207 
19208    SUMA_ENTRY;
19209 
19210    if ( (SO1->Side != SUMA_LEFT && SO1->Side != SUMA_RIGHT) ||
19211         (SO2->Side != SUMA_LEFT && SO2->Side != SUMA_RIGHT) ||
19212         (SO1->Side == SO2->Side) ) {
19213       SUMA_LH("Only work with left and right surface pairs")
19214       SUMA_RETURN(1);
19215    }
19216 
19217    if (SO1->NodeList_swp || SO2->NodeList_swp) {
19218       SUMA_S_Err("Cannot operate here while NodeList is swapped");
19219       SUMA_RETURN(0);
19220    }
19221 
19222    if (!sv->GVS[sv->StdView].LHlol) {
19223       if (SUMA_LeftShownOnLeft(sv, SO1, SO2, 1, 0)) {
19224          sv->GVS[sv->StdView].LHlol = 1;
19225       } else {
19226          sv->GVS[sv->StdView].LHlol = -1;
19227       }
19228 
19229    }
19230    if (SO1->Side == SUMA_LEFT) { SOv[0] = SO1; SOv[1] = SO2; }
19231    else { SOv[0] = SO2; SOv[1] = SO1;}
19232 
19233    splitx = 0;
19234 
19235    if (!strcmp(which,"VisX0")) {
19236 
19237    /* Making sure surfaces don't ride on each other
19238       Assume we're only working on the RL, X axis   */
19239       if ((SO1->AnatCorrect || SO2->AnatCorrect)) {
19240          SUMA_LHv("Out of principle,  won't transform VisX0\n"
19241                   " for anatomically correct surfaces (%d %d)\n"
19242                   " Nothing to be done here\n",
19243                      SO1->AnatCorrect, SO2->AnatCorrect);
19244          SUMA_RETURN(1);
19245       }
19246 
19247       if (!(x0 = SUMA_Fetch_VisX_Datum ("Arrange_At_Load", SOv[0]->VisX0.Xchain,
19248                                         ADD_AFTER, NULL))) {
19249          SUMA_S_Err("Should not have failed to fetch VisX0 with addition!");
19250          SUMA_RETURN(0);
19251       }
19252       if (!(x1 = SUMA_Fetch_VisX_Datum ("Arrange_At_Load", SOv[1]->VisX0.Xchain,
19253                                         ADD_AFTER, NULL))) {
19254          SUMA_S_Err("Should not have failed to fetch VisX1 with addition!");
19255          SUMA_RETURN(0);
19256       }
19257       /* How much do the surfaces overlap along X?
19258          SOv[0] is the left side surface , see NIH-6 pp 223*/
19259       dx = SOv[1]->MeshAxis->BR[0][0] - SOv[0]->MeshAxis->BR[0][1];
19260                                                 /* xminRIGHT - xmaxLEFT */
19261       dx2 = SOv[1]->MeshAxis->BR[0][1] - SOv[0]->MeshAxis->BR[0][0];
19262                                                 /* xmaxRIGHT - xminLEFT */
19263       /* Rightmost of Right side surface, RAI assumed for coords */
19264       A[0] = SOv[1]->MeshAxis->BR[0][0]; A[1]=0.0; A[2]=0.0; /* ignore Y & Z */
19265       /* Leftmost of Right side */
19266       B[0] = SOv[1]->MeshAxis->BR[0][1]; B[1]=0.0; B[2]=0.0;
19267 
19268       /* same for the Left side surface */
19269       C[0] = SOv[0]->MeshAxis->BR[0][0]; C[1]=0.0; C[2]=0.0;
19270       D[0] = SOv[0]->MeshAxis->BR[0][1]; D[1]=0.0; D[2]=0.0;
19271 
19272       for (i=0; i<3; ++i) {
19273          AC[i] = C[i]-A[i];
19274          BC[i] = C[i]-B[i];
19275          AD[i] = D[i]-A[i];
19276          BD[i] = D[i]-B[i];
19277       }
19278       dot1 = SUMA_MT_DOT(AC, BC);
19279       dot2 = SUMA_MT_DOT(AD, BD);
19280       doti = BC[0];
19281 
19282       state = -1;
19283       if (dot1 >= 0.0 && dot2 >= 0.0) {
19284          if (doti >= 0) {
19285             state = 0;
19286          } else {
19287             state = 4;
19288          }
19289       } else if (dot1 >= 0.0 && dot2 < 0.0) {
19290          state = 3;
19291       } else if (dot1 < 0.0 && dot2 >= 0.0) {
19292          state = 1;
19293       } else if (dot1 < 0.0 && dot2 < 0.0) {
19294          state = 2;
19295       }
19296       if (state < 0) {
19297          SUMA_S_Warnv("Case not accounted for: dot1 = %f dot2 = %f doti = %f\n"
19298                       "No separation attempted\n",
19299                dot1, dot2, doti);
19300       }
19301       SUMA_LHv("Have Left surface %s: %.3f %.3f\n"
19302                "    right surface %s  %.3f %.3f\n"
19303                ", dx = %f, dx2=%f\n"
19304                "dot1 = %.3f dot2 = %.3f doti = %.3f, state = %d\n",
19305                SOv[0]->Label,
19306                   SOv[0]->MeshAxis->BR[0][0], SOv[0]->MeshAxis->BR[0][1],
19307                SOv[1]->Label,
19308                   SOv[1]->MeshAxis->BR[0][0], SOv[1]->MeshAxis->BR[0][1],
19309                   dx, dx2,
19310                dot1, dot2, doti, state);
19311 
19312       /* split the difference, if need be
19313          If this fails at time, the separation amount
19314          should be rewritten in terms of the vectors defined above
19315          and for each of the states separately. For now we leave
19316          well enough alone.*/
19317       if (state == 1 || state == 2 || state == 3 || state == 4) {
19318                                                       /* need separation */
19319          /* Augment the distance by 10% of the surface sizes
19320             Don't bother for flat maps */
19321          if (SOv[0]->EmbedDim == 3 && SOv[1]->EmbedDim == 3) {
19322             SUMA_LH("Vanilla");
19323             dx = dx - 0.1/2.0*
19324                    ( (SOv[0]->MeshAxis->BR[0][1] - SOv[0]->MeshAxis->BR[0][0]) +
19325                      (SOv[1]->MeshAxis->BR[0][1] - SOv[1]->MeshAxis->BR[0][0]) );
19326             if (sv->GVS[sv->StdView].LHlol == -1) dx = -dx;
19327             /* move left surface to the left and right surface to the right */
19328             x0->Xform[0][3] = dx/2.0;
19329             x1->Xform[0][3] = -dx/2.0;
19330             x0->XformType = SHIFT; /* translation */
19331             x1->XformType = SHIFT; /* translation */
19332          } else if (SOv[0]->EmbedDim == 2 && SOv[1]->EmbedDim == 2) {
19333             /* you'll want to rotate one flat map about its Z axis
19334                You should really compute the needed x axis separation
19335                after the coords are rotated or risk overlap after rotation.
19336                Will see if that is needed in practice. Also, this may not
19337                be appropriate for flat maps not made by FreeSurfer, I can
19338                easily put a switch for that */
19339             SUMA_LH("Special flat");
19340             if (sv->GVS[sv->StdView].LHlol == -1) dx = -dx;
19341             rotax[0] = rotax[1] = 0.0; rotax[2] = 1.0;
19342             C[0] = SOv[1]->Center[0];
19343             C[1] = SOv[1]->Center[1];
19344             C[2] = SOv[1]->Center[2];
19345             if (!SUMA_BuildRotationMatrix(C, rotax, SUMA_PI,
19346                                           x1->Xform)) {
19347                SUMA_S_Err("Failed to build rotation for surface 1");
19348                SUMA_RETURN(0);
19349             }
19350             x0->Xform[0][3] = dx/2.0;
19351             x1->Xform[0][3] = -dx/2.0;
19352             x0->XformType = SHIFT; /* translation */
19353             x1->XformType = AFFINE; /* affine */
19354          } else { /* would you ever get here? */
19355             SUMA_LH("Did not expect this");
19356             if (sv->GVS[sv->StdView].LHlol == -1) dx = -dx;
19357             /* move left surface to the left and right surface to the right */
19358             x0->Xform[0][3] = dx/2.0;
19359             x1->Xform[0][3] = -dx/2.0;
19360             x0->XformType = SHIFT; /* translation */
19361             x1->XformType = SHIFT; /* translation */
19362          }
19363          if (!SUMA_ApplyVisXform(SOv[0], "VisX0",
19364                                  FORWARD_XFORM, recompute_norm)) {
19365                SUMA_S_Err("Failed to apply SUMA_ApplyVisXform");
19366                SUMA_RETURN(0);
19367          }
19368          if (!SUMA_ApplyVisXform(SOv[1], "VisX0",
19369                                  FORWARD_XFORM, recompute_norm)) {
19370             SUMA_S_Err("Failed to apply SUMA_ApplyVisXform");
19371             SUMA_RETURN(0);
19372          }
19373       }
19374    } else if (!strcmp(which,"VisX")){
19375       /* if Prying is to be added, it should be after CoordBias */
19376       x0 = SUMA_Fetch_VisX_Datum ("Prying", SOv[0]->VisX.Xchain,
19377                                   ADD_AFTER,"CoordBias");
19378       x1 = SUMA_Fetch_VisX_Datum ("Prying", SOv[1]->VisX.Xchain,
19379                                   ADD_AFTER, "CoordBias");
19380 
19381       /* open up the gap */
19382       sgn = -1.0;
19383       regdeal = 0;
19384       rot = sv->GVS[sv->StdView].vLHpry[0];
19385       if (!(SUMA_IS_GEOM_SYMM(SOv[0]->isSphere) &&
19386             SUMA_IS_GEOM_SYMM(SOv[1]->isSphere))   &&
19387           !(SOv[0]->EmbedDim == 2 && SOv[1]->EmbedDim == 2) ) {
19388          SUMA_LH("Regular deal");
19389          regdeal = 1;
19390                      if (sv->PryAx == 3) {
19391          if (rot*sv->GVS[sv->StdView].LHlol >= 0) {/*rot. about posterior axes */
19392             /* Compute average medial Z axis (Box segment 12 from left hemi +
19393                                                   segment 11 from right hemi )
19394                (see SUMA_SortedAxisSegmentList() and labbook NIH-IV, pp 21)*/
19395             Pb[0] = (SOv[0]->MeshAxis->BR[0][1] +    /* pt B, left hemi (xmax)*/
19396                      SOv[1]->MeshAxis->BR[0][0])/2.0;/* pt A, right hemi (xmin)*/
19397             Pb[1] = (SOv[0]->MeshAxis->BR[1][0] +    /* pt B, left hemi (ymin)*/
19398                      SOv[1]->MeshAxis->BR[1][0])/2.0;/* pt A, right hemi (ymin)*/
19399             Pb[2] = (SOv[0]->MeshAxis->BR[2][0] +    /* pt B, left hemi (zmin)*/
19400                      SOv[1]->MeshAxis->BR[2][0])/2.0;/* pt A, right hemi (zmin)*/
19401 
19402             Pt[0] = (SOv[0]->MeshAxis->BR[0][1] +    /* pt F, left hemi (xmax)*/
19403                      SOv[1]->MeshAxis->BR[0][0])/2.0;/* pt E, right hemi (xmin)*/
19404             Pt[1] = (SOv[0]->MeshAxis->BR[1][0] +    /* pt F, left hemi (ymin)*/
19405                      SOv[1]->MeshAxis->BR[1][0])/2.0;/* pt E, right hemi (ymin)*/
19406             Pt[2] = (SOv[0]->MeshAxis->BR[2][1] +    /* pt F, left hemi (zmax)*/
19407                      SOv[1]->MeshAxis->BR[2][1])/2.0;/* pt E, right hemi (zmax)*/
19408          } else {
19409             /* Compute average medial Z axis (Box segment 10 from left hemi +
19410                                                   segment 9 from right hemi )
19411                (see  SUMA_SortedAxisSegmentList() and labbook NIH-IV, pp 21)*/
19412             Pb[0] = (SOv[0]->MeshAxis->BR[0][1] +    /* pt D, left hemi (xmax)*/
19413                      SOv[1]->MeshAxis->BR[0][0])/2.0;/* pt C, right hemi (xmin)*/
19414             Pb[1] = (SOv[0]->MeshAxis->BR[1][1] +    /* pt D, left hemi (ymax)*/
19415                      SOv[1]->MeshAxis->BR[1][1])/2.0;/* pt C, right hemi (ymax)*/
19416             Pb[2] = (SOv[0]->MeshAxis->BR[2][0] +    /* pt D, left hemi (zmin)*/
19417                      SOv[1]->MeshAxis->BR[2][0])/2.0;/* pt C, right hemi (zmin)*/
19418 
19419             Pt[0] = (SOv[0]->MeshAxis->BR[0][1] +    /* pt H, left hemi (xmax)*/
19420                      SOv[1]->MeshAxis->BR[0][0])/2.0;/* pt G, right hemi (xmin)*/
19421             Pt[1] = (SOv[0]->MeshAxis->BR[1][1] +    /* pt H, left hemi (ymax)*/
19422                      SOv[1]->MeshAxis->BR[1][1])/2.0;/* pt G, right hemi (ymax)*/
19423             Pt[2] = (SOv[0]->MeshAxis->BR[2][1] +    /* pt H, left hemi (zmax)*/
19424                      SOv[1]->MeshAxis->BR[2][1])/2.0;/* pt G, right hemi (zmax)*/
19425          }
19426                      } else if (sv->PryAx == 2) {
19427          if (rot*sv->GVS[sv->StdView].LHlol <= 0) {/*rot. about top axes */
19428             /* Compute average medial Y axis (Box segment 12 from left hemi +
19429                                                   segment 11 from right hemi )
19430                (see SUMA_SortedAxisSegmentList() and labbook NIH-IV, pp 21)*/
19431             Pb[0] = (SOv[0]->MeshAxis->BR[0][1] +    /* pt B, left hemi (xmax)*/
19432                      SOv[1]->MeshAxis->BR[0][0])/2.0;/* pt A, right hemi (xmin)*/
19433             Pb[1] = (SOv[0]->MeshAxis->BR[1][0] +    /* pt B, left hemi (ymin)*/
19434                      SOv[1]->MeshAxis->BR[1][0])/2.0;/* pt A, right hemi (ymin)*/
19435             Pb[2] = (SOv[0]->MeshAxis->BR[2][0] +    /* pt B, left hemi (zmin)*/
19436                      SOv[1]->MeshAxis->BR[2][0])/2.0;/* pt A, right hemi (zmin)*/
19437 
19438             Pt[0] = (SOv[0]->MeshAxis->BR[0][1] +    /* pt F, left hemi (xmax)*/
19439                      SOv[1]->MeshAxis->BR[0][0])/2.0;/* pt E, right hemi (xmin)*/
19440             Pt[1] = (SOv[0]->MeshAxis->BR[1][1] +    /* pt F, left hemi (ymax)*/
19441                      SOv[1]->MeshAxis->BR[1][1])/2.0;/* pt E, right hemi (ymax)*/
19442             Pt[2] = (SOv[0]->MeshAxis->BR[2][0] +    /* pt F, left hemi (zmin)*/
19443                      SOv[1]->MeshAxis->BR[2][0])/2.0;/* pt E, right hemi (zmin)*/
19444          } else {
19445             /* Compute average medial Y axis (Box segment 10 from left hemi +
19446                                                   segment 9 from right hemi )
19447                (see  SUMA_SortedAxisSegmentList() and labbook NIH-IV, pp 21)*/
19448             Pb[0] = (SOv[0]->MeshAxis->BR[0][1] +    /* pt D, left hemi (xmax)*/
19449                      SOv[1]->MeshAxis->BR[0][0])/2.0;/* pt C, right hemi (xmin)*/
19450             Pb[1] = (SOv[0]->MeshAxis->BR[1][0] +    /* pt D, left hemi (ymin)*/
19451                      SOv[1]->MeshAxis->BR[1][0])/2.0;/* pt C, right hemi (ymin)*/
19452             Pb[2] = (SOv[0]->MeshAxis->BR[2][1] +    /* pt D, left hemi (zmax)*/
19453                      SOv[1]->MeshAxis->BR[2][1])/2.0;/* pt C, right hemi (zmax)*/
19454 
19455             Pt[0] = (SOv[0]->MeshAxis->BR[0][1] +    /* pt H, left hemi (xmax)*/
19456                      SOv[1]->MeshAxis->BR[0][0])/2.0;/* pt G, right hemi (xmin)*/
19457             Pt[1] = (SOv[0]->MeshAxis->BR[1][1] +    /* pt H, left hemi (ymax)*/
19458                      SOv[1]->MeshAxis->BR[1][1])/2.0;/* pt G, right hemi (ymax)*/
19459             Pt[2] = (SOv[0]->MeshAxis->BR[2][1] +    /* pt H, left hemi (zmax)*/
19460                      SOv[1]->MeshAxis->BR[2][1])/2.0;/* pt G, right hemi (zmax)*/
19461          }
19462                      } else {
19463             SUMA_S_Err("Bad pry axis value, %d", sv->PryAx);
19464             SUMA_RETURN(0);
19465                      }
19466          SUMA_UNIT_VEC(Pb, Pt, rotax, rotmag);
19467          C[0] = C1[0] = (Pt[0] + Pb[0])/2.0;
19468          C[1] = C1[1] = (Pt[1] + Pb[1])/2.0;
19469          C[2] = C1[2] = (Pt[2] + Pb[2])/2.0;
19470       } else if ( SUMA_IS_GEOM_SYMM(SOv[0]->isSphere) &&
19471                   SUMA_IS_GEOM_SYMM(SOv[1]->isSphere)) {
19472                   /* for spheres, best rotate about the screen's Y axis
19473                   and spheres's own centers*/
19474          C[0]  = SOv[0]->Center[0];  C[1]  = SOv[0]->Center[1];
19475                                      C[2]  = SOv[0]->Center[2];
19476          C1[0] = SOv[1]->Center[0];  C1[1] = SOv[1]->Center[1];
19477                                      C1[2] = SOv[1]->Center[2];
19478          SUMA_LH("Spheres!");
19479          if (  sv->GVS[sv->StdView].vLHpry[1] >
19480                1.3*sv->GVS[sv->StdView].vLHpry[0]){
19481             /* stronger vertical movement, rotate about the screen X axis*/
19482             SUMA_NormScreenToWorld(sv, 0, 0, Pb, NULL, 1);
19483             SUMA_NormScreenToWorld(sv, 1, 0, Pt, NULL, 1);
19484             rot = sv->GVS[sv->StdView].vLHpry[1];
19485             sgn = 1.0;
19486          } else if (sv->GVS[sv->StdView].vLHpry[0] >
19487                     1.3*sv->GVS[sv->StdView].vLHpry[1]){
19488             /* stronger horizontal movement, rotate about the screen Y axis*/
19489             SUMA_NormScreenToWorld(sv, 0, 0, Pb, NULL, 1);
19490             SUMA_NormScreenToWorld(sv, 0, 1, Pt, NULL, 1);
19491             rot = sv->GVS[sv->StdView].vLHpry[0];
19492          } else {
19493             /* don't rotate */
19494             rot = 0;
19495          }
19496          SUMA_UNIT_VEC(Pb, Pt, rotax, rotmag);
19497          rot = rot*2.0; /* go to +/- 180 */
19498       } else if ( SOv[0]->EmbedDim == 2 && SOv[1]->EmbedDim == 2 ) {
19499                                                       /* for flatties */
19500          SUMA_LH("Flats!");
19501          C[0]  = SOv[0]->Center[0];  C[1]  = SOv[0]->Center[1];
19502                                      C[2]  = SOv[0]->Center[2];
19503          C1[0] = SOv[1]->Center[0];  C1[1] = SOv[1]->Center[1];
19504                                      C1[2] = SOv[1]->Center[2];
19505          rotax[0] = rotax[1] = 0.0; rotax[2] = 1.0;
19506          rot = rot*2.0; /* go to +/- 180 */
19507 
19508          splitx = 1;/* need to split them apart too */
19509       }
19510          SUMA_LHv("Rotation of %f degrees about [%f %f %f] on "
19511                   "[%f %f %f] and [%f %f %f], splitx = %d\n",
19512                   rot, rotax[0], rotax[1], rotax[2],
19513                   C[0], C[1], C[2], C1[0], C1[1], C1[2], splitx);
19514          if (!SUMA_BuildRotationMatrix(C, rotax, rot*SUMA_PI/180.0,
19515                                        x0->Xform)) {
19516             SUMA_S_Err("Failed to build rotation for surface 0");
19517             SUMA_RETURN(0);
19518          }
19519          if (!SUMA_BuildRotationMatrix(C1, rotax, sgn*rot*SUMA_PI/180.0,
19520                                        x1->Xform)) {
19521             SUMA_S_Err("Failed to build rotation for surface 0");
19522             SUMA_RETURN(0);
19523          }
19524 
19525          if (splitx) {
19526             SUMA_Axis mxfrm0, mxfrm1;
19527             float dxi = SOv[1]->MeshAxis->BR[0][0] - SOv[0]->MeshAxis->BR[0][1];;
19528             /* compute the new x axis overlap */
19529 
19530             SUMA_XformAxis(SOv[0]->MeshAxis, x0->Xform, 0, &mxfrm0);
19531             SUMA_XformAxis(SOv[1]->MeshAxis, x1->Xform, 0, &mxfrm1);
19532             dx  = mxfrm1.BR[0][0] - mxfrm0.BR[0][1];
19533             dxi = mxfrm0.BR[0][0] - mxfrm1.BR[0][1];
19534 
19535             if (SUMA_ABS(dx) > SUMA_ABS(dxi)) dx = dxi; /* inverted layout */
19536             if (dx < 0) {
19537                if (sv->GVS[sv->StdView].LHlol == -1) dx = -dx;
19538                x0->Xform[0][3] += dx/2.0;
19539                x1->Xform[0][3] += -dx/2.0;
19540             }
19541          }
19542 
19543          if (regdeal && sv->GVS[sv->StdView].vLHpry[1] > 0) {
19544             SUMA_LH("Red alert, red alert %f",
19545                     sv->GVS[sv->StdView].vLHpry[1]);
19546             dx = sv->GVS[sv->StdView].vLHpry[1];
19547             if (sv->GVS[sv->StdView].LHlol == -1) dx = -dx;
19548             x0->Xform[0][3] += -dx/2.0;
19549             x1->Xform[0][3] +=  dx/2.0;
19550          }
19551 
19552          x0->XformType = AFFINE; /* affine */
19553          x1->XformType = AFFINE; /* affine */
19554          if (!SUMA_ApplyVisXform(SOv[0], "VisX",
19555                                  FORWARD_XFORM, recompute_norm)) {
19556                SUMA_S_Err("Failed to apply SUMA_ApplyVisXform");
19557                SUMA_RETURN(0);
19558          }
19559          if (!SUMA_ApplyVisXform(SOv[1], "VisX",
19560                                  FORWARD_XFORM, recompute_norm)) {
19561             SUMA_S_Err("Failed to apply SUMA_ApplyVisXform");
19562             SUMA_RETURN(0);
19563          }
19564    } else {
19565       SUMA_S_Errv("Bad Witch! %s\n", which);
19566       SUMA_RETURN(0);
19567    }
19568    SUMA_RETURN(1);
19569 }
19570 
SUMA_EmptyDrawMasks(SUMA_DRAW_MASKS * DW)19571 SUMA_Boolean SUMA_EmptyDrawMasks(SUMA_DRAW_MASKS * DW)
19572 {
19573    static char FuncName[]={"SUMA_EmptyDrawMasks"};
19574    SUMA_ENTRY;
19575 
19576    if (!DW) {
19577       SUMA_S_Err("NULL input");
19578       SUMA_RETURN(NOPE);
19579    }
19580 
19581    if (DW->nodemask) SUMA_free(DW->nodemask);
19582    if (DW->DrwPtchs) dlist_destroy(DW->DrwPtchs);
19583 
19584    DW->nodemask = NULL;
19585    DW->N_nz_nodemask = 0;
19586    DW->DrwPtchs = NULL;
19587    DW->PatchRegenID = 0;
19588    DW->PatchGenID = -1;
19589    SUMA_ifree(DW->user_exp);
19590    SUMA_ifree(DW->cmask_exp);
19591    SUMA_ifree(DW->last_cmask_exp);
19592    SUMA_RETURN(YUP);
19593 }
SUMA_FreeDrawMasks(SUMA_DRAW_MASKS * DW)19594 SUMA_Boolean SUMA_FreeDrawMasks(SUMA_DRAW_MASKS * DW)
19595 {
19596    static char FuncName[]={"SUMA_FreeDrawMasks"};
19597    int kkk=0;
19598 
19599    SUMA_ENTRY;
19600 
19601    if (DW == NULL) {
19602       /* That's OK */
19603       SUMA_RETURN (YUP);
19604    }
19605    /* is this pointer used by others ? */
19606    if (DW->N_links) {
19607       DW = (SUMA_DRAW_MASKS*)SUMA_UnlinkFromPointer((void *)DW);
19608       SUMA_RETURN (YUP);
19609    }
19610 
19611    /* No more links, go for it */
19612    SUMA_EmptyDrawMasks(DW);
19613 
19614    SUMA_free(DW); DW = NULL;
19615 
19616    SUMA_RETURN (YUP);
19617 }
19618 
19619 
19620 /*!**
19621 File : SUMA_Load_Surface_Object.c
19622 \author Ziad Saad
19623 Date : Wed Jan 23 15:18:12 EST 2002
19624 
19625 Purpose :
19626 
19627 
19628 
19629 Usage :
19630     Ans = SUMA_Free_Surface_Object ( SO)
19631 
19632 
19633 Input paramters :
19634 \param   SO (SUMA_SurfaceObject *) Surface Object pointer
19635 
19636 Returns :
19637 \return  Ans (SUMA_Boolean)
19638 
19639 \sa SUMA_Load_Surface_Object
19640 ***/
SUMA_Free_Surface_Object(SUMA_SurfaceObject * SO)19641 SUMA_Boolean SUMA_Free_Surface_Object (SUMA_SurfaceObject *SO)
19642 {
19643    static char FuncName[]={"SUMA_Free_Surface_Object"};
19644    int i;
19645    SUMA_Boolean LocalHead = NOPE;
19646 
19647    SUMA_ENTRY;
19648 
19649    if (!SO) {
19650       SUMA_SL_Warn("NULL SO");
19651       SUMA_RETURN(YUP);
19652    }
19653    if (LocalHead) {
19654       if (SO->Label)
19655          fprintf (SUMA_STDERR, "%s: freeing SO %s\n", FuncName, SO->Label);
19656       else fprintf (SUMA_STDERR, "%s: freeing SO\n", FuncName);
19657    }
19658    /* Start with the big ones and down*/
19659    /* From SUMA 1.2 and on, some glar_ pointers are copies
19660       of others and should not be freed */
19661    SO->glar_FaceSetList = NULL;
19662    SO->glar_NodeList = NULL;
19663    SO->glar_NodeNormList = NULL;
19664    SO->glar_FaceNormList = NULL;
19665    SO->NodeList_swp = NULL;
19666 
19667    if (LocalHead) fprintf (stdout, "SO->NodeList... ");
19668    if (SO->NodeList)   SUMA_free(SO->NodeList);
19669    /*fprintf (stdout, "SO->FaceSetList... ");*/
19670    if (SO->FaceSetList) SUMA_free(SO->FaceSetList);
19671    /*fprintf (stdout, "SO->FaceSetList... ");*/
19672    if (SO->NodeNormList) SUMA_free(SO->NodeNormList);
19673    /*fprintf (stdout, "SO->NodeNormList... ");*/
19674    if (SO->FaceNormList) SUMA_free(SO->FaceNormList);
19675    /*fprintf (stdout, "SO->FaceNormList... ");*/
19676    if (SO->Name_NodeParent) SUMA_free(SO->Name_NodeParent);
19677    if (LocalHead) fprintf (stdout, "SO->Name.FileName... ");
19678    if (SO->Name.FileName) SUMA_free(SO->Name.FileName);
19679 
19680    if (LocalHead)
19681       fprintf (SUMA_STDERR, "%s: freeing SO->Name.Path\n", FuncName);
19682    if (SO->Name.Path) SUMA_free(SO->Name.Path);
19683    if (SO->SpecFile.Path) SUMA_free(SO->SpecFile.Path);
19684    if (SO->SpecFile.FileName) SUMA_free(SO->SpecFile.FileName);
19685    if (SO->MeshAxis) SUMA_Free_Axis (SO->MeshAxis);
19686    if (LocalHead)
19687       fprintf (SUMA_STDERR, "%s: freeing SO->NodeMarker\n", FuncName);
19688    if (SO->NodeMarker) SUMA_Free_SphereMarker (SO->NodeMarker);
19689    if (LocalHead)
19690       fprintf (SUMA_STDERR, "%s: freeing SO->FaceSetMarker\n", FuncName);
19691    if (SO->FaceSetMarker) SUMA_Free_FaceSetMarker(SO->FaceSetMarker);
19692    if (LocalHead)
19693       fprintf (SUMA_STDERR, "%s: freeing SO->idcode_str\n", FuncName);
19694    if (SO->idcode_str) SUMA_free(SO->idcode_str);
19695    if (SO->facesetlist_idcode_str) SUMA_free(SO->facesetlist_idcode_str);
19696    if (SO->nodelist_idcode_str) SUMA_free(SO->nodelist_idcode_str);
19697    if (SO->facenormals_idcode_str) SUMA_free(SO->facenormals_idcode_str);
19698    if (SO->nodenormals_idcode_str) SUMA_free(SO->nodenormals_idcode_str);
19699    if (SO->polyarea_idcode_str) SUMA_free(SO->polyarea_idcode_str);
19700    if (LocalHead)
19701       fprintf (SUMA_STDERR, "%s: freeing SO->LocalDomainParentID\n", FuncName);
19702    if (SO->LocalDomainParentID) SUMA_free(SO->LocalDomainParentID);
19703    if (SO->LocalDomainParent) SUMA_free(SO->LocalDomainParent);
19704    if (SO->LocalCurvatureParentID) SUMA_free(SO->LocalCurvatureParentID);
19705    if (SO->LocalCurvatureParent) SUMA_free(SO->LocalCurvatureParent);
19706    if (SO->OriginatorID) SUMA_free(SO->OriginatorID);
19707    if (SO->DomainGrandParentID) SUMA_free(SO->DomainGrandParentID);
19708    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing SO->Group\n", FuncName);
19709    if (SO->Group) SUMA_free(SO->Group);
19710    if (SO->State) SUMA_free(SO->State);
19711    if (SO->PolyArea) SUMA_free(SO->PolyArea);
19712    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing SO->SC\n", FuncName);
19713    if (SO->SC) {
19714       SUMA_Free_SURFACE_CURVATURE(SO->SC);
19715    }
19716    if (SO->Group_idcode_str) SUMA_free(SO->Group_idcode_str);
19717    if (SO->OriginatorLabel) SUMA_free(SO->OriginatorLabel);
19718    if (SO->parent_vol_idcode_str) SUMA_free(SO->parent_vol_idcode_str);
19719 
19720 
19721    if (LocalHead)
19722       fprintf (SUMA_STDERR,
19723                "%s: freeing %d overlays\n", FuncName, SO->N_Overlays);
19724 
19725    /* freeing overlays */
19726    if (SO->N_Overlays) {
19727       /* freeing color overlays */
19728       for (i=0; i < SO->N_Overlays; ++i) {
19729          SUMA_FreeOverlayPointer (SO->Overlays[i]);
19730          SO->Overlays[i] = NULL;
19731       }
19732       SO->N_Overlays = 0;
19733    }
19734    /*Now free the vector of pointers */
19735    SUMA_free(SO->Overlays);
19736 
19737    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing FN\n", FuncName);
19738    /* freeing FN,  make sure that there are no links to FN*/
19739    if (SO->FN) {
19740       if (!SUMA_Free_FirstNeighb (SO->FN)) {
19741          fprintf(SUMA_STDERR,
19742                   "Error SUMA_Free_Surface_Object : Failed to free SO->FN");
19743       }
19744       SO->FN = NULL;
19745    }
19746 
19747    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing Label\n", FuncName);
19748    /* freeing Label */
19749    if (SO->Label) SUMA_free(SO->Label);
19750 
19751    /* freeing EL,  make sure that there are no links to EL*/
19752    if (SO->EL) {
19753       SUMA_free_Edge_List (SO->EL);
19754    }
19755    SO->EL = NULL;
19756 
19757    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing MF\n", FuncName);
19758    if (SO->MF){
19759       SUMA_Free_MemberFaceSets (SO->MF);
19760       SO->MF = NULL;
19761    }
19762    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing SurfCont\n", FuncName);
19763    if (SO->SurfCont) SUMA_FreeSurfContStruct(SO->SurfCont);
19764 
19765    if (SO->PermCol) SUMA_free(SO->PermCol);
19766 
19767    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing VolPar\n", FuncName);
19768    if (SO->VolPar) SUMA_Free_VolPar(SO->VolPar);
19769 
19770    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing aSO\n", FuncName);
19771    if (SO->aSO) SO->aSO = SUMA_FreeAfniSurfaceObject(SO->aSO);
19772 
19773 
19774    if (LocalHead)
19775       fprintf (SUMA_STDERR, "%s: freeing CommonNodeObject\n", FuncName);
19776    if (SO->CommonNodeObject)
19777       SUMA_Free_Displayable_Object_Vect(SO->CommonNodeObject,1);
19778       SO->CommonNodeObject = NULL;
19779    if (SO->NodeObjects)
19780       SUMA_Free_Displayable_Object_Vect (SO->NodeObjects, 1);
19781       SO->NodeObjects = NULL;
19782 
19783    if (SO->NodeNIDOObjects) {
19784       for (i=0; i<SO->N_Node; ++i) {
19785          if (SO->NodeNIDOObjects[i]) SUMA_free_NIDO(SO->NodeNIDOObjects[i]);
19786       }
19787       SUMA_free(SO->NodeNIDOObjects);
19788    }
19789 
19790    if (SO->NodeAreas) SUMA_free(SO->NodeAreas);
19791 
19792    SUMA_EmptyVisXform(&(SO->VisX0));
19793    SUMA_EmptyVisXform(&(SO->VisX));
19794 
19795    SUMA_FreeDrawMasks(SO->DW);
19796 
19797    if (SO) SUMA_free(SO);
19798 
19799    if (LocalHead) fprintf (stdout, "Done\n");
19800    SUMA_RETURN (YUP);
19801 }
19802 
SUMA_GeomTypeName(SUMA_GEOM_TYPE tp)19803 static char *SUMA_GeomTypeName(SUMA_GEOM_TYPE tp) {
19804    switch(tp) {
19805       case SUMA_GEOM_NOT_SET:
19806          return("Not Set");
19807       case SUMA_GEOM_SPHERE:
19808          return("Sphere");
19809       case SUMA_GEOM_ICOSAHEDRON:
19810          return("Icosahedron");
19811       case SUMA_GEOM_IRREGULAR:
19812          return("Irregular");
19813       case SUMA_N_GEOM:
19814          return("Number of geometries");
19815       default:
19816          return("Should not have this");
19817    }
19818    return("What the hell?");
19819 }
19820 
SUMA_SideName(SUMA_SO_SIDE ss)19821 char *SUMA_SideName(SUMA_SO_SIDE ss) {
19822    switch (ss) {
19823       case SUMA_SIDE_ERROR:
19824          return("side_error");
19825       case SUMA_NO_SIDE:
19826          return("no_side");
19827       case SUMA_LR:
19828          return("LR");
19829       case SUMA_LEFT:
19830          return("L");
19831       case SUMA_RIGHT:
19832          return("R");
19833       default:
19834          return("BadNewsCandidate");
19835    }
19836 }
19837 
SUMA_SideType(char * ss)19838 SUMA_SO_SIDE SUMA_SideType(char *ss) {
19839    if (!ss) return(SUMA_NO_SIDE);
19840    if (!strcmp(ss,"no_side")) return(SUMA_NO_SIDE);
19841    if (!strcmp(ss,"side_error")) return(SUMA_SIDE_ERROR);
19842    if (!strcmp(ss,"LR")) return(SUMA_LR);
19843    if (!strcmp(ss,"R")) return(SUMA_RIGHT);
19844    if (!strcmp(ss,"L")) return(SUMA_LEFT);
19845    return(SUMA_SIDE_ERROR);
19846 }
19847 
SUMA_VisX_XformType2Name(SUMA_VISX_XFORM_TYPE tt)19848 char *SUMA_VisX_XformType2Name(SUMA_VISX_XFORM_TYPE tt)
19849 {
19850    switch (tt) {
19851       case ID:
19852          return("Identity");
19853       case SHIFT:
19854          return("Translation");
19855       case AFFINE:
19856          return("Affine");
19857       case DISP:
19858          return("Displacement");
19859       default:
19860          return("Transform Type Unknown");
19861    }
19862    return("NichtGoot");
19863 }
19864 
SUMA_VisX_Info(SUMA_VIS_XFORM VisX,int N_Node,char * mumble)19865 char *SUMA_VisX_Info(SUMA_VIS_XFORM VisX, int N_Node, char *mumble)
19866 {
19867    static char FuncName[]={"SUMA_VisX_Info"};
19868    int nn=0;
19869    char *s = NULL;
19870    DListElmt *el = NULL;
19871    SUMA_VIS_XFORM_DATUM *xx=NULL;
19872    SUMA_STRING *SS = NULL;
19873 
19874    SUMA_ENTRY;
19875 
19876    if (!mumble) mumble = "";
19877 
19878    SS = SUMA_StringAppend (NULL, NULL);
19879    SS = SUMA_StringAppend_va(SS,
19880                         "%s%d xforms (%p), Applied %d, XformedCoords %p\n",
19881                         mumble,
19882                            VisX.Xchain?dlist_size(VisX.Xchain):0,
19883                            VisX.Xchain,
19884                            VisX.Applied, VisX.XformedCoords);
19885    if (VisX.Xchain && dlist_size(VisX.Xchain)) {
19886       do {
19887          if (!el) el = dlist_head(VisX.Xchain);
19888          else el = dlist_next(el);
19889          xx = (SUMA_VIS_XFORM_DATUM *)el->data;
19890          if (xx->XformType==AFFINE || xx->XformType==SHIFT) {
19891             SS = SUMA_StringAppend_va(SS,
19892                                     "   Xform #%d, %s, Type %s\n"
19893                                     "       Xform: %.3f %.3f %.3f %.3f \n"
19894                                     "              %.3f %.3f %.3f %.3f \n"
19895                                     "              %.3f %.3f %.3f %.3f \n"
19896                                     "              %.3f %.3f %.3f %.3f \n",
19897                         nn, xx->label, SUMA_VisX_XformType2Name(xx->XformType),
19898                         xx->Xform[0][0], xx->Xform[0][1],
19899                            xx->Xform[0][2], xx->Xform[0][3],
19900                         xx->Xform[1][0], xx->Xform[1][1],
19901                            xx->Xform[1][2], xx->Xform[1][3],
19902                         xx->Xform[2][0], xx->Xform[2][1],
19903                            xx->Xform[2][2], xx->Xform[2][3],
19904                         xx->Xform[3][0], xx->Xform[3][1],
19905                            xx->Xform[3][2], xx->Xform[3][3]);
19906          } else if (xx->XformType==DISP) {
19907             SS = SUMA_StringAppend_va(SS,
19908                                     "   Xform #%d, %s, Type %s\n"
19909                                     "       Disp: %.3f %.3f %.3f \n"
19910                                     "             ... \n"
19911                                     "             %.3f %.3f %.3f \n",
19912                         nn, xx->label, SUMA_VisX_XformType2Name(xx->XformType),
19913                         N_Node>3 ? xx->dxyz[0]:0.0,
19914                         N_Node>3 ? xx->dxyz[1]:0.0,
19915                         N_Node>3 ? xx->dxyz[2]:0.0,
19916                         N_Node>3 ? xx->dxyz[3*(N_Node-1)]:0.0,
19917                         N_Node>3 ? xx->dxyz[3*(N_Node-1)+1]:0.0,
19918                         N_Node>3 ? xx->dxyz[3*(N_Node-1)+2]:0.0
19919                         );
19920          } else if (xx->XformType==ID) {
19921             SS = SUMA_StringAppend_va(SS,
19922                                     "   Xform #%d, %s, Type %s\n"
19923                                     "   Identity\n",
19924                         nn, xx->label, SUMA_VisX_XformType2Name(xx->XformType));
19925          } else {
19926             SS = SUMA_StringAppend_va(SS,
19927                                     "   Xform #%d, %s, Type %s\n"
19928                                     "   Bad news\n",
19929                         nn, xx->label, SUMA_VisX_XformType2Name(xx->XformType));
19930          }
19931          ++nn;
19932       } while (el != dlist_tail(VisX.Xchain));
19933    }
19934    SUMA_SS2S(SS,s);
19935    SUMA_RETURN(s);
19936 }
19937 
SUMA_ADO_Info(SUMA_ALL_DO * ado,DList * DsetList,int detail)19938 char *SUMA_ADO_Info(SUMA_ALL_DO *ado, DList *DsetList, int detail)
19939 {
19940    static char FuncName[]={"SUMA_ADO_Info"};
19941    SUMA_STRING *SS = NULL;
19942    char *s = NULL;
19943 
19944    if (!ado) {
19945       SS = SUMA_StringAppend (NULL, NULL);
19946       SS = SUMA_StringAppend_va (SS, "NULL input to %s\n", FuncName);
19947       SS = SUMA_StringAppend (SS, NULL);
19948       s = SS->s; SUMA_free(SS);
19949       return(s);
19950    }
19951    switch(ado->do_type) {
19952       case SO_type:
19953          return(SUMA_SurfaceObject_Info((SUMA_SurfaceObject *)ado, DsetList));
19954       case ANY_DSET_type:
19955       case MD_DSET_type:
19956       case GDSET_type:
19957          return(SUMA_DsetInfo((SUMA_DSET *)ado, detail));
19958       case CDOM_type:
19959          SUMA_S_Err("Have not written SUMA_CIFTI_Info yet");
19960          s = SUMA_copy_string("Have not written SUMA_CIFTI_Info yet");
19961          return(s);
19962       case TRACT_type:
19963          return(SUMA_TractDOInfo((SUMA_TractDO *)ado, detail));
19964       case VO_type:
19965          return(SUMA_VolumeObjectInfo((SUMA_VolumeObject *)ado, detail));
19966       case MASK_type:
19967          return(SUMA_MaskDOInfo((SUMA_MaskDO *)ado, detail));
19968       default:
19969          SS = SUMA_StringAppend (NULL, NULL);
19970          SS = SUMA_StringAppend_va (SS, "Not ready to give info for %s\n",
19971                   SUMA_ObjectTypeCode2ObjectTypeName(ado->do_type));
19972          SS = SUMA_StringAppend (SS, NULL);
19973          s = SS->s; SUMA_free(SS);
19974          return(s);
19975    }
19976    return(SUMA_copy_string("WhatTheWhat???"));
19977 }
19978 
19979 /*!
19980    \brief Creates a string containing information about the surface
19981 
19982    \param SO (SUMA_SurfaceObject *) pointer to surface object structure
19983    \param   DsetList (DList *) List of data sets (used to output convexity info)
19984    \return s (char *) pointer to NULL terminated string containing surface info.
19985    It is your responsability to free it.
19986    \sa SUMA_Print_Surface_Object
19987 
19988 */
SUMA_SurfaceObject_Info(SUMA_SurfaceObject * SO,DList * DsetList)19989 char *SUMA_SurfaceObject_Info (SUMA_SurfaceObject *SO, DList *DsetList)
19990 {
19991    static char FuncName[]={"SUMA_SurfaceObject_Info"};
19992    int MaxShow = 5, i,j, ND = 0, NP = 0, N_max = 10000, eu=-1002;
19993    char stmp[1000], *s = NULL;
19994    SUMA_STRING *SS = NULL;
19995 
19996    SUMA_ENTRY;
19997 
19998    SS = SUMA_StringAppend (NULL, NULL);
19999 
20000    if (SO) {
20001       ND = SO->NodeDim;
20002       NP = SO->FaceSetDim;
20003 
20004       /* SO->Label */
20005       if (SO->Label == NULL)
20006          SS = SUMA_StringAppend (SS,"Label: NULL.\n");
20007       else   {
20008          SS = SUMA_StringAppend_va (SS, "Label: %s\n", SO->Label);
20009       }
20010 
20011       /* SO->AnatCorrect */
20012       if (SO->AnatCorrect)
20013          SS = SUMA_StringAppend (SS,"Anatomically correct = YES\n");
20014       else SS = SUMA_StringAppend (SS,"Anatomically correct = NO\n");
20015 
20016       switch (SO->Side) {
20017          case SUMA_SIDE_ERROR:
20018             SS = SUMA_StringAppend (SS,"Error in side specification\n");
20019             break;
20020          case SUMA_NO_SIDE:
20021             SS = SUMA_StringAppend (SS,"No side specified.\n");
20022             break;
20023          case SUMA_LR:
20024             SS = SUMA_StringAppend (SS,"Left and Right hemispheres.\n");
20025             break;
20026          case SUMA_LEFT:
20027             SS = SUMA_StringAppend (SS,"Left hemisphere.\n");
20028             break;
20029          case SUMA_RIGHT:
20030             SS = SUMA_StringAppend (SS,"Right hemisphere.\n");
20031             break;
20032          default:
20033             SS = SUMA_StringAppend (SS,"Chimchunga.\n");
20034             break;
20035       }
20036 
20037       switch (SO->FileType) {
20038          case SUMA_SUREFIT:
20039             SS = SUMA_StringAppend_va (SS, "SureFit surface.\n");
20040             SS = SUMA_StringAppend_va (SS,"Coord FileName: %s \n",
20041                                           SO->Name_coord.FileName);
20042             SS = SUMA_StringAppend_va (SS,"Coord Path: %s \n",
20043                                           SO->Name_coord.Path);
20044             SS = SUMA_StringAppend_va (SS,"Topo FileName: %s \n",
20045                                           SO->Name_topo.FileName);
20046             SS = SUMA_StringAppend_va (SS,"Topo Path: %s \n",
20047                                           SO->Name_topo.Path);
20048             break;
20049          case SUMA_VEC:
20050             SS = SUMA_StringAppend_va (SS,"VEC surface.\n");
20051             SS = SUMA_StringAppend_va (SS,"NodeList FileName: %s \n",
20052                                           SO->Name_coord.FileName);
20053             SS = SUMA_StringAppend_va (SS,"NodeList Path: %s \n",
20054                                           SO->Name_coord.Path);
20055             SS = SUMA_StringAppend_va (SS,"FaceSetList FileName: %s \n",
20056                                           SO->Name_topo.FileName);
20057             SS = SUMA_StringAppend_va (SS,"FaceSetList Path: %s \n",
20058                                           SO->Name_topo.Path);
20059             break;
20060          case SUMA_FREE_SURFER:
20061          case SUMA_FREE_SURFER_PATCH:
20062             SS = SUMA_StringAppend_va (SS,"FreeSurfer surface.\n");
20063             SS = SUMA_StringAppend_va (SS,"FileName: %s\n", SO->Name.FileName);
20064             SS = SUMA_StringAppend_va (SS,"Path: %s\n", SO->Name.Path);
20065             break;
20066          case SUMA_INVENTOR_GENERIC:
20067             SS = SUMA_StringAppend_va (SS,"Inventor generic surface.\n");
20068             SS = SUMA_StringAppend_va (SS,"FileName: %s\n", SO->Name.FileName);
20069             SS = SUMA_StringAppend_va (SS,"Path: %s\n", SO->Name.Path);
20070             break;
20071          case SUMA_PLY:
20072             SS = SUMA_StringAppend_va (SS,"PLY surface.\n");
20073             SS = SUMA_StringAppend_va (SS,"FileName: %s\n", SO->Name.FileName);
20074             SS = SUMA_StringAppend_va (SS,"Path: %s\n", SO->Name.Path);
20075             break;
20076          case SUMA_STL:
20077             SS = SUMA_StringAppend_va (SS,"STL surface.\n");
20078             SS = SUMA_StringAppend_va (SS,"FileName: %s\n", SO->Name.FileName);
20079             SS = SUMA_StringAppend_va (SS,"Path: %s\n", SO->Name.Path);
20080             break;
20081          case SUMA_MNI_OBJ:
20082             SS = SUMA_StringAppend_va (SS,"MNI OBJ surface.\n");
20083             SS = SUMA_StringAppend_va (SS,"FileName: %s\n", SO->Name.FileName);
20084             SS = SUMA_StringAppend_va (SS,"Path: %s\n", SO->Name.Path);
20085             break;
20086          case SUMA_OPENDX_MESH:
20087             SS = SUMA_StringAppend_va (SS,"OpenDX surface.\n");
20088             SS = SUMA_StringAppend_va (SS,"FileName: %s\n", SO->Name.FileName);
20089             SS = SUMA_StringAppend_va (SS,"Path: %s\n", SO->Name.Path);
20090             break;
20091          case SUMA_OBJ_MESH:
20092             SS = SUMA_StringAppend_va (SS,"OBJ surface.\n");
20093             SS = SUMA_StringAppend_va (SS,"FileName: %s\n", SO->Name.FileName);
20094             SS = SUMA_StringAppend_va (SS,"Path: %s\n", SO->Name.Path);
20095             break;
20096          case SUMA_BRAIN_VOYAGER:
20097             SS = SUMA_StringAppend_va (SS,"Brain Voyager surface.\n");
20098             SS = SUMA_StringAppend_va (SS,"FileName: %s\n", SO->Name.FileName);
20099             SS = SUMA_StringAppend_va (SS,"Path: %s\n", SO->Name.Path);
20100             break;
20101          case SUMA_BYU:
20102             SS = SUMA_StringAppend_va (SS,"BYU surface.\n");
20103             SS = SUMA_StringAppend_va (SS,"FileName: %s\n", SO->Name.FileName);
20104             SS = SUMA_StringAppend_va (SS,"Path: %s\n", SO->Name.Path);
20105             break;
20106          case SUMA_GIFTI:
20107             SS = SUMA_StringAppend_va (SS,"GIFTI surface.\n");
20108             SS = SUMA_StringAppend_va (SS,"FileName: %s\n", SO->Name.FileName);
20109             SS = SUMA_StringAppend_va (SS,"Path: %s\n", SO->Name.Path);
20110             break;
20111          case SUMA_PREDEFINED:
20112             SS = SUMA_StringAppend_va (SS,"Predefined surface.\n");
20113             SS = SUMA_StringAppend_va (SS,"FileName: %s\n", SO->Name.FileName);
20114             SS = SUMA_StringAppend_va (SS,"Path: %s\n", SO->Name.Path);
20115             break;
20116          case SUMA_FT_NOT_SPECIFIED:
20117             SS = SUMA_StringAppend_va (SS,"File Type not specified.\n");
20118             break;
20119          default:
20120             SS = SUMA_StringAppend_va (SS,"Unknown surface type.\n");
20121             break;
20122       }
20123 
20124       SS = SUMA_StringAppend_va (SS,"SpecFile:");
20125       if (SO->SpecFile.Path) SS = SUMA_StringAppend_va (SS,"%s",
20126                                           SO->SpecFile.Path);
20127       if (SO->SpecFile.FileName) SS = SUMA_StringAppend_va (SS,"%s",
20128                                           SO->SpecFile.FileName);
20129       SS = SUMA_StringAppend_va (SS,"\n");
20130 
20131       SS = SUMA_StringAppend_va (SS,"FileType: %d\t FileFormat: %d\n",
20132                                           SO->FileType, SO->FileFormat);
20133 
20134       if (!SO->idcode_str) SS = SUMA_StringAppend_va (SS,"IDcode is NULL\n");
20135       else SS = SUMA_StringAppend_va (SS,"IDcode: %s\n", SO->idcode_str);
20136       if (!SO->parent_vol_idcode_str) SS = SUMA_StringAppend_va
20137                                           (SS,"parent_vol_IDcode is NULL\n");
20138       else SS = SUMA_StringAppend_va (SS,"parent_vol_IDcode: %s\n",
20139                                           SO->parent_vol_idcode_str);
20140       if (!SO->facesetlist_idcode_str) SS = SUMA_StringAppend_va
20141                                           (SS,"faceset_IDcode is NULL\n");
20142       else SS = SUMA_StringAppend_va (SS,"faceset_IDcode: %s\n",
20143                                           SO->facesetlist_idcode_str);
20144       if (!SO->nodelist_idcode_str) SS = SUMA_StringAppend_va
20145                                           (SS,"nodelist_IDcode is NULL\n");
20146       else SS = SUMA_StringAppend_va (SS,"nodelist_IDcode: %s\n",
20147                                           SO->nodelist_idcode_str);
20148       if (!SO->facenormals_idcode_str) SS = SUMA_StringAppend_va
20149                                           (SS,"facenormals_IDcode is NULL\n");
20150       else SS = SUMA_StringAppend_va (SS,"facenormals_IDcode: %s\n",
20151                                           SO->facenormals_idcode_str);
20152       if (!SO->nodenormals_idcode_str) SS = SUMA_StringAppend_va
20153                                           (SS,"nodenormals_IDcode is NULL\n");
20154       else SS = SUMA_StringAppend_va (SS,"nodenormals_IDcode: %s\n",
20155                                           SO->nodenormals_idcode_str);
20156       if (!SO->polyarea_idcode_str) SS = SUMA_StringAppend_va
20157                                           (SS,"polyarea_IDcode is NULL\n");
20158       else SS = SUMA_StringAppend_va (SS,"polyarea_IDcode: %s\n",
20159                                           SO->polyarea_idcode_str);
20160 
20161       if (!SO->LocalDomainParent) SS = SUMA_StringAppend_va
20162                                           (SS,"LocalDomainParent is NULL\n");
20163       else SS = SUMA_StringAppend_va (SS,"LocalDomainParent: %s\n",
20164                                           SO->LocalDomainParent);
20165 
20166       if (!SO->LocalDomainParentID) SS = SUMA_StringAppend_va
20167                                           (SS,"LocalDomainParentID is NULL\n");
20168       else SS = SUMA_StringAppend_va (SS,"LocalDomainParentID: %s\n",
20169                                           SO->LocalDomainParentID);
20170 
20171       if (!SO->LocalCurvatureParent) SS = SUMA_StringAppend_va
20172                                           (SS,"LocalCurvatureParent is NULL\n");
20173       else SS = SUMA_StringAppend_va (SS,"LocalCurvatureParent: %s\n",
20174                                           SO->LocalCurvatureParent);
20175 
20176       if (!SO->LocalCurvatureParentID)
20177          SS = SUMA_StringAppend_va (SS,"LocalCurvatureParentID is NULL\n");
20178       else SS = SUMA_StringAppend_va (SS,"LocalCurvatureParentID: %s\n",
20179                                           SO->LocalCurvatureParentID);
20180 
20181       if (!SO->OriginatorID)
20182          SS = SUMA_StringAppend_va (SS,"OriginatorID is NULL\n");
20183       else SS = SUMA_StringAppend_va (SS,"OriginatorID: %s\n",
20184                                           SO->OriginatorID);
20185 
20186       if (!SO->OriginatorLabel)
20187          SS = SUMA_StringAppend_va (SS,"OriginatorLabel is NULL\n");
20188       else SS = SUMA_StringAppend_va (SS,"OriginatorLabel: %s\n",
20189                                           SO->OriginatorLabel);
20190 
20191       if (!SO->DomainGrandParentID) SS = SUMA_StringAppend_va
20192                                           (SS,"DomainGrandParentID is NULL\n");
20193       else SS = SUMA_StringAppend_va (SS,"DomainGrandParentID: %s\n",
20194                                           SO->DomainGrandParentID);
20195 
20196       SS = SUMA_StringAppend_va (SS,
20197                                  "GroupLabel: %s\tGroupID: %s\t"
20198                                  "State: %s\t",
20199                                  SO->Group, SO->Group_idcode_str,
20200                                  SO->State);
20201 
20202       if (SUMA_ismappable(SO)) {
20203          if (SUMA_isLocalDomainParent(SO)) {
20204             sprintf (stmp,"Surface is a Local Domain Parent.\n");
20205             SS = SUMA_StringAppend (SS,stmp);
20206          } else {
20207             sprintf (stmp,"Surface is Mappable.\n");
20208            SS = SUMA_StringAppend (SS,stmp);
20209          }
20210       } else {
20211          sprintf (stmp,"Surface is NOT Mappable.\n");
20212          SS = SUMA_StringAppend (SS,stmp);
20213       }
20214 
20215 
20216       if (SO->Name_NodeParent == NULL) {
20217          sprintf (stmp,"Name_NodeParent is NULL\n");
20218          SS = SUMA_StringAppend (SS,stmp);
20219       } else   {
20220          sprintf (stmp,"Name_NodeParent: %s\n", SO->Name_NodeParent);
20221          SS = SUMA_StringAppend (SS,stmp);
20222       }
20223 
20224       if (SO->MeshAxis) {
20225          sprintf (stmp,"ShowMeshAxis: %d\t MeshAxis Defined\n",
20226                                           SO->ShowMeshAxis);
20227          SS = SUMA_StringAppend (SS,stmp);
20228       }   else {
20229          sprintf (stmp,"ShowMeshAxis: %d\t MeshAxis Undefined\n",
20230                                           SO->ShowMeshAxis);
20231          SS = SUMA_StringAppend (SS,stmp);
20232       }
20233 
20234       sprintf (stmp,"RenderMode: %d (pointsize %f)\n",
20235                SO->PolyMode, SO->PointSize);
20236       SS = SUMA_StringAppend (SS,stmp);
20237 
20238       sprintf (stmp,"TransMode: %d\n", SO->TransMode);
20239       SS = SUMA_StringAppend (SS,stmp);
20240 
20241       sprintf (stmp,"N_Node: %d\t NodeDim: %d, EmbedDim: %d\n", \
20242          SO->N_Node, SO->NodeDim, SO->EmbedDim);
20243       SS = SUMA_StringAppend (SS,stmp);
20244       sprintf (stmp,"RotationWeight: %d, ViewCenterWeight %d\n",
20245                      SO->RotationWeight, SO->ViewCenterWeight);
20246       SS = SUMA_StringAppend (SS,stmp);
20247       s = SUMA_VisX_Info(SO->VisX0, SO->N_Node, "VisX0: ");
20248       SS = SUMA_StringAppend_va(SS, s);
20249       SUMA_free(s); s = NULL;
20250       s = SUMA_VisX_Info(SO->VisX, SO->N_Node, "VisX: ");
20251       SS = SUMA_StringAppend_va(SS, s);
20252       SUMA_free(s); s = NULL;
20253 
20254       sprintf (stmp,"N_FaceSet: %d, FaceSetDim %d\n", SO->N_FaceSet,
20255                      SO->FaceSetDim);
20256       SS = SUMA_StringAppend (SS,stmp);
20257 
20258       SUMA_EULER_SO(SO, eu);
20259       SS = SUMA_StringAppend_va (SS, "Euler Characteristic = %d\n\n", eu);
20260 
20261       sprintf (stmp,"Center of Mass: [%.3f\t%.3f\t%.3f]\n",
20262                      SO->Center[0], SO->Center[1],SO->Center[2]);
20263       SS = SUMA_StringAppend (SS,stmp);
20264       if (  SO->isSphere == SUMA_GEOM_SPHERE ||
20265             SO->isSphere == SUMA_GEOM_ICOSAHEDRON ) {
20266          sprintf (stmp, "Surface is considered a %s.\n"
20267                         "Sphere Center: [%.3f\t%.3f\t%.3f]\n",
20268                         SUMA_GeomTypeName(SO->isSphere),
20269                         SO->SphereCenter[0],
20270                         SO->SphereCenter[1],SO->SphereCenter[2]);
20271          SS = SUMA_StringAppend (SS,stmp);
20272          sprintf (stmp,"Sphere Radius: [%.3f]\n", SO->SphereRadius);
20273          SS = SUMA_StringAppend (SS,stmp);
20274       } else if (SO->isSphere > SUMA_GEOM_NOT_SET) {
20275          sprintf (stmp, "Surface geometry is considered irregular.\n"
20276                         "Sphere Center Set To: [%.3f\t%.3f\t%.3f]\n",
20277                         SO->SphereCenter[0], SO->SphereCenter[1],
20278                         SO->SphereCenter[2]);
20279          SS = SUMA_StringAppend (SS,stmp);
20280          sprintf (stmp,"Sphere Radius Set To: [%.3f]\n", SO->SphereRadius);
20281          SS = SUMA_StringAppend (SS,stmp);
20282       }  else {
20283          sprintf (stmp, "Surface geometry has not been checked for type.\n"
20284                         "Sphere Center Set To: [%.3f\t%.3f\t%.3f]\n",
20285                         SO->SphereCenter[0], SO->SphereCenter[1],
20286                         SO->SphereCenter[2]);
20287          SS = SUMA_StringAppend (SS,stmp);
20288          sprintf (stmp,"Sphere Radius Set To: [%.3f]\n", SO->SphereRadius);
20289          SS = SUMA_StringAppend (SS,stmp);
20290       }
20291       sprintf (stmp,"MaxDist From Center: %.3f at node %d\n",
20292                      SO->MaxCentDist, SO->MaxCentDistNode);
20293       SS = SUMA_StringAppend (SS,stmp);
20294       sprintf (stmp,"MinDist From Center: %.3f at node %d\n",
20295                      SO->MinCentDist, SO->MinCentDistNode);
20296       SS = SUMA_StringAppend (SS,stmp);
20297 
20298       sprintf (stmp,"Maximum: [%.3f\t%.3f\t%.3f]\t (aMax %.3f)\n",
20299                      SO->MaxDims[0], SO->MaxDims[1],SO->MaxDims[2],
20300                      SO->aMaxDims);
20301       SS = SUMA_StringAppend (SS,stmp);
20302 
20303       sprintf (stmp,"Minimum: [%.3f\t%.3f\t%.3f]\t (aMin %.3f)\n\n",
20304                      SO->MinDims[0], SO->MinDims[1],SO->MinDims[2],
20305                      SO->aMinDims);
20306       SS = SUMA_StringAppend (SS,stmp);
20307       sprintf (stmp,"SUMA_VolPar_Aligned: %d\n", SO->SUMA_VolPar_Aligned);
20308       SS = SUMA_StringAppend (SS,stmp);
20309       sprintf (stmp,"APPLIED_A2Exp_XFORM: %s\n",
20310                SUMA_WarpTypeName(SO->APPLIED_A2Exp_XFORM));
20311       sprintf (stmp,"SelectedNode %d\n", SO->SelectedNode);
20312       SS = SUMA_StringAppend (SS,stmp);
20313 
20314       sprintf (stmp,"SelectedFaceSet %d\n\n", SO->SelectedFaceSet);
20315       SS = SUMA_StringAppend (SS,stmp);
20316 
20317       SS = SUMA_StringAppend (SS, SUMA_VolPar_Info(SO->VolPar));
20318 
20319       if (SO->NodeList == NULL) {
20320          sprintf (stmp,"NodeList is NULL\n\n");
20321          SS = SUMA_StringAppend (SS,stmp);
20322       } else {
20323          if (MaxShow > SO->N_Node) MaxShow = SO->N_Node;
20324          sprintf (stmp,
20325                   "NodeList (showing %d out of %d elements):\n",
20326                   MaxShow, SO->N_Node);
20327          SS = SUMA_StringAppend (SS,stmp);
20328          for (i=0; i < MaxShow; ++i)   {
20329             for (j=0; j < SO->NodeDim; ++j) {
20330                sprintf (stmp, "\t%.3f", SO->NodeList[ND * i + j]);
20331                SS = SUMA_StringAppend (SS,stmp);
20332             }
20333             sprintf (stmp, "\n\n");
20334             SS = SUMA_StringAppend (SS,stmp);
20335          }
20336       }
20337 
20338       SS = SUMA_StringAppend_va (SS,
20339                      "Node Normal Direction (1=out, -1=in, 0=dunno) = %d\n",
20340                      SO->normdir);
20341       if (SO->NodeNormList == NULL) {
20342          sprintf (stmp,"NodeNormList is NULL\n\n");
20343          SS = SUMA_StringAppend (SS,stmp);
20344       } else {
20345          if (MaxShow > SO->N_Node) MaxShow = SO->N_Node;
20346          sprintf (stmp, "NodeNormList (showing %d out of %d elements):\n",
20347                         MaxShow, SO->N_Node);
20348          SS = SUMA_StringAppend (SS,stmp);
20349          for (i=0; i < MaxShow; ++i)   {
20350             for (j=0; j < 3; ++j) {
20351                sprintf (stmp, "\t%.3f", SO->NodeNormList[ND * i + j]);
20352                SS = SUMA_StringAppend (SS,stmp);
20353             }
20354             sprintf (stmp, "\n");
20355             SS = SUMA_StringAppend (SS,stmp);
20356          }
20357          sprintf (stmp, "\n");
20358          SS = SUMA_StringAppend (SS,stmp);
20359       }
20360 
20361       if (SO->NodeAreas == NULL) {
20362          sprintf (stmp,"NodeAreas is NULL\n\n");
20363          SS = SUMA_StringAppend (SS,stmp);
20364       } else {
20365          if (MaxShow > SO->N_Node) MaxShow = SO->N_Node;
20366          sprintf (stmp, "NodeAreas (showing %d out of %d elements):\n",
20367                         MaxShow, SO->N_Node);
20368          SS = SUMA_StringAppend (SS,stmp);
20369          for (i=0; i < MaxShow; ++i)   {
20370                sprintf (stmp, "\t%.3f\n", SO->NodeAreas[i]);
20371                SS = SUMA_StringAppend (SS,stmp);
20372          }
20373          sprintf (stmp, "\n");
20374          SS = SUMA_StringAppend (SS,stmp);
20375       }
20376 
20377       if (SO->FaceSetList == NULL) {
20378          sprintf (stmp,"FaceSetList is NULL\n\n");
20379          SS = SUMA_StringAppend (SS,stmp);
20380       } else {
20381          if (MaxShow > SO->N_FaceSet) MaxShow = SO->N_FaceSet;
20382          sprintf (stmp, "FaceSetList: (showing %d out of %d elements):\n",
20383                         MaxShow, SO->N_FaceSet);
20384          SS = SUMA_StringAppend (SS,stmp);
20385          for (i=0; i < MaxShow; ++i)   {
20386             for (j=0; j < SO->FaceSetDim; ++j) {
20387                sprintf (stmp, "\t%d", SO->FaceSetList[NP * i + j]);
20388                SS = SUMA_StringAppend (SS,stmp);
20389             }
20390             sprintf (stmp, "\n");
20391             SS = SUMA_StringAppend (SS,stmp);
20392          }
20393          sprintf (stmp, "\n");
20394          SS = SUMA_StringAppend (SS,stmp);
20395       }
20396 
20397       if (SO->FaceNormList == NULL) {
20398          sprintf (stmp,"FaceNormList is NULL\n\n");
20399          SS = SUMA_StringAppend (SS,stmp);
20400       } else {
20401          if (MaxShow > SO->N_FaceSet) MaxShow = SO->N_FaceSet;
20402          sprintf (stmp, "FaceNormList (showing %d out of %d elements):\n",
20403                         MaxShow, SO->N_FaceSet);
20404          SS = SUMA_StringAppend (SS,stmp);
20405          for (i=0; i < MaxShow; ++i)   {
20406             for (j=0; j < 3; ++j) {
20407                sprintf (stmp, "\t%.3f", SO->FaceNormList[NP * i + j]);
20408                SS = SUMA_StringAppend (SS,stmp);
20409             }
20410             sprintf (stmp, "\n");
20411             SS = SUMA_StringAppend (SS,stmp);
20412          }
20413          sprintf (stmp, "\n");
20414          SS = SUMA_StringAppend (SS,stmp);
20415       }
20416 
20417 
20418       if (SO->MF == NULL) {
20419          sprintf (stmp,"SO->MF = NULL\n\n") ;
20420          SS = SUMA_StringAppend (SS,stmp);
20421       } else {
20422          if (MaxShow > SO->N_Node) MaxShow = SO->N_Node;
20423          sprintf (stmp, "SO->MF (showing %d out of %d elements):\n",
20424                         MaxShow, SO->N_Node);
20425          SS = SUMA_StringAppend (SS,stmp);
20426          for (i=0; i < MaxShow ; ++i)   {
20427             sprintf (stmp,"\tNode %d: Member of %d FaceSets: ",
20428                            i, SO->MF->N_Memb[i]);
20429             SS = SUMA_StringAppend (SS,stmp);
20430             for (j=0; j < SO->MF->N_Memb[i]; ++j) {
20431                sprintf (stmp,"%d, ", SO->MF->NodeMemberOfFaceSet[i][j]);
20432                SS = SUMA_StringAppend (SS,stmp);
20433             }
20434             sprintf (stmp,"\n");
20435             SS = SUMA_StringAppend (SS,stmp);
20436          }
20437          sprintf (stmp, "\n");
20438          SS = SUMA_StringAppend (SS,stmp);
20439       }
20440 
20441       if (SO->FN == NULL) {
20442          sprintf (stmp,"SO->FN = NULL\n\n") ;
20443          SS = SUMA_StringAppend (SS,stmp);
20444       } else {
20445          if (MaxShow > SO->N_Node) MaxShow = SO->N_Node;
20446          sprintf (stmp,
20447                   "SO->FN, Max. Neighbs of %d "
20448                   "(showing %d out of %d elements):\n",
20449                   SO->FN->N_Neighb_max, MaxShow, SO->N_Node);
20450          SS = SUMA_StringAppend (SS,stmp);
20451          for (i=0; i < MaxShow ; ++i)   {
20452             sprintf (stmp,"\tNode %d: %d Neighbors:\t", i, SO->FN->N_Neighb[i]);
20453             SS = SUMA_StringAppend (SS,stmp);
20454              for (j=0; j< SO->FN->N_Neighb[i]; ++j) {
20455                sprintf (stmp,"%d, ", SO->FN->FirstNeighb[i][j]);
20456                SS = SUMA_StringAppend (SS,stmp);
20457             }
20458             sprintf (stmp,"\n");
20459             SS = SUMA_StringAppend (SS,stmp);
20460          }
20461          sprintf (stmp, "\n");
20462          SS = SUMA_StringAppend (SS,stmp);
20463       }
20464 
20465       if (SO->EL == NULL) {
20466          sprintf (stmp,"SO->EL = NULL\n\n") ;
20467          SS = SUMA_StringAppend (SS,stmp);
20468       } else {
20469          if (MaxShow > SO->EL->N_EL) MaxShow = SO->EL->N_EL;
20470          sprintf (stmp, "SO->EL, %d edges, %d unique edges.\n"
20471                         "Sloppy avg seg. length: %f\n"
20472                         "max_Hosts %d, min_Hosts %d "
20473                         "(showing %d out of %d elements):\n",
20474                SO->EL->N_EL, SO->EL->N_Distinct_Edges,
20475                SO->EL->AvgLe,
20476                SO->EL->max_N_Hosts, SO->EL->min_N_Hosts, MaxShow, SO->EL->N_EL);
20477          SS = SUMA_StringAppend (SS,stmp);
20478          for (i=0; i < MaxShow ; ++i)   {
20479             sprintf (stmp,"\tEdge %d: %d %d\tFlip %d Tri %d N_tri %d\n",
20480                 i, SO->EL->EL[i][0], SO->EL->EL[i][1], SO->EL->ELps[i][0],
20481                 SO->EL->ELps[i][1],SO->EL->ELps[i][2]);
20482             SS = SUMA_StringAppend (SS,stmp);
20483          }
20484          sprintf (stmp,"\n");
20485          SS = SUMA_StringAppend (SS,stmp);
20486 
20487          if (MaxShow > SO->N_FaceSet) MaxShow = SO->N_FaceSet;
20488          sprintf (stmp,
20489                   "Triangle Limbs, (showing %d out of %d elements):\n",
20490                   MaxShow, SO->N_FaceSet);
20491          SS = SUMA_StringAppend (SS,stmp);
20492          for (i=0; i < MaxShow ; ++i)   {
20493             sprintf (stmp,"\tTri_limb[%d][:] = %d %d %d\n",
20494                            i, SO->EL->Tri_limb[i][0],
20495                            SO->EL->Tri_limb[i][1],SO->EL->Tri_limb[i][2]);
20496             SS = SUMA_StringAppend (SS,stmp);
20497          }
20498          sprintf (stmp, "\n");
20499          SS = SUMA_StringAppend (SS,stmp);
20500       }
20501 
20502       if (SO->PolyArea == NULL) {
20503          sprintf (stmp,"SO->PolyArea = NULL\n\n") ;
20504          SS = SUMA_StringAppend (SS,stmp);
20505       } else {
20506          if (MaxShow > SO->N_FaceSet) MaxShow = SO->N_FaceSet;
20507          sprintf (stmp,
20508                   "SO->PolyArea, showing %d out of %d elements:\n",
20509                   MaxShow, SO->N_FaceSet);
20510          SS = SUMA_StringAppend (SS,stmp);
20511          for (i=0; i < MaxShow ; ++i)   {
20512             sprintf (stmp,"\tFaceSet %d: Area = %f\n", i, SO->PolyArea[i]);
20513             SS = SUMA_StringAppend (SS,stmp);
20514          }
20515       }
20516       sprintf (stmp,"\n");
20517       SS = SUMA_StringAppend (SS,stmp);
20518 
20519       if (DsetList) {
20520          float *Cx = NULL;
20521          Cx = (float *)SUMA_GetCx(SO->idcode_str, DsetList, 0);
20522          if (Cx == NULL) {
20523             sprintf (stmp,"Cx = NULL\n\n") ;
20524             SS = SUMA_StringAppend (SS,stmp);
20525          } else {
20526             if (MaxShow > SO->N_Node) MaxShow = SO->N_Node;
20527             sprintf (stmp, "Cx, showing %d out of %d elements:\n",
20528                            MaxShow, SO->N_Node);
20529             SS = SUMA_StringAppend (SS,stmp);
20530             for (i=0; i < MaxShow ; ++i)   {
20531                sprintf (stmp,"\t Cx[%d] = %f\n", i, Cx[i]);
20532                SS = SUMA_StringAppend (SS,stmp);
20533             }
20534          }
20535       } else {
20536          SS = SUMA_StringAppend (SS, "NULL DsetList, No Cx can be found.\n");
20537       }
20538 
20539       if (SO->N_Overlays) {
20540          sprintf (stmp,"%d Overlay planes.\n", SO->N_Overlays);
20541          SS = SUMA_StringAppend (SS,stmp);
20542          s = SUMA_ColorOverlayPlane_Info(SO->Overlays, SO->N_Overlays, 0);
20543          if (s) {
20544             SS = SUMA_StringAppend (SS,s);
20545             SUMA_free(s);
20546             s = NULL;
20547          }
20548 
20549       }else {
20550          sprintf (stmp,"No overlay planes.\n");
20551          SS = SUMA_StringAppend (SS,stmp);
20552       }
20553       sprintf (stmp,"\n");
20554       SS = SUMA_StringAppend (SS,stmp);
20555 
20556       if (!SO->PermCol) SUMA_StringAppend (SS,"PermCol = NULL\n");
20557       else SUMA_StringAppend (SS,"PermCol is NOT NULL\n");
20558 
20559       if (  (SO->PermCol && SO->N_Overlays) ||
20560             (SO->PermCol && SO->N_Overlays) ) {
20561          SUMA_StringAppend (SS,  "CONFLICT! "
20562                                  "Both PermCol and Overlays are specified!\n");
20563       }
20564 
20565       s = SUMA_AfniSurfaceObject_Info(SO->aSO, 0, NULL);
20566 
20567       SUMA_StringAppend (SS, s);
20568       SUMA_free(s); s = NULL;
20569 
20570    } else {
20571       sprintf (stmp, "NULL Surface Object Pointer.");
20572       SS = SUMA_StringAppend (SS, stmp);
20573    }
20574 
20575    if (SO->CommonNodeObject) {
20576       s = SUMA_DOv_Info(SO->CommonNodeObject, 1, 1);
20577       SUMA_StringAppend (SS, s);
20578       SUMA_free(s); s = NULL;
20579    } else {
20580       SS = SUMA_StringAppend (SS, "CommonNodeObject is NULL\n");
20581    }
20582 
20583    if (SO->NodeObjects) {
20584       s = SUMA_DOv_Info(SO->NodeObjects, 1, 1);
20585       SUMA_StringAppend (SS, s);
20586       SUMA_free(s); s = NULL;
20587    } else {
20588       SS = SUMA_StringAppend (SS, "NodeObjects is NULL\n");
20589    }
20590 
20591    if (SO->NodeNIDOObjects) {
20592       SS = SUMA_StringAppend (SS, "NodeNIDOObjects is NOT NULL\n");
20593    } else {
20594       SS = SUMA_StringAppend (SS, "NodeNIDOObjects is NULL\n");
20595    }
20596 
20597    if (SO->DW) {
20598       if (SO->DW->DrwPtchs) {
20599          SS = SUMA_StringAppend_va (SS, "Have %d draw patches\n",
20600                                     dlist_size(SO->DW->DrwPtchs));
20601       } else {
20602          SS = SUMA_StringAppend (SS, "NULL draw patches\n");
20603       }
20604       if (SO->DW->nodemask) {
20605          SS = SUMA_StringAppend_va (SS,
20606                            "Have nodemask pointer %p, %d non-zero nodes\n",
20607                            SO->DW->nodemask, SO->DW->N_nz_nodemask);
20608       } else {
20609          SS = SUMA_StringAppend (SS, "NULL nodemask\n");
20610       }
20611       SS = SUMA_StringAppend_va (SS,"      user_exp: %s\n"
20612                                     "     cmask_exp: %s\n"
20613                                     "last_cmask_exp: %s\n",
20614                            CHECK_NULL_STR(SO->DW->user_exp),
20615                            CHECK_NULL_STR(SO->DW->cmask_exp),
20616                            CHECK_NULL_STR(SO->DW->last_cmask_exp));
20617    } else {
20618       SS = SUMA_StringAppend (SS, "NULL DW\n");
20619    }
20620 
20621    /* clean SS */
20622    SS = SUMA_StringAppend (SS, NULL);
20623    /* copy s pointer and free SS */
20624    s = SS->s;
20625    SUMA_free(SS);
20626 
20627    SUMA_RETURN (s);
20628 }
20629 
20630 /*!**
20631 File : SUMA_Load_Surface_Object.c
20632 \author Ziad Saad
20633 Date : Fri Jan 25  2002
20634 
20635 Purpose :
20636    Print the contents of a Surface Object
20637 
20638 
20639 Usage :
20640     SUMA_Print_Surface_Object ( SO, Out)
20641 
20642 
20643 Input paramters :
20644 \param   SO (SUMA_SurfaceObject *) Surface Object pointer
20645 \param   Out (FILE *) stream pointer. (can use stdout or stderr)
20646          If you pass a file pointer, make sure it is open before
20647          making the function call. Also, make sure you close it
20648          afterwards. You can pass a NULL pointer and the output
20649          will default to stdout.
20650 \sa SUMA_Load_Surface_Object
20651 \sa SUMA_SurfaceObject_Info
20652 ***/
20653 
SUMA_Print_Surface_Object(SUMA_SurfaceObject * SO,FILE * Out)20654 void SUMA_Print_Surface_Object (SUMA_SurfaceObject *SO, FILE *Out)
20655 {
20656    static char FuncName[]={"SUMA_Print_Surface_Object"};
20657    char *s;
20658 
20659    SUMA_ENTRY;
20660 
20661    if (Out == NULL) Out = stdout;
20662 
20663    if (SUMAg_CF)
20664       s = SUMA_SurfaceObject_Info (SO, SUMAg_CF->DsetList);
20665    else
20666       s = SUMA_SurfaceObject_Info (SO, NULL);
20667 
20668    if (s) {
20669       fprintf (Out, "%s", s);
20670       SUMA_free(s);
20671    }else {
20672       fprintf (SUMA_STDERR,
20673                "Error %s: Failed in SUMA_SurfaceObject_Info.\n", FuncName);
20674    }
20675 
20676    SUMA_RETURNe;
20677 }
20678 
SUMA_SO_GeometricType(SUMA_SurfaceObject * SO)20679 char *SUMA_SO_GeometricType(SUMA_SurfaceObject *SO) {
20680    static char FuncName[]={"SUMA_SO_GeometricType"};
20681    char *cc=NULL;
20682 
20683    SUMA_ENTRY;
20684 
20685    if (SO->aSO) {
20686       cc = SUMA_NI_AttrOfNamedElement(SO->aSO,
20687                                       "Node_XYZ","GeometricType");
20688       SUMA_RETURN(cc);
20689    }
20690 
20691    if (SO->isSphere == SUMA_GEOM_SPHERE) {
20692       SUMA_RETURN("Spherical");
20693    }
20694    /* if need be, try guessing for different common surface type */
20695 
20696    SUMA_RETURN("Unknown");
20697 }
20698 
SUMA_SO_AnatomicalStructureSecondary(SUMA_SurfaceObject * SO)20699 char *SUMA_SO_AnatomicalStructureSecondary(SUMA_SurfaceObject *SO) {
20700    static char FuncName[]={"SUMA_SO_AnatomicalStructureSecondary"};
20701    char *cc=NULL;
20702 
20703    SUMA_ENTRY;
20704 
20705    if (SO->aSO) {
20706       cc = SUMA_NI_AttrOfNamedElement(SO->aSO,
20707                                       "Node_XYZ",
20708                                       "AnatomicalStructureSecondary");
20709      SUMA_RETURN(cc);
20710    }
20711 
20712    /* some guessing from FreeSurfer settings */
20713    if (  SUMA_iswordin_ci(SO->State,"pial") == 1 ||
20714          SUMA_iswordin_ci(SO->Label,"pial") == 1 ||
20715          SUMA_iswordin_ci(SO->Name.FileName,"pial") == 1 )
20716             SUMA_RETURN("Pial");
20717    if (SUMA_iswordin_ci(SO->State,"smoothwm") == 1||
20718          SUMA_iswordin_ci(SO->Label,"smoothwm") == 1 ||
20719          SUMA_iswordin_ci(SO->Name.FileName,"smoothwm") == 1)
20720             SUMA_RETURN("GrayWhite");
20721    if (SUMA_iswordin_ci(SO->State,"white") == 1||
20722          SUMA_iswordin_ci(SO->Label,"white") == 1 ||
20723          SUMA_iswordin_ci(SO->Name.FileName,"white") == 1)
20724                SUMA_RETURN("GrayWhite");
20725 
20726 
20727    SUMA_RETURN("Unknown");
20728 }
20729 
SUMA_SO_AnatomicalStructurePrimary(SUMA_SurfaceObject * SO)20730 char *SUMA_SO_AnatomicalStructurePrimary(SUMA_SurfaceObject *SO) {
20731    static char FuncName[]={"SUMA_SO_AnatomicalStructurePrimary"};
20732    char *cc=NULL;
20733 
20734    SUMA_ENTRY;
20735 
20736    if (SO->aSO) {
20737       cc = SUMA_NI_AttrOfNamedElement(SO->aSO,
20738                                       "Node_XYZ",
20739                                       "AnatomicalStructurePrimary");
20740       SUMA_RETURN(cc);
20741    }
20742 
20743    /* weak guess, based on side */
20744    if (SO->Side <= SUMA_NO_SIDE) SO->Side = SUMA_GuessSide(SO);
20745    if (SO->Side == SUMA_LEFT) SUMA_RETURN("CortexLeft");
20746    if (SO->Side == SUMA_RIGHT) SUMA_RETURN("CortexRight");
20747    if (SO->Side == SUMA_LR) SUMA_RETURN("CortexRightAndLeft");
20748 
20749 
20750    SUMA_RETURN("Unknown");
20751 }
SUMA_SO_TopologicalType(SUMA_SurfaceObject * SO)20752 char *SUMA_SO_TopologicalType(SUMA_SurfaceObject *SO) {
20753    static char FuncName[]={"SUMA_SO_TopologicalType"};
20754    char *cc=NULL;
20755 
20756    SUMA_ENTRY;
20757 
20758    if (SO->aSO) {
20759       cc = SUMA_NI_AttrOfNamedElement(SO->aSO,
20760                                       "Mesh_IJK",
20761                                       "TopologicalType");
20762       SUMA_RETURN(cc);
20763    }
20764 
20765    /* guess, based on edges */
20766    if (SO->EL) {
20767       if (  SO->EL->min_N_Hosts == SO->EL->max_N_Hosts &&
20768             SO->EL->min_N_Hosts == 2 ) SUMA_RETURN("Closed");
20769       else if (SO->EL->min_N_Hosts == 1) SUMA_RETURN("Open"); /* could also be
20770                                                                  cut...*/
20771       else if (SO->EL->max_N_Hosts > 2) SUMA_RETURN("Not_2_Manifold");
20772    }
20773 
20774    SUMA_RETURN("Unknown");
20775 }
20776 /*
20777    Keep function in sync with SUMA_ExtractAfniSO_FromSumaSO
20778 */
SUMA_MergeAfniSO_In_SumaSO(NI_group ** aSOp,SUMA_SurfaceObject * SO)20779 SUMA_Boolean SUMA_MergeAfniSO_In_SumaSO(NI_group **aSOp,
20780                                         SUMA_SurfaceObject *SO)
20781 {
20782    static char FuncName[]={"SUMA_MergeAfniSO_In_SumaSO"};
20783    NI_group *aSO=NULL;
20784    int i,j,k;
20785    double *dv=NULL, xform[4][4];
20786    NI_element *nelxyz=NULL, *nelnormals=NULL, *nelxform=NULL, *nelijk=NULL;
20787 
20788    SUMA_Boolean LocalHead=NOPE;
20789 
20790    SUMA_ENTRY;
20791 
20792    if (!SO) SUMA_RETURN(NOPE);
20793    if (aSOp) {
20794       if (SO->aSO) {
20795          SUMA_S_Err("Not ready to merge with pre-existing aSO");
20796          SUMA_RETURN(NOPE);
20797       }
20798       aSO = *aSOp;
20799       if (!aSO) SUMA_RETURN(NOPE);
20800 
20801       if (SO->NodeList || SO->FaceSetList || SO->NodeNormList) {
20802          SUMA_S_Err("This assumes SO->NodeList and others like it to be NULL!");
20803          SUMA_RETURN(NOPE);
20804       }
20805       /* copy common fields one by one.
20806          Follow AFNI_SurfaceObject structure closely.
20807          Keep new fields in aSO */
20808       SUMA_LH("Moving node coordinates");
20809       nelxyz = SUMA_FindNgrNamedElement(aSO, "Node_XYZ");
20810       SO->N_Node = SUMA_NI_get_int(nelxyz, "N_Node");
20811       SO->NodeDim = SUMA_NI_get_int(nelxyz, "NodeDim");
20812       SO->EmbedDim = SUMA_NI_get_int(nelxyz, "EmbedDim");
20813       if (nelxyz->vec_num) {
20814          if (!(SO->NodeList = (float *)SUMA_calloc(SO->NodeDim*SO->N_Node,
20815                                                   sizeof(float)))) {
20816             SUMA_S_Err("Failed to allocate");
20817             SUMA_RETURN(NOPE);
20818          }
20819          memcpy(  SO->NodeList, nelxyz->vec[0],
20820                   SO->NodeDim*SO->N_Node*sizeof(float));
20821          NI_remove_column(nelxyz,0);
20822       } else {
20823          SO->NodeList = NULL;
20824       }
20825 
20826 
20827       SUMA_LH("Moving mesh ijk");
20828       nelijk = SUMA_FindNgrNamedElement(aSO, "Mesh_IJK");
20829       SO->N_FaceSet = SUMA_NI_get_int(nelijk, "N_FaceSet");
20830       SO->FaceSetDim = SUMA_NI_get_int(nelijk, "FaceSetDim");
20831       if (nelijk->vec_num) {
20832          if (!(SO->FaceSetList = (int *)
20833                                  SUMA_calloc(SO->FaceSetDim*SO->N_FaceSet,
20834                                              sizeof(int)))) {
20835             SUMA_S_Err("Failed to allocate");
20836             SUMA_RETURN(NOPE);
20837          }
20838          memcpy(  SO->FaceSetList, nelijk->vec[0],
20839                   SO->FaceSetDim*SO->N_FaceSet*sizeof(int));
20840          NI_remove_column(nelijk,0);
20841       } else {
20842          SO->FaceSetList = NULL;
20843       }
20844       SUMA_LH("Moving normals");
20845       nelnormals = SUMA_FindNgrNamedElement(aSO, "Node_Normals");
20846       if (nelnormals->vec_num) {
20847          if (!(SO->NodeNormList = (float *)SUMA_calloc(SO->NodeDim*SO->N_Node,
20848                                                        sizeof(float)))) {
20849             SUMA_S_Err("Failed to allocate");
20850             SUMA_RETURN(NOPE);
20851          }
20852          memcpy(  SO->NodeNormList, nelnormals->vec[0],
20853                   SO->NodeDim*SO->N_Node*sizeof(float));
20854          NI_remove_column(nelnormals,0);
20855          SO->glar_NodeNormList = (GLfloat *) SO->NodeNormList;
20856       } else {
20857          SO->NodeNormList = NULL;
20858          SO->glar_NodeNormList = NULL;
20859       }
20860 
20861       SO->aSO = aSO;
20862       *aSOp = NULL; /* allow no one to touch this anymore */
20863 
20864       /* Is there an xform to apply ? */
20865       SUMA_LH("Dealing with Xforms.\n"
20866               "Note that transform is not applied to normals.\n"
20867               "Not sure what the standard dictates for such a case.");
20868       if (!SUMA_GetSOCoordXform(SO, xform)) {
20869          SUMA_S_Err("Failed to get xform!");
20870          NI_set_attribute(nelxyz,"inxformspace","no");
20871       } else {
20872          if (!SUMA_Apply_Coord_xform(SO->NodeList, SO->N_Node, SO->NodeDim,
20873                                      xform, 0, NULL)) {
20874             SUMA_S_Err("Failed to apply xform!");
20875             NI_set_attribute(nelxyz,"inxformspace","no");
20876          }else{
20877          NI_set_attribute(nelxyz,"inxformspace","yes");
20878          }
20879       }
20880 
20881       /* Now fill up some additional fields */
20882       SUMA_LH("Filling extras");
20883       SO->Side = SUMA_GuessSide(SO);
20884       if (SO->isSphere == SUMA_GEOM_NOT_SET) SUMA_SetSphereParams(SO, -0.1);
20885       SO->AnatCorrect = SUMA_GuessAnatCorrect(SO);
20886       SO->State =
20887          SUMA_append_replace_string(
20888             NI_get_attribute(nelxyz,"GeometricType"),
20889             NI_get_attribute(nelxyz,"AnatomicalStructureSecondary"),
20890             ".", 0);
20891 
20892    } else { /* add new one */
20893       SUMA_LH("Adding a new aSO");
20894       if (SO->aSO) {
20895          SUMA_S_Err("aSO already exists.");
20896          SUMA_RETURN(NOPE);
20897       }
20898       aSO = SUMA_NewAfniSurfaceObject();
20899       nelxyz = SUMA_FindNgrNamedElement(aSO, "Node_XYZ");
20900       NI_alter_veclen(nelxyz,SO->NodeDim*SO->N_Node);
20901       nelijk = SUMA_FindNgrNamedElement(aSO, "Mesh_IJK");
20902       NI_alter_veclen(nelijk,SO->FaceSetDim*SO->N_FaceSet);
20903       nelnormals = SUMA_FindNgrNamedElement(aSO, "Node_Normals");
20904       NI_alter_veclen(nelnormals,SO->NodeDim*SO->N_Node);
20905       nelxform = SUMA_FindNgrNamedElement(aSO, "Coord_System");
20906       /* fillup IDs, Creating function cannot call ID creating routines */
20907       SUMA_PUT_ID_ATTR(nelxyz,"idcode_str", NULL);
20908       SUMA_PUT_ID_ATTR(nelijk, "idcode_str", NULL);
20909 
20910       /* fillup date */
20911       {  char *date=tross_datetime();
20912          NI_set_attribute(nelxyz,"date", date);
20913          NI_set_attribute(nelijk,"date", date);
20914          free(date);
20915       }
20916 
20917       /* populate xform with junk since this concept does not exist in SO */
20918       NI_set_attribute(nelxyz,"inxformspace","no");
20919       NI_set_attribute(nelxform, "dataspace", "NIFTI_XFORM_UNKNOWN");
20920       NI_set_attribute(nelxform, "xformspace", "NIFTI_XFORM_UNKNOWN");
20921       dv = (double *)nelxform->vec[0];
20922       k = 0;
20923       for (i=0; i<4;++i)
20924          for (j=0; j<4;++j) {
20925             if (i==j) dv[k]=1.0;
20926             else dv[k]=0.0;
20927             ++k;
20928          }
20929 
20930       /* Have aSO, now start filling it up */
20931       SUMA_LH("Filling new aSO");
20932       NI_SET_INT(nelxyz,"N_Node",SO->N_Node) ;
20933       NI_SET_INT(nelxyz,"NodeDim", SO->NodeDim);
20934       NI_SET_INT(nelxyz,"EmbedDim", SO->EmbedDim) ;
20935 
20936       NI_SET_INT(nelijk,"N_FaceSet", SO->N_FaceSet) ;
20937       NI_SET_INT(nelijk,"FaceSetDim", SO->FaceSetDim)  ;
20938 
20939       NI_set_attribute( nelxyz,
20940                         "GeometricType",
20941                         SUMA_SO_GeometricType(SO));
20942       NI_set_attribute( nelxyz,
20943                         "AnatomicalStructureSecondary",
20944                         SUMA_SO_AnatomicalStructureSecondary(SO));
20945       NI_set_attribute( nelxyz,
20946                         "AnatomicalStructurePrimary",
20947                         SUMA_SO_AnatomicalStructurePrimary(SO));
20948       NI_set_attribute( nelijk,
20949                         "TopologicalType",
20950                         SUMA_SO_TopologicalType(SO));
20951       SO->aSO = aSO;
20952 
20953    }
20954 
20955    SUMA_RETURN(YUP);
20956 }
20957 
20958 /* wipe out any pre-existing xform in aSO */
SUMA_Blank_AfniSO_Coord_System(NI_group * aSO)20959 SUMA_Boolean SUMA_Blank_AfniSO_Coord_System(NI_group *aSO)
20960 {
20961    int i, j;
20962    double *dv;
20963    NI_element *nelxform=NULL;
20964    if (aSO) {
20965       if (!(nelxform = SUMA_FindNgrNamedElement(aSO, "Coord_System"))){
20966          nelxform = NI_new_data_element("Coord_System", 16);
20967          NI_add_column(nelxform,NI_DOUBLE,NULL);
20968          NI_add_to_group(aSO, nelxform);
20969       }
20970       dv = (double *)nelxform->vec[0];
20971       if (dv) { /* make identity */
20972          for (i=0; i<4; ++i)
20973             for (j=0; j<4; ++j) {
20974                if (i==j) dv[i*4+j]=1.0;
20975                else dv[i*4+j]= 0.0;
20976             }
20977       }
20978       NI_set_attribute( nelxform,"dataspace","NIFTI_XFORM_UNKNOWN");
20979       NI_set_attribute( nelxform,"xformspace","NIFTI_XFORM_UNKNOWN");
20980    }
20981    return(YUP);
20982 }
20983 
SUMA_VO_NumVE(SUMA_VolumeObject * VO)20984 int SUMA_VO_NumVE(SUMA_VolumeObject *VO) {
20985    int i=0;
20986    if (!VO) SUMA_RETURN(-1);
20987    if (VO->VE) {
20988       while (VO->VE[i]) ++i;
20989    }
20990    return(i);
20991 }
20992 
SUMA_VE_dset(SUMA_VolumeElement ** VE,int ivo)20993 SUMA_DSET *SUMA_VE_dset(SUMA_VolumeElement **VE, int ivo)
20994 {
20995    static char FuncName[]={"SUMA_VE_dset"};
20996    SUMA_DSET *sdset = NULL;
20997    SUMA_ENTRY;
20998 
20999    if (ivo < 0) ivo = 0;
21000    if (!VE || !VE[ivo]) SUMA_RETURN(NULL);
21001    sdset = DSET_FIND(VE[ivo]->dset_idcode_str);
21002    SUMA_RETURN(sdset);
21003 }
21004 
21005 
SUMA_VO_dset(SUMA_VolumeObject * VO)21006 SUMA_DSET *SUMA_VO_dset(SUMA_VolumeObject *VO)
21007 {
21008    static char FuncName[]={"SUMA_VO_dset"};
21009    SUMA_ENTRY;
21010 
21011    if (!VO) SUMA_RETURN(NULL);
21012 
21013    SUMA_RETURN(SUMA_VE_dset(VO->VE,0));
21014 }
21015 
SUMA_AddDsetVolumeObject(SUMA_VolumeObject * VO,THD_3dim_dataset ** dsetp)21016 SUMA_Boolean SUMA_AddDsetVolumeObject( SUMA_VolumeObject *VO,
21017                                        THD_3dim_dataset **dsetp) {
21018    static char FuncName[]={"SUMA_AddDsetVolumeObject"};
21019    THD_3dim_dataset *dset=NULL;
21020    int n_VE=0;
21021    SUMA_Boolean LocalHead=NOPE;
21022 
21023    SUMA_ENTRY;
21024 
21025 
21026    if (dsetp) dset = *dsetp;
21027 
21028    if (!dset) {
21029       SUMA_S_Err("Got nothing to work with!");
21030       SUMA_RETURN(NOPE);
21031    }
21032    n_VE = SUMA_VO_NumVE(VO);
21033    if (n_VE > 0) {
21034       SUMA_S_Warn("You need to decide what to do here"
21035                   "One thought is that each newly loaded volume"
21036                   "under the same VO should be on the grid of the"
21037                   "1st dset. This way all data will be defined"
21038                   "as multiple color planes on a surface. Can't beat"
21039                   "that idea. New grids should simply go under a "
21040                   "different grid, a different VO.");
21041       /* resample dset to SUMA_VO_dset(VO); ... */
21042    }
21043    if (dset) {
21044       SUMA_LHv("Adding dset %s in slot %d\n", DSET_HEADNAME(dset), n_VE);
21045       {
21046          SUMA_DSET *sdset=NULL;
21047          static int ncnt;
21048          if (LocalHead) {
21049             SUMA_S_Warn("The bold experiment,"
21050                      "Need to fix messy business in SUMA_adset_to_VE...\n"
21051                      "Need to document meaning of VE in VO in the header.\n" );
21052             ++ncnt;
21053          }
21054          sdset = SUMA_adset_to_VE(VO, &dset);
21055          if (LocalHead) SUMA_ShowDset(sdset, 0, NULL);
21056       }
21057 
21058    }
21059 
21060    if (dsetp) { /* make sure user can't manipulate initial volume,
21061                    long gone now */
21062       *dsetp=NULL;
21063    }
21064 
21065    SUMA_RETURN(YUP);
21066 }
21067 
21068 /*!
21069 Create a Volume Object data structure
21070 */
SUMA_CreateVolumeObject(char * Label)21071 SUMA_VolumeObject *SUMA_CreateVolumeObject(char *Label)
21072 {
21073    static char FuncName[]={"SUMA_CreateVolumeObject"};
21074    SUMA_VolumeObject *VO=NULL;
21075    int i, j, newval;
21076    int Texcomps=1, max3dtexdims=0;
21077    SUMA_Boolean LocalHead = NOPE;
21078 
21079    SUMA_ENTRY;
21080 
21081 
21082    VO = (SUMA_VolumeObject *)SUMA_calloc(1,sizeof(SUMA_VolumeObject));
21083    if (VO == NULL) {
21084       SUMA_S_Crit("Failed to allocate");
21085       SUMA_RETURN(NULL);
21086    }
21087 
21088 
21089    VO->do_type = VO_type;
21090    if (Label) {
21091       VO->Label = SUMA_copy_string(Label);
21092    } else {
21093       VO->Label = SUMA_copy_string("NoLabel");
21094    }
21095    VO->idcode_str = UNIQ_hashcode(VO->Label);
21096    VO->VoxelMarker = NULL;
21097 
21098    VO->Saux = NULL;
21099    VO->FreeSaux = NULL;
21100    if (!SUMA_AddVolSaux(VO)) {
21101       SUMA_S_Err("Failed to add Vol Saux");
21102    }
21103 
21104    VO->Show = 1;
21105 
21106    VO->VE = (SUMA_VolumeElement **)
21107       SUMA_calloc(SUMA_MAX_N_VE, sizeof(SUMA_VolumeElement *));
21108 
21109    VO->CutPlane[0][0] = -1.0;
21110    VO->CutPlane[0][1] = 0.0;
21111    VO->CutPlane[0][2] = 0.0;
21112    VO->CutPlane[0][3] = 50.0;
21113 
21114    VO->CutPlane[1][0] = 1.0;
21115    VO->CutPlane[1][1] = 0.0;
21116    VO->CutPlane[1][2] = 0.0;
21117    VO->CutPlane[1][3] = 50.0;
21118 
21119    VO->CutPlane[2][0] = 0.0;
21120    VO->CutPlane[2][1] = -1.0;
21121    VO->CutPlane[2][2] = 0.0;
21122    VO->CutPlane[2][3] = 50.0;
21123 
21124    VO->CutPlane[3][0] = 0.0;
21125    VO->CutPlane[3][1] = 1.0;
21126    VO->CutPlane[3][2] = 0.0;
21127    VO->CutPlane[3][3] = 50.0;
21128 
21129    VO->CutPlane[4][0] = 0.0;
21130    VO->CutPlane[4][1] = 0.0;
21131    VO->CutPlane[4][2] = -1.0;
21132    VO->CutPlane[4][3] = 50.0;
21133 
21134    VO->CutPlane[5][0] = 0.0;
21135    VO->CutPlane[5][1] = 0.0;
21136    VO->CutPlane[5][2] = 1.0;
21137    VO->CutPlane[5][3] = 50.0;
21138 
21139    VO->UseCutPlane[0] = 1;
21140    VO->UseCutPlane[1] = 1;
21141    for (i=2; i<6; ++i) {
21142       VO->UseCutPlane[i] = 1;
21143    }
21144    VO->SelectedCutPlane = 0;
21145 
21146    VO->SelectedVoxel = -1;
21147    VO->ShowSelectedVoxel = 0;
21148 
21149 
21150    VO->SOcut = (SUMA_SurfaceObject **)SUMA_calloc(6,
21151                                  sizeof(SUMA_SurfaceObject *));
21152    SUMA_RETURN(VO);
21153 }/* SUMA_CreateVolumeObject */
21154 
21155 
SUMA_FreeVolumeObject(SUMA_VolumeObject * VO)21156 SUMA_VolumeObject *SUMA_FreeVolumeObject(SUMA_VolumeObject *VO) {
21157    static char FuncName[]={"SUMA_FreeVolumeObject"};
21158    int i;
21159    SUMA_ENTRY;
21160 
21161    if (!VO) SUMA_RETURN(NULL);
21162 
21163    if (VO->VE) {
21164       i = 0;
21165       while (VO->VE[i]) {
21166          if (VO->VE[i]->dset_idcode_str) {
21167             SUMA_S_Warn("Should one consider freeing DSET structure"
21168                         " from dset list here?"
21169                         "Is it not better to use pointer copies and"
21170                         "free when there are no more copies?");
21171             SUMA_free(VO->VE[i]->dset_idcode_str);
21172             VO->VE[i]->dset_idcode_str = NULL;
21173          }
21174          if (VO->VE[i]->texName)
21175             SUMA_free(VO->VE[i]->texName); VO->VE[i]->texName = NULL;
21176          if (VO->VE[i]->texvec)
21177             SUMA_free(VO->VE[i]->texvec); VO->VE[i]->texvec = NULL;
21178          SUMA_free(VO->VE[i]);
21179          ++i;
21180       }
21181       SUMA_free(VO->VE);
21182    }
21183    if (VO->Saux) {
21184       if (!VO->FreeSaux) {
21185          SUMA_S_Err("You're leaky, you're leaky");
21186       } else VO->FreeSaux(VO->Saux);
21187       VO->Saux=NULL; /* pointer freed in freeing function */
21188    }
21189 
21190    if (VO->VoxelMarker) {
21191       SUMA_S_Warn("Don't know how to free this yet! Leak Leak!");
21192    }
21193    if (VO->idcode_str) SUMA_free(VO->idcode_str); VO->idcode_str=NULL;
21194    if (VO->Label) SUMA_free(VO->Label); VO->Label = NULL;
21195    if (VO->SOcut) {
21196       for (i=0; i<6; ++i) {
21197          if (VO->SOcut[i]) SUMA_Free_Surface_Object(VO->SOcut[i]);
21198       }
21199       SUMA_free(VO->SOcut);
21200    }
21201 
21202    SUMA_free(VO);
21203 
21204    SUMA_RETURN(NULL);
21205 }
21206 
21207 /*!
21208 Create a CIFTI displayable Object data structure
21209 */
SUMA_CreateCIFTIObject(char * Label)21210 SUMA_CIFTI_DO *SUMA_CreateCIFTIObject(char *Label)
21211 {
21212    static char FuncName[]={"SUMA_CreateCIFTIObject"};
21213    SUMA_CIFTI_DO *CO=NULL;
21214    SUMA_Boolean LocalHead = NOPE;
21215 
21216    SUMA_ENTRY;
21217 
21218    CO = (SUMA_CIFTI_DO *)SUMA_calloc(1,sizeof(SUMA_CIFTI_DO));
21219    if (CO == NULL) {
21220       SUMA_S_Crit("Failed to allocate");
21221       SUMA_RETURN(NULL);
21222    }
21223 
21224 
21225    CO->do_type = CDOM_type;
21226    if (Label) {
21227       CO->Label = SUMA_copy_string(Label);
21228    } else {
21229       CO->Label = SUMA_copy_string("NoLabel");
21230    }
21231    CO->idcode_str = UNIQ_hashcode(CO->Label);
21232 
21233    CO->Saux = NULL;
21234    CO->FreeSaux = NULL;
21235    if (!SUMA_AddCIFTISaux(CO)) {
21236       SUMA_S_Err("Failed to add CIFTI Saux");
21237    }
21238 
21239    CO->N_subdoms = 0;
21240    CO->subdoms_id = NULL;
21241 
21242    CO->Show = 1;
21243 
21244 
21245    CO->SelectedDatum = -1;
21246    CO->SelectedSubAdo = -1;
21247 
21248    SUMA_RETURN(CO);
21249 }
21250 
SUMA_FreeCIFTIObject(SUMA_CIFTI_DO * CO)21251 SUMA_CIFTI_DO *SUMA_FreeCIFTIObject(SUMA_CIFTI_DO *CO)
21252 {
21253    static char FuncName[]={"SUMA_FreeCIFTIObject"};
21254    int i;
21255    SUMA_ALL_DO *asdo=NULL;
21256    SUMA_Boolean LocalHead = NOPE;
21257 
21258    SUMA_ENTRY;
21259 
21260    if (!CO) SUMA_RETURN(NULL);
21261 
21262 
21263    if (CO->Saux) {
21264       if (!CO->FreeSaux) {
21265          SUMA_S_Err("You're leaky, you're leaky");
21266       } else CO->FreeSaux(CO->Saux);
21267       CO->Saux=NULL; /* pointer freed in freeing function */
21268    }
21269 
21270    SUMA_ifree(CO->idcode_str);
21271    SUMA_ifree(CO->Label);
21272 
21273    for (i=0; i<CO->N_subdoms; ++i) {
21274       if (CO->subdoms_id[i]) {
21275          asdo = SUMA_CIFTI_subdom_ado(CO,i);
21276 	 SUMA_LH("Note that subdomain %s is not being freed here. \n"
21277 	               "It remains in the DO list, free it from there \n"
21278 		       "if you must.", ADO_LABEL(asdo));
21279       	 SUMA_ifree(CO->subdoms_id[i]);
21280       }
21281    }
21282    SUMA_ifree(CO->subdoms_id);
21283 
21284    SUMA_free(CO);
21285 
21286    SUMA_RETURN(NULL);
21287 }
21288 
21289 /*!
21290 Create a Surface Object data structure
21291 */
SUMA_Alloc_SurfObject_Struct(int N)21292 SUMA_SurfaceObject *SUMA_Alloc_SurfObject_Struct(int N)
21293 {
21294    static char FuncName[]={"SUMA_Alloc_SurfObject_Struct"};
21295    SUMA_SurfaceObject *SO;
21296    int i, j;
21297 
21298    SUMA_ENTRY;
21299 
21300    SO = (SUMA_SurfaceObject *)SUMA_calloc(N, sizeof(SUMA_SurfaceObject));
21301    if (SO == NULL) {
21302       SUMA_alloc_problem(  "SUMA_Alloc_SurfObject_Struct:\n"
21303                            "could not allocate memory for SO");
21304    }
21305 
21306    for (i=0; i< N; ++i) {
21307       memset(&(SO[i]), 0, sizeof(SUMA_SurfaceObject));
21308       SO[i].do_type = SO_type;
21309       SO[i].FileType = SUMA_FT_NOT_SPECIFIED;
21310       SO[i].FileFormat = SUMA_FF_NOT_SPECIFIED;
21311       SO[i].NodeMarker = NULL;
21312       SO[i].SelectedNode = -1;
21313       if (!SUMA_AddSurfSaux(SO+i)) {
21314          SUMA_S_Err("Failed to add Tract Saux");
21315       }
21316       SO[i].Name_NodeParent = NULL;
21317       SO[i].Label = NULL;
21318       SO[i].EmbedDim = 3;
21319                /* the zeros in Center, MaxDims, MinDims, */
21320                /* aMinDims and aMaxDims */
21321                /* are used to flag unitialized parameters */
21322                /* always keep zero for initialization */
21323                /* see SUMA_isSODimInitialized */
21324       SO[i].Center[0] = SO[i].Center[1] = SO[i].Center[2] = 0.0;
21325       SO[i].MaxDims[0] = SO[i].MaxDims[1] = SO[i].MaxDims[2] = 0.0;
21326       SO[i].MinDims[0] = SO[i].MinDims[1] = SO[i].MinDims[2] = 0.0;
21327       SO[i].aMinDims = 0.0;
21328       SO[i].aMaxDims = 0.0;
21329       SO[i].MaxCentDist = 0.0;
21330       SO[i].MaxCentDistNode = -1;
21331       SO[i].MinCentDist = 0.0;
21332       SO[i].MinCentDistNode = -1;
21333 
21334       SO[i].ViewCenterWeight = -1;
21335       SO[i].RotationWeight = -1;
21336       SO[i].patchNodeMask = NULL;
21337       SO[i].patchaMaxDims = 0.0;
21338       SO[i].patchaMinDims = 0.0;
21339       SO[i].patchMinDims[0] = SO[i].patchMinDims[1] =
21340                                     SO[i].patchMinDims[2] = 0.0;
21341       SO[i].patchMaxDims[0] = SO[i].patchMaxDims[1] =
21342                                     SO[i].patchMaxDims[2] = 0.0;
21343       SO[i].patchCenter[0] = SO[i].patchCenter[1] =
21344                                     SO[i].patchCenter[2] = 0.0;
21345       SO[i].N_patchNode = 0;
21346       SO[i].MF = NULL;
21347       SO[i].FN = NULL;
21348       SO[i].EL = NULL;
21349       SO[i].PolyArea = NULL;
21350       SO[i].SC = NULL;
21351       SO[i].VolPar = NULL;
21352       SO[i].NodeDim = 0;
21353       SO[i].N_Node = 0;
21354       SO[i].NodeList = NULL;
21355       SO[i].FaceSetDim = 0;
21356       SO[i].N_FaceSet = 0;
21357       SO[i].FaceSetList = NULL;
21358       SO[i].FaceNormList = NULL;
21359       SO[i].NodeNormList = NULL;
21360       SO[i].normdir = 0;
21361       SO[i].glar_NodeList = NULL;
21362       SO[i].glar_FaceSetList = NULL;
21363       SO[i].glar_FaceNormList = NULL;
21364       SO[i].glar_NodeNormList = NULL;
21365       SO[i].NodeList_swp = NULL;
21366       /* create vector of pointers */
21367       SO[i].Overlays =
21368          (SUMA_OVERLAYS **)
21369             SUMA_malloc(sizeof(SUMA_OVERLAYS *) * SUMA_MAX_OVERLAYS);
21370       /* fill pointers with NULL */
21371       for (j=0; j < SUMA_MAX_OVERLAYS; ++j) {
21372          SO[i].Overlays[j] = NULL;
21373       }
21374       SO[i].N_Overlays = 0;
21375       SO[i].SentToAfni = NOPE;
21376 
21377       SO[i].MeshAxis = NULL;
21378       SO[i].ShowMeshAxis = -1;
21379       SO[i].State = NULL;
21380       SO[i].Group = NULL;
21381       SO[i].FaceSetMarker = NULL;
21382       SO[i].SelectedFaceSet = -1;
21383       SO[i].idcode_str = NULL;
21384       SO[i].facesetlist_idcode_str = NULL;
21385       SO[i].nodelist_idcode_str = NULL;
21386       SO[i].facenormals_idcode_str = NULL;
21387       SO[i].nodenormals_idcode_str = NULL;
21388       SO[i].polyarea_idcode_str = NULL;
21389       SO[i].SpecFile.Path = NULL;
21390       SO[i].SpecFile.FileName = NULL;
21391       SO[i].Name.Path = NULL;
21392       SO[i].Name.FileName = NULL;
21393       SO[i].Name_coord.Path = NULL;
21394       SO[i].Name_coord.FileName = NULL;
21395       SO[i].Name_topo.Path = NULL;
21396       SO[i].Name_topo.FileName = NULL;
21397       SO[i].SUMA_VolPar_Aligned = NOPE;
21398       SO[i].APPLIED_A2Exp_XFORM = NO_WARP;
21399       SO[i].SurfCont = NULL; /* This is now handled in SUMA_LoadSpec_eng
21400                               (used to be SUMA_CreateSurfContStruct();) */
21401       SO[i].PolyMode = SRM_ViewerDefault;
21402       SO[i].Show = YUP;
21403       SO[i].Side = SUMA_NO_SIDE;
21404       SO[i].isSphere = SUMA_GEOM_NOT_SET;
21405       SO[i].SphereRadius = -1.0;
21406       SO[i].SphereCenter[0] = -1.0;
21407       SO[i].SphereCenter[1] = -1.0;
21408       SO[i].SphereCenter[2] = -1.0;
21409       SO[i].AnatCorrect = NOPE;
21410       SO[i].DomainGrandParentID = NULL;
21411       SO[i].OriginatorID = NULL;
21412       SO[i].LocalDomainParent = NULL;
21413       SO[i].LocalCurvatureParent = NULL;
21414       SO[i].LocalDomainParentID = NULL;
21415       SO[i].LocalCurvatureParentID = NULL;
21416       SO[i].PermCol = NULL;
21417       SO[i].Group_idcode_str = NULL;
21418       SO[i].OriginatorLabel = NULL;
21419       SO[i].parent_vol_idcode_str = NULL;
21420 
21421       SO[i].aSO = NULL;
21422 
21423       SO[i].CommonNodeObject = NULL;
21424       SO[i].NodeObjects = NULL;
21425       SO[i].NodeNIDOObjects = NULL;
21426       SO[i].NodeAreas = NULL;
21427 
21428       SO[i].PointSize = -1.0;
21429       SUMA_EmptyVisXform(&(SO[i].VisX0));
21430       SUMA_EmptyVisXform(&(SO[i].VisX));
21431 
21432       SO[i].DW = NULL;
21433      }
21434    SUMA_RETURN(SO);
21435 }/* SUMA_Alloc_SurfObject_Struct */
21436 
SUMA_nixSODim(SUMA_SurfaceObject * SO)21437 SUMA_Boolean SUMA_nixSODim(SUMA_SurfaceObject *SO)
21438 {
21439    if (!SO) return(NOPE);
21440 
21441    SO->MaxDims[0] = SO->MaxDims[1] = SO->MaxDims[2] = 0.0;
21442    SO->MinDims[0] = SO->MinDims[1] = SO->MinDims[2] = 0.0;
21443    SO->aMinDims = SO->aMaxDims == 0.0;
21444    return(YUP);
21445 }
21446 
SUMA_isSODimInitialized(SUMA_SurfaceObject * SO)21447 SUMA_Boolean SUMA_isSODimInitialized(SUMA_SurfaceObject *SO)
21448 {
21449    if (!SO) return(NOPE);
21450 
21451    if (  SO->MaxDims[0] == 0.0 && SO->MaxDims[1] == 0.0 &&
21452                                           SO->MaxDims[2] == 0.0 &&
21453          SO->MinDims[0] == 0.0 && SO->MinDims[1] == 0.0 &&
21454                                           SO->MinDims[2] == 0.0 &&
21455          SO->aMinDims == 0.0 && SO->aMaxDims == 0.0) {
21456 
21457          return(NOPE);
21458    }
21459    return(YUP);
21460 }
21461 
SUMA_SetSODims(SUMA_SurfaceObject * SO)21462 SUMA_Boolean SUMA_SetSODims(SUMA_SurfaceObject *SO)
21463 {
21464    static char FuncName[]={"SUMA_SetSODims"};
21465    SUMA_Boolean LocalHead = NOPE;
21466 
21467    SUMA_ENTRY;
21468 
21469    if (!SO) SUMA_RETURN(NOPE);
21470       SUMA_MIN_MAX_SUM_VECMAT_COL (
21471             SO->NodeList, SO->N_Node,
21472             SO->NodeDim, SO->MinDims,
21473             SO->MaxDims, SO->Center);
21474 
21475       SO->Center[0] /= SO->N_Node;
21476       SO->Center[1] /= SO->N_Node;
21477       SO->Center[2] /= SO->N_Node;
21478 
21479       SUMA_MIN_VEC (SO->MinDims, 3, SO->aMinDims );
21480       SUMA_MAX_VEC (SO->MaxDims, 3, SO->aMaxDims);
21481 
21482       SUMA_SO_MAX_MIN_DIST(SO, SO->MaxCentDist, SO->MaxCentDistNode,
21483                                SO->MinCentDist, SO->MinCentDistNode);
21484 
21485    SUMA_LHv("Min:[%f %f %f]\n"
21486             "Max:[%f %f %f]\n"
21487             "aMax: %f, aMin %f\n"
21488             "Max Dist To Cent: %f at %d\n"
21489             "Min Dist To Cent: %f at %d\n",
21490             SO->MinDims[0], SO->MinDims[1],SO->MinDims[2],
21491             SO->MaxDims[0], SO->MaxDims[1],SO->MaxDims[2],
21492             SO->aMaxDims, SO->aMinDims,
21493             SO->MaxCentDist, SO->MaxCentDistNode,
21494             SO->MinCentDist, SO->MinCentDistNode);
21495 
21496    SUMA_RETURN(YUP);
21497 }
21498 
21499 /*!
21500    \brief function for freeing a SUMA_ROI structure.
21501    ans = SUMA_freeROI (ROI);
21502    \param ROI (SUMA_ROI *) pointer to an ROI structure
21503    \return YUP/NOPE
21504 
21505    \sa SUMA_AllocateROI
21506 */
SUMA_freeROI(SUMA_ROI * ROI)21507 SUMA_Boolean SUMA_freeROI (SUMA_ROI *ROI)
21508 {
21509    static char FuncName[]={"SUMA_freeROI"};
21510 
21511    SUMA_ENTRY;
21512 
21513    if (ROI->Parent_idcode_str) SUMA_free(ROI->Parent_idcode_str);
21514    if (ROI->idcode_str) SUMA_free(ROI->idcode_str);
21515    if (ROI->Label) SUMA_free(ROI->Label);
21516    if (ROI->ElInd) SUMA_free(ROI->ElInd);
21517    if (ROI) SUMA_free(ROI);
21518 
21519    SUMA_RETURN (YUP);
21520 }
21521 
21522 /*!
21523    \brief function for freeing a SUMA_DRAWN_ROI structure.
21524    ans = SUMA_freeDrawnROI (D_ROI);
21525    \param D_ROI (SUMA_DRAWN_ROI *) pointer to a drawn ROI structure
21526    \return YUP/NOPE
21527 
21528    \sa SUMA_AllocateDrawnROI
21529 */
SUMA_freeDrawnROI(SUMA_DRAWN_ROI * D_ROI)21530 SUMA_Boolean SUMA_freeDrawnROI (SUMA_DRAWN_ROI *D_ROI)
21531 {
21532    static char FuncName[]={"SUMA_freeDrawnROI"};
21533 
21534    SUMA_ENTRY;
21535 
21536 
21537    if (D_ROI->Parent_idcode_str) SUMA_free(D_ROI->Parent_idcode_str);
21538    if (D_ROI->idcode_str) SUMA_free(D_ROI->idcode_str);
21539    if (D_ROI->Label) SUMA_free(D_ROI->Label);
21540    if (D_ROI->ColPlaneName) SUMA_free(D_ROI->ColPlaneName);
21541    if (D_ROI->ROIstrokelist) SUMA_EmptyDestroyList(D_ROI->ROIstrokelist);
21542    if (D_ROI->ActionStack) SUMA_EmptyDestroyActionStack(D_ROI->ActionStack);
21543    if (D_ROI->CE) SUMA_free(D_ROI->CE);
21544    if (D_ROI) SUMA_free(D_ROI);
21545 
21546    SUMA_RETURN (YUP);
21547 }
21548 
21549 /*!
21550    \brief function for creating (allocating and initializing) the contents of a SUMA_ROI structure.
21551    ROI = SUMA_AllocateROI (Parent_idcode_str, Type, label, int N_ElInd, int *ElInd)
21552 
21553    \param Parent_idcode_str (char *) idcode of parent surface
21554    \param Type (SUMA_ROI_TYPE) type of ROI
21555    \param label  (char *) label ascii label to label ROI. If you pass NULL, a number is assigned to the ROI automatically
21556    \param N_ElInd (int) number of elements in ElInd to allocate for.
21557    \param ElInd (int *) vector of indices to initialize the ROI with, pass NULL for no initialization.
21558                         Values in ElInd are copied into ROI->ElInd.
21559    \return (SUMA_ROI *) ROI pointer to ROI object created
21560                an idcode_str is assigned to ROI
21561    \sa SUMA_freeROI
21562 */
SUMA_AllocateROI(char * Parent_idcode_str,SUMA_ROI_TYPE Type,char * label,int N_ElInd,int * ElInd)21563 SUMA_ROI *SUMA_AllocateROI (char *Parent_idcode_str, SUMA_ROI_TYPE Type, char *label, int N_ElInd, int *ElInd)
21564 {
21565    SUMA_ROI *ROI = NULL;
21566    static int ROI_index = 0;
21567    int i = 0;
21568    static char FuncName[]={"SUMA_AllocateROI"};
21569 
21570    SUMA_ENTRY;
21571 
21572    ROI = (SUMA_ROI *) SUMA_calloc(1,sizeof(SUMA_ROI));
21573    ROI->idcode_str = (char *)SUMA_calloc (SUMA_IDCODE_LENGTH+1, sizeof(char));
21574    ROI->Parent_idcode_str = (char *)SUMA_calloc (strlen(Parent_idcode_str)+1, sizeof (char));
21575    if (label) ROI->Label = (char *)SUMA_calloc (strlen(label)+1, sizeof(char));
21576    else ROI->Label = (char *)SUMA_calloc (20, sizeof(char));
21577    ROI->ElInd = (int *)SUMA_calloc (N_ElInd, sizeof (int));
21578 
21579    if (!ROI || !ROI->idcode_str || !ROI->Parent_idcode_str || !ROI->Label || !ROI->ElInd) {
21580       fprintf (SUMA_STDERR, "Error %s: Failed allocating.\n", FuncName);
21581       SUMA_RETURN (NULL);
21582    }
21583 
21584    ROI->N_ElInd = N_ElInd;
21585 
21586    if (ElInd) {
21587       for (i=0; i<N_ElInd; ++i)
21588          ROI->ElInd[i] = ElInd[i];
21589    }
21590 
21591    UNIQ_idcode_fill(ROI->idcode_str);
21592 
21593    ROI->Parent_idcode_str = strcpy (ROI->Parent_idcode_str, Parent_idcode_str);
21594    if (label) ROI->Label = strcpy (ROI->Label, label);
21595    else sprintf (ROI->Label, "auto label %d", ROI_index);
21596 
21597    ROI->Type = Type;
21598 
21599    ++ROI_index;
21600    SUMA_RETURN (ROI);
21601 }
21602 
21603 
21604 /*!
21605    \brief function for creating (allocating and initializing) the contents of a SUMA_DRAWN_ROI structure.
21606    D_ROI = SUMA_AllocateDrawnROI (Parent_idcode_str, DrawStatus, Type, label , ilabel)
21607    \param Parent_idcode_str (char *) idcode of parent surface
21608    \param DrawStatus (SUMA_ROI_DRAWING_STATUS) status of ROI being drawn
21609    \param Type (SUMA_ROI_DRAWING_TYPE) type of ROI being drawn
21610    \param label (char *) label ascii label to label ROI. If you pass NULL, a number is assigned to the ROI automatically
21611    \param ilabel (int) integer label (or value)
21612    \return (SUMA_DRAWN_ROI *) D_ROI pointer to ROI object created
21613 
21614    \sa SUMA_NIMLDrawnROI_to_DrawnROI where a SUMA_DRAWN_ROI is also created
21615 */
SUMA_AllocateDrawnROI(char * Parent_idcode_str,SUMA_ROI_DRAWING_STATUS DrawStatus,SUMA_ROI_DRAWING_TYPE Type,char * label,int ilabel)21616 SUMA_DRAWN_ROI *SUMA_AllocateDrawnROI (
21617    char *Parent_idcode_str,
21618    SUMA_ROI_DRAWING_STATUS DrawStatus,
21619    SUMA_ROI_DRAWING_TYPE Type,
21620    char *label, int ilabel)
21621 {
21622    SUMA_DRAWN_ROI *D_ROI = NULL;
21623    static int ROI_index = 1;
21624    char stmp[32], sd='\0';
21625    SUMA_SurfaceObject *SO=NULL;
21626    static char FuncName[]={"SUMA_AllocateDrawnROI"};
21627 
21628    SUMA_ENTRY;
21629 
21630    D_ROI = (SUMA_DRAWN_ROI *) SUMA_calloc(1,sizeof(SUMA_DRAWN_ROI));
21631    D_ROI->idcode_str = (char *)SUMA_calloc (SUMA_IDCODE_LENGTH, sizeof(char));
21632    D_ROI->Parent_idcode_str =
21633       (char *)SUMA_calloc (strlen(Parent_idcode_str)+1, sizeof (char));
21634    D_ROI->Parent_side = SUMA_NO_SIDE;
21635    /* get some decent name for colplane */
21636    SO = SUMA_findSOp_inDOv(Parent_idcode_str, SUMAg_DOv, SUMAg_N_DOv);
21637    if (SO && SO->Label) {
21638       if (SO->Side == SUMA_LEFT) {
21639          sd = 'L';
21640       } else if (SO->Side == SUMA_RIGHT) {
21641          sd = 'R';
21642       } else if (SO->Side == SUMA_LR) {
21643          sd = 'B';
21644       } else if (SO->Side == SUMA_NO_SIDE) {
21645          sd = '-';
21646       } else if (SO->Side == SUMA_SIDE_ERROR) {
21647          sd = 'E';
21648       }
21649       snprintf(stmp,12*sizeof(char),".%c.%s",sd,SO->State);
21650       D_ROI->ColPlaneName = SUMA_append_string("ROI",stmp);
21651       D_ROI->Parent_side = SO->Side;
21652    } else {
21653       D_ROI->ColPlaneName = SUMA_copy_string("DefROIpl");
21654    }
21655    D_ROI->FillColor[0] = 1.0;
21656    D_ROI->FillColor[1] = 0.0;
21657    D_ROI->FillColor[2] = 0.0;
21658    D_ROI->FillColor[3] = 1.0;
21659    D_ROI->EdgeColor[0] = 0.0;
21660    D_ROI->EdgeColor[1] = 0.0;
21661    D_ROI->EdgeColor[2] = 1.0;
21662    D_ROI->EdgeColor[3] = 1.0;
21663    D_ROI->EdgeThickness = 2;
21664    D_ROI->ROIstrokelist = (DList *)SUMA_calloc(1,sizeof(DList));
21665    dlist_init(D_ROI->ROIstrokelist, SUMA_FreeROIDatum);
21666    D_ROI->CE = NULL;
21667    D_ROI->N_CE = -1;
21668 
21669    if (label)
21670       D_ROI->Label = (char *)SUMA_calloc (strlen(label)+1, sizeof(char));
21671    else D_ROI->Label = (char *)SUMA_calloc (20, sizeof(char));
21672 
21673    if (  !D_ROI ||
21674          !D_ROI->idcode_str || !D_ROI->Parent_idcode_str || !D_ROI->Label) {
21675       fprintf (SUMA_STDERR, "Error %s: Failed allocating.\n", FuncName);
21676       SUMA_RETURN (NULL);
21677    }
21678 
21679    UNIQ_idcode_fill(D_ROI->idcode_str);
21680 
21681    D_ROI->Parent_idcode_str =
21682       strcpy (D_ROI->Parent_idcode_str, Parent_idcode_str);
21683    if (label) D_ROI->Label = strcpy (D_ROI->Label, label);
21684    else sprintf (D_ROI->Label, "auto label %d", ROI_index);
21685 
21686    D_ROI->DrawStatus = DrawStatus;
21687    D_ROI->Type = Type;
21688 
21689    D_ROI->ActionStack = SUMA_CreateActionStack ();
21690    D_ROI->StackPos = NULL;
21691 
21692    D_ROI->iLabel = ilabel;
21693    D_ROI->ColorByLabel = YUP;
21694 
21695    ++ROI_index;
21696    SUMA_RETURN (D_ROI);
21697 }
21698 
21699 /*!
21700    A destructor for SUMA_ROI_DATUM *
21701 */
SUMA_FreeROIDatum(void * data)21702 void SUMA_FreeROIDatum (void * data)
21703 {
21704    static char FuncName[]={"SUMA_FreeROIDatum"};
21705    SUMA_ROI_DATUM *ROId=NULL;
21706    SUMA_Boolean LocalHead = NOPE;
21707 
21708    SUMA_ENTRY;
21709 
21710    ROId = (SUMA_ROI_DATUM *)data;
21711 
21712    if (!ROId) {
21713       SUMA_RETURNe;
21714    }
21715 
21716    if (LocalHead) fprintf (SUMA_STDERR, "%s: Freeing nPath\n", FuncName);
21717    if (ROId->nPath) SUMA_free(ROId->nPath);
21718    if (LocalHead) fprintf (SUMA_STDERR, "%s: Freeing tPath\n", FuncName);
21719    if (ROId->tPath) SUMA_free(ROId->tPath);
21720    if (LocalHead) fprintf (SUMA_STDERR, "%s: Freeing ROId\n", FuncName);
21721    SUMA_free(ROId);
21722 
21723    SUMA_RETURNe;
21724 }
21725 
21726 /*!
21727    A constructor for SUMA_ROI_DATUM *
21728 */
SUMA_AllocROIDatum(void)21729 SUMA_ROI_DATUM * SUMA_AllocROIDatum (void)
21730 {
21731    static char FuncName[]={"SUMA_AllocROIDatum"};
21732    SUMA_ROI_DATUM *ROId=NULL;
21733 
21734    SUMA_ENTRY;
21735 
21736    ROId = (SUMA_ROI_DATUM *) SUMA_calloc(1,sizeof(SUMA_ROI_DATUM));
21737 
21738    if (!ROId) {
21739       SUMA_RETURN (NULL);
21740    }
21741 
21742    ROId->nPath = ROId->tPath = NULL;
21743    ROId->N_n = ROId->N_t = 0;
21744    ROId->nDistance = ROId->tDistance = 0.0;
21745    ROId->Type = SUMA_ROI_Undefined;
21746    ROId->action = SUMA_BSA_Undefined;
21747    SUMA_RETURN (ROId);
21748 }
21749 
21750 /*!
21751    \brief Determine if nPath in ROId1 and ROId2 are identical (same nodes).
21752 
21753    - Comparison will fail if either datum is null
21754 
21755    - Function not tested
21756 
21757 */
SUMA_isROIdequal(SUMA_ROI_DATUM * ROId1,SUMA_ROI_DATUM * ROId2)21758 SUMA_Boolean SUMA_isROIdequal (SUMA_ROI_DATUM *ROId1, SUMA_ROI_DATUM *ROId2)
21759 {
21760    static char FuncName[]={"SUMA_isROIdequal"};
21761    int i;
21762 
21763    SUMA_ENTRY;
21764 
21765    if (!ROId1 || !ROId2) SUMA_RETURN(NOPE);
21766    if (ROId1->N_n != ROId2->N_n) SUMA_RETURN(NOPE);
21767    if (!ROId1->nPath || !ROId2->nPath) SUMA_RETURN(NOPE);
21768    i = 0;
21769    do {
21770       if (ROId1->nPath[i] != ROId2->nPath[i]) SUMA_RETURN(NOPE);
21771       ++i;
21772    }while (i < ROId2->N_n);
21773 
21774    SUMA_RETURN(YUP);
21775 }
21776 
21777 /*!
21778    \brief Merges two ROIdatum together.
21779    ans = SUMA_AppendToROIdatum (ROIlink, ROId);
21780    ROId = [ROId ROIlink]
21781 
21782    \param ROIlink (SUMA_ROI_DATUM *)
21783    \param ROId (SUMA_ROI_DATUM *)
21784    \return ans YUP/NOPE
21785 
21786    - ROId becomes ROId followed by ROIlink
21787    - ROIlink is not freed
21788    - It is required that the last node of ROId be the first node of ROIlink.
21789    - This is not required for the tPath (the triangle path). By the same token,
21790    it is not guaranteed that the resultant tPath is contiguous (not yet).
21791 
21792    \sa SUMA_PrependToROIdatum
21793 */
SUMA_AppendToROIdatum(SUMA_ROI_DATUM * ROId1,SUMA_ROI_DATUM * ROId2)21794 SUMA_Boolean SUMA_AppendToROIdatum (SUMA_ROI_DATUM *ROId1, SUMA_ROI_DATUM *ROId2)
21795 {
21796    static char FuncName[]={"SUMA_AppendToROIdatum"};
21797    int i, N_nNew=-1, N_tNew=-1, *tPathNew=NULL, *nPathNew=NULL;
21798    SUMA_Boolean CommonTip = NOPE;
21799 
21800    SUMA_ENTRY;
21801 
21802    if (!ROId1) SUMA_RETURN(YUP);
21803    if (!ROId1->N_n)  SUMA_RETURN(YUP);
21804    if (!ROId2) {
21805       fprintf (SUMA_STDERR, "Error %s: NULL ROId2.\n", FuncName);
21806       SUMA_RETURN(NOPE);
21807    }
21808    /* make sure the last node of ROId2 and the first node of ROId1 match */
21809    if (ROId2->N_n) {
21810       if (ROId1->nPath[0] != ROId2->nPath[ROId2->N_n-1]) {
21811          fprintf (SUMA_STDERR, "Error %s: Last node of ROId2 is not the same as the first node of ROId1.\n", FuncName);
21812          SUMA_RETURN(NOPE);
21813       }
21814    }
21815    /* now merge the two */
21816 
21817    /* FIRST the nodes */
21818    /* figure out the new N_n */
21819    N_nNew = ROId1->N_n + ROId2->N_n -1;
21820 
21821    /* create a new nPath pointer */
21822    nPathNew = (int *)SUMA_calloc (N_nNew, sizeof (int));
21823    if (!nPathNew) {
21824       fprintf (SUMA_STDERR, "Error %s: Failed to allocate. \n", FuncName);
21825       SUMA_RETURN(NOPE);
21826    }
21827 
21828    for (i=0; i<ROId2->N_n; ++i) nPathNew[i] = ROId2->nPath[i];
21829    for (i=1; i<ROId1->N_n; ++i) nPathNew[ROId2->N_n+i-1] = ROId1->nPath[i];
21830    SUMA_free(ROId2->nPath);
21831    ROId2->nPath = nPathNew;
21832    ROId2->N_n = N_nNew;
21833 
21834    /* SECOND THE triangles */
21835    CommonTip = NOPE;
21836    if (!ROId1->tPath || !ROId1->N_t) {
21837       /* nothing to do */
21838       ROId2->tPath = NULL;
21839       ROId2->N_t = 0;
21840       SUMA_RETURN(YUP);
21841    }else{
21842       /* do the strips have a common triangle at the end ? */
21843       if (ROId2->N_t) {
21844          if (ROId1->tPath[0] == ROId2->tPath[ROId2->N_t-1]) CommonTip = YUP;
21845       }
21846    }
21847    if (CommonTip) {
21848       /* figure out the new N_n */
21849       N_tNew = ROId1->N_t + ROId2->N_t -1;
21850 
21851       /* create a new tPath pointer */
21852       tPathNew = (int *)SUMA_calloc (N_tNew, sizeof (int));
21853       if (!tPathNew) {
21854          fprintf (SUMA_STDERR, "Error %s: Failed to allocate. \n", FuncName);
21855          SUMA_RETURN(NOPE);
21856       }
21857       for (i=0; i<ROId2->N_t; ++i) tPathNew[i] = ROId2->tPath[i];
21858       for (i=1; i<ROId1->N_t; ++i) tPathNew[ROId2->N_t+i-1] = ROId1->tPath[i];
21859       SUMA_free(ROId2->tPath);
21860    }else {
21861       /* figure out the new N_n */
21862       N_tNew = ROId1->N_t + ROId2->N_t;
21863 
21864       /* create a new tPath pointer */
21865       tPathNew = (int *)SUMA_calloc (N_tNew, sizeof (int));
21866       if (!tPathNew) {
21867          fprintf (SUMA_STDERR, "Error %s: Failed to allocate. \n", FuncName);
21868          SUMA_RETURN(NOPE);
21869       }
21870       for (i=0; i<ROId2->N_t; ++i) tPathNew[i] = ROId2->tPath[i];
21871       for (i=0; i<ROId1->N_t; ++i) tPathNew[ROId2->N_t+i] = ROId1->tPath[i];
21872       SUMA_free(ROId2->tPath);
21873    }
21874    ROId2->tPath = tPathNew;
21875    ROId2->N_t = N_tNew;
21876 
21877 
21878    SUMA_RETURN(YUP);
21879 }
21880 
21881 /*!
21882    \brief Merges two ROIdatum together.
21883    ans = SUMA_PrependToROIdatum (ROIlink, ROId);
21884    ROId = [ROIlink ROId]
21885 
21886    \param ROIlink (SUMA_ROI_DATUM *)
21887    \param ROId (SUMA_ROI_DATUM *)
21888    \return ans YUP/NOPE
21889 
21890    - ROId becomes ROIlink followed by ROId
21891    - ROIlink is not freed
21892    - It is required that the last node of ROIlink be the first node of ROId.
21893    - This is not required for the tPath (the triangle path). By the same token,
21894    it is not guaranteed that the resultant tPath is contiguous (not yet).
21895 
21896    \sa SUMA_AppendToROIdatum
21897 */
SUMA_PrependToROIdatum(SUMA_ROI_DATUM * ROId1,SUMA_ROI_DATUM * ROId2)21898 SUMA_Boolean SUMA_PrependToROIdatum (
21899    SUMA_ROI_DATUM *ROId1,
21900    SUMA_ROI_DATUM *ROId2)
21901 {
21902    static char FuncName[]={"SUMA_PrependToROIdatum"};
21903    int i=0, N_nNew=-1, N_tNew=-1, *tPathNew=NULL, *nPathNew=NULL;
21904    SUMA_Boolean CommonTip = NOPE;
21905 
21906    SUMA_ENTRY;
21907 
21908    if (!ROId1) SUMA_RETURN(YUP);
21909    if (!ROId1->N_n)  SUMA_RETURN(YUP);
21910    if (!ROId2) {
21911       fprintf (SUMA_STDERR, "Error %s: NULL ROId2.\n", FuncName);
21912       SUMA_RETURN(NOPE);
21913    }
21914    /* make sure the last node of ROId1 and the first node of ROId2 match */
21915    if (ROId2->N_n) {
21916       if (ROId1->nPath[ROId1->N_n-1] != ROId2->nPath[0]) {
21917          fprintf (SUMA_STDERR,
21918                   "Error %s: Last node of ROId1 is not the same \n"
21919                   "as the first node of ROId2.\n", FuncName);
21920          SUMA_RETURN(NOPE);
21921       }
21922    }
21923    /* now merge the two */
21924 
21925    /* FIRST the nodes */
21926    /* figure out the new N_n */
21927    N_nNew = ROId1->N_n + ROId2->N_n -1;
21928 
21929    /* create a new nPath pointer */
21930    nPathNew = (int *)SUMA_calloc (N_nNew, sizeof (int));
21931    if (!nPathNew) {
21932       fprintf (SUMA_STDERR, "Error %s: Failed to allocate. \n", FuncName);
21933       SUMA_RETURN(NOPE);
21934    }
21935    for (i=0; i<ROId1->N_n; ++i) nPathNew[i] = ROId1->nPath[i];
21936    for (i=1; i<ROId2->N_n; ++i) nPathNew[ROId1->N_n+i-1] = ROId2->nPath[i];
21937    SUMA_free(ROId2->nPath);
21938    ROId2->nPath = nPathNew;
21939    ROId2->N_n = N_nNew;
21940 
21941    /* SECOND THE triangles */
21942    CommonTip = NOPE;
21943    if (!ROId1->tPath || !ROId1->N_t) {
21944       /* nothing to do */
21945       ROId2->tPath = NULL;
21946       ROId2->N_t = 0;
21947       SUMA_RETURN(YUP);
21948    }else{
21949       /* do the strips have a common triangle at the end ? */
21950       if (ROId2->N_t) {
21951          if (ROId1->tPath[ROId1->N_t-1] == ROId2->tPath[0]) CommonTip = YUP;
21952       }
21953    }
21954    if (CommonTip) {
21955       /* figure out the new N_n */
21956       N_tNew = ROId1->N_t + ROId2->N_t -1;
21957 
21958       /* create a new tPath pointer */
21959       tPathNew = (int *)SUMA_calloc (N_tNew, sizeof (int));
21960       if (!tPathNew) {
21961          fprintf (SUMA_STDERR, "Error %s: Failed to allocate. \n", FuncName);
21962          SUMA_RETURN(NOPE);
21963       }
21964       for (i=0; i<ROId1->N_t; ++i) tPathNew[i] = ROId1->tPath[i];
21965       for (i=1; i<ROId2->N_t; ++i) tPathNew[ROId1->N_t+i-1] = ROId2->tPath[i];
21966       SUMA_free(ROId2->tPath);
21967    }else {
21968       /* figure out the new N_n */
21969       N_tNew = ROId1->N_t + ROId2->N_t;
21970 
21971       /* create a new tPath pointer */
21972       tPathNew = (int *)SUMA_calloc (N_tNew, sizeof (int));
21973       if (!tPathNew) {
21974          fprintf (SUMA_STDERR, "Error %s: Failed to allocate. \n", FuncName);
21975          SUMA_RETURN(NOPE);
21976       }
21977       for (i=0; i<ROId1->N_t; ++i) tPathNew[i] = ROId1->tPath[i];
21978       for (i=0; i<ROId2->N_t; ++i) tPathNew[ROId1->N_t+i] = ROId2->tPath[i];
21979       SUMA_free(ROId2->tPath);
21980    }
21981    ROId2->tPath = tPathNew;
21982    ROId2->N_t = N_tNew;
21983 
21984    SUMA_RETURN(YUP);
21985 }
21986 
21987 /*!
21988    \brief Show contents of a drawn ROI datum
21989    SUMA_ShowDrawnROIDatum (ROId, Out, ShortVersion);
21990 
21991    \param ROId (SUMA_ROI_DATUM *)
21992    \param Out (FILE *) (stderr if NULL)
21993    \param ShortVersion (SUMA_Boolean) if YUP, short version
21994 
21995 */
SUMA_ShowDrawnROIDatum(SUMA_ROI_DATUM * ROId,FILE * out,SUMA_Boolean ShortVersion)21996 void SUMA_ShowDrawnROIDatum (SUMA_ROI_DATUM *ROId, FILE *out, SUMA_Boolean ShortVersion)
21997 {
21998    static char FuncName[]={"SUMA_ShowDrawnROIDatum"};
21999    int i;
22000 
22001    SUMA_ENTRY;
22002 
22003    if (!out) out = SUMA_STDERR;
22004 
22005    if (!ROId) {
22006       fprintf(out, "%s: NULL ROId\n", FuncName);
22007       SUMA_RETURNe;
22008    }
22009 
22010    if (!ROId->N_n) {
22011       fprintf(out, "%s: Empty ROId. (N_n = 0)\n", FuncName);
22012       SUMA_RETURNe;
22013    }
22014 
22015    if (ROId->N_n && !ROId->nPath) {
22016       fprintf(out, "Error %s: nPath is NULL with N_n != 0.\n", FuncName);
22017       SUMA_RETURNe;
22018    }
22019 
22020    if (ROId->N_n == 1) {
22021       fprintf(out, "%s: ROId (type %d) has 1 node (%d) in nPath.\n",
22022          FuncName, ROId->Type, ROId->nPath[0]);
22023    }else {
22024       fprintf(out, "%s: ROId (type %d) has %d nodes in nPath [%d..%d].\n",
22025          FuncName, ROId->Type, ROId->N_n, ROId->nPath[0], ROId->nPath[ROId->N_n-1]);
22026       if (!ShortVersion) {
22027          for (i=0; i <ROId->N_n; ++i) fprintf (out, "%d: %d\t", i, ROId->nPath[i]);
22028          fprintf (out, "\n");
22029       }
22030    }
22031 
22032    if (ROId->N_t && !ROId->tPath) {
22033       fprintf(out, "Error %s: tPath is NULL with N_t != 0.\n", FuncName);
22034       SUMA_RETURNe;
22035    }
22036 
22037    if (!ROId->N_t) {
22038       fprintf(out, "%s: Empty ROId->tPath. (N_t = 0)\n", FuncName);
22039       SUMA_RETURNe;
22040    }else {
22041          if (ROId->N_t == 1) {
22042             fprintf(out, "%s: ROId (type %d) has 1 triangle (%d) in tPath.\n",
22043                FuncName, ROId->Type, ROId->tPath[0]);
22044          }else {
22045             fprintf(out, "%s: ROId (type %d) has %d triangles in tPath [%d..%d].\n",
22046                FuncName, ROId->Type, ROId->N_t, ROId->tPath[0], ROId->tPath[ROId->N_t-1]);
22047             if (!ShortVersion) {
22048                for (i=0; i <ROId->N_t; ++i) fprintf (out, "%d: %d\t", i, ROId->tPath[i]);
22049                fprintf (out, "\n");
22050             }
22051          }
22052    }
22053 
22054    SUMA_RETURNe;
22055 }
22056 
22057 #define SUMA_FS_DIJKSTRA_DISTANCE_FACTOR 1.20711 /* taken from pp 198, col 1 Fischl et al Neuroimage 9, 195-207 1999, Cortical Surface-Based Analysis */
SUMA_ReportDrawnROIDatumLength(SUMA_SurfaceObject * SO,SUMA_ROI_DATUM * ROId,FILE * out,SUMA_WIDGET_INDEX_DRAWROI_WHATDIST option)22058 void SUMA_ReportDrawnROIDatumLength(SUMA_SurfaceObject *SO, SUMA_ROI_DATUM *ROId,                                     FILE *out,
22059                                     SUMA_WIDGET_INDEX_DRAWROI_WHATDIST option)
22060 {
22061    static char FuncName[]={"SUMA_ReportDrawnROIDatumLength"};
22062    int N0, N1, i, N_n, *nPath, N_left;
22063    SUMA_Boolean *isNodeInMesh = NULL;
22064    float *p1, *p2;
22065    float ds = 0, d = 0, ds_c, dd, dd_c, deuc;
22066    char *s = NULL;
22067    SUMA_STRING *SS = NULL;
22068    SUMA_Boolean LocalHead = NOPE;
22069 
22070    SUMA_ENTRY;
22071 
22072    if (!ROId) SUMA_RETURNe;
22073    if (ROId->N_n < 2) SUMA_RETURNe;
22074    if (option != SW_DrawROI_WhatDistAll && option != SW_DrawROI_WhatDistTrace) {
22075       SUMA_SL_Err("Why do you get this here ?");
22076       SUMA_RETURNe;
22077    }
22078    SS = SUMA_StringAppend (NULL, NULL);
22079 
22080    /* calculate path distance */
22081    ds = 0.0;
22082    for (i=0; i<ROId->N_n-1; ++i) {
22083       p1 = &(SO->NodeList[3*ROId->nPath[i]]);
22084       p2 = &(SO->NodeList[3*ROId->nPath[i+1]]);
22085       SUMA_SEG_NORM(p1, p2, d);
22086       ds = ds + d;
22087    }
22088    ds_c = ds / SUMA_FS_DIJKSTRA_DISTANCE_FACTOR;
22089    SUMA_SEG_LENGTH((SO->NodeList+SO->NodeDim*ROId->nPath[0]),
22090                    (SO->NodeList+SO->NodeDim*ROId->nPath[ROId->N_n - 1]),
22091                    deuc);
22092    dd = -1.0;  dd_c = -1.0;
22093    if (option == SW_DrawROI_WhatDistAll) { /* do shortest distance */
22094       isNodeInMesh = (SUMA_Boolean*) SUMA_malloc(  SO->N_Node *
22095                                                    sizeof(SUMA_Boolean));
22096       N_left = SO->N_Node; for (i=0;i<N_left;++i) isNodeInMesh[i] = YUP;
22097       if (!isNodeInMesh) {
22098          SUMA_SL_Err("Failed to allocate!\n"
22099                      "Will not compute shortest distance.");
22100       }else {
22101          nPath = SUMA_Dijkstra ( SO, ROId->nPath[0],
22102                                  ROId->nPath[ROId->N_n - 1],
22103                                  isNodeInMesh, &N_left, 1, &dd, &N_n);
22104          if (nPath) {
22105             SUMA_free(nPath);
22106             nPath = NULL;
22107             dd_c = dd / SUMA_FS_DIJKSTRA_DISTANCE_FACTOR;
22108          } else {
22109             dd = -2.0;  dd_c = -2.0;
22110          }
22111          SUMA_free(isNodeInMesh); isNodeInMesh = NULL;
22112       }
22113       SS = SUMA_StringAppend_va(SS,
22114          "#Distances on %s\n"
22115          "#n0\tn1\tN_n\td\td_c\tds\tds_c\td3\n"
22116          "%d\t%d\t%d\t%.2f\t%.2f\t%.2f\t%.2f\t%.2f\n",
22117          SO->Label, ROId->nPath[0], ROId->nPath[ROId->N_n - 1],
22118          ROId->N_n, ds, ds_c, dd, dd_c, deuc);
22119    } else if (option == SW_DrawROI_WhatDistTrace) {
22120       SS = SUMA_StringAppend_va(SS,
22121          "#Distances on %s\n"
22122          "#n0\tn1\tN_n\td\td_c\td3\n"
22123          "%d\t%d\t%d\t%.2f\t%.2f\t%.2f\n",
22124          SO->Label, ROId->nPath[0], ROId->nPath[ROId->N_n - 1],
22125          ROId->N_n, ds, ds_c, deuc);
22126    }
22127 
22128    SUMA_SS2S(SS,s);
22129    if (out) fprintf(out, "%s", s);
22130 
22131    SUMA_L_Text("%s",s);
22132 
22133    SUMA_free (s); s= NULL;
22134    SUMA_RETURNe;
22135 }
22136 /*!
22137    \brief Show contents of a drawn ROI
22138    SUMA_ShowDrawnROI (ROI, Out, ShortVersion);
22139 
22140    \param ROId (SUMA_DRAWN_ROI *)
22141    \param Out (FILE *) (stderr if NULL)
22142    \param ShortVersion (SUMA_Boolean) if YUP, short version
22143 
22144 */
SUMA_ShowDrawnROI(SUMA_DRAWN_ROI * D_ROI,FILE * out,SUMA_Boolean ShortVersion)22145 void SUMA_ShowDrawnROI (SUMA_DRAWN_ROI *D_ROI, FILE *out,
22146                         SUMA_Boolean ShortVersion)
22147 {
22148    static char FuncName[]={"SUMA_ShowDrawnROI"};
22149    int i;
22150 
22151    SUMA_ENTRY;
22152 
22153    if (!out) out = SUMA_STDERR;
22154 
22155    fprintf(out, "--------------------------------------------\n");
22156 
22157    if (!D_ROI) {
22158       fprintf(out, "%s: NULL D_ROI\n", FuncName);
22159       SUMA_RETURNe;
22160    }
22161 
22162    fprintf(out, "%s: ROI Label %s, Type %d, DrawStatus %d\n"
22163                 " Idcode %s, Parent Idcode %s, Side %s\n",
22164          FuncName, D_ROI->Label, D_ROI->Type, D_ROI->DrawStatus,
22165          D_ROI->idcode_str, D_ROI->Parent_idcode_str,
22166          SUMA_SideName(D_ROI->Parent_side) );
22167 
22168    if (D_ROI->ActionStack) {
22169       fprintf (out, "%s: There are %d actions in the ActionStack.\n",
22170                      FuncName, dlist_size(D_ROI->ActionStack));
22171    }else {
22172       fprintf (out, "%s: ActionStack is NULL.\n", FuncName);
22173    }
22174 
22175    if (!D_ROI->ROIstrokelist) {
22176       fprintf(out, "%s: NULL ROIstrokelist.\n", FuncName);
22177       SUMA_RETURNe;
22178    }
22179 
22180 
22181    if (!dlist_size(D_ROI->ROIstrokelist)) {
22182       fprintf(out, "%s: ROIstrokelist is empty.\n", FuncName);
22183    } else {
22184       DListElmt *NextElm=NULL;
22185       int cnt = 0;
22186       fprintf(out, "%s: ROIstrokelist has %d elements.\n",
22187                      FuncName, dlist_size(D_ROI->ROIstrokelist));
22188       do {
22189 
22190          if (!NextElm) NextElm = dlist_head(D_ROI->ROIstrokelist);
22191          else NextElm = dlist_next(NextElm);
22192          ++cnt;
22193          fprintf(out, "%d\t+++++++++++\n", cnt);
22194          SUMA_ShowDrawnROIDatum ((SUMA_ROI_DATUM *)NextElm->data, out, ShortVersion);
22195       } while (NextElm != dlist_tail(D_ROI->ROIstrokelist));
22196    }
22197 
22198    fprintf(out, "--------------------------------------------\n");
22199 
22200    SUMA_RETURNe;
22201 }
22202 
22203 /*!
22204    \brief SUMA_FillToMask_Engine (FN, Visited, Mask, seed, N_Visited, N_Node);
22205    the engine function for SUMA_FillToMask.
22206    replaces the recursive version now called SUMA_FillToMask_Engine_old
22207 */
SUMA_FillToMask_Engine(SUMA_NODE_FIRST_NEIGHB * FN,int * Visited,int * ROI_Mask,int nseed,int * N_Visited,int N_Node)22208 void SUMA_FillToMask_Engine (SUMA_NODE_FIRST_NEIGHB *FN, int *Visited, int *ROI_Mask,
22209                               int nseed, int *N_Visited, int N_Node)
22210 {
22211    static char FuncName[]={"SUMA_FillToMask_Engine"};
22212    int i, nnext;
22213    int *candidate = NULL;
22214    int N_candidate = 0;
22215    SUMA_Boolean LocalHead = NOPE;
22216 
22217    SUMA_ENTRY;
22218 
22219    candidate = (int *)SUMA_calloc(N_Node, sizeof(int));
22220    if (!candidate) {
22221       SUMA_SL_Crit("Failed to Allocate");
22222       SUMA_RETURNe;
22223    }
22224 
22225    do {
22226       if (!Visited[nseed]) { Visited[nseed] = 1; ++*N_Visited; } /* add the seed, if not added yet */
22227 
22228       for (i=0; i<FN->N_Neighb[nseed]; ++i) {
22229          nnext = FN->FirstNeighb[nseed][i];
22230          /* fprintf (SUMA_STDERR,"nnext=%d\n", nnext); fflush(SUMA_STDERR); */
22231          if (!Visited[nnext] && !ROI_Mask[nnext]) {
22232             /*fprintf (SUMA_STDERR,"N_candidate=%d\n", N_candidate);*/
22233             candidate[N_candidate] = nnext; ++N_candidate;
22234             Visited[nnext] = 1; ++*N_Visited;   /* add this candidate so you don't revisit it as a new candidate later */
22235          }
22236       }
22237       if (N_candidate) { /* Need this safeguard, in case there are no candidates.
22238                         Happened when fill area has one empty node in it only!
22239                         Fixed in Madison 06, ZSS*/
22240          nseed = candidate[N_candidate-1]; --N_candidate;
22241       }
22242    } while (N_candidate);
22243 
22244    if (candidate) SUMA_free(candidate); candidate = NULL;
22245    SUMA_RETURNe;
22246 }
22247 
22248 /*!
22249    \brief SUMA_FillToMask_Engine (FN, Visited, Mask, seed, N_Visited);
22250    the recursive function for SUMA_FillToMask.
22251    Do not use logging functions here.
22252 
22253    CAN cause Illegal instruction interrupts, bad for blood glucose levels.
22254    Need non recursive version (crashes at cnt = 70676)
22255 */
22256 
SUMA_FillToMask_Engine_old(SUMA_NODE_FIRST_NEIGHB * FN,int * Visited,int * ROI_Mask,int nseed,int * N_Visited)22257 void SUMA_FillToMask_Engine_old (SUMA_NODE_FIRST_NEIGHB *FN, int *Visited, int *ROI_Mask, int nseed, int *N_Visited)
22258 {
22259    int i, nnext;
22260    /* static cnt = 0;
22261    ++cnt;
22262    fprintf (SUMA_STDERR,"    cnt = %d\n", cnt); fflush(SUMA_STDERR); */
22263    Visited[nseed] = 1;
22264    ++*N_Visited;
22265    for (i=0; i<FN->N_Neighb[nseed]; ++i) {
22266       nnext = FN->FirstNeighb[nseed][i];
22267       /* fprintf (SUMA_STDERR,"nnext=%d\n", nnext); fflush(SUMA_STDERR); */
22268       if (!Visited[nnext] && !ROI_Mask[nnext]) {
22269          /*fprintf (SUMA_STDERR,"In!\n"); fflush(SUMA_STDERR); */
22270          SUMA_FillToMask_Engine_old(FN, Visited, ROI_Mask, nnext, N_Visited);
22271       }
22272    }
22273    /* --cnt; */
22274    return;
22275 }
22276 /*!
22277 \brief Returns the ROI formed by connected nodes that are bound by Mask
22278       ROIfill = SUMA_FillToMask (SO, ROI_Mask, FirstSurfNode);
22279 
22280 \param SO (SUMA_SurfaceObject *)
22281 \param ROI_Mask (int *) if (ROI_Mask[n]) then node n is a boundary
22282 \param FirstSurfNode (int) node index from which the fill begins.
22283 
22284 \return ROIfill (SUMA_ROI_DATUM *) of the type SUMA_ROI_NodeGroup
22285 \sa SUMA_FillToMask_Engine
22286 */
SUMA_FillToMask(SUMA_SurfaceObject * SO,int * ROI_Mask,int nseed)22287 SUMA_ROI_DATUM * SUMA_FillToMask(SUMA_SurfaceObject *SO, int *ROI_Mask, int nseed)
22288 {
22289    static char FuncName[]={"SUMA_FillToMask"};
22290    SUMA_ROI_DATUM *ROIfill = NULL;
22291    int *Visited = NULL;
22292    int N_Visited = 0, i, nnext;
22293    SUMA_Boolean LocalHead = NOPE;
22294 
22295    /* register at the first call only */
22296    SUMA_ENTRY;
22297 
22298    if (!ROI_Mask) {
22299       SUMA_S_Err("NULL Mask.");
22300       SUMA_RETURN(NULL);
22301    }
22302 
22303    /* make sure your seed is not on the edge */
22304    if (ROI_Mask[nseed]) {
22305       SUMA_S_Err("seed is on the edge.");
22306       SUMA_RETURN(NULL);
22307    }
22308 
22309    if (!Visited) { /* allocate */
22310       Visited = (int *)SUMA_calloc (SO->N_Node, sizeof (int));
22311       if (!Visited) {
22312          SUMA_S_Err("Could not allocate for Visited.");
22313          SUMA_RETURN(NULL);
22314       }
22315    }
22316 
22317    N_Visited = 0;
22318 
22319    SUMA_FillToMask_Engine (SO->FN, Visited, ROI_Mask, nseed, &N_Visited, SO->N_Node);
22320 
22321    if (LocalHead) fprintf (SUMA_STDERR, "%s: Found %d nodes to fill.\n", FuncName, N_Visited);
22322 
22323    ROIfill = SUMA_AllocROIDatum();
22324    ROIfill->Type = SUMA_ROI_NodeGroup;
22325 
22326    /* Now put the nodes in the path */
22327    ROIfill->N_n = N_Visited;
22328    ROIfill->nPath = (int *)SUMA_calloc (ROIfill->N_n, sizeof(int));
22329    if (!ROIfill->nPath) {
22330       SUMA_S_Err("Could not allocate for nPath.\n");
22331       if (Visited) SUMA_free(Visited);
22332       SUMA_RETURN(NULL);
22333    }
22334 
22335    N_Visited = 0;
22336    for (i=0; i<SO->N_Node; ++i) {
22337       if (Visited[i]) {
22338          ROIfill->nPath[N_Visited] = i;
22339          ++N_Visited;
22340       }
22341    }
22342 
22343    if (Visited) SUMA_free(Visited);
22344    SUMA_RETURN(ROIfill);
22345 }
22346 
22347 
22348 /*!
22349    \brief function to turn a set of nodes into a DrawnROI
22350 
22351    \param Node (int *) pointer to set of nodes forming ROI
22352                Redundant nodes are removed. Nodes are copied
22353                to new location so you can free this pointer
22354                if you wish.
22355    \param N_Node (int) number of nodes in ROI
22356    \param Value (int) to go in ROI->iLabel
22357    \param Parent_idcode_str (char *) to get copied into
22358          ROI->Parent_idcode_str
22359    \param Label (char *) to get copied into ROI->Label
22360    \param ColPlaneName (char *) to get copied into ROI->ColPlaneName
22361    \param FillColor (float[4])
22362    \param EdgeColor (float[4])
22363    \param EdgeThickness (int)
22364    \param ForDisplay (SUMA_Boolean) YUP: Prepare ROI for display
22365                                     (creates the contour for the ROI,
22366                                     requires that Parent surface object be loaded)
22367    \return ROI (SUMA_DRAWN_ROI *)
22368 
22369    - No DO/Undos possible in this format
22370 */
22371 
SUMA_1DROI_to_DrawnROI(int * Node,int N_Node,int Value,char * Parent_idcode_str,char * Label,char * ColPlaneName,float * FillColor,float * EdgeColor,int EdgeThickness,SUMA_DO * dov,int N_dov,SUMA_Boolean ForDisplay)22372 SUMA_DRAWN_ROI * SUMA_1DROI_to_DrawnROI (
22373    int *Node, int N_Node, int Value, char *Parent_idcode_str,
22374    char *Label, char *ColPlaneName,
22375    float *FillColor, float *EdgeColor, int EdgeThickness,
22376    SUMA_DO *dov, int N_dov, SUMA_Boolean ForDisplay)
22377 {
22378    static char FuncName[]={"SUMA_1DROI_to_DrawnROI"};
22379    SUMA_ROI_DATUM *ROI_Datum = NULL;
22380    SUMA_DRAWN_ROI *ROI = NULL;
22381    SUMA_Boolean LocalHead = NOPE;
22382 
22383    SUMA_ENTRY;
22384 
22385    if (!Node) SUMA_RETURN(NULL);
22386 
22387    /* allocate and initialize */
22388    ROI = SUMA_AllocateDrawnROI (Parent_idcode_str, SUMA_ROI_Finished,
22389                                SUMA_ROI_Collection,  Label,  Value);
22390 
22391    /* add the colors */
22392    SUMA_COPY_VEC(EdgeColor, ROI->EdgeColor, 4, float, float);
22393    SUMA_COPY_VEC(FillColor, ROI->FillColor, 4, float, float);
22394    ROI->EdgeThickness = EdgeThickness;
22395 
22396    /* fill in the only ROI datum */
22397    ROI_Datum = SUMA_AllocROIDatum ();
22398    ROI_Datum->action = SUMA_BSA_Undefined;
22399    if(LocalHead)
22400       fprintf (SUMA_STDERR,
22401                "%s: About to add %d nodes of value %d...\n",
22402                FuncName, N_Node, Value);
22403 
22404    ROI_Datum->nPath = SUMA_UniqueInt(Node, N_Node, &ROI_Datum->N_n, NOPE);
22405    if (!ROI_Datum->nPath) {
22406       SUMA_SLP_Crit("Failed to allocate");
22407       SUMA_RETURN(NOPE);
22408    }
22409    ROI_Datum->Type = SUMA_ROI_NodeGroup;
22410 
22411    SUMA_LH("Appending stroke");
22412    /* just append that baby */
22413    dlist_ins_next(ROI->ROIstrokelist, dlist_tail(ROI->ROIstrokelist),
22414                   (void *)ROI_Datum);
22415 
22416    if (ForDisplay) {
22417       /* You must find the contour by yourself. This is normally
22418       done when the status is set to SUMA_ROI_Finished via the
22419       action stack functions */
22420       {
22421          int *cNodes, N_cNodes, i=0;
22422          SUMA_Boolean Unique = NOPE;
22423          SUMA_SurfaceObject *SO=NULL;
22424          SUMA_LH("Getting Contour ");
22425          N_cNodes = 0;
22426          Unique = NOPE;
22427             /* Set to YUP if you have node indices listed more than once.
22428                            1D ROIs are uniquized in the reading functions*/
22429          cNodes = SUMA_NodesInROI (ROI, &N_cNodes, Unique);
22430          if (cNodes) {
22431             if (!(SO = SUMA_findSOp_inDOv(ROI->Parent_idcode_str, dov, N_dov))) {
22432                SUMA_SLP_Err("No surface found");
22433                SUMA_RETURN(NOPE);
22434             }
22435             for (i=0; i<N_cNodes; ++i) {
22436                if (cNodes[i] < 0 || cNodes[i] >= SO->N_Node) {
22437                   SUMA_SLP_Err("Nodes in ROI negative, or >= SO->N_Node");
22438                   SUMA_RETURN(NOPE);
22439                }
22440             }
22441             ROI->CE = SUMA_GetContour (
22442                         SO,
22443                         cNodes, N_cNodes, &(ROI->N_CE),
22444                         0, NULL, NULL, 1);
22445             if (!ROI->CE) { SUMA_LH("Null DrawnROI->CE"); }
22446             else { SUMA_LH("Good DrawnROI->CE"); }
22447             SUMA_free(cNodes);
22448          }
22449       }
22450    }
22451    SUMA_RETURN(ROI);
22452 }
22453 
22454 /* ------------------------------------------------------------
22455    A set of functions to keep track of rendering state changes.
22456    A function to keep track of OpenGL's rendering state changes.
22457    The idea is to be able to leave things as they were at a
22458    particular point, no matter what functions do in the meanwhile.
22459    ------------------------------------------------------------ */
22460 /*!
22461 
22462    SUMA_GLStateTrack(char *action, DList **stu, char *progenitor,
22463                      char *state, void *val);
22464 
22465    action (char *): "n" for "new" return a new empty list of states.
22466                           Use "new" when you want to set a
22467                           starting point for recording the state changes
22468                     "s" for "set" set a particular state:
22469                           if state has not been set yet,
22470                               create an entry for it
22471                               record its current value
22472                           set state value per user's request
22473                     "f" for "force" reset the initial value of a state
22474                            if state has not been set yet,
22475                               set state value per user's request
22476                            else modifiy initial state value to user's request
22477                     "r" for "revert" undo all the state settings in the  list
22478                              delete list and return NULL
22479                     "k" for "kill" delete list without reverting to initial
22480                                    states
22481    stu (DList **): Linked list keeping track of states that get modified
22482                   *stu should be NULL when calling with action "new"
22483                   *stu is set to NULL after actions "r" or "k"
22484    progenitor (char *): Who is issuing these actions? Just for debugging.
22485    state (char *): Name of state to be acted on. Examples include:
22486                   "GL_LIGHTING", "GL_POLYGON_STIPPLE", etc.
22487    val (void *): The value for the state. In most cases this is just
22488                  0 or 1, for disable or enable, respectively.
22489 
22490    SEE ALSO: SUMA_RecordEnablingState() and SUMA_RestoreEnablingState()
22491 */
SUMA_GLStateTrack(char * action,DList ** stu,char * progenitor,char * state,void * val)22492 int SUMA_GLStateTrack(char *action, DList **stu, char *progenitor,
22493                       char *state, void *val)
22494 {
22495    static char FuncName[]={"SUMA_GLStateTrack"};
22496    DList *st=NULL;
22497    DListElmt *el=NULL;
22498    SUMA_GL_STEL *stel=NULL;
22499    SUMA_Boolean LocalHead = NOPE;
22500 
22501    SUMA_ENTRY;
22502 
22503    if (!action || !stu) {
22504       SUMA_S_Err("Bad action, or bad stu");
22505       SUMA_RETURN(0);
22506    }
22507 
22508    st = *stu;
22509 
22510    SUMA_LHv("Action %s, st=%p, progenitor %s, state %s, val %p\n",
22511             action, st, CHECK_NULL_STR(progenitor), CHECK_NULL_STR(state), val);
22512    /* A new tracking list */
22513    if (action[0] == 'n') {
22514       if (st != NULL) {
22515          SUMA_S_Err("When calling with new, need to have *stu = NULL");
22516          SUMA_RETURN(0);
22517       }
22518       st = (DList *)SUMA_calloc(1, sizeof(DList));
22519       *stu = st;
22520       dlist_init(st, SUMA_FreeStateTrackEl);
22521       SUMA_RETURN(1);
22522    }
22523 
22524    /* A dump of the tracking list */
22525    if (action[0] == 'd') {/* short for !strcmp(action, "dump") */
22526       if (st == NULL) {
22527          fprintf(SUMA_STDERR, "NULL tracking list\n");
22528          SUMA_RETURN(0);
22529       }
22530       fprintf(SUMA_STDERR, "%d element in tracking list\n", dlist_size(st));
22531       do {
22532          if (!el) el = dlist_head(st);
22533          else el = el->next;
22534          stel = (SUMA_GL_STEL *)el->data;
22535          fprintf(SUMA_STDERR, "%s now %s, initial %s, by %s\n",
22536                   stel->state_s, stel->now_s, stel->init_s, stel->whodunit);
22537       } while (el);
22538       SUMA_RETURN(1);
22539    }
22540 
22541    /* Set, or force set a state */
22542    if (action[0] == 's' || action[0] == 'f') { /* set or force */
22543       if (st == NULL) { /* no tracking, just do it */
22544          SUMA_LH("No tracking");
22545          stel = SUMA_NewStateTrackEl(state, progenitor);
22546          if (!SUMA_SetTrackElVal(stel, val, "apply")) {
22547             SUMA_S_Err("Failed setting state val");
22548             SUMA_free(stel); stel=NULL;
22549             SUMA_RETURN(0);
22550          }
22551          SUMA_free(stel); stel=NULL;
22552          SUMA_RETURN(1);
22553       }
22554       if (!(stel = SUMA_FindStateTrackEl(state, st))) { /* a new one */
22555          SUMA_LH("New stel");
22556          stel = SUMA_NewStateTrackEl(state, progenitor);
22557          if (!SUMA_SetTrackElVal(stel, val, "save")) {
22558             SUMA_S_Err("Failed setting state val");
22559             SUMA_free(stel); stel=NULL;
22560             SUMA_RETURN(0);
22561          }
22562          /* add to list */
22563          dlist_ins_next(st, dlist_tail(st), (void *)stel);
22564       } else { /* an existing one */
22565          SUMA_LH("Reuse stel");
22566          if (!SUMA_SetTrackElVal(stel, val,
22567                                  (action[0] == 'f') ? "save":"apply")) {
22568             SUMA_S_Err("Failed updating state val");
22569             SUMA_free(stel); stel=NULL;
22570             SUMA_RETURN(0);
22571          }
22572       }
22573       SUMA_RETURN(1);
22574    }
22575 
22576    /* revert all to initial state */
22577    if (action[0] == 'r' || action[0] == 'k') { /* revert or kill */
22578       if (st == NULL) {
22579          fprintf(SUMA_STDERR, "NULL tracking list, cannot revert\n");
22580          SUMA_RETURN(0);
22581       }
22582       if (dlist_size(st)) {
22583          do {
22584             if (!el) el = dlist_head(st);
22585             else el = el->next;
22586             if (el) {
22587                stel = (SUMA_GL_STEL *)el->data;
22588                if (action[0] == 'r') { /* revert */
22589                   SUMA_LHv("reverting %s\n", stel->state_s);
22590                   SUMA_SetTrackElVal(stel, NULL, "revert");
22591                   SUMA_LHv("  reverted%s\n", stel->state_s);
22592                }
22593             }
22594          } while (el && (el != dlist_tail(st)));
22595       }
22596       /* destroy list */
22597       SUMA_LH("Shiva time");
22598       dlist_destroy(st); SUMA_free(st); st = NULL;
22599       *stu = NULL;
22600       SUMA_RETURN(1);
22601    }
22602 
22603    SUMA_S_Err("Had nothing to do");
22604    SUMA_RETURN(0);
22605 }
22606 
22607 /* Only put states that are controlled by glEnable/glDisable here */
SUMA_GLstateToEnum(char * state)22608 int SUMA_GLstateToEnum(char *state) {
22609    if (!state) return(-1);
22610    if (!strcmp(state,"GL_LIGHTING")) return(GL_LIGHTING);
22611    if (!strcmp(state,"GL_POLYGON_STIPPLE")) return(GL_POLYGON_STIPPLE);
22612    if (!strcmp(state,"GL_DEPTH_TEST")) return(GL_DEPTH_TEST);
22613    if (!strcmp(state,"GL_POLYGON_OFFSET_FILL")) return(GL_POLYGON_OFFSET_FILL);
22614    return(-2);
22615 }
22616 
22617 /* Only put states that are controlled by glEnable/glDisable here */
SUMA_EnumToGLstate(int glpar)22618 char *SUMA_EnumToGLstate(int glpar) {
22619    if (glpar==-1) return(NULL);
22620    if (glpar==GL_LIGHTING) return("GL_LIGHTING");
22621    if (glpar==GL_POLYGON_STIPPLE) return("GL_POLYGON_STIPPLE");
22622    if (glpar==GL_DEPTH_TEST) return("GL_DEPTH_TEST");
22623    if (glpar==GL_POLYGON_OFFSET_FILL) return("GL_POLYGON_OFFSET_FILL");
22624    return("unknown");
22625 }
22626 
22627 /*!
22628    Set gl state and keep tracking.
22629    if act[0] == "r" : Revert to initial setting. val is not needed.
22630       act[0] == "s" : Save initial setting and apply val.
22631       act[0] == "i" : Note initial setting, and apply nothing.
22632       act[0] == "a"  : Don't touch initial setting, just apply setting
22633                         in val
22634 */
SUMA_SetTrackElVal(SUMA_GL_STEL * stel,void * val,char * act)22635 int SUMA_SetTrackElVal(SUMA_GL_STEL *stel, void *val, char *act) {
22636    static char FuncName[]={"SUMA_SetTrackElVal"};
22637    GLenum glpar;
22638    SUMA_Boolean LocalHead = NOPE;
22639 
22640    SUMA_ENTRY;
22641 
22642    if (!stel || !act) {
22643       SUMA_S_Err("Nothing to do");
22644       SUMA_RETURN(0);
22645    }
22646 
22647    if (act[0] != 'r' && act[0] != 's' && act[0] != 'a' && act[0] != 'i') {
22648       SUMA_S_Errv("Bad act==%s\n", act)
22649       SUMA_RETURN(0);
22650    }
22651 
22652    SUMA_LHv("---->Have %s, init_s %s, now_s %s, act %s, val %p\n",
22653             stel->state_s, stel->init_s, stel->now_s, act, val);
22654 
22655    if ((glpar = (GLenum)SUMA_GLstateToEnum(stel->state_s)) >= 0) {
22656       if (act[0] != 'r') {
22657          if (act[0] == 's' || act[0] == 'i') {
22658             stel->init_i = (int)glIsEnabled(glpar);
22659             sprintf(stel->init_s,"%d", stel->init_i);
22660             if (act[0] == 'i') {
22661                stel->now_i = stel->init_i;
22662                sprintf(stel->now_s,"%d", stel->now_i);
22663             }
22664          }
22665          if (act[0] == 'a' || act[0] == 's') {
22666             {  /* Note, than when passing a '0' for disable, val == NULL,
22667                   so you can't object to a NULL val, or use it as a special
22668                   flag */
22669                stel->now_i = (int)(val?1:0);
22670                sprintf(stel->now_s,"%d", stel->now_i);
22671             }
22672          }
22673          /* apply */
22674          if (act[0] != 'i') {
22675             if (stel->now_i) glEnable(glpar);
22676             else glDisable(glpar);
22677          }
22678       } else { /* revert to initial setting */
22679          if (stel->now_i != stel->init_i) {
22680             if (stel->init_i) glEnable(glpar);
22681             else glDisable(glpar);
22682             stel->now_i = stel->init_i;
22683          }
22684       }
22685    } else if (!strcmp(stel->state_s,"glPolygonOffset")) {
22686       if (act[0] != 'r') {
22687          if (act[0] == 's' || act[0] == 'i') {
22688             glGetFloatv(GL_POLYGON_OFFSET_FACTOR, stel->init_f4);
22689             glGetFloatv(GL_POLYGON_OFFSET_UNITS, stel->init_f4+1);
22690             sprintf(stel->init_s,"%f, %f", stel->init_f4[0], stel->init_f4[1]);
22691             if (act[0] == 'i') {
22692                stel->now_f4[0] = stel->init_f4[0];
22693                stel->now_f4[1] = stel->init_f4[1];
22694                sprintf(stel->now_s,"%f, %f",
22695                            stel->now_f4[0], stel->now_f4[1]);
22696             }
22697          }
22698          if (act[0] == 'a' || act[0] == 's') {
22699             if (!val) {
22700                SUMA_S_Warn("Nothing to do here");
22701                SUMA_RETURN(0);
22702             } else {
22703                float *fv=(float*)val;
22704                stel->now_f4[0] = fv[0];
22705                stel->now_f4[1] = fv[1];
22706                sprintf(stel->now_s,"%f, %f",
22707                            stel->now_f4[0], stel->now_f4[1]);
22708             }
22709          }
22710          /* apply */
22711          if (act[0] != 'i') {
22712             glPolygonOffset(stel->now_f4[0], stel->now_f4[1]);
22713          }
22714       } else { /* revert to initial setting */
22715          if (stel->now_f4[0] != stel->init_f4[0] ||
22716              stel->now_f4[1] != stel->init_f4[1]) {
22717             glPolygonOffset(stel->init_f4[0], stel->init_f4[1]);
22718             stel->now_f4[0] = stel->init_f4[0];
22719             stel->now_f4[1] = stel->init_f4[1];
22720          }
22721       }
22722    } else if (!strcmp(stel->state_s,"glPolygonMode")) {
22723       if (act[0] != 'r') {
22724          if (act[0] == 's' || act[0] == 'i') {
22725                /* This is a little problematic. While I can set
22726                polygon mode separately for FRONT and BACK or triangles,
22727                I can only query state common to front and and back ... */
22728             stel->init_f4[0] = (float)GL_FRONT_AND_BACK; /* no choice */
22729             glGetFloatv(GL_POLYGON_MODE, stel->init_f4+1);
22730             sprintf(stel->init_s,"%d, %d",
22731                   (int)stel->init_f4[0], (int)stel->init_f4[1]);
22732             if (act[0] == 'i') {
22733                stel->now_f4[0] = stel->init_f4[0];
22734                stel->now_f4[1] = stel->init_f4[1];
22735                sprintf(stel->now_s,"%d, %d",
22736                            (int)stel->now_f4[0], (int)stel->now_f4[1]);
22737             }
22738          }
22739          if (act[0] == 'a' || act[0] == 's') {
22740             if (!val) {
22741                SUMA_S_Warn("Nothing to do here");
22742                SUMA_RETURN(0);
22743             } else {
22744                float *fv=(float*)val;
22745                stel->now_f4[0] = fv[0];
22746                stel->now_f4[1] = fv[1];
22747                sprintf(stel->now_s,"%d, %d",
22748                            (int)stel->now_f4[0], (int)stel->now_f4[1]);
22749             }
22750          }
22751          /* apply */
22752          if (act[0] != 'i') {
22753             glPolygonOffset((GLenum)stel->now_f4[0], (GLenum)stel->now_f4[1]);
22754          }
22755       } else { /* revert to initial setting */
22756          if (stel->now_f4[0] != stel->init_f4[0] ||
22757              stel->now_f4[1] != stel->init_f4[1]) {
22758             glPolygonOffset((GLenum)stel->init_f4[0], (GLenum)stel->init_f4[1]);
22759             stel->now_f4[0] = stel->init_f4[0];
22760             stel->now_f4[1] = stel->init_f4[1];
22761          }
22762       }
22763    } else {
22764       SUMA_S_Errv("Not ready to set anything for %s\n", stel->init_s);
22765       SUMA_RETURN(0);
22766    }
22767 
22768    SUMA_LHv("---->On output %s, init_s %s, now_s %s, act %s, val %p\n",
22769             stel->state_s, stel->init_s, stel->now_s, act, val);
22770    SUMA_RETURN(1);
22771 }
22772 
SUMA_NewStateTrackEl(char * state,char * progenitor)22773 SUMA_GL_STEL *SUMA_NewStateTrackEl(char *state, char *progenitor) {
22774    static char FuncName[]={"SUMA_NewStateTrackEl"};
22775    SUMA_GL_STEL *stel=NULL;
22776 
22777    SUMA_ENTRY;
22778 
22779    if (!state) {
22780       SUMA_S_Err("Nothing to do");
22781       SUMA_RETURN(stel);
22782    }
22783 
22784    stel = (SUMA_GL_STEL *)SUMA_calloc(1, sizeof(SUMA_GL_STEL));
22785    strcpy(stel->state_s,state);
22786 
22787    if (!progenitor) progenitor = "unknown";
22788    strcpy(stel->whodunit,progenitor);
22789 
22790 
22791    SUMA_RETURN(stel);
22792 }
22793 
SUMA_FreeStateTrackEl(void * stel)22794 void SUMA_FreeStateTrackEl(void *stel) {
22795    if (stel) {
22796       SUMA_free(stel);
22797    }
22798    return;
22799 }
SUMA_FindStateTrackEl(char * state,DList * st)22800 SUMA_GL_STEL *SUMA_FindStateTrackEl(char *state, DList *st) {
22801    static char FuncName[]={"SUMA_FindStateTrackEl"};
22802    DListElmt *el=NULL;
22803    SUMA_GL_STEL *stel=NULL;
22804 
22805    SUMA_ENTRY;
22806    if (!state || !st) SUMA_RETURN(NULL);
22807    if (!dlist_size(st)) SUMA_RETURN(NULL);
22808    do {
22809       if (!el) el = dlist_head(st);
22810       else el = el->next;
22811       if (el) {
22812          stel = (SUMA_GL_STEL *)el->data;
22813          if (!strcmp(stel->state_s, state)) SUMA_RETURN(stel);
22814       }
22815    } while (el && (el != dlist_tail(st)));
22816 
22817    SUMA_RETURN(NULL);
22818 }
22819 
22820 /* ------------------------------------------------------------ */
22821 
22822 /* Stippling masks for transparency */
22823 static int stippleMask_shft[17] = { 0, 0, 0, 0, 0,
22824                                     0, 0, 0, 0, 0,
22825                                     0, 0, 0, 0, 0,
22826                                     0, 0 };
22827 static int shift_by_type[17] = { -2, -2, -2, -2, -2,
22828                                     -2, -2, -2, -2, -2,
22829                                     -2, -2, -2, -2, -2,
22830                                     -2, -2 };;
22831 
22832 static GLubyte stippleMask[17][128] =
22833 {
22834   /* NOTE: 0% opaqueness is faster to set and probably faster to render with:
22835 	glDisable(GL_POLYGON_STIPPLE);
22836 	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); */
22837   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22838     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22839     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22840     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22841     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22842     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22843     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22844     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
22845 
22846   {0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22847     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22848     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22849     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22850     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22851     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22852     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22853     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
22854 
22855   {0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
22856     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
22857     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
22858     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
22859     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
22860     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
22861     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
22862     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00},
22863 
22864   {0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
22865     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
22866     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
22867     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
22868     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
22869     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
22870     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
22871     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00},
22872 
22873   {0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
22874     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
22875     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
22876     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
22877     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
22878     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
22879     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
22880     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00},
22881 
22882   {0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
22883     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
22884     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
22885     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
22886     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
22887     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
22888     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
22889     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00},
22890 
22891   {0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
22892     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
22893     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
22894     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
22895     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
22896     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
22897     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
22898     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11},
22899 
22900   {0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
22901     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
22902     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
22903     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
22904     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
22905     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
22906     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
22907     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11},
22908 
22909   {0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
22910     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
22911     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
22912     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
22913     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
22914     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
22915     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
22916     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55},
22917 
22918   {0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
22919     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
22920     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
22921     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
22922     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
22923     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
22924     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
22925     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55},
22926 
22927   {0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
22928     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
22929     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
22930     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
22931     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
22932     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
22933     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
22934     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55},
22935 
22936   {0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
22937     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
22938     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
22939     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
22940     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
22941     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
22942     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
22943     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55},
22944 
22945   {0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
22946     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
22947     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
22948     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
22949     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
22950     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
22951     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
22952     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55},
22953 
22954   {0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
22955     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
22956     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
22957     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
22958     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
22959     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
22960     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
22961     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55},
22962 
22963   {0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
22964     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
22965     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
22966     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
22967     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
22968     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
22969     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
22970     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77},
22971 
22972   {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
22973     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
22974     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
22975     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
22976     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
22977     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
22978     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
22979     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77},
22980 
22981   /* NOTE: 100% opaqueness is faster to set and probably faster to render with:
22982         glDisable(GL_POLYGON_STIPPLE); */
22983   {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
22984     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
22985     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
22986     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
22987     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
22988     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
22989     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
22990     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
22991 };
22992 
22993 const GLubyte stippleMask_init[17][128] =
22994 {
22995   /* NOTE: 0% opaqueness is faster to set and probably faster to render with:
22996 	glDisable(GL_POLYGON_STIPPLE);
22997 	glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE); */
22998   {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
22999     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23000     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23001     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23002     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23003     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23004     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23005     0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
23006 
23007   {0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23008     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23009     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23010     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23011     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23012     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23013     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
23014     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
23015 
23016   {0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
23017     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
23018     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
23019     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
23020     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
23021     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
23022     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
23023     0x88, 0x88, 0x88, 0x88, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00},
23024 
23025   {0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
23026     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
23027     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
23028     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
23029     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
23030     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
23031     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00,
23032     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x22, 0x00, 0x00, 0x00, 0x00},
23033 
23034   {0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
23035     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
23036     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
23037     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
23038     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
23039     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
23040     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
23041     0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00},
23042 
23043   {0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
23044     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
23045     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
23046     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
23047     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
23048     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
23049     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00,
23050     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x00, 0x00, 0x00, 0x00},
23051 
23052   {0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
23053     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
23054     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
23055     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
23056     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
23057     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
23058     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
23059     0xaa, 0xaa, 0xaa, 0xaa, 0x44, 0x44, 0x44, 0x44, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11},
23060 
23061   {0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
23062     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
23063     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
23064     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
23065     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
23066     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
23067     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11,
23068     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x11, 0x11, 0x11, 0x11},
23069 
23070   {0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
23071     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
23072     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
23073     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
23074     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
23075     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
23076     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
23077     0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55},
23078 
23079   {0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
23080     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
23081     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
23082     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
23083     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
23084     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
23085     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55,
23086     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xaa, 0xaa, 0xaa, 0xaa, 0x55, 0x55, 0x55, 0x55},
23087 
23088   {0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
23089     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
23090     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
23091     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
23092     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
23093     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
23094     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
23095     0xee, 0xee, 0xee, 0xee, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55},
23096 
23097   {0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
23098     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
23099     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
23100     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
23101     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
23102     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
23103     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55,
23104     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xbb, 0xbb, 0xbb, 0xbb, 0x55, 0x55, 0x55, 0x55},
23105 
23106   {0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
23107     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
23108     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
23109     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
23110     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
23111     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
23112     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
23113     0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55},
23114 
23115   {0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
23116     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
23117     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
23118     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
23119     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
23120     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
23121     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55,
23122     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x55, 0x55, 0x55, 0x55},
23123 
23124   {0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
23125     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
23126     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
23127     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
23128     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
23129     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
23130     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
23131     0xff, 0xff, 0xff, 0xff, 0xdd, 0xdd, 0xdd, 0xdd, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77},
23132 
23133   {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
23134     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
23135     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
23136     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
23137     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
23138     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
23139     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77,
23140     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x77, 0x77, 0x77, 0x77},
23141 
23142   /* NOTE: 100% opaqueness is faster to set and probably faster to render with:
23143         glDisable(GL_POLYGON_STIPPLE); */
23144   {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
23145     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
23146     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
23147     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
23148     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
23149     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
23150     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
23151     0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
23152 };
23153 
SUMA_StippleMaskResest(void)23154 void SUMA_StippleMaskResest(void) {
23155    int n;
23156    for (n=0; n<17; ++n) {
23157       if (stippleMask_shft[n]) {
23158          memcpy(stippleMask[n], stippleMask_init[n], 128*sizeof(GLubyte));
23159          stippleMask_shft[n] = 0;
23160          shift_by_type[n]=-2;
23161       }
23162    }
23163    return;
23164 }
23165 
SUMA_StippleMaskShift(GLubyte * mm)23166 GLubyte * SUMA_StippleMaskShift(GLubyte *mm) {
23167    static GLubyte bt[1024], b0;
23168    int n, nbits, n8, k;
23169 
23170    /* Turn stipple mask to pixel mask of 0s and 1s */
23171    for (n=0; n<128; ++n) {
23172       n8 = 8*n;
23173       bt[n8+0] =  ( (mm[n] & ( 1 << 0 )) >> 0 ) ;
23174       bt[n8+1] =  ( (mm[n] & ( 1 << 1 )) >> 1 ) ;
23175       bt[n8+2] =  ( (mm[n] & ( 1 << 2 )) >> 2 ) ;
23176       bt[n8+3] =  ( (mm[n] & ( 1 << 3 )) >> 3 ) ;
23177       bt[n8+4] =  ( (mm[n] & ( 1 << 4 )) >> 4 ) ;
23178       bt[n8+5] =  ( (mm[n] & ( 1 << 5 )) >> 5 ) ;
23179       bt[n8+6] =  ( (mm[n] & ( 1 << 6 )) >> 6 ) ;
23180       bt[n8+7] =  ( (mm[n] & ( 1 << 7 )) >> 7 ) ;
23181    }
23182    /* offset each row of the 32x32 pixel mask */
23183    for (n=0; n<32; ++n) {
23184       b0 = bt[n*32];
23185       for (k=0; k<31; ++k) {
23186          n8 = k+n*32;
23187          bt[n8] = bt[n8+1];
23188       }
23189       bt[31+n*32] = b0;
23190    }
23191 
23192    /* Now recreate stipple mask  */
23193    for (n=0; n<128; ++n) {
23194       n8 = 8*n;
23195       mm[n] =  ( bt[n8  ] << 0 ) | ( bt[n8+1] << 1 ) | ( bt[n8+2] << 2 )  |
23196                ( bt[n8+3] << 3 ) | ( bt[n8+4] << 4 ) | ( bt[n8+5] << 5 )  |
23197                ( bt[n8+6] << 6 ) | ( bt[n8+7] << 7 ) ;
23198    }
23199 
23200    return(mm);
23201 }
23202 
SUMA_StippleMask(int transp)23203 const GLubyte *SUMA_StippleMask(int transp) {
23204    if (transp < STM_0 || transp > STM_16) {
23205       fprintf(stderr,"Error SUMA_StippleMask: Bad transp %d\n", transp);
23206       transp = STM_0;
23207    }
23208    transp = transp - STM_0;
23209    return((const GLubyte *)stippleMask[16-transp]);
23210 }
23211 
23212 /* If btp >=0, then a mask shift is done only if the last call
23213    performed a shift with the same btp .
23214    This option is useful is you're grouping object types and
23215    want the shifting to be done the same way for a particular
23216    type of objects.
23217    The ideal case of shifting with each new object is problematic
23218    because we can't shift a whole lot for certain masks without creating
23219    differing overlaps. For instance, say you have two surfaces and a
23220    volume. If you use a different mask for each object at 50% shifts,
23221    and with rendering order surf1, surf2, vol, then vol will end up
23222    obscuring surf1 because two shifts get you back to the same mask.
23223    One could do with random mask patterns and be better off in terms of
23224    occlusion, but random mask patterns are ugly, though they may work once I
23225    introduce convolution options for the final image. For now, deciding on shifts
23226    by object type might work a little better, as long as the types are grouped
23227    together                                        ZSS March 13 2014    */
SUMA_StippleMask_shift(int transp,int btp)23228 const GLubyte *SUMA_StippleMask_shift(int transp, int btp) {
23229    const GLubyte *mm=NULL;
23230    if (transp < STM_0 || transp > STM_16) {
23231       fprintf(stderr,"Error SUMA_StippleMask: Bad transp %d\n", transp);
23232       transp = STM_0;
23233    }
23234    transp = transp - STM_0;
23235    if (btp >= 0 && shift_by_type[16-transp] == btp) {
23236       /* don't shift any more, same type as last time */
23237       mm = (const GLubyte *)stippleMask[16-transp];
23238    } else {
23239       mm = (const GLubyte *)SUMA_StippleMaskShift(stippleMask[16-transp]);
23240       ++stippleMask_shft[16-transp];
23241       shift_by_type[16-transp] = btp;
23242    }
23243    return(mm);
23244 }
23245 
SUMA_StippleMask_rand(int transp)23246 const GLubyte *SUMA_StippleMask_rand(int transp) {
23247    GLubyte bt[1024];
23248    static GLubyte sm[128];
23249    static int seed = 0;
23250    int n, nbits, *ir=NULL, n8;
23251 
23252    if (transp < STM_0 || transp > STM_16) {
23253       fprintf(stderr,"Error SUMA_StippleMask: Bad transp %d\n", transp);
23254       transp = STM_0;
23255    }
23256 
23257    transp = transp - STM_0;
23258    nbits = (int)((float)transp/16.0*1024);
23259    ir = z_rand_order(0, 1023, seed++);
23260    if (transp <= 8) {
23261       memset(bt, 1, sizeof(GLubyte)*1024);
23262       for (n=0; n<nbits; ++n) bt[ir[n]]=0;
23263    } else {
23264       memset(bt, 0, sizeof(GLubyte)*1024);
23265       for (n=0; n<1024-nbits; ++n) bt[ir[n]]=1;
23266    }
23267    SUMA_free(ir); ir=NULL;
23268    /* turn to byte stipple mask */
23269    for (n=0; n<128; ++n) {
23270       n8 = 8*n;
23271       sm[n] =  ( bt[n8  ] << 0 ) | ( bt[n8+1] << 1 ) | ( bt[n8+2] << 2 )  |
23272                ( bt[n8+3] << 3 ) | ( bt[n8+4] << 4 ) | ( bt[n8+5] << 5 )  |
23273                ( bt[n8+6] << 6 ) | ( bt[n8+7] << 7 ) ;
23274    }
23275    return((const GLubyte *)sm);
23276 }
23277 
23278 /* Chunky stippling pattern
23279 Valid stip values are from 0 (no holes) to 16 (nothing shown) inclusive */
SUMA_StippleLineMask_rand(int stip,int chunk_width,int rseed)23280 GLushort SUMA_StippleLineMask_rand(int stip, int chunk_width, int rseed) {
23281    GLubyte bt[16];
23282    static GLushort sm;
23283    static int seed = 0;
23284    int n, *ir=NULL, maxchunks, nchunks, maxlevel=16,
23285        j0, j1, transp;
23286 
23287    if (chunk_width < 1 || chunk_width > 16) {
23288       chunk_width = 2;
23289    }
23290 
23291    if (!(maxchunks = SUMA_ROUND(16/chunk_width))) {
23292       maxchunks = 1;
23293    }
23294 
23295    if (stip < 0  ||
23296        stip > 16) {
23297       fprintf(stderr,"Error SUMA_StippleMask_rand: Bad stip %d\n", stip);
23298       stip = 8;
23299    }
23300 
23301    if (stip == 16) return(0); /* nothing will be shown */
23302    else if (stip == 0) { /* no stippling */
23303       for (n=0; n<16; ++n)  sm = sm | 1 << n ;
23304       return(sm);
23305    }
23306 
23307    /* I'd rather think transparency */
23308    transp = 16-stip;
23309    if (!(nchunks = (int)((float)transp/maxlevel*maxchunks))) {
23310       nchunks = 1;
23311    }
23312 
23313    if (rseed) {
23314       ir = z_rand_order(0, maxchunks-1, seed++);
23315    } else {
23316       ir = z_rand_order(0, maxchunks-1, 1111);
23317    }
23318    memset(bt, 0, sizeof(GLubyte)*16);
23319    for (n=0; n<nchunks; ++n) {
23320       j0 = ir[n]*chunk_width; j1 = SUMA_MIN_PAIR(j0+chunk_width, 16);
23321       while(j0 < j1) {
23322          bt[j0]=1; ++j0;
23323       }
23324    }
23325       #if 0
23326    fprintf(stderr,"%d chunks (%d wide) @chunk indices[", nchunks, chunk_width);
23327    for (n=0; n<nchunks; ++n) { fprintf(stderr,"%d ", ir[n]); }
23328    fprintf(stderr,"]\n");
23329    for (n=0; n<16; ++n) {
23330       fprintf(stderr,"%d",bt[n]);
23331    }
23332    fprintf(stderr,"\n");
23333       #endif
23334    SUMA_free(ir); ir=NULL;
23335    /* turn to byte stipple mask */
23336    sm = 0;
23337    for (n=0; n<16; ++n) {
23338       sm = sm | bt[n] << n ;
23339    }
23340    return(sm);
23341 }
23342 
SUMA_cube_surface(float sz,float * cen)23343 SUMA_SurfaceObject *SUMA_cube_surface(float sz, float *cen)
23344 {
23345    static char FuncName[]={"SUMA_cube_surface"};
23346    float sz3[3];
23347    sz3[0]=sz/2.0; sz3[1]=-1.0;
23348    return(SUMA_box_surface(sz3,cen,NULL,1));
23349 }
23350 
SUMA_box_surface(float * hd3,float * cen,float * col,int n_obj)23351 SUMA_SurfaceObject *SUMA_box_surface(float *hd3, float *cen, float *col,
23352                                      int n_obj)
23353 {
23354    static char FuncName[]={"SUMA_box_surface"};
23355    int *FaceSetList=NULL;
23356    float *NodeList=NULL;
23357    int        Faces[12][3] = { {0 , 1 , 2 },
23358                                {0 , 2 , 3 },
23359                                {1 , 5 , 6 },
23360                                {1 , 6 , 2 },
23361                                {4 , 6 , 5 },
23362                                {4 , 7 , 6 },
23363                                {3 , 2 , 6 },
23364                                {3 , 6 , 7 },
23365                                {0 , 7 , 4 },
23366                                {0 , 3 , 7 },
23367                                {0 , 5 , 1 },
23368                                {0 , 4 , 5 } };
23369    float     Nodes[8][3]   = { {0.0 , 0.0 , 0.0},
23370                                {1.0 , 0.0 , 0.0},
23371                                {1.0 , 1.0 , 0.0},
23372                                {0.0 , 1.0 , 0.0},
23373                                {0.0 , 0.0 , 1.0},
23374                                {1.0 , 0.0 , 1.0},
23375                                {1.0 , 1.0 , 1.0},
23376                                {0.0 , 1.0 , 1.0} };
23377    float cen0[3] = { 0.0,  0.0, 0.0 };
23378    SUMA_SurfaceObject *SO=NULL;
23379    int i, iobj=0, ioff=0;
23380    float *tcen;
23381    SUMA_NEW_SO_OPT *nsoopt = NULL;
23382 
23383    SUMA_ENTRY;
23384 
23385    /* create a surface */
23386    nsoopt = SUMA_NewNewSOOpt();
23387 
23388    NodeList = (float *)
23389       SUMA_malloc(8*3*n_obj*sizeof(float));
23390    FaceSetList = (int *)SUMA_malloc(12*3*n_obj*sizeof(int));
23391 
23392    for (iobj=0; iobj<n_obj; ++iobj) {
23393       if (hd3[3*iobj+0] == 0.0f) hd3[3*iobj+0] = 0.5;
23394       if (hd3[3*iobj+1] <= 0.0f) {
23395          hd3[3*iobj+1] = hd3[3*iobj+0];
23396          hd3[3*iobj+2] = hd3[3*iobj+0];
23397       }
23398 
23399       if (!cen) tcen = (float *)cen0;
23400       else tcen = cen+3*iobj;
23401       ioff = 3*8*iobj;
23402       for (i=0; i<8; ++i) {
23403          NodeList[ioff+3*i  ] = (Nodes[i][0]-0.5)*2.0*hd3[3*iobj+0]+tcen[0];
23404          NodeList[ioff+3*i+1] = (Nodes[i][1]-0.5)*2.0*hd3[3*iobj+1]+tcen[1];
23405          NodeList[ioff+3*i+2] = (Nodes[i][2]-0.5)*2.0*hd3[3*iobj+2]+tcen[2];
23406       }
23407       for (i=0; i<12; ++i) {
23408          ioff = 3*12*iobj;
23409          FaceSetList[ioff+3*i  ] = Faces[i][0]+12*iobj;
23410          FaceSetList[ioff+3*i+1] = Faces[i][1]+12*iobj;
23411          FaceSetList[ioff+3*i+2] = Faces[i][2]+12*iobj;
23412       }
23413    }
23414    SO = SUMA_NewSO(&NodeList, 8*n_obj, &FaceSetList, 12*n_obj, nsoopt);
23415    if (col) {
23416       if (!SO->PermCol)
23417          SO->PermCol = (float *)SUMA_malloc(4*sizeof(float)*SO->N_Node);
23418       for (iobj=0; iobj<n_obj; ++iobj) {
23419          ioff = 4*8*iobj;
23420          for (i=0; i<8; ++i) {
23421             SO->PermCol[ioff+4*i  ] = col[4*iobj  ];
23422             SO->PermCol[ioff+4*i+1] = col[4*iobj+1];
23423             SO->PermCol[ioff+4*i+2] = col[4*iobj+2];
23424             SO->PermCol[ioff+4*i+3] = col[4*iobj+3];
23425          }
23426       }
23427    }
23428 
23429    SO->normdir = 1;
23430 
23431    nsoopt=SUMA_FreeNewSOOpt(nsoopt);
23432 
23433    SUMA_RETURN(SO);
23434 }
23435 
SUMA_ball_surface(float * hd3,float * cen,float * col,int n_obj)23436 SUMA_SurfaceObject *SUMA_ball_surface(float *hd3, float *cen, float *col,
23437                                      int n_obj)
23438 {
23439    static char FuncName[]={"SUMA_ball_surface"};
23440    SUMA_SurfaceObject *SO=NULL;
23441    int i, iobj=0, ioff=0;
23442    float *tcen;
23443    SUMA_NEW_SO_OPT *nsoopt = NULL;
23444 
23445    SUMA_ENTRY;
23446 
23447    if (n_obj != 1) {
23448       SUMA_S_Err("Not ready for n_obj != 1");
23449       SUMA_RETURN(NULL);
23450    }
23451    /* create a surface */
23452    if (!(SO = SUMA_CreateIcosahedron(hd3[0], 5, cen, "n", 1))) {
23453          SUMA_S_Err("Failed to create sphere SO!");
23454          SUMA_RETURN(NOPE);
23455    }
23456    SUMA_RECOMPUTE_NORMALS(SO);
23457    /* and the stupid copies */
23458    SO->glar_NodeList = SO->NodeList;
23459    SO->glar_FaceSetList = SO->FaceSetList;
23460    SO->glar_NodeNormList = SO->NodeNormList;
23461    SO->glar_FaceNormList = SO->FaceNormList;
23462 
23463    if (col) {
23464       if (!SO->PermCol)
23465          SO->PermCol = (float *)SUMA_malloc(4*sizeof(float)*SO->N_Node);
23466       for (iobj=0; iobj<n_obj; ++iobj) {
23467          ioff = 4*SO->N_Node*iobj;
23468          for (i=0; i<SO->N_Node; ++i) {
23469             SO->PermCol[ioff+4*i  ] = col[4*iobj  ];
23470             SO->PermCol[ioff+4*i+1] = col[4*iobj+1];
23471             SO->PermCol[ioff+4*i+2] = col[4*iobj+2];
23472             SO->PermCol[ioff+4*i+3] = col[4*iobj+3];
23473          }
23474       }
23475    }
23476 
23477    SO->normdir = 1;
23478 
23479    SUMA_RETURN(SO);
23480 }
23481 
23482 
SUMA_MDO_to_NIMDO(SUMA_MaskDO * mdo,NI_group * cont)23483 NI_group *SUMA_MDO_to_NIMDO(SUMA_MaskDO *mdo, NI_group *cont)
23484 {
23485    static char FuncName[]={"SUMA_MDO_to_NIMDO"};
23486    NI_group *ngr = NULL;
23487 
23488    SUMA_ENTRY;
23489 
23490    if (!mdo) SUMA_RETURN(ngr);
23491 
23492    if (mdo->mtype[0] == '\0') {
23493       SUMA_S_Err("NULL mtype"); SUMA_RETURN(ngr);
23494    }
23495 
23496    ngr = NI_new_group_element();
23497    NI_rename_group(ngr, "Mask");
23498 
23499    NI_set_attribute(ngr,"idcode_str",mdo->idcode_str);
23500    NI_set_attribute(ngr,"label",mdo->Label);
23501    NI_set_attribute(ngr,"mtype",mdo->mtype);
23502    NI_SET_FLOATv(ngr,"cen", mdo->cen, 3);
23503    NI_SET_FLOATv(ngr,"hdim", mdo->hdim, 3);
23504    NI_SET_FLOATv(ngr,"init_cen", mdo->init_cen, 3);
23505    NI_SET_FLOATv(ngr,"init_hdim", mdo->init_hdim, 3);
23506    NI_SET_FLOATv(ngr,"init_col", mdo->init_col,4);
23507    NI_SET_FLOAT(ngr,"dim", mdo->dim);
23508    NI_SET_INT(ngr,"trans", mdo->trans);
23509    NI_set_attribute(ngr,"varname", mdo->varname);
23510    if (mdo->Parent_idcode_str)
23511       NI_set_attribute(ngr,"Parent_idcode_str", mdo->Parent_idcode_str);
23512 
23513    if (cont) NI_add_to_group(cont, ngr);
23514 
23515    SUMA_RETURN(ngr);
23516 }
23517 
SUMA_NIMDO_to_MDO(NI_group * ngr)23518 SUMA_MaskDO *SUMA_NIMDO_to_MDO(NI_group *ngr)
23519 {
23520    static char FuncName[]={"SUMA_NIMDO_to_MDO"};
23521    SUMA_MaskDO *mdo = NULL;
23522    char *att=NULL, *attL;
23523    int i;
23524    static int icall=0;
23525    char hid[32];
23526    SUMA_Boolean LocalHead = NOPE;
23527 
23528    SUMA_ENTRY;
23529 
23530    if (!ngr) SUMA_RETURN(mdo);
23531 
23532    if (strcmp(ngr->name, "Mask")) SUMA_RETURN(mdo);
23533 
23534    if (!(att=NI_get_attribute(ngr,"mtype")) ||
23535        (strcmp(att,"ball") && strcmp(att,"box"))) {
23536       SUMA_S_Err("Unexpected mtype %s", att?att:"NULL");
23537       SUMA_RETURN(mdo);
23538    }
23539 
23540    SUMA_LH("Creating mask");
23541    if (!(attL = NI_get_attribute(ngr,"label"))) {
23542       sprintf(hid,"Lmsk%d", icall); ++icall;
23543       attL = hid;
23544    }
23545    if (!(mdo = SUMA_Alloc_MaskDO (1, attL, attL,
23546                   NI_get_attribute(ngr,"idcode_str"), 1))) {
23547       SUMA_S_Err("Failed in SUMA_Allocate_MaskDO.");
23548       SUMA_RETURN(NULL);
23549    }
23550    strcpy(mdo->mtype, att);
23551 
23552    if (!SUMA_AddMaskSaux(mdo)) {
23553       SUMA_S_Err("Failed to add Mask Saux");
23554       SUMA_free_MaskDO(mdo);
23555       SUMA_RETURN(NULL);
23556    }
23557 
23558    /* fill up mdo */
23559    SUMA_LH("Fill up mdo (%d obj)", mdo->N_obj);
23560    NI_GET_FLOATv(ngr, "init_cen", mdo->init_cen, 3, LocalHead);
23561    NI_GET_FLOATv(ngr, "init_hdim", mdo->init_hdim, 3, LocalHead);
23562    NI_GET_FLOATv(ngr, "cen", mdo->cen, 3, LocalHead);
23563    NI_GET_FLOATv(ngr, "hdim", mdo->hdim, 3, LocalHead);
23564    NI_GET_FLOAT(ngr, "dim", mdo->dim);
23565    NI_GET_FLOATv(ngr, "init_col", mdo->init_col, 4, LocalHead);
23566    mdo->dcolv[0] = mdo->init_col[0]*mdo->dim;
23567    mdo->dcolv[1] = mdo->init_col[1]*mdo->dim;
23568    mdo->dcolv[2] = mdo->init_col[2]*mdo->dim;
23569    mdo->dcolv[3] = mdo->init_col[3];
23570 
23571    NI_GET_INT(ngr, "trans", mdo->trans);
23572    SUMA_MDO_SetVarName(mdo, NI_get_attribute(ngr,"varname"));
23573 
23574    SUMA_LH("Returning mdo");
23575 
23576    SUMA_RETURN(mdo);
23577 }
23578 
23579