Skip to content

AFNI/NIfTI Server

Sections
Personal tools
You are here: Home » AFNI » Documentation

Doxygen Source Code Documentation


Main Page   Alphabetical List   Data Structures   File List   Data Fields   Globals   Search  

SUMA_CreateDO.c

Go to the documentation of this file.
00001 /*! Functions to create Displayable Objects */
00002 #include "SUMA_suma.h"
00003 
00004 extern SUMA_CommonFields *SUMAg_CF; 
00005 extern SUMA_DO *SUMAg_DOv;
00006 extern SUMA_SurfaceViewer *SUMAg_SVv;
00007 extern int SUMAg_N_SVv;
00008 extern int SUMAg_N_DOv;
00009 
00010 SUMA_NEW_SO_OPT *SUMA_NewNewSOOpt(void)
00011 {
00012    static char FuncName[]={"SUMA_NewNewSOOpt"};
00013    SUMA_NEW_SO_OPT *nsoopt=NULL;
00014    SUMA_ENTRY;
00015    
00016    nsoopt = (SUMA_NEW_SO_OPT *) SUMA_malloc(sizeof(SUMA_NEW_SO_OPT));
00017    nsoopt->idcode_str = NULL;
00018    nsoopt->LocalDomainParentID = NULL;
00019    nsoopt->FileFormat = SUMA_ASCII;
00020    nsoopt->FileType = SUMA_FT_NOT_SPECIFIED;
00021    nsoopt->DoMetrics = YUP;
00022    nsoopt->DoNormals = YUP;
00023    nsoopt->DoCenter = YUP;
00024    SUMA_RETURN(nsoopt);
00025 }
00026 
00027 SUMA_NEW_SO_OPT *SUMA_FreeNewSOOpt(SUMA_NEW_SO_OPT *nsopt)
00028 {
00029    static char FuncName[]={"SUMA_FreeNewSOOpt"};
00030    SUMA_ENTRY;
00031    
00032    if (!nsopt) SUMA_RETURN(NULL);
00033    if (nsopt->idcode_str) SUMA_free(nsopt->idcode_str);
00034    if (nsopt->LocalDomainParentID) SUMA_free(nsopt->LocalDomainParentID);
00035    SUMA_RETURN(NULL);
00036 }
00037 
00038 /*!
00039    Creates a surface object and its normals and edge list from a list of Nodes and triangles.
00040    NodeListp (float **) pointer to nodelist. This points to the vector of node coordinates.
00041                         The copy into SO is done by pointer and *NodeListp is set to NULL
00042                         to keep users on the straight and narrow.
00043    N_Node (int) number of nodes
00044    
00045    FaceSetList (int **) pointer to facesetlist. Assumes triangular mesh
00046    N_FaceSet (int) number of triangles
00047    nsooptu (SUMA_NEW_SO_OPT *) an options structure to dictate what to do with certain
00048                      fields of SO. At the moment, just pass NULL.
00049 */
00050 SUMA_SurfaceObject *SUMA_NewSO(float **NodeList, int N_Node, int **FaceSetList, int N_FaceSet, SUMA_NEW_SO_OPT *nsooptu)
00051 {
00052    static char FuncName[]={"SUMA_NewSO"};
00053    SUMA_SurfaceObject *SO = NULL;
00054    SUMA_NEW_SO_OPT *nsoopt=NULL;
00055    SUMA_Boolean LocalHead = NOPE;
00056    
00057    SUMA_ENTRY;
00058    
00059    if (!nsooptu) {
00060       nsoopt = SUMA_NewNewSOOpt();
00061    } else {
00062       nsoopt = nsooptu;
00063    }
00064    
00065    SO = SUMA_Alloc_SurfObject_Struct(1); 
00066    
00067    SO->FileFormat = nsoopt->FileFormat;
00068    SO->FileType = nsoopt->FileType;
00069    
00070    SUMA_LH("NodeList");
00071    SO->NodeDim = 3;
00072    SO->NodeList = *NodeList; *NodeList = NULL;  /* keeps user from freeing afterwards ... */
00073    SO->N_Node = N_Node;
00074    
00075    if (nsoopt->DoCenter) {
00076       SUMA_LH("Center deal")
00077       SUMA_DIM_CENTER(SO);
00078    } else {
00079       SUMA_LH("Skipping Center deal")
00080    }
00081    
00082    SUMA_LH("FaceSetList");
00083    SO->FaceSetDim = 3;
00084    SO->FaceSetList = *FaceSetList; *FaceSetList = NULL;  /* keeps user from freeing afterwards ... */
00085    SO->N_FaceSet = N_FaceSet;
00086    
00087    if (nsoopt->DoMetrics) {
00088       SUMA_LH("Metrics");
00089       if (!SUMA_SurfaceMetrics(SO, "EdgeList, MemberFace", NULL)) {
00090          SUMA_SL_Warn("Failed to compute metrics\nReturing with whatever is salvageable");
00091       }
00092    } else {
00093       SUMA_LH("Skipping metrics");
00094    }      
00095    if (nsoopt->DoNormals) {
00096       SUMA_LH("Normals");
00097       SUMA_RECOMPUTE_NORMALS(SO);
00098    } else {
00099       SUMA_LH("Skipping normals");
00100    }
00101    SUMA_LH("trimmings");
00102    SO->idcode_str = (char *)SUMA_calloc (SUMA_IDCODE_LENGTH, sizeof(char));  
00103    if (nsoopt->idcode_str) sprintf(SO->idcode_str, "%s", nsoopt->idcode_str);
00104    else UNIQ_idcode_fill (SO->idcode_str);
00105    if (nsoopt->LocalDomainParentID) SO->LocalDomainParentID = SUMA_copy_string(nsoopt->LocalDomainParentID);
00106    SO->LocalDomainParentID = SUMA_copy_string(SO->idcode_str);
00107    
00108    /* the stupid copies */
00109    SO->glar_NodeList = (GLfloat *)SO->NodeList;
00110    SO->glar_FaceSetList = (GLint *) SO->FaceSetList;
00111    SO->glar_NodeNormList = (GLfloat *) SO->NodeNormList; 
00112    SO->glar_FaceNormList = (GLfloat *) SO->FaceNormList; 
00113    
00114    if (nsooptu != nsoopt) {
00115       nsoopt=SUMA_FreeNewSOOpt(nsoopt); 
00116    }
00117    
00118    SUMA_RETURN(SO);
00119 }
00120 
00121 /*!
00122    \brief A function to create a surface that is a child of another.
00123            function can also be used to replace NodeList and/or 
00124            FaceSetList in the same SurfaceObject
00125    \param SO (SUMA_SurfaceObject *) 
00126    \param NodeList (float *): list of node coordinates, SO->NodeDim*N_Node elements long
00127    \param N_Node (int) : number of nodes in NodeList
00128    \param FaceSetList (int*): list of facesets, SO->FaceSetDim*N_FaceSet element long
00129    \param N_FaceSet (int): number of facesets
00130    \param replace: (SUMA_Boolean)   YUP = replace NodeList and/or FaceSetList in SO and return SO. 
00131                                     NOPE = return a new SurfaceObject, 
00132    \sa SUMA_NewSO
00133 DO NOT FREE NodeList and/or FaceSetList upon returning
00134 */
00135 SUMA_SurfaceObject *SUMA_CreateChildSO(SUMA_SurfaceObject * SO, 
00136                                        float *NodeList, int N_Node, 
00137                                        int *FaceSetList, int N_FaceSet,
00138                                        SUMA_Boolean replace)
00139 {
00140    static char FuncName[]={"SUMA_CreateChildSO"};
00141    SUMA_SurfaceObject *SOn=NULL;
00142    SUMA_Boolean RedoNormals = NOPE, RedoFaces = NOPE;
00143    SUMA_Boolean LocalHead = NOPE;
00144 
00145    SUMA_ENTRY;
00146 
00147    if (!SO) SUMA_RETURN(NULL);
00148    if (!NodeList && !FaceSetList && replace ) { SUMA_SL_Err("Nothing to do"); }
00149 
00150    if (NodeList) { 
00151       if (N_Node != SO->N_Node) {
00152          SUMA_SL_Err("Not ready for partial node lists.\n");
00153          SUMA_RETURN(NULL);
00154       }  
00155    }
00156 
00157    if (replace) { SUMA_LH("Reusing old surface"); SOn = SO; }
00158    else { SUMA_LH("New Surface"); SOn =  SUMA_Alloc_SurfObject_Struct(1); } 
00159 
00160    if (NodeList) {
00161       SUMA_LH("New Node List");
00162       SOn->NodeDim = SO->NodeDim;
00163       SOn->NodeList = NodeList; SOn->N_Node = N_Node;
00164       SUMA_LH("Recalculating center");
00165       SUMA_DIM_CENTER(SOn);
00166       RedoNormals = YUP;
00167    } else {
00168       if (!replace) {
00169          SUMA_LH("Copying old node list");
00170          SOn->NodeDim = SO->NodeDim;
00171          SOn->N_Node = SO->N_Node;
00172          SOn->NodeList = (float *)SUMA_malloc(SOn->N_Node*3*sizeof(float));
00173          if (!SOn->NodeList) { SUMA_SL_Crit("Failed to allocate."); SUMA_RETURN(NULL); }
00174          SUMA_COPY_VEC(SO->NodeList, SOn->NodeList, SOn->N_Node*3, float, float);
00175          RedoNormals = YUP;
00176       }
00177    }
00178  
00179    if (FaceSetList) {
00180       SUMA_LH("New FaceSet List");
00181       SOn->FaceSetList = FaceSetList; SOn->N_FaceSet = N_FaceSet; SOn->FaceSetDim = SO->FaceSetDim;
00182       /* Need a new edge list */
00183       if (!SUMA_SurfaceMetrics(SOn, "EdgeList, MemberFace", NULL)) {
00184          SUMA_SL_Warn("Failed to compute metrics\nReturing with whatever is salvageable");
00185       }
00186       RedoNormals = YUP;
00187    } else {
00188       if (!replace) {
00189          SUMA_LH("Copying old FaceSet list");
00190          SOn->N_FaceSet = SO->N_FaceSet;
00191          SOn->FaceSetDim = SO->FaceSetDim;
00192          SOn->FaceSetList = (int *)SUMA_malloc(SOn->N_FaceSet*SOn->FaceSetDim*sizeof(int));
00193          if (!SOn->FaceSetList) { SUMA_SL_Crit("Failed to allocate."); SUMA_RETURN(NULL); }
00194          SUMA_COPY_VEC(SO->FaceSetList, SOn->FaceSetList, SOn->N_FaceSet*SOn->FaceSetDim, int, int);
00195          RedoNormals = YUP;
00196          /* Need to inherit edge list */
00197          if (0 &&!SUMA_SurfaceMetrics(SOn, "EdgeList, MemberFace", SO)) {
00198             SUMA_SL_Warn("Failed to compute metrics\nReturing with whatever is salvageable");
00199          }
00200       }
00201    }
00202 
00203    if (RedoNormals) {
00204       SUMA_LH("Recalculating normals and convexitation");
00205       SUMA_RECOMPUTE_NORMALS(SOn);
00206       if (0 &&!SUMA_SurfaceMetrics(SOn, "Convexity", SO)) {
00207          SUMA_SL_Warn("Failed to compute metrics\nReturing with whatever is salvageable");
00208       }
00209    }
00210 
00211    if (!replace) {
00212       SUMA_LH("New IDs");
00213       SOn->idcode_str = (char *)SUMA_calloc (SUMA_IDCODE_LENGTH, sizeof(char));  
00214       UNIQ_idcode_fill (SOn->idcode_str);
00215       SOn->LocalDomainParentID = SUMA_copy_string(SO->LocalDomainParentID);
00216    }
00217 
00218    /* the stupid copies */
00219    
00220    SOn->glar_NodeList = (GLfloat *)SOn->NodeList;
00221    SOn->glar_NodeNormList = (GLfloat *)SOn->NodeNormList;
00222    SOn->glar_FaceSetList = (GLint *) SOn->FaceSetList;
00223    SOn->glar_FaceNormList = (GLfloat *) SOn->FaceNormList;
00224    
00225    SUMA_RETURN(SOn);
00226 }
00227 SUMA_SurfaceObject *SUMA_Cmap_To_SO (SUMA_COLOR_MAP *Cmap, float orig[3], float topright[3], int verb)
00228 {
00229    static char FuncName[]={"SUMA_Cmap_To_SO"};
00230    SUMA_SurfaceObject *SO= NULL;
00231    int i, i3, i4, in, k;
00232    float dh, dw, *hp = NULL;
00233    SUMA_SURF_NORM SN;
00234    SUMA_Boolean LocalHead = NOPE;
00235    
00236    SUMA_ENTRY;
00237    
00238    SUMA_LH("Allocating surface.");
00239    SO = SUMA_Alloc_SurfObject_Struct(1);
00240    if (!Cmap) { SUMA_SL_Err("No Cmap"); SUMA_RETURN(NULL); }
00241    if (!Cmap->N_Col) { SUMA_SL_Err("No colours"); SUMA_RETURN(NULL); }
00242    if (!SO) { SUMA_SL_Crit("Failed to allocate"); SUMA_RETURN(NULL); }
00243    
00244    #if 0
00245    if (Cmap->frac) { 
00246       /* DEBUG ONLY */
00247       verb = 2;
00248       SUMA_SL_Note("DEBUG ONLY, Leaky approach .. ");
00249       Cmap = SUMA_Linearize_Color_Map(Cmap, -1);
00250    }
00251    #endif
00252    
00253    /* scaling factors */
00254    dh = (topright[1] - orig[1]) / Cmap->N_Col;
00255    hp = (float *)SUMA_calloc(Cmap->N_Col+1, sizeof(float));
00256    if (!hp) {
00257       SUMA_SL_Crit("malloc error");
00258       SUMA_RETURN(NULL);
00259    }
00260    hp[0] = 0.0;
00261    for (i=0; i<Cmap->N_Col; ++i) {
00262       if (Cmap->frac) {
00263          if (LocalHead) fprintf (SUMA_STDERR, "%s: icol %d, frac=%f\n", FuncName, i,  Cmap->frac[i]);
00264          if (Cmap->Sgn >= 0) {
00265             hp[i+1] = Cmap->frac[i] * (topright[1] - orig[1]);
00266          } else {
00267             hp[i+1] = (1.0 +Cmap->frac[i]) / 2.0 * (topright[1] - orig[1]);
00268          }
00269       } else hp[i+1] = hp[i]+dh;
00270    }
00271    
00272    dw = topright[0] - orig[0];
00273    if (dh <= 0 || dw <= 0) {
00274       SUMA_SL_Err("Whatchyoutalkinaboutwillis?");
00275       SUMA_RETURN(NULL);
00276    }
00277    
00278    SUMA_LH("Allocating surface elements.");
00279    /* allocate for the NodeList */
00280    SO->FileType = SUMA_CMAP_SO;
00281    SO->N_Node = 4 * (Cmap->N_Col);
00282    SO->N_FaceSet = 2 * Cmap->N_Col;
00283    SO->NodeDim = 3;
00284    SO->EmbedDim = 2;
00285    SO->FaceSetDim = 3;
00286    SO->idcode_str = (char *)SUMA_malloc(SUMA_IDCODE_LENGTH * sizeof(char));
00287    SO->NodeList = (float *)SUMA_malloc(SO->N_Node * 3*sizeof(float));
00288    SO->FaceSetList = (int *)SUMA_malloc(SO->N_FaceSet * 3 * sizeof(int));
00289    SO->PermCol = (GLfloat *)SUMA_malloc(SO->N_Node * 4*sizeof(GLfloat));
00290    if (!SO->idcode_str || !SO->NodeList || !SO->FaceSetList || !SO->PermCol) { SUMA_SL_Crit("Failed to allocate"); SUMA_RETURN(NULL);}
00291    
00292    SUMA_LH("Filling up surface id.");
00293    /* fill up idcode*/
00294    UNIQ_idcode_fill(SO->idcode_str);
00295    
00296    SUMA_LH("Filling up surface nodelist.");
00297    /* fill up coordinates first */
00298    i=0;     /* color index */
00299    in = 0;  /* node index */
00300    i3 = in * 3;
00301    while (i < Cmap->N_Col) {
00302       /* 4 nodes per color */
00303       SO->NodeList[i3] =    orig[0]; SO->NodeList[i3+1] = hp[i]   + orig[1]; SO->NodeList[i3+2] = 0.0; ++in; i3 = in * 3;
00304       SO->NodeList[i3] = dw+orig[0]; SO->NodeList[i3+1] = hp[i]   + orig[1]; SO->NodeList[i3+2] = 0.0; ++in; i3 = in * 3;
00305       SO->NodeList[i3] = dw+orig[0]; SO->NodeList[i3+1] = hp[i+1] + orig[1]; SO->NodeList[i3+2] = 0.0; ++in; i3 = in * 3;
00306       SO->NodeList[i3] =    orig[0]; SO->NodeList[i3+1] = hp[i+1] + orig[1]; SO->NodeList[i3+2] = 0.0; ++in; i3 = in * 3;
00307       ++i;
00308    }
00309    
00310    SUMA_LH("Bounding Box");
00311    /* Calculate Min, Max, Mean */
00312    SUMA_MIN_MAX_SUM_VECMAT_COL (SO->NodeList, SO->N_Node, SO->NodeDim, SO->MinDims, SO->MaxDims, SO->Center);
00313      
00314    SO->Center[0] /= SO->N_Node;
00315    SO->Center[1] /= SO->N_Node;
00316    SO->Center[2] /= SO->N_Node;
00317 
00318    SUMA_MIN_VEC (SO->MinDims, 3, SO->aMinDims );
00319    SUMA_MAX_VEC (SO->MaxDims, 3, SO->aMaxDims);
00320    
00321    SUMA_LH("Filling up surface facesetlist.");
00322    /* fill up triangles */
00323    i = 0;   /* color index */
00324    i4 = 4*i;
00325    in = 0;  /* triangle index */
00326    i3 = in *3;
00327    while (i < Cmap->N_Col) {
00328       /* 2 triangles per color, 4 nodes per color*/
00329       SO->FaceSetList[i3] = i4; SO->FaceSetList[i3+1] = i4+1; SO->FaceSetList[i3+2] = i4+2; ++in; i3 = in *3;
00330       SO->FaceSetList[i3] = i4; SO->FaceSetList[i3+1] = i4+2; SO->FaceSetList[i3+2] = i4+3; ++in; i3 = in *3;; 
00331       ++i; i4 = 4*i;
00332    }
00333    
00334    SUMA_LH("Filling up surface colors.");
00335    /* fill up the color vector */
00336    i=0; /* color index */
00337    in = 0;  /* node index */
00338    i4 = in * 4;
00339    while (i < Cmap->N_Col) {
00340       for (k=0; k<4; ++k) {
00341          /* 4 nodes per color */
00342          SO->PermCol[i4]   = Cmap->M[i][0]; SO->PermCol[i4+1] = Cmap->M[i][1]; 
00343          SO->PermCol[i4+2] = Cmap->M[i][2]; SO->PermCol[i4+3] = 1.0;  ++in; i4 = in * 4;
00344       }
00345       ++i;
00346    } 
00347    
00348    /* if verb, write out the results for checking */
00349    if (verb > 1) {
00350       char *fname;
00351       FILE *fout;
00352       
00353       SUMA_LH("writing out surface.");
00354 
00355       fname = SUMA_append_string(Cmap->Name, ".1D.NodeList");
00356       if (!fname) { SUMA_SL_Err("Failed to create name"); SUMA_RETURN(SO); }
00357       fout = fopen(fname,"w"); 
00358       if (fout) {
00359          for (i=0; i < SO->N_Node; ++i) fprintf (fout,"%f %f %f\n", SO->NodeList[3*i], SO->NodeList[3*i+1], SO->NodeList[3*i+2]);
00360          fclose(fout); SUMA_free(fname); fname = NULL;
00361       }else { SUMA_SL_Err("Failed to write NodeList"); SUMA_RETURN(SO); }
00362       
00363       fname = SUMA_append_string(Cmap->Name, ".1D.FaceSetList");
00364       if (!fname) { SUMA_SL_Err("Failed to create name"); SUMA_RETURN(SO); }
00365       fout = fopen(fname,"w"); 
00366       if (fout) {
00367          for (i=0; i < SO->N_FaceSet; ++i) fprintf (fout,"%d %d %d\n", SO->FaceSetList[3*i], SO->FaceSetList[3*i+1], SO->FaceSetList[3*i+2]);
00368          fclose(fout); SUMA_free(fname); fname = NULL;
00369       }else { SUMA_SL_Err("Failed to write FaceSetList"); SUMA_RETURN(SO); }
00370       
00371       fname = SUMA_append_string(Cmap->Name, ".1D.col");
00372       if (!fname) { SUMA_SL_Err("Failed to create name"); SUMA_RETURN(SO); }
00373       fout = fopen(fname,"w"); 
00374       if (fout) {
00375          for (i=0; i < SO->N_Node; ++i) fprintf (fout,"%d %f %f %f\n", i, SO->PermCol[4*i], SO->PermCol[4*i+1], SO->PermCol[4*i+2]);
00376          fclose(fout); SUMA_free(fname); fname = NULL;
00377       }else { SUMA_SL_Err("Failed to write Col file"); SUMA_RETURN(SO); }
00378    }
00379    
00380    /* free hp */
00381    if (hp) SUMA_free(hp); hp = NULL;
00382    
00383    /* some more stuff */
00384    SN = SUMA_SurfNorm(SO->NodeList,  SO->N_Node, SO->FaceSetList, SO->N_FaceSet );
00385    SO->NodeNormList = SN.NodeNormList;
00386    SO->FaceNormList = SN.FaceNormList;
00387    
00388    /* the shameful pointer copies */
00389    SO->glar_NodeList = (GLfloat *) SO->NodeList;
00390    SO->glar_FaceSetList = (GLint *) SO->FaceSetList;
00391    SO->glar_FaceNormList = (GLfloat *) SO->FaceNormList;
00392    SO->glar_NodeNormList = (GLfloat *) SO->NodeNormList;
00393    
00394    SUMA_RETURN(SO);
00395 }
00396 
00397 /*!
00398    Create a surface object for the colormap 
00399    This one creates a surface where successive colors share an edge.
00400    This makes the coloring annoying since you need to use flat shading 
00401    and make sure you colorize the proper nodes (see p172, OpenGL programming guide and
00402    NIH-3 lab-book 157. The coloring as implemented here is not correct in that 
00403    it does not follow the i+2 rule (see OpenGL book ref) but I have decided to
00404    create a different surface which has 4 nodes per color and no sharing of 
00405    nodes/edges for successive colors.
00406    
00407    See SUMA_Cmap_To_SO
00408 */
00409 SUMA_SurfaceObject *SUMA_Cmap_To_SO_old (SUMA_COLOR_MAP *Cmap, float orig[3], float topright[3], int verb)
00410 {
00411    static char FuncName[]={"SUMA_Cmap_To_SO_old"};
00412    SUMA_SurfaceObject *SO= NULL;
00413    int icol, i, i3, i4;
00414    float dh, dw;
00415    SUMA_SURF_NORM SN;
00416    SUMA_Boolean LocalHead = NOPE;
00417    
00418    SUMA_ENTRY;
00419    
00420    SUMA_SL_Err("Function is obsolete.\nUse SUMA_Cmap_To_SO");
00421    
00422    SUMA_LH("Allocating surface.");
00423    SO = SUMA_Alloc_SurfObject_Struct(1);
00424    if (!Cmap) { SUMA_SL_Err("No Cmap"); SUMA_RETURN(NULL); }
00425    if (!Cmap->N_Col) { SUMA_SL_Err("No colours"); SUMA_RETURN(NULL); }
00426    if (!SO) { SUMA_SL_Crit("Failed to allocate"); SUMA_RETURN(NULL); }
00427    
00428    /* scaling factors */
00429    dh = (topright[1] - orig[1]) / Cmap->N_Col;
00430    dw = topright[0] - orig[0];
00431    if (dh <= 0 || dw <= 0) {
00432       SUMA_SL_Err("Whatchyoutalkinaboutwillis?");
00433       SUMA_RETURN(NULL);
00434    }
00435    
00436    SUMA_LH("Allocating surface elements.");
00437    /* allocate for the NodeList */
00438    SO->FileType = SUMA_CMAP_SO;
00439    SO->N_Node = 2 * (Cmap->N_Col + 1);
00440    SO->N_FaceSet = 2 * Cmap->N_Col;
00441    SO->NodeDim = 3;
00442    SO->EmbedDim = 2;
00443    SO->FaceSetDim = 3;
00444    SO->idcode_str = (char *)SUMA_malloc(SUMA_IDCODE_LENGTH * sizeof(char));
00445    SO->NodeList = (float *)SUMA_malloc(SO->N_Node * 3*sizeof(float));
00446    SO->FaceSetList = (int *)SUMA_malloc(SO->N_FaceSet * 3 * sizeof(int));
00447    SO->PermCol = (GLfloat *)SUMA_malloc(SO->N_Node * 4*sizeof(GLfloat));
00448    if (!SO->idcode_str || !SO->NodeList || !SO->FaceSetList || !SO->PermCol) { SUMA_SL_Crit("Failed to allocate"); SUMA_RETURN(NULL);}
00449    
00450    SUMA_LH("Filling up surface id.");
00451    /* fill up idcode*/
00452    UNIQ_idcode_fill(SO->idcode_str);
00453    
00454    SUMA_LH("Filling up surface nodelist.");
00455    /* fill up coordinates first */
00456    /* first fill the oth and the 1st node. They don't follow the cute series */
00457    SO->NodeList[0] = orig[0];    SO->NodeList[1] = orig[1];    SO->NodeList[2] = 0.0;
00458    SO->NodeList[3] = dw+orig[0]; SO->NodeList[4] = orig[1];    SO->NodeList[5] = 0.0;
00459    
00460    i=2;
00461    while (i < SO->N_Node) {
00462       /* even i */
00463       i3 = i * 3;
00464       SO->NodeList[i3] = dw+orig[0];SO->NodeList[i3+1] = i/2 * dh + orig[1]; SO->NodeList[i3+2] = 0.0; ++i;
00465       /* odd i */ 
00466       i3 = i * 3;
00467       SO->NodeList[i3] = orig[0];   SO->NodeList[i3+1] = i/2 * dh + orig[1]; SO->NodeList[i3+2] = 0.0; ++i;
00468    }
00469    
00470    SUMA_LH("Filling up surface facesetlist.");
00471    /* fill up triangles */
00472    /* fill up the oth and 1st triangles, they don't follow the cute series */
00473    SO->FaceSetList[0] = 0; SO->FaceSetList[1] = 1; SO->FaceSetList[2] = 2;
00474    SO->FaceSetList[3] = 2; SO->FaceSetList[4] = 3; SO->FaceSetList[5] = 0;
00475    
00476    icol = 1;
00477    while (icol < Cmap->N_Col) {
00478       i = 2 * icol;    /* 2 triangles per color */
00479       /* first triangle */
00480       i3 = i * 3;
00481       SO->FaceSetList[i3] = i+1; SO->FaceSetList[i3+1] = i; SO->FaceSetList[i3+2] = i+2;
00482       /* second triangle */
00483       i3 = (i+1) * 3;
00484       SO->FaceSetList[i3] = i+2; SO->FaceSetList[i3+1] = i+3; SO->FaceSetList[i3+2] = i+1; 
00485       ++icol;
00486    }
00487    
00488    SUMA_LH("Filling up surface colors.");
00489    /* fill up the color vector */
00490    /* Node 0 is special */
00491    SO->PermCol[0] = Cmap->M[0][0]; SO->PermCol[1] = Cmap->M[0][1]; SO->PermCol[2] = Cmap->M[0][2]; SO->PermCol[3] = 1.0;
00492    /* last node is special */
00493    i4 = 4 * (SO->N_Node -1);
00494    SO->PermCol[i4  ] = Cmap->M[Cmap->N_Col-1][0]; 
00495    SO->PermCol[i4+1] = Cmap->M[Cmap->N_Col-1][1]; 
00496    SO->PermCol[i4+2] = Cmap->M[Cmap->N_Col-1][2]; 
00497    SO->PermCol[i4+3] = 1.0;
00498    
00499    i=1;
00500    icol = 0;
00501    while (i < SO->N_Node -1) {
00502       /* Next two get the icolth color */
00503       i4 = 4*i;
00504       SO->PermCol[i4] = Cmap->M[icol][0];  SO->PermCol[i4+1] = Cmap->M[icol][1]; 
00505       SO->PermCol[i4+2] = Cmap->M[icol][2];SO->PermCol[i4+3] = 1.0;  ++i; 
00506       i4 = 4*i;
00507       SO->PermCol[i4] = Cmap->M[icol][0];  SO->PermCol[i4+1] = Cmap->M[icol][1]; 
00508       SO->PermCol[i4+2] = Cmap->M[icol][2];SO->PermCol[i4+3] = 1.0;  ++i; 
00509       ++icol;
00510    } 
00511    
00512    /* if verb, write out the results for checking */
00513    if (verb > 1) {
00514       char *fname;
00515       FILE *fout;
00516       
00517       SUMA_LH("writing out surface.");
00518 
00519       fname = SUMA_append_string(Cmap->Name, ".1D.NodeList");
00520       if (!fname) { SUMA_SL_Err("Failed to create name"); SUMA_RETURN(SO); }
00521       fout = fopen(fname,"w"); 
00522       if (fout) {
00523          for (i=0; i < SO->N_Node; ++i) fprintf (fout,"%f %f %f\n", SO->NodeList[3*i], SO->NodeList[3*i+1], SO->NodeList[3*i+2]);
00524          fclose(fout); SUMA_free(fname); fname = NULL;
00525       }else { SUMA_SL_Err("Failed to write NodeList"); SUMA_RETURN(SO); }
00526       
00527       fname = SUMA_append_string(Cmap->Name, ".1D.FaceSetList");
00528       if (!fname) { SUMA_SL_Err("Failed to create name"); SUMA_RETURN(SO); }
00529       fout = fopen(fname,"w"); 
00530       if (fout) {
00531          for (i=0; i < SO->N_FaceSet; ++i) fprintf (fout,"%d %d %d\n", SO->FaceSetList[3*i], SO->FaceSetList[3*i+1], SO->FaceSetList[3*i+2]);
00532          fclose(fout); SUMA_free(fname); fname = NULL;
00533       }else { SUMA_SL_Err("Failed to write FaceSetList"); SUMA_RETURN(SO); }
00534       
00535       fname = SUMA_append_string(Cmap->Name, ".1D.col");
00536       if (!fname) { SUMA_SL_Err("Failed to create name"); SUMA_RETURN(SO); }
00537       fout = fopen(fname,"w"); 
00538       if (fout) {
00539          for (i=0; i < SO->N_Node; ++i) fprintf (fout,"%d %f %f %f\n", i, SO->PermCol[4*i], SO->PermCol[4*i+1], SO->PermCol[4*i+2]);
00540          fclose(fout); SUMA_free(fname); fname = NULL;
00541       }else { SUMA_SL_Err("Failed to write Col file"); SUMA_RETURN(SO); }
00542    }
00543    
00544    /* some more stuff */
00545    SN = SUMA_SurfNorm(SO->NodeList,  SO->N_Node, SO->FaceSetList, SO->N_FaceSet );
00546    SO->NodeNormList = SN.NodeNormList;
00547    SO->FaceNormList = SN.FaceNormList;
00548    
00549    /* the shameful pointer copies */
00550    SO->glar_NodeList = (GLfloat *) SO->NodeList;
00551    SO->glar_FaceSetList = (GLint *) SO->FaceSetList;
00552    SO->glar_FaceNormList = (GLfloat *) SO->FaceNormList;
00553    SO->glar_NodeNormList = (GLfloat *) SO->NodeNormList;
00554    
00555    SUMA_RETURN(SO);
00556 }
00557 
00558 /*!
00559  allocate for a segment DO 
00560    SDO = SUMA_Alloc_SegmentDO ( N_n, Label)
00561 
00562    \param N_n (int) number of nodes to allocate for n0 and n1. 
00563       if N_n > 0  SDO->n0 and n1 (GLfloat *) vector to 3*N_n elements to contain the XYZ of nodes n0 and n1.
00564       else SDO->n0 and n1 = NULL
00565    \param Label (char *) label of segment DO. Pass NULL for no labels
00566 
00567    \returns SDO (SUMA_SegmentDO *) 
00568      
00569 */
00570 SUMA_SegmentDO * SUMA_Alloc_SegmentDO (int N_n, char *Label)
00571 {
00572    static char FuncName[]={"SUMA_Alloc_SegmentDO"};
00573    SUMA_SegmentDO * SDO= NULL;
00574 
00575    SUMA_ENTRY;
00576    
00577    SDO = (SUMA_SegmentDO *) SUMA_malloc (sizeof (SUMA_SegmentDO));
00578    if (!SDO) {
00579          fprintf(stderr,"Error %s: Failed to allocate for SDO\n", FuncName);
00580          SUMA_RETURN (SDO);
00581    }
00582    if (N_n > 0) {
00583       SDO->n0 = (GLfloat *) SUMA_calloc (3*N_n, sizeof(GLfloat));
00584       SDO->n1 = (GLfloat *) SUMA_calloc (3*N_n, sizeof(GLfloat));
00585    
00586       if (!SDO->n0 || !SDO->n1) {
00587          fprintf(stderr,"Error %s: Failed to allocate for SDO-n1 or SDO->n0\n", FuncName);
00588          if (SDO->n0) SUMA_free (SDO->n0);
00589          if (SDO->n1) SUMA_free (SDO->n1);
00590          if (SDO) SUMA_free (SDO);
00591          SUMA_RETURN (NULL);
00592       }
00593    } else {
00594       SDO->n0 = NULL;
00595       SDO->n1 = NULL;
00596       SDO->N_n = 0;
00597    }
00598    
00599    SDO->idcode_str = (char *)SUMA_calloc (SUMA_IDCODE_LENGTH, sizeof(char));
00600    UNIQ_idcode_fill(SDO->idcode_str);
00601    
00602    
00603    if (Label) {
00604       SDO->Label = (char *)SUMA_calloc (strlen(Label)+1, sizeof(char));
00605       SDO->Label = strcpy (SDO->Label, Label);
00606    } else {
00607       SDO->Label = NULL;
00608    }
00609    
00610    SDO->N_n = N_n;
00611    SDO->Stipple = SUMA_SOLID_LINE;
00612    /* setup some default values */
00613    SDO->LineWidth = 4.0;
00614    SDO->LineCol[0] = 1.0; SDO->LineCol[1] = 0.3; SDO->LineCol[2] = 1.0; SDO->LineCol[3] = 1.0; 
00615    
00616    SUMA_RETURN (SDO);
00617 }
00618 
00619 void SUMA_free_SegmentDO (SUMA_SegmentDO * SDO)
00620 {
00621    static char FuncName[]={"SUMA_free_SegmentDO"};
00622 
00623    SUMA_ENTRY;
00624    
00625    if (!SDO) SUMA_RETURNe;
00626    
00627    if (SDO->n0) SUMA_free(SDO->n0);
00628    if (SDO->n1) SUMA_free(SDO->n1);
00629    if (SDO->idcode_str) SUMA_free(SDO->idcode_str);
00630    if (SDO->Label) SUMA_free(SDO->Label);
00631    if (SDO) SUMA_free(SDO);
00632    
00633    SUMA_RETURNe;
00634 }
00635 
00636 SUMA_SegmentDO * SUMA_ReadSegDO (char *s)
00637 {
00638    static char FuncName[]={"SUMA_ReadSegDO"};
00639    SUMA_SegmentDO *SDO = NULL;
00640    MRI_IMAGE * im = NULL;
00641    float *far=NULL;
00642    int itmp, itmp2;
00643    int nrow=-1, ncol=-1;
00644    
00645    SUMA_ENTRY;
00646    
00647    if (!s) {
00648       SUMA_SLP_Err("NULL s");
00649       SUMA_RETURN(NULL);
00650    }
00651    
00652    im = mri_read_1D (s);
00653 
00654    if (!im) {
00655       SUMA_SLP_Err("Failed to read 1D file");
00656       SUMA_RETURN(NULL);
00657    }
00658    im = mri_read_1D (s);
00659 
00660    if (!im) {
00661       SUMA_SLP_Err("Failed to read 1D file");
00662       SUMA_RETURN(NULL);
00663    }
00664 
00665    far = MRI_FLOAT_PTR(im);
00666    ncol = im->nx;
00667    nrow = im->ny;
00668 
00669    if (!ncol) {
00670       SUMA_SLP_Err("Empty file");
00671       SUMA_RETURN(NULL);
00672    }
00673    if (nrow !=  6 ) {
00674       SUMA_SLP_Err("File must have\n"
00675                    "6 columns.");
00676       mri_free(im); im = NULL;   /* done with that baby */
00677       SUMA_RETURN(NULL);
00678    }/* find out if file exists and how many values it contains */
00679 
00680    /* allocate for segments DO */
00681    SDO = SUMA_Alloc_SegmentDO (ncol, s);
00682    if (!SDO) {
00683       fprintf(SUMA_STDERR,"Error %s: Failed in SUMA_Allocate_SegmentDO.\n", FuncName);
00684       SUMA_RETURN(NULL);
00685    }
00686 
00687    /* fill up SDO */
00688    itmp = 0;
00689    while (itmp < SDO->N_n) {
00690       itmp2 = 3*itmp;
00691       SDO->n0[itmp2]   = far[itmp       ];
00692       SDO->n0[itmp2+1] = far[itmp+  ncol];
00693       SDO->n0[itmp2+2] = far[itmp+2*ncol];
00694       SDO->n1[itmp2]   = far[itmp+3*ncol];
00695       SDO->n1[itmp2+1] = far[itmp+4*ncol];
00696       SDO->n1[itmp2+2] = far[itmp+5*ncol]; 
00697       ++itmp;
00698    } 
00699 
00700    mri_free(im); im = NULL; far = NULL;
00701 
00702    SUMA_RETURN(SDO);
00703 }
00704 
00705 
00706 /*! Allocate for a axis object */
00707 SUMA_Axis* SUMA_Alloc_Axis (const char *Name)
00708 {   
00709    static char FuncName[]={"SUMA_Alloc_Axis"};
00710    SUMA_Axis* Ax;
00711 
00712    SUMA_ENTRY;
00713 
00714    Ax = (SUMA_Axis *) SUMA_malloc (sizeof (SUMA_Axis));
00715    if (Ax == NULL) {
00716       fprintf(stderr,"SUMA_Alloc_Axis Error: Failed to allocate Ax\n");
00717       SUMA_RETURN (Ax);
00718    }
00719    
00720    /* setup some default values */
00721    Ax->type = SUMA_STD_ZERO_CENTERED;
00722    Ax->XaxisColor[0] = 1.0;
00723    Ax->XaxisColor[1] = 0.0;
00724    Ax->XaxisColor[2] = 0.0;
00725    Ax->XaxisColor[3] = 0.0;
00726    
00727    Ax->YaxisColor[0] = 0.0;
00728    Ax->YaxisColor[1] = 1.0;
00729    Ax->YaxisColor[2] = 0.0;
00730    Ax->YaxisColor[3] = 0.0;
00731    
00732    Ax->ZaxisColor[0] = 0.0;
00733    Ax->ZaxisColor[1] = 0.0;
00734    Ax->ZaxisColor[2] = 1.0;
00735    Ax->ZaxisColor[3] = 0.0;
00736    
00737    Ax->LineWidth = 1.0;
00738    Ax->Stipple = SUMA_SOLID_LINE;
00739    Ax->XYZspan[0] = Ax->XYZspan[1] = Ax->XYZspan[2] = 800;
00740    
00741    Ax->Center[0] = Ax->Center[1] = Ax->Center[2] = 0.0;
00742    
00743    if (Name != NULL) {
00744       if (strlen(Name) > SUMA_MAX_LABEL_LENGTH-1) {
00745          fprintf(SUMA_STDERR, "Error %s: Name too long (> %d).\n",\
00746             FuncName, SUMA_MAX_LABEL_LENGTH);
00747          Ax->Name = NULL;
00748          Ax->idcode_str = NULL;
00749       } else {
00750          Ax->Name = (char *)SUMA_calloc (strlen(Name)+1, sizeof(char));
00751          Ax->idcode_str = (char *)SUMA_calloc (SUMA_IDCODE_LENGTH+1, sizeof(char));
00752          if (Ax->Name == NULL) {
00753             fprintf(SUMA_STDERR,"Error %s: Failed to allocate for Ax->Name.\n", \
00754                FuncName);
00755          }
00756          sprintf(Ax->Name, "%s", Name);
00757          UNIQ_idcode_fill(Ax->idcode_str); 
00758       }
00759       
00760    }
00761    SUMA_RETURN (Ax);
00762 }
00763 void SUMA_Free_Axis (SUMA_Axis *Ax)
00764 {
00765    static char FuncName[]={"SUMA_Free_Axis"};
00766    
00767    SUMA_ENTRY;
00768 
00769    if (Ax->Name != NULL) SUMA_free(Ax->Name);
00770    if (Ax->idcode_str != NULL) SUMA_free(Ax->idcode_str);
00771    if (Ax) SUMA_free(Ax);
00772    SUMA_RETURNe;
00773 }
00774 
00775 void SUMA_EyeAxisStandard (SUMA_Axis* Ax, SUMA_SurfaceViewer *csv)
00776 {
00777    static char FuncName[]={"SUMA_EyeAxisStandard"};
00778    SUMA_Boolean LocalHead = NOPE;
00779    
00780    SUMA_ENTRY;
00781 
00782    Ax->Stipple = SUMA_DASHED_LINE;
00783    Ax->XYZspan[0] = Ax->XYZspan[1] = Ax->XYZspan[2] = 1000.0;
00784    Ax->Center[0] = csv->GVS[csv->StdView].ViewCenter[0];
00785    Ax->Center[1] = csv->GVS[csv->StdView].ViewCenter[1];
00786    Ax->Center[2] = csv->GVS[csv->StdView].ViewCenter[2];
00787    SUMA_RETURNe;
00788 }
00789 
00790 void SUMA_MeshAxisStandard (SUMA_Axis* Ax, SUMA_SurfaceObject *cso)
00791 {
00792    static char FuncName[]={"SUMA_EyeAxisStandard"};
00793    
00794    SUMA_ENTRY;
00795 
00796    Ax->Stipple = SUMA_SOLID_LINE;
00797    Ax->XYZspan[0]= Ax->XYZspan[1]= Ax->XYZspan[2]= 100.0;
00798    Ax->BR[0][0] = cso->MinDims[0]; Ax->BR[0][1] = cso->MaxDims[0];
00799    Ax->BR[1][0] = cso->MinDims[1]; Ax->BR[1][1] = cso->MaxDims[1];
00800    Ax->BR[2][0] = cso->MinDims[2]; Ax->BR[2][1] = cso->MaxDims[2];
00801    Ax->Center[0] = cso->Center[0];
00802    Ax->Center[1] = cso->Center[1];
00803    Ax->Center[2] = cso->Center[2];
00804    Ax->MTspace = 10; Ax->mTspace = 2;
00805    Ax->MTsize = 4; Ax->mTsize = 2;
00806    {
00807       char *eee = getenv("SUMA_UseCrossTicks");
00808       if (eee) {
00809          SUMA_TO_LOWER(eee);
00810          if (strcmp (eee, "yes") == 0) Ax->DoCross = 1;
00811             else Ax->DoCross = 0;
00812       } else {
00813          Ax->DoCross = 0;
00814       }
00815    }
00816    SUMA_RETURNe;
00817 }
00818 
00819 void SUMA_WorldAxisStandard (SUMA_Axis* Ax, SUMA_SurfaceViewer *sv)
00820 {
00821    static char FuncName[]={"SUMA_WorldAxisStandard"};
00822    float MinDims[3], MaxDims[3];
00823    int i, j, Nvis, *Vis_IDs=NULL;
00824    SUMA_SurfaceObject *cso=NULL;
00825    SUMA_Boolean LocalHead = NOPE;
00826    
00827    SUMA_ENTRY;
00828    
00829    if (!Ax) {
00830       SUMA_SL_Err("NULL Ax!");
00831       SUMA_RETURNe;
00832    }
00833    
00834    Ax->Stipple = SUMA_SOLID_LINE;
00835    Ax->XYZspan[0]= Ax->XYZspan[1]= Ax->XYZspan[2]= 100.0;
00836    Ax->MTspace = 10; Ax->mTspace = 2;
00837    Ax->MTsize = 4; Ax->mTsize = 2;
00838    {
00839       char *eee = getenv("SUMA_UseCrossTicks");
00840       if (eee) {
00841          SUMA_TO_LOWER(eee);
00842          if (strcmp (eee, "yes") == 0) Ax->DoCross = 1;
00843             else Ax->DoCross = 0;
00844       } else {
00845          Ax->DoCross = 0;
00846       }
00847    }
00848    
00849    Ax->Center[0] = sv->GVS[sv->StdView].RotaCenter[0];
00850    Ax->Center[1] = sv->GVS[sv->StdView].RotaCenter[1];
00851    Ax->Center[2] = sv->GVS[sv->StdView].RotaCenter[2];
00852 
00853    Vis_IDs = (int *)SUMA_malloc(sizeof(int)*SUMAg_N_DOv);
00854    Nvis = SUMA_VisibleSOs (sv, SUMAg_DOv, Vis_IDs);
00855    
00856    if (Nvis > 0) {
00857       for (i=0; i<Nvis; ++i) {
00858          cso = (SUMA_SurfaceObject *)SUMAg_DOv[Vis_IDs[i]].OP;
00859          if (!i) {
00860             for (j=0; j<3; ++j) {
00861                MinDims[j] = cso->MinDims[j];
00862                MaxDims[j] = cso->MaxDims[j];
00863             }
00864          } else {
00865             for (j=0; j<3; ++j) {
00866                if (cso->MinDims[j] < MinDims[j]) MinDims[j] = cso->MinDims[j];
00867                if (cso->MaxDims[j] > MaxDims[j]) MaxDims[j] = cso->MaxDims[j];
00868             }
00869          }
00870       }
00871       Ax->BR[0][0] = MinDims[0]; Ax->BR[0][1] = MaxDims[0];
00872       Ax->BR[1][0] = MinDims[1]; Ax->BR[1][1] = MaxDims[1];
00873       Ax->BR[2][0] = MinDims[2]; Ax->BR[2][1] = MaxDims[2];
00874    }
00875    if (Vis_IDs) SUMA_free(Vis_IDs);
00876    
00877    SUMA_RETURNe;
00878 }
00879 
00880 SUMA_Boolean SUMA_DrawSegmentDO (SUMA_SegmentDO *SDO)
00881 {
00882    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
00883    int i, N_n3;
00884    static char FuncName[]={"SUMA_DrawSegmentDO"};
00885    
00886    SUMA_ENTRY;
00887    
00888    if (!SDO) {
00889       fprintf(stderr,"Error %s: NULL pointer.\n", FuncName);
00890       SUMA_RETURN (NOPE);
00891    }
00892    
00893    glLineWidth(SDO->LineWidth);
00894    
00895    switch (SDO->Stipple) {
00896       case SUMA_DASHED_LINE:
00897          glEnable(GL_LINE_STIPPLE);
00898          glLineStipple (1, 0x00FF); /* dashed, see OpenGL Prog guide, page 55 */
00899          break;
00900       case SUMA_SOLID_LINE:
00901          break;
00902       default:
00903          fprintf(stderr,"Error %s: Unrecognized Stipple option\n", FuncName);
00904          SUMA_RETURN(NOPE);
00905    }
00906    
00907    glBegin(GL_LINES);
00908    glMaterialfv(GL_FRONT, GL_EMISSION, SDO->LineCol); /*turn on emissivity for */
00909    glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor); /* turn off ambient and diffuse components */
00910    glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
00911    
00912    i = 0;
00913    N_n3 = 3*SDO->N_n;
00914    while (i < N_n3) {
00915       glVertex3f(SDO->n0[i], SDO->n0[i+1], SDO->n0[i+2]);
00916       glVertex3f(SDO->n1[i], SDO->n1[i+1], SDO->n1[i+2]); 
00917       i += 3;
00918    }
00919    
00920    glEnd();
00921       switch (SDO->Stipple) {
00922       case SUMA_DASHED_LINE:
00923          glDisable(GL_LINE_STIPPLE);
00924          break;
00925       case SUMA_SOLID_LINE:
00926          break;
00927    }
00928    
00929    glMaterialfv(GL_FRONT, GL_EMISSION, NoColor); /*turn off emissivity */
00930 
00931    SUMA_RETURN (YUP);
00932    
00933 }
00934 
00935 /*!
00936    A macro to be inserted into SUMA_SortedAxisSegmentList's switch statement
00937 */
00938 #define SUMA_SORTED_AXIS_WORKS { \
00939             ASIp->Quad[0] = Q[ASIp->PointIndex[0]];   \
00940             ASIp->Quad[1] = Q[ASIp->PointIndex[1]];   \
00941             for (i=0;i<3;++i) d[i] = ( P[ASIp->PointIndex[1]][i] - P[ASIp->PointIndex[0]][i] ); \
00942             SUMA_NORM_VEC (d, 3, ASIp->world_length); \
00943             ASIp->screen_length_x = S[ASIp->PointIndex[1]*3] - S[ASIp->PointIndex[0]*3];   \
00944             ASIp->screen_length_y = S[ASIp->PointIndex[1]*3+1] - S[ASIp->PointIndex[0]*3+1];   \
00945             for (i=0;i<3;++i) d[i] = ( ( P[ASIp->PointIndex[0]][i] + P[ASIp->PointIndex[1]][i] ) / 2.0 - sv->Pcenter_close[i] ); \
00946             SUMA_NORM_VEC (d, 3, ASIp->MidSegDist);   \
00947             for (i=0;i<2;++i) d[i] = ( S[ASIp->PointIndex[0]*3+i] - LLC[i] );  \
00948             SUMA_NORM_VEC (d, 2, d1);  \
00949             for (i=0;i<2;++i) d[i] = ( S[ASIp->PointIndex[1]*3+i] - LLC[i] );  \
00950             SUMA_NORM_VEC (d, 2, d2);  \
00951             if (d1 < d2) { ASIp->LLCclosestDist = d1; ASIp->LLCclosestPoint = 0; }  \
00952             else { ASIp->LLCclosestDist = d2; ASIp->LLCclosestPoint = 1; } \
00953             for (i=0;i<3;++i) d[i] = ( C[ASIp->FaceIndex[0]][i] - sv->Pcenter_close[i] ); \
00954             SUMA_NORM_VEC (d, 3, d1);  \
00955             for (i=0;i<3;++i) d[i] = ( C[ASIp->FaceIndex[1]][i] - sv->Pcenter_close[i] ); \
00956             SUMA_NORM_VEC (d, 3, d2); if (d1 < d2) ASIp->MidFaceDist = d1; else ASIp->MidFaceDist = d2;  \
00957             SUMA_COPY_VEC(P[ASIp->PointIndex[0]], ASIp->P1, 3, double, double);  \
00958             SUMA_COPY_VEC(P[ASIp->PointIndex[1]], ASIp->P2, 3, double, double);  \
00959             ASIp->TxOff[0] = (-ASIp->tick2_dir[0] - ASIp->tick1_dir[0]);   \
00960             ASIp->TxOff[1] = (-ASIp->tick2_dir[1] - ASIp->tick1_dir[1]);   \
00961             ASIp->TxOff[2] = (-ASIp->tick2_dir[2] - ASIp->tick1_dir[2]);   \
00962             SUMA_NORM_VEC (ASIp->TxOff, 3, d1); /* DO NOT USE /= in the next line !!! */\
00963             ASIp->TxOff[0] = ASIp->TxOff[0] / d1; ASIp->TxOff[1] = ASIp->TxOff[1] / d1; ASIp->TxOff[2] = ASIp->TxOff[2] / d1; \
00964 }
00965 /*!
00966    
00967    \param opt (SUMA_SORT_BOX_AXIS_OPTION) Specifies how sorting of segments is done in the list.
00968    
00969    Creates the various segments needed to form a box axis.
00970    
00971    - Your job is to free DList's elements and destroy and free DList after the function returns.
00972    
00973    \sa Labbook NIH-4 page 21 for annotation of Box Axis ....
00974 */
00975 DList *SUMA_SortedAxisSegmentList (SUMA_SurfaceViewer *sv, SUMA_Axis *Ax, SUMA_SORT_BOX_AXIS_OPTION opt)
00976 {
00977    static char FuncName[]={"SUMA_SortedAxisSegmentList"};
00978    double P[8][3], C[6][3], d[3], d1, d2, S[24], world_length, screen_length_x, screen_length_y;
00979    int Q[8];
00980    static double xAx[3] = {1, 0, 0}, yAx[3] = { 0, 1, 0 }, zAx[3] = {0, 0, 1}, LLC[3] = {0, 0, 0};
00981    static double mxAx[3] = {-1, 0, 0}, myAx[3] = { 0, -1, 0 }, mzAx[3] = {0, 0, -1};
00982    DList *list = NULL;
00983    DListElmt *Elm = NULL;
00984    SUMA_Boolean Found = NOPE;
00985    SUMA_AxisSegmentInfo **ASI = NULL, *ASIp=NULL, *ASIptmp=NULL;
00986    int i=0, j=0;
00987    SUMA_Boolean LocalHead = NOPE;
00988 
00989    SUMA_ENTRY;
00990    
00991    LLC[1] = (double)sv->WindHeight;
00992    if (Ax->type != SUMA_SCALE_BOX) {
00993       SUMA_S_Err("Nothing to be done here.\nFor Scale Box type axis only.");
00994       SUMA_RETURN(NULL);
00995    }
00996    
00997    /* form box corner points */
00998    P[0][0] = Ax->BR[0][0]; P[0][1] = Ax->BR[1][0]; P[0][2] = Ax->BR[2][0]; /*xmin, ymin, zmin */ 
00999    P[1][0] = Ax->BR[0][1]; P[1][1] = Ax->BR[1][0]; P[1][2] = Ax->BR[2][0]; /*xmax, ymin, zmin */ 
01000    P[2][0] = Ax->BR[0][0]; P[2][1] = Ax->BR[1][1]; P[2][2] = Ax->BR[2][0]; /*xmin, ymax, zmin */ 
01001    P[3][0] = Ax->BR[0][1]; P[3][1] = Ax->BR[1][1]; P[3][2] = Ax->BR[2][0]; /*xmax, ymax, zmin */
01002    P[4][0] = Ax->BR[0][0]; P[4][1] = Ax->BR[1][0]; P[4][2] = Ax->BR[2][1]; /*xmin, ymin, zmax */ 
01003    P[5][0] = Ax->BR[0][1]; P[5][1] = Ax->BR[1][0]; P[5][2] = Ax->BR[2][1]; /*xmax, ymin, zmax */ 
01004    P[6][0] = Ax->BR[0][0]; P[6][1] = Ax->BR[1][1]; P[6][2] = Ax->BR[2][1]; /*xmin, ymax, zmax */ 
01005    P[7][0] = Ax->BR[0][1]; P[7][1] = Ax->BR[1][1]; P[7][2] = Ax->BR[2][1]; /*xmax, ymax, zmax */
01006    
01007    /* figure out equivalent screen coords */
01008    SUMA_World2ScreenCoords (sv, 8, (double *)P, S, Q, 0);
01009    
01010    /* form plane centers */
01011    for (i=0; i<3; ++i) { C[0][i] = ( P[0][i] + P[1][i] + P[5][i] + P[4][i] ) / 4.0; } /* Plane a, b, f, e*/
01012    for (i=0; i<3; ++i) { C[1][i] = ( P[0][i] + P[1][i] + P[3][i] + P[2][i] ) / 4.0; } /* Plane a, b, d, c*/
01013    for (i=0; i<3; ++i) { C[2][i] = ( P[0][i] + P[2][i] + P[6][i] + P[4][i] ) / 4.0; } /* Plane a, c, g, e*/
01014    for (i=0; i<3; ++i) { C[3][i] = ( P[4][i] + P[5][i] + P[7][i] + P[6][i] ) / 4.0; } /* Plane e, f, h, g*/
01015    for (i=0; i<3; ++i) { C[4][i] = ( P[1][i] + P[3][i] + P[7][i] + P[5][i] ) / 4.0; } /* Plane b, d, h, f*/
01016    for (i=0; i<3; ++i) { C[5][i] = ( P[2][i] + P[3][i] + P[7][i] + P[6][i] ) / 4.0; } /* Plane c, d, h, g*/
01017   
01018    /* for (i=0; i<3; ++i) sv->Ch->c[i] = sv->Plist_close[i];  */
01019    if (LocalHead) { fprintf (SUMA_STDERR,"%s: sv->Pcenter_close = [%f %f %f]\n", FuncName, sv->Pcenter_close[0], sv->Pcenter_close[1], sv->Pcenter_close[2]); }
01020    ASI = (SUMA_AxisSegmentInfo **) SUMA_malloc( 12 * sizeof(SUMA_AxisSegmentInfo *));
01021 
01022    for (j=0; j<12; ++j) {
01023       ASI[j] = (SUMA_AxisSegmentInfo *) SUMA_malloc(sizeof(SUMA_AxisSegmentInfo )); ASIp = ASI[j];
01024       ASIp->SegIndex = j;
01025       switch (j) {
01026          case 0: /* seg, 1 */
01027             ASIp->AxisDim = 0; /* X axis */
01028             ASIp->PointIndex[0] = 0; /* a */
01029             ASIp->PointIndex[1] = 1; /* b */
01030             ASIp->FaceIndex[0] = 0; /* Plane a, b, f, e */
01031             ASIp->FaceIndex[1] = 1; /* Plane a, b, d, c */
01032             SUMA_COPY_VEC(zAx, ASIp->tick1_dir, 3, double, double);
01033             SUMA_COPY_VEC(yAx, ASIp->tick2_dir, 3, double, double);
01034             SUMA_SORTED_AXIS_WORKS;
01035             break;
01036          case 1: /* Seg 2 */
01037             ASIp->AxisDim = 0;  /* X axis */
01038             ASIp->PointIndex[0] = 2; /* c */
01039             ASIp->PointIndex[1] = 3; /* d */
01040             ASIp->FaceIndex[0] = 1; /* Plane a, b, d, c */
01041             ASIp->FaceIndex[1] = 5; /* Plane c, d, h, g */
01042             SUMA_COPY_VEC(zAx, ASIp->tick1_dir, 3, double, double);
01043             SUMA_COPY_VEC(myAx, ASIp->tick2_dir, 3, double, double);
01044             SUMA_SORTED_AXIS_WORKS;
01045             break;
01046          case 2: /* Seg 3 */
01047             ASIp->AxisDim = 0;  /* X axis */
01048             ASIp->PointIndex[0] = 4; /* e */
01049             ASIp->PointIndex[1] = 5; /* f */
01050             ASIp->FaceIndex[0] = 0; /* Plane a, b, f, e*/
01051             ASIp->FaceIndex[1] = 3; /* Plane e, f, h, g*/
01052             SUMA_COPY_VEC(mzAx, ASIp->tick1_dir, 3, double, double);
01053             SUMA_COPY_VEC(yAx, ASIp->tick2_dir, 3, double, double);
01054             SUMA_SORTED_AXIS_WORKS;
01055             break;
01056          case 3: /* Seg 4 */ 
01057             ASIp->AxisDim = 0;  /* X axis */
01058             ASIp->PointIndex[0] = 6; /* g */
01059             ASIp->PointIndex[1] = 7; /* h */
01060             ASIp->FaceIndex[0] = 5; /* Plane c, d, h, g*/
01061             ASIp->FaceIndex[1] = 3; /* Plane e, f, h, g*/
01062             SUMA_COPY_VEC(mzAx, ASIp->tick1_dir, 3, double, double);
01063             SUMA_COPY_VEC(myAx, ASIp->tick2_dir, 3, double, double);
01064             SUMA_SORTED_AXIS_WORKS;
01065             break;
01066          case 4: /* seg 5*/ 
01067             ASIp->AxisDim = 1; /* Y axis */
01068             ASIp->PointIndex[0] = 0; /* a */
01069             ASIp->PointIndex[1] = 2; /* c */
01070             ASIp->FaceIndex[0] = 1; /* Plane a, b, d, c*/
01071             ASIp->FaceIndex[1] = 2; /* Plane a, c, g, e*/
01072             SUMA_COPY_VEC(xAx, ASIp->tick1_dir, 3, double, double);
01073             SUMA_COPY_VEC(zAx, ASIp->tick2_dir, 3, double, double);
01074             SUMA_SORTED_AXIS_WORKS;
01075             break;
01076          case 5: /* seg 6*/ 
01077             ASIp->AxisDim = 1; /* Y axis */ 
01078             ASIp->PointIndex[0] = 1; /* b */
01079             ASIp->PointIndex[1] = 3; /* d */
01080             ASIp->FaceIndex[0] = 1; /* Plane a, b, d, c*/
01081             ASIp->FaceIndex[1] = 4; /* Plane b, d, h, f*/
01082             SUMA_COPY_VEC(mxAx, ASIp->tick1_dir, 3, double, double);
01083             SUMA_COPY_VEC(zAx, ASIp->tick2_dir, 3, double, double);
01084             SUMA_SORTED_AXIS_WORKS;
01085             break;
01086          case 6: /* seg 7*/ 
01087             ASIp->AxisDim = 1; /* Y axis */ 
01088             ASIp->PointIndex[0] = 4; /* e */
01089             ASIp->PointIndex[1] = 6; /* g */
01090             ASIp->FaceIndex[0] = 2; /* Plane a, c, g, e*/
01091             ASIp->FaceIndex[1] = 3; /* Plane e, f, h, g*/
01092             SUMA_COPY_VEC(xAx, ASIp->tick1_dir, 3, double, double);
01093             SUMA_COPY_VEC(mzAx, ASIp->tick2_dir, 3, double, double);
01094             SUMA_SORTED_AXIS_WORKS;
01095             break;
01096          case 7: /* seg 8*/ 
01097             ASIp->AxisDim = 1; /* Y axis */ 
01098             ASIp->PointIndex[0] = 5; /* f */
01099             ASIp->PointIndex[1] = 7; /* h */
01100             ASIp->FaceIndex[0] = 3; /* Plane e, f, h, g*/
01101             ASIp->FaceIndex[1] = 4; /* Plane b, d, h, f*/
01102             SUMA_COPY_VEC(mxAx, ASIp->tick1_dir, 3, double, double);
01103             SUMA_COPY_VEC(mzAx, ASIp->tick2_dir, 3, double, double);
01104             SUMA_SORTED_AXIS_WORKS;
01105             break;
01106          case 8: /* seg 9*/ 
01107             ASIp->AxisDim = 2; /* Z axis */ 
01108             ASIp->PointIndex[0] = 0; /* a */
01109             ASIp->PointIndex[1] = 4; /* e */
01110             ASIp->FaceIndex[0] = 0; /* Plane a, b, f, e */
01111             ASIp->FaceIndex[1] = 2; /* Plane a, c, g, e */
01112             SUMA_COPY_VEC(xAx, ASIp->tick1_dir, 3, double, double);
01113             SUMA_COPY_VEC(yAx, ASIp->tick2_dir, 3, double, double);
01114             SUMA_SORTED_AXIS_WORKS;
01115             break;
01116          case 9: /* seg 10*/ 
01117             ASIp->AxisDim = 2; /* Z axis */ 
01118             ASIp->PointIndex[0] = 1; /* b */
01119             ASIp->PointIndex[1] = 5; /* f */
01120             ASIp->FaceIndex[0] = 0; /* Plane a, b, f, e*/
01121             ASIp->FaceIndex[1] = 4; /* Plane b, d, h, f*/
01122             SUMA_COPY_VEC(mxAx, ASIp->tick1_dir, 3, double, double);
01123             SUMA_COPY_VEC(yAx, ASIp->tick2_dir, 3, double, double);
01124             SUMA_SORTED_AXIS_WORKS;
01125             break;
01126          case 10: /* seg 11*/ 
01127             ASIp->AxisDim = 2; /* Z axis */ 
01128             ASIp->PointIndex[0] = 2; /* c */
01129             ASIp->PointIndex[1] = 6; /* g */
01130             ASIp->FaceIndex[0] = 5; /* Plane c, d, h, g*/
01131             ASIp->FaceIndex[1] = 2; /* Plane a, c, g, e*/
01132             SUMA_COPY_VEC(xAx, ASIp->tick1_dir, 3, double, double);
01133             SUMA_COPY_VEC(myAx, ASIp->tick2_dir, 3, double, double);
01134             SUMA_SORTED_AXIS_WORKS;
01135             break;
01136          case 11: /* seg 12*/ 
01137             ASIp->AxisDim = 2; /* Z axis */ 
01138             ASIp->PointIndex[0] = 3; /* d */
01139             ASIp->PointIndex[1] = 7; /* h */
01140             ASIp->FaceIndex[0] = 5; /* Plane c, d, h, g*/
01141             ASIp->FaceIndex[1] = 4; /* Plane b, d, h, f*/
01142             SUMA_COPY_VEC(mxAx, ASIp->tick1_dir, 3, double, double);
01143             SUMA_COPY_VEC(myAx, ASIp->tick2_dir, 3, double, double);
01144             SUMA_SORTED_AXIS_WORKS;
01145             break;
01146       }
01147    }
01148 
01149    list = (DList *)SUMA_malloc(sizeof(DList));
01150    dlist_init(list, NULL);
01151    for (i=0; i<12; ++i) {
01152       ASIp = ASI[i];
01153       if (!list->size) {
01154          dlist_ins_next(list, dlist_tail(list), (void*)ASIp);
01155       } else {
01156          Elm = NULL;
01157          do {
01158             Found = NOPE;
01159             if (!Elm) {
01160                Elm = dlist_head(list);
01161             } else {
01162                Elm = dlist_next(Elm);
01163             }
01164             
01165             ASIptmp = (SUMA_AxisSegmentInfo *)Elm->data;
01166                switch (opt) {
01167                   case SUMA_BY_SEGMENT_DISTANCE:
01168                      if (ASIp->MidSegDist < ASIptmp->MidSegDist) {
01169                         dlist_ins_prev(list, Elm, (void *)ASIp);
01170                         Found = YUP;
01171                      }
01172                      break;
01173                   case SUMA_BY_PLANE_DISTANCE:
01174                      if (ASIp->MidFaceDist < ASIptmp->MidFaceDist) {
01175                         dlist_ins_prev(list, Elm, (void *)ASIp);
01176                         Found = YUP;
01177                      }
01178                      break;
01179                   case SUMA_SORT_BY_LLC_DISTANCE:
01180                      if (ASIp->LLCclosestDist < ASIptmp->LLCclosestDist) {
01181                         dlist_ins_prev(list, Elm, (void *)ASIp);
01182                         Found = YUP;
01183                      }
01184                      break;
01185                   case SUMA_SORT_BY_LL_QUAD:
01186                      if (ASIp->Quad[0] == SUMA_LOWER_LEFT_SCREEN || ASIp->Quad[1] == SUMA_LOWER_LEFT_SCREEN) {
01187                         SUMA_LH("Found a LLS");
01188                         dlist_ins_prev(list, dlist_head(list), (void *)ASIp);
01189                         Found = YUP;
01190                      }else {
01191                         dlist_ins_next(list, dlist_tail(list), (void *)ASIp);
01192                         Found = YUP;
01193                      }
01194                      break;
01195                   case SUMA_NO_SORT:
01196                      dlist_ins_next(list, Elm, (void *)ASIp); 
01197                      Found = YUP;
01198                      break;
01199                   default:
01200                      SUMA_S_Err("Whatchyoutalkingboutwillis?\nBad, bad bad bad.");
01201                      SUMA_RETURN(NULL);
01202                }
01203                if (!Found && Elm == dlist_tail(list)) {
01204                   dlist_ins_next(list, Elm, (void *)ASIp); 
01205                   Found = YUP;
01206                }
01207             } while (!Found); 
01208       }
01209       
01210    }
01211    if (LocalHead) {
01212       Elm = NULL;
01213       i = 0;
01214       fprintf (SUMA_STDERR,"%s: Sorting by %d order\n", FuncName, opt);
01215       do {
01216          if (!Elm) {
01217             Elm = dlist_head(list);
01218          } else {
01219             Elm = dlist_next(Elm);
01220          }
01221          ASIp = (SUMA_AxisSegmentInfo *)Elm->data;
01222          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", 
01223                      FuncName, i, ASIp->AxisDim, ASIp->MidSegDist, ASIp->MidFaceDist, ASIp->Quad[0], ASIp->Quad[1], ASIp->world_length, ASIp->screen_length_x, ASIp->screen_length_y);
01224          ++i;
01225       } while(Elm != dlist_tail(list));
01226    }
01227    SUMA_free(ASI); ASI = NULL;
01228    SUMA_LH("Returning");
01229    SUMA_RETURN(list);
01230 }
01231 
01232 
01233 /*!
01234    \sa Labbook NIH-4 page 21 for annotation of Box Axis ....
01235 */
01236 SUMA_Boolean SUMA_DrawAxis (SUMA_Axis* Ax, SUMA_SurfaceViewer *sv)
01237 { 
01238    static char FuncName[]={"SUMA_DrawAxis"};
01239    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
01240    double P1[3], P2[3], cP[8][3], SC[12][3], d[12];
01241    int i, N_Ax;
01242    DList *slist=NULL;
01243    DListElmt *Elm=NULL;
01244    SUMA_AxisSegmentInfo *ASI = NULL;
01245    SUMA_Boolean LocalHead = NOPE;
01246    
01247    SUMA_ENTRY;
01248    
01249    if (!Ax) {
01250       SUMA_SL_Err("Null Axis!");
01251       SUMA_RETURN(NOPE);
01252    }
01253    
01254    glLineWidth(Ax->LineWidth);
01255    switch (Ax->Stipple) {
01256       case SUMA_DASHED_LINE:
01257          glEnable(GL_LINE_STIPPLE);
01258          glLineStipple (1, 0x00FF); /* dashed, see OpenGL Prog guide, page 55 */
01259          break;
01260       case SUMA_SOLID_LINE:
01261          break;
01262       default:
01263          fprintf(stderr,"Error SUMA_DrawAxis: Unrecognized Stipple option\n");
01264          SUMA_RETURN(NOPE);
01265    }
01266    
01267    switch (Ax->type) {
01268       case SUMA_STD_ZERO_CENTERED:
01269          glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor); /* turn off ambient and diffuse components */
01270          glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
01271          
01272          glMaterialfv(GL_FRONT, GL_EMISSION, Ax->XaxisColor); /*turn on emissivity for axis*/
01273          glBegin(GL_LINES);
01274          glVertex3f(-Ax->XYZspan[0]+Ax->Center[0], Ax->Center[1], Ax->Center[2]);
01275          glVertex3f(Ax->XYZspan[0]+Ax->Center[0], Ax->Center[1], Ax->Center[2]); 
01276          glEnd();
01277          
01278          glMaterialfv(GL_FRONT, GL_EMISSION, Ax->YaxisColor); /*turn on emissivity for axis*/
01279          glBegin(GL_LINES);
01280          glVertex3f(Ax->Center[0], -Ax->XYZspan[1]+Ax->Center[1], Ax->Center[2]);
01281          glVertex3f(Ax->Center[0], +Ax->XYZspan[1]+Ax->Center[1], Ax->Center[2]); 
01282          glEnd();
01283          
01284          glMaterialfv(GL_FRONT, GL_EMISSION, Ax->ZaxisColor); /*turn on emissivity for axis*/
01285          glBegin(GL_LINES);
01286          glVertex3f(Ax->Center[0], Ax->Center[1], -Ax->XYZspan[2]+Ax->Center[2]);
01287          glVertex3f(Ax->Center[0], Ax->Center[1], Ax->XYZspan[2]+Ax->Center[2]); 
01288          glEnd();
01289          
01290          glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, NoColor); /*turn off emissivity for axis*/
01291 
01292          break;
01293       case SUMA_SCALE_BOX:
01294          /* Sort segments by distance from screen center*/
01295          slist = SUMA_SortedAxisSegmentList (sv , Ax, SUMA_SORT_BY_LLC_DISTANCE); 
01296                      /* - when using SUMA_BY_PLANE_DISTANCE, it makes sense to show  
01297                         the first 4 segments, but you have no perception of the depth
01298                         - when using SUMA_NO_SORT, show all 12 segments so you'll see the box
01299                         - The world distance thingy does not quite work because because the plane you want to
01300                         hide is the one opposite to the one closest to your face. That plane is not
01301                         necessarily the farthest from sv->Pcenter_close, perhaps what you need to do is 
01302                         define the lower left point of the box and allow for either a boxed axis
01303                         or a 3d axis from the lower left corner.... 
01304                         - So I am now using the screen coordinates SUMA_SORT_BY_LLC_DISTANCE and SUMA_SORT_BY_LL_QUAD,
01305                         and sorting by SUMA_SORT_BY_LLC_DISTANCE works best. You can just show the first 3 axis and you're
01306                         cool, for most angles.
01307                         - You also need a pixels/mm number
01308                         to decide on where to put the text.*/ 
01309          
01310          if (sv->ShowWorldAxis == SUMA_THREE_WAX || sv->ShowWorldAxis == SUMA_THREE_TEXT_WAX) N_Ax = 3;
01311          else N_Ax = slist->size;
01312  
01313          Elm = dlist_head(slist); i = 0;
01314          do {
01315             ASI = (SUMA_AxisSegmentInfo *)Elm->data;
01316             if (ASI->AxisDim == 0) {
01317                if (LocalHead) fprintf(SUMA_STDERR,"%s: X axis, i = %d, SegIndex = %d, world, Sx, Sy = %.2f,%.2f,%.2f, off = %f, %f %f\n", FuncName, i, ASI->SegIndex, ASI->world_length, ASI->screen_length_x, ASI->screen_length_y, ASI->TxOff[0], ASI->TxOff[1],ASI->TxOff[2]); 
01318             } else if (ASI->AxisDim == 1) {
01319                if (LocalHead) fprintf(SUMA_STDERR,"%s: Y axis, i = %d, SegIndex = %d, world, Sx, Sy = %.2f,%.2f,%.2f, off = %f, %f %f\n", FuncName, i, ASI->SegIndex, ASI->world_length, ASI->screen_length_x, ASI->screen_length_y, ASI->TxOff[0], ASI->TxOff[1],ASI->TxOff[2]); 
01320             } else if (ASI->AxisDim == 2) {
01321                if (LocalHead) fprintf(SUMA_STDERR,"%s: Z axis, i = %d, SegIndex = %d, world, Sx, Sy = %.2f,%.2f,%.2f, off = %f, %f %f\n", FuncName, i, ASI->SegIndex, ASI->world_length, ASI->screen_length_x, ASI->screen_length_y, ASI->TxOff[0], ASI->TxOff[1],ASI->TxOff[2]); 
01322             } else { SUMA_S_Err("Major bobo."); SUMA_RETURN(NOPE); }
01323             
01324             if (i < 3 && (sv->ShowWorldAxis == SUMA_THREE_TEXT_WAX || sv->ShowWorldAxis == SUMA_BOX_TEXT_WAX)) 
01325                SUMA_DrawLineAxis (ASI, Ax, YUP);
01326             else SUMA_DrawLineAxis (ASI, Ax, NOPE);
01327             
01328             SUMA_free(ASI); ASI = NULL; 
01329             if (Elm != dlist_tail(slist)) {
01330                Elm = dlist_next(Elm); 
01331             } else {
01332                Elm = NULL;
01333             }
01334             ++i;
01335          } while (i < N_Ax && Elm);   
01336          
01337          /* destroy list */
01338          dlist_destroy(slist);
01339          SUMA_free(slist); slist = NULL;
01340          break;
01341       default:
01342          SUMA_S_Err("Should not be here.");
01343          SUMA_RETURN(NOPE);
01344          break;
01345    }
01346    switch (Ax->Stipple) {
01347       case SUMA_DASHED_LINE:
01348          glDisable(GL_LINE_STIPPLE);
01349          break;
01350       case SUMA_SOLID_LINE:
01351          break;
01352    }
01353    SUMA_RETURN (YUP);
01354 }
01355 
01356 /*!
01357    \brief writes axis text 
01358 */
01359 SUMA_Boolean SUMA_AxisText(SUMA_AxisSegmentInfo *ASIp, double *Ps)
01360 {
01361    static char FuncName[]={"SUMA_AxisText"};
01362    GLboolean valid;
01363    GLfloat rpos[4];
01364    char txt[20]={"What the hell?"};
01365    int is;
01366    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
01367    static float txcol[3] = {1, 1, 1};
01368    static int width, height;
01369    SUMA_Boolean LocalHead = NOPE;
01370 
01371    SUMA_ENTRY;
01372 
01373       
01374    glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, NoColor); 
01375    glMaterialfv(GL_FRONT, GL_EMISSION, txcol); /*turn on emissidity for text*/
01376    glRasterPos3f(Ps[0], Ps[1], Ps[2]);
01377    glGetFloatv(GL_CURRENT_RASTER_POSITION, rpos);
01378    glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
01379    if (LocalHead) fprintf(SUMA_STDERR, "%s: Raster position (%g,%g, %g) is %s\n",
01380       FuncName, rpos[0], rpos[1], rpos[2], valid ? "valid" : "INVALID");
01381 
01382    /* do some text action */
01383    if (valid) {
01384       glColor3fv(txcol); 
01385       sprintf(txt,"%.1f", Ps[ASIp->AxisDim]);
01386       /* sprintf(txt,"%s", MV_format_fval2(Ps[ASIp->AxisDim], 5)); */
01387       for (is=0; txt[is] != '\0'; is++) {
01388          glutBitmapCharacter(GLUT_BITMAP_9_BY_15, txt[is]);
01389       }  
01390    }
01391    glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);  /*turn off emissidity for text*/ 
01392       
01393    SUMA_RETURN(YUP);
01394 }
01395 
01396 /*! 
01397    \brief Draws a scale line.
01398    
01399    \param ASIp (SUMA_AxisSegmentInfo *) structure containing segment info
01400    \param Ax (SUMA_Axis *)
01401 */
01402 SUMA_Boolean SUMA_DrawLineAxis ( SUMA_AxisSegmentInfo *ASIp, SUMA_Axis *Ax, SUMA_Boolean AddText)
01403 {
01404    static char FuncName[]={"SUMA_DrawLineAxis"};
01405    double u3[3],nu, nu3, txofffac, size[2], space[2];
01406    double Pt[3], Ps[3];
01407    int prec = 1000, NmT;
01408    int i, jj, nTick[2];
01409    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
01410    SUMA_Boolean LocalHead = NOPE;
01411       
01412    SUMA_ENTRY;
01413          
01414    glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor); /* turn off ambient and diffuse components */
01415    glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
01416             
01417    if (ASIp->AxisDim == 0) {
01418       glMaterialfv(GL_FRONT, GL_EMISSION, Ax->XaxisColor); /*turn on emissivity for X axis*/
01419       if (LocalHead) fprintf(SUMA_STDERR,"%s: X axis\n", FuncName); 
01420    } else if (ASIp->AxisDim == 1) {
01421       glMaterialfv(GL_FRONT, GL_EMISSION, Ax->YaxisColor); /*turn on emissivity for Y axis*/
01422       if (LocalHead) fprintf(SUMA_STDERR,"%s: Y axis\n", FuncName); 
01423    } else if (ASIp->AxisDim == 2) {
01424       glMaterialfv(GL_FRONT, GL_EMISSION, Ax->ZaxisColor); /*turn on emissivity for Z axis*/
01425       if (LocalHead) fprintf(SUMA_STDERR,"%s: Z axis\n", FuncName); 
01426    }
01427             
01428    glBegin(GL_LINES);
01429    /* draw the line */
01430    glVertex3f(ASIp->P1[0], ASIp->P1[1], ASIp->P1[2]);
01431    glVertex3f(ASIp->P2[0], ASIp->P2[1], ASIp->P2[2]);
01432 
01433    /* work the ticks */
01434    /* unit vector */
01435    SUMA_UNIT_VEC(ASIp->P1, ASIp->P2, u3, nu3);
01436    for (jj=0; jj<2; ++jj) {
01437       if (jj == 0) { 
01438          space[0] = Ax->mTspace;
01439          size[0] = Ax->mTsize;
01440       } else {
01441          space[1] = Ax->MTspace;
01442          size[1] = Ax->MTsize;
01443       }
01444       
01445       /* starting point */
01446       /* is ASIp->P1 an OK point ?*/
01447       SUMA_NORM_VEC(ASIp->P1, 3, nu);
01448       if (! ( (int)(prec * nu) % (int)(prec * space[jj]) ) ) {
01449          /* a good starting point */
01450          SUMA_COPY_VEC(ASIp->P1, Pt, 3, float, float);
01451          SUMA_LH("Using ASIp->P1 as starting tick point"); 
01452       } else {
01453           NmT = (int)(prec * nu) / (int)(prec * space[jj]); NmT /= prec;
01454           Pt[0] = NmT * space[jj] * u3[0] +ASIp->P1[0]; Pt[1] = NmT * space[jj] * u3[1]+ASIp->P1[1];  Pt[2] = NmT * space[jj] * u3[2]+ASIp->P1[2];
01455       }
01456       if (LocalHead) fprintf(SUMA_STDERR,"%s:\nStarting ticks at [%f %f %f]\nnu3 = %f\n", FuncName, Pt[0], Pt[1], Pt[2], nu3);
01457 
01458 
01459       /* draw the ticks */
01460       i = 0;
01461       if (LocalHead) fprintf(SUMA_STDERR,"%s:\nspace = %f\nsize = %f\n", FuncName, space[jj], size[jj]);
01462       if (Ax->DoCross) {
01463          size[jj] /= 2.0;
01464          while (i*space[jj] < nu3) {
01465             Ps[0] = i*space[jj]*u3[0] + Pt[0]; Ps[1] = i*space[jj]*u3[1] + Pt[1]; Ps[2] = i*space[jj]*u3[2] + Pt[2]; /* center */
01466             #if 0 
01467                if (LocalHead) fprintf(SUMA_STDERR,"%s:\nPs = [%f %f %f]; \n", FuncName, Ps[0], Ps[1], Ps[2]);
01468             #endif
01469             glVertex3f(Ps[0]-ASIp->tick1_dir[0]*size[jj], Ps[1]-ASIp->tick1_dir[1]*size[jj], Ps[2]-ASIp->tick1_dir[2]*size[jj]);
01470             glVertex3f(Ps[0]+ASIp->tick1_dir[0]*size[jj], Ps[1]+ASIp->tick1_dir[1]*size[jj], Ps[2]+ASIp->tick1_dir[2]*size[jj]);
01471             glVertex3f(Ps[0]-ASIp->tick2_dir[0]*size[jj], Ps[1]-ASIp->tick2_dir[1]*size[jj], Ps[2]-ASIp->tick2_dir[2]*size[jj]);
01472             glVertex3f(Ps[0]+ASIp->tick2_dir[0]*size[jj], Ps[1]+ASIp->tick2_dir[1]*size[jj], Ps[2]+ASIp->tick2_dir[2]*size[jj]);
01473             ++i;
01474          }
01475       } else {
01476          while (i*space[jj] < nu3) {
01477             Ps[0] = i*space[jj]*u3[0] + Pt[0]; Ps[1] = i*space[jj]*u3[1] + Pt[1]; Ps[2] = i*space[jj]*u3[2] + Pt[2]; /* center */
01478             #if 0 
01479               if (LocalHead) fprintf(SUMA_STDERR,"%s:\nPs = [%f %f %f]; \n", FuncName, Ps[0], Ps[1], Ps[2]);
01480             #endif
01481             glVertex3f(Ps[0], Ps[1], Ps[2]);
01482             glVertex3f(Ps[0]+ASIp->tick1_dir[0]*size[jj], Ps[1]+ASIp->tick1_dir[1]*size[jj], Ps[2]+ASIp->tick1_dir[2]*size[jj]);
01483             glVertex3f(Ps[0], Ps[1], Ps[2]);
01484             glVertex3f(Ps[0]+ASIp->tick2_dir[0]*size[jj], Ps[1]+ASIp->tick2_dir[1]*size[jj], Ps[2]+ASIp->tick2_dir[2]*size[jj]);
01485                #if 0 /* for a little debug */
01486                if (jj==1) {
01487                   glVertex3f(Ps[0], Ps[1], Ps[2]);
01488                   txofffac = 1.0 * size[1];
01489                   Ps[0] = i*space[1]*u3[0] + Pt[0] + txofffac * ASIp->TxOff[0]; 
01490                   Ps[1] = i*space[1]*u3[1] + Pt[1] + txofffac * ASIp->TxOff[1]; 
01491                   Ps[2] = i*space[1]*u3[2] + Pt[2] + txofffac * ASIp->TxOff[2];
01492                   glVertex3f(Ps[0], Ps[1], Ps[2]);
01493                }
01494                #endif
01495             ++i;
01496          }
01497       }
01498       nTick[jj] = i-1;
01499       
01500       
01501    }
01502    
01503    glEnd();
01504 
01505    glMaterialfv(GL_FRONT_AND_BACK, GL_EMISSION, NoColor); /*turn off emissivity for axis*/
01506    
01507          
01508 
01509    if (AddText) { /* do the text for major ticks only */
01510       float MinYstep, MinXstep, dSxT, dSyT, curXstep, curYstep;
01511       int OKnext;
01512       dSxT = (float)fabs(ASIp->screen_length_x) / (float)nTick[1];
01513       dSyT = (float)fabs(ASIp->screen_length_y) / (float)nTick[1];
01514       MinYstep = 15 ; /* height of letters in pixels (using GLUT_BITMAP_9_BY_15) */
01515       MinXstep = 9 * 5; /* length of string in pixels (around 5 chars, including sign, using %.1f )*/
01516       if (LocalHead) fprintf (SUMA_STDERR,"%s:\ndS = %f, %f\n", FuncName, dSxT, dSyT);
01517       i = 0;
01518       if (Ax->DoCross) { /* size has already been modified above ... */
01519          /* perhaps add a factor to the shift below, we'll see .. */
01520          txofffac = 2.0 * size[1];
01521       } else {
01522          txofffac = 1.0 * size[1];
01523       }
01524             OKnext = 1;
01525             curXstep =0; curYstep=0;
01526             while (i*space[1] < nu3) {
01527                if(OKnext) {
01528                   Ps[0] = i*space[1]*u3[0] + Pt[0] + txofffac * ASIp->TxOff[0]; 
01529                   Ps[1] = i*space[1]*u3[1] + Pt[1] + txofffac * ASIp->TxOff[1]; 
01530                   Ps[2] = i*space[1]*u3[2] + Pt[2] + txofffac * ASIp->TxOff[2];
01531                   SUMA_AxisText(ASIp, Ps);
01532                }
01533                curXstep += dSxT; curYstep += dSyT; 
01534                if (curXstep > MinXstep || curYstep > MinYstep) { 
01535                   OKnext = 1;
01536                   curXstep =0; curYstep=0;
01537                } else {
01538                   OKnext = 0;
01539                }
01540                ++i;
01541             }
01542    }
01543 
01544    SUMA_RETURN(YUP);
01545 }
01546   
01547 /*!
01548    \brief find ROIs created on SO. ROIs created on a relative of SO will not be 
01549    returned. 
01550    \param SO (SUMA_SurfaceObject *)SO
01551    \param dov (SUMA_DO*) displayable objects vector
01552    \param N_do (int) number of displayable objects
01553    \param N_ROI (int *) to hold the number of DrawnROIs found
01554    \return ROIv (SUMA_DRAWN_ROI **) vector of SUMA_DRAWN_ROI * 
01555       such that ROIv[i]->Parent_idcode_str = SO->idcode_str
01556     
01557    - free  ROIv with SUMA_free(ROIv);
01558      
01559    \sa SUMA_Find_ROIrelatedtoSO 
01560 */
01561 SUMA_DRAWN_ROI **SUMA_Find_ROIonSO (SUMA_SurfaceObject *SO, SUMA_DO* dov, int N_do, int *N_ROI)
01562 {
01563    static char FuncName[]={"SUMA_Find_ROIonSO"};
01564    SUMA_DRAWN_ROI **ROIv=NULL;
01565    SUMA_DRAWN_ROI *D_ROI = NULL;
01566    int i, roi_cnt=0;
01567    SUMA_Boolean LocalHead = NOPE;
01568    
01569    SUMA_ENTRY;
01570    
01571    *N_ROI = -1;
01572    
01573    /* allocate for maximum */
01574    ROIv = (SUMA_DRAWN_ROI **)SUMA_malloc(sizeof(SUMA_DRAWN_ROI *)*N_do);
01575    if (!ROIv) {
01576       SUMA_SL_Crit("Failed to allocate for ROIv");
01577       SUMA_RETURN(NULL);
01578    }
01579    
01580    roi_cnt=0;
01581    for (i=0; i < N_do; ++i) {
01582       if (dov[i].ObjectType == ROIdO_type) {
01583          D_ROI = (SUMA_DRAWN_ROI *)dov[i].OP;
01584          if (!strncmp(D_ROI->Parent_idcode_str, SO->idcode_str, strlen(SO->idcode_str))) {
01585             SUMA_LH("Found an ROI");
01586             ROIv[roi_cnt] = D_ROI;
01587             ++roi_cnt;
01588          }
01589       }
01590       if (dov[i].ObjectType == ROIO_type) {
01591          SUMA_SL_Warn("ROIO_types are being ignored.");
01592       }
01593    }
01594    
01595    /* realloc */
01596    ROIv = (SUMA_DRAWN_ROI **)SUMA_realloc(ROIv, sizeof(SUMA_DRAWN_ROI *)*roi_cnt);
01597    if (!ROIv) {
01598       SUMA_SL_Crit("Failed to reallocate for ROIv");
01599       SUMA_RETURN(NULL);
01600    }
01601    *N_ROI = roi_cnt;
01602    
01603    SUMA_RETURN(ROIv);
01604 }
01605 
01606 /*!
01607    \brief find ROIs related to SO. ROIs created on a relative of SO will be returned. 
01608    \param SO (SUMA_SurfaceObject *)SO
01609    \param dov (SUMA_DO*) displayable objects vector
01610    \param N_do (int) number of displayable objects
01611    \param N_ROI (int *) to hold the number of DrawnROIs found
01612    \return ROIv (SUMA_DRAWN_ROI **) vector of SUMA_DRAWN_ROI * 
01613       such that ROIv[i]->Parent_idcode_str = SO->idcode_str
01614     
01615    - free  ROIv with SUMA_free(ROIv);
01616 
01617    \sa SUMA_Find_ROIonSO
01618 */
01619 SUMA_DRAWN_ROI **SUMA_Find_ROIrelatedtoSO (SUMA_SurfaceObject *SO, SUMA_DO* dov, int N_do, int *N_ROI)
01620 {
01621    static char FuncName[]={"SUMA_Find_ROIrelatedtoSO"};
01622    SUMA_DRAWN_ROI **ROIv=NULL;
01623    SUMA_DRAWN_ROI *D_ROI = NULL;
01624    int i, roi_cnt=0;
01625    SUMA_Boolean LocalHead = NOPE;
01626    
01627    SUMA_ENTRY;
01628    
01629    *N_ROI = -1;
01630    
01631    /* allocate for maximum */
01632    ROIv = (SUMA_DRAWN_ROI **)SUMA_malloc(sizeof(SUMA_DRAWN_ROI *)*N_do);
01633    if (!ROIv) {
01634       SUMA_SL_Crit("Failed to allocate for ROIv");
01635       SUMA_RETURN(NULL);
01636    }
01637    
01638    roi_cnt=0;
01639    for (i=0; i < N_do; ++i) {
01640       if (dov[i].ObjectType == ROIdO_type) {
01641          D_ROI = (SUMA_DRAWN_ROI *)dov[i].OP;
01642          if (SUMA_isdROIrelated (D_ROI, SO)) {
01643             SUMA_LH("Found an ROI");
01644             ROIv[roi_cnt] = D_ROI;
01645             ++roi_cnt;
01646          }
01647       }
01648       if (dov[i].ObjectType == ROIO_type) {
01649          SUMA_SL_Warn("ROIO_types are being ignored.");
01650       }
01651    }
01652    
01653    /* realloc */
01654    ROIv = (SUMA_DRAWN_ROI **)SUMA_realloc(ROIv, sizeof(SUMA_DRAWN_ROI *)*roi_cnt);
01655    if (!ROIv) {
01656       SUMA_SL_Crit("Failed to reallocate for ROIv");
01657       SUMA_RETURN(NULL);
01658    }
01659    *N_ROI = roi_cnt;
01660    
01661    SUMA_RETURN(ROIv);
01662 }
01663 
01664 /*! Create the ROIs for a particular surface */
01665 SUMA_Boolean SUMA_Draw_SO_ROI (SUMA_SurfaceObject *SO, SUMA_DO* dov, int N_do)
01666 {
01667    static char FuncName[]={"SUMA_Draw_SO_ROI"};
01668    GLfloat ROI_SphCol[] = {1.0, 0.0, 0.0, 1.0};
01669    GLfloat ROI_SphCol_frst[] = {1.0, 0.0, 0.0, 1.0};
01670    GLfloat ROI_FaceGroup[] = {0.8, 0.3, 1.0, 1.0 };
01671    GLfloat ROI_NodeGroup[] = {0.8, 0.3, 0.5, 1.0 };
01672    GLfloat ROI_EdgeGroup[] = {0.8, 0.8, 0.1, 1.0 };
01673    GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
01674    GLfloat NoCol[4] = {0.0, 0.0, 0.0, 0.0};
01675    GLfloat Red[4] = {1.0, 0.0, 0.0, 1.0};
01676    GLfloat Green[4] = {0.0, 1.0, 0.0, 1.0};
01677    GLfloat Blue[4] = {0.0, 0.0, 1.0, 1.0};
01678    GLfloat Yellow[4] = {1.0, 1.0, 0.0, 1.0};
01679    GLfloat Cyan[4] = {0.0, 1.0, 1.0, 1.0};
01680    GLfloat Pink[4] = {1.0, 0.0, 1.0, 1.0};
01681    int i, id, ii, id1,id2, id3, EdgeIndex, FaceIndex, Node1, Node2, Node3, N_ROId=0, idFirst=0;
01682    float dx, dy, dz = 0.0;
01683    SUMA_DRAWN_ROI *D_ROI = NULL;
01684    SUMA_ROI_DATUM *ROId=NULL;
01685    SUMA_ROI *ROI = NULL;
01686    DListElmt *NextElm=NULL;
01687    SUMA_Boolean LocalHead = NOPE;
01688    
01689    SUMA_ENTRY;
01690    
01691    
01692    for (i=0; i < N_do; ++i) {
01693       switch (dov[i].ObjectType) { /* case Object Type */
01694          case ROIdO_type:
01695             D_ROI = (SUMA_DRAWN_ROI *)dov[i].OP;
01696             if (!D_ROI->ROIstrokelist) {
01697                fprintf (SUMA_STDERR, "Error %s: NULL ROIstrokeList.\n", FuncName);
01698                SUMA_RETURN (NOPE);
01699             }else if (!dlist_size(D_ROI->ROIstrokelist)) {
01700                if (LocalHead) fprintf (SUMA_STDERR, "%s: Empty ROIstrokelist.\n", FuncName);
01701                break;
01702             }
01703             if (SUMA_isdROIrelated (D_ROI, SO)) { /* draw it */
01704                if (LocalHead) fprintf(SUMA_STDERR, "%s: Drawing Drawn ROI %s (Status %d)\n", FuncName, D_ROI->Label, D_ROI->DrawStatus);
01705                if (D_ROI->DrawStatus == SUMA_ROI_InCreation) {
01706                   switch (D_ROI->Type) {
01707                      case SUMA_ROI_OpenPath:
01708                         SUMA_LH("Red first, Green next");
01709                         SUMA_COPY_VEC(Red, ROI_SphCol_frst, 4, GLfloat, GLfloat);
01710                         SUMA_COPY_VEC(Green, ROI_SphCol, 4, GLfloat, GLfloat);     
01711                         break;   
01712                      case SUMA_ROI_ClosedPath:
01713                         SUMA_LH("Yellow first, Cyan next");
01714                         SUMA_COPY_VEC(Yellow, ROI_SphCol_frst, 4, GLfloat, GLfloat);
01715                         SUMA_COPY_VEC(Cyan, ROI_SphCol, 4, GLfloat, GLfloat);      
01716                         break;   
01717                      case SUMA_ROI_FilledArea:
01718                         SUMA_LH("Pink First, Yellow Next");
01719                         SUMA_COPY_VEC(Pink, ROI_SphCol_frst, 4, GLfloat, GLfloat);
01720                         SUMA_COPY_VEC(Cyan, ROI_SphCol, 4, GLfloat, GLfloat);       
01721                         break;   
01722                      default:
01723                         SUMA_LH("Default");
01724                         ROI_SphCol_frst[0] = 1.0; ROI_SphCol_frst[1] = 0.3; ROI_SphCol_frst[2] = 1.0; ROI_SphCol_frst[3] = 1.0;     
01725                         ROI_SphCol[0] = 1.0; ROI_SphCol[1] = 1.0; ROI_SphCol[2] = 0.0; ROI_SphCol[3] = 1.0;     
01726                         break;
01727 
01728                   }
01729                   /* start with the first element */
01730                   NextElm = NULL;
01731                   N_ROId = 0;
01732                   do {
01733                      if (!NextElm) {
01734                         NextElm = dlist_head(D_ROI->ROIstrokelist);
01735                      }else {
01736                         NextElm = dlist_next(NextElm);
01737                      }
01738                      ROId = (SUMA_ROI_DATUM *)NextElm->data;
01739                      if (ROId->Type == SUMA_ROI_NodeSegment) { 
01740                         if (ROId->N_n) {
01741                            if (!N_ROId) {
01742                               /* draw 1st sphere */
01743                               SUMA_LH("First sphere");
01744                               glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, ROI_SphCol_frst);
01745                               idFirst = 3 * ROId->nPath[0];
01746                               glTranslatef (SO->NodeList[idFirst], SO->NodeList[idFirst+1], SO->NodeList[idFirst+2]);
01747                               gluSphere(SO->NodeMarker->sphobj, SO->NodeMarker->sphrad, SO->NodeMarker->slices, SO->NodeMarker->stacks);
01748                               glTranslatef (-SO->NodeList[idFirst], -SO->NodeList[idFirst+1], -SO->NodeList[idFirst+2]);
01749                            } 
01750 
01751                            glLineWidth(6);
01752                            glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, ROI_SphCol);
01753                            /* always start at 1 since the 0th node was draw at the end of the previous ROId */
01754                            for (ii = 1; ii < ROId->N_n; ++ii) {
01755                               id = 3 * ROId->nPath[ii];
01756                               id2 = 3 * ROId->nPath[ii-1];
01757 
01758                               /* draw lines connecting spheres */
01759                               glBegin(GL_LINES);
01760                               glVertex3f(SO->NodeList[id2], SO->NodeList[id2+1], SO->NodeList[id2+2]);
01761                               glVertex3f(SO->NodeList[id], SO->NodeList[id+1], SO->NodeList[id+2]); 
01762                               glEnd();
01763 
01764                               glTranslatef (SO->NodeList[id], SO->NodeList[id+1], SO->NodeList[id+2]);
01765                               gluSphere(SO->NodeMarker->sphobj, SO->NodeMarker->sphrad, SO->NodeMarker->slices, SO->NodeMarker->stacks);
01766                               glTranslatef (-SO->NodeList[id], -SO->NodeList[id+1], -SO->NodeList[id+2]);
01767                            }
01768 
01769 
01770                            ++N_ROId;
01771                         }
01772                      } else { /* non segment type Drawn ROI */
01773                            #if 0 
01774                               /* it is too much to fill with spheres... */
01775                               glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, ROI_NodeGroup);
01776                               for (ii=0; ii < ROId->N_n; ++ii) {
01777                                  id = 3 * ROId->nPath[ii];
01778                                  glTranslatef (SO->NodeList[id], SO->NodeList[id+1], SO->NodeList[id+2]);
01779                                  gluSphere(SO->NodeMarker->sphobj, SO->NodeMarker->sphrad, SO->NodeMarker->slices, SO->NodeMarker->stacks);
01780                                  glTranslatef (-SO->NodeList[id], -SO->NodeList[id+1], -SO->NodeList[id+2]);
01781                               }
01782                            #endif
01783                      }
01784                   } while (NextElm != dlist_tail(D_ROI->ROIstrokelist));
01785                } else {
01786                   /* finished, draw contour */
01787                   SUMA_LH("Finished DROI");
01788                   ROI_SphCol_frst[0] = 1.0; ROI_SphCol_frst[1] = 0.3; ROI_SphCol_frst[2] = 1.0; ROI_SphCol_frst[3] = 1.0;     
01789                   ROI_SphCol[0] = 1.0; ROI_SphCol[1] = 1.0; ROI_SphCol[2] = 0.0; ROI_SphCol[3] = 1.0;
01790                   
01791                   
01792                   if (D_ROI->CE) {
01793                      int id1cont, id2cont, icont;
01794                      /* Draw the contour */
01795                      glLineWidth(6);
01796                      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, D_ROI->FillColor);
01797                      
01798                      for (icont = 0; icont < D_ROI->N_CE; ++icont) {
01799                         SUMA_LH("Drawing contour ...");
01800                         id1cont = 3 * D_ROI->CE[icont].n1;
01801                         id2cont = 3 * D_ROI->CE[icont].n2;
01802                         glBegin(GL_LINES);
01803                         glVertex3f(SO->NodeList[id2cont], SO->NodeList[id2cont+1], SO->NodeList[id2cont+2]);
01804                         glVertex3f(SO->NodeList[id1cont], SO->NodeList[id1cont+1], SO->NodeList[id1cont+2]); 
01805                         glEnd();
01806                      }
01807                   }
01808                   
01809                   
01810                   
01811                }
01812 
01813             }
01814             break;
01815             
01816          case ROIO_type:
01817             /* hopefully he distinction between drawn and not drawn will no longer be needed .... */
01818             ROI = (SUMA_ROI *)dov[i].OP;
01819             if (SUMA_isROIrelated (ROI, SO)) { /* draw it */
01820                if (LocalHead) fprintf(SUMA_STDERR, "%s: Drawing ROI %s \n", FuncName, ROI->Label);
01821                switch (ROI->Type) { /* ROI types */
01822                   case SUMA_ROI_EdgeGroup:
01823                      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, ROI_EdgeGroup);
01824                      for (ii=0; ii < ROI->N_ElInd; ++ii) {
01825                         EdgeIndex = ROI->ElInd[ii];
01826                         Node1 = SO->EL->EL[EdgeIndex][0];
01827                         Node2 = SO->EL->EL[EdgeIndex][1];
01828                         id = 3 * Node1;
01829                         id2 = 3 * Node2;
01830                         
01831                         glLineWidth(3);
01832                         
01833                         glBegin(GL_LINES);
01834                         glVertex3f(SO->NodeList[id2], SO->NodeList[id2+1], SO->NodeList[id2+2]);
01835                         glVertex3f(SO->NodeList[id], SO->NodeList[id+1], SO->NodeList[id+2]); 
01836                         glEnd();
01837                      }
01838                      break;
01839                   case SUMA_ROI_NodeGroup:
01840                      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, ROI_NodeGroup);
01841                      for (ii=0; ii < ROI->N_ElInd; ++ii) {
01842                         id = 3 * ROI->ElInd[ii];
01843                         glTranslatef (SO->NodeList[id], SO->NodeList[id+1], SO->NodeList[id+2]);
01844                         gluSphere(SO->NodeMarker->sphobj, SO->NodeMarker->sphrad, SO->NodeMarker->slices, SO->NodeMarker->stacks);
01845                         glTranslatef (-SO->NodeList[id], -SO->NodeList[id+1], -SO->NodeList[id+2]);
01846                      }
01847                      break;
01848                   case SUMA_ROI_FaceGroup:   
01849                      glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, ROI_FaceGroup);
01850                      for (ii=0; ii < ROI->N_ElInd; ++ii) {
01851                            FaceIndex = ROI->ElInd[ii];
01852                            id = FaceIndex * 3;
01853                          
01854                            Node1 = SO->FaceSetList[id];
01855                            Node2 = SO->FaceSetList[id+1];
01856                            Node3 = SO->FaceSetList[id+2];
01857                            
01858                            id1 = 3 * Node1;
01859                            id2 = 3 * Node2;
01860                            id3 = 3 * Node3;
01861                            
01862                            glLineWidth(6);
01863                            
01864                            #if 0 /* no need for that one, most likely */
01865                               
01866                               dx = SUMA_SELECTED_FACESET_OFFSET_FACTOR * SO->FaceNormList[id];
01867                               dy = SUMA_SELECTED_FACESET_OFFSET_FACTOR * SO->FaceNormList[id+1];
01868                               dz = SUMA_SELECTED_FACESET_OFFSET_FACTOR * SO->FaceNormList[id+2];
01869 
01870 
01871                               glBegin(GL_LINE_LOOP);
01872                                  glVertex3f(SO->NodeList[id1]+dx, SO->NodeList[id1+1]+dy, SO->NodeList[id1+2]+dz);
01873                                  glVertex3f(SO->NodeList[id2]+dx, SO->NodeList[id2+1]+dy, SO->NodeList[id2+2]+dz);
01874                                  glVertex3f(SO->NodeList[id3]+dx, SO->NodeList[id3+1]+dy, SO->NodeList[id3+2]+dz);
01875                               glEnd();
01876 
01877 
01878                               glBegin(GL_LINE_LOOP);
01879                                  glVertex3f(SO->NodeList[id1]-dx, SO->NodeList[id1+1]-dy, SO->NodeList[id1+2]-dz);
01880                                  glVertex3f(SO->NodeList[id2]-dx, SO->NodeList[id2+1]-dy, SO->NodeList[id2+2]-dz);
01881                                  glVertex3f(SO->NodeList[id3]-dx, SO->NodeList[id3+1]-dy, SO->NodeList[id3+2]-dz);
01882                               glEnd();
01883                            #endif
01884                            
01885                            glBegin(GL_LINE_LOOP);
01886                               glVertex3f(SO->NodeList[id1], SO->NodeList[id1+1], SO->NodeList[id1+2]);
01887                               glVertex3f(SO->NodeList[id2], SO->NodeList[id2+1], SO->NodeList[id2+2]);
01888                               glVertex3f(SO->NodeList[id3], SO->NodeList[id3+1], SO->NodeList[id3+2]);
01889                            glEnd();
01890 
01891                      }
01892                      break;
01893                   default:
01894                      fprintf(SUMA_STDERR, "Error %s: Not ready to drawn this type of ROI.\n", FuncName);
01895                      break;
01896                } /* ROI types */
01897             } /* draw it */
01898             break;
01899          default:
01900             /* not an ROI */
01901             break;
01902       }/* case Object Type */
01903       
01904    }
01905 
01906    SUMA_RETURN (YUP);
01907 }         
01908 
01909 /*!
01910    \brief A wrapper for SUMA_Paint_SO_ROIplanes
01911    
01912    Notification of afni is done if requested 
01913 */
01914 SUMA_Boolean SUMA_Paint_SO_ROIplanes_w (SUMA_SurfaceObject *SO, 
01915                                        SUMA_DO* dov, int N_do)
01916 {
01917    static char FuncName[]={"SUMA_Paint_SO_ROIplanes_w"};
01918    NI_element **nelv=NULL;
01919    int N_nelv = 0, ii=0;
01920    SUMA_Boolean CreateNel, LocalHead = NOPE;
01921    
01922    SUMA_ENTRY;
01923    
01924    SUMA_LH("Called");
01925    
01926    CreateNel = SUMAg_CF->ROI2afni;
01927    if (!SUMA_Paint_SO_ROIplanes (SO, SUMAg_DOv, SUMAg_N_DOv,
01928                                  &CreateNel,
01929                                  &nelv, &N_nelv)) {
01930       SUMA_SLP_Err("Failed in SUMA_Paint_SO_ROIplanes.");
01931       SUMA_RETURN(NOPE);
01932    }
01933    
01934    if (SUMAg_CF->ROI2afni != CreateNel) {
01935       /* it was turned off in the function */
01936       SUMAg_CF->ROI2afni = CreateNel;
01937       if (SUMAg_CF->X->DrawROI) {
01938          XmToggleButtonSetState (SUMAg_CF->X->DrawROI->AfniLink_tb, SUMAg_CF->ROI2afni, NOPE);
01939       }
01940    }
01941    
01942    if (SUMAg_CF->ROI2afni) {
01943       SUMA_LH("Should send nels to AFNI...");
01944       if (N_nelv) {
01945          for (ii=0; ii < N_nelv; ++ii) {
01946             SUMA_LH("Send this nel to AFNI.");
01947             /* SUMA_ShowNel(nelv[ii]);*/
01948             if (NI_write_element( SUMAg_CF->ns_v[SUMA_AFNI_STREAM_INDEX] , nelv[ii] , NI_BINARY_MODE ) < 0) {
01949                SUMA_SLP_Err("NI_write_element failed.");
01950             }
01951             SUMA_LH("Free this nel.");
01952             NI_free_element(nelv[ii]) ; nelv[ii] = NULL;
01953          }
01954          SUMA_LH("Now free nelv");
01955          SUMA_free(nelv);nelv = NULL;
01956       }
01957    }
01958    
01959    SUMA_RETURN(YUP);
01960    
01961 }
01962 
01963 /*!
01964    \brief Where real men draw their ROIs
01965    
01966    - First the function creates a list
01967    of the various ROI planes on SO
01968    - For each plane
01969       - Fill them up with ROIs nodes, do mixing if necessary
01970       - If CreateNel is YUP, a NI data set of the type
01971        SUMA_NODE_ROI is created for each color plane.
01972        These data sets are meant to be sent to AFNI in realtime.
01973        You will have to free nelvp
01974    
01975    
01976 */
01977 SUMA_Boolean SUMA_Paint_SO_ROIplanes ( SUMA_SurfaceObject *SO, 
01978                                        SUMA_DO* dov, int N_do, 
01979                                        SUMA_Boolean *CreateNel,
01980                                        NI_element ***nelvp, int *N_nelvp)
01981 {
01982    static char FuncName[]={"SUMA_Paint_SO_ROIplanes"};
01983    DList * ROIPlaneList = NULL;
01984    SUMA_ROI_PLANE *Plane = NULL;
01985    int *N_ColHist = NULL, *ivect = NULL, *Nodes=NULL, *ilab=NULL, *labvect=NULL;
01986    float *r=NULL, *g=NULL, *b=NULL, *rvect=NULL, *gvect=NULL, *bvect=NULL;
01987    float FillColor[3];
01988    int i, ii, N_NewNode = 0, istore, OverInd=-1, inode, i_D_ROI, LastOfPreSeg, N_Nodes=0;
01989    SUMA_OVERLAY_PLANE_DATA sopd;
01990    DListElmt *NextPlaneElm = NULL, *NextROIElm = NULL, *NextElm=NULL;
01991    SUMA_DRAWN_ROI *D_ROI = NULL;
01992    SUMA_ROI_DATUM *ROId=NULL;
01993    NI_element **nelv = NULL;
01994    SUMA_STANDARD_CMAP mapcode;
01995    DList *list=NULL;
01996    SUMA_EngineData *ED = NULL;
01997    SUMA_Boolean Unique = NOPE;
01998    SUMA_Boolean LocalHead = NOPE;
01999             
02000    SUMA_ENTRY;
02001    
02002    SUMA_LH("Called");
02003    /* select the color map */
02004    {
02005       char *eee = getenv("SUMA_ROIColorMap");
02006       if (eee) {
02007          if (strcmp (eee, "bgyr64") == 0) {
02008             mapcode = SUMA_CMAP_BGYR64;
02009          } else if (strcmp (eee, "ygbrp64") == 0) {
02010             mapcode = SUMA_CMAP_ROI64;
02011          } else if (strcmp (eee, "roi64") == 0) {
02012             mapcode = SUMA_CMAP_ROI64;
02013          } else if (strcmp (eee, "ygbrp128") == 0) {
02014             mapcode = SUMA_CMAP_ROI128;
02015          } else if (strcmp (eee, "ygbrp256") == 0) {
02016             mapcode = SUMA_CMAP_ROI256;
02017          } else if (strcmp (eee, "roi128") == 0) {
02018             mapcode = SUMA_CMAP_ROI128;
02019          } else if (strcmp (eee, "roi256") == 0) {
02020             mapcode = SUMA_CMAP_ROI256;
02021          } else {
02022             mapcode = SUMA_CMAP_ROI128;
02023             if (LocalHead) fprintf(SUMA_STDERR,"%s: Unrecognized option. Using default\n", FuncName);
02024          }
02025       } else {
02026          mapcode = SUMA_CMAP_ROI128;
02027          if (LocalHead) fprintf(SUMA_STDERR,"%s: Undefined environment. Using default\n", FuncName);
02028       }
02029    }
02030    if (LocalHead) {
02031       int N_tmp;
02032       char *nm_tmp = SUMA_StandardMapName (mapcode, &N_tmp);
02033       fprintf(SUMA_STDERR,"%s: mapcode = %d, named %s %d cols\n", FuncName, mapcode, nm_tmp, N_tmp);
02034    }
02035    /* intilialize list */
02036    ROIPlaneList = SUMA_Addto_ROIplane_List (NULL, NULL, 0);
02037    /* go through all ROIs and place each under its ROI plane */
02038    for (i=0; i < N_do; ++i) {
02039       switch (dov[i].ObjectType) { /* case Object Type */
02040          case ROIdO_type:
02041             D_ROI = (SUMA_DRAWN_ROI *)dov[i].OP;
02042             break;
02043          default:
02044             D_ROI = NULL;
02045             break;
02046       }
02047       if (D_ROI && SUMA_isdROIrelated (D_ROI, SO)) {
02048          /* found one, put it in list if useful */
02049          if (D_ROI->ROIstrokelist) {
02050                SUMA_LH("Adding plane");
02051                /* add it to plane list */
02052                /* Add the plane, even if it has no strokes in it. 
02053                Otherwise, the last undo will have no effect on the 
02054                paint job. Bug fix Wed Jun 11 11:04:08 EDT 2003*/
02055                ROIPlaneList = SUMA_Addto_ROIplane_List ( ROIPlaneList,
02056                                                          dov, i);
02057                                                          
02058          }
02059       
02060       }
02061    }   
02062    
02063    if (*CreateNel && !nelvp) {
02064       SUMA_SLP_Err("nelvp is null!\n"
02065                    "Turning ROIlink Off.");
02066       *CreateNel = NOPE;
02067    }
02068    if (*CreateNel && !SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX]) {
02069       SUMA_SLP_Err(  "You are not connected\n"
02070                      "to AFNI. Turning \n"
02071                      "ROIlink Off.");
02072       *CreateNel = NOPE;
02073    }
02074    
02075    if (*CreateNel) { 
02076       /* user wants ni elements to sent to AFNI */
02077       nelv = (NI_element **) SUMA_calloc(dlist_size(ROIPlaneList), sizeof(NI_element *));
02078       if (!nelv) {
02079          SUMA_SLP_Err("Failed to allocate\nfor nelv.");
02080          SUMA_RETURN(NOPE);
02081       }
02082       *N_nelvp = dlist_size(ROIPlaneList);
02083    }
02084    
02085    /* For each ROI plane */
02086    NextPlaneElm = NULL;
02087    for (i=0; i < dlist_size(ROIPlaneList); ++i) {
02088       if (!NextPlaneElm) NextPlaneElm = dlist_head(ROIPlaneList);
02089       else NextPlaneElm = NextPlaneElm->next;
02090 
02091       Plane = (SUMA_ROI_PLANE *)NextPlaneElm->data;
02092       
02093       if (LocalHead) fprintf (SUMA_STDERR,"%s: Processing plane %s\n", FuncName, Plane->name);
02094       
02095       if (!dlist_size(Plane->ROI_index_lst)) continue;
02096       
02097       /* allocate for node color history and all node colors */
02098       N_ColHist = (int *) SUMA_calloc(SO->N_Node, sizeof (int));
02099       r = (float *)SUMA_malloc (SO->N_Node*sizeof(float));
02100       g = (float *)SUMA_malloc (SO->N_Node*sizeof(float));
02101       b = (float *)SUMA_malloc (SO->N_Node*sizeof(float));
02102       if (*CreateNel) ilab = (int *) SUMA_calloc(SO->N_Node, sizeof (int));
02103       if (!N_ColHist || !r || !g || !b || (*CreateNel && !ilab)) {
02104          SUMA_SLP_Crit( "Failed to allocate.\n"
02105                         "for N_ColHist, r, g or b.");
02106          SUMA_RETURN(NOPE);
02107       }
02108       
02109       N_NewNode = 0; /* keep track of the total number of colored nodes */
02110       /* now go through each ROI in that plane and merge the colors */
02111       NextROIElm = NULL;
02112       do {
02113          SUMA_LH("New NextROIElm");
02114          if (!NextROIElm) NextROIElm = dlist_head(Plane->ROI_index_lst);
02115          else NextROIElm = NextROIElm->next;
02116          i_D_ROI = (int)(NextROIElm->data);
02117          if (LocalHead) fprintf (SUMA_STDERR, 
02118                                  "%s: Working with DO %d/%d.\n",
02119                                  FuncName,  i_D_ROI, N_do);  
02120          D_ROI = (SUMA_DRAWN_ROI *) dov[i_D_ROI].OP;
02121          
02122          /* Set the fillcolor */
02123          if (D_ROI->ColorByLabel) {
02124             if (!SUMAg_CF->ROI_CM) {
02125                if (!(SUMAg_CF->ROI_CM = SUMA_GetStandardMap (mapcode))) {
02126                   SUMA_SLP_Err( "Failed to create\n"
02127                                  "color map. Reverting\n"
02128                                  "to FillColors");
02129                   D_ROI->ColorByLabel = NOPE;
02130                }
02131                if (LocalHead) {
02132                   fprintf (SUMA_STDERR,"%s:\nHave colormap of code %d, %d colors.\n", FuncName, mapcode, SUMAg_CF->ROI_CM->N_Col);
02133                }
02134                /* if connected to AFNI, send color map */
02135                if (SUMAg_CF->Connected_v[SUMA_AFNI_STREAM_INDEX] && SUMAg_CF->ROI2afni) {
02136                   list = SUMA_CreateList();
02137                   ED = SUMA_InitializeEngineListData (SE_SendColorMapToAfni);
02138                   if (!SUMA_RegisterEngineListCommand (  list, ED, 
02139                                                          SEF_i, (void*)&mapcode, 
02140                                                          SES_SumaWidget, NULL, NOPE, 
02141                                                          SEI_Head, NULL )) {
02142                      fprintf(SUMA_STDERR,"Error %s: Failed to register command\n", FuncName);
02143                      SUMA_RETURN(NOPE);
02144                   }
02145                   if (!SUMA_Engine (&list)) {
02146                      fprintf(stderr, "Error %s: SUMA_Engine call failed.\n", FuncName);
02147                      SUMA_RETURN(NOPE);
02148                   }
02149                   
02150                }
02151             }
02152          } 
02153          
02154          /* make sure Color ByLabel is possible */
02155          if (D_ROI->ColorByLabel) {
02156             if (D_ROI->iLabel < 0 || D_ROI->iLabel >= SUMAg_CF->ROI_CM->N_Col) {
02157                SUMA_SLP_Err(  "ROI iLabel < 0 or \n"
02158                               "higher than the number\n"
02159                               "of colors in the map.\n"
02160                               "Reverting to FillColors");
02161                D_ROI->ColorByLabel = NOPE;
02162             }
02163          }
02164          
02165          if (D_ROI->ColorByLabel) {
02166             if (D_ROI->iLabel < 0 || D_ROI->iLabel >= SUMAg_CF->ROI_CM->N_Col) {
02167                SUMA_SLP_Err(  "ROI iLabel < 0 or \n"
02168                               "higher than the number\n"
02169                               "of colors in the map.\n"
02170                               "Reverting to FillColors");
02171                D_ROI->ColorByLabel = NOPE;
02172             }
02173             /* coloring for ROIs is straight forward, index based */
02174             D_ROI->FillColor[0] = SUMAg_CF->ROI_CM->M[D_ROI->iLabel][0];
02175             D_ROI->FillColor[1] = SUMAg_CF->ROI_CM->M[D_ROI->iLabel][1];
02176             D_ROI->FillColor[2] = SUMAg_CF->ROI_CM->M[D_ROI->iLabel][2];
02177          } else {
02178             SUMA_COPY_VEC (D_ROI->FillColor, FillColor, 3,float, float);
02179          }
02180          
02181          /* now for each node in the DrawnROI, add its color */
02182          N_Nodes = 0;
02183          Unique = YUP; /* This is to eliminate redundant nodes 
02184                         that can legally occur when the path loops
02185                         over itself. As a result, nodes
02186                         that are visited multiple times appear
02187                         brighter than the surrounding. */
02188          Nodes = SUMA_NodesInROI (D_ROI, &N_Nodes, Unique);
02189          if (Nodes) {
02190             for (ii=0; ii < N_Nodes; ++ii) {
02191                inode = Nodes[ii];
02192                if (!N_ColHist[inode]) {
02193                   r[inode] = D_ROI->FillColor[0];
02194                   g[inode] = D_ROI->FillColor[1];
02195                   b[inode] = D_ROI->FillColor[2];
02196                   if (*CreateNel) ilab[inode] = D_ROI->iLabel;
02197                   ++N_NewNode;
02198                } else { /* already used up color, add new color */
02199                   SUMA_LH("Revisiting Color");
02200                   r[inode] = r[inode] + D_ROI->FillColor[0];
02201                   g[inode] = g[inode] + D_ROI->FillColor[1];
02202                   b[inode] = b[inode] + D_ROI->FillColor[2];
02203                   if (*CreateNel) {
02204                      /* IGNORE repeats for the same node for now */
02205                   }
02206                }
02207                ++N_ColHist[inode];
02208             }
02209             
02210             SUMA_free(Nodes);
02211          }
02212       } while (NextROIElm != dlist_tail(Plane->ROI_index_lst));
02213       
02214       SUMA_LH("Scaling and storing ");
02215       /* create a conveninent list of the colors that goes into */
02216       ivect = (int *)SUMA_malloc(N_NewNode * sizeof(int));
02217       rvect = (float *)SUMA_malloc(N_NewNode * sizeof(float));
02218       gvect = (float *)SUMA_malloc(N_NewNode * sizeof(float));
02219       bvect = (float *)SUMA_malloc(N_NewNode * sizeof(float));
02220       if (*CreateNel) labvect = (int *)SUMA_malloc(N_NewNode * sizeof(int));
02221       if (!ivect || !rvect || !gvect || !bvect || (*CreateNel && !labvect)) {
02222          SUMA_SLP_Crit( "Failed to allocate.\n"
02223                         "for *vect family");
02224          SUMA_RETURN(NOPE);
02225       }
02226       
02227       istore = 0;
02228       for (ii=0; ii < SO->N_Node; ++ii) {
02229          if (N_ColHist[ii]) {
02230             #if 0
02231                /* You do not want to average the colors after summing them
02232                because that will have the effect of dimming them.
02233                Say you had 0 0 1 and 0 1 0
02234                You'll end up with 0 0.5 0.5 which does not have the 
02235                same brightness as the original colors.
02236                You might want to make the brightness uniform but
02237                we leave that for posterity ...
02238                */ 
02239                if (N_ColHist[ii] > 1) {
02240                   /* scale the summed colors for that plane */
02241                   
02242                   r[ii] /= N_ColHist[ii];
02243                   g[ii] /= N_ColHist[ii];
02244                   b[ii] /= N_ColHist[ii];
02245                }
02246             #endif
02247             /* put the colors in the short vectors */
02248             ivect[istore] = ii;
02249             rvect[istore] = r[ii];
02250             gvect[istore] = g[ii];
02251             bvect[istore] = b[ii];
02252             if (*CreateNel) labvect[istore] = ilab[ii];
02253             ++istore;
02254          }
02255       }
02256       
02257       if (LocalHead) fprintf (SUMA_STDERR,"%s: N_NewNode = %d, istore = %d.\n",
02258                                     FuncName, N_NewNode, istore);
02259       SUMA_LH("Freedom");
02260       /* free the big ones */
02261       SUMA_free(N_ColHist); 
02262       SUMA_free(r); 
02263       SUMA_free(g); 
02264       SUMA_free(b);
02265       if (*CreateNel) SUMA_free(ilab);
02266       
02267    /* put the colors in a color plane */
02268       sopd.N = N_NewNode;
02269       sopd.Type = SOPT_ifff;
02270       sopd.Source = SES_Suma;
02271       sopd.GlobalOpacity = 0.3;
02272       sopd.isBackGrnd = NOPE;
02273       sopd.Show = YUP;
02274       sopd.DimFact = 0.5;
02275       sopd.i = (void *)ivect;
02276       sopd.r = (void *)rvect;
02277       sopd.g = (void *)gvect;
02278       sopd.b = (void *)bvect;
02279       sopd.a = NULL;
02280 
02281       SUMA_LH("Calling SUMA_iRGB_to_OverlayPointer");
02282       if (!SUMA_iRGB_to_OverlayPointer (SO, Plane->name, &sopd, &OverInd, dov, N_do, SUMAg_CF->DsetList)) {
02283          SUMA_SLP_Err("Failed to fetch or create overlay pointer.");
02284          SUMA_RETURN(NOPE);
02285       }      
02286       SUMA_LH("Returned SUMA_iRGB_to_OverlayPointer");
02287       
02288       if (*CreateNel) {
02289          NI_element *nel = NULL;
02290          char *TargetVol=NULL;
02291          
02292          /* form the nel for this plane */
02293          SUMA_allow_nel_use(1);
02294          nel = SUMA_NewNel ( SUMA_NODE_ROI, /* one of SUMA_DSET_TYPE */
02295                        SO->LocalDomainParentID, /* idcode of Domain Parent */
02296                        NULL, /* idcode of geometry parent, not useful here*/
02297                        N_NewNode,
02298                        NULL, 
02299                        NULL); /* Number of elements */
02300          
02301          if (!nel) {
02302             SUMA_SLP_Err("Failed in SUMA_NewNel");
02303             SUMA_RETURN(NOPE);
02304          }
02305          
02306          if (N_NewNode) {
02307             /* Add the index column */
02308             SUMA_LH("Adding index column...");
02309             SUMA_allow_nel_use(1);
02310             if (!SUMA_AddNelCol (nel, "node index", SUMA_NODE_INDEX, (void *)ivect, NULL, 1)) {
02311                SUMA_SL_Err("Failed in SUMA_AddNelCol");
02312                SUMA_RETURN(NOPE);
02313             }
02314 
02315             /* Add the label column */
02316             SUMA_LH("Adding label column...");
02317             SUMA_allow_nel_use(1);
02318             if (!SUMA_AddNelCol (nel, "integer label", SUMA_NODE_ILABEL, (void *)labvect, NULL, 1)) {
02319                SUMA_SL_Err("Failed in SUMA_AddNelCol");
02320                SUMA_RETURN(NOPE);
02321             }
02322          }
02323          
02324          /* What is the target volume for this nel */
02325          TargetVol = SUMA_append_replace_string(SO->Group, Plane->name, "-", 0); 
02326          NI_set_attribute (nel, "target_volume", TargetVol);
02327          SUMA_free(TargetVol);
02328          
02329          /* which colormap was used */
02330          NI_set_attribute (nel, "color_map", SUMAg_CF->ROI_CM->Name);
02331          
02332          /* what is the volume parent ? This one will act as a gridparent 
02333             for the functional data set*/
02334          NI_set_attribute (nel, "volume_idcode", SO->VolPar->vol_idcode_str);
02335          
02336          nelv[i] = nel; nel = NULL;
02337          
02338          /* DO NOT FREE ivect, it is used in sopd */
02339          SUMA_free(labvect);
02340       }
02341       
02342    } 
02343    
02344    if (!dlist_size(ROIPlaneList)) {
02345       /* 
02346       SUMA_SLP_Err(  "Flow error\n"
02347                      "You are not expected\n"
02348                      "to land here." );
02349       Do not complain, you can get here if you
02350       are connected to SUMA. 
02351       Aint nothing wrong with this.
02352       */
02353       N_NewNode = 0;
02354       ivect = NULL; 
02355       rvect = NULL;
02356       gvect = NULL;
02357       bvect = NULL;
02358       if (*CreateNel) labvect = NULL;  
02359    }
02360    
02361       
02362    SUMA_LH("Destroying list");
02363    /* destroy plane list */
02364    dlist_destroy (ROIPlaneList);
02365 
02366    /* Set the remix flag for that surface */
02367    if(!SUMA_SetRemixFlag (SO->idcode_str, SUMAg_SVv, SUMAg_N_SVv)) {
02368       fprintf (SUMA_STDERR,"Error %s: Failed in SUMA_SetRemixFlag.\n", FuncName);
02369       SUMA_RETURN(NOPE);
02370    }   
02371    
02372    if (*CreateNel) {
02373       *nelvp = nelv;
02374    }
02375    
02376    /* should be cool, now return */   
02377    SUMA_RETURN(YUP);
02378 }
02379 
02380 /*!
02381    \brief int * SUMA_NodesInROI (SUMA_DRAWN_ROI *D_ROI, int *N_Nodes, SUMA_Boolean Unique) 
02382    Returns a vector containing the number of nodes making up an ROI 
02383    
02384    \param D_ROI (SUMA_DRAWN_ROI *)
02385    \param N_Nodes (int *) updated with the total number of nodes in Nodes
02386    \param Unique (SUMA_Boolean) Remove repeated node occurences
02387    \return Nodes (int *) N_Nodesx1 vector of nodes forming ROI
02388    
02389    - Nodes (and N_Nodes) might have duplicate node entries, unless you set Unique
02390 */
02391 int * SUMA_NodesInROI (SUMA_DRAWN_ROI *D_ROI, int *N_Nodes, SUMA_Boolean Unique) 
02392 {
02393    static char FuncName[]={"SUMA_NodesInROI"};
02394    int *Nodes = NULL, LastOfPreSeg, N_max = -1, ii;
02395    DListElmt *NextElm = NULL;
02396    SUMA_ROI_DATUM *ROId=NULL;
02397    
02398    SUMA_ENTRY;
02399    
02400    if (!dlist_size(D_ROI->ROIstrokelist)) {
02401       *N_Nodes = 0;
02402       SUMA_RETURN (NULL);
02403    }
02404    
02405    /* a quick count of number of nodes */
02406    SUMA_ROI_CRUDE_COUNT_NODES(D_ROI, N_max);
02407    
02408    if (!N_max) {
02409       *N_Nodes = 0;
02410       SUMA_RETURN (NULL);
02411    }
02412     
02413    Nodes = (int*)SUMA_malloc(N_max*sizeof(int));
02414    if (!Nodes) {
02415       SUMA_SLP_Crit("Failed to allocate for Nodes.");
02416       *N_Nodes = -1;
02417       SUMA_RETURN(NULL);
02418    }
02419      
02420    /* Fill 'er up */
02421    *N_Nodes = 0;
02422    LastOfPreSeg = -1; /* index of last node in previous segment */
02423    NextElm = NULL;
02424    do {
02425       if (!NextElm) NextElm = dlist_head(D_ROI->ROIstrokelist);
02426       else NextElm = dlist_next(NextElm);
02427 
02428       ROId = (SUMA_ROI_DATUM *)NextElm->data;
02429       
02430       for (ii=0; ii < ROId->N_n; ++ii) {
02431          if (ROId->nPath[ii] != LastOfPreSeg) {
02432             Nodes[*N_Nodes] = ROId->nPath[ii];
02433             ++ *N_Nodes;
02434          }
02435       }
02436       if (ROId->N_n) { /* store last node of segment */
02437          LastOfPreSeg = ROId->nPath[ROId->N_n - 1];
02438       } else {
02439          LastOfPreSeg = -1;
02440       }
02441    } while (NextElm != dlist_tail(D_ROI->ROIstrokelist));
02442 
02443    /* user wants sorting ? */
02444    if (Unique) {
02445       int *Nodes_Unq = NULL;
02446       int N_Nodes_Unq = -1;
02447       Nodes_Unq = SUMA_UniqueInt (Nodes, *N_Nodes, &N_Nodes_Unq, 0);
02448       if (Nodes) SUMA_free(Nodes);  Nodes = NULL; 
02449       *N_Nodes = N_Nodes_Unq;
02450       Nodes = Nodes_Unq;
02451    } 
02452       
02453    SUMA_RETURN(Nodes);
02454    
02455 }
02456 
02457 void SUMA_Free_ROI_PlaneData (void *da)
02458 {
02459    static char FuncName[]={"SUMA_Free_ROI_PlaneData"};
02460    SUMA_ROI_PLANE *pl = NULL;
02461    
02462    SUMA_ENTRY;
02463    
02464    pl = (SUMA_ROI_PLANE *)da;
02465    
02466    if (!pl) SUMA_RETURNe;
02467    
02468    /* destroy the list containing ROIs belonging to plane */
02469    if (pl->ROI_index_lst) dlist_destroy (pl->ROI_index_lst);
02470    if (pl->name) SUMA_free(pl->name);
02471    
02472    /* now free the structure */
02473    SUMA_free(pl);
02474    
02475    SUMA_RETURNe;
02476 }
02477 
02478 /*!
02479    \brief Adds and ROI in the list of ROI planes
02480    
02481    ROIplaneList = SUMA_Addto_ROIplane_List (ROIplaneListIn,
02482                                              dov, idov);
02483    
02484    \param ROIplaneListIn (DList *) the list of 
02485       ROI planes
02486    \param dov (SUMA_DO *) vector of displayable objects
02487    \param idov (int) index into dov of DrawnROI object
02488    \return ROIplaneList DList *) the updated
02489       list of ROI planes
02490    
02491    - If the ROI is part of a new plane, 
02492    the plane is added to the list and the ROI
02493    is placed under that plane.
02494    - If the ROI is part of a plane in the list
02495    then the ROI is placed under that plane
02496    - The first time you call the function, 
02497    send in NULL for ROIplaneListIn to initialize
02498    the list.
02499    - The subsequent times you call the function
02500    use the returned ROIplaneList for ROIplaneListIn
02501    
02502 */
02503 DList * SUMA_Addto_ROIplane_List (DList *ROIplaneListIn, SUMA_DO *dov, int idov)
02504 {
02505    static char FuncName[]={"SUMA_Addto_ROIplane_List"};
02506    DList *ROIplaneList = NULL;
02507    DListElmt *NextElm = NULL;
02508    SUMA_DRAWN_ROI *D_ROI = NULL;
02509    char *UsedName = NULL;
02510    SUMA_DO *doel = NULL;
02511    SUMA_ROI_PLANE *Plane;
02512    int i;
02513    SUMA_Boolean found = NOPE, LocalHead = NOPE;
02514    
02515    SUMA_ENTRY;
02516    
02517    if (!ROIplaneListIn) { /* initialization land */
02518       ROIplaneList = (DList *)SUMA_malloc(sizeof(DList));
02519       dlist_init (ROIplaneList, SUMA_Free_ROI_PlaneData);
02520       SUMA_RETURN(ROIplaneList);
02521    } else {
02522       ROIplaneList = ROIplaneListIn;
02523    }
02524    
02525    doel = &(dov[idov]);
02526    
02527    if (doel->ObjectType != ROIdO_type) {
02528       SUMA_SLP_Crit("Only planning to deal\n"
02529                    "with ROIdO_type type");
02530       dlist_destroy(ROIplaneList);
02531       SUMA_RETURN(NULL);
02532    }
02533    
02534    D_ROI = (SUMA_DRAWN_ROI *)doel->OP;
02535    
02536    /* What is the name of this ROI's plane ?*/
02537    if (!D_ROI->ColPlaneName) {
02538       /* Bad, no color plane name, give it a fake one */
02539       UsedName = SUMA_copy_string("DefROIpl");
02540    }else {
02541       UsedName = SUMA_copy_string(D_ROI->ColPlaneName);
02542    }
02543    
02544    /* search for the plane name in the list */
02545    i = 0;
02546    found = NOPE;
02547    Plane = NULL;
02548    while (!found && i < ROIplaneList->size) {
02549       if (i == 0) NextElm = dlist_head(ROIplaneList);
02550       else NextElm = dlist_next(NextElm);
02551       Plane = (SUMA_ROI_PLANE *)NextElm->data;
02552       if (strcmp (UsedName,Plane->name) == 0) {
02553          SUMA_LH("PlaneFound");
02554          found = YUP;
02555          SUMA_free(UsedName); /* no longer needed */
02556       }
02557       ++i;
02558    }
02559    
02560    if (!found) { /* must create this plane */
02561       Plane = (SUMA_ROI_PLANE *)SUMA_malloc(sizeof(SUMA_ROI_PLANE));
02562       Plane->name = UsedName; /* preserved, don't go freeing UsedName later! */
02563       Plane->ROI_index_lst = (DList *) SUMA_malloc(sizeof(DList));
02564       dlist_init(Plane->ROI_index_lst, NULL);
02565       dlist_ins_next(ROIplaneList, dlist_tail(ROIplaneList), (void *)Plane);
02566    }
02567    
02568    /* now put the ROI in question in that list, easiest is to store its index into dov */
02569    dlist_ins_next(Plane->ROI_index_lst, dlist_tail(Plane->ROI_index_lst), (void *)idov);
02570    
02571    /* OK, done, now return */
02572    SUMA_RETURN(ROIplaneList);
02573 }
02574 
02575 /*! Create the cross hair */
02576 SUMA_Boolean SUMA_DrawCrossHair (SUMA_CrossHair* Ch)
02577 {
02578    static char FuncName[]={"SUMA_DrawCrossHair"};
02579    static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
02580    
02581    SUMA_ENTRY;
02582 
02583    glLineWidth(Ch->LineWidth);
02584    /*fprintf(SUMA_STDOUT, "Center: %f, %f, %f. Gap %f, Radius: %f\n",\
02585       Ch->c[0], Ch->c[2], Ch->c[2], Ch->g, Ch->r);*/
02586       glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor); /* turn off ambient and diffuse components */
02587       glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
02588       if (Ch->g) { /* gap */
02589          glMaterialfv(GL_FRONT, GL_EMISSION, Ch->XaxisColor); /*turn on emissivity for axis*/
02590          glBegin(GL_LINES);
02591          glVertex3f(Ch->c[0] - Ch->r, Ch->c[1], Ch->c[2]);
02592          glVertex3f(Ch->c[0] - Ch->g, Ch->c[1], Ch->c[2]);
02593          glVertex3f(Ch->c[0] + Ch->r, Ch->c[1], Ch->c[2]);
02594          glVertex3f(Ch->c[0] + Ch->g, Ch->c[1], Ch->c[2]);
02595          glEnd();  
02596 
02597          glMaterialfv(GL_FRONT, GL_EMISSION, Ch->YaxisColor); /*turn on emissivity for axis*/
02598          glBegin(GL_LINES);
02599          glVertex3f(Ch->c[0], Ch->c[1] - Ch->r, Ch->c[2]);
02600          glVertex3f(Ch->c[0], Ch->c[1] - Ch->g, Ch->c[2]);
02601          glVertex3f(Ch->c[0], Ch->c[1] + Ch->r, Ch->c[2]);
02602          glVertex3f(Ch->c[0], Ch->c[1] + Ch->g, Ch->c[2]);
02603          glEnd();  
02604 
02605          glMaterialfv(GL_FRONT, GL_EMISSION, Ch->ZaxisColor); /*turn on emissivity for axis*/
02606          glBegin(GL_LINES);
02607          glVertex3f(Ch->c[0], Ch->c[1], Ch->c[2] - Ch->r);
02608          glVertex3f(Ch->c[0], Ch->c[1], Ch->c[2] - Ch->g);
02609          glVertex3f(Ch->c[0], Ch->c[1], Ch->c[2] + Ch->r);
02610          glVertex3f(Ch->c[0], Ch->c[1], Ch->c[2] + Ch->g);
02611          glEnd();  
02612 
02613       }/*gap */ else {/*no gap */
02614          glMaterialfv(GL_FRONT, GL_EMISSION, Ch->XaxisColor); /*turn on emissivity for axis*/
02615          glBegin(GL_LINES);
02616          glVertex3f(Ch->c[0] - Ch->r, Ch->c[1], Ch->c[2]);
02617          glVertex3f(Ch->c[0] + Ch->r, Ch->c[1], Ch->c[2]);
02618          glEnd();  
02619          
02620          glMaterialfv(GL_FRONT, GL_EMISSION, Ch->YaxisColor); /*turn on emissivity for axis*/
02621          glBegin(GL_LINES);
02622          glVertex3f(Ch->c[0], Ch->c[1] - Ch->r, Ch->c[2]);
02623          glVertex3f(Ch->c[0], Ch->c[1] + Ch->r, Ch->c[2]);
02624          glEnd();  
02625 
02626          glMaterialfv(GL_FRONT, GL_EMISSION, Ch->ZaxisColor); /*turn on emissivity for axis*/
02627          glBegin(GL_LINES);
02628          glVertex3f(Ch->c[0], Ch->c[1], Ch->c[2] - Ch->r);
02629          glVertex3f(Ch->c[0], Ch->c[1], Ch->c[2] + Ch->r);
02630          glEnd();  
02631       }
02632       glMaterialfv(GL_FRONT, GL_EMISSION, NoColor); /*turn off emissivity for axis*/
02633 
02634    
02635    if (Ch->ShowSphere) {
02636       /*fprintf(SUMA_STDOUT, "SHOWING SPHERE\n");*/
02637       glMaterialfv(GL_FRONT, GL_EMISSION, Ch->sphcol); /*turn on emissivity for sphere */
02638       glTranslatef (Ch->c[0], Ch->c[1],Ch->c[2]);
02639       gluSphere(Ch->sphobj, Ch->sphrad, Ch->slices, Ch->stacks);
02640       glTranslatef (-Ch->c[0], -Ch->c[1],-Ch->c[2]);
02641       glMaterialfv(GL_FRONT, GL_EMISSION, NoColor); /*turn off emissivity for axis*/
02642    }
02643    
02644    SUMA_RETURN (YUP);
02645 }
02646 
02647 /* Allocate for a CrossHair object */
02648 SUMA_CrossHair* SUMA_Alloc_CrossHair (void)
02649 {   
02650    static char FuncName[]={"SUMA_Alloc_CrossHair"};
02651    SUMA_CrossHair* Ch;
02652    
02653    SUMA_ENTRY;
02654 
02655    Ch = SUMA_malloc (sizeof (SUMA_CrossHair));
02656    if (Ch == NULL) {
02657       fprintf(stderr,"SUMA_Alloc_CrossHair Error: Failed to allocate Ch\n");
02658       SUMA_RETURN (NULL);
02659    }
02660    
02661    /* setup some default values */
02662    Ch->XaxisColor[0] = 1.0;
02663    Ch->XaxisColor[1] = 0.0;
02664    Ch->XaxisColor[2] = 0.0;
02665    Ch->XaxisColor[3] = 0.0;
02666    
02667    Ch->YaxisColor[0] = 0.0;
02668    Ch->YaxisColor[1] = 1.0;
02669    Ch->YaxisColor[2] = 0.0;
02670    Ch->YaxisColor[3] = 0.0;
02671    
02672    Ch->ZaxisColor[0] = 0.0;
02673    Ch->ZaxisColor[1] = 0.0;
02674    Ch->ZaxisColor[2] = 1.0;
02675    Ch->ZaxisColor[3] = 0.0;
02676    
02677    Ch->LineWidth = SUMA_CROSS_HAIR_LINE_WIDTH;
02678    Ch->Stipple = SUMA_SOLID_LINE;
02679    Ch->c[0] = Ch->c[1] = Ch->c[2] = 0.0;
02680    
02681    Ch->g = SUMA_CROSS_HAIR_GAP; 
02682    Ch->r = SUMA_CROSS_HAIR_RADIUS; 
02683    
02684    /* create the ball object*/
02685    Ch->ShowSphere   = YUP;
02686    Ch->sphobj = gluNewQuadric();
02687    /* for wire frame  use GLU_LINE with GLU_NONE */
02688    /* for solid, use GLU_FILL and GLU_SMOOTH */
02689    #ifdef SUMA_SOLID_LOCAL
02690       gluQuadricDrawStyle (Ch->sphobj, GLU_FILL); 
02691       gluQuadricNormals (Ch->sphobj , GLU_SMOOTH);
02692    #else
02693       gluQuadricDrawStyle (Ch->sphobj, GLU_LINE);
02694       gluQuadricNormals (Ch->sphobj , GLU_NONE);
02695    #endif
02696    
02697    Ch->sphcol[0] = 1.0; Ch->sphcol[1] = 1.0; Ch->sphcol[2] = 0.0; Ch->sphcol[3] = 0.0;
02698    Ch->sphrad = SUMA_CROSS_HAIR_SPHERE_RADIUS;
02699    Ch->slices = 10;
02700    Ch->stacks = 10;
02701    
02702    Ch->SurfaceID = -1;
02703    Ch->NodeID = -1;
02704    SUMA_RETURN (Ch);
02705 }
02706 
02707 /*! Free a CrossHair object */
02708 void SUMA_Free_CrossHair (SUMA_CrossHair *Ch)
02709 {
02710    static char FuncName[]={"SUMA_Free_CrossHair"};
02711    
02712    SUMA_ENTRY;
02713 
02714    if (Ch->sphobj) gluDeleteQuadric(Ch->sphobj);
02715    if (Ch) SUMA_free(Ch);
02716    SUMA_RETURNe;
02717 }
02718 
02719 
02720 /* Allocate for a SphereMarker object */
02721 SUMA_SphereMarker* SUMA_Alloc_SphereMarker (void)
02722 {   
02723    static char FuncName[]={"SUMA_SphereMarker"};
02724    SUMA_SphereMarker* SM;
02725    
02726    SUMA_ENTRY;
02727 
02728    SM = SUMA_malloc (sizeof (SUMA_SphereMarker));
02729    if (SM == NULL) {
02730       fprintf(stderr,"SUMA_Alloc_SphereMarker Error: Failed to allocate SM\n");
02731       SUMA_RETURN (NULL);
02732    }
02733    
02734    /* create the ball object*/
02735    SM->sphobj = gluNewQuadric();
02736    /* for wire frame  use GLU_LINE with GLU_NONE */
02737    /* for solid, use GLU_FILL and GLU_SMOOTH */
02738    #ifdef SUMA_SOLID_LOCAL
02739       gluQuadricDrawStyle (SM->sphobj, GLU_FILL); 
02740       gluQuadricNormals (SM->sphobj , GLU_SMOOTH);
02741    #else
02742       gluQuadricDrawStyle (SM->sphobj, GLU_LINE);
02743       gluQuadricNormals (SM->sphobj , GLU_NONE);
02744    #endif
02745    SM->sphcol[0] = 0.50; SM->sphcol[1] = 0.5; SM->sphcol[2] = 1.0; SM->sphcol[3] = 1.0;
02746    SM->sphrad = SUMA_SELECTED_NODE_SPHERE_RADIUS;
02747    SM->slices = 10;
02748    SM->stacks = 10;
02749    SM->c[0] = SM->c[1] = SM->c[2] = 0.0; 
02750    
02751    SUMA_RETURN (SM);
02752 }
02753 
02754 /*! Free a SphereMarker object */
02755 void SUMA_Free_SphereMarker (SUMA_SphereMarker *SM)
02756 {
02757    static char FuncName[]={"SUMA_Free_SphereMarker"};
02758    
02759    SUMA_ENTRY;
02760 
02761    if (SM->sphobj) gluDeleteQuadric(SM->sphobj);
02762    if (SM) SUMA_free(SM);
02763    SUMA_RETURNe;
02764 }
02765 
02766 /*! Create the highlighted faceset  marker */
02767 SUMA_Boolean SUMA_DrawFaceSetMarker (SUMA_FaceSetMarker* FM)
02768 {   static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0}, dx, dy, dz;
02769    static char FuncName[]={"SUMA_DrawFaceSetMarker"};
02770    
02771    SUMA_ENTRY;
02772 
02773    dx = SUMA_SELECTED_FACESET_OFFSET_FACTOR * FM->NormVect[0];
02774    dy = SUMA_SELECTED_FACESET_OFFSET_FACTOR * FM->NormVect[1];
02775    dz = SUMA_SELECTED_FACESET_OFFSET_FACTOR * FM->NormVect[2];
02776     
02777    glLineWidth(FM->LineWidth);
02778    glDisable(GL_LINE_STIPPLE);
02779 
02780    glMaterialfv(GL_FRONT, GL_EMISSION, FM->LineCol); /*turn on emissivity for triangle*/
02781    glMaterialfv(GL_FRONT, GL_AMBIENT, NoColor); /* turn off ambient and diffuse components */
02782    glMaterialfv(GL_FRONT, GL_DIFFUSE, NoColor);
02783 
02784    glBegin(GL_LINE_LOOP);
02785       glVertex3f(FM->n0[0]+dx, FM->n0[1]+dy, FM->n0[2]+dz);
02786       glVertex3f(FM->n1[0]+dx, FM->n1[1]+dy, FM->n1[2]+dz);
02787       glVertex3f(FM->n2[0]+dx, FM->n2[1]+dy, FM->n2[2]+dz);
02788    glEnd();
02789    glBegin(GL_LINE_LOOP);
02790       glVertex3f(FM->n0[0]-dx, FM->n0[1]-dy, FM->n0[2]-dz);
02791       glVertex3f(FM->n1[0]-dx, FM->n1[1]-dy, FM->n1[2]-dz);
02792       glVertex3f(FM->n2[0]-dx, FM->n2[1]-dy, FM->n2[2]-dz);
02793    glEnd();
02794    glMaterialfv(GL_FRONT, GL_EMISSION, NoColor);
02795    SUMA_RETURN (YUP);
02796 }   
02797 
02798 /* Allocate for a faceset mrker */
02799 SUMA_FaceSetMarker* SUMA_Alloc_FaceSetMarker (void)
02800 {
02801    SUMA_FaceSetMarker* FM;
02802    static char FuncName[]={"SUMA_Alloc_FaceSetMarker"};
02803    
02804    SUMA_ENTRY;
02805 
02806    FM = SUMA_malloc (sizeof (SUMA_FaceSetMarker));
02807    if (FM == NULL) {
02808       fprintf(stderr,"SUMA_Alloc_FaceSetMarker Error: Failed to allocate FM\n");
02809       SUMA_RETURN (NULL);
02810    }
02811     
02812    /* setup some default values */
02813    FM->LineWidth = SUMA_SELECTED_FACESET_LINE_WIDTH;
02814    FM->LineCol[0] = FM->LineCol[1] = FM->LineCol[2] = SUMA_SELECTED_FACESET_LINE_INTENSITY; FM->LineCol[3] = 1;
02815    
02816    SUMA_RETURN (FM);
02817 }
02818 /*! Free a FaceSetMarker object */
02819 void SUMA_Free_FaceSetMarker (SUMA_FaceSetMarker* FM)
02820 {
02821    static char FuncName[]={"SUMA_Free_FaceSetMarker"};
02822 
02823    SUMA_ENTRY;
02824 
02825    if (FM) SUMA_free(FM);
02826    SUMA_RETURNe;
02827 }
02828 
02829 #define TestImage 0 
02830 #define TestTexture 0 /* needs TestImage to be active */
02831 /*! Create a tesselated mesh */
02832 void SUMA_DrawMesh(SUMA_SurfaceObject *SurfObj, SUMA_SurfaceViewer *sv)
02833 {  static GLfloat NoColor[] = {0.0, 0.0, 0.0, 0.0};
02834    GLfloat *colp = NULL;
02835    int i, ii, ND, id, ip, NP, PolyMode;
02836    static char FuncName[]={"SUMA_DrawMesh"};
02837    SUMA_DRAWN_ROI *DrawnROI = NULL;
02838       static unsigned char *image=NULL;
02839       static GLuint texName;
02840    SUMA_Boolean LocalHead = NOPE;
02841       
02842    SUMA_ENTRY;
02843    
02844    #if TestImage
02845    if (image) {
02846       SUMA_SL_Note("Binding texture");
02847       glBindTexture(GL_TEXTURE_2D, texName);
02848    }
02849    #endif
02850       
02851    SUMA_LH("Poly Mode");
02852    /* check on rendering mode */
02853    if (SurfObj->PolyMode != SRM_ViewerDefault) {
02854      /* not the default, do the deed */
02855      SUMA_SET_GL_RENDER_MODE(SurfObj->PolyMode); 
02856    }
02857    
02858    SUMA_LH("Draw Method");
02859    ND = SurfObj->NodeDim;
02860    NP = SurfObj->FaceSetDim;
02861    switch (DRAW_METHOD) { 
02862       case STRAIGHT:
02863          switch (RENDER_METHOD) {
02864             case TRIANGLES:
02865                glBegin (GL_TRIANGLES);
02866                break;
02867             case POINTS:
02868                glPointSize(4.0); /* keep outside of glBegin */
02869                glBegin (GL_POINTS);
02870                break;
02871          } /* switch RENDER_METHOD */
02872          glColor4f(NODE_COLOR_R, NODE_COLOR_G, NODE_COLOR_B, SUMA_NODE_ALPHA);
02873          for (i=0; i < SurfObj->N_FaceSet; i++)
02874          {   
02875             ip = NP * i;
02876             id = ND * SurfObj->FaceSetList[ip];
02877             glNormal3fv(&SurfObj->NodeNormList[id]);
02878             glVertex3fv(&SurfObj->NodeList[id]); /* glVertex3f(0.1, 0.9, 0.0); */
02879 
02880             id = ND * SurfObj->FaceSetList[ip+1];
02881             glNormal3fv(&SurfObj->NodeNormList[id]);
02882             glVertex3fv(&SurfObj->NodeList[id]);/* glVertex3f(0.1, 0.1, 0.0); */
02883 
02884             id = ND * SurfObj->FaceSetList[ip+2];
02885             glNormal3fv(&SurfObj->NodeNormList[id]);
02886             glVertex3fv(&SurfObj->NodeList[id]);/* glVertex3f(0.7, 0.5, 0.0); */
02887          }
02888          glEnd();
02889          break;
02890       
02891       case ARRAY:
02892          /* This allows each node to follow the color specified when it was drawn */ 
02893          glColorMaterial(GL_FRONT, GL_AMBIENT_AND_DIFFUSE); 
02894          glEnable(GL_COLOR_MATERIAL);
02895          
02896          /*Now setup various pointers*/
02897          glEnableClientState (GL_COLOR_ARRAY);
02898          glEnableClientState (GL_VERTEX_ARRAY);
02899          glEnableClientState (GL_NORMAL_ARRAY);
02900          colp = SUMA_GetColorList (sv, SurfObj->idcode_str);
02901          if (!colp) { /* no color list, try  PermCol */
02902             if (SurfObj->PermCol) {
02903                glColorPointer (4, GL_FLOAT, 0, SurfObj->PermCol);
02904             } else {
02905                SUMA_SL_Err("Null Color Pointer.");
02906             }
02907          } else { 
02908             glColorPointer (4, GL_FLOAT, 0, SUMA_GetColorList (sv, SurfObj->idcode_str));
02909          }
02910          glVertexPointer (3, GL_FLOAT, 0, SurfObj->glar_NodeList);
02911          glNormalPointer (GL_FLOAT, 0, SurfObj->glar_NodeNormList);
02912          if (LocalHead) fprintf(stdout, "Ready to draw Elements %d\n", SurfObj->N_FaceSet); 
02913          switch (RENDER_METHOD) {
02914             case TRIANGLES:
02915                glDrawElements (GL_TRIANGLES, (GLsizei)SurfObj->N_FaceSet*3, GL_UNSIGNED_INT, SurfObj->glar_FaceSetList);
02916                break;
02917             case POINTS:
02918                glPointSize(4.0); /* keep outside of glBegin */
02919                /* it is inefficient to draw points using the glar_FaceSetList because nodes are listed more 
02920                than once. You are better off creating an index vector into glar_NodeList to place all the points, just once*/ 
02921                glDrawElements (GL_POINTS, (GLsizei)SurfObj->N_FaceSet*3, GL_UNSIGNED_INT, SurfObj->glar_FaceSetList);
02922                break;
02923          } /* switch RENDER_METHOD */
02924 
02925          #if TestImage
02926          if (1){
02927             GLboolean valid;
02928             GLfloat rpos[4];
02929             char  string[]= {"Yo Baby sssup? 1 2 3, 4.2 mm"};
02930             int is;
02931             float txcol[3] = {0.2, 0.5, 1};
02932             static int width, height;
02933 
02934             SUMA_SL_Note(  "Doing the splat and the text thing\n"
02935                            "from Kilgard's renderSplat in splatlogo.c\n"
02936                            "to understand scaling operations.\n");
02937             
02938             if (SurfObj->ShowSelectedNode && SurfObj->SelectedNode >= 0) {
02939                id = ND * SurfObj->SelectedNode;
02940             } else { id = 0; }
02941             
02942             glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, NoColor);
02943             glMaterialfv(GL_FRONT, GL_EMISSION, txcol); /*turn on emissidity for text*/
02944             glRasterPos3f(SurfObj->NodeList[id], SurfObj->NodeList[id+1],SurfObj->NodeList[id+2]);
02945             glGetFloatv(GL_CURRENT_RASTER_POSITION, rpos);
02946             glGetBooleanv(GL_CURRENT_RASTER_POSITION_VALID, &valid);
02947             printf("%s: Raster position (%g,%g, %g) is %s\n",
02948                FuncName, rpos[0], rpos[1], rpos[2], valid ? "valid" : "INVALID");
02949 
02950             /* do some text action */
02951             SUMA_SL_Note(  "Some colored text\n"
02952                            "Might affect la drawing\n"
02953                            "color elsewhere");
02954             glColor3fv(txcol); 
02955             for (is=0; string[is] != '\0'; is++) {
02956                glutBitmapCharacter(GLUT_BITMAP_9_BY_15, string[is]);
02957             }  
02958             glMaterialfv(GL_FRONT, GL_EMISSION, NoColor); /*turn off emissidity for text*/
02959 
02960             if (!image) {
02961                FILE *fid;
02962                SUMA_SL_Note(  "Reading the image.");
02963                image = SUMA_read_ppm("IMG_0526.ppm", &width, &height, 1);
02964                if (!image) {
02965                   SUMA_SL_Err("Failed to read image.");
02966                }else{
02967                   #if TestTexture
02968                   SUMA_SL_Note("Creating texture, see init pp 415 in OpenGL programming guide, 3red");
02969                   glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
02970                   glGenTextures(1, &texName);
02971                   glBindTexture(GL_TEXTURE_2D, texName);
02972                   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_WRAP_S, GL_CLAMP); /* GL_REPEAT, GL_CLAMP */
02973                   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
02974                   glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
02975                   glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image);
02976                   glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE); /* GL_REPLACE, GL_MODULATE */
02977                   glTexGeni(GL_S, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP); /* GL_SPHERE_MAP, GL_EYE_LINEAR, GL_OBJECT_LINEAR */
02978                   glTexGeni(GL_T, GL_TEXTURE_GEN_MODE, GL_SPHERE_MAP);
02979                   glEnable(GL_TEXTURE_GEN_S);
02980                   glEnable(GL_TEXTURE_GEN_T);
02981                   glEnable(GL_TEXTURE_2D);
02982                   glEnable(GL_CULL_FACE);
02983                   glEnable(GL_LIGHTING);
02984                   glEnable(GL_LIGHT0);
02985                   glEnable(GL_AUTO_NORMAL);
02986                   glEnable(GL_NORMALIZE);
02987                   glMaterialf(GL_FRONT, GL_SHININESS, 64.0);
02988                   #endif
02989                }
02990                /*
02991                fid = fopen("junk.img", "w");
02992                SUMA_disp_vecucmat (image, width*height, 4, 1, SUMA_ROW_MAJOR, fid, NOPE);
02993                fclose(fid);
02994                */
02995                
02996             }
02997             if (image) {
02998                SUMA_SL_Note(  "Drawing the image.");
02999                /* NOTE. The raster position has been pushed aside by the string.
03000                If you want it back, you need a new call to glRasterPos3f */
03001                glRasterPos3f(SurfObj->NodeList[id], SurfObj->NodeList[id+1],SurfObj->NodeList[id+2]);
03002                glAlphaFunc(GL_GEQUAL, 0.25);/* Should do this only once, not each time you render ...*/
03003                glEnable(GL_ALPHA_TEST);
03004                glDrawPixels(width, height, GL_RGBA,
03005                   GL_UNSIGNED_BYTE, image);
03006                glDisable(GL_ALPHA_TEST);
03007             }
03008          }
03009          #endif
03010 
03011          /*fprintf(stdout, "Disabling clients\n");*/
03012          glDisableClientState (GL_COLOR_ARRAY);   
03013          glDisableClientState (GL_VERTEX_ARRAY);
03014          glDisableClientState (GL_NORMAL_ARRAY);   
03015          /*fprintf(stdout, "Out SUMA_DrawMesh, ARRAY mode\n");*/
03016          
03017          glDisable(GL_COLOR_MATERIAL);
03018          
03019          SUMA_LH("ROIs");
03020          /* draw surface ROIs */
03021          if (!SUMA_Draw_SO_ROI (SurfObj, SUMAg_DOv, SUMAg_N_DOv)) {
03022             fprintf (SUMA_STDERR, "Error %s: Failed in drawing ROI objects.\n", FuncName);
03023          }
03024          /* Draw Axis */
03025          SUMA_LH("Axis");
03026          if (SurfObj->MeshAxis && SurfObj->ShowMeshAxis)   {
03027             if (!SUMA_DrawAxis (SurfObj->MeshAxis, sv)) {
03028                fprintf(stderr,"Error SUMA_DrawAxis: Unrecognized Stipple option\n");
03029             }
03030          }
03031          
03032          SUMA_LH("Highlight");
03033          /* Draw Selected Node Highlight */
03034          if (SurfObj->ShowSelectedNode && SurfObj->SelectedNode >= 0) {
03035             if (LocalHead) fprintf(SUMA_STDOUT,"Drawing Node Selection \n");
03036             id = ND * SurfObj->SelectedNode;
03037             glMaterialfv(GL_FRONT, GL_EMISSION, SurfObj->NodeMarker->sphcol); /*turn on emissidity for sphere */
03038             glMaterialfv(GL_FRONT, GL_AMBIENT_AND_DIFFUSE, NoColor);
03039             glTranslatef (SurfObj->NodeList[id], SurfObj->NodeList[id+1],SurfObj->NodeList[id+2]);
03040             gluSphere(SurfObj->NodeMarker->sphobj, SurfObj->NodeMarker->sphrad, SurfObj->NodeMarker->slices, SurfObj->NodeMarker->stacks);
03041             glTranslatef (-SurfObj->NodeList[id], -SurfObj->NodeList[id+1],-SurfObj->NodeList[id+2]);
03042             glMaterialfv(GL_FRONT, GL_EMISSION, NoColor); /*turn off emissidity for axis*/
03043          }
03044          
03045          /* Draw Selected FaceSet Highlight */
03046          if (SurfObj->ShowSelectedFaceSet && SurfObj->SelectedFaceSet >= 0) {
03047             if (LocalHead) fprintf(SUMA_STDOUT,"Drawing FaceSet Selection \n");            
03048             if (!SUMA_DrawFaceSetMarker (SurfObj->FaceSetMarker)) {
03049                fprintf(SUMA_STDERR,"Error SUMA_DrawMesh: Failed in SUMA_DrawFaceSetMarker\b");
03050             }
03051          } 
03052 
03053          break;
03054 
03055    } /* switch DRAW_METHOD */
03056    
03057    SUMA_LH("RenderMode");
03058    /* reset viewer default rendering modes */
03059    if (SurfObj->PolyMode != SRM_ViewerDefault) {
03060      /* not the default, do the deed */
03061      SUMA_SET_GL_RENDER_MODE(sv->PolyMode); 
03062    }   
03063 
03064    SUMA_LH("Done");
03065    SUMA_RETURNe;
03066 } /* SUMA_DrawMesh */
03067 
03068 /*!**
03069 File : SUMA_Load_Surface_Object.c
03070 \author Ziad Saad
03071 Date : Wed Jan 23 15:18:12 EST 2002
03072    
03073 Purpose : 
03074    
03075    
03076    
03077 Usage : 
03078     Ans = SUMA_Free_Surface_Object ( SO)
03079    
03080    
03081 Input paramters : 
03082 \param   SO (SUMA_SurfaceObject *) Surface Object pointer
03083    
03084 Returns : 
03085 \return  Ans (SUMA_Boolean) 
03086 
03087 \sa SUMA_Load_Surface_Object        
03088 ***/
03089 SUMA_Boolean SUMA_Free_Surface_Object (SUMA_SurfaceObject *SO)
03090 {   
03091    static char FuncName[]={"SUMA_Free_Surface_Object"};
03092    int i;
03093    SUMA_Boolean LocalHead = NOPE;
03094    
03095    SUMA_ENTRY;
03096 
03097    if (!SO) {
03098       SUMA_SL_Warn("NULL SO");
03099       SUMA_RETURN(YUP);
03100    }
03101    if (LocalHead) {
03102       if (SO->Label) fprintf (SUMA_STDERR, "%s: freeing SO %s\n", FuncName, SO->Label);
03103       else fprintf (SUMA_STDERR, "%s: freeing SO\n", FuncName);
03104    }
03105    /* Start with the big ones and down*/
03106    /* From SUMA 1.2 and on, some glar_ pointers are copies of others and should not be freed */ 
03107    SO->glar_FaceSetList = NULL;
03108    SO->glar_NodeList = NULL;
03109    SO->glar_NodeNormList = NULL;
03110    SO->glar_FaceNormList = NULL;
03111    
03112    if (LocalHead) fprintf (stdout, "SO->NodeList... ");
03113    if (SO->NodeList)   SUMA_free(SO->NodeList);
03114    /*fprintf (stdout, "SO->FaceSetList... ");*/ 
03115    if (SO->FaceSetList) SUMA_free(SO->FaceSetList);
03116    /*fprintf (stdout, "SO->FaceSetList... ");*/ 
03117    if (SO->NodeNormList) SUMA_free(SO->NodeNormList);
03118    /*fprintf (stdout, "SO->NodeNormList... ");*/ 
03119    if (SO->FaceNormList) SUMA_free(SO->FaceNormList);
03120    /*fprintf (stdout, "SO->FaceNormList... ");*/ 
03121    if (SO->Name_NodeParent) SUMA_free(SO->Name_NodeParent);
03122    if (LocalHead) fprintf (stdout, "SO->Name.FileName... "); 
03123    if (SO->Name.FileName) SUMA_free(SO->Name.FileName);
03124    
03125    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing SO->Name.Path\n", FuncName);
03126    if (SO->Name.Path) SUMA_free(SO->Name.Path);
03127    if (SO->SpecFile.Path) SUMA_free(SO->SpecFile.Path);
03128    if (SO->SpecFile.FileName) SUMA_free(SO->SpecFile.FileName);
03129    if (SO->MeshAxis) SUMA_Free_Axis (SO->MeshAxis);
03130    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing SO->NodeMarker\n", FuncName);
03131    if (SO->NodeMarker) SUMA_Free_SphereMarker (SO->NodeMarker);
03132    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing SO->FaceSetMarker\n", FuncName);
03133    if (SO->FaceSetMarker) SUMA_Free_FaceSetMarker(SO->FaceSetMarker);
03134    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing SO->idcode_str\n", FuncName);
03135    if (SO->idcode_str) SUMA_free(SO->idcode_str); 
03136    if (SO->facesetlist_idcode_str) SUMA_free(SO->facesetlist_idcode_str);
03137    if (SO->nodelist_idcode_str) SUMA_free(SO->nodelist_idcode_str);
03138    if (SO->facenormals_idcode_str) SUMA_free(SO->facenormals_idcode_str);
03139    if (SO->nodenormals_idcode_str) SUMA_free(SO->nodenormals_idcode_str);
03140    if (SO->polyarea_idcode_str) SUMA_free(SO->polyarea_idcode_str);
03141    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing SO->LocalDomainParentID\n", FuncName);
03142    if (SO->LocalDomainParentID) SUMA_free(SO->LocalDomainParentID);
03143    if (SO->LocalDomainParent) SUMA_free(SO->LocalDomainParent);
03144    if (SO->LocalCurvatureParentID) SUMA_free(SO->LocalCurvatureParentID);
03145    if (SO->LocalCurvatureParent) SUMA_free(SO->LocalCurvatureParent);
03146    if (SO->OriginatorID) SUMA_free(SO->OriginatorID);
03147    if (SO->DomainGrandParentID) SUMA_free(SO->DomainGrandParentID);
03148    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing SO->Group\n", FuncName);
03149    if (SO->Group) SUMA_free(SO->Group);
03150    if (SO->State) SUMA_free(SO->State);
03151    if (SO->PolyArea) SUMA_free(SO->PolyArea);
03152    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing SO->SC\n", FuncName);
03153    if (SO->SC) {
03154       SUMA_Free_SURFACE_CURVATURE(SO->SC);
03155    }
03156    if (SO->Group_idcode_str) SUMA_free(SO->Group_idcode_str);
03157    if (SO->ModelName) SUMA_free(SO->ModelName);
03158    if (SO->OriginatorLabel) SUMA_free(SO->OriginatorLabel);
03159    if (SO->StandardSpace) SUMA_free(SO->StandardSpace);
03160    if (SO->parent_vol_idcode_str) SUMA_free(SO->parent_vol_idcode_str);
03161 
03162    #if 0 /* no more Cx inside SO */
03163    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing Cx\n", FuncName);
03164    /* freeing Cx,  make sure that there are no links to Cx*/
03165    if (SO->Cx || SO->Cx_Inode) { /* there should be no case where only one of two is null but if such a case existed, you'll get notified below. */
03166       if (SUMA_ReleaseLink(SO->Cx_Inode)) { 
03167          /* some links are left, do not free memory */
03168       } else {
03169          if (SO->Cx) SUMA_free(SO->Cx);
03170          /* now free SO->Cx_Inode */
03171          if (SO->Cx_Inode) SUMA_free(SO->Cx_Inode);
03172       }
03173       SO->Cx = NULL;
03174       SO->Cx_Inode = NULL;
03175    } 
03176    #endif 
03177    
03178    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing %d overlays\n", FuncName, SO->N_Overlays);
03179    
03180    /* freeing overlays */
03181    if (SO->N_Overlays) {
03182       /* freeing color overlays */
03183       for (i=0; i < SO->N_Overlays; ++i) {
03184          SUMA_FreeOverlayPointer (SO->Overlays[i]);
03185          SO->Overlays[i] = NULL;
03186       }
03187       SO->N_Overlays = 0;
03188    }
03189    /*Now free the vector of pointers */
03190    SUMA_free(SO->Overlays);
03191    if (LocalHead) fprintf (SUMA_STDERR, "%s: freeing FN\n", FuncName);
03192 
03193    /* freeing FN,  make sure that there are no links to FN*/
03194    if (SO->FN) {
03195       if (!SUMA_Free_FirstNeighb (SO->FN)) {
03196                fprintf(SUMA_STDERR,"Error SUMA_Free_Surface_Object : Failed to free SO->FN");
03197       }
03198       SO->FN = NULL;
03199    }
03200    
03201    /* freeing Label */
03202    if (SO->Label) SUMA_free(SO->Label);
03203    
03204    /* freeing EL,  make sure that there are no links to EL*/
03205    if (SO->EL) {
03206       SUMA_free_Edge_List (SO->EL);
03207    }
03208    SO->EL = NULL;
03209    
03210    if (SO->MF){ 
03211       SUMA_Free_MemberFaceSets (SO->MF);
03212       SO->MF = NULL;
03213    }
03214    if (SO->SurfCont) SUMA_FreeSurfContStruct(SO->SurfCont);
03215    
03216    if (SO->PermCol) SUMA_free(SO->PermCol);
03217    
03218    if (SO->VolPar) SUMA_Free_VolPar(SO->VolPar); 
03219    
03220    if (SO) SUMA_free(SO);
03221    
03222    if (LocalHead) fprintf (stdout, "Done\n");
03223    SUMA_RETURN (YUP);
03224 }   
03225 
03226 
03227 /*!
03228    \brief Creates a string containing information about the surface
03229    
03230    \param SO (SUMA_SurfaceObject *) pointer to surface object structure
03231    \param   DsetList (DList *) List of data sets (used to output convexity info)         
03232    \return s (char *) pointer to NULL terminated string containing surface info.
03233    It is your responsability to free it.
03234    \sa SUMA_Print_Surface_Object
03235    
03236 */
03237 char *SUMA_SurfaceObject_Info (SUMA_SurfaceObject *SO, DList *DsetList)
03238 {
03239    static char FuncName[]={"SUMA_SurfaceObject_Info"};
03240    int MaxShow = 5, i,j, ND = 0, NP = 0, N_max = 10000, eu=-1002;
03241    char stmp[1000], *s = NULL;
03242    SUMA_STRING *SS = NULL;
03243    
03244    SUMA_ENTRY;
03245    
03246    SS = SUMA_StringAppend (NULL, NULL);
03247       
03248    if (SO) {
03249       ND = SO->NodeDim;
03250       NP = SO->FaceSetDim;
03251       
03252       /* SO->Label */
03253       if (SO->Label == NULL)
03254          SS = SUMA_StringAppend (SS,"Label: NULL.\n");
03255       else   {
03256          SS = SUMA_StringAppend_va (SS, "Label: %s\n", SO->Label);
03257       }
03258       
03259       /* SO->AnatCorrect */
03260       if (SO->AnatCorrect) SS = SUMA_StringAppend (SS,"Anatomically correct = YES\n");
03261       else SS = SUMA_StringAppend (SS,"Anatomically correct = NO\n");
03262       
03263       switch (SO->Side) {
03264          case SUMA_SIDE_ERROR:
03265             SS = SUMA_StringAppend (SS,"Error in side specification\n");
03266             break;
03267          case SUMA_NO_SIDE:
03268             SS = SUMA_StringAppend (SS,"No side specified.\n");
03269             break;
03270          case SUMA_LEFT:
03271             SS = SUMA_StringAppend (SS,"Left hemisphere.\n");
03272             break;
03273          case SUMA_RIGHT:
03274             SS = SUMA_StringAppend (SS,"Right hemisphere.\n");
03275             break;
03276          default:
03277             SS = SUMA_StringAppend (SS,"Chimchunga.\n");
03278             break;
03279       }
03280       
03281       switch (SO->FileType) {
03282          case SUMA_SUREFIT:
03283             SS = SUMA_StringAppend_va (SS, "SureFit surface.\n");
03284             SS = SUMA_StringAppend_va (SS,"Coord FileName: %s \n", SO->Name_coord.FileName);
03285             SS = SUMA_StringAppend_va (SS,"Coord Path: %s \n", SO->Name_coord.Path);
03286             SS = SUMA_StringAppend_va (SS,"Topo FileName: %s \n", SO->Name_topo.FileName);
03287             SS = SUMA_StringAppend_va (SS,"Topo Path: %s \n", SO->Name_topo.Path);
03288             break;
03289          case SUMA_VEC:
03290             SS = SUMA_StringAppend_va (SS,"VEC surface.\n");
03291             SS = SUMA_StringAppend_va (SS,"NodeList FileName: %s \n", SO->Name_coord.FileName);
03292             SS = SUMA_StringAppend_va (SS,"NodeList Path: %s \n", SO->Name_coord.Path);
03293             SS = SUMA_StringAppend_va (SS,"FaceSetList FileName: %s \n", SO->Name_topo.FileName);
03294             SS = SUMA_StringAppend_va (SS,"FaceSetList Path: %s \n", SO->Name_topo.Path);
03295             break;
03296          case SUMA_FREE_SURFER:
03297          case SUMA_FREE_SURFER_PATCH:
03298             SS = SUMA_StringAppend_va (SS,"FreeSurfer surface.\n");
03299             SS = SUMA_StringAppend_va (SS,"FileName: %s\n", SO->Name.FileName);
03300             SS = SUMA_StringAppend_va (SS,"Path: %s\n", SO->Name.Path);
03301             break;
03302          case SUMA_INVENTOR_GENERIC:
03303             SS = SUMA_StringAppend_va (SS,"Inventor generic surface.\n");
03304             SS = SUMA_StringAppend_va (SS,"FileName: %s\n", SO->Name.FileName);
03305             SS = SUMA_StringAppend_va (SS,"Path: %s\n", SO->Name.Path);
03306             break;
03307          case SUMA_PLY: 
03308             SS = SUMA_StringAppend_va (SS,"PLY surface.\n");
03309             SS = SUMA_StringAppend_va (SS,"FileName: %s\n", SO->Name.FileName);
03310             SS = SUMA_StringAppend_va (SS,"Path: %s\n", SO->Name.Path);
03311             break;
03312          case SUMA_OPENDX_MESH: 
03313             SS = SUMA_StringAppend_va (SS,"OpenDX surface.\n");
03314             SS = SUMA_StringAppend_va (SS,"FileName: %s\n", SO->Name.FileName);
03315             SS = SUMA_StringAppend_va (SS,"Path: %s\n", SO->Name.Path);
03316             break;
03317          case SUMA_FT_NOT_SPECIFIED:
03318             SS = SUMA_StringAppend_va (SS,"File Type not specified.\n");
03319             break;
03320          default:
03321             SS = SUMA_StringAppend_va (SS,"Unknown surface type.\n");
03322             break;
03323       }
03324 
03325       SS = SUMA_StringAppend_va (SS,"SpecFile:");
03326       if (SO->SpecFile.Path) SS = SUMA_StringAppend_va (SS,"%s", SO->SpecFile.Path);
03327       if (SO->SpecFile.FileName) SS = SUMA_StringAppend_va (SS,"%s", SO->SpecFile.FileName);
03328       SS = SUMA_StringAppend_va (SS,"\n");
03329       
03330       SS = SUMA_StringAppend_va (SS,"FileType: %d\t FileFormat: %d\n", SO->FileType, SO->FileFormat);
03331 
03332       if (!SO->idcode_str) SS = SUMA_StringAppend_va (SS,"IDcode is NULL\n");
03333       else SS = SUMA_StringAppend_va (SS,"IDcode: %s\n", SO->idcode_str);
03334       if (!SO->parent_vol_idcode_str) SS = SUMA_StringAppend_va (SS,"parent_vol_IDcode is NULL\n");
03335       else SS = SUMA_StringAppend_va (SS,"parent_vol_IDcode: %s\n", SO->parent_vol_idcode_str);
03336       if (!SO->facesetlist_idcode_str) SS = SUMA_StringAppend_va (SS,"faceset_IDcode is NULL\n");
03337       else SS = SUMA_StringAppend_va (SS,"faceset_IDcode: %s\n", SO->facesetlist_idcode_str);
03338       if (!SO->nodelist_idcode_str) SS = SUMA_StringAppend_va (SS,"nodelist_IDcode is NULL\n");
03339       else SS = SUMA_StringAppend_va (SS,"nodelist_IDcode: %s\n", SO->nodelist_idcode_str);
03340       if (!SO->facenormals_idcode_str) SS = SUMA_StringAppend_va (SS,"facenormals_IDcode is NULL\n");
03341       else SS = SUMA_StringAppend_va (SS,"facenormals_IDcode: %s\n", SO->facenormals_idcode_str);
03342       if (!SO->nodenormals_idcode_str) SS = SUMA_StringAppend_va (SS,"nodenormals_IDcode is NULL\n");
03343       else SS = SUMA_StringAppend_va (SS,"nodenormals_IDcode: %s\n", SO->nodenormals_idcode_str);
03344       if (!SO->polyarea_idcode_str) SS = SUMA_StringAppend_va (SS,"polyarea_IDcode is NULL\n");
03345       else SS = SUMA_StringAppend_va (SS,"polyarea_IDcode: %s\n", SO->polyarea_idcode_str);
03346       
03347       
03348       if (!SO->LocalDomainParent) SS = SUMA_StringAppend_va (SS,"LocalDomainParent is NULL\n");
03349       else SS = SUMA_StringAppend_va (SS,"LocalDomainParent: %s\n", SO->LocalDomainParent);
03350 
03351       if (!SO->LocalDomainParentID) SS = SUMA_StringAppend_va (SS,"LocalDomainParentID is NULL\n");
03352       else SS = SUMA_StringAppend_va (SS,"LocalDomainParentID: %s\n", SO->LocalDomainParentID);
03353      
03354       if (!SO->LocalCurvatureParent) SS = SUMA_StringAppend_va (SS,"LocalCurvatureParent is NULL\n");
03355       else SS = SUMA_StringAppend_va (SS,"LocalCurvatureParent: %s\n", SO->LocalCurvatureParent);
03356        
03357       if (!SO->LocalCurvatureParentID) SS = SUMA_StringAppend_va (SS,"LocalCurvatureParentID is NULL\n");
03358       else SS = SUMA_StringAppend_va (SS,"LocalCurvatureParentID: %s\n", SO->LocalCurvatureParentID);
03359        
03360       if (!SO->OriginatorID) SS = SUMA_StringAppend_va (SS,"OriginatorID is NULL\n");
03361       else SS = SUMA_StringAppend_va (SS,"OriginatorID: %s\n", SO->OriginatorID);
03362 
03363       if (!SO->OriginatorLabel) SS = SUMA_StringAppend_va (SS,"OriginatorLabel is NULL\n");
03364       else SS = SUMA_StringAppend_va (SS,"OriginatorLabel: %s\n", SO->OriginatorLabel);
03365        
03366       if (!SO->DomainGrandParentID) SS = SUMA_StringAppend_va (SS,"DomainGrandParentID is NULL\n");
03367       else SS = SUMA_StringAppend_va (SS,"DomainGrandParentID: %s\n", SO->DomainGrandParentID);
03368              
03369       SS = SUMA_StringAppend_va (SS,"GroupLabel: %s\tGroupID: %s\tModelName %s\tState: %s\tStandardSpace %s\n", 
03370                                  SO->Group, SO->Group_idcode_str, SO->ModelName, SO->State, SO->StandardSpace);
03371 
03372       if (SUMA_ismappable(SO)) {
03373          if (SUMA_isLocalDomainParent(SO)) {
03374             sprintf (stmp,"Surface is a Local Domain Parent.\n");
03375             SS = SUMA_StringAppend (SS,stmp);
03376          } else {
03377             sprintf (stmp,"Surface is Mappable.\n");
03378            SS = SUMA_StringAppend (SS,stmp);
03379          }
03380       } else {
03381          sprintf (stmp,"Surface is NOT Mappable.\n");
03382          SS = SUMA_StringAppend (SS,stmp);
03383       }
03384 
03385 
03386       if (SO->Name_NodeParent == NULL) {
03387          sprintf (stmp,"Name_NodeParent is NULL\n");
03388          SS = SUMA_StringAppend (SS,stmp);
03389       } else   {
03390          sprintf (stmp,"Name_NodeParent: %s\n", SO->Name_NodeParent);
03391          SS = SUMA_StringAppend (SS,stmp);
03392       }
03393 
03394       if (SO->MeshAxis) {
03395          sprintf (stmp,"ShowMeshAxis: %d\t MeshAxis Defined\n", SO->ShowMeshAxis);
03396          SS = SUMA_StringAppend (SS,stmp);
03397       }   else {
03398          sprintf (stmp,"ShowMeshAxis: %d\t MeshAxis Undefined\n", SO->ShowMeshAxis);
03399          SS = SUMA_StringAppend (SS,stmp);
03400       }  
03401       
03402       sprintf (stmp,"RenderMode: %d\n", SO->PolyMode);
03403       SS = SUMA_StringAppend (SS,stmp);
03404       
03405       sprintf (stmp,"N_Node: %d\t NodeDim: %d, EmbedDim: %d\n", \
03406          SO->N_Node, SO->NodeDim, SO->EmbedDim);
03407       SS = SUMA_StringAppend (SS,stmp);
03408       sprintf (stmp,"RotationWeight: %d, ViewCenterWeight %d\n", SO->RotationWeight, SO->ViewCenterWeight);
03409       SS = SUMA_StringAppend (SS,stmp);
03410       sprintf (stmp,"N_FaceSet: %d, FaceSetDim %d\n", SO->N_FaceSet, SO->FaceSetDim);
03411       SS = SUMA_StringAppend (SS,stmp);
03412       
03413       SUMA_EULER_SO(SO, eu);
03414       SS = SUMA_StringAppend_va (SS, "Euler No. = %d\n\n", eu);
03415       
03416       sprintf (stmp,"Center: [%.3f\t%.3f\t%.3f]\n", SO->Center[0], SO->Center[1],SO->Center[2]);
03417       SS = SUMA_StringAppend (SS,stmp);
03418 
03419       sprintf (stmp,"Maximum: [%.3f\t%.3f\t%.3f]\t (aMax %.3f)\n", SO->MaxDims[0], SO->MaxDims[1],SO->MaxDims[2], SO->aMaxDims);
03420       SS = SUMA_StringAppend (SS,stmp);
03421 
03422       sprintf (stmp,"Minimum: [%.3f\t%.3f\t%.3f]\t (aMin %.3f)\n\n", SO->MinDims[0], SO->MinDims[1],SO->MinDims[2], SO->aMinDims);
03423       SS = SUMA_StringAppend (SS,stmp);
03424       sprintf (stmp,"SUMA_VolPar_Aligned: %d\n", SO->SUMA_VolPar_Aligned);
03425       SS = SUMA_StringAppend (SS,stmp);
03426       sprintf (stmp,"VOLREG_APPLIED: %d\n", SO->VOLREG_APPLIED);
03427       SS = SUMA_StringAppend (SS,stmp);
03428       sprintf (stmp,"ROTATE_APPLIED: %d\n", SO->ROTATE_APPLIED);
03429       SS = SUMA_StringAppend (SS,stmp);
03430       sprintf (stmp,"TAGALIGN_APPLIED: %d\n", SO->TAGALIGN_APPLIED);
03431       SS = SUMA_StringAppend (SS,stmp);
03432       sprintf (stmp,"ShowSelecetedNode: %d\tSelectedNode %d\n",\
03433          SO->ShowSelectedNode, SO->SelectedNode);
03434       SS = SUMA_StringAppend (SS,stmp);
03435 
03436       sprintf (stmp,"ShowSelecetedFaceSet: %d\tSelectedFaceSet %d\n\n",\
03437          SO->ShowSelectedFaceSet, SO->SelectedFaceSet);
03438       SS = SUMA_StringAppend (SS,stmp);
03439 
03440       SS = SUMA_StringAppend (SS, SUMA_VolPar_Info(SO->VolPar));
03441 
03442       if (SO->NodeList == NULL) {
03443          sprintf (stmp,"NodeList is NULL\n\n");
03444          SS = SUMA_StringAppend (SS,stmp);
03445       } else {
03446          if (MaxShow > SO->N_Node) MaxShow = SO->N_Node; 
03447          sprintf (stmp, "NodeList (showing %d out of %d elements):\n", MaxShow, SO->N_Node);
03448          SS = SUMA_StringAppend (SS,stmp);
03449          for (i=0; i < MaxShow; ++i)   {
03450             for (j=0; j < SO->NodeDim; ++j) {
03451                sprintf (stmp, "\t%.3f", SO->NodeList[ND * i + j]);
03452                SS = SUMA_StringAppend (SS,stmp);
03453             }
03454             sprintf (stmp, "\n\n");
03455             SS = SUMA_StringAppend (SS,stmp);
03456          }
03457       }
03458 
03459       if (SO->NodeNormList == NULL) {
03460          sprintf (stmp,"NodeNormList is NULL\n\n");
03461          SS = SUMA_StringAppend (SS,stmp);
03462       } else {
03463          if (MaxShow > SO->N_Node) MaxShow = SO->N_Node; 
03464          sprintf (stmp, "NodeNormList (showing %d out of %d elements):\n", MaxShow, SO->N_Node);
03465          SS = SUMA_StringAppend (SS,stmp);
03466          for (i=0; i < MaxShow; ++i)   {
03467             for (j=0; j < 3; ++j) {
03468                sprintf (stmp, "\t%.3f", SO->NodeNormList[ND * i + j]);
03469                SS = SUMA_StringAppend (SS,stmp);
03470             }
03471             sprintf (stmp, "\n");
03472             SS = SUMA_StringAppend (SS,stmp);
03473          }
03474          sprintf (stmp, "\n");
03475          SS = SUMA_StringAppend (SS,stmp);
03476       }
03477 
03478 
03479       if (SO->FaceSetList == NULL) {
03480          sprintf (stmp,"FaceSetList is NULL\n\n");
03481          SS = SUMA_StringAppend (SS,stmp);
03482       } else {
03483          if (MaxShow > SO->N_FaceSet) MaxShow = SO->N_FaceSet; 
03484          sprintf (stmp, "FaceSetList: (showing %d out of %d elements):\n", MaxShow, SO->N_FaceSet);
03485          SS = SUMA_StringAppend (SS,stmp);
03486          for (i=0; i < MaxShow; ++i)   {
03487             for (j=0; j < SO->FaceSetDim; ++j) {
03488                sprintf (stmp, "\t%d", SO->FaceSetList[NP * i + j]);
03489                SS = SUMA_StringAppend (SS,stmp);
03490             }
03491             sprintf (stmp, "\n");
03492             SS = SUMA_StringAppend (SS,stmp);
03493          }
03494          sprintf (stmp, "\n");
03495          SS = SUMA_StringAppend (SS,stmp);
03496       }
03497 
03498       if (SO->FaceNormList == NULL) {
03499          sprintf (stmp,"FaceNormList is NULL\n\n");
03500          SS = SUMA_StringAppend (SS,stmp);
03501       } else {
03502          if (MaxShow > SO->N_FaceSet) MaxShow = SO->N_FaceSet; 
03503          sprintf (stmp, "FaceNormList (showing %d out of %d elements):\n", MaxShow, SO->N_FaceSet);
03504          SS = SUMA_StringAppend (SS,stmp);
03505          for (i=0; i < MaxShow; ++i)   {
03506             for (j=0; j < 3; ++j) {
03507                sprintf (stmp, "\t%.3f", SO->FaceNormList[NP * i + j]);
03508                SS = SUMA_StringAppend (SS,stmp);
03509             }
03510             sprintf (stmp, "\n");
03511             SS = SUMA_StringAppend (SS,stmp);
03512          }
03513          sprintf (stmp, "\n");
03514          SS = SUMA_StringAppend (SS,stmp);
03515       }
03516 
03517 
03518       if (SO->MF == NULL) {
03519          sprintf (stmp,"SO->MF = NULL\n\n") ;
03520          SS = SUMA_StringAppend (SS,stmp);
03521       } else {
03522          if (MaxShow > SO->N_Node) MaxShow = SO->N_Node; 
03523          sprintf (stmp, "SO->MF (showing %d out of %d elements):\n", MaxShow, SO->N_Node);
03524          SS = SUMA_StringAppend (SS,stmp);
03525          for (i=0; i < MaxShow ; ++i)   {
03526             sprintf (stmp,"\tNode %d: Member of %d FaceSets: ", i, SO->MF->N_Memb[i]);
03527             SS = SUMA_StringAppend (SS,stmp);
03528             for (j=0; j < SO->MF->N_Memb[i]; ++j) {
03529                sprintf (stmp,"%d, ", SO->MF->NodeMemberOfFaceSet[i][j]);
03530                SS = SUMA_StringAppend (SS,stmp);
03531             }
03532             sprintf (stmp,"\n");
03533             SS = SUMA_StringAppend (SS,stmp);
03534          }
03535          sprintf (stmp, "\n");
03536          SS = SUMA_StringAppend (SS,stmp);
03537       }
03538 
03539       if (SO->FN == NULL) {
03540          sprintf (stmp,"SO->FN = NULL\n\n") ;
03541          SS = SUMA_StringAppend (SS,stmp);
03542       } else {
03543          if (MaxShow > SO->N_Node) MaxShow = SO->N_Node; 
03544          sprintf (stmp, "SO->FN, Max. Neighbs of %d (showing %d out of %d elements):\n", SO->FN->N_Neighb_max, MaxShow, SO->N_Node);
03545          SS = SUMA_StringAppend (SS,stmp);
03546          for (i=0; i < MaxShow ; ++i)   {
03547             sprintf (stmp,"\tNode %d: %d Neighbors:\t", i, SO->FN->N_Neighb[i]);
03548             SS = SUMA_StringAppend (SS,stmp);
03549              for (j=0; j< SO->FN->N_Neighb[i]; ++j) {
03550                sprintf (stmp,"%d, ", SO->FN->FirstNeighb[i][j]);
03551                SS = SUMA_StringAppend (SS,stmp);
03552             }
03553             sprintf (stmp,"\n");
03554             SS = SUMA_StringAppend (SS,stmp);
03555          }
03556          sprintf (stmp, "\n");
03557          SS = SUMA_StringAppend (SS,stmp);
03558       }
03559 
03560       if (SO->EL == NULL) {
03561          sprintf (stmp,"SO->EL = NULL\n\n") ;
03562          SS = SUMA_StringAppend (SS,stmp);
03563       } else {
03564          if (MaxShow > SO->EL->N_EL) MaxShow = SO->EL->N_EL; 
03565          sprintf (stmp, "SO->EL, %d edges, %d unique edges.\n"
03566                         "max_Hosts %d, min_Hosts %d (showing %d out of %d elements):\n", \
03567                SO->EL->N_EL, SO->EL->N_Distinct_Edges, SO->EL->max_N_Hosts, SO->EL->min_N_Hosts, MaxShow, SO->EL->N_EL);
03568          SS = SUMA_StringAppend (SS,stmp);
03569          for (i=0; i < MaxShow ; ++i)   {
03570             sprintf (stmp,"\tEdge %d: %d %d\tFlip %d Tri %d N_tri %d\n",\
03571                 i, SO->EL->EL[i][0], SO->EL->EL[i][1], SO->EL->ELps[i][0], SO->EL->ELps[i][1],SO->EL->ELps[i][2]);
03572             SS = SUMA_StringAppend (SS,stmp);   
03573          }
03574          sprintf (stmp,"\n");
03575          SS = SUMA_StringAppend (SS,stmp);
03576          
03577          if (MaxShow > SO->N_FaceSet) MaxShow = SO->N_FaceSet; 
03578          sprintf (stmp, "Triangle Limbs, (showing %d out of %d elements):\n", MaxShow, SO->N_FaceSet);
03579          SS = SUMA_StringAppend (SS,stmp);
03580          for (i=0; i < MaxShow ; ++i)   {
03581             sprintf (stmp,"\tTri_limb[%d][:] = %d %d %d\n", \
03582             i, SO->EL->Tri_limb[i][0], SO->EL->Tri_limb[i][1],SO->EL->Tri_limb[i][2]);
03583             SS = SUMA_StringAppend (SS,stmp);
03584          } 
03585          sprintf (stmp, "\n");
03586          SS = SUMA_StringAppend (SS,stmp);
03587       }
03588 
03589       if (SO->PolyArea == NULL) {
03590          sprintf (stmp,"SO->PolyArea = NULL\n\n") ;
03591          SS = SUMA_StringAppend (SS,stmp);
03592       } else {
03593          if (MaxShow > SO->N_FaceSet) MaxShow = SO->N_FaceSet;
03594          sprintf (stmp, "SO->PolyArea, showing %d out of %d elements:\n", MaxShow, SO->N_FaceSet);
03595          SS = SUMA_StringAppend (SS,stmp);
03596          for (i=0; i < MaxShow ; ++i)   {
03597             sprintf (stmp,"\tFaceSet %d: Area = %f\n", i, SO->PolyArea[i]);
03598             SS = SUMA_StringAppend (SS,stmp);
03599          }
03600       }
03601       sprintf (stmp,"\n");
03602       SS = SUMA_StringAppend (SS,stmp);
03603       
03604       if (DsetList) {
03605          float *Cx = NULL;
03606          Cx = (float *)SUMA_GetCx(SO->idcode_str, DsetList, 0);
03607          if (Cx == NULL) {
03608             sprintf (stmp,"Cx = NULL\n\n") ;
03609             SS = SUMA_StringAppend (SS,stmp);
03610          } else {
03611             if (MaxShow > SO->N_Node) MaxShow = SO->N_Node;
03612             sprintf (stmp, "Cx, showing %d out of %d elements:\n", MaxShow, SO->N_Node);
03613             SS = SUMA_StringAppend (SS,stmp);
03614             for (i=0; i < MaxShow ; ++i)   {
03615                sprintf (stmp,"\t Cx[%d] = %f\n", i, Cx[i]);
03616                SS = SUMA_StringAppend (SS,stmp);
03617             }
03618          }
03619       } else {
03620          SS = SUMA_StringAppend (SS, "NULL DsetList, No Cx can be found.\n");
03621       }
03622       
03623       if (SO->N_Overlays) {
03624          sprintf (stmp,"%d Overlay planes.\n", SO->N_Overlays);
03625          SS = SUMA_StringAppend (SS,stmp);
03626          s = SUMA_ColorOverlayPlane_Info(SO->Overlays, SO->N_Overlays, 0);
03627          if (s) {
03628             SS = SUMA_StringAppend (SS,s);
03629             SUMA_free(s);
03630             s = NULL;
03631          }
03632          
03633       }else {
03634          sprintf (stmp,"No overlay planes.\n");
03635          SS = SUMA_StringAppend (SS,stmp);
03636       }
03637       sprintf (stmp,"\n");
03638       SS = SUMA_StringAppend (SS,stmp);
03639       
03640       if (!SO->PermCol) SUMA_StringAppend (SS,"PermCol = NULL\n");
03641       else SUMA_StringAppend (SS,"PermCol is NOT NULL\n");
03642       
03643       if ( (SO->PermCol && SO->N_Overlays) || (SO->PermCol && SO->N_Overlays) ) {
03644          SUMA_StringAppend (SS,"CONFLICT! Both PermCol and Overlays are specified!\n");
03645       }
03646       
03647    } else {
03648       sprintf (stmp, "NULL Surface Object Pointer.");
03649       SS = SUMA_StringAppend (SS, stmp);
03650    }   
03651    
03652    /* clean SS */
03653    SS = SUMA_StringAppend (SS, NULL);
03654    /* copy s pointer and free SS */
03655    s = SS->s;
03656    SUMA_free(SS); 
03657    
03658    SUMA_RETURN (s);
03659 }
03660 
03661 /*!**
03662 File : SUMA_Load_Surface_Object.c
03663 \author Ziad Saad
03664 Date : Fri Jan 25  2002
03665    
03666 Purpose : 
03667    Print the contents of a Surface Object
03668    
03669    
03670 Usage : 
03671     SUMA_Print_Surface_Object ( SO, Out)
03672    
03673    
03674 Input paramters : 
03675 \param   SO (SUMA_SurfaceObject *) Surface Object pointer
03676 \param   Out (FILE *) stream pointer. (can use stdout or stderr)
03677          If you pass a file pointer, make sure it is open before 
03678          making the function call. Also, make sure you close it
03679          afterwards. You can pass a NULL pointer and the output 
03680          will default to stdout.
03681 \sa SUMA_Load_Surface_Object  
03682 \sa SUMA_SurfaceObject_Info      
03683 ***/
03684    
03685 void SUMA_Print_Surface_Object (SUMA_SurfaceObject *SO, FILE *Out)
03686 {   
03687    static char FuncName[]={"SUMA_Print_Surface_Object"};
03688    char *s;
03689    
03690    SUMA_ENTRY;
03691 
03692    if (Out == NULL) Out = stdout;
03693    
03694    if (SUMAg_CF)    
03695       s = SUMA_SurfaceObject_Info (SO, SUMAg_CF->DsetList);
03696    else 
03697       s = SUMA_SurfaceObject_Info (SO, NULL);
03698       
03699    if (s) {
03700       fprintf (Out, "%s", s);
03701       SUMA_free(s);
03702    }else {
03703       fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_SurfaceObject_Info.\n", FuncName);
03704    }   
03705    
03706    SUMA_RETURNe;
03707 }   
03708 
03709 /*!
03710 Create a Surface Object data structure 
03711 */
03712 
03713 SUMA_SurfaceObject *SUMA_Alloc_SurfObject_Struct(int N)
03714 {
03715    static char FuncName[]={"SUMA_Alloc_SurfObject_Struct"};
03716    SUMA_SurfaceObject *SO;
03717    int i, j;
03718    
03719    SUMA_ENTRY;
03720 
03721    SO = (SUMA_SurfaceObject *)SUMA_malloc(sizeof(SUMA_SurfaceObject)*N);
03722    if (SO == NULL) {
03723       SUMA_alloc_problem("SUMA_Alloc_SurfObject_Struct: could not allocate memory for SO");
03724    }
03725    
03726    for (i=0; i< N; ++i) {
03727       SO[i].FileType = SUMA_FT_NOT_SPECIFIED;
03728       SO[i].FileFormat = SUMA_FF_NOT_SPECIFIED;
03729       SO[i].NodeMarker = NULL;
03730       SO[i].Name_NodeParent = NULL;
03731       SO[i].Label = NULL;
03732       SO[i].EmbedDim = 3;
03733       SO[i].Center[0] = SO[i].Center[1] = SO[i].Center[2] = 0.0;
03734       SO[i].MaxDims[0] = SO[i].MaxDims[1] = SO[i].MaxDims[2] = 0.0;       
03735       SO[i].MinDims[0] = SO[i].MinDims[1] = SO[i].MinDims[2] = 0.0;       
03736       SO[i].aMinDims = 0.0;     
03737       SO[i].aMaxDims = 0.0;
03738       SO[i].MF = NULL;
03739       SO[i].FN = NULL;
03740       SO[i].EL = NULL;
03741       SO[i].PolyArea = NULL;
03742       SO[i].SC = NULL;
03743       SO[i].VolPar = NULL;
03744       SO[i].NodeList = NULL; 
03745       SO[i].FaceSetList = NULL; 
03746       SO[i].FaceNormList = NULL; 
03747       SO[i].NodeNormList = NULL; 
03748       SO[i].glar_NodeList = NULL; 
03749       SO[i].glar_FaceSetList = NULL; 
03750       SO[i].glar_FaceNormList = NULL; 
03751       SO[i].glar_NodeNormList = NULL; 
03752       /* create vector of pointers */
03753       SO[i].Overlays = (SUMA_OVERLAYS **) SUMA_malloc(sizeof(SUMA_OVERLAYS *) * SUMA_MAX_OVERLAYS);
03754       /* fill pointers with NULL */
03755       for (j=0; j < SUMA_MAX_OVERLAYS; ++j) {
03756          SO[i].Overlays[j] = NULL;
03757       }
03758       SO[i].N_Overlays = 0;
03759       SO[i].SentToAfni = NOPE;
03760       
03761       SO[i].MeshAxis = NULL;
03762       SO[i].State = NULL;
03763       SO[i].Group = NULL;
03764       SO[i].FaceSetMarker = NULL;
03765       SO[i].idcode_str = NULL;
03766       SO[i].facesetlist_idcode_str = NULL;
03767       SO[i].nodelist_idcode_str = NULL;
03768       SO[i].facenormals_idcode_str = NULL;
03769       SO[i].nodenormals_idcode_str = NULL;
03770       SO[i].polyarea_idcode_str = NULL;
03771       SO[i].SpecFile.Path = NULL;
03772       SO[i].SpecFile.FileName = NULL;
03773       SO[i].Name.Path = NULL;
03774       SO[i].Name.FileName = NULL;
03775       SO[i].Name_coord.Path = NULL;
03776       SO[i].Name_coord.FileName = NULL;
03777       SO[i].Name_topo.Path = NULL;
03778       SO[i].Name_topo.FileName = NULL;
03779       SO[i].SUMA_VolPar_Aligned = NOPE;
03780       SO[i].VOLREG_APPLIED = NOPE;
03781       SO[i].TAGALIGN_APPLIED = NOPE;
03782       SO[i].ROTATE_APPLIED = NOPE;
03783       SO[i].SurfCont = NULL; /* This is now handled in SUMA_LoadSpec_eng (used to be SUMA_CreateSurfContStruct();) */
03784       SO[i].PolyMode = SRM_ViewerDefault;
03785       SO[i].Show = YUP;
03786       SO[i].Side = SUMA_NO_SIDE;
03787       SO[i].AnatCorrect = NOPE;
03788       SO[i].DomainGrandParentID = NULL;
03789       SO[i].OriginatorID = NULL;
03790       SO[i].LocalDomainParent = NULL;
03791       SO[i].LocalCurvatureParent = NULL;
03792       SO[i].LocalDomainParentID = NULL;
03793       SO[i].LocalCurvatureParentID = NULL;
03794       SO[i].PermCol = NULL;
03795       
03796       SO[i].Group_idcode_str = NULL;
03797       SO[i].ModelName = NULL;
03798       SO[i].OriginatorLabel = NULL;
03799       SO[i].StandardSpace = NULL;
03800       SO[i].parent_vol_idcode_str = NULL;
03801      }
03802    SUMA_RETURN(SO);
03803 }/* SUMA_Alloc_SurfObject_Struct */
03804 
03805 /*! 
03806    \brief function for freeing a SUMA_ROI structure.
03807    ans = SUMA_freeROI (ROI);
03808    \param ROI (SUMA_ROI *) pointer to an ROI structure
03809    \return YUP/NOPE
03810    
03811    \sa SUMA_AllocateROI
03812 */
03813 SUMA_Boolean SUMA_freeROI (SUMA_ROI *ROI) 
03814 {
03815    static char FuncName[]={"SUMA_freeROI"};
03816    
03817    SUMA_ENTRY;
03818       
03819    if (ROI->Parent_idcode_str) SUMA_free(ROI->Parent_idcode_str);
03820    if (ROI->idcode_str) SUMA_free(ROI->idcode_str);
03821    if (ROI->Label) SUMA_free(ROI->Label);
03822    if (ROI->ElInd) SUMA_free(ROI->ElInd);
03823    if (ROI) SUMA_free(ROI);
03824    
03825    SUMA_RETURN (YUP);
03826 }
03827 
03828 /*! 
03829    \brief function for freeing a SUMA_DRAWN_ROI structure.
03830    ans = SUMA_freeDrawnROI (D_ROI);
03831    \param D_ROI (SUMA_DRAWN_ROI *) pointer to a drawn ROI structure
03832    \return YUP/NOPE
03833    
03834    \sa SUMA_AllocateDrawnROI
03835 */
03836 SUMA_Boolean SUMA_freeDrawnROI (SUMA_DRAWN_ROI *D_ROI) 
03837 {
03838    static char FuncName[]={"SUMA_freeDrawnROI"};
03839    
03840    SUMA_ENTRY;
03841    
03842    
03843    if (D_ROI->Parent_idcode_str) SUMA_free(D_ROI->Parent_idcode_str);
03844    if (D_ROI->idcode_str) SUMA_free(D_ROI->idcode_str);
03845    if (D_ROI->Label) SUMA_free(D_ROI->Label);
03846    if (D_ROI->ColPlaneName) SUMA_free(D_ROI->ColPlaneName); 
03847    if (D_ROI->ROIstrokelist) SUMA_EmptyDestroyList(D_ROI->ROIstrokelist);
03848    if (D_ROI->ActionStack) SUMA_EmptyDestroyActionStack(D_ROI->ActionStack);
03849    if (D_ROI->CE) SUMA_free(D_ROI->CE);
03850    if (D_ROI) SUMA_free(D_ROI);
03851    
03852    SUMA_RETURN (YUP);
03853 }
03854 
03855 /*! 
03856    \brief function for creating (allocating and initializing) the contents of a SUMA_ROI structure.
03857    ROI = SUMA_AllocateROI (Parent_idcode_str, Type, label, int N_ElInd, int *ElInd) 
03858    
03859    \param Parent_idcode_str (char *) idcode of parent surface
03860    \param Type (SUMA_ROI_TYPE) type of ROI 
03861    \param label  (char *) label ascii label to label ROI. If you pass NULL, a number is assigned to the ROI automatically
03862    \param N_ElInd (int) number of elements in ElInd to allocate for.
03863    \param ElInd (int *) vector of indices to initialize the ROI with, pass NULL for no initialization.
03864                         Values in ElInd are copied into ROI->ElInd.
03865    \return (SUMA_ROI *) ROI pointer to ROI object created
03866                an idcode_str is assigned to ROI
03867    \sa SUMA_freeROI             
03868 */
03869 SUMA_ROI *SUMA_AllocateROI (char *Parent_idcode_str, SUMA_ROI_TYPE Type, char *label, int N_ElInd, int *ElInd) 
03870 {
03871    SUMA_ROI *ROI = NULL;
03872    static int ROI_index = 0;
03873    int i = 0;
03874    static char FuncName[]={"SUMA_AllocateROI"};
03875    
03876    SUMA_ENTRY;
03877    
03878    ROI = (SUMA_ROI *) SUMA_malloc (sizeof(SUMA_ROI));
03879    ROI->idcode_str = (char *)SUMA_calloc (SUMA_IDCODE_LENGTH+1, sizeof(char));
03880    ROI->Parent_idcode_str = (char *)SUMA_calloc (strlen(Parent_idcode_str)+1, sizeof (char));
03881    if (label) ROI->Label = (char *)SUMA_calloc (strlen(label)+1, sizeof(char));
03882    else ROI->Label = (char *)SUMA_calloc (20, sizeof(char));
03883    ROI->ElInd = (int *)SUMA_calloc (N_ElInd, sizeof (int));
03884    
03885    if (!ROI || !ROI->idcode_str || !ROI->Parent_idcode_str || !ROI->Label || !ROI->ElInd) {
03886       fprintf (SUMA_STDERR, "Error %s: Failed allocating.\n", FuncName);
03887       SUMA_RETURN (NULL);
03888    }
03889    
03890    ROI->N_ElInd = N_ElInd;
03891    
03892    if (ElInd) {
03893       for (i=0; i<N_ElInd; ++i)
03894          ROI->ElInd[i] = ElInd[i];
03895    }
03896    
03897    UNIQ_idcode_fill(ROI->idcode_str);   
03898    
03899    ROI->Parent_idcode_str = strcpy (ROI->Parent_idcode_str, Parent_idcode_str);
03900    if (label) ROI->Label = strcpy (ROI->Label, label);
03901    else sprintf (ROI->Label, "auto label %d", ROI_index);
03902    
03903    ROI->Type = Type;
03904    
03905    ++ROI_index;
03906    SUMA_RETURN (ROI);
03907 }
03908 
03909 
03910 /*! 
03911    \brief function for creating (allocating and initializing) the contents of a SUMA_DRAWN_ROI structure.
03912    D_ROI = SUMA_AllocateDrawnROI (Parent_idcode_str, DrawStatus, Type, label , ilabel) 
03913    \param Parent_idcode_str (char *) idcode of parent surface
03914    \param DrawStatus (SUMA_ROI_DRAWING_STATUS) status of ROI being drawn
03915    \param Type (SUMA_ROI_DRAWING_TYPE) type of ROI being drawn
03916    \param label (char *) label ascii label to label ROI. If you pass NULL, a number is assigned to the ROI automatically
03917    \param ilabel (int) integer label (or value)
03918    \return (SUMA_DRAWN_ROI *) D_ROI pointer to ROI object created
03919    
03920    \sa SUMA_NIMLDrawnROI_to_DrawnROI where a SUMA_DRAWN_ROI is also created
03921 */
03922 SUMA_DRAWN_ROI *SUMA_AllocateDrawnROI (char *Parent_idcode_str, SUMA_ROI_DRAWING_STATUS DrawStatus, 
03923                                        SUMA_ROI_DRAWING_TYPE Type, char *label, int ilabel) 
03924 {
03925    SUMA_DRAWN_ROI *D_ROI = NULL;
03926    static int ROI_index = 1;
03927    static char FuncName[]={"SUMA_AllocateDrawnROI"};
03928    
03929    SUMA_ENTRY;
03930    
03931    D_ROI = (SUMA_DRAWN_ROI *) SUMA_malloc (sizeof(SUMA_DRAWN_ROI));
03932    D_ROI->idcode_str = (char *)SUMA_calloc (SUMA_IDCODE_LENGTH, sizeof(char));
03933    D_ROI->Parent_idcode_str = (char *)SUMA_calloc (strlen(Parent_idcode_str)+1, sizeof (char));
03934    D_ROI->ColPlaneName = SUMA_copy_string("DefROIpl");
03935    D_ROI->FillColor[0] = 1.0; D_ROI->FillColor[1] = 0.0; D_ROI->FillColor[2] = 0.0;
03936    D_ROI->EdgeColor[0] = 0.0; D_ROI->EdgeColor[1] = 0.0; D_ROI->EdgeColor[2] = 1.0;
03937    D_ROI->EdgeThickness = 2;
03938    D_ROI->ROIstrokelist = (DList *)SUMA_malloc (sizeof(DList));
03939    dlist_init(D_ROI->ROIstrokelist, SUMA_FreeROIDatum);
03940    D_ROI->CE = NULL;
03941    D_ROI->N_CE = -1;
03942    
03943    if (label) D_ROI->Label = (char *)SUMA_calloc (strlen(label)+1, sizeof(char));
03944    else D_ROI->Label = (char *)SUMA_calloc (20, sizeof(char));
03945    
03946    if (!D_ROI || !D_ROI->idcode_str || !D_ROI->Parent_idcode_str || !D_ROI->Label) {
03947       fprintf (SUMA_STDERR, "Error %s: Failed allocating.\n", FuncName);
03948       SUMA_RETURN (NULL);
03949    }
03950       
03951    UNIQ_idcode_fill(D_ROI->idcode_str);   
03952    
03953    D_ROI->Parent_idcode_str = strcpy (D_ROI->Parent_idcode_str, Parent_idcode_str);
03954    if (label) D_ROI->Label = strcpy (D_ROI->Label, label);
03955    else sprintf (D_ROI->Label, "auto label %d", ROI_index);
03956    
03957    D_ROI->DrawStatus = DrawStatus;
03958    D_ROI->Type = Type;
03959    
03960    D_ROI->ActionStack = SUMA_CreateActionStack ();
03961    D_ROI->StackPos = NULL;
03962    
03963    D_ROI->iLabel = ilabel;
03964    D_ROI->ColorByLabel = YUP;
03965    
03966    ++ROI_index;
03967    SUMA_RETURN (D_ROI);
03968 }
03969 
03970 /*!
03971    A destructor for SUMA_ROI_DATUM *
03972 */
03973 void SUMA_FreeROIDatum (void * data) 
03974 {
03975    static char FuncName[]={"SUMA_FreeROIDatum"};
03976    SUMA_ROI_DATUM *ROId=NULL;
03977    SUMA_Boolean LocalHead = NOPE;
03978    
03979    SUMA_ENTRY;
03980    
03981    ROId = (SUMA_ROI_DATUM *)data;
03982    
03983    if (!ROId) {
03984       SUMA_RETURNe;
03985    }
03986    
03987    if (LocalHead) fprintf (SUMA_STDERR, "%s: Freeing nPath\n", FuncName);
03988    if (ROId->nPath) SUMA_free(ROId->nPath);
03989    if (LocalHead) fprintf (SUMA_STDERR, "%s: Freeing tPath\n", FuncName);
03990    if (ROId->tPath) SUMA_free(ROId->tPath);
03991    if (LocalHead) fprintf (SUMA_STDERR, "%s: Freeing ROId\n", FuncName);
03992    SUMA_free(ROId);
03993    
03994    SUMA_RETURNe;
03995 }
03996 
03997 /*!
03998    A constructor for SUMA_ROI_DATUM *
03999 */
04000 SUMA_ROI_DATUM * SUMA_AllocROIDatum (void) 
04001 {
04002    static char FuncName[]={"SUMA_AllocROIDatum"};
04003    SUMA_ROI_DATUM *ROId=NULL;
04004    
04005    SUMA_ENTRY;
04006    
04007    ROId = (SUMA_ROI_DATUM *) SUMA_malloc (sizeof(SUMA_ROI_DATUM));
04008    
04009    if (!ROId) {
04010       SUMA_RETURN (NULL);
04011    }
04012    
04013    ROId->nPath = ROId->tPath = NULL;
04014    ROId->N_n = ROId->N_t = 0;
04015    ROId->nDistance = ROId->tDistance = 0.0;
04016    ROId->Type = SUMA_ROI_Undefined;
04017    ROId->action = SUMA_BSA_Undefined;
04018    SUMA_RETURN (ROId);
04019 }
04020 
04021 /*!
04022    \brief Determine if nPath in ROId1 and ROId2 are identical (same nodes).
04023    
04024    - Comparison will fail if either datum is null
04025    
04026    - Function not tested 
04027    
04028 */
04029 SUMA_Boolean SUMA_isROIdequal (SUMA_ROI_DATUM *ROId1, SUMA_ROI_DATUM *ROId2)
04030 {
04031    static char FuncName[]={"SUMA_isROIdequal"};
04032    int i;
04033    
04034    SUMA_ENTRY;
04035    
04036    if (!ROId1 || !ROId2) SUMA_RETURN(NOPE);
04037    if (ROId1->N_n != ROId2->N_n) SUMA_RETURN(NOPE);
04038    if (!ROId1->nPath || !ROId2->nPath) SUMA_RETURN(NOPE);
04039    i = 0;
04040    do {
04041       if (ROId1->nPath[i] != ROId2->nPath[i]) SUMA_RETURN(NOPE);
04042       ++i;
04043    }while (i < ROId2->N_n);
04044    
04045    SUMA_RETURN(YUP);
04046 }
04047 
04048 /*!
04049    \brief Merges two ROIdatum together. 
04050    ans = SUMA_AppendToROIdatum (ROIlink, ROId);
04051    ROId = [ROId ROIlink]
04052    
04053    \param ROIlink (SUMA_ROI_DATUM *)
04054    \param ROId (SUMA_ROI_DATUM *)
04055    \return ans YUP/NOPE
04056    
04057    - ROId becomes ROId followed by ROIlink 
04058    - ROIlink is not freed
04059    - It is required that the last node of ROId be the first node of ROIlink.
04060    - This is not required for the tPath (the triangle path). By the same token,
04061    it is not guaranteed that the resultant tPath is contiguous (not yet).
04062    
04063    \sa SUMA_PrependToROIdatum
04064 */
04065 SUMA_Boolean SUMA_AppendToROIdatum (SUMA_ROI_DATUM *ROId1, SUMA_ROI_DATUM *ROId2)
04066 {
04067    static char FuncName[]={"SUMA_AppendToROIdatum"};
04068    int i, N_nNew=-1, N_tNew=-1, *tPathNew=NULL, *nPathNew=NULL;
04069    SUMA_Boolean CommonTip = NOPE;
04070    
04071    SUMA_ENTRY;
04072    
04073    if (!ROId1) SUMA_RETURN(YUP);
04074    if (!ROId1->N_n)  SUMA_RETURN(YUP);
04075    if (!ROId2) {
04076       fprintf (SUMA_STDERR, "Error %s: NULL ROId2.\n", FuncName);
04077       SUMA_RETURN(NOPE);
04078    }
04079    /* make sure the last node of ROId2 and the first node of ROId1 match */
04080    if (ROId2->N_n) {
04081       if (ROId1->nPath[0] != ROId2->nPath[ROId2->N_n-1]) {
04082          fprintf (SUMA_STDERR, "Error %s: Last node of ROId2 is not the same as the first node of ROId1.\n", FuncName);
04083          SUMA_RETURN(NOPE);
04084       }
04085    }
04086    /* now merge the two */
04087    
04088    /* FIRST the nodes */
04089    /* figure out the new N_n */
04090    N_nNew = ROId1->N_n + ROId2->N_n -1;
04091    
04092    /* create a new nPath pointer */
04093    nPathNew = (int *)SUMA_calloc (N_nNew, sizeof (int));
04094    if (!nPathNew) {
04095       fprintf (SUMA_STDERR, "Error %s: Failed to allocate. \n", FuncName);
04096       SUMA_RETURN(NOPE);
04097    }
04098    
04099    for (i=0; i<ROId2->N_n; ++i) nPathNew[i] = ROId2->nPath[i];
04100    for (i=1; i<ROId1->N_n; ++i) nPathNew[ROId2->N_n+i-1] = ROId1->nPath[i];
04101    SUMA_free(ROId2->nPath);
04102    ROId2->nPath = nPathNew;
04103    ROId2->N_n = N_nNew;
04104    
04105    /* SECOND THE triangles */
04106    CommonTip = NOPE;
04107    if (!ROId1->tPath || !ROId1->N_t) {
04108       /* nothing to do */
04109       ROId2->tPath = NULL;
04110       ROId2->N_t = 0;
04111       SUMA_RETURN(YUP);
04112    }else{
04113       /* do the strips have a common triangle at the end ? */
04114       if (ROId2->N_t) {
04115          if (ROId1->tPath[0] == ROId2->tPath[ROId2->N_t-1]) CommonTip = YUP;
04116       }
04117    }
04118    if (CommonTip) {
04119       /* figure out the new N_n */
04120       N_tNew = ROId1->N_t + ROId2->N_t -1;
04121 
04122       /* create a new tPath pointer */
04123       tPathNew = (int *)SUMA_calloc (N_tNew, sizeof (int));
04124       if (!tPathNew) {
04125          fprintf (SUMA_STDERR, "Error %s: Failed to allocate. \n", FuncName);
04126          SUMA_RETURN(NOPE);
04127       }
04128       for (i=0; i<ROId2->N_t; ++i) tPathNew[i] = ROId2->tPath[i];
04129       for (i=1; i<ROId1->N_t; ++i) tPathNew[ROId2->N_t+i-1] = ROId1->tPath[i];
04130       SUMA_free(ROId2->tPath);
04131    }else {
04132       /* figure out the new N_n */
04133       N_tNew = ROId1->N_t + ROId2->N_t;
04134 
04135       /* create a new tPath pointer */
04136       tPathNew = (int *)SUMA_calloc (N_tNew, sizeof (int));
04137       if (!tPathNew) {
04138          fprintf (SUMA_STDERR, "Error %s: Failed to allocate. \n", FuncName);
04139          SUMA_RETURN(NOPE);
04140       }
04141       for (i=0; i<ROId2->N_t; ++i) tPathNew[i] = ROId2->tPath[i];
04142       for (i=0; i<ROId1->N_t; ++i) tPathNew[ROId2->N_t+i] = ROId1->tPath[i];
04143       SUMA_free(ROId2->tPath);
04144    }
04145    ROId2->tPath = tPathNew;
04146    ROId2->N_t = N_tNew;
04147 
04148    
04149    SUMA_RETURN(YUP);
04150 }
04151 
04152 /*!
04153    \brief Merges two ROIdatum together. 
04154    ans = SUMA_PrependToROIdatum (ROIlink, ROId);
04155    ROId = [ROIlink ROId]
04156    
04157    \param ROIlink (SUMA_ROI_DATUM *)
04158    \param ROId (SUMA_ROI_DATUM *)
04159    \return ans YUP/NOPE
04160    
04161    - ROId becomes ROIlink followed by ROId
04162    - ROIlink is not freed
04163    - It is required that the last node of ROIlink be the first node of ROId.
04164    - This is not required for the tPath (the triangle path). By the same token,
04165    it is not guaranteed that the resultant tPath is contiguous (not yet).
04166    
04167    \sa SUMA_AppendToROIdatum
04168 */
04169 SUMA_Boolean SUMA_PrependToROIdatum (SUMA_ROI_DATUM *ROId1, SUMA_ROI_DATUM *ROId2)
04170 {
04171    static char FuncName[]={"SUMA_PrependToROIdatum"};
04172    int i, N_nNew=-1, N_tNew=-1, *tPathNew=NULL, *nPathNew=NULL;
04173    SUMA_Boolean CommonTip = NOPE;
04174    
04175    SUMA_ENTRY;
04176    
04177    if (!ROId1) SUMA_RETURN(YUP);
04178    if (!ROId1->N_n)  SUMA_RETURN(YUP);
04179    if (!ROId2) {
04180       fprintf (SUMA_STDERR, "Error %s: NULL ROId2.\n", FuncName);
04181       SUMA_RETURN(NOPE);
04182    }
04183    /* make sure the last node of ROId1 and the first node of ROId2 match */
04184    if (ROId2->N_n) {
04185       if (ROId1->nPath[ROId1->N_n-1] != ROId2->nPath[0]) {
04186          fprintf (SUMA_STDERR, "Error %s: Last node of ROId1 is not the same as the first node of ROId2.\n", FuncName);
04187          SUMA_RETURN(NOPE);
04188       }
04189    }
04190    /* now merge the two */
04191    
04192    /* FIRST the nodes */
04193    /* figure out the new N_n */
04194    N_nNew = ROId1->N_n + ROId2->N_n -1;
04195    
04196    /* create a new nPath pointer */
04197    nPathNew = (int *)SUMA_calloc (N_nNew, sizeof (int));
04198    if (!nPathNew) {
04199       fprintf (SUMA_STDERR, "Error %s: Failed to allocate. \n", FuncName);
04200       SUMA_RETURN(NOPE);
04201    }
04202    for (i=0; i<ROId1->N_n; ++i) nPathNew[i] = ROId1->nPath[i];
04203    for (i=1; i<ROId2->N_n; ++i) nPathNew[ROId1->N_n+i-1] = ROId2->nPath[i];
04204    SUMA_free(ROId2->nPath);
04205    ROId2->nPath = nPathNew;
04206    ROId2->N_n = N_nNew;
04207    
04208    /* SECOND THE triangles */
04209    CommonTip = NOPE;
04210    if (!ROId1->tPath || !ROId1->N_t) {
04211       /* nothing to do */
04212       ROId2->tPath = NULL;
04213       ROId2->N_t = 0;
04214       SUMA_RETURN(YUP);
04215    }else{
04216       /* do the strips have a common triangle at the end ? */
04217       if (ROId2->N_t) {
04218          if (ROId1->tPath[ROId1->N_t-1] == ROId2->tPath[0]) CommonTip = YUP;
04219       }
04220    }
04221    if (CommonTip) {
04222       /* figure out the new N_n */
04223       N_tNew = ROId1->N_t + ROId2->N_t -1;
04224 
04225       /* create a new tPath pointer */
04226       tPathNew = (int *)SUMA_calloc (N_tNew, sizeof (int));
04227       if (!tPathNew) {
04228          fprintf (SUMA_STDERR, "Error %s: Failed to allocate. \n", FuncName);
04229          SUMA_RETURN(NOPE);
04230       }
04231       for (i=0; i<ROId1->N_t; ++i) tPathNew[i] = ROId1->tPath[i];
04232       for (i=1; i<ROId2->N_t; ++i) tPathNew[ROId1->N_t+i-1] = ROId2->tPath[i];
04233       SUMA_free(ROId2->tPath);
04234    }else {
04235       /* figure out the new N_n */
04236       N_tNew = ROId1->N_t + ROId2->N_t;
04237 
04238       /* create a new tPath pointer */
04239       tPathNew = (int *)SUMA_calloc (N_tNew, sizeof (int));
04240       if (!tPathNew) {
04241          fprintf (SUMA_STDERR, "Error %s: Failed to allocate. \n", FuncName);
04242          SUMA_RETURN(NOPE);
04243       }
04244       for (i=0; i<ROId1->N_t; ++i) tPathNew[i] = ROId1->tPath[i];
04245       for (i=0; i<ROId2->N_t; ++i) tPathNew[ROId1->N_t+i] = ROId2->tPath[i];
04246       SUMA_free(ROId2->tPath);
04247    }
04248    ROId2->tPath = tPathNew;
04249    ROId2->N_t = N_tNew;
04250    
04251    SUMA_RETURN(YUP);
04252 }
04253 
04254 /*!
04255    \brief Show contents of a drawn ROI datum
04256    SUMA_ShowDrawnROIDatum (ROId, Out, ShortVersion);
04257    
04258    \param ROId (SUMA_ROI_DATUM *) 
04259    \param Out (FILE *) (stderr if NULL)
04260    \param ShortVersion (SUMA_Boolean) if YUP, short version
04261 
04262 */
04263 void SUMA_ShowDrawnROIDatum (SUMA_ROI_DATUM *ROId, FILE *out, SUMA_Boolean ShortVersion)
04264 {
04265    static char FuncName[]={"SUMA_ShowDrawnROIDatum"};
04266    int i;
04267    
04268    SUMA_ENTRY;
04269    
04270    if (!out) out = SUMA_STDERR;
04271    
04272    if (!ROId) {
04273       fprintf(out, "%s: NULL ROId\n", FuncName);
04274       SUMA_RETURNe;
04275    }
04276    
04277    if (!ROId->N_n) {
04278       fprintf(out, "%s: Empty ROId. (N_n = 0)\n", FuncName);
04279       SUMA_RETURNe;
04280    }
04281    
04282    if (ROId->N_n && !ROId->nPath) {
04283       fprintf(out, "Error %s: nPath is NULL with N_n != 0.\n", FuncName);
04284       SUMA_RETURNe;
04285    }
04286    
04287    if (ROId->N_n == 1) {
04288       fprintf(out, "%s: ROId (type %d) has 1 node (%d) in nPath.\n", 
04289          FuncName, ROId->Type, ROId->nPath[0]);
04290    }else {
04291       fprintf(out, "%s: ROId (type %d) has %d nodes in nPath [%d..%d].\n", 
04292          FuncName, ROId->Type, ROId->N_n, ROId->nPath[0], ROId->nPath[ROId->N_n-1]);
04293       if (!ShortVersion) {
04294          for (i=0; i <ROId->N_n; ++i) fprintf (out, "%d: %d\t", i, ROId->nPath[i]);
04295          fprintf (out, "\n");
04296       }
04297    }
04298    
04299    if (ROId->N_t && !ROId->tPath) {
04300       fprintf(out, "Error %s: tPath is NULL with N_t != 0.\n", FuncName);
04301       SUMA_RETURNe;
04302    }
04303    
04304    if (!ROId->N_t) {
04305       fprintf(out, "%s: Empty ROId->tPath. (N_t = 0)\n", FuncName);
04306       SUMA_RETURNe;
04307    }else {
04308          if (ROId->N_t == 1) {
04309             fprintf(out, "%s: ROId (type %d) has 1 triangle (%d) in tPath.\n", 
04310                FuncName, ROId->Type, ROId->tPath[0]);
04311          }else {
04312             fprintf(out, "%s: ROId (type %d) has %d triangles in tPath [%d..%d].\n", 
04313                FuncName, ROId->Type, ROId->N_t, ROId->tPath[0], ROId->tPath[ROId->N_t-1]);
04314             if (!ShortVersion) {
04315                for (i=0; i <ROId->N_t; ++i) fprintf (out, "%d: %d\t", i, ROId->tPath[i]);
04316                fprintf (out, "\n");
04317             }
04318          }
04319    }
04320    
04321    SUMA_RETURNe;
04322 }
04323 
04324 #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 */
04325 void SUMA_ReportDrawnROIDatumLength(SUMA_SurfaceObject *SO, SUMA_ROI_DATUM *ROId, FILE *out, SUMA_WIDGET_INDEX_DRAWROI_WHATDIST option)
04326 {
04327    static char FuncName[]={"SUMA_ReportDrawnROIDatumLength"};
04328    int N0, N1, i, N_n, *nPath, N_left;
04329    SUMA_Boolean *isNodeInMesh = NULL;
04330    float *p1, *p2;
04331    float ds = 0, d = 0, ds_c, dd, dd_c;
04332    char *s = NULL;
04333    SUMA_STRING *SS = NULL;   
04334    SUMA_Boolean LocalHead = NOPE;
04335    
04336    SUMA_ENTRY;
04337    
04338    if (!ROId) SUMA_RETURNe;
04339    if (ROId->N_n < 2) SUMA_RETURNe;
04340    if (option != SW_DrawROI_WhatDistAll && option != SW_DrawROI_WhatDistTrace) {
04341       SUMA_SL_Err("Why do you get this here ?");
04342       SUMA_RETURNe;
04343    }
04344    SS = SUMA_StringAppend (NULL, NULL);
04345 
04346    /* calculate path distance */
04347    ds = 0.0;
04348    for (i=0; i<ROId->N_n-1; ++i) {
04349       p1 = &(SO->NodeList[3*ROId->nPath[i]]);
04350       p2 = &(SO->NodeList[3*ROId->nPath[i+1]]);
04351       SUMA_SEG_NORM(p1, p2, d); 
04352       ds = ds + d;
04353    }
04354    ds_c = ds / SUMA_FS_DIJKSTRA_DISTANCE_FACTOR;
04355    
04356    dd = -1.0;  dd_c = -1.0;
04357    if (option == SW_DrawROI_WhatDistAll) { /* do shortest distance */
04358       isNodeInMesh = (SUMA_Boolean*) SUMA_malloc(SO->N_Node * sizeof(SUMA_Boolean)); N_left = SO->N_Node; for (i=0;i<N_left;++i) isNodeInMesh[i] = YUP;
04359       if (!isNodeInMesh) {
04360          SUMA_SL_Err("Failed to allocate!\nWill not compute shortest distance.");
04361       }else {
04362          nPath = SUMA_Dijkstra (SO, ROId->nPath[0], ROId->nPath[ROId->N_n - 1], isNodeInMesh, &N_left, 1, &dd, &N_n);
04363          if (nPath) { 
04364             SUMA_free(nPath); nPath = NULL; dd_c = dd / SUMA_FS_DIJKSTRA_DISTANCE_FACTOR;
04365          } else { 
04366             dd = -2.0;  dd_c = -2.0;
04367          }
04368          SUMA_free(isNodeInMesh); isNodeInMesh = NULL;
04369       }
04370       SS = SUMA_StringAppend_va(SS,
04371          "#Distances on %s\n"
04372          "#n0\tn1\tN_n\td\td_c\tds\tds_c\n"
04373          "%d\t%d\t%d\t%.2f\t%.2f\t%.2f\t%.2f\n", 
04374          SO->Label, ROId->nPath[0], ROId->nPath[ROId->N_n - 1], ROId->N_n, ds, ds_c, dd, dd_c);
04375    } else if (option == SW_DrawROI_WhatDistTrace) {
04376       SS = SUMA_StringAppend_va(SS,
04377          "#Distances on %s\n"
04378          "#n0\tn1\tN_n\td\td_c\n"
04379          "%d\t%d\t%d\t%.2f\t%.2f\n", 
04380          SO->Label, ROId->nPath[0], ROId->nPath[ROId->N_n - 1], ROId->N_n, ds, ds_c);
04381    }
04382    
04383    SUMA_SS2S(SS,s);
04384    if (out) fprintf(out, "%s", s);
04385    
04386    SUMA_L_Text(s);
04387    
04388    SUMA_free (s); s= NULL;
04389    SUMA_RETURNe;
04390 } 
04391 /*!
04392    \brief Show contents of a drawn ROI
04393    SUMA_ShowDrawnROI (ROI, Out, ShortVersion);
04394    
04395    \param ROId (SUMA_DRAWN_ROI *) 
04396    \param Out (FILE *) (stderr if NULL)
04397    \param ShortVersion (SUMA_Boolean) if YUP, short version
04398 
04399 */
04400 void SUMA_ShowDrawnROI (SUMA_DRAWN_ROI *D_ROI, FILE *out, SUMA_Boolean ShortVersion)
04401 {
04402    static char FuncName[]={"SUMA_ShowDrawnROI"};
04403    int i;
04404    
04405    SUMA_ENTRY;
04406    
04407    if (!out) out = SUMA_STDERR;
04408 
04409    fprintf(out, "--------------------------------------------\n");
04410    
04411    if (!D_ROI) {
04412       fprintf(out, "%s: NULL D_ROI\n", FuncName);
04413       SUMA_RETURNe;
04414    }
04415    
04416    fprintf(out, "%s: ROI Label %s, Type %d, DrawStatus %d\n Idcode %s, Parent Idcode %s\n", 
04417          FuncName, D_ROI->Label, D_ROI->Type, D_ROI->DrawStatus, D_ROI->idcode_str, D_ROI->Parent_idcode_str );
04418    
04419    if (D_ROI->ActionStack) {
04420       fprintf (out, "%s: There are %d actions in the ActionStack.\n", FuncName, dlist_size(D_ROI->ActionStack));
04421    }else {
04422       fprintf (out, "%s: ActionStack is NULL.\n", FuncName);
04423    }
04424    
04425    if (!D_ROI->ROIstrokelist) {
04426       fprintf(out, "%s: NULL ROIstrokelist.\n", FuncName);
04427       SUMA_RETURNe;
04428    }
04429    
04430 
04431    if (!dlist_size(D_ROI->ROIstrokelist)) {
04432       fprintf(out, "%s: ROIstrokelist is empty.\n", FuncName);
04433    } else {
04434       DListElmt *NextElm=NULL;
04435       int cnt = 0;
04436       fprintf(out, "%s: ROIstrokelist has %d elements.\n", FuncName, dlist_size(D_ROI->ROIstrokelist));
04437       do {
04438          
04439          if (!NextElm) NextElm = dlist_head(D_ROI->ROIstrokelist);
04440          else NextElm = dlist_next(NextElm);
04441          ++cnt;
04442          fprintf(out, "%d\t+++++++++++\n", cnt);
04443          SUMA_ShowDrawnROIDatum ((SUMA_ROI_DATUM *)NextElm->data, out, ShortVersion);
04444       } while (NextElm != dlist_tail(D_ROI->ROIstrokelist));
04445    }
04446    
04447    fprintf(out, "--------------------------------------------\n");
04448    
04449    SUMA_RETURNe;
04450 }
04451 
04452 /*!
04453    \brief SUMA_FillToMask_Engine (FN, Visited, Mask, seed, N_Visited, N_Node);
04454    the engine function for SUMA_FillToMask.
04455    replaces the recursive version now called SUMA_FillToMask_Engine_old
04456 */
04457 void SUMA_FillToMask_Engine (SUMA_NODE_FIRST_NEIGHB *FN, int *Visited, int *ROI_Mask, int nseed, int *N_Visited, int N_Node)
04458 {  
04459    static char FuncName[]={"SUMA_FillToMask_Engine"};
04460    int i, nnext;
04461    int *candidate = NULL;
04462    int N_candidate = 0;
04463    SUMA_Boolean LocalHead = NOPE;
04464    
04465    SUMA_ENTRY;
04466    
04467    candidate = (int *)SUMA_calloc(N_Node, sizeof(int));
04468    if (!candidate) {
04469       SUMA_SL_Crit("Failed to Allocate");
04470       SUMA_RETURNe;
04471    }
04472    
04473    do {
04474       if (!Visited[nseed]) { Visited[nseed] = 1; ++*N_Visited; } /* add the seed, if not added yet */
04475       
04476       for (i=0; i<FN->N_Neighb[nseed]; ++i) {
04477          nnext = FN->FirstNeighb[nseed][i];
04478          /* fprintf (SUMA_STDERR,"nnext=%d\n", nnext); fflush(SUMA_STDERR); */
04479          if (!Visited[nnext] && !ROI_Mask[nnext]) {
04480             candidate[N_candidate] = nnext; ++N_candidate; 
04481             Visited[nnext] = 1; ++*N_Visited;   /* add this candidate so you don't revisit it as a new candidate later */
04482          }
04483       }
04484       nseed = candidate[N_candidate-1]; --N_candidate;
04485    } while (N_candidate);
04486    
04487    if (candidate) SUMA_free(candidate); candidate = NULL; 
04488    SUMA_RETURNe;
04489 }
04490 
04491 /*!
04492    \brief SUMA_FillToMask_Engine (FN, Visited, Mask, seed, N_Visited);
04493    the recursive function for SUMA_FillToMask.
04494    Do not use logging functions here.
04495    
04496    CAN cause Illegal instruction interrupts, bad for blood glucose levels.
04497    Need non recursive version (crashes at cnt = 70676)
04498 */
04499 
04500 void SUMA_FillToMask_Engine_old (SUMA_NODE_FIRST_NEIGHB *FN, int *Visited, int *ROI_Mask, int nseed, int *N_Visited)
04501 {  
04502    int i, nnext;
04503    /* static cnt = 0;
04504    ++cnt;
04505    fprintf (SUMA_STDERR,"    cnt = %d\n", cnt); fflush(SUMA_STDERR); */
04506    Visited[nseed] = 1;
04507    ++*N_Visited;
04508    for (i=0; i<FN->N_Neighb[nseed]; ++i) {
04509       nnext = FN->FirstNeighb[nseed][i];
04510       /* fprintf (SUMA_STDERR,"nnext=%d\n", nnext); fflush(SUMA_STDERR); */
04511       if (!Visited[nnext] && !ROI_Mask[nnext]) {
04512          /*fprintf (SUMA_STDERR,"In!\n"); fflush(SUMA_STDERR); */
04513          SUMA_FillToMask_Engine_old(FN, Visited, ROI_Mask, nnext, N_Visited);
04514       }
04515    }
04516    /* --cnt; */
04517    return;
04518 }
04519 /*!
04520 \brief Returns the ROI formed by connected nodes that are bound by Mask
04521       ROIfill = SUMA_FillToMask (SO, ROI_Mask, FirstSurfNode);
04522       
04523 \param SO (SUMA_SurfaceObject *)
04524 \param ROI_Mask (int *) if (ROI_Mask[n]) then node n is a boundary
04525 \param FirstSurfNode (int) node index from which the fill begins.
04526        
04527 \return ROIfill (SUMA_ROI_DATUM *) of the type SUMA_ROI_NodeGroup
04528 \sa SUMA_FillToMask_Engine
04529 */
04530 SUMA_ROI_DATUM * SUMA_FillToMask(SUMA_SurfaceObject *SO, int *ROI_Mask, int nseed) 
04531 {
04532    static char FuncName[]={"SUMA_FillToMask"};
04533    SUMA_ROI_DATUM *ROIfill = NULL;
04534    int *Visited = NULL;
04535    int N_Visited = 0, i, nnext;
04536    SUMA_Boolean LocalHead = NOPE;
04537    
04538    /* register at the first call only */
04539    SUMA_ENTRY;
04540    
04541    if (!ROI_Mask) {
04542       SUMA_S_Err("NULL Mask.");
04543       SUMA_RETURN(NULL);
04544    }
04545    
04546    /* make sure your seed is not on the edge */
04547    if (ROI_Mask[nseed]) {
04548       SUMA_S_Err("seed is on the edge.");
04549       SUMA_RETURN(NULL);
04550    }
04551 
04552    if (!Visited) { /* allocate */
04553       Visited = (int *)SUMA_calloc (SO->N_Node, sizeof (int));
04554       if (!Visited) {
04555          SUMA_S_Err("Could not allocate for Visited.");
04556          SUMA_RETURN(NULL);
04557       }
04558    }
04559    
04560    N_Visited = 0;
04561 
04562    SUMA_FillToMask_Engine (SO->FN, Visited, ROI_Mask, nseed, &N_Visited, SO->N_Node);
04563    
04564    if (LocalHead) fprintf (SUMA_STDERR, "%s: Found %d nodes to fill.\n", FuncName, N_Visited);
04565       
04566    ROIfill = SUMA_AllocROIDatum();
04567    ROIfill->Type = SUMA_ROI_NodeGroup;
04568    
04569    /* Now put the nodes in the path */
04570    ROIfill->N_n = N_Visited;
04571    ROIfill->nPath = (int *)SUMA_calloc (ROIfill->N_n, sizeof(int));
04572    if (!ROIfill->nPath) {
04573       SUMA_S_Err("Could not allocate for nPath.\n");
04574       if (Visited) SUMA_free(Visited);
04575       SUMA_RETURN(NULL);
04576    }
04577    
04578    N_Visited = 0;
04579    for (i=0; i<SO->N_Node; ++i) {
04580       if (Visited[i]) {
04581          ROIfill->nPath[N_Visited] = i;
04582          ++N_Visited;
04583       }
04584    }
04585    
04586    if (Visited) SUMA_free(Visited);
04587    SUMA_RETURN(ROIfill);
04588 }
04589 
04590 
04591 /*! 
04592    \brief function to turn a set of nodes into a DrawnROI
04593    
04594    \param Node (int *) pointer to set of nodes forming ROI
04595                Redundant nodes are removed. Nodes are copied
04596                to new location so you can free this pointer
04597                if you wish.
04598    \param N_Node (int) number of nodes in ROI
04599    \param Value (int) to go in ROI->iLabel
04600    \param Parent_idcode_str (char *) to get copied into 
04601          ROI->Parent_idcode_str
04602    \param Label (char *) to get copied into ROI->Label
04603    \param ColPlaneName (char *) to get copied into ROI->ColPlaneName 
04604    \param FillColor (float[3])
04605    \param EdgeColor (float[3])
04606    \param EdgeThickness (int)
04607    \param ForDisplay (SUMA_Boolean) YUP: Prepare ROI for display
04608                                     (creates the contour for the ROI,
04609                                     requires that Parent surface object be loaded)
04610    \return ROI (SUMA_DRAWN_ROI *)
04611    
04612    - No DO/Undos possible in this format
04613 */
04614 
04615 SUMA_DRAWN_ROI * SUMA_1DROI_to_DrawnROI ( int *Node, int N_Node, int Value, char *Parent_idcode_str, 
04616                                           char *Label, char *ColPlaneName, 
04617                                           float *FillColor, float *EdgeColor, int EdgeThickness, 
04618                                           SUMA_DO *dov, int N_dov, SUMA_Boolean ForDisplay)
04619 {
04620    static char FuncName[]={"SUMA_1DROI_to_DrawnROI"};
04621    SUMA_ROI_DATUM *ROI_Datum = NULL;
04622    SUMA_DRAWN_ROI *ROI = NULL;
04623    SUMA_Boolean LocalHead = NOPE;
04624    
04625    SUMA_ENTRY;
04626    
04627    if (!Node) SUMA_RETURN(NULL);
04628    
04629    /* allocate and initialize */
04630    ROI = SUMA_AllocateDrawnROI (Parent_idcode_str, SUMA_ROI_Finished,
04631                                SUMA_ROI_Collection,  Label,  Value);
04632    
04633    /* add the colors */
04634    SUMA_COPY_VEC(EdgeColor, ROI->EdgeColor, 3, float, float);
04635    SUMA_COPY_VEC(FillColor, ROI->FillColor, 3, float, float);
04636    ROI->EdgeThickness = EdgeThickness;
04637    
04638    /* fill in the only ROI datum */
04639    ROI_Datum = SUMA_AllocROIDatum ();
04640    ROI_Datum->action = SUMA_BSA_Undefined;
04641    if(LocalHead) fprintf (SUMA_STDERR,"%s: About to add %d nodes of value %d...\n", FuncName, N_Node, Value);
04642    
04643    ROI_Datum->nPath = SUMA_UniqueInt(Node, N_Node, &ROI_Datum->N_n, NOPE);
04644    if (!ROI_Datum->nPath) {
04645       SUMA_SLP_Crit("Failed to allocate");
04646       SUMA_RETURN(NOPE);
04647    }
04648    ROI_Datum->Type = SUMA_ROI_NodeGroup;
04649    
04650    SUMA_LH("Appending stroke");
04651    /* just append that baby */
04652    dlist_ins_next(ROI->ROIstrokelist, dlist_tail(ROI->ROIstrokelist), (void *)ROI_Datum);
04653    
04654    if (ForDisplay) {
04655       /* You must find the contour by yourself. This is normally
04656       done when the status is set to SUMA_ROI_Finished via the 
04657       action stack functions */
04658       { 
04659          int *cNodes, N_cNodes;
04660          SUMA_Boolean Unique = NOPE;
04661 
04662          SUMA_LH("Getting Contour ");
04663          N_cNodes = 0;
04664          Unique = NOPE; /* Set to YUP if you have node indices listed more than once. 
04665                            1D ROIs are uniquized in the reading functions*/
04666          cNodes = SUMA_NodesInROI (ROI, &N_cNodes, Unique);
04667          if (cNodes) {
04668             ROI->CE = SUMA_GetContour (
04669                            SUMA_findSOp_inDOv(ROI->Parent_idcode_str, dov, N_dov), 
04670                            cNodes, N_cNodes, &(ROI->N_CE), 0, NULL);
04671             if (!ROI->CE) { SUMA_LH("Null DrawnROI->CE"); }
04672             else { SUMA_LH("Good DrawnROI->CE"); }
04673             SUMA_free(cNodes);
04674          }
04675       }
04676    }
04677    SUMA_RETURN(ROI);
04678 }
 

Powered by Plone

This site conforms to the following standards: