1 
2 /*----------------------------------------------------------------------
3  * history:
4  *
5  * 11 Dec 2003  [rickr]
6  *   - added functions:
7  *       o  SUMA_spec_select_surfs	- restrict spec struct from name list
8  *       o  SUMA_swap_spec_entries	- swap 2 entries in spec struct
9  *       o  SUMA_unique_name_ind	- verify unique surf name in spec
10  *       o  SUMA_coord_file		- get file name, based on surf type
11  *       o  swap_strings		- swap 2 strings via 3rd
12  *----------------------------------------------------------------------
13 */
14 
15 /* Header FILES */
16 
17 #include "SUMA_suma.h"
18 
19 
20 /*#define  DO_SCALE_RANGE   *//*!< scale node coordinates to 0 <--> 100. DO NOT USE IT, OBSOLETE*/
21 #ifndef DO_SCALE_RANGE
22    #define DO_SCALE 319.7   /*!< scale node coordinates by specified factor. Useful for tesscon coordinate system in iv files*/
23 #endif
24 
25 /* CODE */
26 
27 /*!
28   SUMA_AllocSpecFields (SUMA_SurfSpecFile *Spec)
29  \brief Function to allocate space for the spec file fields.
30  Clumsy but does the work, needed to get around stack size limits of 8 Mb
31  \sa  SUMA_FreeSpecFields
32 */
SUMA_AllocSpecFields(SUMA_SurfSpecFile * Spec)33 SUMA_Boolean SUMA_AllocSpecFields (SUMA_SurfSpecFile *Spec)
34 {
35    static char FuncName[]={"SUMA_AllocSpecFields"};
36    SUMA_Boolean LocalHead = NOPE;
37 
38    SUMA_ENTRY;
39 
40 
41    if (!Spec) SUMA_RETURN(NOPE);
42 
43    Spec->N_Surfs = -1;    /* flag for initialization */
44    Spec->N_States = 0;
45    Spec->N_Groups = 0;
46 
47    Spec->SurfaceType = (char **)SUMA_allocate2D(SUMA_MAX_N_SURFACE_SPEC ,
48                               SUMA_MAX_LABEL_LENGTH, sizeof(char));
49    if (!Spec->SurfaceType) {
50       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
51    }
52    Spec->SurfaceFormat = (char **)SUMA_allocate2D(SUMA_MAX_N_SURFACE_SPEC,
53                               SUMA_MAX_LABEL_LENGTH , sizeof(char));
54    if (!Spec->SurfaceFormat) {
55       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
56    }
57    Spec->TopoFile = (char **)SUMA_allocate2D(SUMA_MAX_N_SURFACE_SPEC,
58                                     SUMA_MAX_FP_NAME_LENGTH , sizeof(char));
59    if (!Spec->TopoFile) {
60       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
61    }
62    Spec->CoordFile = (char **)SUMA_allocate2D(SUMA_MAX_N_SURFACE_SPEC,
63                         SUMA_MAX_FP_NAME_LENGTH , sizeof(char));
64    if (!Spec->CoordFile) {
65       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
66    }
67    Spec->MappingRef = (char **)SUMA_allocate2D(SUMA_MAX_N_SURFACE_SPEC,
68                         SUMA_MAX_FP_NAME_LENGTH , sizeof(char));
69    if (!Spec->MappingRef) {
70       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
71    }
72    Spec->SureFitVolParam = (char **)SUMA_allocate2D(SUMA_MAX_N_SURFACE_SPEC,
73                         SUMA_MAX_FP_NAME_LENGTH , sizeof(char));
74    if (!Spec->SureFitVolParam) {
75       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
76    }
77    Spec->SurfaceFile = (char **)SUMA_allocate2D(SUMA_MAX_N_SURFACE_SPEC,
78                         SUMA_MAX_FP_NAME_LENGTH , sizeof(char));
79    if (!Spec->SurfaceFile) {
80       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
81    }
82    Spec->VolParName = (char **)SUMA_allocate2D(SUMA_MAX_N_SURFACE_SPEC,
83                         SUMA_MAX_FP_NAME_LENGTH , sizeof(char));
84    if (!Spec->VolParName) {
85       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
86    }
87    Spec->IDcode = (char **)SUMA_calloc(SUMA_MAX_N_SURFACE_SPEC, sizeof(char*));
88    if (!Spec->IDcode) {
89       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
90    }
91    Spec->State = (char **)SUMA_allocate2D(SUMA_MAX_N_SURFACE_SPEC,
92                               SUMA_MAX_LABEL_LENGTH, sizeof(char));
93    if (!Spec->State) {
94       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
95    }
96    Spec->Group = (char **)SUMA_allocate2D(SUMA_MAX_N_SURFACE_SPEC,
97                               SUMA_MAX_LABEL_LENGTH, sizeof(char));
98    if (!Spec->Group) {
99       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
100    }
101    Spec->SurfaceLabel = (char **)SUMA_allocate2D(SUMA_MAX_N_SURFACE_SPEC,
102                               SUMA_MAX_LABEL_LENGTH, sizeof(char));
103    if (!Spec->SurfaceLabel) {
104       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
105    }
106    Spec->EmbedDim = (int *)SUMA_calloc(SUMA_MAX_N_SURFACE_SPEC, sizeof(int));
107    if (!Spec->EmbedDim) {
108       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
109    }
110 
111    /* modifications to the lame MappingRef field */
112    Spec->AnatCorrect = (char **)SUMA_allocate2D(SUMA_MAX_N_SURFACE_SPEC,
113                               SUMA_MAX_LABEL_LENGTH, sizeof(char));
114    if (!Spec->AnatCorrect) {
115       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
116    }
117    Spec->Hemisphere = (char **)SUMA_allocate2D(SUMA_MAX_N_SURFACE_SPEC,
118                               SUMA_MAX_LABEL_LENGTH, sizeof(char));
119    if (!Spec->Hemisphere) {
120       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
121    }
122    Spec->DomainGrandParentID = (char **)SUMA_allocate2D(SUMA_MAX_N_SURFACE_SPEC,
123                               SUMA_MAX_LABEL_LENGTH, sizeof(char));
124    if (!Spec->DomainGrandParentID) {
125       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
126    }
127    Spec->OriginatorID = (char **)SUMA_allocate2D(SUMA_MAX_N_SURFACE_SPEC,
128                               SUMA_MAX_LABEL_LENGTH, sizeof(char));
129    if (!Spec->OriginatorID) {
130       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
131    }
132    Spec->LocalCurvatureParent = (char **)SUMA_allocate2D(SUMA_MAX_N_SURFACE_SPEC,
133                         SUMA_MAX_FP_NAME_LENGTH , sizeof(char));
134    if (!Spec->LocalCurvatureParent) {
135       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
136    }
137    Spec->LocalDomainParent = (char **)SUMA_allocate2D(SUMA_MAX_N_SURFACE_SPEC,
138                         SUMA_MAX_FP_NAME_LENGTH , sizeof(char));
139    if (!Spec->LocalDomainParent) {
140       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
141    }
142    Spec->LabelDset = (char **)SUMA_allocate2D(SUMA_MAX_N_SURFACE_SPEC,
143                         SUMA_MAX_FP_NAME_LENGTH , sizeof(char));
144    if (!Spec->LabelDset) {
145       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
146    }
147    Spec->NodeMarker = (char **)SUMA_allocate2D(SUMA_MAX_N_SURFACE_SPEC,
148                         SUMA_MAX_FP_NAME_LENGTH , sizeof(char));
149    if (!Spec->NodeMarker) {
150       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
151    }
152 
153    Spec->DO_name = (char **)SUMA_allocate2D(SUMA_MAX_N_DO_SPEC,
154                                  SUMA_MAX_FP_NAME_LENGTH , sizeof(char));
155    Spec->DO_type = (int *)SUMA_calloc(SUMA_MAX_N_DO_SPEC, sizeof(int));
156    Spec->N_DO = 0;
157 
158    Spec->StateList = (char *)SUMA_calloc( SUMA_MAX_N_SURFACE_SPEC*100,
159                                           sizeof(char));
160    if (!Spec->StateList) {
161       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
162    }
163    Spec->SpecFilePath = (char *)SUMA_calloc(SUMA_MAX_DIR_LENGTH, sizeof(char));
164    if (!Spec->SpecFilePath) {
165       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
166    }
167    Spec->SpecFileName = (char *)SUMA_calloc(SUMA_MAX_NAME_LENGTH, sizeof(char));
168    if (!Spec->SpecFileName) {
169       SUMA_S_Err("Failed to allocate"); SUMA_RETURN(NOPE);
170    }
171 
172    SUMA_RETURN(YUP);
173 }
174 
175 
SUMA_FreeSpecFields(SUMA_SurfSpecFile * Spec)176 SUMA_Boolean SUMA_FreeSpecFields (SUMA_SurfSpecFile *Spec)
177 {
178    static char FuncName[]={"SUMA_FreeSpecFields"};
179 
180    SUMA_ENTRY;
181 
182    if (!Spec) SUMA_RETURN(YUP);
183    if ( (Spec->N_Surfs < 0 && Spec->N_Surfs != -1) ||
184          Spec->N_Surfs > SUMA_MAX_N_SURFACE_SPEC ) {
185       SUMA_S_Err("Suspicious values in Spec->N_Surfs, will not free fields");
186       SUMA_RETURN(NOPE);
187    }
188    if (Spec->SurfaceType) {
189       SUMA_free2D((char **)Spec->SurfaceType, SUMA_MAX_N_SURFACE_SPEC);
190       Spec->SurfaceType = NULL; }
191    if (Spec->SurfaceFormat) {
192       SUMA_free2D((char **)Spec->SurfaceFormat, SUMA_MAX_N_SURFACE_SPEC);
193       Spec->SurfaceFormat = NULL; }
194    if (Spec->TopoFile) {
195       SUMA_free2D((char **)Spec->TopoFile, SUMA_MAX_N_SURFACE_SPEC);
196       Spec->TopoFile = NULL; }
197    if (Spec->CoordFile) {
198       SUMA_free2D((char **)Spec->CoordFile, SUMA_MAX_N_SURFACE_SPEC);
199       Spec->CoordFile = NULL; }
200    if (Spec->MappingRef) {
201       SUMA_free2D((char **)Spec->MappingRef, SUMA_MAX_N_SURFACE_SPEC);
202       Spec->MappingRef = NULL; }
203    if (Spec->SureFitVolParam) {
204       SUMA_free2D((char **)Spec->SureFitVolParam, SUMA_MAX_N_SURFACE_SPEC);
205       Spec->SureFitVolParam = NULL; }
206 
207    if (Spec->SurfaceFile) {
208       SUMA_free2D((char **)Spec->SurfaceFile, SUMA_MAX_N_SURFACE_SPEC);
209       Spec->SurfaceFile = NULL; }
210 
211    if (Spec->DO_name) {
212       SUMA_free2D((char **)Spec->DO_name, SUMA_MAX_N_DO_SPEC);
213       Spec->DO_name = NULL; }
214    if (Spec->DO_type) SUMA_free(Spec->DO_type); Spec->DO_type=NULL;
215    Spec->N_DO = 0;
216 
217    if (Spec->VolParName) {
218       SUMA_free2D((char **)Spec->VolParName, SUMA_MAX_N_SURFACE_SPEC);
219       Spec->VolParName = NULL; }
220    if (Spec->IDcode) { SUMA_free(Spec->IDcode);
221       Spec->IDcode = NULL; /* IDcode[i] = is a pointer copy */}
222    if (Spec->State) {
223       SUMA_free2D((char **)Spec->State, SUMA_MAX_N_SURFACE_SPEC);
224       Spec->State = NULL; }
225 
226    if (Spec->Group) {
227       SUMA_free2D((char **)Spec->Group, SUMA_MAX_N_SURFACE_SPEC);
228       Spec->Group= NULL; }
229 
230    if (Spec->SurfaceLabel) {
231       SUMA_free2D((char **)Spec->SurfaceLabel, SUMA_MAX_N_SURFACE_SPEC);
232       Spec->SurfaceLabel = NULL; }
233 
234    if (Spec->EmbedDim) { SUMA_free(Spec->EmbedDim);
235       Spec->EmbedDim = NULL; }
236 
237    /* modifications to the lame MappingRef field */
238    if (Spec->AnatCorrect) {
239       SUMA_free2D((char **)Spec->AnatCorrect, SUMA_MAX_N_SURFACE_SPEC);
240       Spec->AnatCorrect = NULL; }
241 
242    if (Spec->Hemisphere) {
243       SUMA_free2D((char **)Spec->Hemisphere, SUMA_MAX_N_SURFACE_SPEC);
244       Spec->Hemisphere = NULL; }
245 
246    if (Spec->DomainGrandParentID) {
247       SUMA_free2D((char **)Spec->DomainGrandParentID, SUMA_MAX_N_SURFACE_SPEC);
248       Spec->DomainGrandParentID = NULL; }
249 
250    if (Spec->OriginatorID) {
251       SUMA_free2D((char **)Spec->OriginatorID, SUMA_MAX_N_SURFACE_SPEC);
252       Spec->OriginatorID = NULL; }
253 
254    if (Spec->LocalCurvatureParent) {
255       SUMA_free2D((char **)Spec->LocalCurvatureParent, SUMA_MAX_N_SURFACE_SPEC);
256       Spec->LocalCurvatureParent = NULL; }
257 
258    if (Spec->LocalDomainParent) {
259       SUMA_free2D((char **)Spec->LocalDomainParent, SUMA_MAX_N_SURFACE_SPEC);
260       Spec->LocalDomainParent = NULL; }
261 
262    if (Spec->LabelDset) {
263       SUMA_free2D((char **)Spec->LabelDset, SUMA_MAX_N_SURFACE_SPEC);
264       Spec->LabelDset = NULL; }
265 
266    if (Spec->NodeMarker) {
267       SUMA_free2D((char **)Spec->NodeMarker, SUMA_MAX_N_SURFACE_SPEC);
268       Spec->NodeMarker = NULL; }
269 
270    Spec->N_Surfs = -2; /* flag for freeing */
271    Spec->N_States = 0;
272    Spec->N_Groups = 0;
273 
274 
275    if (Spec->StateList) { SUMA_free(Spec->StateList);
276       Spec->StateList = NULL; }
277    if (Spec->SpecFilePath) { SUMA_free(Spec->SpecFilePath);
278       Spec->SpecFilePath = NULL; }
279    if (Spec->SpecFileName) { SUMA_free(Spec->SpecFileName);
280       Spec->SpecFileName = NULL; }
281 
282    SUMA_RETURN(YUP);
283 }
284 
285 /*!
286    \brief Function to write surface objects to disk in various formats
287    ans = SUMA_Save_Surface_Object (void * F_name, SUMA_SurfaceObject *SO, SUMA_SO_File_Type SO_FT,
288                               SUMA_SO_File_Format SO_FF, void *someparam);
289    \param F_name (void *)
290          For SUMA_INVENTOR_GENERIC F_name is (char *) containing path (if any) and filename of surface
291          For SUMA_SUREFIT F_name is (SUMA_SFname *) containing full topo and coord names, with path (if any)
292          For SUMA_FREE_SURFER F_name is  (char *) name of .asc file (with path)
293          For SUMA_VEC (a dumb ascii format), F_name is (SUMA_SFname *) containing the nodelist file in name_coord
294           and facesetlist file in name_topo (path included).
295          For SUMA_PLY (char *) name of .ply file (with path)
296          For SUMA_OPENDX_MESH (char *) name of .dx file (with path)
297    \param   SO_FT (SUMA_SO_File_Type) file type to be read (inventor, free surfer , Surefit )
298    \param   SO_FF (SUMA_SO_File_Format) Ascii or Binary (only ascii at the moment, except for .ply files)
299    \param someparam (void *) a pointer used to pass extra parameters. At the moment, used for passing a parent
300                            surface when writing FreeSurferPatches
301    \sa SUMA_Load_Surface_Object()
302 
303    NOTE:
304    Vertex coordinates are written as in SO->NodeList
305    The Volume Parent transformation is not undone.
306    For SureFit surfaces, the volume param shift is not undone.
307 */
SUMA_Save_Surface_Object_Wrap(char * surf_name,char * topo_name,SUMA_SurfaceObject * SO,SUMA_SO_File_Type SO_FT,SUMA_SO_File_Format SO_FF,void * someparam)308 void * SUMA_Save_Surface_Object_Wrap (
309                         char *surf_name, char *topo_name,
310                         SUMA_SurfaceObject *SO,
311                         SUMA_SO_File_Type SO_FT, SUMA_SO_File_Format SO_FF,
312                         void *someparam)
313 {
314    static char FuncName[]={"SUMA_Save_Surface_Object_Wrap"};
315    void *SO_name=NULL;
316    SUMA_Boolean exists;
317 
318    SUMA_ENTRY;
319 
320    if (!surf_name || !SO) {
321       SUMA_S_Err("NULL input"); SUMA_RETURN(NULL);
322    }
323 
324    if (SO_FT == SUMA_FT_NOT_SPECIFIED) {
325       SO_FT = SUMA_GuessSurfFormatFromExtension(surf_name, "usegifti.gii");
326    }
327 
328    if (!(SO_name = SUMA_2Prefix2SurfaceName (surf_name, topo_name,
329                                              NULL, NULL, SO_FT, &exists))) {
330       SUMA_S_Err("Failed to form SO_name");
331       SUMA_RETURN(NULL);
332    }
333    if (!SUMA_Save_Surface_Object (SO_name, SO, SO_FT, SO_FF, someparam)) {
334       SUMA_S_Err("Failed to save surface");
335       SUMA_RETURN(NULL);
336    }
337 
338    SUMA_RETURN(SO_name);
339 }
340 
SUMA_Save_Surface_Object(void * F_name,SUMA_SurfaceObject * SO,SUMA_SO_File_Type SO_FT,SUMA_SO_File_Format SO_FF,void * someparam)341 SUMA_Boolean SUMA_Save_Surface_Object (void * F_name, SUMA_SurfaceObject *SO,
342                                        SUMA_SO_File_Type SO_FT,
343                                        SUMA_SO_File_Format SO_FF,
344                                        void *someparam)
345 {/*SUMA_Save_Surface_Object*/
346    static char FuncName[]={"SUMA_Save_Surface_Object"};
347 
348    SUMA_ENTRY;
349 
350    if (!F_name) {
351       SUMA_S_Err("Null filename!");
352       SUMA_RETURN(NOPE);
353    }
354    switch (SO_FT) {
355       case SUMA_OBJ_MESH:
356          SUMA_S_Err("Nothing for OBJ_MESH yet");
357          SUMA_RETURN(NOPE);
358          break;
359       case SUMA_OPENDX_MESH:
360          if (!SUMA_OpenDX_Write ((char *)F_name, SO)) {
361             fprintf (SUMA_STDERR,
362                      "Error %s: Failed to write SUMA_OPENDX_MESH surface.\n"
363                      , FuncName);
364             SUMA_RETURN (NOPE);
365          }
366          break;
367       case SUMA_PLY:
368          if (!SUMA_Ply_Write ((char *)F_name, SO)) {
369             fprintf (SUMA_STDERR,
370                      "Error %s: Failed to write PLY surface.\n"
371                      , FuncName);
372             SUMA_RETURN (NOPE);
373          }
374          break;
375       case SUMA_STL:
376          if (!SUMA_STL_Write ((char *)F_name, SO)) {
377             fprintf (SUMA_STDERR,
378                      "Error %s: Failed to write STL surface.\n"
379                      , FuncName);
380             SUMA_RETURN (NOPE);
381          }
382          break;
383       case SUMA_MNI_OBJ:
384          if (!SUMA_MNI_OBJ_Write ((char *)F_name, SO)) {
385             fprintf (SUMA_STDERR,
386                      "Error %s: Failed to write MNI_OBJ surface.\n"
387                      , FuncName);
388             SUMA_RETURN (NOPE);
389          }
390          break;
391       case SUMA_FREE_SURFER:
392          if (SO_FF == SUMA_FF_NOT_SPECIFIED) SO_FF = SUMA_ASCII;
393          if (SO_FF != SUMA_ASCII) {
394             fprintf (SUMA_STDERR,
395                      "Warning %s: "
396                      "Only ASCII supported for Free Surfer surfaces.\n"
397                      , FuncName);
398          }
399          if (!SUMA_FS_Write ((char *)F_name, SO,
400                               "!ascii version in FreeSurfer format (SUMA)")) {
401             fprintf (SUMA_STDERR,
402                      "Error %s: Failed to write FreeSurfer surface.\n"
403                      , FuncName);
404             SUMA_RETURN (NOPE);
405          }
406          break;
407       case SUMA_FREE_SURFER_PATCH:
408          if (SO_FF == SUMA_FF_NOT_SPECIFIED) SO_FF = SUMA_ASCII;
409          if (SO_FF != SUMA_ASCII) {
410             fprintf (SUMA_STDERR,
411                      "Warning %s: "
412                      "Only ASCII supported for Free Surfer surface patches.\n"
413                      , FuncName);
414          }
415          if (!SUMA_FreeSurfer_WritePatch ((char *)F_name, SO, NULL,
416                                           (SUMA_SurfaceObject *)someparam)) {
417             fprintf (SUMA_STDERR,
418                      "Error %s: Failed to write FreeSurfer surface.\n"
419                      , FuncName);
420             SUMA_RETURN (NOPE);
421          }
422          break;
423       case SUMA_SUREFIT:
424          if (SO_FF == SUMA_FF_NOT_SPECIFIED) SO_FF = SUMA_ASCII;
425          if (SO_FF != SUMA_ASCII) {
426             fprintf (SUMA_STDERR,
427                      "Warning %s: Only ASCII supported for SureFit surfaces.\n"
428                      , FuncName);
429          }
430          if (!SUMA_SureFit_Write ((SUMA_SFname *)F_name, SO)) {
431             fprintf (SUMA_STDERR,
432                      "Error %s: Failed to write SureFit surface.\n"
433                      , FuncName);
434             SUMA_RETURN (NOPE);
435          }
436          break;
437       case SUMA_VEC:
438          if (SO_FF == SUMA_FF_NOT_SPECIFIED) SO_FF = SUMA_ASCII;
439          if (SO_FF != SUMA_ASCII) {
440             fprintf (SUMA_STDERR,
441                      "Warning %s: Only ASCII supported for vec surfaces.\n"
442                      , FuncName);
443          }
444          if (!SUMA_VEC_Write ((SUMA_SFname *)F_name, SO)) {
445             fprintf (SUMA_STDERR,
446                      "Error %s: Failed to write vec surface.\n"
447                      , FuncName);
448             SUMA_RETURN (NOPE);
449          }
450          break;
451       case SUMA_BYU:
452          if (SO_FF == SUMA_FF_NOT_SPECIFIED) SO_FF = SUMA_ASCII;
453          if (SO_FF != SUMA_ASCII) {
454             fprintf (SUMA_STDERR,
455                      "Warning %s: Only ASCII supported for BYU surfaces.\n"
456                      , FuncName);
457          }
458          if (!SUMA_BYU_Write ((char *)F_name, SO, 1)) {
459             fprintf (SUMA_STDERR,
460                      "Error %s: Failed to write BYU surface.\n"
461                      , FuncName);
462             SUMA_RETURN (NOPE);
463          }
464          break;
465       case SUMA_INVENTOR_GENERIC:
466          fprintf (SUMA_STDERR,
467                   "Error %s: "
468                   "Not ready to deal with inventor surface writing.\n"
469                   , FuncName);
470          SUMA_RETURN (NOPE);
471          break;
472       case SUMA_BRAIN_VOYAGER:
473          fprintf (SUMA_STDERR,
474                   "Error %s: "
475                   "Not ready to deal with brain voyager surface writing.\n"
476                   , FuncName);
477          SUMA_RETURN (NOPE);
478          break;
479       case SUMA_GIFTI:
480          if (!SUMA_GIFTI_Write ((char *)F_name, SO, SO_FF)) {
481             fprintf (SUMA_STDERR,
482                      "Error %s: Failed to write GIFTI surface.\n"
483                      , FuncName);
484             SUMA_RETURN (NOPE);
485          }
486          break;
487       case SUMA_PREDEFINED:
488          if (!SUMA_GIFTI_Write ((char *)F_name, SO, SUMA_ASCII)) {
489             fprintf (SUMA_STDERR,
490                      "Error %s: Failed to write predefined GIFTI surface.\n"
491                      , FuncName);
492             SUMA_RETURN (NOPE);
493          }
494          break;
495       case SUMA_FT_NOT_SPECIFIED:
496       default:
497          fprintf (SUMA_STDERR, "Error %s: Bad surface type.\n", FuncName);
498          SUMA_RETURN (NOPE);
499 
500    }
501 
502    SUMA_RETURN (YUP);
503 }
504 
505 /*!
506    \brief for a new SO, calculate the following:
507    Normals, dimensions, SUMA's NodeMarker FaceSetMarker, etc.
508 */
SUMA_PrepSO_GeomProp_GL(SUMA_SurfaceObject * SO)509 SUMA_Boolean SUMA_PrepSO_GeomProp_GL(SUMA_SurfaceObject *SO)
510 {
511    static char FuncName[]={"SUMA_PrepSO_GeomProp_GL"};
512    static int iwarn=0;
513    int k, ND, id;
514    SUMA_SURF_NORM SN;
515    byte *PatchNodeMask=NULL;
516    SUMA_SurfaceViewer *sv=NULL;
517    SUMA_Boolean LocalHead = NOPE;
518 
519    SUMA_ENTRY;
520 
521    SUMA_LHv("Unleashed on surface %s\n", CHECK_NULL_STR(SO->Label));
522 
523    /* Calculate Min, Max, Mean */
524 
525    if (!SUMA_isSODimInitialized(SO)) {
526       if (!SUMA_SetSODims(SO)) {
527          SUMA_S_Err("Failed to set dims!");
528          SUMA_RETURN(NOPE);
529       }
530    } else {
531       SUMA_LH("SODim initialized already");
532    }
533 
534    /* calculate the center and dimensions for the nodes in the patch only */
535    PatchNodeMask = SUMA_MaskOfNodesInPatch(SO, &(SO->N_patchNode));
536    if (!SO->N_patchNode || SO->N_patchNode == SO->N_Node) {
537       SUMA_LHv("Up here, isSphere = %d\n", SO->isSphere);
538       if (!PatchNodeMask ) {
539          SUMA_SL_Err("Failed in SUMA_MaskOfNodesInPatch.\n"
540                      "Using values from all nodes.");
541       } else {
542          SUMA_LH("Using values from all nodes.");
543       }
544       if (!SUMA_IS_GEOM_SYMM(SO->isSphere)) {
545          SUMA_COPY_VEC(SO->Center, SO->patchCenter, 3, float, float);
546       } else {
547          SUMA_COPY_VEC(SO->SphereCenter, SO->patchCenter, 3, float, float);
548       }
549       SUMA_COPY_VEC(SO->MinDims, SO->patchMinDims, 3, float, float);
550       SUMA_COPY_VEC(SO->MaxDims, SO->patchMaxDims, 3, float, float);
551       SO->patchaMaxDims = SO->aMaxDims;
552       SO->patchaMinDims = SO->aMinDims;
553    }else {
554       SUMA_LH("Down there");
555       SUMA_MIN_MAX_SUM_VECMAT_MASK_COL (
556                   SO->NodeList, SO->N_Node,
557                   SO->NodeDim, PatchNodeMask,
558                   SO->patchMinDims, SO->patchMaxDims,
559                   SO->patchCenter);
560       SO->patchCenter[0] /= SO->N_patchNode;
561       SO->patchCenter[1] /= SO->N_patchNode;
562       SO->patchCenter[2] /= SO->N_patchNode;
563       SUMA_MIN_VEC (SO->patchMinDims, 3, SO->patchaMinDims );
564       SUMA_MAX_VEC (SO->patchMaxDims, 3, SO->patchaMaxDims);
565    }
566 
567    if (SO->patchNodeMask) {
568       SUMA_S_Err( "Hmm, unexpected."
569           "This function is usually called once per surface, "
570           "it is OK to call it more than once, but be sure it is necessary"
571           "before you turn this error message off");
572       SUMA_free(SO->patchNodeMask);
573    }
574    SO->patchNodeMask = NULL;
575 
576    if (PatchNodeMask) {
577       if (SO->N_patchNode != SO->N_Node) {
578          SO->patchNodeMask =   PatchNodeMask; PatchNodeMask = NULL;
579       } else {
580          SUMA_free(PatchNodeMask) ; PatchNodeMask = NULL;
581       }
582    }
583    #ifdef DO_SCALE_RANGE
584    SUMA_LH("In scale range");
585    { float tmpfact;
586    /* Now do some scaling */
587    tmpfact = (SO->aMaxDims - SO->aMinDims)/100;
588    ND = SO->NodeDim;
589    for (k=0; k < SO->N_Node; k++)
590    {
591       id = NodeDim * k;
592       SO->NodeList[k] = (SO->NodeList[k] - SO->aMinDims)/tmpfact;
593       SO->NodeList[k+1] = (SO->NodeList[k+1] - SO->aMinDims)/tmpfact;
594       SO->NodeList[k+2] = (SO->NodeList[k+2] - SO->aMinDims)/tmpfact;
595    }
596 
597    SO->Center[0] = (SO->Center[0] - SO->aMinDims)/tmpfact;
598    SO->Center[1] = (SO->Center[1] - SO->aMinDims)/tmpfact;
599    SO->Center[2] = (SO->Center[2] - SO->aMinDims)/tmpfact;
600 
601    SO->MinDims[0] = (SO->MinDims[0] - SO->aMinDims)/tmpfact;
602    SO->MinDims[1] = (SO->MinDims[1] - SO->aMinDims)/tmpfact;
603    SO->MinDims[2] = (SO->MinDims[2] - SO->aMinDims)/tmpfact;
604 
605    SO->MaxDims[0] = (SO->MaxDims[0] - SO->aMinDims)/tmpfact;
606    SO->MaxDims[1] = (SO->MaxDims[1] - SO->aMinDims)/tmpfact;
607    SO->MaxDims[2] = (SO->MaxDims[2] - SO->aMinDims)/tmpfact;
608 
609    SO->aMinDims = 0.0;
610    SO->aMaxDims = 100.0;
611    }
612    #endif
613    #ifdef DO_SCALE
614 
615    /* Now do some scaling */
616    SUMA_LH("In scale section");
617    if ( (SO->aMaxDims - SO->aMinDims) > SUMA_TESSCON_DIFF_FLAG) {
618       if (AFNI_yesenv("SUMA_TESSCON_AutoScale")) {
619          fprintf (stdout,  "\n"
620                            "\n"
621                            "WARNING %s:\n"
622                            " Assuming surface to be in tesscon units,\n"
623                            " scaling down by %f.\n"
624                            "\aYou might have abnormally large or small \n"
625                            "freakish vertex coordinates.\n"
626                            "Max/Min Dims = %f/%f\n"
627                            "\n",
628             FuncName, SUMA_TESSCON_TO_MM,
629             SO->aMaxDims, SO->aMinDims);
630          ND = SO->NodeDim;
631          for (k=0; k < SO->N_Node; k++)
632          {
633             id = ND * k;
634             SO->NodeList[id] /= SUMA_TESSCON_TO_MM;
635             SO->NodeList[id+1] /= SUMA_TESSCON_TO_MM;
636             SO->NodeList[id+2] /= SUMA_TESSCON_TO_MM;
637          }
638 
639          SO->Center[0] /= SUMA_TESSCON_TO_MM;
640          SO->Center[1] /= SUMA_TESSCON_TO_MM;
641          SO->Center[2] /= SUMA_TESSCON_TO_MM;
642 
643          SO->MinDims[0] /= SUMA_TESSCON_TO_MM;
644          SO->MinDims[1] /= SUMA_TESSCON_TO_MM;
645          SO->MinDims[2] /= SUMA_TESSCON_TO_MM;
646 
647          SO->MaxDims[0] /= SUMA_TESSCON_TO_MM;
648          SO->MaxDims[1] /= SUMA_TESSCON_TO_MM;
649          SO->MaxDims[2] /= SUMA_TESSCON_TO_MM;
650 
651          SO->aMinDims /= SUMA_TESSCON_TO_MM;
652          SO->aMaxDims /= SUMA_TESSCON_TO_MM;
653       } else {
654          SUMA_S_Note("Surface dim range a little strange.\n"
655                      "Make sure dimensions are OK.\n"
656                      "Max/Min Dims = %f/%f\n",
657                      SO->aMaxDims, SO->aMinDims);
658       }
659    }
660    #endif
661 
662    SUMA_LHv("Checking too small a surface: %f\n", SO->MaxCentDist);
663    /* check for too small a surface */
664    if (SO->MaxCentDist < 10.0 && !iwarn) {
665       if (!(sv = SUMA_BestViewerForADO((SUMA_ALL_DO *)SO))) sv = SUMAg_SVv;
666       if (sv) { /* This can be null when surfaces are created on the fly,
667                    No need to warn in that case though.*/
668            ;  /* took out actual warning - mostly nuisance - 10 Oct 2017 DRG */
669            if (!iwarn) ++iwarn;
670 /*         if (sv->GVS[sv->StdView].DimSclFac < 5 && !iwarn) {
671             ++iwarn;
672             SUMA_S_Note(
673                "Surface size is quite small, rendering errors might occur.\n"
674                "If your coordinate units are in cm, set SUMA_NodeCoordsUnits \n"
675                "In your ~/.sumarc to 'cm' instead of the default 'mm'\n"
676             "If you do not have a '~/.sumarc', just run 'suma -update_env'\n");
677          }*/
678       }
679    }
680    SUMA_LH("Computing normals");
681    /* Calculate SurfaceNormals */
682 
683    if (SO->NodeNormList && SO->FaceNormList) {
684       SUMA_LH("Node normals already computed, skipping...");
685    } else {
686       SN = SUMA_SurfNorm(  SO->NodeList,  SO->N_Node,
687                            SO->FaceSetList, SO->N_FaceSet );
688       SO->NodeNormList = SN.NodeNormList;
689       SO->FaceNormList = SN.FaceNormList;
690    }
691 
692    /*create the structures for GL rendering */
693    /*The data is being duplicated at the moment and perhaps
694       I should just stick with the 1D stuf */
695    if (sizeof(GLfloat) != sizeof(float)) {
696       SUMA_SL_Crit("GLfloat and float have differing sizes!\n");
697       SUMA_RETURN(NOPE); }
698 
699    if (sizeof(GLint) != sizeof(int)) {
700       SUMA_SL_Crit("GLint and int have differing sizes!\n");
701       SUMA_RETURN(NOPE); }
702 
703    SO->glar_NodeList = (GLfloat *) SO->NodeList; /* copy pointer, not data */
704    SO->glar_FaceSetList = (GLint *) SO->FaceSetList; /* copy pointer, not data */
705    SO->glar_FaceNormList = (GLfloat *) SO->FaceNormList; /* copy pointer */
706    SO->glar_NodeNormList = (GLfloat *) SO->NodeNormList; /* copy pointer */
707 
708    /* a surface object does contribute to the rotation
709       center of the viewer displaying it */
710    SO->RotationWeight = SO->N_Node;
711    SO->ViewCenterWeight = SO->N_Node;
712 
713    /* No selections yet, but make the preps */
714       SUMA_SV_SetShowSelectedDatum(sv, YUP, NOPE);
715       SUMA_SV_SetShowSelectedFaceSet(sv, YUP, NOPE);
716       SO->SelectedFaceSet = -1;
717       SO->SelectedNode = -1;
718       /* create the ball object*/
719       if (SO->NodeMarker) {
720          SUMA_LH("NodeMarker already present. Skipping");
721       } else {
722          SO->NodeMarker = SUMA_Alloc_SphereMarker ();
723       }
724       if (SO->NodeMarker == NULL) {
725          fprintf( SUMA_STDERR,
726                   "Error%s: Could not allocate for SO->NodeMarker\n", FuncName);
727          SUMA_Free_Surface_Object (SO);
728          SUMA_RETURN (NOPE);
729       }
730       /* create the FaceSetMarker object */
731       if (SO->FaceSetMarker) {
732          SUMA_LH("FaceSetMarker already present. Skipping");
733       } else {
734          SO->FaceSetMarker = SUMA_Alloc_FaceSetMarker();
735       }
736      if (SO->FaceSetMarker == NULL) {
737          fprintf( SUMA_STDERR,
738                   "Error%s: Could not allocate for SO->FaceSetMarker\n",
739                   FuncName);
740          SUMA_Free_Surface_Object (SO);
741          SUMA_RETURN (NOPE);
742       }
743 
744    /* find normal directions, if possible.
745       Do not do this here, normally, I can guess well and
746       if certain about orientation
747       for a particular format, set at surface reading level.
748       No need to do more computations */
749       /* if (SO->normdir == 0) SO->normdir = SUMA_SurfNormDir(SO); */
750 
751    SUMA_RETURN(YUP);
752 }
753 
754 
755 /*!
756    Call the function engine, with debug turned on.      20 Oct 2003 [rickr]
757 */
SUMA_Load_Surface_Object(void * SO_FileName_vp,SUMA_SO_File_Type SO_FT,SUMA_SO_File_Format SO_FF,char * VolParName)758 SUMA_SurfaceObject * SUMA_Load_Surface_Object (void *SO_FileName_vp, SUMA_SO_File_Type SO_FT, SUMA_SO_File_Format SO_FF, char *VolParName)
759 {/*SUMA_Load_Surface_Object*/
760    static char FuncName[]={"SUMA_Load_Surface_Object"};
761 
762    SUMA_ENTRY;
763 
764    SUMA_RETURN( SUMA_Load_Surface_Object_eng( SO_FileName_vp, SO_FT, SO_FF,
765                                               VolParName, 1) );
766 }/*SUMA_Load_Surface_Object*/
767 
768 
769 /* - appended _eng to engine function name             20 Oct 2003 [rickr]
770  * - added debug parmeter
771  * - only print non-error info when debug flag is set
772 */
773 /*!
774 \brief
775       SO = SUMA_Load_Surface_Object_eng ( SO_FileName, SO_FT, SO_FF, char *VolParName, int debug)
776 
777 
778 Input paramters :
779 \param   (void *) SO_FileName
780          For SUMA_INVENTOR_GENERIC SO_FileName is (char *) containing path (if any) and filename of surface
781          For SUMA_SUREFIT SO_FileName is (SUMA_SFname *) containing full topo and coord names, with path (if any)
782          For SUMA_FREE_SURFER SO_FileName is  (char *) name of .asc file (with path)
783          For SUMA_VEC (a dumb ascii format), SO_FileName is (SUMA_SFname *) containing the nodelist file in name_coord
784           and facesetlist file in name_topo (path included).
785          For SUMA_PLY (char *) name of .ply file (with path)
786          For SUMA_OPENDX_MESH (char *) name of .dx file (with path)
787 \param   SO_FT (SUMA_SO_File_Type) file type to be read (inventor, free surfer , Surefit )
788 \param   SO_FF (SUMA_SO_File_Format) Ascii or Binary (only ascii at the moment, except for .ply files)
789 \param   VolParName (char *) filename (+path) of parent volume, pass NULL for none
790          If you pass NULL, no transformation is applied to the coordinates read.
791 \param   debug (int) flag specifying whether to output surface object info
792 
793 \return   SO (SUMA_SurfaceObject *) Surface Object pointer
794    The following fields are set (or initialized):
795    SO->NodeDim
796    SO->FaceSetDim
797    SO->NodeList
798    SO->FaceSetList
799    SO->N_Node;
800    SO->N_FaceSet;
801    SO->Name;
802    SO->FileType;
803    SO->FileFormat
804    SO->idcode_str
805    SO->Center
806    SO->aMaxDims
807    SO->aMinDims
808    SO->NodeNormList
809    SO->FaceNormList
810    SO->glar_NodeList
811    SO->glar_FaceSetList
812    SO->glar_FaceNormList
813    SO->glar_NodeNormList
814    SO->RotationWeight
815    SO->ViewCenterWeight
816    SO->SelectedFaceSet
817    SO->SelectedNode
818    SO->NodeMarker
819    SO->FaceSetMarker
820    SO->VolPar
821    SO->SUMA_VolPar_Aligned
822 
823 \sa SUMA_IV*
824 \sa SUMA_Save_Surface_Object()
825 \sa SUMA_Align_to_VolPar()
826 
827 ***/
SUMA_Load_Surface_Object_eng(void * SO_FileName_vp,SUMA_SO_File_Type SO_FT,SUMA_SO_File_Format SO_FF,char * VolParName,int debug)828 SUMA_SurfaceObject * SUMA_Load_Surface_Object_eng (
829       void *SO_FileName_vp, SUMA_SO_File_Type SO_FT,
830       SUMA_SO_File_Format SO_FF, char *VolParName,
831       int debug)
832 {/*SUMA_Load_Surface_Object_eng*/
833    static char FuncName[]={"SUMA_Load_Surface_Object_eng"};
834    char stmp[1000], *SO_FileName=NULL;
835    SUMA_SFname *SF_FileName;
836    SUMA_SureFit_struct *SF;
837    SUMA_FreeSurfer_struct *FS;
838    SUMA_SO_File_Type gSO_FT;
839    char *tname=NULL, *psv=NULL, *pname=NULL;
840    int i1=0, par=0;
841    SUMA_SurfaceObject *SO;
842 
843    SUMA_Boolean LocalHead = NOPE;
844 
845    SUMA_ENTRY;
846 
847    /* Allocate and initialize SUMA_SurfaceObject Pointer */
848    SO = SUMA_Alloc_SurfObject_Struct(1);
849 
850    if (SO_FT == SUMA_SUREFIT || SO_FT == SUMA_VEC) {
851       tname = ((SUMA_SFname*)SO_FileName_vp)->name_coord;
852    } else {
853       tname = (char *)SO_FileName_vp;
854       /* A little ugly, but check if this is a template name */
855       i1 = SUMA_is_predefined_SO_name(tname, &par, NULL, &psv, &pname);
856       if (i1 ==  4 ) {
857          tname = pname;
858          VolParName = psv;
859       } else {
860          SUMA_ifree(pname); SUMA_ifree(psv);
861       }
862    }
863    if (tname) {
864       gSO_FT = SUMA_GuessSurfFormatFromExtension(tname, NULL);
865       if (SO_FT <= SUMA_FT_NOT_SPECIFIED && gSO_FT > SO_FT) {
866          SUMA_S_Notev( "Surface type not specified.\n"
867                        "Format appears to be %s\n"
868                        "based on filename extension.\n",
869                        SUMA_SurfaceTypeString(gSO_FT));
870          SO_FT = gSO_FT;
871       }
872       if (i1 == 4) { /* Have template surface, adopt format */
873          SO_FT = gSO_FT;
874       }
875       if (  gSO_FT > SUMA_FT_NOT_SPECIFIED &&
876             gSO_FT != SO_FT && !pname) {
877          SUMA_S_Warnv("Warning Warning MSB!!!\n"
878                       "Surface file name's (%s) extension indcates a\n"
879                       "surface of type %s and conflicts with specified\n"
880                       "type of %s.\n"
881                       "Function will attempt to proceed as if type is\n"
882                       "%s.\n",
883                       tname, SUMA_SurfaceTypeString(gSO_FT),
884                       SUMA_SurfaceTypeString(SO_FT),
885                       SUMA_SurfaceTypeString(SO_FT));
886       }
887    }
888    /* check if recognizable type */
889    switch (SO_FT) {
890       case SUMA_INVENTOR_GENERIC:
891          break;
892       case SUMA_SUREFIT:
893          break;
894       case SUMA_FREE_SURFER:
895       case SUMA_FREE_SURFER_PATCH:
896          break;
897       case SUMA_STL:
898          break;
899       case SUMA_PLY:
900          break;
901       case SUMA_OBJ_MESH:
902          break;
903       case SUMA_MNI_OBJ:
904          break;
905       case SUMA_OPENDX_MESH:
906          break;
907       case SUMA_VEC:
908          break;
909       case SUMA_BRAIN_VOYAGER:
910          break;
911       case SUMA_BYU:
912          break;
913       case SUMA_GIFTI:
914          break;
915       case SUMA_PREDEFINED:
916          break;
917       default:
918          SUMA_error_message(FuncName, "SO_FileType not supported", 0);
919          SUMA_ifree(pname); SUMA_ifree(psv);
920          SUMA_RETURN (NULL);
921          break;
922    } /* SO_FT*/
923 
924 
925    /* proceed for reading */
926    switch (SO_FT) {
927       case SUMA_CMAP_SO:
928          /* nothing to do here */
929          SUMA_SL_Err("Don't know how to read those from disk:");
930          SUMA_ifree(pname); SUMA_ifree(psv);
931          SUMA_RETURN(NULL);
932 
933       case SUMA_FT_NOT_SPECIFIED:
934          fprintf (SUMA_STDERR,"Error %s: No File Type specified.\n", FuncName);
935          SUMA_ifree(pname); SUMA_ifree(psv);
936          SUMA_RETURN(NULL);
937 
938       case SUMA_N_SO_FILE_TYPE:
939          fprintf (SUMA_STDERR,
940                   "Error %s: This should not happen (SUMA_N_SO_FILE_TYPE)\n",
941                   FuncName);
942          SUMA_ifree(pname); SUMA_ifree(psv);
943          SUMA_RETURN(NULL);
944 
945       case SUMA_STL:
946          if (!SUMA_STL_Read (tname, SO)) {
947             fprintf (SUMA_STDERR,
948                      "Error %s: Failed in SUMA_STL_Read.\n", FuncName);
949             SUMA_ifree(pname); SUMA_ifree(psv);
950             SUMA_RETURN(NULL);
951          }
952          SUMA_NEW_ID(SO->idcode_str,tname);
953 
954          /* change coordinates to align them with volparent data set,
955             if possible */
956          if (VolParName != NULL) {
957             SO->VolPar = SUMA_VolPar_Attr (VolParName);
958             if (SO->VolPar == NULL) {
959                fprintf( SUMA_STDERR,
960                         "Error %s: Failed to load parent volume attributes.\n",
961                         FuncName);
962             } else {
963 
964             if (!SUMA_Align_to_VolPar (SO, NULL)) SO->SUMA_VolPar_Aligned = NOPE;
965                else {
966                   SO->SUMA_VolPar_Aligned = YUP;
967                   /*SUMA_Show_VolPar(SO->VolPar, NULL);*/
968                }
969             }
970          } else {
971             SO->SUMA_VolPar_Aligned = NOPE;
972          }
973          SO->normdir = 0;  /* not set */
974          break;
975       case SUMA_PLY:
976          if (!SUMA_Ply_Read (tname, SO)) {
977             fprintf (SUMA_STDERR,
978                      "Error %s: Failed in SUMA_Ply_Read.\n", FuncName);
979             SUMA_ifree(pname); SUMA_ifree(psv);
980             SUMA_RETURN(NULL);
981          }
982          SUMA_NEW_ID(SO->idcode_str,tname);
983 
984          /* change coordinates to align them with volparent data set,
985             if possible */
986          if (VolParName != NULL) {
987             SO->VolPar = SUMA_VolPar_Attr (VolParName);
988             if (SO->VolPar == NULL) {
989                fprintf( SUMA_STDERR,
990                         "Error %s: Failed to load parent volume attributes.\n",
991                         FuncName);
992             } else {
993 
994             if (!SUMA_Align_to_VolPar (SO, NULL)) SO->SUMA_VolPar_Aligned = NOPE;
995                else {
996                   SO->SUMA_VolPar_Aligned = YUP;
997                   /*SUMA_Show_VolPar(SO->VolPar, NULL);*/
998                }
999             }
1000          } else {
1001             SO->SUMA_VolPar_Aligned = NOPE;
1002          }
1003          SO->normdir = 0;  /* not set */
1004          break;
1005       case SUMA_MNI_OBJ:
1006          if (!SUMA_MNI_OBJ_Read (tname, SO)) {
1007             fprintf (SUMA_STDERR,
1008                      "Error %s: Failed in SUMA_MNI_OBJ_Read.\n", FuncName);
1009             SUMA_ifree(pname); SUMA_ifree(psv);
1010             SUMA_RETURN(NULL);
1011          }
1012          SUMA_NEW_ID(SO->idcode_str,tname);
1013 
1014          /* change coordinates to align them with
1015             volparent data set, if possible */
1016          if (VolParName != NULL) {
1017             SO->VolPar = SUMA_VolPar_Attr (VolParName);
1018             if (SO->VolPar == NULL) {
1019                fprintf( SUMA_STDERR,
1020                         "Error %s: Failed to load parent volume attributes.\n",
1021                         FuncName);
1022             } else {
1023 
1024             if (!SUMA_Align_to_VolPar (SO, NULL))
1025                SO->SUMA_VolPar_Aligned = NOPE;
1026                else {
1027                   SO->SUMA_VolPar_Aligned = YUP;
1028                   /*SUMA_Show_VolPar(SO->VolPar, NULL);*/
1029                }
1030             }
1031          } else {
1032             SO->SUMA_VolPar_Aligned = NOPE;
1033          }
1034          SO->normdir = 0;  /* not set */
1035          break;
1036       case SUMA_OPENDX_MESH:
1037          if (!SUMA_OpenDX_Read_SO (tname, SO)) {
1038             fprintf (SUMA_STDERR,
1039                      "Error %s: Failed in SUMA_OpenDX_Read_SO.\n", FuncName);
1040             SUMA_ifree(pname); SUMA_ifree(psv);
1041             SUMA_RETURN(NULL);
1042          }
1043          SUMA_NEW_ID(SO->idcode_str,tname);
1044 
1045          /* change coordinates to align them with volparent data set,
1046             if possible */
1047          if (VolParName != NULL) {
1048             SO->VolPar = SUMA_VolPar_Attr (VolParName);
1049             if (SO->VolPar == NULL) {
1050                fprintf(SUMA_STDERR,
1051                         "Error %s: Failed to load parent volume attributes.\n",
1052                         FuncName);
1053             } else {
1054 
1055             if (!SUMA_Align_to_VolPar (SO, NULL)) SO->SUMA_VolPar_Aligned = NOPE;
1056                else {
1057                   SO->SUMA_VolPar_Aligned = YUP;
1058                   /*SUMA_Show_VolPar(SO->VolPar, NULL);*/
1059                }
1060             }
1061          } else {
1062             SO->SUMA_VolPar_Aligned = NOPE;
1063          }
1064 
1065          SO->normdir = -1;  /* negative */
1066          break;
1067      case SUMA_OBJ_MESH:
1068          {
1069             if (!(SUMA_OBJ_Read_SO(tname, SO, NULL))) {
1070                SUMA_S_Err("Failed to read %s", tname);
1071                SUMA_ifree(pname); SUMA_ifree(psv);
1072                SUMA_RETURN(NULL);
1073             }
1074             /* Don't change ID here, that is done inside SUMA_OBJ_Read_SO */
1075             /* change coordinates to align them with volparent data set,
1076                if possible */
1077             if (VolParName != NULL) {
1078                SO->VolPar = SUMA_VolPar_Attr (VolParName);
1079                if (SO->VolPar == NULL) {
1080                   SUMA_S_Err("Failed to load parent volume attributes.\n");
1081                } else {
1082                   if (!SUMA_Align_to_VolPar (SO, NULL))
1083                      SO->SUMA_VolPar_Aligned = NOPE;
1084                   else {
1085                      SO->SUMA_VolPar_Aligned = YUP;
1086                      /*SUMA_Show_VolPar(SO->VolPar, NULL);*/
1087                   }
1088                }
1089             } else {
1090                SO->SUMA_VolPar_Aligned = NOPE;
1091             }
1092 
1093             SO->normdir = -1;  /* negative */
1094             break;
1095 
1096          }
1097          break;
1098      case SUMA_PREDEFINED:
1099          i1 = SUMA_is_predefined_SO_name(tname, &par,
1100                                          NULL, NULL, NULL);
1101          switch(i1) {
1102             case 1:
1103                SO = SUMA_CreateIcosahedron(30, par, NULL, "n", 1);
1104                break;
1105             case 2:
1106                SO = SUMA_CreateIcosahedron(30, par, NULL, "y", 1);
1107                break;
1108             case 0:
1109                break;
1110             default:
1111                SUMA_S_Errv("Not ready for typ %d on %s\n",
1112                            i1, tname);
1113                SUMA_ifree(pname); SUMA_ifree(psv);
1114                SUMA_RETURN(NULL);
1115                break;
1116          }
1117          SO->Name = SUMA_StripPath(tname);
1118          SO->FileType = SUMA_PREDEFINED;
1119          /* change coordinates to align them with volparent data set,
1120             if possible */
1121          if (VolParName != NULL) {
1122             SO->VolPar = SUMA_VolPar_Attr (VolParName);
1123             if (SO->VolPar == NULL) {
1124                fprintf(SUMA_STDERR,
1125                         "Error %s: Failed to load parent volume attributes.\n",
1126                         FuncName);
1127             } else {
1128 
1129             if (!SUMA_Align_to_VolPar (SO, NULL)) SO->SUMA_VolPar_Aligned = NOPE;
1130                else {
1131                   SO->SUMA_VolPar_Aligned = YUP;
1132                   /*SUMA_Show_VolPar(SO->VolPar, NULL);*/
1133                }
1134          }
1135          } else {
1136             SO->SUMA_VolPar_Aligned = NOPE;
1137          }
1138 
1139          SO->normdir = 1;
1140          break;
1141 
1142      case SUMA_BRAIN_VOYAGER:
1143          if (0 && SUMA_GuessSurfFormatFromExtension(tname,
1144                                                          NULL)==SUMA_GIFTI) {
1145             /* Allowing for cases where BrainVoyager.gii surfaces are in the same
1146             coordinate system as their native format and so will require
1147             the VolPar transform below. I did not think this should happen
1148             with GIFTI. The surface coords should correspond directly to those
1149             of the NIFTI volume
1150             Exception added for Adam Greenberg, surfaces are not well
1151             centered in the viewer. This will need fixing is this condition
1152             is to be allowed. Problem is that it appears BV's gifti surfaces
1153             might still be in their native coord system, not as set by
1154             the transform matrix in the gii file */
1155             SUMA_S_Warn("This should not be used regularly.\n"
1156                         "Surfaces will not display in the proper place\n"
1157                         "in SUMA.\n");
1158             if (!SUMA_GIFTI_Read (tname, SO, 1)) {
1159                fprintf (SUMA_STDERR,
1160                      "Error %s: Failed in SUMA_GIFTI_Read.\n", FuncName);
1161                SUMA_ifree(pname); SUMA_ifree(psv);
1162                SUMA_RETURN(NULL);
1163             }
1164             SO->FileType = SUMA_BRAIN_VOYAGER;
1165          } else {
1166             if (!SUMA_BrainVoyager_Read (tname, SO, 1, 1)) {
1167                fprintf (SUMA_STDERR,
1168                         "Error %s: Failed in SUMA_BrainVoyager_Read.\n",
1169                         FuncName);
1170                SUMA_ifree(pname); SUMA_ifree(psv);
1171                SUMA_RETURN(NULL);
1172             }
1173          }
1174          SUMA_NEW_ID(SO->idcode_str,tname);
1175 
1176          /* change coordinates to align them with volparent data set,
1177             if possible */
1178          if (VolParName != NULL) {
1179             SO->VolPar = SUMA_VolPar_Attr (VolParName);
1180             if (SO->VolPar == NULL) {
1181                fprintf( SUMA_STDERR,
1182                         "Error %s: Failed to load parent volume attributes.\n",
1183                         FuncName);
1184             } else {
1185             if (!SUMA_Align_to_VolPar (SO, NULL))
1186                SO->SUMA_VolPar_Aligned = NOPE;
1187                else {
1188                   SO->SUMA_VolPar_Aligned = YUP;
1189                   /*SUMA_Show_VolPar(SO->VolPar, NULL);*/
1190                }
1191             }
1192          } else {
1193             SO->SUMA_VolPar_Aligned = NOPE;
1194          }
1195 
1196          if (SO->SUMA_VolPar_Aligned) SO->normdir = 1;  /* positive */
1197          else SO->normdir = -1; /* negative */
1198          break;
1199 
1200       case SUMA_BYU:
1201          if (!SUMA_BYU_Read (tname, SO, 1, 1)) {
1202             fprintf (SUMA_STDERR,
1203                      "Error %s: Failed in SUMA_BYU_Read.\n", FuncName);
1204             SUMA_ifree(pname); SUMA_ifree(psv);
1205             SUMA_RETURN(NULL);
1206          }
1207          SUMA_NEW_ID(SO->idcode_str,tname);
1208 
1209          /* change coordinates to align them with volparent data set,
1210             if possible */
1211          if (VolParName != NULL) {
1212             SO->VolPar = SUMA_VolPar_Attr (VolParName);
1213             if (SO->VolPar == NULL) {
1214                fprintf( SUMA_STDERR,
1215                         "Error %s: Failed to load parent volume attributes.\n",
1216                         FuncName);
1217             } else {
1218 
1219             if (!SUMA_Align_to_VolPar (SO, NULL))
1220                SO->SUMA_VolPar_Aligned = NOPE;
1221                else {
1222                   SO->SUMA_VolPar_Aligned = YUP;
1223                   /*SUMA_Show_VolPar(SO->VolPar, NULL);*/
1224                }
1225             }
1226          } else {
1227             SO->SUMA_VolPar_Aligned = NOPE;
1228          }
1229 
1230          SO->normdir = SUMA_SurfNormDir(SO);  /* guess */
1231          break;
1232 
1233       case SUMA_GIFTI:
1234          if (!SUMA_GIFTI_Read (tname, SO, 1)) {
1235             fprintf (SUMA_STDERR,
1236                      "Error %s: Failed in SUMA_GIFTI_Read.\n", FuncName);
1237             SUMA_ifree(pname); SUMA_ifree(psv);
1238             SUMA_RETURN(NULL);
1239          }
1240          SUMA_NEW_ID(SO->idcode_str,tname);
1241 
1242          /* change coordinates to align them with volparent data set,
1243             if possible */
1244          if (VolParName != NULL) {
1245             SO->VolPar = SUMA_VolPar_Attr (VolParName);
1246             if (SO->VolPar == NULL) {
1247                fprintf( SUMA_STDERR,
1248                         "Error %s: Failed to load parent volume attributes.\n",
1249                         FuncName);
1250             } else {
1251 
1252             if (!SUMA_Align_to_VolPar (SO, NULL))
1253                SO->SUMA_VolPar_Aligned = NOPE;
1254                else {
1255                   SO->SUMA_VolPar_Aligned = YUP;
1256                   /*SUMA_Show_VolPar(SO->VolPar, NULL);*/
1257                }
1258             }
1259          } else {
1260             SO->SUMA_VolPar_Aligned = NOPE;
1261          }
1262 
1263          SO->normdir = SUMA_SurfNormDir(SO);  /* guess */
1264          break;
1265 
1266       case SUMA_INVENTOR_GENERIC:
1267          SO_FileName = tname;
1268          /* You need to split name into path and name ... */
1269 	      if ( debug )
1270             fprintf(stdout,"%s\n", SO_FileName);
1271          SO->Name = SUMA_StripPath(SO_FileName);
1272          /* check for file existence  */
1273          if (!SUMA_filexists(SO_FileName)) {
1274             snprintf(stmp,998,"File %s not found!", SO_FileName);
1275             SUMA_error_message(FuncName, stmp, 0);
1276             SUMA_RETURN (NULL);
1277          }
1278          SO->FileType = SO_FT;
1279          SO->FileFormat = SO_FF;
1280          SO->NodeDim = 3; /* This must be automated */
1281          SO->NodeList = SUMA_IV_XYZextract (SO_FileName, &(SO->N_Node), 0);
1282          if (SO->NodeList == NULL) {
1283             SUMA_error_message(FuncName,"SUMA_IV_XYZextract failed!",0);
1284             SUMA_ifree(pname); SUMA_ifree(psv);
1285             SUMA_RETURN(NULL);
1286          }
1287          SO->FaceSetList = SUMA_IV_FaceSetsextract (SO_FileName,
1288                                                    &(SO->N_FaceSet));
1289          if (SO->FaceSetList == NULL) {
1290             SUMA_error_message(FuncName,"SUMA_IV_FaceSetsextract failed!",0);
1291             SUMA_ifree(pname); SUMA_ifree(psv);
1292             SUMA_RETURN(NULL);
1293          }
1294          SO->FaceSetDim = 3; /*This must also be automated */
1295          SUMA_NEW_ID(SO->idcode_str,SO_FileName);
1296 
1297          SO->normdir = 0;  /* not set */
1298          break;
1299 
1300       case SUMA_FREE_SURFER:
1301       case SUMA_FREE_SURFER_PATCH:
1302          /* Allocate for FS */
1303          FS = (SUMA_FreeSurfer_struct *)
1304                   SUMA_malloc(sizeof(SUMA_FreeSurfer_struct));
1305          if (FS == NULL) {
1306             fprintf( SUMA_STDERR,
1307                      "Error %s: Failed to allocate for FS\n", FuncName);
1308             SUMA_ifree(pname); SUMA_ifree(psv);
1309             SUMA_RETURN (NULL);
1310          }
1311          /* add a couple of lines to appease the optimation gods...         */
1312          /* (suma, v2s, SSmooth were crashing on FC7)   23 Jan 2008 [rickr] */
1313          memset(FS, 0, sizeof(SUMA_FreeSurfer_struct));
1314          if(debug > 1) fprintf(stderr,"-- optimization appeasement message\n");
1315          SO->Name = SUMA_StripPath((char*)SO_FileName_vp);
1316          SO->FileType = SO_FT;
1317          SO->FileFormat = SO_FF;
1318          SO->NodeDim = 3; /* This must be automated */
1319          /*read the surface file */
1320          if (SO->FileFormat == SUMA_ASCII) {    // PDL: NB: This is where the ascii file,
1321                                       //  containing the surface specifications, is read
1322             if (!SUMA_FreeSurfer_Read_eng((char*)SO_FileName_vp, FS, debug)) {
1323                fprintf( SUMA_STDERR,
1324                         "Error %s: Failed in SUMA_FreeSurfer_Read.\n",
1325                         FuncName);
1326                SUMA_ifree(pname); SUMA_ifree(psv);
1327                SUMA_RETURN (NULL);
1328             }
1329          } else if (SO->FileFormat == SUMA_BINARY_BE) {
1330             if (!SUMA_FreeSurfer_ReadBin_eng((char*)SO_FileName_vp, FS, debug)) {
1331                fprintf( SUMA_STDERR,
1332                         "Error %s: Failed in SUMA_FreeSurfer_Read.\n",
1333                         FuncName);
1334                SUMA_ifree(pname); SUMA_ifree(psv);
1335                SUMA_RETURN (NULL);
1336             }
1337          } else {
1338             SUMA_SL_Err("Format not supported.");
1339             SUMA_ifree(pname); SUMA_ifree(psv);
1340             SUMA_RETURN (NULL);
1341          }
1342 	 if ( debug > 1)
1343             SUMA_Show_FreeSurfer (FS, NULL);
1344          /* save the juice and clean up the rest */
1345          SO->N_Node = FS->N_Node;
1346          /* Save the pointers to NodeList and FaceSetList and
1347             clear what is left of FS structure at the end */
1348          SO->NodeList = FS->NodeList;
1349          FS->NodeList = NULL;
1350          SO->FaceSetList = FS->FaceSetList;
1351          SO->N_FaceSet = FS->N_FaceSet;
1352          FS->FaceSetList = NULL;
1353          SO->FaceSetDim = 3; /*This must also be automated */
1354 
1355 
1356          /* change coordinates to align them with volparent data set,
1357             if possible */
1358          if (VolParName != NULL) {
1359             SO->VolPar = SUMA_VolPar_Attr (VolParName);
1360             if (SO->VolPar == NULL) {
1361                fprintf( SUMA_STDERR,
1362                         "Error %s: Failed to load parent volume attributes.\n",
1363                         FuncName);
1364             } else {
1365                if (!SUMA_Align_to_VolPar (SO, (void*)FS))
1366                   SO->SUMA_VolPar_Aligned = NOPE;
1367                   else {
1368                      SO->SUMA_VolPar_Aligned = YUP;
1369                      /*SUMA_Show_VolPar(SO->VolPar, NULL);*/
1370                   }
1371             }
1372          } else {
1373             SO->SUMA_VolPar_Aligned = NOPE;
1374          }
1375          SO->normdir = 1; /* normals point out */
1376          /* free FS */
1377          if (!SUMA_Free_FreeSurfer (FS)) {
1378             fprintf( SUMA_STDERR,
1379                      "Error %s: Failed in SUMA_Free_FreeSurfer.\n", FuncName);
1380             SUMA_ifree(pname); SUMA_ifree(psv);
1381             SUMA_RETURN (NULL);
1382          }
1383 
1384          /* create the IDcode */
1385          SUMA_NEW_ID(SO->idcode_str, tname);
1386          if (LocalHead)
1387             fprintf (SUMA_STDERR,
1388                      "%s: Assigned idcode_str:%s:.\n", FuncName, SO->idcode_str);
1389 
1390          SO->normdir = 1;  /* positive */
1391          break;
1392 
1393       case SUMA_VEC:
1394          /* naming is with two files, similar to SureFit */
1395          SF_FileName = (SUMA_SFname *)SO_FileName_vp;
1396          /* form the topo and the coord names */
1397          SO->Name_coord = SUMA_StripPath(SF_FileName->name_coord);
1398          SO->Name_topo = SUMA_StripPath(SF_FileName->name_topo);
1399          SO->FileType = SO_FT;
1400          SO->FileFormat = SO_FF;
1401          SO->NodeDim = 3; /* This must be automated */
1402          /* check for files */
1403          if (!SUMA_filexists(SF_FileName->name_coord)) {
1404             fprintf(SUMA_STDERR,"Error %s: Could not find %s\n",
1405                      FuncName, SF_FileName->name_coord);
1406             SUMA_ifree(pname); SUMA_ifree(psv);
1407             SUMA_RETURN (NULL);
1408          }
1409          if (!SUMA_filexists(SF_FileName->name_topo)) {
1410             fprintf(SUMA_STDERR,"Error %s: Could not find %s\n",
1411                      FuncName, SF_FileName->name_topo);
1412             SUMA_ifree(pname); SUMA_ifree(psv);
1413             SUMA_RETURN (NULL);
1414          }
1415 
1416          if (!SUMA_VEC_Read(SF_FileName, SO)) {
1417             SUMA_SLP_Err("Failed to read 1D file");
1418             if (SO->NodeList) SUMA_free(SO->NodeList);
1419             if (SO->FaceSetList) SUMA_free(SO->FaceSetList);
1420             SUMA_ifree(pname); SUMA_ifree(psv);
1421             SUMA_RETURN (NULL);
1422          }
1423 
1424          sprintf (stmp, "%s%s", SF_FileName->name_coord, SF_FileName->name_topo);
1425          SUMA_NEW_ID(SO->idcode_str, stmp);
1426 
1427          /* change coordinates to align them with volparent data set,
1428             if possible */
1429          if (VolParName != NULL) {
1430             SO->VolPar = SUMA_VolPar_Attr (VolParName);
1431             if (SO->VolPar == NULL) {
1432                fprintf( SUMA_STDERR,
1433                         "Error %s: Failed to load parent volume attributes.\n",
1434                         FuncName);
1435             } else {
1436 
1437             if (!SUMA_Align_to_VolPar (SO, NULL)) SO->SUMA_VolPar_Aligned = NOPE;
1438                else {
1439                   SO->SUMA_VolPar_Aligned = YUP;
1440                   /*SUMA_Show_VolPar(SO->VolPar, NULL);*/
1441                }
1442          }
1443          } else {
1444             SO->SUMA_VolPar_Aligned = NOPE;
1445          }
1446 
1447          SO->normdir = 0;  /* not set */
1448          break;
1449 
1450       case SUMA_FT_ERROR:
1451          SUMA_SL_Err("Error specifying file type.");
1452          break;
1453 
1454       case SUMA_SUREFIT:
1455          /* Allocate for SF */
1456          SF = (SUMA_SureFit_struct *) SUMA_calloc(1,
1457                                         sizeof(SUMA_SureFit_struct));
1458          if (SF == NULL) {
1459             fprintf( SUMA_STDERR,
1460                      "Error %s: Failed to allocate for SF\n", FuncName);
1461             SUMA_ifree(pname); SUMA_ifree(psv);
1462             SUMA_RETURN (NULL);
1463          }
1464          SF->NodeList= NULL;
1465          SF->NodeId = NULL;
1466          SF->allzerocoord = NULL;
1467          SF->Specs_mat = NULL;
1468          SF->FaceSetList = NULL;
1469          SF->FN.N_Neighb = NULL;
1470          SF->FN.FirstNeighb = NULL;
1471          SF->FN.NodeId = NULL;
1472          SF->caret_version = -1.0;
1473          SF_FileName = (SUMA_SFname *)SO_FileName_vp;
1474          /* form the topo and the coord names */
1475          SO->Name_coord = SUMA_StripPath(SF_FileName->name_coord);
1476          SO->Name_topo = SUMA_StripPath(SF_FileName->name_topo);
1477          SO->FileType = SO_FT;
1478          SO->FileFormat = SO_FF;
1479          SO->NodeDim = 3; /* This must be automated */
1480 
1481          /*read the coordinate file */
1482          if (!SUMA_SureFit_Read_Coord (SF_FileName->name_coord,
1483                                        SF)) {
1484             fprintf( SUMA_STDERR,
1485                      "Error %s: Failed in SUMA_SureFit_Read_Coord.\n", FuncName);
1486             SUMA_ifree(pname); SUMA_ifree(psv);
1487             SUMA_RETURN (NULL);
1488          }
1489          /* copy the pertinent data to SO */
1490          SO->N_Node = SF->N_Node;
1491          /* Save the pointers to NodeList and FaceSetList and
1492             clear what is left of SF structure at the end */
1493          SO->NodeList = SF->NodeList;
1494          SF->NodeList = NULL;
1495 
1496 
1497          /*read the topology file */
1498          if (!SUMA_SureFit_Read_Topo (SF_FileName->name_topo, SF)) {
1499             fprintf( SUMA_STDERR,
1500                      "Error %s: Failed in SUMA_SureFit_Read_Topo.\n", FuncName);
1501             SUMA_ifree(pname); SUMA_ifree(psv);
1502             SUMA_RETURN (NULL);
1503          }
1504 
1505 
1506          /* read the param file */
1507          if (strlen(SF_FileName->name_param)){
1508             if (!SUMA_Read_SureFit_Param(SF_FileName->name_param, SF)) {
1509                fprintf( SUMA_STDERR,
1510                         "Error %s: Failed in SUMA_Read_SureFit_Param.\n",
1511                         FuncName);
1512             }
1513          } else {
1514             if (VolParName != NULL) {
1515                SUMA_S_Note("Volume Parent specified without .param file.\n"
1516                      "Be sure surface and volume line up.");
1517             }
1518          }
1519 
1520          /* copy the pertinent data to SO */
1521          SO->FaceSetList = SF->FaceSetList;
1522          SO->N_FaceSet = SF->N_FaceSet;
1523          SF->FaceSetList = NULL;
1524          SO->FaceSetDim = 3; /*This must also be automated */
1525 
1526          /* change coordinates to align them with volparent data set,
1527             if possible */
1528          if (VolParName != NULL ) {
1529             SO->VolPar = SUMA_VolPar_Attr (VolParName);
1530             if (SO->VolPar == NULL) {
1531                fprintf( SUMA_STDERR,
1532                         "Error %s: Failed to load parent volume attributes.\n",
1533                         FuncName);
1534             } else {
1535                /*SUMA_Show_VolPar(SO->VolPar, NULL);*/
1536 
1537                if (!SUMA_Align_to_VolPar (SO, (void *)SF))
1538                   SO->SUMA_VolPar_Aligned = NOPE;
1539                else
1540                   SO->SUMA_VolPar_Aligned = YUP;
1541             }
1542          } else {
1543             /* OK to go there with new caret files */
1544             if (!SUMA_Align_to_VolPar (SO, (void *)SF))
1545                SO->SUMA_VolPar_Aligned = NOPE;
1546             else
1547                SO->SUMA_VolPar_Aligned = YUP;
1548          }
1549 
1550          sprintf (stmp, "%s%s", SF_FileName->name_coord, SF_FileName->name_topo);
1551          SUMA_NEW_ID(SO->idcode_str, stmp);
1552 
1553          if ((int) SF->tag_version == 1) { SO->normdir = 1; }
1554          else SO->normdir = -1;
1555 
1556          /* SUMA_Show_SureFit(SF, SUMA_STDERR); */
1557 
1558          /* free SF */
1559          if (!SUMA_Free_SureFit (SF)) {
1560             fprintf( SUMA_STDERR,
1561                      "Error %s: Failed in SUMA_Free_SureFit.\n", FuncName);
1562             SUMA_ifree(pname); SUMA_ifree(psv);
1563             SUMA_RETURN (NULL);
1564          }
1565 
1566          break;
1567    } /* SO_FileType*/
1568 
1569    /* sanity check (this one's here for a reason) */
1570    if (SO->N_Node <=0 || SO->N_FaceSet<=0) {
1571       SUMA_SL_Crit("0 nodes or 0 facesets.\nProceed I will not.\n");
1572       SUMA_Free_Surface_Object (SO);
1573       SUMA_ifree(pname); SUMA_ifree(psv);
1574       SUMA_RETURN (NULL);
1575    }
1576 
1577    /* A trick for Stephen Tyree, Pat Bellgowan, and other mad men */
1578    if (AFNI_yesenv("SUMA_FLIP_X_COORD")) {
1579       int i, id;
1580       for (i=0; i < SO->N_Node; ++i) {
1581             id = i * SO->NodeDim;
1582             SO->NodeList[id] = -SO->NodeList[id];
1583       }
1584       SO->normdir = -SO->normdir;
1585    }
1586    if (SO->isSphere == SUMA_GEOM_NOT_SET) {
1587       SUMA_SetSphereParams(SO, -0.1);
1588    }  /* sets the spheriosity parameters */
1589 
1590 
1591 
1592    if (!SUMA_PrepSO_GeomProp_GL (SO)) {
1593       SUMA_SL_Err("Failed to set surface's properties");
1594       SUMA_ifree(pname); SUMA_ifree(psv);
1595       SUMA_RETURN (NULL);
1596    }
1597 
1598 
1599    SUMA_ifree(pname); SUMA_ifree(psv);
1600    SUMA_RETURN (SO);
1601 
1602 }/*SUMA_Load_Surface_Object_eng*/
1603 
1604 /*!< Look for datasets names exactly like the surface but with
1605 a dataset extension and load them if found*/
SUMA_AutoLoad_SO_Dsets(SUMA_SurfaceObject * SO)1606 SUMA_Boolean SUMA_AutoLoad_SO_Dsets(SUMA_SurfaceObject *SO)
1607 {
1608    static char FuncName[]={"SUMA_AutoLoad_SO_Dsets"};
1609    char *ddd=NULL, *ddde=NULL, *soname=NULL;
1610    SUMA_Boolean LocalHead = NOPE;
1611 
1612    SUMA_ENTRY;
1613 
1614    soname = SUMA_SurfaceFileName(SO, 1);
1615    if (!soname) soname = SUMA_copy_string("No_SO_name.gii");
1616    ddd = SUMA_RemoveSurfNameExtension (soname, SO->FileType);
1617    SUMA_LH("Checking for %s dsets on root %s", soname, ddd);
1618    if (SUMA_filexists((ddde = SUMA_append_string(ddd,".niml.dset")))) {
1619       SUMA_S_Note("Auto Loading %s onto %s", ddde, soname);
1620       SUMA_LoadDsetOntoSO(ddde, (void *)SO);
1621       SUMA_ifree(ddde);
1622    }
1623    if (ddde) {/* try again */
1624       SUMA_ifree(ddde);
1625       if (SUMA_filexists((ddde = SUMA_append_string(ddd,".1D.dset")))) {
1626          SUMA_S_Note("Auto Loading %s onto %s", ddde, soname);
1627          SUMA_LoadDsetOntoSO(ddde, (void *)SO);
1628          SUMA_ifree(ddde);
1629       }
1630    }
1631    if (ddde) {/* try again */
1632       SUMA_ifree(ddde);
1633       if (SUMA_filexists((ddde = SUMA_append_string(ddd,".gii.dset")))) {
1634          SUMA_S_Note("Auto Loading %s onto %s", ddde, soname);
1635          SUMA_LoadDsetOntoSO(ddde, (void *)SO);
1636          SUMA_ifree(ddde);
1637       }
1638    }
1639    if (ddde) {/* try again */
1640       SUMA_ifree(ddde);
1641       if ( SO->FileType != SUMA_GIFTI &&
1642            SUMA_filexists((ddde = SUMA_append_string(ddd,".gii")))) {
1643          SUMA_S_Note("Auto Loading %s onto %s", ddde, soname);
1644          SUMA_LoadDsetOntoSO(ddde, (void *)SO);
1645          SUMA_ifree(ddde);
1646       }
1647    }
1648    SUMA_ifree(ddd);
1649    SUMA_ifree(soname);
1650    if (!ddde) SUMA_RETURN(YUP); /* got one */
1651 
1652    SUMA_ifree(ddde);
1653    SUMA_RETURN(NOPE);
1654 }
1655 
1656 
1657 
1658 /*!
1659    SUMA_Boolean SUMA_ParseLHS_RHS (char *s, char *lhs, char *rhs)
1660 
1661    Parses S of the form "lhs = rhs"
1662    s, lhs and rhs must be allocated for
1663 
1664    \param s (char *) "joe = fred"
1665    \param lhs (char *) "joe"
1666                      if you send in lhs[0] = '\0'; it gets
1667                      filled with joe for you.
1668    \param rhs (char *) returned "fred"
1669    \ret YUP/NOPE for goodness, badness
1670 
1671 */
SUMA_ParseLHS_RHS(char * s,char * lhs,char * rhs)1672 SUMA_Boolean SUMA_ParseLHS_RHS (char *s, char *lhs, char *rhs)
1673 {
1674    static char FuncName[]={"SUMA_ParseLHS_RHS"};
1675    char *op=NULL, *op2=NULL;
1676    SUMA_Boolean LocalHead = NOPE;
1677 
1678    SUMA_ENTRY;
1679 
1680    if (s == NULL) {
1681       fprintf(SUMA_STDERR,"Error %s: NULL s\n", FuncName);
1682       SUMA_RETURN (NOPE);
1683    }
1684    rhs[0] = '\0';
1685 
1686    /* skip first blank */
1687    SUMA_SKIP_BLANK(s, NULL);
1688 
1689    /* seek first = */
1690    SUMA_LHv("Have >%s<\n", s);
1691    op=s;
1692    SUMA_SKIP_TO_NEXT_CHAR(s,NULL,'=');
1693    if (lhs[0] == '\0') { /* load left hand side */
1694       SUMA_FILL_STRING(op, s, lhs);
1695       SUMA_DEBLANK_RHS(lhs);
1696       SUMA_LHv("LHS now: >%s<\n", lhs);
1697    }
1698    if (*s != '=') {
1699       SUMA_LH("No equal, no right hand side\n");
1700       SUMA_RETURN (NOPE);
1701    }
1702    /* get all the rhs */
1703    ++s;
1704    SUMA_SKIP_BLANK(s, NULL);
1705    SUMA_FILL_STRING(s, NULL, rhs);
1706    /* deblank end of rhs */
1707    SUMA_DEBLANK_RHS(rhs);
1708 
1709    SUMA_LHv("Have %s, lhs>%s<, rhs >%s<\n", s, lhs, rhs);
1710    SUMA_RETURN (YUP);
1711 }
1712 
1713 /* Undo the separation of left/right deformed states
1714                   the _lh and _rh are what @SUMA_Make_Spec_FS used
1715                   to flag these special states */
1716 #define SUMA_LH_UNIFY_STATE_FIX(ss) { \
1717    SUMA_CropExtension((ss), "_lh_lh"); /* don't ask */\
1718    SUMA_CropExtension((ss), "_rh_rh"); /* don't ask */\
1719    SUMA_CropExtension((ss), "_lh"); \
1720    SUMA_CropExtension((ss), "_rh"); \
1721 }
1722 
1723 /*!
1724    Function to read the surface specs file.
1725    \param fname (char *) name of the specs file
1726    \param Spec (SUMA_SurfSpecFile *) pre-allocated pointer to
1727           SUMA_SurfSpecFile structure. )
1728    \ret YUP, good, NOPE, not good
1729 */
SUMA_Read_SpecFile(char * f_name,SUMA_SurfSpecFile * Spec)1730 SUMA_Boolean SUMA_Read_SpecFile (
1731                   char *f_name, SUMA_SurfSpecFile * Spec)
1732 {/* SUMA_Read_SpecFile */
1733    static char FuncName[]={"SUMA_Read_SpecFile"};
1734    char  s[SUMA_MAX_DIR_LENGTH], stmp[SUMA_MAX_DIR_LENGTH],
1735          stmp2[SUMA_MAX_DIR_LENGTH], c;
1736    int ex, skp, evl, i, kkk, LHunify=0;
1737    FILE *sf_file;
1738    SUMA_FileName SpecName;
1739    SUMA_Boolean onGIFTIalert = NOPE;
1740    SUMA_Boolean   OKread_SurfaceFormat, OKread_SurfaceType,
1741                   OKread_TopoFile, OKread_CoordFile;
1742    SUMA_Boolean   OKread_MappingRef, OKread_SureFitVolParam,
1743                   OKread_FreeSurferSurface, OKread_InventorSurface;
1744    SUMA_Boolean   OKread_Group, OKread_State, OKread_EmbedDim,
1745                   OKread_SurfaceVolume, OKread_SurfaceLabel;
1746    SUMA_Boolean   OKread_AnatCorrect, OKread_Hemisphere,
1747                   OKread_DomainGrandParentID, OKread_OriginatorID;
1748    SUMA_Boolean   OKread_LocalCurvatureParent, OKread_LocalDomainParent,
1749                   OKread_LabelDset, OKread_NodeMarker;
1750    char DupWarn[]={  "Bad format in specfile "
1751                      "(you may need a NewSurface line). "
1752                      "Duplicate specification of"};
1753    char NewSurfWarn[]={ "Bad format in specfile. "
1754                         "You must start with NewSurface line "
1755                         "before any other field."};
1756    SUMA_Boolean LocalHead = NOPE;
1757 
1758    SUMA_ENTRY;
1759 
1760    if (SUMA_isEnv("SUMA_LHunify","YES")) LHunify = 1;
1761 
1762    /*make sure file is there */
1763    if (!SUMA_filexists(f_name)) {
1764       fprintf(SUMA_STDERR,
1765                "Error %s: File %s does not exist or cannot be read.\n",
1766                FuncName, f_name);
1767       SUMA_RETURN (NOPE);
1768    }
1769 
1770    if (Spec->N_Surfs != -1) {
1771       fprintf(SUMA_STDERR,
1772                "Error %s: Spec is not fresh after SUMA_AllocSpecFields.\n"
1773                "Perhaps you have redundant definitions of the input surface\n",
1774                FuncName);
1775       SUMA_RETURN (NOPE);
1776    }
1777 
1778    Spec->N_Surfs = 0;
1779 
1780    /* set the path for the spec file */
1781    SpecName = SUMA_StripPath (f_name);
1782    if (strlen(SpecName.Path) > SUMA_MAX_DIR_LENGTH-1) {
1783       fprintf( SUMA_STDERR,
1784                "Error %s: Path of specfile > %d charcters.\n",
1785                FuncName, SUMA_MAX_DIR_LENGTH-1);
1786       SUMA_RETURN (NOPE);
1787    }
1788    if (strlen(SpecName.FileName) > SUMA_MAX_NAME_LENGTH-1) {
1789       fprintf( SUMA_STDERR,
1790                "Error %s: Name of specfile > %d charcters.\n",
1791                FuncName, SUMA_MAX_NAME_LENGTH-1);
1792       SUMA_RETURN (NOPE);
1793    }
1794    snprintf(Spec->SpecFilePath,SUMA_MAX_DIR_LENGTH*sizeof(char),
1795             "%s", SpecName.Path);
1796    snprintf(Spec->SpecFileName,SUMA_MAX_NAME_LENGTH*sizeof(char),
1797             "%s", SpecName.FileName);
1798 
1799    if (SUMA_iswordin(Spec->SpecFileName,"N27")) onGIFTIalert = 1;
1800 
1801    /* free SpecName since it's not used elsewhere */
1802    if (SpecName.Path) SUMA_free(SpecName.Path);
1803    if (SpecName.FileName) SUMA_free(SpecName.FileName);
1804 
1805    /*read the thing*/
1806    sf_file = fopen (f_name,"r");
1807    if (sf_file == NULL)
1808       {
1809          fprintf( SUMA_STDERR,
1810                   "Error %s: Could not open file for read\n", FuncName);
1811          SUMA_RETURN (NOPE);
1812       }
1813 
1814    /*read until you find not a comment */
1815 
1816    /* read the first line, skipping leading space */
1817    do {
1818       ex = fscanf (sf_file,"%c",&c);
1819    } while (ex != EOF && isspace(c));
1820 
1821    i=0;
1822    while (ex != EOF && c != '\n') {
1823          s[i] = c; ++i;
1824       ex = fscanf (sf_file,"%c",&c);
1825    }
1826    s[i] = '\0';
1827    if (LocalHead) fprintf(SUMA_STDERR,"Read %s\n", s);
1828    OKread_Group = YUP; /* it is OK to read a group before
1829                            a new surface is declared */
1830    OKread_SurfaceFormat = OKread_SurfaceType =
1831       OKread_TopoFile = OKread_CoordFile = NOPE;
1832    OKread_MappingRef = OKread_SureFitVolParam =
1833       OKread_FreeSurferSurface = OKread_InventorSurface = NOPE;
1834    OKread_State = OKread_EmbedDim = OKread_SurfaceVolume =
1835       OKread_SurfaceLabel = NOPE ;
1836    OKread_AnatCorrect = OKread_Hemisphere = OKread_DomainGrandParentID =
1837       OKread_OriginatorID = NOPE;
1838    OKread_LocalCurvatureParent = OKread_LocalDomainParent =
1839       OKread_LabelDset = OKread_NodeMarker = NOPE;
1840 
1841    Spec->StateList[0] = '\0';
1842    Spec->Group[0][0] = '\0';
1843    Spec->N_Surfs = Spec->N_States = Spec->N_Groups = 0;
1844    while (ex !=EOF) {
1845       evl = SUMA_iswordin (s,"#");
1846       if (evl != 1) { /* not a comment */
1847          if (LocalHead) fprintf(SUMA_STDERR,"Not a comment: %s\n", s);
1848          skp = 0;
1849          sprintf(stmp,"NewSurface");
1850          if (!skp && SUMA_iswordin (s, stmp) == 1) {
1851             if(Spec->N_Surfs >= SUMA_MAX_N_SURFACE_SPEC) {
1852                fprintf( SUMA_STDERR,
1853                         "Error %s: Cannot read in more than %d new surfaces.\n",
1854                         FuncName, SUMA_MAX_N_SURFACE_SPEC);
1855                SUMA_RETURN (NOPE);
1856             }
1857             Spec->N_Surfs += 1;
1858             if (LocalHead)
1859                fprintf( SUMA_STDERR,
1860                         "Found New Surface, N = %d\n", Spec->N_Surfs);
1861             /* initialize some of the fields */
1862             if (Spec->N_Surfs == 1) { /* first surface, initialize to empty */
1863                sprintf(Spec->SurfaceFormat[Spec->N_Surfs-1],"ASCII");
1864                Spec->SurfaceType[Spec->N_Surfs-1][0] = '\0';
1865                Spec->TopoFile[Spec->N_Surfs-1][0] =
1866                   Spec->CoordFile[Spec->N_Surfs-1][0] = '\0';
1867                Spec->MappingRef[Spec->N_Surfs-1][0] = '\0';  /* Should become
1868                                                                 obsolete,
1869                                                                 ZSS Jan 02 03 */
1870                Spec->SureFitVolParam[Spec->N_Surfs-1][0] = '\0';
1871                Spec->SurfaceFile[Spec->N_Surfs-1][0] = '\0';
1872                Spec->State[Spec->N_Surfs-1][0] = '\0';
1873                Spec->IDcode[Spec->N_Surfs-1] = NULL; /* this field is set in
1874                                                          LoadSpec function */
1875                Spec->EmbedDim[Spec->N_Surfs-1] = 3;
1876                Spec->VolParName[Spec->N_Surfs-1][0] = '\0';
1877                Spec->SurfaceLabel[Spec->N_Surfs-1][0] = '\0';
1878                Spec->AnatCorrect[Spec->N_Surfs-1][0] = '\0';
1879                Spec->Hemisphere[Spec->N_Surfs-1][0] = '\0';
1880                Spec->DomainGrandParentID[Spec->N_Surfs-1][0] = '\0';
1881                Spec->OriginatorID[Spec->N_Surfs-1][0] = '\0';
1882                Spec->LocalCurvatureParent[Spec->N_Surfs-1][0] = '\0';
1883                Spec->LocalDomainParent[Spec->N_Surfs-1][0] = '\0';
1884                Spec->LabelDset[Spec->N_Surfs-1][0] = '\0';
1885                Spec->NodeMarker[Spec->N_Surfs-1][0] = '\0';
1886             } else {
1887                /* make sure important fields have been filled */
1888                if (Spec->SurfaceType[Spec->N_Surfs-2][0] == '\0') {
1889                   fprintf(SUMA_STDERR,
1890                            "Error %s: Failed to specify surface type "
1891                            "for surface %d\n",
1892                            FuncName, Spec->N_Surfs-2);
1893                   SUMA_RETURN (NOPE);
1894                }
1895                /* initilize SOME of the fields to previous one */
1896                Spec->CoordFile[Spec->N_Surfs-1][0] = '\0';  /* *** BA, Dec 03 */
1897                Spec->SurfaceFile[Spec->N_Surfs-1][0] = '\0';/* *** BA, Dec 03 */
1898 
1899                strcpy(  Spec->SurfaceFormat[Spec->N_Surfs-1],
1900                         Spec->SurfaceFormat[Spec->N_Surfs-2]);
1901                strcpy(  Spec->SurfaceType[Spec->N_Surfs-1],
1902                         Spec->SurfaceType[Spec->N_Surfs-2]);
1903                strcpy(  Spec->TopoFile[Spec->N_Surfs-1],
1904                         Spec->TopoFile[Spec->N_Surfs-2]);
1905                strcpy(  Spec->MappingRef[Spec->N_Surfs-1],
1906                         Spec->MappingRef[Spec->N_Surfs-2]);/*  Should become
1907                                                                obsolete,
1908                                                                ZSS Jan 02 03 */
1909                strcpy(  Spec->SureFitVolParam[Spec->N_Surfs-1],
1910                         Spec->SureFitVolParam[Spec->N_Surfs-2]);
1911                Spec->VolParName[Spec->N_Surfs-1][0] = '\0';
1912                      /* it is confusing to users to inherit
1913                         this one from the pervious, keep it separate.*/
1914                Spec->IDcode[Spec->N_Surfs-1] = NULL; /*  this field is set in
1915                                                          LoadSpec function */
1916                Spec->SurfaceLabel[Spec->N_Surfs-1][0] = '\0';
1917                strcpy(  Spec->Group[Spec->N_Surfs-1],
1918                         Spec->Group[Spec->N_Surfs-2]);
1919                strcpy(  Spec->State[Spec->N_Surfs-1],
1920                         Spec->State[Spec->N_Surfs-2]);
1921                Spec->EmbedDim[Spec->N_Surfs-1] =
1922                   Spec->EmbedDim[Spec->N_Surfs-2];
1923                /* perhaps make these inheritable from previous */
1924                Spec->AnatCorrect[Spec->N_Surfs-1][0] = '\0';
1925                Spec->Hemisphere[Spec->N_Surfs-1][0] = '\0';
1926                Spec->DomainGrandParentID[Spec->N_Surfs-1][0] = '\0';
1927                Spec->OriginatorID[Spec->N_Surfs-1][0] = '\0';
1928                Spec->LocalCurvatureParent[Spec->N_Surfs-1][0] = '\0';
1929                Spec->LocalDomainParent[Spec->N_Surfs-1][0] = '\0';
1930                Spec->LabelDset[Spec->N_Surfs-1][0] = '\0';
1931                Spec->NodeMarker[Spec->N_Surfs-1][0] = '\0';
1932                /* only Spec->CoordFile, Spec->SurfaceFile MUST be
1933                   specified with a new surface */
1934             }
1935             OKread_SurfaceFormat = OKread_SurfaceType = OKread_TopoFile =
1936                OKread_CoordFile = YUP;
1937             OKread_MappingRef = OKread_SureFitVolParam =
1938                OKread_FreeSurferSurface = OKread_InventorSurface = YUP;
1939             OKread_Group = OKread_State = OKread_EmbedDim =
1940                OKread_SurfaceLabel = OKread_SurfaceVolume = YUP;
1941             OKread_AnatCorrect = OKread_Hemisphere =
1942                OKread_DomainGrandParentID = OKread_OriginatorID = YUP;
1943             OKread_LocalCurvatureParent = OKread_LocalDomainParent =
1944                OKread_LabelDset = OKread_NodeMarker = YUP;
1945             skp = 1;
1946          }
1947 
1948          sprintf(stmp,"StateDef");
1949          if (!skp && SUMA_iswordin (s, stmp) == 1) {
1950             /* found a state definition, parse it
1951             Use Spec->State[0] as buffer, since SurfaceState comes later*/
1952             if (LocalHead)
1953                fprintf( SUMA_STDERR,
1954                         "%s: Sending %p )\n",
1955                         FuncName, Spec->State[0]);
1956             if (!SUMA_ParseLHS_RHS (
1957                      s, stmp,
1958                      Spec->State[0])) {
1959                fprintf( SUMA_STDERR,
1960                         "Error %s: Error in SUMA_ParseLHS_RHS.\n",
1961                         FuncName);
1962                SUMA_RETURN (NOPE);
1963             }
1964 
1965             if (LHunify) { /* remove the separation of left/right deformed states
1966                               the _lh and _rh are what @SUMA_Make_Spec_FS used
1967                               to flag these special states */
1968                SUMA_LH_UNIFY_STATE_FIX(Spec->State[0]);
1969             }
1970             if (Spec->N_States == 0) {
1971                /* first state, add it to the list of states */
1972                sprintf(Spec->StateList, "%s|", Spec->State[0]);
1973                Spec->N_States += 1;
1974             } else  {
1975                if (strcmp(Spec->StateList, Spec->State[0]) == 0) {
1976                   /* it's a duplicate, complain and get outa here */
1977                   fprintf( SUMA_STDERR,
1978                            "Error %s: Duplicate StateDef (%s).\n",
1979                            FuncName, Spec->State[0]);
1980                   SUMA_RETURN (NOPE);
1981                } else {
1982                   /* a new one, add it to the list and
1983                      increment States counter */
1984                   Spec->StateList =
1985                      SUMA_append_replace_string(
1986                            Spec->StateList, "|",
1987                            Spec->State[0], 1);
1988                   Spec->N_States += 1;
1989                }
1990             }
1991             Spec->State[0][0] = '\0';
1992             skp = 1;
1993          }
1994 
1995          sprintf(stmp,"Group");
1996          if (!skp && SUMA_iswordin (s, stmp) == 1) {
1997             /* found a group definition, parse it */
1998             if (LocalHead)
1999                fprintf(SUMA_STDERR,"%s: Found %s.\n", FuncName, stmp);
2000             if (Spec->N_Surfs < 1) { /* no surfaces have been defined yet,
2001                                         group goes for all */
2002                if (!SUMA_ParseLHS_RHS (
2003                      s, stmp,
2004                      Spec->Group[0])) {
2005                   fprintf( SUMA_STDERR,
2006                            "Error %s: Error in SUMA_ParseLHS_RHS.\n",
2007                            FuncName);
2008                   SUMA_RETURN (NOPE);
2009                }
2010             } else {
2011                if (!SUMA_ParseLHS_RHS (
2012                      s, stmp,
2013                      Spec->Group[Spec->N_Surfs-1])) {
2014                   fprintf( SUMA_STDERR,
2015                            "Error %s: Error in SUMA_ParseLHS_RHS.\n",
2016                            FuncName);
2017                   SUMA_RETURN (NOPE);
2018                }
2019             }
2020 
2021             if (Spec->N_Surfs < 1) Spec->N_Groups += 1;
2022             else {   /* recount groups */
2023                Spec->N_Groups = 1;
2024                for (kkk=0; kkk< Spec->N_Surfs -1; ++kkk) {
2025                   if (strcmp(Spec->Group[kkk], Spec->Group[0])) {
2026                      Spec->N_Groups += 1; /* Have new group */
2027                      break;
2028                   }
2029                }
2030             }
2031 
2032             if (!OKread_Group) {
2033                fprintf( SUMA_STDERR,"Error %s: %s %s\n",
2034                         FuncName, DupWarn, stmp);
2035                SUMA_RETURN (NOPE);
2036             } else {
2037                OKread_Group = NOPE;
2038             }
2039             skp = 1;
2040          }
2041 
2042          sprintf(stmp,"Anatomical");
2043          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2044             /* found Anatomically Correct field, parse it */
2045             if (!SUMA_ParseLHS_RHS (s, stmp,
2046                                     Spec->AnatCorrect[Spec->N_Surfs-1])) {
2047                fprintf( SUMA_STDERR,
2048                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2049                SUMA_RETURN (NOPE);
2050             }
2051             if (  strcmp(Spec->AnatCorrect[Spec->N_Surfs-1],"Y") &&
2052                   strcmp(Spec->AnatCorrect[Spec->N_Surfs-1],"N")) {
2053                SUMA_SL_Err("Anatomical can only be Y ot N");
2054                SUMA_RETURN (NOPE);
2055             }
2056             if (!OKread_AnatCorrect) {
2057                fprintf( SUMA_STDERR,"Error %s: %s %s\n",
2058                         FuncName, DupWarn, stmp);
2059                SUMA_RETURN (NOPE);
2060             } else  {
2061                OKread_AnatCorrect = NOPE;
2062             }
2063             skp = 1;
2064          }
2065 
2066          sprintf(stmp,"Hemisphere");
2067          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2068             /* found Hemisphere field, parse it */
2069             if (!SUMA_ParseLHS_RHS (
2070                      s, stmp,
2071                      Spec->Hemisphere[Spec->N_Surfs-1])) {
2072                fprintf(SUMA_STDERR,
2073                   "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2074                SUMA_RETURN (NOPE);
2075             }
2076             if (  strcmp(Spec->Hemisphere[Spec->N_Surfs-1],"L") &&
2077                   strcmp(Spec->Hemisphere[Spec->N_Surfs-1],"R") &&
2078                   strcmp(Spec->Hemisphere[Spec->N_Surfs-1],"B")) {
2079                SUMA_SL_Err("Hemisphere can only be L or R or B");
2080                SUMA_RETURN (NOPE);
2081             }
2082             if (!OKread_Hemisphere) {
2083                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2084                SUMA_RETURN (NOPE);
2085             } else  {
2086                OKread_Hemisphere = NOPE;
2087             }
2088             skp = 1;
2089          }
2090 
2091          sprintf(stmp,"DomainGrandParentID");
2092          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2093             /* found DomainGrandParentID field, parse it */
2094             if (!SUMA_ParseLHS_RHS (
2095                      s, stmp,
2096                      Spec->DomainGrandParentID[Spec->N_Surfs-1])) {
2097                fprintf( SUMA_STDERR,
2098                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2099                SUMA_RETURN (NOPE);
2100             }
2101 
2102             if (!OKread_DomainGrandParentID) {
2103                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2104                SUMA_RETURN (NOPE);
2105             } else  {
2106                OKread_DomainGrandParentID = NOPE;
2107             }
2108             skp = 1;
2109          }
2110 
2111          sprintf(stmp,"OriginatorID");
2112          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2113             /* found OriginatorID  field, parse it */
2114             if (!SUMA_ParseLHS_RHS (
2115                      s, stmp,
2116                      Spec->OriginatorID[Spec->N_Surfs-1])) {
2117                fprintf( SUMA_STDERR,
2118                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2119                SUMA_RETURN (NOPE);
2120             }
2121 
2122             if (!OKread_OriginatorID) {
2123                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2124                SUMA_RETURN (NOPE);
2125             } else  {
2126                OKread_OriginatorID = NOPE;
2127             }
2128             skp = 1;
2129          }
2130 
2131          sprintf(stmp,"LocalCurvatureParent");
2132          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2133             /* found LocalCurvatureParent  field, parse it */
2134             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
2135                fprintf( SUMA_STDERR,
2136                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2137                SUMA_RETURN (NOPE);
2138             }
2139             snprintf (Spec->LocalCurvatureParent[Spec->N_Surfs-1],
2140                         SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
2141                      "%s%s", Spec->SpecFilePath, stmp2);
2142 
2143             if (!OKread_LocalCurvatureParent) {
2144                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2145                SUMA_RETURN (NOPE);
2146             } else  {
2147                OKread_LocalCurvatureParent = NOPE;
2148             }
2149             skp = 1;
2150          }
2151 
2152          sprintf(stmp,"LocalDomainParent");
2153          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2154             /* found LocalDomainParent  field, parse it */
2155             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
2156                fprintf( SUMA_STDERR,
2157                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2158                SUMA_RETURN (NOPE);
2159             }
2160 
2161             snprintf (Spec->LocalDomainParent[Spec->N_Surfs-1],
2162                         SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
2163                "%s%s", Spec->SpecFilePath, stmp2);
2164 
2165             if (!OKread_LocalDomainParent) {
2166                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2167                SUMA_RETURN (NOPE);
2168             } else  {
2169                OKread_LocalDomainParent = NOPE;
2170             }
2171             skp = 1;
2172          }
2173 
2174          sprintf(stmp,"LabelDset");
2175          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2176             /* found LabelDset  field, parse it */
2177             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
2178                fprintf( SUMA_STDERR,
2179                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2180                SUMA_RETURN (NOPE);
2181             }
2182 
2183             snprintf (Spec->LabelDset[Spec->N_Surfs-1],
2184                         SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
2185                "%s%s", Spec->SpecFilePath, stmp2);
2186 
2187             if (!OKread_LabelDset) {
2188                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2189                SUMA_RETURN (NOPE);
2190             } else  {
2191                OKread_LabelDset = NOPE;
2192             }
2193             skp = 1;
2194          }
2195 
2196          sprintf(stmp,"NodeMarker");
2197          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2198             /* found NodeMarker  field, parse it */
2199             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
2200                fprintf( SUMA_STDERR,
2201                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2202                SUMA_RETURN (NOPE);
2203             }
2204 
2205             snprintf (Spec->NodeMarker[Spec->N_Surfs-1],
2206                         SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
2207                "%s%s", Spec->SpecFilePath, stmp2);
2208 
2209             if (!OKread_NodeMarker) {
2210                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2211                SUMA_RETURN (NOPE);
2212             } else  {
2213                OKread_NodeMarker = NOPE;
2214             }
2215             skp = 1;
2216          }
2217 
2218 
2219          sprintf(stmp,"EmbedDimension");
2220          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2221             /* found surface embedding dimension, parse it */
2222             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
2223                fprintf( SUMA_STDERR,
2224                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2225                SUMA_RETURN (NOPE);
2226             }
2227             Spec->EmbedDim[Spec->N_Surfs-1] = atoi(stmp2);
2228             if (  Spec->EmbedDim[Spec->N_Surfs-1] < 2 ||
2229                   Spec->EmbedDim[Spec->N_Surfs-1] > 3) {
2230                fprintf( SUMA_STDERR,
2231                         "Error %s: Bad Embedding dimension %d.\n"
2232                         "Only 2 and 3 allowed.\n",
2233                   FuncName, Spec->EmbedDim[Spec->N_Surfs-1]);
2234                SUMA_RETURN (NOPE);
2235             }
2236             if (!OKread_EmbedDim) {
2237                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2238                SUMA_RETURN (NOPE);
2239             } else  {
2240                OKread_EmbedDim = NOPE;
2241             }
2242             skp = 1;
2243          }
2244 
2245          sprintf(stmp,"SurfaceState");
2246          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2247             /* found surface state, parse it */
2248             if (!SUMA_ParseLHS_RHS (
2249                      s, stmp,
2250                      Spec->State[Spec->N_Surfs-1])) {
2251                fprintf( SUMA_STDERR,
2252                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2253                SUMA_RETURN (NOPE);
2254             }
2255             if (LHunify) {
2256                SUMA_LH_UNIFY_STATE_FIX(Spec->State[Spec->N_Surfs-1]);
2257             }
2258 
2259             /* make sure it is in the StateList */
2260             if (SUMA_iswordin (Spec->StateList, Spec->State[Spec->N_Surfs-1])
2261                 != 1) {
2262                fprintf( SUMA_STDERR,
2263                         "Error %s: State %s was not predefined in StateDef.\n"
2264                         "StateDef List (| delimited) = %s \n",\
2265                 FuncName, Spec->State[Spec->N_Surfs-1], Spec->StateList);
2266                SUMA_RETURN (NOPE);
2267             }
2268             if (!OKread_State) {
2269                fprintf( SUMA_STDERR,
2270                         "Error %s: %s %s\n", FuncName, DupWarn, stmp);
2271                SUMA_RETURN (NOPE);
2272             } else  {
2273                OKread_State = NOPE;
2274             }
2275             skp = 1;
2276          }
2277 
2278          sprintf(stmp,"SurfaceFormat");
2279          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2280             if (Spec->N_Surfs < 1) {
2281                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
2282                SUMA_RETURN (NOPE);
2283             }
2284             /*fprintf(SUMA_STDERR,"Found %s: ", stmp);*/
2285 
2286             if (!SUMA_ParseLHS_RHS (
2287                      s, stmp,
2288                      Spec->SurfaceFormat[Spec->N_Surfs-1])) {
2289                fprintf( SUMA_STDERR,
2290                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2291                SUMA_RETURN (NOPE);
2292             }
2293 
2294             if (!OKread_SurfaceFormat) {
2295                fprintf( SUMA_STDERR,
2296                         "Error %s: %s %s\n", FuncName, DupWarn, stmp);
2297                SUMA_RETURN (NOPE);
2298             } else {
2299                OKread_SurfaceFormat = NOPE;
2300             }
2301             skp = 1;
2302             /*fprintf(  SUMA_STDERR,"%s\n",
2303                         Spec->SurfaceFormat[Spec->N_Surfs-1]);*/
2304          }
2305 
2306          sprintf(stmp,"SurfaceType");
2307          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2308             if (Spec->N_Surfs < 1) {
2309                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
2310                SUMA_RETURN (NOPE);
2311             }
2312             /*fprintf(SUMA_STDERR,"Found %s\n", stmp);*/
2313             if (!SUMA_ParseLHS_RHS (
2314                      s, stmp,
2315                      Spec->SurfaceType[Spec->N_Surfs-1])) {
2316                fprintf( SUMA_STDERR,
2317                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2318                SUMA_RETURN (NOPE);
2319             }
2320             if (!OKread_SurfaceType) {
2321                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2322                SUMA_RETURN (NOPE);
2323             } else {
2324                OKread_SurfaceType = NOPE;
2325             }
2326             skp = 1;
2327          }
2328 
2329          sprintf(stmp,"TopoFile");
2330          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2331             /*fprintf(SUMA_STDERR,"Found %s\n", stmp);*/
2332             if (Spec->N_Surfs < 1) {
2333                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
2334                SUMA_RETURN (NOPE);
2335             }
2336             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
2337                fprintf( SUMA_STDERR,
2338                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2339                SUMA_RETURN (NOPE);
2340             }
2341             snprintf(Spec->TopoFile[Spec->N_Surfs-1],
2342                         SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
2343                "%s%s", Spec->SpecFilePath, stmp2);
2344 
2345             if (!OKread_TopoFile) {
2346                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2347                SUMA_RETURN (NOPE);
2348             } else {
2349                OKread_TopoFile = NOPE;
2350             }
2351             skp = 1;
2352          }
2353 
2354          sprintf(stmp,"SureFitTopo");
2355          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2356             /*fprintf(SUMA_STDERR,"Found %s\n", stmp);*/
2357             if (Spec->N_Surfs < 1) {
2358                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
2359                SUMA_RETURN (NOPE);
2360             }
2361             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
2362                fprintf( SUMA_STDERR,
2363                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2364                SUMA_RETURN (NOPE);
2365             }
2366             snprintf(Spec->TopoFile[Spec->N_Surfs-1],
2367                         SUMA_MAX_FP_NAME_LENGTH * sizeof(char),"%s%s",
2368                Spec->SpecFilePath, stmp2);
2369 
2370             if (!OKread_TopoFile) {
2371                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2372                SUMA_RETURN (NOPE);
2373             } else {
2374                OKread_TopoFile = NOPE;
2375             }
2376             skp = 1;
2377          }
2378 
2379          sprintf(stmp,"CoordFile");
2380          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2381             /*fprintf(SUMA_STDERR,"Found %s\n", stmp);*/
2382             if (Spec->N_Surfs < 1) {
2383                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
2384                SUMA_RETURN (NOPE);
2385             }
2386             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
2387                fprintf( SUMA_STDERR,
2388                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2389                SUMA_RETURN (NOPE);
2390             }
2391             snprintf (Spec->CoordFile[Spec->N_Surfs-1],
2392                         SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
2393                "%s%s", Spec->SpecFilePath, stmp2);
2394 
2395             if (!OKread_CoordFile) {
2396                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2397                SUMA_RETURN (NOPE);
2398             } else {
2399                OKread_CoordFile = NOPE;
2400             }
2401             skp = 1;
2402          }
2403 
2404          sprintf(stmp,"SureFitCoord");
2405          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2406             /*fprintf(SUMA_STDERR,"Found %s\n", stmp);*/
2407             if (Spec->N_Surfs < 1) {
2408                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
2409                SUMA_RETURN (NOPE);
2410             }
2411             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
2412                fprintf( SUMA_STDERR,
2413                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2414                SUMA_RETURN (NOPE);
2415             }
2416             snprintf (Spec->CoordFile[Spec->N_Surfs-1],
2417                         SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
2418                "%s%s", Spec->SpecFilePath, stmp2);
2419 
2420             if (!OKread_CoordFile) {
2421                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2422                SUMA_RETURN (NOPE);
2423             } else {
2424                OKread_CoordFile = NOPE;
2425             }
2426             skp = 1;
2427          }
2428 
2429          sprintf(stmp,"MappingRef");
2430          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2431             if (LocalHead)  fprintf(SUMA_STDERR,"Found %s\n", stmp);
2432             if (Spec->N_Surfs < 1) {
2433                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
2434                SUMA_RETURN (NOPE);
2435             }
2436             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
2437                fprintf( SUMA_STDERR,
2438                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2439                SUMA_RETURN (NOPE);
2440             }
2441             snprintf (Spec->MappingRef[Spec->N_Surfs-1],
2442                         SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
2443                "%s%s", Spec->SpecFilePath, stmp2);
2444             if (!OKread_MappingRef) {
2445                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2446                SUMA_RETURN (NOPE);
2447             } else {
2448                OKread_MappingRef = NOPE;
2449             }
2450             skp = 1;
2451          }
2452          /* Should become obsolete, ZSS Jan 02 03 */
2453 
2454          sprintf(stmp,"SureFitVolParam");
2455          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2456             if (LocalHead) fprintf(SUMA_STDERR,"Found %s\n", stmp);
2457             if (Spec->N_Surfs < 1) {
2458                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
2459                SUMA_RETURN (NOPE);
2460             }
2461             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
2462                fprintf( SUMA_STDERR,
2463                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2464                SUMA_RETURN (NOPE);
2465             }
2466             snprintf (Spec->SureFitVolParam[Spec->N_Surfs-1],
2467                         SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
2468                "%s%s", Spec->SpecFilePath, stmp2);
2469 
2470             if (!OKread_SureFitVolParam) {
2471                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2472                SUMA_RETURN (NOPE);
2473             } else {
2474                OKread_SureFitVolParam = NOPE;
2475             }
2476             skp = 1;
2477          }
2478 
2479          sprintf(stmp,"FreeSurferSurface");
2480          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2481             if (LocalHead) fprintf(SUMA_STDERR,"Found %s\n", stmp);
2482             if (Spec->N_Surfs < 1) {
2483                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
2484                SUMA_RETURN (NOPE);
2485             }
2486             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
2487                fprintf(SUMA_STDERR,
2488                   "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2489                SUMA_RETURN (NOPE);
2490             }
2491             snprintf (Spec->SurfaceFile[Spec->N_Surfs-1],
2492                       SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
2493                "%s%s", Spec->SpecFilePath, stmp2);
2494             if (!OKread_FreeSurferSurface) {
2495                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2496                SUMA_RETURN (NOPE);
2497             } else {
2498                OKread_FreeSurferSurface = NOPE;
2499             }
2500             skp = 1;
2501          }
2502 
2503          sprintf(stmp,"SurfaceName");
2504          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2505             if (LocalHead) fprintf(SUMA_STDERR,"Found %s\n", stmp);
2506             if (Spec->N_Surfs < 1) {
2507                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
2508                SUMA_RETURN (NOPE);
2509             }
2510             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
2511                fprintf( SUMA_STDERR,
2512                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2513                SUMA_RETURN (NOPE);
2514             }
2515             snprintf (Spec->SurfaceFile[Spec->N_Surfs-1],
2516                         SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
2517                "%s%s", Spec->SpecFilePath, stmp2);
2518             if (!OKread_FreeSurferSurface) {
2519                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2520                SUMA_RETURN (NOPE);
2521             } else {
2522                OKread_FreeSurferSurface = NOPE;
2523             }
2524             if (onGIFTIalert) {
2525                if (SUMA_isExtension(Spec->SurfaceFile[Spec->N_Surfs-1],".gii")) {
2526                   /* have gifti file with N27 spec, check gifti date */
2527                   if (THD_filetime_diff(Spec->SurfaceFile[Spec->N_Surfs-1],
2528                                         2013, 8, 1) < 0) {
2529                      SUMA_S_Warnv(
2530 "*******************************************************\n"
2531 "File %s is probably from SUMA's \n"
2532 "N27 GIFTI surfaces that are in RAI. With this new version\n"
2533 "of SUMA all GIFTI surfaces must be in LPI.\n"
2534 "\n"
2535 "You need to either correct these old surfaces or get\n"
2536 "a new copy of the template surface archives: \n"
2537 "   https://afni.nimh.nih.gov/pub/dist/tgz/suma_MNI_N27.tgz\n"
2538 "or\n"
2539 "   https://afni.nimh.nih.gov/pub/dist/tgz/suma_TT_N27.tgz\n"
2540 "or\n"
2541 "   https://afni.nimh.nih.gov/pub/dist/tgz/suma_MNI152_2009.tgz\n"
2542 "\n"
2543 "If you choose to correct what you have, instead of a new\n"
2544 "download, see the help for option -nocor in @SUMA_Make_Spec_FS \n"
2545 "for suggestions.\n"
2546 "\n"
2547 "Results obtained with older versions of SUMA on old GIFTI\n"
2548 "surfaces are valid. You just can't mix old files with \n"
2549 "versions of SUMA postdating Aug. 1st 2013\n"
2550 "As usual, if you have concerns, open surfaces in SUMA \n"
2551 "and talk to AFNI. If contours line up, you're OK.\n"
2552 "*******************************************************\n"
2553 "*******************************************************\n"
2554 "\n",
2555                       Spec->SurfaceFile[Spec->N_Surfs-1]);
2556 
2557                   }
2558                }
2559             }
2560             skp = 1;
2561          }
2562 
2563          sprintf(stmp,"InventorSurface");
2564          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2565             if (LocalHead) fprintf(SUMA_STDERR,"Found %s\n", stmp);
2566             if (Spec->N_Surfs < 1) {
2567                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
2568                SUMA_RETURN (NOPE);
2569             }
2570             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
2571                fprintf(SUMA_STDERR,
2572                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2573                SUMA_RETURN (NOPE);
2574             }
2575             snprintf(Spec->SurfaceFile[Spec->N_Surfs-1],
2576                      SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
2577                "%s%s", Spec->SpecFilePath, stmp2);
2578 
2579             if (!OKread_InventorSurface) {
2580                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2581                SUMA_RETURN (NOPE);
2582             } else {
2583                OKread_InventorSurface = NOPE;
2584             }
2585             skp = 1;
2586          }
2587 
2588          sprintf(stmp,"SurfaceVolume");
2589          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2590             if (LocalHead) fprintf(SUMA_STDERR,"Found %s\n", stmp);
2591             if (Spec->N_Surfs < 1) {
2592                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
2593                SUMA_RETURN (NOPE);
2594             }
2595             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
2596                fprintf(SUMA_STDERR,
2597                   "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2598                SUMA_RETURN (NOPE);
2599             }
2600 
2601             fprintf(SUMA_STDOUT,
2602                "Note %s: Found SurfaceVolume in Spec File, "
2603                "Name must include path to volume.\n", FuncName);
2604 
2605             sprintf(Spec->VolParName[Spec->N_Surfs-1], "%s",  stmp2);
2606 
2607             if (!OKread_SurfaceVolume) {
2608                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2609                SUMA_RETURN (NOPE);
2610             } else {
2611                OKread_SurfaceVolume = NOPE;
2612             }
2613             skp = 1;
2614          }
2615 
2616          sprintf(stmp,"SurfaceLabel");
2617          if (!skp && SUMA_iswordin (s, stmp) == 1) {
2618             if (LocalHead) fprintf(SUMA_STDERR,"Found %s\n", stmp);
2619             if (Spec->N_Surfs < 1) {
2620                fprintf(SUMA_STDERR,"Error %s: %s\n", FuncName, NewSurfWarn);
2621                SUMA_RETURN (NOPE);
2622             }
2623             if (!SUMA_ParseLHS_RHS (s, stmp, stmp2)) {
2624                fprintf( SUMA_STDERR,
2625                         "Error %s: Error in SUMA_ParseLHS_RHS.\n", FuncName);
2626                SUMA_RETURN (NOPE);
2627             }
2628 
2629             sprintf(Spec->SurfaceLabel[Spec->N_Surfs-1], "%s",  stmp2);
2630 
2631             if (!OKread_SurfaceLabel) {
2632                fprintf(SUMA_STDERR,"Error %s: %s %s\n", FuncName, DupWarn, stmp);
2633                SUMA_RETURN (NOPE);
2634             } else {
2635                OKread_SurfaceLabel = NOPE;
2636             }
2637             skp = 1;
2638          }
2639 
2640          if (!skp) {
2641             fprintf(SUMA_STDERR,
2642                "Error %s: Your spec file contains uncommented gibberish:\n"
2643                "  %s\n"
2644                "Please deal with it.\n",
2645             FuncName, s);
2646             SUMA_RETURN (NOPE);
2647          }
2648       } else {/* not not a comment */
2649          /*fprintf(SUMA_STDERR,"A comment: %s\n", s);*/
2650       }
2651 
2652       /* read the next line */
2653       do {
2654          ex = fscanf (sf_file,"%c",&c);
2655       } while (ex!=EOF && isspace(c));
2656       i=0;
2657       while (ex != EOF && c != '\n') {
2658          s[i] = c; ++i;
2659          ex = fscanf (sf_file,"%c",&c);
2660       }
2661       s[i] = '\0';
2662       if (LocalHead) fprintf(SUMA_STDERR,"Read %s\n", s);
2663    }
2664    fclose (sf_file);
2665    /* make sure last entry was good */
2666    if (Spec->SurfaceType[Spec->N_Surfs-1][0] == '\0') {
2667       fprintf( SUMA_STDERR,
2668                "Error %s: Failed to specify surface type for surface %d\n",
2669                FuncName, Spec->N_Surfs-1);
2670       SUMA_RETURN (NOPE);
2671    }
2672 
2673    if (!SUMA_CheckOnSpecFile (Spec)) {
2674       SUMA_SL_Err("Badness in the spec file.\n");
2675       SUMA_RETURN(NOPE);
2676    }
2677 
2678    SUMA_RETURN (YUP);
2679 }/* SUMA_Read_SpecFile */
2680 
2681 
2682 /*!
2683    \brief merge left and right side specfiles in a manner that suits AFNI
2684 */
2685 #define SUMA_COPY_SPEC_FIELD(trgspec, cnt, srcspec, isurf, fld) {  \
2686             if(srcspec->fld[isurf]) {\
2687                snprintf(trgspec->fld[cnt],   \
2688                      SUMA_MAX_FP_NAME_LENGTH * sizeof(char),\
2689                      "%s", srcspec->fld[isurf]); \
2690             } else { /* Should not happen */\
2691                fprintf(SUMA_STDERR, "** Error %s\n"  \
2692                                     "This should not be\n", FuncName);   \
2693             }  \
2694          }
SUMA_Merge_SpecFiles(SUMA_SurfSpecFile * lhs,SUMA_SurfSpecFile * rhs,SUMA_SurfSpecFile * bhs,char * FileName)2695 SUMA_Boolean SUMA_Merge_SpecFiles( SUMA_SurfSpecFile *lhs,
2696                                    SUMA_SurfSpecFile *rhs,
2697                                    SUMA_SurfSpecFile *bhs,
2698                                    char *FileName)
2699 {
2700    static char FuncName[]={"SUMA_Merge_SpecFiles"};
2701    SUMA_SurfSpecFile *vs[20];
2702    char *ss[20], *ns=NULL;
2703    int i, c, k;
2704    SUMA_Boolean LocalHead=NOPE;
2705 
2706    SUMA_ENTRY;
2707 
2708    if (!lhs || !rhs || !bhs ||
2709        (!lhs->N_Surfs && !rhs->N_Surfs) ) SUMA_RETURN(NOPE);
2710 
2711    SUMA_LH("Init");
2712    if (!SUMA_AllocSpecFields(bhs)) {
2713       SUMA_S_Err("Failed to init spec fields.");
2714       SUMA_RETURN(NOPE);
2715    }
2716 
2717    vs[0] = lhs;
2718    ss[0] = "_lh";
2719    vs[1] = rhs;
2720    ss[1] = "_rh";
2721 
2722    SUMA_LH("Check");
2723    /* checks */
2724    for (k=1; k<2; ++k) {
2725       if (strcmp(lhs->Group[0], rhs->Group[0])) {
2726          SUMA_S_Err("Not ready to merge different groups");
2727          SUMA_RETURN(NOPE);
2728       }
2729    }
2730 
2731 
2732    /* loop accross states and relabel non-anatomically correct states */
2733    c = 0;
2734    for (k=0; k<2; ++k) {
2735       for (i=0; i<vs[k]->N_Surfs; ++i) {
2736          SUMA_LHv("Copy vs[%d,%d]-->%d\n",k,i,c);
2737          SUMA_COPY_SPEC_FIELD(bhs, c, vs[k], i, SurfaceType);
2738          SUMA_COPY_SPEC_FIELD(bhs, c, vs[k], i, SurfaceFormat);
2739          SUMA_COPY_SPEC_FIELD(bhs, c, vs[k], i, TopoFile);
2740          SUMA_COPY_SPEC_FIELD(bhs, c, vs[k], i, CoordFile);
2741          SUMA_COPY_SPEC_FIELD(bhs, c, vs[k], i, MappingRef);
2742          SUMA_COPY_SPEC_FIELD(bhs, c, vs[k], i, SureFitVolParam);
2743          SUMA_COPY_SPEC_FIELD(bhs, c, vs[k], i, SurfaceFile);
2744          SUMA_COPY_SPEC_FIELD(bhs, c, vs[k], i, VolParName);
2745          bhs->IDcode[c] = vs[k]->IDcode[i];/* IDcode is a pointer copy */
2746          if (vs[k]->AnatCorrect[i][0] == 'N') {
2747             ns = SUMA_append_string(vs[k]->State[i],ss[k]);
2748             snprintf(bhs->State[c],
2749                      SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
2750                      "%s", ns); SUMA_free(ns); ns = NULL;
2751          } else {
2752             SUMA_COPY_SPEC_FIELD(bhs, c, vs[k], i, State);
2753          }
2754          SUMA_COPY_SPEC_FIELD(bhs, c, vs[k], i, LabelDset);
2755          SUMA_COPY_SPEC_FIELD(bhs, c, vs[k], i, NodeMarker);
2756          SUMA_COPY_SPEC_FIELD(bhs, c, vs[k], i, Group);
2757          if (strcmp(bhs->Group[0], vs[k]->Group[i])) {
2758             SUMA_S_Warn("Unexpected Group mismatch!\n"
2759                         "Assumption was that all surfs\n"
2760                         "in spec file are of the same group\n"
2761                         "Proceeding, beware.\n");
2762          }
2763          SUMA_COPY_SPEC_FIELD(bhs, c, vs[k], i, SurfaceLabel);
2764          bhs->EmbedDim[c] = vs[k]->EmbedDim[i];
2765          SUMA_COPY_SPEC_FIELD(bhs, c, vs[k], i, AnatCorrect);
2766          SUMA_COPY_SPEC_FIELD(bhs, c, vs[k], i, Hemisphere);
2767          SUMA_COPY_SPEC_FIELD(bhs, c, vs[k], i, DomainGrandParentID);
2768          SUMA_COPY_SPEC_FIELD(bhs, c, vs[k], i, OriginatorID);
2769          SUMA_COPY_SPEC_FIELD(bhs, c, vs[k], i, LocalCurvatureParent);
2770          SUMA_COPY_SPEC_FIELD(bhs, c, vs[k], i, LocalDomainParent);
2771          ++c;
2772       }
2773    }
2774 
2775    bhs->N_Surfs = c;
2776    bhs->N_Groups = 1;
2777 
2778    SUMA_LH("States");
2779    /* do the states */
2780    sprintf(bhs->StateList, "%s|", bhs->State[0]);
2781    bhs->N_States = 1;
2782    for (c=1; c<bhs->N_Surfs; ++c) {
2783       SUMA_LHv("Is %s in %s\n", bhs->State[c], bhs->StateList);
2784       if (!strstr(bhs->StateList, bhs->State[c])) {/* new one */
2785          SUMA_LH("            No");
2786          bhs->StateList =  SUMA_append_replace_string(bhs->StateList, "|",
2787                                                       bhs->State[c], 1);
2788          bhs->N_States += 1;
2789       }
2790    }
2791 
2792    snprintf(bhs->SpecFilePath,
2793             SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
2794             "%s", SUMA_FnameGet(FileName,"Pa", SUMAg_CF->cwd));
2795    snprintf(bhs->SpecFileName,
2796             SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
2797             "%s", SUMA_FnameGet(FileName,"f", SUMAg_CF->cwd));
2798 
2799 
2800    SUMA_RETURN(YUP);
2801 }
2802 
2803 /*!
2804    Remove surfaces of a certain state from the spec struct
2805    If ldp is not NULL, remove if both domain parent and the
2806    state match. ldp match is always partial.
2807 
2808    Returns the number of surfaces remaining in the spec struct
2809 */
SUMA_RemoveSpecState(SUMA_SurfSpecFile * Spec,char * state_rm,int exact_match,char * ldp)2810 int SUMA_RemoveSpecState(SUMA_SurfSpecFile  *Spec,
2811                          char *state_rm, int exact_match,
2812                          char *ldp)
2813 {
2814    static char FuncName[]={"SUMA_RemoveSpecState"};
2815    int i, k, copyit;
2816    SUMA_Boolean LocalHead = NOPE;
2817 
2818    SUMA_ENTRY;
2819 
2820    if (!Spec || !state_rm) SUMA_RETURN(0);
2821 
2822    k = 0;
2823    for (i=0; i<Spec->N_Surfs; ++i) {
2824       copyit = 1;
2825       if ( (exact_match == 0 &&  strstr(Spec->State[i],state_rm)) ||
2826            (exact_match == 1 && !strcmp(Spec->State[i],state_rm))) {
2827          /* found state to remove */
2828          copyit = 0;
2829          SUMA_LHv("Will remove %s\n", Spec->State[i]);
2830       }
2831       /* don't use exact match for Spec->LocalDomainParent[i],
2832          unless you account for the paths. "SAME" ends up being
2833          "./SAME", for example. */
2834       if (!copyit && ldp && !strstr(Spec->LocalDomainParent[i], ldp)) {
2835          /* no match for ldp, cancel */
2836          copyit = 1;
2837          SUMA_LHv("Canceling removal ldp is %s\n", Spec->LocalDomainParent[i]);
2838       }
2839       if ( copyit ) {
2840          SUMA_LHv("Working to copy state %s for surface i=%d k=%d\n",
2841                         Spec->State[i], i, k);
2842          if (k < i) {
2843          sprintf(Spec->State[k], "%s",Spec->State[i]);
2844          sprintf(Spec->SurfaceType[k], "%s",Spec->SurfaceType[i]);
2845          sprintf(Spec->SurfaceFormat[k], "%s",Spec->SurfaceFormat[i]);
2846          sprintf(Spec->TopoFile[k], "%s",Spec->TopoFile[i]);
2847          sprintf(Spec->CoordFile[k], "%s",Spec->CoordFile[i]);
2848          sprintf(Spec->MappingRef[k], "%s",Spec->MappingRef[i]);
2849          sprintf(Spec->SureFitVolParam[k], "%s",Spec->SureFitVolParam[i]);
2850          sprintf(Spec->SurfaceFile[k], "%s",Spec->SurfaceFile[i]);
2851          sprintf(Spec->VolParName[k], "%s",Spec->VolParName[i]);
2852          if (Spec->IDcode[i]) sprintf(Spec->IDcode[k], "%s",Spec->IDcode[i]);
2853          else Spec->IDcode[k]=NULL;
2854          sprintf(Spec->State[k], "%s",Spec->State[i]);
2855          sprintf(Spec->LabelDset[k], "%s",Spec->LabelDset[i]);
2856          sprintf(Spec->Group[k], "%s",Spec->Group[i]);
2857          sprintf(Spec->SurfaceLabel[k], "%s",Spec->SurfaceLabel[i]);
2858          Spec->EmbedDim[k] = Spec->EmbedDim[i];
2859          sprintf(Spec->AnatCorrect[k], "%s",Spec->AnatCorrect[i]);
2860          sprintf(Spec->Hemisphere[k], "%s",Spec->Hemisphere[i]);
2861          sprintf(Spec->DomainGrandParentID[k],
2862                                  "%s",Spec->DomainGrandParentID[i]);
2863          sprintf(Spec->OriginatorID[k], "%s",Spec->OriginatorID[i]);
2864          sprintf(Spec->LocalCurvatureParent[k],
2865                                  "%s",Spec->LocalCurvatureParent[i]);
2866          sprintf(Spec->LocalDomainParent[k], "%s",Spec->LocalDomainParent[i]);
2867          sprintf(Spec->NodeMarker[k], "%s",Spec->NodeMarker[i]);
2868          }
2869          ++k;
2870       }
2871    }
2872    if (k != Spec->N_Surfs) Spec->N_States = Spec->N_States-1;
2873    Spec->N_Surfs = k;
2874 
2875    SUMA_RETURN(k);
2876 }
2877 
2878 /*!
2879    \brief Write SUMA_SurfSpecFile  structure to disk
2880    \param Spec: Structure containing specfile
2881    \param specFileNm: Name of specfile.
2882                      If NULL, use
2883                       name in Spec->SpecFileName
2884    \param program: name of program to put in comments if not NULL
2885    \param histnote: a history note to add as comment if not NULL
2886 */
SUMA_Write_SpecFile(SUMA_SurfSpecFile * Spec,char * specFileNmU,char * program,char * histnote)2887 SUMA_Boolean SUMA_Write_SpecFile ( SUMA_SurfSpecFile * Spec,
2888                            char *specFileNmU,
2889                            char *program,
2890                            char *histnote) {
2891 
2892    static char FuncName[]={"SUMA_Write_SpecFile"};
2893    FILE *outFile=NULL;
2894    int i=0, k=0, tag=0, ifSmwm=0, p=0;
2895    char writename[SUMA_MAX_FILENAME_LENGTH+3]={""};
2896    char *specFileNm=NULL;
2897 
2898    SUMA_ENTRY;
2899 
2900    if (!Spec) SUMA_RETURN(NOPE);
2901 
2902 
2903    if (specFileNmU && specFileNmU[0]) {
2904       specFileNm = SUMA_Extension(specFileNmU, ".spec", NOPE);
2905       sprintf(writename,"%s",specFileNm);
2906    } else {
2907       if (!Spec->SpecFileName) SUMA_RETURN(NOPE);
2908       specFileNm = SUMA_Extension(Spec->SpecFileName, ".spec", NOPE);
2909       if (Spec->SpecFilePath) {
2910          sprintf( writename,
2911                   "%s/%s",
2912                   Spec->SpecFilePath,
2913                   specFileNm);
2914       } else {
2915          sprintf( writename,
2916                   "%s",
2917                   specFileNm);
2918       }
2919    }
2920    if (SUMA_filexists(writename) && !THD_ok_overwrite()) {
2921       SUMA_S_Errv("Spec file %s exists, will not overwrite\n", writename);
2922       SUMA_RETURN(NOPE);
2923    }
2924    if (specFileNm) SUMA_free(specFileNm); specFileNm = NULL;
2925 
2926    outFile = fopen(writename, "w");
2927 
2928    if (!outFile) {
2929       fprintf (SUMA_STDERR, "Failed in opening %s for writing.\n", writename);
2930       exit (1);
2931    }
2932    else {
2933       if (program && program[0])
2934          fprintf (outFile, "# %s generated spec file\n", program);
2935       if (histnote) fprintf (outFile, "#History: %s\n\n", histnote);
2936       else fprintf (outFile, "\n");
2937       fprintf (outFile, "#define the group\n\tGroup = %s\n\n", Spec->Group[0]);
2938       fprintf (outFile, "#define various States\n");
2939       for (i=0; i<Spec->N_Surfs; ++i) {
2940          tag = 0;
2941          for (k=0; k<i; ++k) {
2942             if ( strcmp( Spec->State[k], Spec->State[i] ) == 0 ) tag = -1;
2943          }
2944          if (tag==0) {
2945             fprintf( outFile, "\tStateDef = %s\n", Spec->State[i]);
2946          }
2947       }
2948 
2949       for (i=0; i<Spec->N_Surfs; ++i) {
2950          fprintf (outFile,
2951                   "\nNewSurface\n"
2952                   "\tSurfaceFormat = %s\n"
2953                   "\tSurfaceType = %s\n",
2954                   Spec->SurfaceFormat[i],
2955                   Spec->SurfaceType[i]);
2956          if (Spec->SurfaceFile[i][0]) {
2957             fprintf (outFile,
2958                      "\tSurfaceName = %s\n",
2959                      Spec->SurfaceFile[i] );
2960          } else {
2961             fprintf (outFile,
2962                      "\tCoordFile = %s\n",
2963                      Spec->CoordFile[i] );
2964             fprintf (outFile,
2965                      "\tTopoFile = %s\n",
2966                      Spec->TopoFile[i] );
2967          }
2968          if (Spec->SureFitVolParam[i][0]) {
2969             fprintf (outFile,
2970                      "\tSureFitVolParam = %s\n",
2971                      Spec->SureFitVolParam[i] );
2972          }
2973          if (Spec->LocalDomainParent[i][0]) {
2974             fprintf (outFile,
2975                      "\tLocalDomainParent = %s\n",
2976                    Spec->LocalDomainParent[i] );
2977          } else {
2978             fprintf (outFile,
2979                      "\tLocalDomainParent = SAME\n" );
2980          }
2981          if (Spec->LabelDset[i][0]) {
2982             fprintf (outFile,
2983                      "\tLabelDset = %s\n",
2984                    Spec->LabelDset[i] );
2985          } else {
2986          }
2987          if (Spec->NodeMarker[i][0]) {
2988             fprintf (outFile,
2989                      "\tNodeMarker = %s\n",
2990                    Spec->NodeMarker[i] );
2991          } else {
2992          }
2993          fprintf (outFile, "\tSurfaceState = %s\n"
2994                            "\tEmbedDimension = %d\n",
2995                            Spec->State[i], Spec->EmbedDim[i]);
2996 
2997          if (Spec->VolParName[i][0]) {
2998             fprintf (outFile,
2999                      "\tSurfaceVolume = %s\n",
3000                      Spec->VolParName[i] );
3001          }
3002          /* For now, only one group is allowed */
3003          if (  Spec->Group[i][0] && Spec->Group[0][0] &&
3004                strcmp(Spec->Group[i], Spec->Group[0])) {
3005             SUMA_S_Errv("SUMA does not read specfile with\n"
3006                         "surfaces from multiple groups yet\n"
3007                         "No point in trying to write that one.\n"
3008                         "Group[%d]=%s and Group[0]=%s\n"
3009                         , i, Spec->Group[i], Spec->Group[0]);
3010             SUMA_RETURN(NOPE);
3011             /* otherwise you just do:
3012                You can add this if all the groups are the same.
3013                SUMA will recognize that it is the same group and
3014                won't complain, but it might confuse the users*/
3015             if (Spec->Group[i][0]) {
3016                fprintf (outFile,
3017                         "\tGroup = %s\n",
3018                         Spec->Group[i] );
3019             }
3020          }
3021 
3022          if (Spec->SurfaceLabel[i][0]) {
3023             fprintf (outFile,
3024                      "\tSurfaceLabel = %s\n",
3025                      Spec->SurfaceLabel[i] );
3026          }
3027          if (Spec->AnatCorrect[i][0]) {
3028             fprintf (outFile,
3029                      "\tAnatomical = %s\n",
3030                      Spec->AnatCorrect[i] );
3031          }
3032          if (Spec->Hemisphere[i][0]) {
3033             fprintf (outFile,
3034                      "\tHemisphere = %s\n",
3035                      Spec->Hemisphere[i] );
3036          }
3037          if (Spec->DomainGrandParentID[i][0]) {
3038             fprintf (outFile,
3039                      "\tDomainGrandParentID = %s\n",
3040                      Spec->DomainGrandParentID[i] );
3041          }
3042          if (Spec->OriginatorID[i][0]) {
3043             fprintf (outFile,
3044                      "\tOriginatorID = %s\n",
3045                      Spec->OriginatorID[i] );
3046          }
3047          if (Spec->LocalCurvatureParent[i][0]) {
3048             fprintf (outFile,
3049                      "\tLocalCurvatureParent = %s\n",
3050                      Spec->LocalCurvatureParent[i] );
3051          }
3052 /*
3053          if (Spec->xxx[i][0]) {
3054             fprintf (outFile,
3055                      "\tyyy = %s\n",
3056                      Spec->xxx[i] );
3057          }
3058 */
3059       }
3060 
3061       fclose(outFile);
3062    }
3063    SUMA_RETURN(YUP);
3064 } /* SUMA_Write_SpecFile */
3065 
3066 /*!
3067    \brief more checksums on the contents of the specfile
3068 */
SUMA_CheckOnSpecFile(SUMA_SurfSpecFile * Spec)3069 SUMA_Boolean SUMA_CheckOnSpecFile (SUMA_SurfSpecFile *Spec)
3070 {
3071    static char FuncName[]={"SUMA_CheckOnSpecFile"};
3072    static int ob_warn = 0;
3073    int i;
3074    SUMA_Boolean LocalHead = NOPE;
3075 
3076    SUMA_ENTRY;
3077 
3078    if (Spec->N_Surfs == -1) {
3079       SUMA_S_Err("Struct fresh out of SUMA_AllocSpecFields");
3080       SUMA_RETURN(NOPE);
3081    }
3082 
3083    for (i=0; i<Spec->N_Surfs; ++i) {
3084       if (  Spec->MappingRef[i][0] &&
3085            (Spec->LocalDomainParent[i][0] ||
3086             Spec->LocalCurvatureParent[i][0] ||
3087             Spec->OriginatorID[i][0] ||
3088             Spec->DomainGrandParentID[i][0]) ) {
3089          SUMA_SL_Err("You cannont mix MappingRef with\n"
3090                      "newer fields such as:\n"
3091                      "LocalDomainParent, LocalCurvatureParent\n"
3092                      "OriginatorID or DomainGrandParentID  ");
3093          SUMA_RETURN(NOPE);
3094       }
3095       if (  Spec->MappingRef[i][0] ) {
3096 
3097          if (LocalHead && !ob_warn) {
3098             fprintf(SUMA_STDERR, "Warning:\n"
3099                                  "The field MappingRef in the spec file \n"
3100                                  "is obsolete. Consider replacing: \n"
3101                                  "  MappingRef = %s\n"
3102                                  "  with\n"
3103                                  "  LocalDomainParent = %s\n"
3104                                  "Similar warnings will be muted.\n",
3105                                  Spec->MappingRef[i], Spec->MappingRef[i]);
3106          }
3107          strcpy(Spec->LocalDomainParent[i], Spec->MappingRef[i]);
3108          strcpy(Spec->LocalCurvatureParent[i], Spec->MappingRef[i]);
3109          Spec->MappingRef[i][0] = '\0';
3110          ++ob_warn;
3111       }
3112       if ( strlen(Spec->LocalCurvatureParent[i]) ) {
3113          if ( ! strstr( Spec->LocalCurvatureParent[i],
3114                          Spec->LocalDomainParent[i]) ) {
3115             SUMA_SL_Err("Fields LocalCurvatureParent and LocalDomainParent \n"
3116                         "must be identical.\n");
3117             SUMA_RETURN(NOPE);
3118          }
3119       } else {
3120          sprintf( Spec->LocalCurvatureParent[i], "%s",
3121                   Spec->LocalDomainParent[i]);
3122       }
3123 
3124       if (strlen(Spec->LocalDomainParent[i]) &&
3125          SUMA_iswordsame(Spec->SurfaceFile[i],Spec->LocalDomainParent[i]) == 1){
3126          SUMA_LH("Make LDP be SAME");
3127          snprintf (Spec->LocalDomainParent[i],
3128                    SUMA_MAX_FP_NAME_LENGTH * sizeof(char),
3129                    "%s%s", Spec->SpecFilePath, "SAME");
3130       }
3131    }
3132 
3133    SUMA_RETURN(YUP);
3134 }
3135 
SUMA_ShowSpecStruct(SUMA_SurfSpecFile * Spec,FILE * Out,int detail)3136 SUMA_Boolean SUMA_ShowSpecStruct (SUMA_SurfSpecFile *Spec, FILE *Out, int detail)
3137 {
3138    static char FuncName[]={"SUMA_ShowSpecStruct"};
3139    FILE *Outp;
3140    char *s;
3141 
3142    SUMA_ENTRY;
3143 
3144    if (!Spec) {
3145       SUMA_SL_Err("NULL Spec");
3146       SUMA_RETURN(NOPE);
3147    }
3148 
3149    if (Spec->N_Surfs == -1) {
3150       SUMA_S_Err("Struct fresh out of SUMA_AllocSpecFields");
3151       SUMA_RETURN(NOPE);
3152    }
3153 
3154    if (!Out) Outp = stdout;
3155    else Outp = Out;
3156 
3157    s = SUMA_SpecStructInfo (Spec, detail);
3158 
3159    if (!s) {
3160       SUMA_SL_Err("Failed in   SUMA_SpecStructInfo");
3161       SUMA_RETURN(NOPE);
3162    }
3163 
3164    fprintf(Outp, "%s", s);
3165 
3166    SUMA_free(s); s = NULL;
3167 
3168    SUMA_RETURN(YUP);
3169 }
3170 /*!
3171    \brief show the contents of Spec structure
3172    ans = SUMA_ShowSpecStruct (Spec, Out, detail);
3173 
3174    \param Spec (SUMA_SurfSpecFile *)
3175    \param Out (FILE *)  Pointer to output file
3176                         If NULL then output is to stdout
3177    \param detail (int) 1:  only surface name or coord file
3178                            name if surface file is split to coord.
3179                            and topo. files
3180                        2:  surface name and BOTH coord and topo files
3181                            whenever applicable
3182                        3:  The whole nine yards.
3183    \return ans (YUP = good, NOPE = bad)
3184    \sa SUMA_Read_SpecFile
3185 */
SUMA_SpecStructInfo(SUMA_SurfSpecFile * Spec,int detail)3186 char* SUMA_SpecStructInfo (SUMA_SurfSpecFile *Spec, int detail)
3187 {
3188    static char FuncName[]={"SUMA_ShowSpecStructInfo"};
3189    char name_coord[SUMA_MAX_LABEL_LENGTH];
3190    char name_topo[SUMA_MAX_LABEL_LENGTH], *s = NULL;
3191    SUMA_STRING *SS = NULL;
3192    char stmp[1000];
3193    int i;
3194    SUMA_Boolean ShowCoord, ShowTopo, ShowRest;
3195 
3196    SUMA_ENTRY;
3197 
3198    ShowCoord = ShowTopo = ShowRest = NOPE;
3199 
3200    if (detail == 1) ShowCoord = YUP;
3201    else if (detail == 2) { ShowCoord = YUP; ShowTopo = YUP; }
3202    else if (detail == 3) { ShowCoord = YUP; ShowTopo = YUP; ShowRest = YUP; }
3203    else {
3204       SUMA_SL_Err("Bad value for detail, 0 < detail < 4");
3205       SUMA_RETURN(NULL);
3206    }
3207 
3208    SS = SUMA_StringAppend (NULL, NULL);
3209    if (Spec->N_Surfs == -1)
3210       SS = SUMA_StringAppend_va (SS,"Spec fresh out of SUMA_AllocSpecFields");
3211 
3212    if (Spec->SpecFilePath)
3213       SS = SUMA_StringAppend_va (SS,"SpecFilePath: %s\n", Spec->SpecFilePath);
3214    else SS = SUMA_StringAppend_va (SS,"SpecFilePath: NULL\n");
3215    if (Spec->SpecFileName)
3216       SS = SUMA_StringAppend_va (SS,"SpecFileName: %s\n", Spec->SpecFileName);
3217    else SS = SUMA_StringAppend_va (SS,"SpecFileName: NULL\n");
3218 
3219    if (!Spec->N_Surfs) {
3220       SS = SUMA_StringAppend (SS,"No surfaces in Spec.\n");
3221    } else {
3222 
3223       sprintf (stmp, "%d surfaces in Spec, %d defined states, %d groups\n",
3224                         Spec->N_Surfs, Spec->N_States, Spec->N_Groups);
3225       SS = SUMA_StringAppend (SS, stmp);
3226 
3227       for (i=0; i < Spec->N_Surfs; ++i) {
3228          name_coord[0] ='\0';
3229          name_topo[0] = '\0';
3230          if (  (SUMA_iswordin(Spec->SurfaceType[i], "SureFit") == 1) ||
3231                (SUMA_iswordin(Spec->SurfaceType[i], "1D") == 1)         ) {
3232             sprintf(name_coord, "%s ", Spec->CoordFile[i]);
3233             sprintf(name_topo,"%s ", Spec->TopoFile[i]);
3234          } else if ( (SUMA_iswordin(Spec->SurfaceType[i], "FreeSurfer") == 1) ||
3235                      (SUMA_iswordin(Spec->SurfaceType[i], "Ply") == 1)        ||
3236                      (SUMA_iswordin(Spec->SurfaceType[i], "GenericInventor") ==
3237                                                                            1) ||
3238                      (SUMA_iswordin(Spec->SurfaceType[i], "OpenDX") == 1) ) {
3239             sprintf(name_coord, "%s ", Spec->SurfaceFile[i]);
3240          }
3241          SS = SUMA_StringAppend_va (SS, "%d) ", i);/* print the index */
3242 
3243          if (ShowCoord)  SS = SUMA_StringAppend (SS, name_coord);
3244          if (ShowTopo &&name_topo[0]) SS = SUMA_StringAppend (SS,  name_topo);
3245          SS = SUMA_StringAppend (SS, "\n");
3246 
3247          if (ShowRest) {
3248             SS = SUMA_StringAppend_va (SS, "\tMappingRef: %s\n",
3249                                        Spec->MappingRef[i]);
3250                                           /* Should become obsolete,
3251                                              ZSS Jan 02 03 */
3252             SS = SUMA_StringAppend_va (SS,
3253                                        "\tType: %s\n",
3254                                        Spec->SurfaceType[i]);
3255             SS = SUMA_StringAppend_va (SS,
3256                                        "\tFormat: %s\n",
3257                                        Spec->SurfaceFormat[i]);
3258             SS = SUMA_StringAppend_va (SS,
3259                                        "\tEmbedDim: %d\n",
3260                                        Spec->EmbedDim[i]);
3261             SS = SUMA_StringAppend_va (SS,
3262                                        "\tState: %s, Group %s\n",
3263                                        Spec->State[i], Spec->Group[i]);
3264 
3265             if (strlen(Spec->SureFitVolParam[i])) {
3266                SS = SUMA_StringAppend_va (SS,
3267                                        "\tSureFitVolParam: %s\n",
3268                                        Spec->SureFitVolParam[i]);
3269             } else  SS = SUMA_StringAppend_va (SS,
3270                                        "\tSureFitVolParam: (empty)\n");
3271 
3272             if (strlen(Spec->VolParName[i]))  {
3273                SS = SUMA_StringAppend_va (SS,
3274                                        "\tVolParName: %s\n",
3275                                        Spec->VolParName[i]);
3276             } else SS = SUMA_StringAppend_va (SS,
3277                                        "\tVolParName: (empty)\n");
3278 
3279             if (Spec->IDcode[i])  {
3280                SS = SUMA_StringAppend_va (SS,
3281                                        "\tIDcode: %s\n",
3282                                        Spec->IDcode[i]);
3283             } else SS = SUMA_StringAppend_va (SS,
3284                                        "\tIDcode: (empty)\n");
3285 
3286             if (strlen(Spec->AnatCorrect[i])) {
3287                SS = SUMA_StringAppend_va (SS,
3288                                        "\tAnatCorrect: %s\n",
3289                                        Spec->AnatCorrect[i]);
3290             } else SS = SUMA_StringAppend_va (SS,
3291                                        "\tAnatCorrect: (empty)\n");
3292 
3293             if (strlen(Spec->Hemisphere[i])) {
3294                SS = SUMA_StringAppend_va (SS,
3295                                        "\tHemisphere: %s\n",
3296                                        Spec->Hemisphere[i]);
3297             } else SS = SUMA_StringAppend_va (SS,
3298                                        "\tHemisphere: (empty)\n");
3299 
3300             if (strlen(Spec->DomainGrandParentID[i])) {
3301                SS = SUMA_StringAppend_va (SS,
3302                                        "\tDomainGrandParentID: %s\n",
3303                                        Spec->DomainGrandParentID[i]);
3304             } else SS = SUMA_StringAppend_va (SS,
3305                                        "\tDomainGrandParentID: (empty)\n");
3306 
3307             if (strlen(Spec->OriginatorID[i])) {
3308                SS = SUMA_StringAppend_va (SS,
3309                                        "\tOriginatorID: %s\n",
3310                                        Spec->OriginatorID[i]);
3311             } else SS = SUMA_StringAppend_va (SS,
3312                                        "\tOriginatorID: (empty)\n");
3313 
3314             if (strlen(Spec->LocalCurvatureParent[i])) {
3315                SS = SUMA_StringAppend_va (SS,
3316                                        "\tLocalCurvatureParent: %s\n",
3317                                        Spec->LocalCurvatureParent[i]);
3318             } else SS = SUMA_StringAppend_va (SS,
3319                                        "\tLocalCurvatureParent: (empty)\n");
3320 
3321             if (strlen(Spec->LocalDomainParent[i])) {
3322                SS = SUMA_StringAppend_va (SS,
3323                                        "\tLocalDomainParent: %s\n",
3324                                        Spec->LocalDomainParent[i]);
3325             } else SS = SUMA_StringAppend_va (SS,
3326                                        "\tLocalDomainParent: (empty)\n");
3327 
3328             if (strlen(Spec->LabelDset[i])) {
3329                SS = SUMA_StringAppend_va (SS,
3330                                        "\tLabelDset: %s\n",
3331                                        Spec->LabelDset[i]);
3332             } else SS = SUMA_StringAppend_va (SS,
3333                                        "\tLabelDset: (empty)\n");
3334 
3335             if (strlen(Spec->NodeMarker[i])) {
3336                SS = SUMA_StringAppend_va (SS,
3337                                        "\tNodeMarker: %s\n",
3338                                        Spec->NodeMarker[i]);
3339             } else SS = SUMA_StringAppend_va (SS,
3340                                        "\tNodeMarker: (empty)\n");
3341             /*
3342             if (strlen(Spec->[i])) {
3343                SS = SUMA_StringAppend_va (SS,
3344                                        "\t: %s\n",
3345                                        Spec->[i]);
3346             } else SS = SUMA_StringAppend_va (SS, "\t: (empty)\n");
3347             */
3348          }
3349       }
3350    }
3351 
3352    /* clean SS */
3353    SS = SUMA_StringAppend (SS, NULL);
3354    /* copy s pointer and free SS */
3355    s = SS->s;
3356    SUMA_free(SS);
3357 
3358    SUMA_RETURN (s);
3359 }
3360 
3361 /*!
3362    \brief loads a surface object specified in Spec[i]
3363 
3364    - NOTABLE SO fields filled in this function are:
3365    SO->NodeList, SO->N_NodeList, SO->FaceSetList, SO->N_FaceSet
3366    SO->Group, SO->idcode_str,
3367    SO->State
3368    SO->EmbedDim
3369    SO->Side
3370    SO->OriginatorID
3371    SO->DomainGrandParentID
3372    SO->LocalCurvatureParent
3373    SO->LocalDomainParent
3374    SO->AnatCorrect
3375    SO->SpecFile
3376    \returns SO (SUMA_SurfaceObject *)
3377 */
SUMA_Load_Spec_Surf(SUMA_SurfSpecFile * Spec,int i,char * tmpVolParName,int debug)3378 SUMA_SurfaceObject * SUMA_Load_Spec_Surf(
3379                            SUMA_SurfSpecFile *Spec,
3380                            int i,
3381                            char *tmpVolParName,
3382                            int debug)
3383 {  /* start SUMA_Load_Spec_Surf */
3384    static char FuncName[]={"SUMA_Load_Spec_Surf"};
3385    SUMA_SFname *SF_name;
3386    SUMA_SurfaceObject *SO=NULL;
3387    SUMA_Boolean brk, SurfIn=NOPE;
3388    SUMA_Boolean LocalHead = NOPE;
3389 
3390    SUMA_ENTRY;
3391 
3392    brk = NOPE;
3393 
3394    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "SureFit") == 1) {
3395       /* load surefit surface */
3396       SF_name = (SUMA_SFname *) SUMA_malloc(sizeof(SUMA_SFname));
3397       sprintf(SF_name->name_coord,"%s", Spec->CoordFile[i]);
3398       sprintf(SF_name->name_topo,"%s", Spec->TopoFile[i]);
3399       if (!strlen(Spec->SureFitVolParam[i])) { /* initialize to empty string */
3400          SF_name->name_param[0] = '\0';
3401       } else {
3402          sprintf(SF_name->name_param,"%s", Spec->SureFitVolParam[i]);
3403       }
3404 
3405       /* Load The Surface */
3406       if (SUMA_iswordin(Spec->SurfaceFormat[i], "ASCII") == 1) {
3407          SO = SUMA_Load_Surface_Object_eng ( (void *)SF_name, SUMA_SUREFIT,
3408                                              SUMA_ASCII, tmpVolParName, debug);
3409       } else {
3410          fprintf( SUMA_STDERR,
3411                   "Error %s: Only ASCII surfaces can be read for now.\n",
3412                   FuncName);
3413          SUMA_RETURN (NULL);
3414       }
3415       if (SO == NULL)   {
3416          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
3417          SUMA_RETURN(NULL);
3418       }
3419 
3420       SUMA_free(SF_name);
3421 
3422       SurfIn = YUP;
3423       brk = YUP;
3424    }/* load surefit surface */
3425 
3426    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "1D") == 1) {
3427       /* load 1D surface */
3428       SF_name = (SUMA_SFname *) SUMA_malloc(sizeof(SUMA_SFname));
3429       sprintf(SF_name->name_coord,"%s", Spec->CoordFile[i]); ;
3430       sprintf(SF_name->name_topo,"%s", Spec->TopoFile[i]);
3431       SF_name->name_param[0] = '\0';
3432 
3433 
3434       /* Load The Surface */
3435       if (SUMA_iswordin(Spec->SurfaceFormat[i], "ASCII") == 1) {
3436          SO = SUMA_Load_Surface_Object_eng ((void *)SF_name, SUMA_VEC,
3437                                              SUMA_ASCII, tmpVolParName, debug);
3438       } else {
3439          fprintf( SUMA_STDERR,
3440                   "Error %s: Only ASCII allowed for 1D files.\n", FuncName);
3441          SUMA_RETURN (NULL);
3442       }
3443       if (SO == NULL)   {
3444          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
3445          SUMA_RETURN(NULL);
3446       }
3447 
3448       SUMA_free(SF_name);
3449 
3450       SurfIn = YUP;
3451       brk = YUP;
3452    }/* load 1D surface */
3453 
3454    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "FreeSurfer") == 1) {
3455       /* load FreeSurfer surface */
3456       if (SUMA_iswordin(Spec->SurfaceFormat[i], "ASCII") == 1)
3457          SO = SUMA_Load_Surface_Object_eng ( (void *)Spec->SurfaceFile[i],
3458                                              SUMA_FREE_SURFER, SUMA_ASCII,
3459                                              tmpVolParName, debug);
3460       else if (SUMA_iswordin(Spec->SurfaceFormat[i], "BINARY") == 1)
3461          SO = SUMA_Load_Surface_Object_eng ( (void *)Spec->SurfaceFile[i],
3462                                              SUMA_FREE_SURFER, SUMA_BINARY_BE,
3463                                              tmpVolParName, debug);
3464       if (SO == NULL)   {
3465          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
3466          SUMA_RETURN(NULL);
3467       }
3468       SurfIn = YUP;
3469       brk = YUP;
3470    } /* load FreeSurfer surface */
3471 
3472    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "Ply") == 1) {
3473       /* load Ply format surface */
3474       SO = SUMA_Load_Surface_Object_eng ( (void *)Spec->SurfaceFile[i], SUMA_PLY,
3475       SUMA_FF_NOT_SPECIFIED, tmpVolParName, debug);
3476 
3477       if (SO == NULL)   {
3478          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
3479          SUMA_RETURN(NULL);
3480       }
3481       SurfIn = YUP;
3482       brk = YUP;
3483    } /* load Ply format surface */
3484 
3485    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "STL") == 1) {
3486       /* load STL format surface */
3487       SO = SUMA_Load_Surface_Object_eng ( (void *)Spec->SurfaceFile[i], SUMA_STL,                                           SUMA_FF_NOT_SPECIFIED, tmpVolParName,
3488                                           debug);
3489 
3490       if (SO == NULL)   {
3491          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
3492          SUMA_RETURN(NULL);
3493       }
3494       SurfIn = YUP;
3495       brk = YUP;
3496    } /* load STL format surface */
3497 
3498    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "MNI") == 1) {
3499       /* load MNI_OBJ format surface */
3500 
3501       SO = SUMA_Load_Surface_Object_eng ((void *)Spec->SurfaceFile[i],
3502                                           SUMA_MNI_OBJ, SUMA_ASCII,
3503                                           tmpVolParName, debug);
3504 
3505       if (SO == NULL)   {
3506          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
3507          SUMA_RETURN(NULL);
3508       }
3509       SurfIn = YUP;
3510       brk = YUP;
3511    } /* load MNI_OBJ format surface */
3512 
3513    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "OpenDX") == 1) {
3514       SO = SUMA_Load_Surface_Object_eng ((void *)Spec->SurfaceFile[i],
3515                         SUMA_OPENDX_MESH, SUMA_ASCII, tmpVolParName, debug);
3516 
3517       if (SO == NULL)   {
3518          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
3519          SUMA_RETURN(NULL);
3520       }
3521       SurfIn = YUP;
3522       brk = YUP;
3523    } /* load OpenDX format surface */
3524 
3525    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "OBJ") == 1) {
3526       SO = SUMA_Load_Surface_Object_eng ((void *)Spec->SurfaceFile[i],
3527                         SUMA_OBJ_MESH, SUMA_ASCII, tmpVolParName, debug);
3528 
3529       if (SO == NULL)   {
3530          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
3531          SUMA_RETURN(NULL);
3532       }
3533       SurfIn = YUP;
3534       brk = YUP;
3535    } /* load OBJ_MESH format surface */
3536 
3537 
3538    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "Predefined") == 1) {
3539 
3540       SO = SUMA_Load_Surface_Object_eng ((void *)Spec->SurfaceFile[i],
3541                      SUMA_PREDEFINED, SUMA_ASCII, tmpVolParName, debug);
3542       if (SO == NULL)   {
3543          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
3544          SUMA_RETURN(NULL);
3545       }
3546       SurfIn = YUP;
3547       brk = YUP;
3548    }
3549 
3550    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "BrainVoyager") == 1) {
3551       /* load BrainVoyager format surface */
3552       SO = SUMA_Load_Surface_Object_eng ( (void *)Spec->SurfaceFile[i],
3553                                           SUMA_BRAIN_VOYAGER,
3554                                           SUMA_FF_NOT_SPECIFIED, tmpVolParName,
3555                                           debug);
3556 
3557       if (SO == NULL)   {
3558          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
3559          SUMA_RETURN(NULL);
3560       }
3561       SurfIn = YUP;
3562       brk = YUP;
3563    } /* load bv format surface */
3564 
3565    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "BYU") == 1) {
3566          /* load BYU format surface */
3567       SO = SUMA_Load_Surface_Object_eng ( (void *)Spec->SurfaceFile[i], SUMA_BYU,
3568                                           SUMA_FF_NOT_SPECIFIED, tmpVolParName,
3569                                           debug);
3570 
3571       if (SO == NULL)   {
3572          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
3573          SUMA_RETURN(NULL);
3574       }
3575       SurfIn = YUP;
3576       brk = YUP;
3577    } /* load byu format surface */
3578 
3579    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "GIFTI") == 1) {
3580       /* load GIFTI format surface */
3581       SO = SUMA_Load_Surface_Object_eng (
3582                (void *)Spec->SurfaceFile[i], SUMA_GIFTI,
3583                SUMA_FF_NOT_SPECIFIED, tmpVolParName, debug);
3584 
3585       if (SO == NULL)   {
3586          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
3587          SUMA_RETURN(NULL);
3588       }
3589       SurfIn = YUP;
3590       brk = YUP;
3591    } /* load gifti format surface */
3592 
3593    if (!brk && SUMA_iswordin(Spec->SurfaceType[i], "GenericInventor") == 1) {
3594                      /* load generic inventor format surface */
3595       if (tmpVolParName != NULL) {
3596          fprintf( SUMA_STDERR,
3597                   "Error %s: Sorry, but Parent volumes "
3598                   "are not supported for generic inventor surfaces.\n",
3599                   FuncName);
3600          SUMA_RETURN (NULL);
3601       }
3602       if (SUMA_iswordin(Spec->SurfaceFormat[i], "ASCII") == 1)
3603          SO = SUMA_Load_Surface_Object_eng ( (void *)Spec->SurfaceFile[i],
3604                                              SUMA_INVENTOR_GENERIC, SUMA_ASCII,
3605                                              NULL, debug);
3606       else {
3607          fprintf( SUMA_STDERR,
3608                   "Error %s: Only ASCII surfaces can be read for now.\n",
3609                   FuncName);
3610          SUMA_RETURN(NULL);
3611       }
3612       if (SO == NULL)   {
3613          fprintf(SUMA_STDERR,"Error %s: could not load SO\n", FuncName);
3614          SUMA_RETURN(NULL);
3615       }
3616       SurfIn = YUP;
3617 
3618       brk = YUP;
3619    }
3620 
3621    if (!brk) {
3622       fprintf( SUMA_STDERR,
3623                "Error %s: Unknown SurfaceFormat %s.\n"
3624                "(Format syntax is case sensitive)\n",
3625                FuncName, Spec->SurfaceType[i]);
3626       SUMA_RETURN(NULL);
3627    }
3628 
3629    if (!SurfIn) {
3630       fprintf(SUMA_STDERR,"Error %s: Failed to read input surface.\n", FuncName);
3631       SUMA_RETURN(NULL);
3632    }
3633 
3634    /* assign its Group and State and Side*/
3635    SUMA_LHv("Assigning group %s , state %s, and EmbedDim %d\n",
3636             Spec->Group[i], Spec->State[i], Spec->EmbedDim[i]);
3637    SO->Group = (char *)SUMA_calloc(strlen(Spec->Group[i])+1, sizeof(char));
3638    SO->State = (char *)SUMA_calloc(strlen(Spec->State[i])+1, sizeof(char));
3639    if (Spec->SurfaceLabel[i][0] == '\0') {
3640       if (!(SO->Label = SUMA_SurfaceFileName (SO, NOPE))) {
3641          SO->Label = SUMA_copy_string("Who_Am_I");
3642       }
3643    } else {
3644       SO->Label = SUMA_copy_string(Spec->SurfaceLabel[i]);
3645    }
3646 
3647    if (SO->isSphere == SUMA_GEOM_NOT_SET) {
3648       SUMA_SetSphereParams(SO, -0.1);   /* sets the spheriosity parameters */
3649    }
3650 
3651    if (!SO->Group || !SO->State || !SO->Label) {
3652       fprintf(SUMA_STDERR,"Error %s: Error allocating lameness.\n", FuncName);
3653       SUMA_RETURN (NULL);
3654    }
3655 
3656    SO->Group = strcpy(SO->Group, Spec->Group[i]);
3657    SO->State = strcpy(SO->State, Spec->State[i]);
3658    SO->EmbedDim = Spec->EmbedDim[i];
3659    if (Spec->Hemisphere[i][0] == 'L') {
3660       SO->Side = SUMA_LEFT;
3661    } else if (Spec->Hemisphere[i][0] == 'R') {
3662       SO->Side = SUMA_RIGHT;
3663    } else if (Spec->Hemisphere[i][0] == 'B') {
3664       SO->Side = SUMA_LR;
3665    } else SO->Side = SUMA_GuessSide (SO);
3666 
3667 
3668    if (Spec->OriginatorID[i][0])
3669       SO->OriginatorID = SUMA_copy_string(Spec->OriginatorID[i]);
3670    if (Spec->DomainGrandParentID[i][0])
3671       SO->DomainGrandParentID = SUMA_copy_string(Spec->DomainGrandParentID[i]);
3672    if (Spec->LocalCurvatureParent[i][0])
3673       SO->LocalCurvatureParent = SUMA_copy_string(Spec->LocalCurvatureParent[i]);
3674    if (Spec->LocalDomainParent[i][0])
3675       SO->LocalDomainParent = SUMA_copy_string(Spec->LocalDomainParent[i]);
3676    if (Spec->AnatCorrect[i][0] == '\0')
3677       Spec->AnatCorrect[i][0] = SUMA_GuessAnatCorrect(SO);
3678    SO->AnatCorrect = NOPE;
3679    if (Spec->AnatCorrect[i][0] == 'Y')  SO->AnatCorrect = YUP;
3680    else SO->AnatCorrect = NOPE;
3681 
3682    if (Spec->SpecFilePath)
3683       SO->SpecFile.Path = SUMA_copy_string(Spec->SpecFilePath);
3684    if (Spec->SpecFileName)
3685       SO->SpecFile.FileName = SUMA_copy_string(Spec->SpecFileName);
3686 
3687    SUMA_RETURN(SO);
3688 
3689 } /* end SUMA_Load_Spec_Surf */
3690 
SUMA_Load_Spec_Surf_with_Metrics(SUMA_SurfSpecFile * Spec,int i,char * tmpVolParName,int debug)3691 SUMA_SurfaceObject * SUMA_Load_Spec_Surf_with_Metrics(
3692                            SUMA_SurfSpecFile *Spec,
3693                            int i,
3694                            char *tmpVolParName,
3695                            int debug)
3696 {
3697    static char FuncName[]={"SUMA_Load_Spec_Surf_with_Metrics"};
3698    SUMA_SurfaceObject *SO=NULL;
3699 
3700    SUMA_ENTRY;
3701 
3702    if (!Spec) SUMA_RETURN(SO);
3703 
3704    if (!(SO = SUMA_Load_Spec_Surf(Spec, i, tmpVolParName, debug))) {
3705       SUMA_S_Errv("Failed to find surface %s %s.\n",
3706            SPEC_NAME_DBG(Spec,i), SPEC_TOPO_DBG(Spec,i));
3707       SUMA_RETURN(SO);
3708    }
3709 
3710    if (!SO->EL) SUMA_SurfaceMetrics_eng(SO, "EdgeList", NULL, debug,
3711                                           SUMAg_CF->DsetList);
3712    if (!SO->MF) SUMA_SurfaceMetrics_eng(SO, "MemberFace", NULL, debug,
3713                                           SUMAg_CF->DsetList);
3714    if (!SO->Label && !(SO->Label = SUMA_SurfaceFileName(SO, NOPE))) {
3715       SO->Label = SUMA_copy_string("A_Horse_With_No_Name");
3716    }
3717 
3718    SUMA_RETURN(SO);
3719 }
3720 
3721 /*!
3722    Take a mappable SO , loaded as it would be out of, say, SUMA_Load_Spec_Surf,
3723    find its metrics, initialize suma structures and add it to DOv
3724 */
SUMA_PrepAddmappableSO(SUMA_SurfaceObject * SO,SUMA_DO * dov,int * N_dov,int debug,DList * DsetList)3725 SUMA_Boolean SUMA_PrepAddmappableSO(SUMA_SurfaceObject *SO, SUMA_DO *dov,
3726                                     int *N_dov, int debug, DList *DsetList)
3727 { /* begin SUMA_PrepAddmappableSO */
3728    static char FuncName[]={"SUMA_PrepAddmappableSO"};
3729    SUMA_OVERLAYS *NewColPlane=NULL;
3730    SUMA_Boolean SurfIn = NOPE;
3731    char DoThis[100];
3732    SUMA_Boolean LocalHead = NOPE;
3733 
3734    SUMA_ENTRY;
3735 
3736    SurfIn = YUP;
3737 
3738    /* set its MappingRef id to its own */
3739       SO->LocalDomainParentID = (char *)SUMA_calloc(  strlen(SO->idcode_str)+1,
3740                                                       sizeof(char));
3741       if (SO->LocalDomainParentID == NULL) {
3742          fprintf( SUMA_STDERR,
3743                   "Error %s: Failed to allocate for SO->LocalDomainParentID. \n"
3744                   "That is pretty bad.\n", FuncName);
3745          SUMA_RETURN (NOPE);
3746       }
3747       SO->LocalDomainParentID = strcpy(SO->LocalDomainParentID, SO->idcode_str);
3748 
3749 
3750    /* if the surface is loaded OK, and it has not been loaded
3751       previously, register it */
3752    if (SurfIn) {
3753       sprintf(DoThis,"Convexity");
3754       if (!SO->EL || !SO->FN) strcat(DoThis,", EdgeList");
3755       if (!SO->MF) strcat(DoThis,", MemberFace");
3756       if (!SUMA_SurfaceMetrics_eng (SO, DoThis, NULL, debug, DsetList)) {
3757          fprintf (SUMA_STDERR,
3758                   "Error %s: Failed in SUMA_SurfaceMetrics.\n", FuncName);
3759          SUMA_RETURN (NOPE);
3760       }
3761 
3762       #if SUMA_CHECK_WINDING
3763       /* if you have surfaces that are not consistent,
3764          you should fix them ahead of time
3765          because orientation affects calculations of normals,
3766          areas (signed), convexity
3767          etc.... */
3768       if (!SUMA_SurfaceMetrics_eng (SO, "CheckWind", NULL, debug, DsetList)) {
3769          fprintf (SUMA_STDERR,
3770                   "Error %s: Failed in SUMA_SurfaceMetrics.\n", FuncName);
3771          SUMA_RETURN (NOPE);
3772       }
3773       #endif
3774 
3775       /* Store it into dov, if not there already */
3776       if (SUMA_whichDO(SO->idcode_str, dov, *N_dov) < 0) {
3777          if (!SUMA_AddDO(dov, N_dov, (void *)SO,  SO_type, SUMA_WORLD)) {
3778             fprintf(SUMA_STDERR,"Error %s: Error Adding DO\n", FuncName);
3779             SUMA_RETURN(NOPE);
3780          }
3781       }
3782 
3783       /* create the surface controller */
3784       if (!SO->SurfCont) {
3785          SO->SurfCont = SUMA_CreateSurfContStruct(SO->idcode_str, SO_type);
3786       } else {
3787          SUMA_S_Note("Surface Controller Exists Already.");
3788       }
3789 
3790       {
3791          SUMA_DSET *dset=NULL;/* create the color plane for Convexity*/
3792 
3793        /* create an overlay plane */
3794          if (!(dset = (SUMA_DSET *)SUMA_GetCx(SO->idcode_str, DsetList, 1))) {
3795             SUMA_SL_Err("Failed to find dset!");
3796             SUMA_RETURN (NOPE);
3797          }
3798          NewColPlane = SUMA_CreateOverlayPointer ("Convexity", dset,
3799                                                   SO->idcode_str, NULL);
3800          if (!NewColPlane) {
3801             fprintf (SUMA_STDERR,
3802                      "Error %s: Failed in SUMA_CreateOverlayPointer.\n",
3803                      FuncName);
3804             SUMA_RETURN (NOPE);
3805          }
3806          /* Add this plane to SO->Overlays */
3807          if (!SUMA_AddNewPlane ((SUMA_ALL_DO *)SO, NewColPlane, NULL, -1, 1)) {
3808             /* duplicate planes will be ignored! */
3809             SUMA_SL_Err("Failed in SUMA_AddNewPlane");
3810             SUMA_FreeOverlayPointer(NewColPlane);
3811             SUMA_RETURN (NOPE);
3812          }
3813          if (!SUMAg_CF->scm) {
3814             SUMAg_CF->scm = SUMA_Build_Color_maps();
3815             if (!SUMAg_CF->scm) {
3816                SUMA_SL_Err("Failed to build color maps.\n");
3817                SUMA_RETURN(NOPE);
3818             }
3819          }
3820 
3821         if (!SUMA_SetConvexityPlaneDefaults(SO, DsetList)) {
3822             SUMA_SL_Err("Failed to set plane defaults."); SUMA_RETURN(NOPE);
3823          }
3824 
3825          /* colorize the plane */
3826          SUMA_ColorizePlane(NewColPlane);
3827 
3828          /* set current plane to it, if none are set */
3829          if (SO->SurfCont && !SO->SurfCont->curColPlane) {
3830             SO->SurfCont->curColPlane = NewColPlane;
3831          }
3832       }
3833 
3834       /* Create a Mesh Axis for the surface */
3835       SO->MeshAxis = SUMA_Alloc_Axis ("Surface Mesh Axis", AO_type);
3836       if (SO->MeshAxis == NULL) {
3837          fprintf(SUMA_STDERR,"Error %s: Error Allocating axis\n", FuncName);
3838          SUMA_RETURN(NOPE);
3839       }
3840       /* Change the defaults of Mesh axis to fit standard  */
3841       /* For the moment, use Box Axis */
3842       SO->MeshAxis->atype = SUMA_SCALE_BOX;
3843 
3844       SUMA_MeshAxisStandard (SO->MeshAxis, (SUMA_ALL_DO *)SO);
3845       /*turn on the viewing for the axis */
3846 
3847       SO->ShowMeshAxis = NOPE;
3848 
3849 
3850    }
3851 
3852    SUMA_RETURN(YUP);
3853 
3854 } /* end SUMA_PrepAddmappableSO */
3855 
3856 
SUMA_Load_SO_NodeMarker(SUMA_SurfaceObject * SO,char * NodeMarker)3857 SUMA_Boolean SUMA_Load_SO_NodeMarker(SUMA_SurfaceObject *SO,
3858                                      char *NodeMarker)
3859 {
3860    static char FuncName[]={"SUMA_Load_SO_NodeMarker"};
3861    SUMA_NIDO *nido=NULL;
3862    int i=0;
3863    SUMA_Boolean LocalHead = NOPE;
3864 
3865    SUMA_ENTRY;
3866 
3867    if (!SO || !NodeMarker) SUMA_RETURN(NOPE);
3868 
3869    SUMA_LHv("Loading %s\n", NodeMarker);
3870    if (!(nido = SUMA_ReadNIDO (NodeMarker, SO->idcode_str))) {
3871       SUMA_S_Errv("Failed to load %s\n", NodeMarker);
3872       SUMA_RETURN(NOPE);
3873    }
3874    nido->do_type = NIDO_type;
3875 
3876    if (SO->CommonNodeObject) {
3877       SUMA_Free_Displayable_Object_Vect(SO->CommonNodeObject,1);
3878       SO->CommonNodeObject = NULL;
3879    }
3880    SO->CommonNodeObject = (SUMA_DO *)SUMA_calloc(1,sizeof(SUMA_DO));
3881 
3882    SO->CommonNodeObject->OP = (void *)nido;
3883    SO->CommonNodeObject->ObjectType = NIDO_type;
3884    SO->CommonNodeObject->CoordType = SUMA_WORLD;
3885    nido = NULL;
3886 
3887    SUMA_LH( "Need to turn SO->CommonNodeObject to "
3888             "SO->NodeObjects, and SO->NodeNIDOObjects");
3889    #if 0
3890    /* this approach is less flexible, only one nel allowed in CommonNodeObject
3891    and it is not any faster than the second approach, wich allows for any NIDO
3892    to be propagated
3893    Just don't have both modes on, you'll be drawing similar objects twice */
3894    if (SO->NodeObjects) {
3895       SUMA_Free_Displayable_Object_Vect(SO->NodeObjects, 1);
3896    }
3897    SO->NodeObjects = SUMA_Multiply_NodeObjects( SO,  SO->CommonNodeObject);
3898    #else
3899    if (SO->NodeNIDOObjects) {
3900       for (i=0; i<SO->N_Node; ++i)
3901          if (SO->NodeNIDOObjects[i]) SUMA_free_NIDO(SO->NodeNIDOObjects[i]);
3902       SUMA_free(SO->NodeNIDOObjects);   SO->NodeNIDOObjects = NULL;
3903    }
3904    SO->NodeNIDOObjects =
3905       SUMA_Multiply_NodeNIDOObjects(SO,  SO->CommonNodeObject, NULL, -1);
3906    #endif
3907 
3908    SUMA_RETURN(YUP);
3909 }
3910 
3911 
3912 /*!
3913    Call the function engine, with debug turned on.      20 Oct 2003 [rickr]
3914 */
SUMA_LoadSpec(SUMA_SurfSpecFile * Spec,SUMA_DO * dov,int * N_dov,char * VolParName)3915 SUMA_Boolean SUMA_LoadSpec (SUMA_SurfSpecFile *Spec, SUMA_DO *dov,
3916                             int *N_dov, char *VolParName)
3917 {/* SUMA_LoadSpec */
3918    static char FuncName[]={"SUMA_LoadSpec"};
3919 
3920    SUMA_ENTRY;
3921 
3922    SUMA_RETURN( SUMA_LoadSpec_eng(Spec, dov, N_dov, VolParName,
3923                                   1, SUMAg_CF->DsetList) );
3924 
3925 }/* SUMA_LoadSpec */
3926 
3927 /* - appended _eng to engine function name             20 Oct 2003 [rickr]
3928  * - added debug parameter
3929  * - only output non-error info when debug flag is set
3930  * - debug level 1, slight detail, level 2 more detail
3931 */
3932 /*!
3933    Loads the surfaces specified in Spec and stores them in DOv
3934 */
3935 static int LoadPacify = 0;
SetLoadPacify(int k)3936 void SetLoadPacify(int k) { LoadPacify = k; }
GetLoadPacify(void)3937 int  GetLoadPacify(void) { return LoadPacify; }
3938 
SUMA_LoadSpec_eng(SUMA_SurfSpecFile * Spec,SUMA_DO * dov,int * N_dov,char * VolParName,int debug,DList * DsetList)3939 SUMA_Boolean SUMA_LoadSpec_eng (
3940                   SUMA_SurfSpecFile *Spec, SUMA_DO *dov, int *N_dov,
3941                   char *VolParName, int debug, DList *DsetList)
3942 {/* SUMA_LoadSpec_eng */
3943    static char FuncName[]={"SUMA_LoadSpec_eng"};
3944    int i, k;
3945    char *tmpid, *tmpVolParName = NULL;
3946    SUMA_SurfaceObject *SO=NULL;
3947    SUMA_Axis *EyeAxis;
3948    SUMA_OVERLAYS *NewColPlane=NULL;
3949    SUMA_Boolean SurfIn = NOPE;
3950    SUMA_Boolean LocalHead = NOPE;
3951 
3952    SUMA_ENTRY;
3953 
3954    if (LocalHead) debug = 1;
3955 
3956    if ( debug )
3957        SUMA_S_Notev("Expecting to read %d surfaces, %d DOs.\n",
3958                      Spec->N_Surfs, Spec->N_DO);
3959    for (i=0; i<Spec->N_Surfs; ++i) { /* first loop across mappable surfaces */
3960       /*locate and load all Mappable surfaces */
3961       if (Spec->LocalDomainParent[i][0] == '\0') {
3962          /* assume surface is local domain parent, otherwise,
3963          surface controller would crash      ZSS  July 13 2010 */
3964          if (debug)
3965             SUMA_S_Warnv(
3966                "MappingRef field unavailable for %s in spec file, "
3967                "Assuming MappingRef = SAME\n"
3968                "You might have problems linking to volume.\n",
3969                 SO->Label);
3970          sprintf(Spec->LocalDomainParent[i], "SAME");
3971       }
3972       if (SUMA_iswordin(Spec->LocalDomainParent[i],"SAME") == 1) {
3973          /* Mappable surfaces */
3974          if ( debug || LoadPacify) { /* turned this back on as a pacifier */
3975 	         fprintf (SUMA_STDERR,"\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv");
3976 	         fprintf (SUMA_STDERR,
3977 		               "Surface #%d/%d(Local Domain Parent), loading ...\n",
3978                      i+1, Spec->N_Surfs );
3979 	      }
3980 
3981          if (Spec->VolParName[i][0] != '\0') {
3982             SUMA_LH("Using Volume Parent Specified in Spec File.\n"
3983                     "This overrides -sv option.");
3984             tmpVolParName = Spec->VolParName[i];
3985          }else {
3986             tmpVolParName = VolParName;
3987          }
3988 
3989          SO = SUMA_Load_Spec_Surf(Spec, i, tmpVolParName, debug);
3990          if (SO) SurfIn = YUP;
3991          else {
3992             SurfIn = NOPE;
3993             SUMA_SL_Err("Failed to read surface.");
3994             SUMA_RETURN(NOPE);
3995          }
3996 
3997          /* store the surface's idcode pointer for use in
3998             non mappable bloc below */
3999             Spec->IDcode[i] = SO->idcode_str;
4000 
4001          /* check if surface read was unique
4002          it's inefficient to check after the surface is read,
4003          but idcode is generated in the read routine
4004          and users should not be making this mistake too often
4005          Search for similar comment elsewhere in the code once
4006          a better remedy is found*/
4007          if (SUMA_existSO (SO->idcode_str, dov, *N_dov)) {
4008             /* Check the filename match, to get around ID collision
4009                This modification is no guarantee that collisions
4010                won't occur but it is a start until I figure out
4011                the problem with hashcode */
4012             char *name=NULL, *mname=NULL;
4013             SUMA_SurfaceObject *SOm = NULL;
4014             SOm = SUMA_findSOp_inDOv(SO->idcode_str, dov, *N_dov);
4015             mname = SUMA_SurfaceFileName(SOm, 1);
4016             name = SUMA_SurfaceFileName(SO, 1);
4017             if (mname && name && strcmp(mname, name)) {
4018                char *stmp;
4019                /* give SO a new ID */
4020                stmp = SUMA_append_replace_string(name, SO->idcode_str,"_",0);
4021                SUMA_ifree(SO->idcode_str);
4022                SUMA_NEW_ID(SO->idcode_str, stmp);
4023                SUMA_ifree(stmp);
4024             }
4025             SUMA_ifree(name); SUMA_ifree(mname);
4026          }
4027          if (SUMA_existSO (SO->idcode_str, dov, *N_dov)) {
4028             SUMA_SurfaceObject *SOm = NULL;
4029             SOm = SUMA_findSOp_inDOv(SO->idcode_str, dov, *N_dov);
4030             SUMA_S_Errv("Surface %s %s (id %s) is in dov already as %s!\n",
4031                         SPEC_NAME_DBG(Spec,i), SPEC_TOPO_DBG(Spec,i),
4032                         SO->idcode_str, SOm->Label);
4033 
4034             /* free SO */
4035             if (!SUMA_Free_Surface_Object (SO)) {
4036                fprintf(SUMA_STDERR,"Error %s: Error freeing SO.\n", FuncName);
4037                SUMA_RETURN (NOPE);
4038             }
4039             SO = NULL;
4040             SurfIn = NOPE;
4041          } else {
4042             if (!SUMA_PrepAddmappableSO(SO, dov, N_dov, debug, DsetList)) {
4043                SUMA_SL_Err("Failed in SUMA_PrepAddmappableSO.");
4044                SUMA_RETURN(NOPE);
4045             }
4046          }
4047          SurfIn = NOPE;
4048 
4049          if (SO && Spec->LabelDset[i][0] != '\0') {
4050             SUMA_LHv("Will need to load label dset %s for %s\n",
4051                          Spec->LabelDset[i], SO->Label);
4052             /* load it straight to SO */
4053             if (!(SUMA_LoadDsetOntoSO_eng(Spec->LabelDset[i], (void *)SO,
4054                                     -1, 0, 0, &NewColPlane))) {
4055                SUMA_S_Errv("Failed to read %s\n", Spec->LabelDset[i]);
4056                SUMA_RETURN(NOPE);
4057             }
4058             /* do some deeds on this overlay */
4059             NewColPlane->GlobalOpacity =
4060                   SUMA_floatEnv("SUMA_LabelDsetOpacity", 0.2);
4061             if (  SUMA_isEnv("SUMA_ShowLabelDsetAtStartup","col") ||
4062                   SUMA_isEnv("SUMA_ShowLabelDsetAtStartup","yes"))
4063                NewColPlane->ShowMode = SW_SurfCont_DsetViewCol;
4064             else if (  SUMA_isEnv("SUMA_ShowLabelDsetAtStartup","con") ) {
4065                NewColPlane->ShowMode = SW_SurfCont_DsetViewCon;
4066             }else if (  SUMA_isEnv("SUMA_ShowLabelDsetAtStartup","c&c") ) {
4067                NewColPlane->ShowMode = SW_SurfCont_DsetViewCaC;
4068             }else if (  SUMA_isEnv("SUMA_ShowLabelDsetAtStartup","xxx") ||
4069                   SUMA_isEnv("SUMA_ShowLabelDsetAtStartup","no")) {
4070                NewColPlane->ShowMode = SW_SurfCont_DsetViewXXX;
4071             }else{ /* show as contours only */
4072                NewColPlane->ShowMode = SW_SurfCont_DsetViewCon;
4073             }
4074             /* create contours for this monster */
4075             SUMA_ContourateDsetOverlay(NewColPlane, NULL);
4076 
4077             /* move that plane down the stack, nice to have convexity stay
4078             on top */
4079             SUMA_MovePlaneDown((SUMA_ALL_DO *)SO, NewColPlane->Name);
4080 
4081             NewColPlane=NULL;          /* don't let anyone here use it */
4082          }
4083          if (SO && Spec->NodeMarker[i][0] != '\0') {
4084             SUMA_LHv("Will load NodeMarker %s for %s\n",
4085                          Spec->NodeMarker[i], SO->Label);
4086             if (!(SUMA_Load_SO_NodeMarker(SO, Spec->NodeMarker[i]))) {
4087                SUMA_S_Errv("Failed to loa NodeMarker %s onto %s\n"
4088                            "Plodding on nonetheless.\n",
4089                            Spec->NodeMarker[i], SO->Label);
4090             }
4091             SUMA_LHv("NodeMarker %s loaded\n", Spec->NodeMarker[i]);
4092          }
4093          /* Any dsets identically named? If so, load them */
4094          if (SUMA_isEnv("SUMA_AutoLoad_Matching_Dset","YES")){
4095              SUMA_AutoLoad_SO_Dsets(SO);
4096          }
4097       }/* Mappable surfaces */
4098    }/* first loop across mappable surfaces */
4099 
4100    for (i=0; i<Spec->N_Surfs; ++i) { /* Now locate and load all
4101                                        NON Mappable surfaces */
4102 
4103       if (Spec->VolParName[i][0] != '\0') {
4104          if (VolParName) {
4105             SUMA_LH("Using Volume Parent Specified in Spec File.\n"
4106                      "This overrides -sv option.");
4107          }
4108          tmpVolParName = Spec->VolParName[i];
4109       }else {
4110          tmpVolParName = VolParName;
4111       }
4112 
4113       if (SUMA_iswordin(Spec->LocalDomainParent[i],"SAME") != 1) {
4114                /* Non Mappable surfaces */
4115 	      if ( debug  || LoadPacify) { \
4116             fprintf (SUMA_STDERR,"\nvvvvvvvvvvvvvvvvvvvvvvvvvvvv");
4117             fprintf (SUMA_STDERR,
4118    		            "Surface #%d/%d (mappable via Local Domain Parent), "
4119                      "loading ...\n",i+1, Spec->N_Surfs);
4120 	      }
4121 
4122          SO = SUMA_Load_Spec_Surf(Spec, i, tmpVolParName, debug);
4123          if (SO) SurfIn = YUP;
4124          else {
4125             SurfIn = NOPE;
4126             SUMA_SL_Err("Failed to read surface.");
4127             SUMA_RETURN(NOPE);
4128          }
4129 
4130 
4131          /* check if surface read was unique
4132             it's inefficient to check after the surface is read,
4133             but idcode is generated in the read routine
4134             and users should not be making this mistake too often */
4135             if (SUMA_existSO (SO->idcode_str, dov, *N_dov)) {
4136                fprintf( SUMA_STDERR,
4137                         "Error %s: Surface %d is specifed more than once.\n"
4138                         "Multiple copies ignored.\n", FuncName, i);
4139                /* free SO */
4140                if (!SUMA_Free_Surface_Object (SO)) {
4141                   fprintf( SUMA_STDERR,
4142                            "Error %s: Error freeing SO.\n", FuncName);
4143                   SUMA_RETURN (NOPE);
4144                }
4145                SurfIn = NOPE;
4146             }
4147 
4148          /* if the surface is loaded OK,
4149             and it has not been loaded previously, register it */
4150          if (SurfIn) {
4151             Spec->IDcode[i] = SO->idcode_str;
4152                               /* add its ID to its Spec entry */
4153             /* Create a Mesh Axis for the surface */
4154             SO->MeshAxis = SUMA_Alloc_Axis ("Surface Mesh Axis", AO_type);
4155             if (SO->MeshAxis == NULL) {
4156                fprintf( SUMA_STDERR,
4157                         "Error %s: Error Allocating axis\n", FuncName);
4158                SUMA_RETURN(NOPE);
4159             }
4160             /* Change the defaults of Mesh axis to fit standard  */
4161             SUMA_MeshAxisStandard (SO->MeshAxis, (SUMA_ALL_DO *)SO);
4162             /*turn off the viewing for the axis */
4163             SO->ShowMeshAxis = NOPE;
4164 
4165             /* Store it into dov */
4166             if (!SUMA_AddDO(dov, N_dov, (void *)SO,  SO_type, SUMA_WORLD)) {
4167                fprintf(SUMA_STDERR,"Error %s: Error Adding DO\n", FuncName);
4168                SUMA_RETURN(NOPE);
4169             }
4170 
4171          /* set its MappingRef id to NULL if none is specified */
4172             if (Spec->LocalDomainParent[i][0] == '\0') {
4173                /* This should not happen after July 13 2010 fix above */
4174                SO->LocalDomainParentID = NULL; /* no known MapRef_idcode */
4175                SUMA_S_Warnv(
4176                   "MappingRef field unavailable for %s in spec file ",
4177                    SO->Label);
4178             } else {
4179                /* make sure that specified Mapping ref had been loaded */
4180                   int j = 0, ifound = -1;
4181                   while (j < Spec->N_Surfs) {
4182                      if (LocalHead) {
4183                         fprintf( SUMA_STDERR,
4184                                  "%s-voila%d/%d:\n%s\n%s\n%s\n%s\n",
4185                                  FuncName, j, Spec->N_Surfs,
4186                                  Spec->LocalDomainParent[i], Spec->CoordFile[j],
4187                                  Spec->TopoFile[j], Spec->SurfaceFile[j]);
4188                      }
4189                      if (strcmp( Spec->LocalDomainParent[i],
4190                                  Spec->CoordFile[j]) == 0 ||
4191                          strcmp( Spec->LocalDomainParent[i],
4192                                  Spec->TopoFile[j]) == 0 ||
4193                          strcmp( Spec->LocalDomainParent[i],
4194                                  Spec->SurfaceFile[j]) == 0) {
4195                         /* found a match */
4196                         ifound = j;
4197                         j = Spec->N_Surfs + 1;
4198                      }
4199                      ++j;
4200                   }
4201                if (ifound >= 0) { /* found */
4202                   if (LocalHead)
4203                      fprintf (SUMA_STDERR,
4204                               "ifound = %d, i = %d\n"
4205                               "Spec->LocalDomainParent[i]:->%s<-\n",
4206                               ifound, i, Spec->LocalDomainParent[i]);
4207                   if (!SUMA_existSO (Spec->IDcode[ifound], dov, *N_dov)) {
4208                      fprintf( SUMA_STDERR,
4209                               "MappingRef unavailable, "
4210                               "that should not happen here.\n");
4211                      SO->LocalDomainParentID = NULL;
4212                      /* showme the contents */
4213                      if (!SUMA_ShowSpecStruct (Spec, NULL, 3)) {
4214                         SUMA_SL_Err("Failed in SUMA_ShowSpecStruct\n");
4215                         exit(1);
4216                      }
4217                   } else {
4218                      /*fprintf(SUMA_STDERR,
4219                               "MappingRef found in mappable surfaces\n");*/
4220                      SO->LocalDomainParentID =
4221                            (char *)SUMA_calloc( strlen(Spec->IDcode[ifound])+1,
4222                                                 sizeof(char));
4223                      if (SO->LocalDomainParentID == NULL) {
4224                         fprintf(SUMA_STDERR,
4225                            "Error %s: Failed to allocate for "
4226                            "SO->LocalDomainParentID. \n"
4227                            "That is pretty bad.\n", FuncName);
4228                         SUMA_RETURN (NOPE);
4229                      }
4230                      SO->LocalDomainParentID =
4231                         strcpy(SO->LocalDomainParentID, Spec->IDcode[ifound]);
4232                   }
4233                } else {
4234                   if (debug)
4235                      SUMA_S_Warnv(
4236                         "MappingRef field unavailable for %s in spec file, "
4237                         "You might have problems linking to volume.\n",
4238                          SO->Label);
4239                   SO->LocalDomainParentID = NULL;
4240                }
4241             }
4242 
4243             /* create the colorlist vector and calculate the surface metrics
4244                with the possibility of inheriting from the mapping reference */
4245             {
4246                SUMA_SurfaceObject *SOinh = NULL;
4247                int ifound = -1;
4248 
4249                if (SO->LocalDomainParentID) {
4250                   ifound =  SUMA_findSO_inDOv ( SO->LocalDomainParentID,
4251                                                 dov, *N_dov);
4252                   if (ifound < 0) {
4253                      SOinh = NULL;
4254                   }else {
4255                      SOinh = (SUMA_SurfaceObject *)(dov[ifound].OP);
4256                   }
4257                } else SOinh = NULL;
4258 
4259                /* deal with surface controller */
4260                if (SOinh) {
4261                   #if SUMA_SEPARATE_SURF_CONTROLLERS
4262                   /* leave controllers separate */
4263                   if (!SO->SurfCont) {
4264                      SO->SurfCont =
4265                         SUMA_CreateSurfContStruct(SO->idcode_str, SO_type);
4266                   } else {
4267                      SUMA_S_Note("Surface Controller Exists Already (b)\n");
4268                   }
4269                   #else
4270                   /* create a link to the surface controller pointer */
4271                   if (!SO->SurfCont) {
4272                      SO->SurfCont = (SUMA_X_SurfCont*)
4273                                     SUMA_LinkToPointer((void *)SOinh->SurfCont);
4274                   } else {
4275                      SUMA_S_Note("Surface Controller Exists Already (c)\n");
4276                   }
4277                   #endif
4278                } else {
4279                   /* brand new one */
4280                   if (!SO->SurfCont) {
4281                      SO->SurfCont = SUMA_CreateSurfContStruct(SO->idcode_str,
4282                                                               SO_type);
4283                   } else {
4284                      SUMA_S_Note("Surface Controller Exists Already (d)\n");
4285                   }
4286                }
4287 
4288 
4289                if (!SUMA_SurfaceMetrics_eng (SO, "EdgeList, MemberFace",
4290                                              SOinh, debug, DsetList)) {
4291                   fprintf (SUMA_STDERR,
4292                            "Error %s: Failed in SUMA_SurfaceMetrics.\n",
4293                            FuncName);
4294                   SUMA_RETURN (NOPE);
4295                }
4296             }
4297 
4298             SurfIn = NOPE;
4299          }
4300          if (Spec->LabelDset[i][0] != '\0') { /* I do not think this should be */
4301             SUMA_S_Notev("Label dsets should only be attached to \n"
4302                          "surfaces with LocalDomainParent = SAME).\n"
4303                          "LabelDset %s is ignored.\n",
4304                          Spec->LabelDset[i]);
4305          }
4306          if (SO && Spec->NodeMarker[i][0] != '\0') {
4307             SUMA_S_Notev("Will need to load NodeMarker %s for non mappable %s\n",
4308                          Spec->NodeMarker[i], SO->Label);
4309          }
4310          if (SUMA_isEnv("SUMA_AutoLoad_Matching_Dset","YES"))
4311                                         SUMA_AutoLoad_SO_Dsets(SO);
4312 
4313       }/* Non Mappable surfaces */
4314 
4315    }/*locate and load all NON Mappable surfaces */
4316 
4317    SUMA_LHv("Have %d DOs to load\n", Spec->N_DO);
4318    for (i=0; i<Spec->N_DO; ++i) {
4319       switch ((SUMA_DO_Types)Spec->DO_type[i]) {
4320          case TRACT_type: {
4321             SUMA_LoadSegDO (Spec->DO_name[i], NULL );
4322             break; }
4323          case MASK_type: {
4324             SUMA_LoadMaskDO (Spec->DO_name[i], NULL );
4325             break; }
4326          case VO_type: {
4327             SUMA_LoadVolDO (Spec->DO_name[i], SUMA_WORLD, NULL,1);
4328             break; }
4329          case GDSET_type:
4330             SUMA_LHv("Loading graph dset %s\n",Spec->DO_name[i]);
4331             /* Expecting it to be a graph dset */
4332             if (!(SUMA_LoadDsetOntoSO_eng(Spec->DO_name[i],
4333                                           NULL, 1, 1, 1, NULL))) {
4334                SUMA_S_Errv("Failed to load %s\n", Spec->DO_name[i]);
4335             }
4336             break;
4337          case CDOM_type:
4338             SUMA_LoadCIFTIDO (Spec->DO_name[i],
4339                               SUMA_WORLD, NULL, 1, 1, 1, 1, NULL);
4340             break;
4341          default:
4342             SUMA_S_Errv("Bad or unexpected type %s for %s\n",
4343                   SUMA_ObjectTypeCode2ObjectTypeName(Spec->DO_type[i]),
4344                      Spec->DO_name[i]);
4345             break;
4346       }
4347    }
4348 
4349    SUMA_RETURN (YUP);
4350 }/* SUMA_LoadSpec_eng */
4351 
4352 
4353 /*!
4354    SUMA_SurfaceMetrics - call the engine with debug set    20 Oct 2003 [rickr]
4355 */
SUMA_SurfaceMetrics(SUMA_SurfaceObject * SO,const char * Metrics,SUMA_SurfaceObject * SOinh)4356 SUMA_Boolean SUMA_SurfaceMetrics(SUMA_SurfaceObject *SO,
4357                                   const char *Metrics,
4358                                   SUMA_SurfaceObject *SOinh)
4359 {
4360    static char FuncName[]={"SUMA_SurfaceMetrics"};
4361 
4362    SUMA_ENTRY;
4363 
4364    SUMA_RETURN(SUMA_SurfaceMetrics_eng(SO, Metrics, SOinh, 1,
4365                                        SUMAg_CF->DsetList));
4366 }
4367 
4368 
4369 /* - appended _eng to engine function name                 20 Oct 2003 [rickr]
4370  * - added debug parameter
4371  * - only output non-error info when debug flag is set
4372 */
4373 /*!
4374    calculate surface properties
4375 
4376    ans = SUMA_SurfaceMetrics_eng (SO, Metrics, SOinh, debug, DList *DsetList)
4377    \param SO (SUMA_SurfaceObject *)
4378    \param Metrics (const char *) list of parameters to compute. Supported parameters are (case sensitive):
4379       "Convexity", "PolyArea", "Curvature", "EdgeList", "MemberFace", "CheckWind"
4380       You can specify more than one parameter "Convexity, PolyArea"
4381       if the field of a certain parameter is not NULL then it is assumed that
4382       this parameter was computed at an earlier time and will not be recalculated.
4383       Some parameters require the computation of others and that's done automatically.
4384    \param SOinh (SUMA_SurfaceObject *) Some of the metrics can be inherited from SOinh (done through inodes)
4385       if things make sense. SOinh is typically the Mapping Reference SO. Pass NULL not to use this feature.
4386       Currently, only EL and FN can use this feature if the number of nodes, facesets match and SOinh is the
4387       mapping reference of SO
4388    \param debug (int) flag specifying whether to output non-error info
4389    \param DsetList (DList *)  pointer to list where computed elements are to be stored
4390                               as datasets. For the moment, this pointer can be NULL and
4391                               if that is the case then nothing will get stored as a dataset.
4392    \return ans (SUMA_Boolean) NOPE = failure
4393 
4394    Convexity : Fills Cx field in SO, An inode is also created
4395 
4396    EdgeList also runs SUMA_Build_FirstNeighb
4397 
4398    Curvature requires also PolyArea, FaceNeighb and EdgeList
4399    CheckWind requires EdgeList
4400 
4401 
4402 */
SUMA_SurfaceMetrics_eng(SUMA_SurfaceObject * SO,const char * Metrics,SUMA_SurfaceObject * SOinh,int debug,DList * DsetList)4403 SUMA_Boolean SUMA_SurfaceMetrics_eng (
4404          SUMA_SurfaceObject *SO,
4405          const char *Metrics,
4406          SUMA_SurfaceObject *SOinh,
4407          int debug,
4408          DList *DsetList)
4409 {
4410    static char FuncName[]={"SUMA_SurfaceMetrics_eng"};
4411    float *Cx=NULL, *SOCx = NULL;
4412    SUMA_Boolean DoConv, DoArea, DoCurv, DoEL, DoMF, DoWind, DoDW,
4413                 LocalHead = NOPE;
4414    int i = 0;
4415 
4416    SUMA_ENTRY;
4417 
4418    if (debug > 1)
4419       fprintf (SUMA_STDERR,
4420                "%s: Calculating surface metrics, please be patient...\n",
4421                FuncName);
4422 
4423    if (!DsetList) {
4424       SUMA_SL_Err("DsetList now is a must.");
4425       SUMA_RETURN(NOPE);
4426    }
4427    DoConv = DoArea = DoCurv = DoEL = DoMF = DoWind = NOPE;
4428    DoDW = YUP; /* No need to skimp on this one, costs nothing */
4429 
4430    if (SUMA_iswordin (Metrics, "Convexity")) DoConv = YUP;
4431    if (SUMA_iswordin (Metrics, "PolyArea")) DoArea = YUP;
4432    if (SUMA_iswordin (Metrics, "Curvature")) DoCurv = YUP;
4433    if (SUMA_iswordin (Metrics, "EdgeList")) DoEL = YUP;
4434    if (SUMA_iswordin (Metrics, "MemberFace")) DoMF = YUP;
4435    if (SUMA_iswordin (Metrics, "CheckWind")) DoWind = YUP;
4436 
4437    /* check for input inconsistencies and warn */
4438    if (!DoConv && !DoArea && !DoCurv && !DoEL  && !DoMF && !DoWind && !DoDW) {
4439       if (debug) fprintf ( SUMA_STDERR,
4440                            "Warning %s: Nothing to do.\n", FuncName);
4441       SUMA_RETURN (YUP);
4442    }
4443 
4444    if (DoConv && (SOCx = (float *)SUMA_GetCx (SO->idcode_str, DsetList, 0))) {
4445       if (debug) fprintf ( SUMA_STDERR,
4446                            "Warning %s: SOCx != NULL \n"
4447                            "and thus appears to have been precomputed.\n",
4448                            FuncName);
4449       DoConv = NOPE;
4450    }
4451 
4452    if (DoArea && SO->PolyArea != NULL) {
4453       if (debug) fprintf ( SUMA_STDERR,
4454                            "Warning %s: SO->PolyArea != NULL and "
4455                            "thus appears to have been precomputed.\n",
4456                            FuncName);
4457       DoArea = NOPE;
4458    }
4459 
4460    if (DoCurv && SO->SC != NULL) {
4461       if (debug) fprintf ( SUMA_STDERR,
4462                            "Warning %s: SO->SC != NULL and thus "
4463                            "appears to have been precomputed.\n",
4464                            FuncName);
4465       DoCurv = NOPE;
4466    }
4467 
4468    if (DoMF && SO->MF != NULL) {
4469       if (debug) fprintf ( SUMA_STDERR,
4470                            "Warning %s: SO->MF != NULL and thus "
4471                            "appears to have been precomputed.\n",
4472                            FuncName);
4473       DoMF = NOPE;
4474    }
4475 
4476    if (DoEL && (SO->EL != NULL || SO->FN != NULL)) {
4477       if (debug) fprintf ( SUMA_STDERR,
4478                            "Warning %s: SO->EL != NULL || SO->FN != NULL "
4479                            "and thus appears to have been precomputed.\n",
4480                            FuncName);
4481       DoEL = NOPE;
4482    }
4483 
4484    if (DoEL && SOinh) {
4485       if (strcmp(SO->LocalDomainParentID, SOinh->idcode_str)) {
4486          SUMA_SL_Warn(  "Cannot inherit Edge List\n"
4487                         "and First Neightbor.\n"
4488                         "Cause: idcode mismatch.\n"
4489                         "Independent lists will\n"
4490                         "be created.\n" );
4491          SOinh = NULL;
4492       }  else if (SO->N_Node != SOinh->N_Node ||
4493                   SO->N_FaceSet != SOinh->N_FaceSet) {
4494          SUMA_SL_Note(  "(IGNORE for surface with cuts)\n"
4495                         "Cannot inherit Edge List\n"
4496                         "and First Neightbor.\n"
4497                         "Cause: Node number mismatch.\n"
4498                         "Independent lists will\n"
4499                         "be created.\n");
4500          SOinh = NULL;
4501       }
4502    }
4503 
4504    if (DoMF && SOinh) {
4505       if (strcmp(SO->LocalDomainParentID, SOinh->idcode_str)) {
4506          SUMA_SL_Warn(  "Cannot inherit MemberFaceSet\n"
4507                         "Cause: idcode mismatch.\n"
4508                         "Independent lists will\n"
4509                         "be created.\n" );
4510          SOinh = NULL;
4511       } else if ( SO->N_Node != SOinh->N_Node ||
4512                   SO->N_FaceSet != SOinh->N_FaceSet) {
4513          SUMA_SL_Warn(  "(IGNORE for surface patches)\n"
4514                         "Cannot inherit MemberFaceSet\n"
4515                         "Cause: Node number mismatch.\n"
4516                         "Independent lists will\n"
4517                         "be created.\n");
4518          SOinh = NULL;
4519       }
4520    }
4521 
4522    /* prerequisits */
4523    if (DoCurv) {
4524       DoArea = YUP;
4525       DoEL = YUP;
4526    }
4527 
4528    if (DoWind) {
4529       DoEL = YUP;
4530    }
4531 
4532    if (DoConv && (!SO->EL || !SO->FN)) {
4533       DoEL = YUP;
4534    }
4535 
4536    /* the computations */
4537    if (DoArea) {
4538       /* create the triangle Area  */
4539       if (SO->NodeDim == 3) {
4540          if (debug)
4541             fprintf( SUMA_STDOUT,
4542                      "%s: Calculating triangle areas ...\n", FuncName);
4543             fflush(SUMA_STDOUT);
4544          SO->PolyArea = SUMA_TriSurf3v (  SO->NodeList,
4545                                           SO->FaceSetList, SO->N_FaceSet);
4546       } else {
4547          if (debug)
4548             fprintf( SUMA_STDOUT,
4549                      "%s: Calculating polygon areas ...\n", FuncName);
4550             fflush(SUMA_STDOUT);
4551          SO->PolyArea = SUMA_PolySurf3 (  SO->NodeList, SO->N_Node,
4552                                           SO->FaceSetList, SO->N_FaceSet,
4553                                           SO->NodeDim, SO->FaceNormList, NOPE);
4554          #if 0
4555             /* a test of the functions for calculating areas */
4556             {
4557                int ji, in0, in1, in2;
4558                float *n0, *n1, *n2, A;
4559                for (ji=0; ji<SO->N_FaceSet; ++ji) {
4560                   in0 = SO->FaceSetList[3*ji];
4561                   in1 = SO->FaceSetList[3*ji+1];
4562                   in2 = SO->FaceSetList[3*ji+2];
4563                   n0 = &(SO->NodeList[3*in0]);
4564                   n1 = &(SO->NodeList[3*in1]);
4565                   n2 = &(SO->NodeList[3*in2]);
4566                   A = SUMA_TriSurf3 (n0, n1, n2);
4567                   if (abs(A - SO->PolyArea[ji]) > 0.00001) {
4568                      fprintf (SUMA_STDERR,
4569     "Error %s: Failed comparing SUMA_TriSurf3 to SUMA_PolySurf3. A = %f vs %f.\n"
4570     "Tri = [ %f, %f, %f; %f, %f, %f; %f, %f, %f]\n",
4571                         FuncName, A, SO->PolyArea[ji],
4572                         n0[0], n0[1], n0[2],
4573                         n1[0], n1[1], n1[2],
4574                         n2[0], n2[1], n2[2]);
4575                   }else fprintf (SUMA_STDERR, "-");
4576 
4577                   SUMA_TRI_AREA (n0, n1, n2, A);
4578                   if (abs(A - SO->PolyArea[ji]) > 0.00001) {
4579                      fprintf (SUMA_STDERR,
4580       "Error %s: Failed comparing SUMA_TRI_AREA to SUMA_PolySurf3. "
4581       "%f vs %f Exiting.\n",
4582                         FuncName, A, SO->PolyArea[ji]);
4583                   }else fprintf (SUMA_STDERR, ".");
4584                }
4585             }
4586          #endif
4587 
4588       }
4589       if (SO->PolyArea == NULL) {
4590          fprintf(SUMA_STDERR,
4591                   "Error %s: Error in SUMA_PolySurf3 or SUMA_TriSurf3v\n",
4592                   FuncName);
4593       }
4594    }
4595 
4596    if (DoEL) {
4597       if (!SOinh) {
4598          /* create the edge list, it's nice and dandy */
4599          if (LocalHead)
4600             fprintf(SUMA_STDOUT, "%s: Making Edge list ....\n", FuncName);
4601          if (SO->EL) {
4602             fprintf (SUMA_STDERR,
4603                      "Warning %s:"
4604                      " SO->FN appears to have been computed before. \n",
4605                      FuncName);
4606          } else {
4607             SO->EL = SUMA_Make_Edge_List_eng (SO->FaceSetList, SO->N_FaceSet,
4608                                               SO->N_Node, SO->NodeList, debug,
4609                                               SO->idcode_str);
4610             if (SO->EL == NULL) {
4611                fprintf( SUMA_STDERR,
4612                         "Error %s: Failed in SUMA_Make_Edge_List.\n"
4613                         " Neighbor list will not be created\n", FuncName);
4614             } else {
4615                if (LocalHead)
4616                   fprintf( SUMA_STDOUT,
4617                            "%s: Making Node Neighbor list ....\n", FuncName);
4618                /* create the node neighbor list */
4619                if (SO->FN) {
4620                   fprintf (SUMA_STDERR,
4621                            "Warning %s:"
4622                            " SO->FN appears to have been computed before. \n",
4623                            FuncName);
4624                } else {
4625                   SO->FN = SUMA_Build_FirstNeighb (SO->EL, SO->N_Node,
4626                                                    SO->idcode_str, debug);
4627                   if (SO->FN == NULL) {
4628                      fprintf( SUMA_STDERR,
4629                               "Error %s: Failed in SUMA_Build_FirstNeighb.\n",
4630                               FuncName);
4631                   }
4632                }
4633             }
4634          }
4635       } else {
4636          if (LocalHead)
4637             fprintf( SUMA_STDOUT,
4638                      "%s: Linking Edge List and First Neighbor Lits ...\n",
4639                      FuncName);
4640          SO->FN = (SUMA_NODE_FIRST_NEIGHB*)SUMA_LinkToPointer((void *)SOinh->FN);
4641          SO->EL = (SUMA_EDGE_LIST*)SUMA_LinkToPointer((void *)SOinh->EL);
4642       }
4643    }
4644 
4645    if (DoConv) {
4646       /* calculate convexity */
4647       if (LocalHead)
4648          fprintf(SUMA_STDOUT, "%s: Calculating convexity ...\n", FuncName);
4649       Cx = SUMA_Convexity(SO->NodeList, SO->N_Node, SO->NodeNormList,
4650                           SO->FN, NULL);
4651       if (Cx == NULL) {
4652          fprintf (SUMA_STDERR, "Error %s: Failed in SUMA_Convexity\n", FuncName);
4653       }
4654 
4655       /* flip sign of convexity if it's a SureFit Surface */
4656       if (  (SO->normdir == 0 && (SO->FileType == SUMA_SUREFIT)) /* guess */
4657             || SO->normdir == -1  /* You know they'z got to be flipped */
4658          ) {
4659          for (i=0; i < SO->N_Node; ++i) {
4660             Cx[i] = -Cx[i];
4661          }
4662       }
4663 
4664       #if 0
4665       {
4666          /* smooth the estimate twice*/
4667          float *attr_sm;
4668          attr_sm = SUMA_SmoothAttr_Neighb (  Cx, SO->N_Node, NULL,
4669                                              SO->FN, 1, NULL);
4670          if (attr_sm == NULL) {
4671                fprintf( stderr,
4672                         "Error %s: Failed in SUMA_SmoothAttr_Neighb\n",
4673                         FuncName);
4674          }   else {
4675             Cx = SUMA_SmoothAttr_Neighb ( attr_sm, SO->N_Node, Cx,
4676                                           SO->FN, 1, NULL);
4677             if (attr_sm) SUMA_free(attr_sm);
4678          }
4679       }
4680       #else
4681          /* smooth the estimate as much as specified*/
4682          {
4683             char *eee = getenv("SUMA_NumConvSmooth");
4684             if (eee) {
4685                int N_smooth = (int)strtod(eee, NULL);
4686                if (N_smooth > 1) {
4687                   Cx = SUMA_SmoothAttr_Neighb_Rec (Cx, SO->N_Node, Cx,
4688                                                    SO->FN, 1, N_smooth, NULL, 1);
4689                } else {
4690                   Cx = SUMA_SmoothAttr_Neighb_Rec (Cx, SO->N_Node, Cx,
4691                                                    SO->FN, 1, 5, NULL, 1);
4692                }
4693             }
4694          }
4695       #endif
4696 
4697       if (Cx == NULL) {
4698          fprintf (SUMA_STDERR,
4699                   "Error %s: Failed in SUMA_SmoothAttr_Neighb\n", FuncName);
4700       }
4701 
4702       /* create a dataset of the convexity */
4703       if (DsetList){ /* put the convexity as a DataSet */
4704          SUMA_DSET *dset = NULL;
4705          char *name_tmp=NULL;
4706          if ((name_tmp = SUMA_SurfaceFileName(SO, 1))) {
4707             /* Go with this baby, maybe someday modify
4708                fuction above to return full path, making it
4709                more robust */
4710             name_tmp = SUMA_append_replace_string("Convexity_",name_tmp,"",2);
4711          } else if (SO->Label) {
4712             name_tmp = SUMA_append_string("Convexity_",SO->Label);
4713          } else if (SO->idcode_str) {
4714             name_tmp = SUMA_append_string("Convexity_",SO->idcode_str);
4715          } else {
4716             name_tmp = SUMA_append_string("Convexity_","Give_Peace_A_Chance");
4717          }
4718          dset = SUMA_CreateDsetPointer(name_tmp, /*   no file name, but specify a
4719                                                       name anyway _COD is
4720                                                       computed on demand*/
4721                                        SUMA_NODE_CONVEXITY,
4722                                        NULL, /* let function create ID code */
4723                                        SO->idcode_str, /* domain owner */
4724                                        SO->N_Node);
4725          SUMA_free(name_tmp); name_tmp = NULL;
4726          if (!SUMA_InsertDsetPointer(&dset, DsetList, 0)) {
4727             SUMA_SL_Err("Failed to insert dset into list");
4728             SUMA_RETURN(NOPE);
4729          }
4730          if (!SUMA_AddDsetNelCol (  dset, "convexity", SUMA_NODE_CX,
4731                                     (void *)Cx, NULL ,1)) {
4732             SUMA_SL_Err("Failed in SUMA_AddNelCol");
4733             SUMA_RETURN(NOPE);
4734          }
4735 
4736          SUMA_free(Cx); Cx = NULL; /* Cx is safe and sound in DsetList */
4737 
4738       }
4739    } /* DoConv */
4740 
4741 
4742    if (DoWind){
4743       int trouble;
4744       /* make sure winding is consistent */
4745       if (!SUMA_MakeConsistent ( SO->FaceSetList, SO->N_FaceSet, SO->EL,
4746                                  1, &trouble)) {
4747          fprintf( SUMA_STDERR,
4748                   "Error %s: Failed in SUMA_MakeConsistent.\n", FuncName);
4749       }else {
4750          if (LocalHead) fprintf(SUMA_STDERR,"%s: Eeeexcellent.\n", FuncName);
4751       }
4752       if (trouble) {
4753          SUMA_SL_Note(  "Even if winding was made consistent,\n"
4754                         "Pre-computed normals and normals-related\n"
4755                         "measures and edge lists will need to be\n"
4756                         "recalculated.\n"
4757                         "See also SurfQual and \n"
4758                         "ConvertSurface's -make_consistent option.\n");
4759       }
4760    }
4761 
4762 
4763    if (DoCurv) {
4764       /* calculate the curvature */
4765       if (LocalHead)
4766          fprintf(SUMA_STDOUT, "%s: Calculating curvature ...\n", FuncName);
4767       SO->SC = SUMA_Surface_Curvature (SO->NodeList, SO->N_Node,
4768                                        SO->NodeNormList, SO->PolyArea,
4769                                        SO->N_FaceSet, SO->FN, SO->EL, NULL,
4770                                        debug);
4771    }
4772 
4773 
4774    if (DoMF) {
4775       if (!SOinh) {
4776          /* determine the MemberFaceSets */
4777          if (LocalHead)
4778             fprintf(SUMA_STDOUT, "%s: Determining MemberFaceSets  ...\n",
4779                     FuncName);
4780          SO->MF = SUMA_MemberFaceSets(SO->N_Node, SO->FaceSetList, SO->N_FaceSet,                                       SO->FaceSetDim, SO->idcode_str);
4781          if (SO->MF->NodeMemberOfFaceSet == NULL) {
4782             fprintf( SUMA_STDERR,
4783                      "Error %s: Error in SUMA_MemberFaceSets\n", FuncName);
4784             SUMA_RETURN (NOPE);/* do not free MF, that's done when SO is freed */
4785          }else {
4786          }
4787       } else { /* inherit */
4788          if (LocalHead)
4789             fprintf(SUMA_STDOUT, "%s: Linking Member Facesets ...\n", FuncName);
4790          SO->MF = (SUMA_MEMBER_FACE_SETS*)SUMA_LinkToPointer((void*)SOinh->MF);
4791       }
4792    }
4793 
4794    /* Initialize drawing masks */
4795    if (DoDW) {
4796       if (!SOinh) {
4797          SO->DW = (SUMA_DRAW_MASKS *)SUMA_calloc(1,sizeof(SUMA_DRAW_MASKS));
4798          SO->DW->do_type = not_DO_type;
4799          SO->DW->LinkedPtrType = SUMA_LINKED_DRAW_MASKS_TYPE;
4800          SO->DW->N_links = 0;
4801          if (SO->idcode_str) sprintf(SO->DW->owner_id, "%s", SO->idcode_str);
4802          else SO->DW->owner_id[0] = '\0';
4803          SUMA_EmptyDrawMasks(SO->DW);
4804       } else {
4805          if (LocalHead)
4806                fprintf(SUMA_STDOUT, "%s: Linking Drawing Masks ...\n", FuncName);
4807          SO->DW = (SUMA_DRAW_MASKS *)SUMA_LinkToPointer((void*)SOinh->DW);
4808       }
4809    }
4810    SUMA_RETURN (YUP);
4811 }
4812 
4813 
4814 
4815 
4816 /*! function to return a string containing the name of the files
4817 defining a surface object
4818 
4819    ans = SUMA_SurfaceFileName (SO, MitPath);
4820    \param SO (SUMA_SurfaceObject *) the surface object
4821    \param MitPath (SUMA_Boolean) if YUP then path is included
4822    \ret ans (char *) containing the name of the file from which the surface
4823       was loaded. If the surface is freesurfer format, the filename is
4824       something like rh.smooth.asc. If it's a SureFit surface then you'll
4825       get both .coord and .topo xxx.coord__yyy.topo
4826       ans is allocated in the function, of course, and must be freed after use
4827 */
4828 
SUMA_SurfaceFileName(SUMA_SurfaceObject * SO,SUMA_Boolean MitPath)4829 char * SUMA_SurfaceFileName (SUMA_SurfaceObject * SO, SUMA_Boolean MitPath)
4830 {
4831    static char FuncName[]={"SUMA_SurfaceFileName"};
4832    char *Name=NULL;
4833    int nalloc=0;
4834 
4835    SUMA_ENTRY;
4836 
4837    /* check if recognizable type */
4838    switch (SO->FileType) {
4839       case SUMA_VEC:
4840       case SUMA_SUREFIT:
4841          if (!SO->Name_coord.Path  || !SO->Name_coord.FileName ||
4842              !SO->Name_topo.Path   || !SO->Name_topo.FileName) {
4843             SUMA_RETURN(NULL);
4844          }
4845          if (MitPath) nalloc =
4846             strlen(SO->Name_coord.Path) +
4847             strlen(SO->Name_coord.FileName) +
4848             strlen(SO->Name_topo.Path) +
4849             strlen(SO->Name_topo.FileName) + 5;
4850          else nalloc =  strlen(SO->Name_coord.FileName) +
4851                         strlen(SO->Name_topo.FileName) + 5;
4852          break;
4853       case SUMA_FT_NOT_SPECIFIED:
4854       case SUMA_INVENTOR_GENERIC:
4855       case SUMA_FREE_SURFER:
4856       case SUMA_FREE_SURFER_PATCH:
4857       case SUMA_BRAIN_VOYAGER:
4858       case SUMA_OPENDX_MESH:
4859       case SUMA_OBJ_MESH:
4860       case SUMA_BYU:
4861       case SUMA_GIFTI:
4862       case SUMA_PREDEFINED:
4863       case SUMA_MNI_OBJ:
4864       case SUMA_STL:
4865       case SUMA_PLY:
4866          if (!SO->Name.Path || !SO->Name.FileName ) {
4867             SUMA_RETURN(NULL);
4868          }
4869          if (MitPath)
4870             nalloc = strlen(SO->Name.Path) + strlen(SO->Name.FileName) + 5;
4871          else nalloc = strlen(SO->Name.FileName) + 5;
4872          break;
4873       default:
4874          SUMA_error_message(FuncName, "SO_FileType not supported", 0);
4875          SUMA_RETURN (NULL);
4876          break;
4877    }
4878 
4879    Name = (char *) SUMA_calloc (nalloc, sizeof(char));
4880    if (!Name) {
4881       fprintf (SUMA_STDERR,"Error %s: Could not allocate for Name.\n", FuncName);
4882       SUMA_RETURN (NULL);
4883    }
4884 
4885    switch (SO->FileType) {
4886       case SUMA_FT_NOT_SPECIFIED:
4887       case SUMA_INVENTOR_GENERIC:
4888       case SUMA_FREE_SURFER:
4889       case SUMA_FREE_SURFER_PATCH:
4890       case SUMA_STL:
4891       case SUMA_PLY:
4892       case SUMA_OPENDX_MESH:
4893       case SUMA_OBJ_MESH:
4894       case SUMA_BYU:
4895       case SUMA_GIFTI:
4896       case SUMA_PREDEFINED:
4897       case SUMA_MNI_OBJ:
4898       case SUMA_BRAIN_VOYAGER:
4899          if (MitPath) sprintf(Name,"%s%s", SO->Name.Path, SO->Name.FileName);
4900          else sprintf(Name,"%s", SO->Name.FileName);
4901          break;
4902       case SUMA_SUREFIT:
4903          if (MitPath) sprintf(Name,"%s%s__%s%s",
4904                               SO->Name_coord.Path, SO->Name_coord.FileName,
4905                               SO->Name_topo.Path, SO->Name_topo.FileName);
4906          else sprintf(Name,"%s__%s",
4907                         SO->Name_coord.FileName, SO->Name_topo.FileName);
4908          break;
4909       case SUMA_VEC:
4910          if (MitPath) sprintf(Name,"%s%s__%s%s",
4911                               SO->Name_coord.Path, SO->Name_coord.FileName,
4912                               SO->Name_topo.Path, SO->Name_topo.FileName);
4913          else sprintf(Name,"%s__%s",
4914             SO->Name_coord.FileName, SO->Name_topo.FileName);
4915          break;
4916       case SUMA_N_SO_FILE_TYPE:
4917       case SUMA_CMAP_SO:
4918       case SUMA_FT_ERROR:
4919          break;
4920    }
4921    SUMA_RETURN (Name);
4922 
4923 }
4924 
4925 /*!
4926    Guess if a surface is anaomically correct from the name.
4927 */
SUMA_GuessAnatCorrect(SUMA_SurfaceObject * SO)4928 char SUMA_GuessAnatCorrect(SUMA_SurfaceObject *SO)
4929 {
4930    static char FuncName[]={"SUMA_GuessAnatCorrect"};
4931 
4932    SUMA_ENTRY;
4933 
4934    switch (SO->FileType) {
4935       case SUMA_INVENTOR_GENERIC:
4936       case SUMA_FREE_SURFER:
4937       case SUMA_FREE_SURFER_PATCH:
4938       case SUMA_OPENDX_MESH:
4939       case SUMA_OBJ_MESH:
4940       case SUMA_STL:
4941       case SUMA_PLY:
4942       case SUMA_BYU:
4943       case SUMA_MNI_OBJ:
4944       case SUMA_PREDEFINED:
4945       case SUMA_BRAIN_VOYAGER:
4946          if (  SUMA_iswordin (SO->Name.FileName, ".white") == 1 ||
4947                SUMA_iswordin (SO->Name.FileName, ".smoothwm") == 1 ||
4948                SUMA_iswordin (SO->Name.FileName, ".pial") == 1 ||
4949                SUMA_iswordin (SO->Name.FileName, ".orig") == 1 ||
4950                SUMA_iswordin (SO->Name.FileName, ".fiducial") == 1 ||
4951                SUMA_iswordin_ci (SO->Name.FileName, "_WM") == 1 ||
4952                SUMA_iswordin_ci (SO->Name.FileName, "_GM") == 1 ||
4953                ( SUMA_iswordin (SO->Name.FileName, "_RECO") == 1 &&
4954                !(SUMA_iswordin (SO->Name.FileName, "_inf") == 1) )
4955                ) {
4956             SUMA_RETURN('Y');
4957          } else {
4958             SUMA_RETURN('N');
4959          }
4960          break;
4961       case SUMA_SUREFIT:
4962       case SUMA_VEC:
4963          if (  SUMA_iswordin (SO->Name_coord.FileName, ".white") == 1 ||
4964                SUMA_iswordin (SO->Name_coord.FileName, ".smoothwm") == 1 ||
4965                SUMA_iswordin (SO->Name_coord.FileName, ".pial") == 1 ||
4966                SUMA_iswordin (SO->Name_coord.FileName, ".orig") == 1 ||
4967                SUMA_iswordin (SO->Name_coord.FileName, ".fiducial") == 1 ||
4968                SUMA_iswordin_ci (SO->Name_coord.FileName, ".Fiducial") == 1 ||
4969                SUMA_iswordin (SO->Name_coord.FileName, ".Raw") == 1 ||
4970                SUMA_iswordin (SO->Name.FileName, "_WM") == 1 ||
4971                SUMA_iswordin (SO->Name.FileName, "_GM") == 1
4972                ) {
4973             SUMA_RETURN('Y');
4974          } else {
4975             SUMA_RETURN('N');
4976          }
4977          break;
4978       case SUMA_N_SO_FILE_TYPE:
4979       case SUMA_FT_NOT_SPECIFIED:
4980       case SUMA_CMAP_SO:
4981       case SUMA_FT_ERROR:
4982          break;
4983       case SUMA_GIFTI:
4984          if (SO->aSO) {
4985             if (  SUMA_iswordsame_ci (  SUMA_NI_AttrOfNamedElement(
4986                                                       SO->aSO,
4987                                                       "Node_XYZ",
4988                                                       "GeometricType"),
4989                                         "Reconstruction") == 1    ||
4990                   SUMA_iswordsame_ci (  SUMA_NI_AttrOfNamedElement(
4991                                                       SO->aSO,
4992                                                       "Node_XYZ",
4993                                                       "GeometricType"),
4994                                         "Anatomical") == 1        ) {
4995                SUMA_RETURN('Y');
4996             }else {
4997                SUMA_RETURN('N');
4998             }
4999          } else {
5000             SUMA_RETURN('N');
5001          }
5002          break;
5003    }
5004 
5005    SUMA_RETURN('\0');
5006 }
5007 
SUMA_GuessSide(SUMA_SurfaceObject * SO)5008 SUMA_SO_SIDE SUMA_GuessSide(SUMA_SurfaceObject *SO)
5009 {
5010    static char FuncName[]={"SUMA_GuessSide"};
5011    char *cc=NULL;
5012 
5013    SUMA_ENTRY;
5014 
5015    switch (SO->FileType) {
5016       case SUMA_INVENTOR_GENERIC:
5017          break;
5018       case SUMA_FREE_SURFER:
5019       case SUMA_FREE_SURFER_PATCH:
5020          if (SUMA_iswordin (SO->Name.FileName, "lh") == 1) {
5021             SUMA_RETURN(SUMA_LEFT);
5022          } else if (SUMA_iswordin (SO->Name.FileName, "rh") == 1) {
5023                      SUMA_RETURN(SUMA_RIGHT);
5024                   }
5025          /* try some more */
5026          if (SUMA_iswordin_ci (SO->Name.FileName, "_lh") == 1 ||
5027              SUMA_iswordin_ci (SO->Name.FileName, ".lh") == 1 ||
5028              SUMA_iswordin_ci (SO->Name.FileName, "lh_") == 1 ||
5029              SUMA_iswordin_ci (SO->Name.FileName, "lh.") == 1) {
5030             SUMA_RETURN(SUMA_LEFT);
5031          } else if (SUMA_iswordin_ci (SO->Name.FileName, "_rh") == 1||
5032                     SUMA_iswordin_ci (SO->Name.FileName, ".rh") == 1 ||
5033                     SUMA_iswordin_ci (SO->Name.FileName, "rh_") == 1 ||
5034                     SUMA_iswordin_ci (SO->Name.FileName, "rh.") == 1) {
5035                      SUMA_RETURN(SUMA_RIGHT);
5036          }
5037          break;
5038       case SUMA_BRAIN_VOYAGER:
5039          if (SUMA_iswordin (SO->Name.FileName, "_LH") == 1) {
5040             SUMA_RETURN(SUMA_LEFT);
5041          } else if (SUMA_iswordin (SO->Name.FileName, "_RH") == 1) {
5042                      SUMA_RETURN(SUMA_RIGHT);
5043                   }
5044          break;
5045       case SUMA_SUREFIT:
5046          if (SUMA_iswordin_ci (SO->Name_coord.FileName, "left") == 1 ||
5047              SUMA_iswordin (SO->Name_coord.FileName, ".L.") == 1) {
5048             SUMA_RETURN(SUMA_LEFT);
5049          } else if (SUMA_iswordin_ci (SO->Name_coord.FileName, "right") == 1 ||
5050              SUMA_iswordin (SO->Name_coord.FileName, ".R.") == 1) {
5051              SUMA_RETURN(SUMA_RIGHT);
5052                 }
5053          break;
5054       case SUMA_VEC:
5055          if (SUMA_iswordin (SO->Name_coord.FileName, "lh") == 1 ||
5056              SUMA_iswordin (SO->Name_coord.FileName, "left") == 1) {
5057                SUMA_RETURN(SUMA_LEFT);
5058          } else if (SUMA_iswordin (SO->Name_coord.FileName, "rh") == 1 ||
5059                      SUMA_iswordin (SO->Name_coord.FileName, "right") == 1) {
5060                      SUMA_RETURN(SUMA_RIGHT);
5061                }
5062          break;
5063       case SUMA_FT_NOT_SPECIFIED:
5064       case SUMA_CMAP_SO:
5065       case SUMA_N_SO_FILE_TYPE:
5066       case SUMA_FT_ERROR:
5067          break;
5068       case SUMA_OPENDX_MESH:
5069       case SUMA_OBJ_MESH:
5070       case SUMA_BYU:
5071       case SUMA_MNI_OBJ:
5072       case SUMA_PREDEFINED:
5073       case SUMA_STL:
5074       case SUMA_PLY:
5075          if (SUMA_iswordin (SO->Name.FileName, "lh") == 1 ||
5076              SUMA_iswordin (SO->Name.FileName, "left") == 1) {
5077                SUMA_RETURN(SUMA_LEFT);
5078          } else if (SUMA_iswordin (SO->Name.FileName, "rh") == 1 ||
5079                   SUMA_iswordin (SO->Name.FileName, "right") == 1) {
5080                      SUMA_RETURN(SUMA_RIGHT);
5081                }
5082          break;
5083       case SUMA_GIFTI:
5084          if (SO->aSO) {
5085             cc = SUMA_NI_AttrOfNamedElement( SO->aSO,
5086                                              "Node_XYZ",
5087                                              "AnatomicalStructurePrimary");
5088             if (!cc || !strcmp(cc,"Unknown")) {
5089                if (SUMA_iswordin (SO->Name.FileName, "lh") == 1 ) {
5090                   SUMA_RETURN(SUMA_LEFT);
5091                } else if (SUMA_iswordin (SO->Name.FileName, "rh") == 1 ) {
5092                   SUMA_RETURN(SUMA_RIGHT);
5093                } else if (SUMA_iswordin (SO->Name_coord.FileName, "lh") == 1 ) {
5094                   SUMA_RETURN(SUMA_LEFT);
5095                } else if (SUMA_iswordin (SO->Name_coord.FileName, "rh") == 1 ) {
5096                   SUMA_RETURN(SUMA_RIGHT);
5097                } else {
5098                   SUMA_RETURN (SUMA_NO_SIDE);
5099                }
5100             } else {
5101                SUMA_RETURN(SUMA_giiStringToNumSide(cc));
5102             }
5103          } else {
5104             SUMA_RETURN(SUMA_NO_SIDE);
5105          }
5106          break;
5107    }
5108 
5109    SUMA_RETURN (SUMA_NO_SIDE);
5110 }
5111 
5112 /*!
5113    tol is the percent tolerance for accepting a surface as a sphere if
5114    its radius fluctuates by tol percent.
5115 */
SUMA_SetSphereParams(SUMA_SurfaceObject * SO,float tol)5116 int SUMA_SetSphereParams(SUMA_SurfaceObject *SO, float tol)
5117 {
5118    static char FuncName[]={"SUMA_SetSphereParams"};
5119    double cent[3], centmed[3], RAD, RAD0, RAD1, rad;
5120    int i, i3;
5121    double r[3], ra=0.0;
5122    char *cc=NULL;
5123    SUMA_GEOM_TYPE isSphere = SUMA_GEOM_NOT_SET;
5124    SUMA_Boolean LocalHead = NOPE;
5125 
5126    SUMA_ENTRY;
5127 
5128    isSphere = SUMA_GEOM_NOT_SET;
5129    if (tol < 0.0) tol = 0.2;
5130 
5131    SUMA_LHv("Setting spheriosity for %s (EmbedDim=%d)\n",
5132       SO->Label ? SO->Label:"NULL", SO->EmbedDim);
5133 
5134    /* Can't rely on SO->EmbedDim for this function.
5135       It is not set when you get here, and you could
5136       get the default of 3, but check it anyway
5137    */
5138    if (SO->EmbedDim > 0 && SO->EmbedDim < 3) SUMA_RETURN(SUMA_GEOM_IRREGULAR);
5139 
5140    /* has this been determined ? */
5141    if (SUMA_IS_GEOM_SYMM(SO->isSphere)) {
5142       SUMA_LHv("%s is labeled as %d already\n", SO->Label, SO->isSphere);
5143       isSphere = SO->isSphere;
5144    }
5145 
5146    if (isSphere == SUMA_GEOM_NOT_SET) {  /* try to guess from name */
5147       SUMA_LHv("Trying to guess from name %s\n", SO->Name.FileName);
5148       switch (SO->FileType) {
5149          case SUMA_INVENTOR_GENERIC:
5150             break;
5151          case SUMA_FREE_SURFER:
5152          case SUMA_FREE_SURFER_PATCH:
5153             if (  SUMA_iswordin_ci (SO->Name.FileName, "sphere.reg") == 1 ||
5154                   SUMA_iswordin (SO->Name.FileName, "sphere") == 1   ) {
5155                isSphere = SUMA_GEOM_SPHERE;
5156             }
5157             break;
5158          case SUMA_BRAIN_VOYAGER:
5159              break;
5160          case SUMA_BYU:
5161              break;
5162          case SUMA_SUREFIT:
5163             if (SUMA_iswordin_ci (SO->Name_coord.FileName, "sphere") == 1 ) {
5164                isSphere = SUMA_GEOM_SPHERE;
5165             }
5166             break;
5167          case SUMA_VEC:
5168             break;
5169          case SUMA_FT_NOT_SPECIFIED:
5170          case SUMA_CMAP_SO:
5171          case SUMA_N_SO_FILE_TYPE:
5172          case SUMA_FT_ERROR:
5173             break;
5174          case SUMA_OPENDX_MESH:
5175          case SUMA_OBJ_MESH:
5176          case SUMA_MNI_OBJ:
5177          case SUMA_STL:
5178          case SUMA_PLY:
5179             break;
5180          case SUMA_PREDEFINED:
5181             if (  !strncmp(SO->Name.FileName, "ld",2) ) {
5182                isSphere = SUMA_GEOM_SPHERE;
5183             }
5184             break;
5185          case SUMA_GIFTI:
5186             if (SO->aSO) {
5187                if ((cc = SUMA_NI_AttrOfNamedElement( SO->aSO,
5188                                                 "Node_XYZ", "GeometricType"))) {
5189                   if (SUMA_iswordsame_ci(cc,"spherical")) {
5190                      isSphere = SUMA_GEOM_SPHERE;
5191                   }
5192                } else {
5193                   if (  SUMA_iswordin_ci (SO->Name.FileName, "sphere.reg") == 1
5194                       ||SUMA_iswordin (SO->Name.FileName, "sphere") == 1   ) {
5195                      isSphere = SUMA_GEOM_SPHERE;
5196                   }
5197                }
5198             } else {
5199                if (  SUMA_iswordin_ci (SO->Name.FileName, "sphere.reg") == 1
5200                       ||SUMA_iswordin (SO->Name.FileName, "sphere") == 1   ) {
5201                      isSphere = SUMA_GEOM_SPHERE;
5202                }
5203             }
5204             break;
5205      }
5206 
5207       /* the quick way, make sure bounding box is not that of a flat surface*/
5208       SUMA_LH("Trying to guess from aspect ratio");
5209       if (!SUMA_isSODimInitialized(SO)) {
5210          if (!SUMA_SetSODims(SO)) {
5211             SUMA_S_Err("Failed to set dims!");
5212             SUMA_RETURN(NOPE);
5213          }
5214       }else {
5215          SUMA_LH("SODim initialized already");
5216       }
5217       ra = 0.0;
5218       for (i=0;i<3;++i) { r[i] = SO->MaxDims[i]-SO->MinDims[i]; ra += r[i]; }
5219       ra /= 3.0;
5220 
5221       if (  r[0] < 0.001 || r[1] < 0.001 || r[2] < 0.001 ||
5222             r[0]/ra < 0.8 || r[1]/ra < 0.8 || r[2]/ra < 0.8) {
5223          SUMA_LHv("too distorted bounding box dimensions=[%f %f %f]\n",
5224                   r[0], r[1], r[2]);
5225          isSphere  = SUMA_GEOM_IRREGULAR;
5226       }
5227    }
5228 
5229 
5230 
5231    if (  isSphere ==  SUMA_GEOM_NOT_SET ||
5232          (SUMA_IS_GEOM_SYMM(isSphere) && SO->SphereRadius < 0.0) ) {
5233                            /* need to figure out the hard way
5234                               or need to fill up params */
5235       if (isSphere ==  SUMA_GEOM_NOT_SET) {
5236          SUMA_LHv("The hard way (tol = %f)\n", tol);
5237       } else {
5238          SUMA_LHv("Need to set radius and center. tol = %f\n", tol);
5239       }
5240       /* the hard way */
5241       if (!SUMA_GetCenterOfSphereSurface(SO, 500, cent, centmed)) {
5242          SUMA_S_Warn("Failed to guess at spheriosity.");
5243          SUMA_RETURN(NOPE);
5244       }
5245       /* is this center inside the bounding box or are we fitting
5246       spheres to flat surfaces */
5247       if (  centmed[0] <= SO->MinDims[0] || centmed[0] >= SO->MaxDims[0] ||
5248             centmed[1] <= SO->MinDims[1] || centmed[1] >= SO->MaxDims[1] ||
5249             centmed[2] <= SO->MinDims[2] || centmed[2] >= SO->MaxDims[2] ) {
5250          SUMA_LH("Failed center test, outside boundig box. Flat surface?\n");
5251             isSphere  = SUMA_GEOM_IRREGULAR;
5252             goto DONE;
5253       }
5254       /* have center, verify that all nodes are within 1/1000 of Rad */
5255       SUMA_LHv("Have a center of [%f   %f   %f] for %s\n",
5256                centmed[0] , centmed[1], centmed[2] ,
5257                SUMA_CHECK_NULL_STR(SO->Label)) ;
5258       RAD = sqrt( SUMA_POW2( SO->NodeList[0] - centmed[0] ) +
5259                   SUMA_POW2( SO->NodeList[1] - centmed[1] ) +
5260                   SUMA_POW2( SO->NodeList[2] - centmed[2] ) );
5261       RAD0 = RAD * (100.0-tol)/100.0;
5262       RAD1 = RAD * (100.0+tol)/100.0;
5263       isSphere = SUMA_GEOM_SPHERE;
5264       for (i=1; i<SO->N_Node && isSphere == SUMA_GEOM_SPHERE; ++i) {
5265          i3 = 3*i;
5266          rad = sqrt( SUMA_POW2( SO->NodeList[i3  ] - centmed[0] ) +
5267                      SUMA_POW2( SO->NodeList[i3+1] - centmed[1] ) +
5268                      SUMA_POW2( SO->NodeList[i3+2] - centmed[2] ) );
5269          if (rad < RAD0 || rad > RAD1) {
5270             /* no cigar */
5271             SUMA_LHv("Failed radius test:\n"
5272                      "Rad range [%f  %f]\n"
5273                      "Rad           %f\n", RAD0, RAD1, rad);
5274             isSphere  = SUMA_GEOM_IRREGULAR;
5275          }
5276       }
5277       if (isSphere == SUMA_GEOM_SPHERE) {
5278          SO->SphereRadius = RAD;
5279          SO->SphereCenter[0] = centmed[0];
5280          SO->SphereCenter[1] = centmed[1];
5281          SO->SphereCenter[2] = centmed[2];
5282          SUMA_LHv("A sphere it is: \n"
5283                   "r = %f\n"
5284                   "c = [%f   %f   %f]\n", SO->SphereRadius,
5285                   SO->SphereCenter[0], SO->SphereCenter[1], SO->SphereCenter[2]);
5286       }else{
5287          SUMA_LH("A sphere it is NOT, assuming it is irregular");
5288       }
5289    } else {
5290       SUMA_LHv("isSphere is %d, "
5291                "SUMA_IS_GEOM_SYMM(isSphere) = %d, SO->SphereRadius=%f\n",
5292                isSphere , SUMA_IS_GEOM_SYMM(isSphere), SO->SphereRadius);
5293    }
5294 
5295    DONE:
5296    SO->isSphere = isSphere;
5297    SUMA_RETURN (YUP);
5298 }
5299 
5300 /*---------------------------------------------------------------------------
5301  * SUMA_spec_select_surfs	  - restrict spec results to given names
5302  *								[rickr]
5303  * for each name in list
5304  *   - verify that it is in the spec file
5305  *   - verify that it is unique in the spec file
5306  * restrict the spec contents to the given name list
5307  *
5308  * return:
5309  *   (-1) on failure
5310  *   new N_Surfs on success
5311  *---------------------------------------------------------------------------
5312 */
SUMA_spec_select_surfs(SUMA_SurfSpecFile * spec,char ** names,int nnames,int debug)5313 int SUMA_spec_select_surfs( SUMA_SurfSpecFile * spec, char ** names, int nnames,
5314 		       int debug )
5315 {
5316     static char FuncName[]={"SUMA_spec_select_surfs"};
5317     char * nfile;
5318     int    name, surf, name_ind;
5319 
5320     SUMA_ENTRY;
5321 
5322     if ( ! spec || ! names )
5323     {
5324 	fprintf(stderr,"** SUMA_spec_select_surfs: invalid params (%p,%p)\n",
5325 		spec, names);
5326 	SUMA_RETURN( -1 );
5327     }
5328 
5329     if ( debug > 1 )
5330 	fprintf(stderr, "-- select surfs: searching %d names...\n", nnames);
5331 
5332     if ( nnames <= 0 )
5333 	SUMA_RETURN( 0 );
5334 
5335     /* first, check for existence and uniquenes in list */
5336     for ( name = 0; name < nnames; name++ )
5337     {
5338 	if ( ! names[name] )	/* then end the process */
5339 	{
5340 	    nnames = name;
5341 	    break;
5342 	}
5343 
5344 	name_ind = SUMA_unique_name_ind(spec, names[name]);
5345 
5346 	if ( name_ind < 0 )
5347 	{
5348 	    if ( name_ind == -1 )
5349 		fprintf(stderr,"** surface name '%s' not found\n",names[name]);
5350 	    SUMA_RETURN( -1 );
5351 	}
5352 
5353 	if ( debug > 1 )
5354 	    fprintf(stderr, "-- select surfs: found name '%s'\n", names[name]);
5355 
5356 	if ( name_ind != name )
5357 	    SUMA_swap_spec_entries(spec, name, name_ind, debug);
5358     }
5359 
5360     /* now set N_Surfs and N_Groups */
5361     spec->N_Surfs = nnames;
5362 
5363     if ( debug > 1 )
5364 	fprintf(stderr, "-- select surfs: returning %d names\n", nnames);
5365 
5366     SUMA_RETURN( nnames );
5367 }
5368 
5369 /*---------------------------------------------------------------------------
5370  * SUMA_spec_set_map_refs	  - set *all* mapping refs to SAME
5371  * 							[rickr]
5372  *---------------------------------------------------------------------------
5373 */
SUMA_spec_set_map_refs(SUMA_SurfSpecFile * spec,int debug)5374 int SUMA_spec_set_map_refs( SUMA_SurfSpecFile * spec, int debug )
5375 {
5376     int sc;
5377 
5378     for (sc = 0; sc < spec->N_Surfs; sc++ )
5379     {
5380 	if ( ! strstr(spec->MappingRef[sc],"SAME") )
5381 	{
5382 	    if ( debug > 0 )
5383 		fprintf(stderr,"-- map ref: replace '%s' with '%s'\n",
5384 			spec->MappingRef[sc], "./SAME");
5385 	    strcpy(spec->MappingRef[sc], "./SAME");
5386 	}
5387 	else if ( debug > 2 )
5388 	    fprintf(stderr,"-- mr: have good map ref '%s'\n",
5389 		    spec->MappingRef[sc]);
5390     }
5391 
5392     return 0;
5393 }
5394 
5395 /*---------------------------------------------------------------------------
5396  * SUMA_swap_spec_entries	  - swap entries for the 2 given indices
5397  * 								[rickr]
5398  * return:
5399  *    0 on success
5400  *   -1 on failure
5401  *---------------------------------------------------------------------------
5402 */
SUMA_swap_spec_entries(SUMA_SurfSpecFile * spec,int i0,int i1,int debug)5403 int SUMA_swap_spec_entries( SUMA_SurfSpecFile * spec, int i0, int i1, int debug)
5404 {
5405     char * cpsave;
5406     char   cssave[SUMA_MAX_NAME_LENGTH];
5407     int    isave, c;
5408 
5409     if ( !spec || (i0 < 0) || (i0 >= spec->N_Surfs) ||
5410 	          (i1 < 0) || (i1 >= spec->N_Surfs) )
5411     {
5412 	fprintf(stderr,"** swap_spec_entries: bad params (%p,%d,%d)\n",
5413 		spec, i0, i1);
5414 	return -1;
5415     }
5416 
5417     if ( debug > 2 )
5418 	fprintf(stderr,"-- swapping spec entries %d and %d\n", i0, i1);
5419 
5420     cssave[SUMA_MAX_NAME_LENGTH-1] = '\0';		/* to be safe */
5421 
5422     swap_strings(spec->SurfaceType[i0], spec->SurfaceType[i1],
5423 	    cssave, SUMA_MAX_LABEL_LENGTH);
5424     swap_strings(spec->SurfaceFormat[i0], spec->SurfaceFormat[i1],
5425 	    cssave, SUMA_MAX_LABEL_LENGTH);
5426     swap_strings(spec->TopoFile[i0], spec->TopoFile[i1],
5427 	    cssave, SUMA_MAX_NAME_LENGTH);
5428     swap_strings(spec->CoordFile[i0], spec->CoordFile[i1],
5429 	    cssave, SUMA_MAX_NAME_LENGTH);
5430     swap_strings(spec->MappingRef[i0], spec->MappingRef[i1],
5431 	    cssave, SUMA_MAX_NAME_LENGTH);
5432     swap_strings(spec->AnatCorrect[i0], spec->AnatCorrect[i1],
5433 	    cssave, SUMA_MAX_NAME_LENGTH);
5434     swap_strings(spec->Hemisphere[i0], spec->Hemisphere[i1],
5435 	    cssave, SUMA_MAX_NAME_LENGTH);
5436     swap_strings(spec->DomainGrandParentID[i0], spec->DomainGrandParentID[i1],
5437 	    cssave, SUMA_MAX_NAME_LENGTH);
5438     swap_strings(spec->OriginatorID[i0], spec->OriginatorID[i1],
5439 	    cssave, SUMA_MAX_NAME_LENGTH);
5440     swap_strings(spec->LocalCurvatureParent[i0], spec->LocalCurvatureParent[i1],
5441 	    cssave, SUMA_MAX_NAME_LENGTH);
5442     swap_strings(spec->LocalDomainParent[i0], spec->LocalDomainParent[i1],
5443 	    cssave, SUMA_MAX_NAME_LENGTH);
5444     swap_strings(spec->SureFitVolParam[i0], spec->SureFitVolParam[i1],
5445 	    cssave, SUMA_MAX_NAME_LENGTH);
5446     swap_strings(spec->SurfaceFile[i0], spec->SurfaceFile[i1],
5447 	    cssave, SUMA_MAX_NAME_LENGTH);
5448     swap_strings(spec->VolParName[i0], spec->VolParName[i1],
5449 	    cssave, SUMA_MAX_NAME_LENGTH);
5450 
5451     cpsave           = spec->IDcode[i0];	/* (char *)IDcode */
5452     spec->IDcode[i0] = spec->IDcode[i1];
5453     spec->IDcode[i1] = cpsave;
5454 
5455     swap_strings(spec->State[i0], spec->State[i1],
5456 	    cssave, SUMA_MAX_LABEL_LENGTH);
5457     swap_strings(spec->Group[i0], spec->Group[i1],
5458 	    cssave, SUMA_MAX_NAME_LENGTH);
5459     swap_strings(spec->SurfaceLabel[i0], spec->SurfaceLabel[i1],
5460 	    cssave, SUMA_MAX_NAME_LENGTH);
5461 
5462     isave              = spec->EmbedDim[i0];
5463     spec->EmbedDim[i0] = spec->EmbedDim[i1];
5464     spec->EmbedDim[i1] = isave;
5465 
5466     /* leave N_Surfs, N_States, N_Groups, StateList, SpecFilePath */
5467 
5468     return 0;
5469 }
5470 
SUMA_copy_spec_entries(SUMA_SurfSpecFile * spec0,SUMA_SurfSpecFile * spec1,int i0,int i1,int debug)5471 int SUMA_copy_spec_entries( SUMA_SurfSpecFile * spec0, SUMA_SurfSpecFile *spec1,
5472                             int i0, int i1, int debug)
5473 {
5474     static char FuncName[]={"SUMA_copy_spec_entries"};
5475     if ( !spec0 || !spec1 ||
5476          (i0 < 0) || (i0 >= spec0->N_Surfs) ||
5477 	      (i1 < 0) || (i1 >= spec1->N_Surfs) )
5478     {
5479 	fprintf(stderr,"** copy_spec_entries: bad params (%p,%d,%p,%d)\n",
5480 		spec0, i0, spec1, i1);
5481 	return -1;
5482     }
5483 
5484     if ( debug > 2 )
5485 	fprintf(stderr,"-- copying spec entries from spec0[%d] to spec1[%d]\n",
5486                   i0, i1);
5487 
5488     copy_strings(spec0->SurfaceType[i0], spec1->SurfaceType[i1],
5489 	              SUMA_MAX_LABEL_LENGTH);
5490     copy_strings(spec0->SurfaceFormat[i0], spec1->SurfaceFormat[i1],
5491 	              SUMA_MAX_LABEL_LENGTH);
5492     copy_strings(spec0->TopoFile[i0], spec1->TopoFile[i1],
5493 	              SUMA_MAX_FP_NAME_LENGTH);
5494     copy_strings(spec0->CoordFile[i0], spec1->CoordFile[i1],
5495 	              SUMA_MAX_NAME_LENGTH);
5496     copy_strings(spec0->MappingRef[i0], spec1->MappingRef[i1],
5497 	              SUMA_MAX_FP_NAME_LENGTH);
5498     copy_strings(spec0->AnatCorrect[i0], spec1->AnatCorrect[i1],
5499 	              SUMA_MAX_LABEL_LENGTH);
5500     copy_strings(spec0->Hemisphere[i0], spec1->Hemisphere[i1],
5501 	              SUMA_MAX_LABEL_LENGTH);
5502     copy_strings(spec0->DomainGrandParentID[i0], spec1->DomainGrandParentID[i1],
5503 	              SUMA_MAX_LABEL_LENGTH);
5504     copy_strings(spec0->OriginatorID[i0], spec1->OriginatorID[i1],
5505 	              SUMA_MAX_LABEL_LENGTH);
5506     copy_strings(spec0->LocalCurvatureParent[i0],spec1->LocalCurvatureParent[i1],
5507 	              SUMA_MAX_FP_NAME_LENGTH);
5508     copy_strings(spec0->LocalDomainParent[i0], spec1->LocalDomainParent[i1],
5509 	              SUMA_MAX_FP_NAME_LENGTH);
5510     copy_strings(spec0->SureFitVolParam[i0], spec1->SureFitVolParam[i1],
5511 	              SUMA_MAX_FP_NAME_LENGTH);
5512     copy_strings(spec0->SurfaceFile[i0], spec1->SurfaceFile[i1],
5513 	              SUMA_MAX_FP_NAME_LENGTH);
5514     copy_strings(spec0->VolParName[i0], spec1->VolParName[i1],
5515 	              SUMA_MAX_FP_NAME_LENGTH);
5516 
5517     spec1->IDcode[i1] = spec0->IDcode[i0]; /* always pointer copy for this one */
5518 
5519     copy_strings(spec0->State[i0], spec1->State[i1],
5520 	              SUMA_MAX_LABEL_LENGTH);
5521     copy_strings(spec0->Group[i0], spec1->Group[i1],
5522 	              SUMA_MAX_LABEL_LENGTH);
5523      copy_strings(spec0->SurfaceLabel[i0], spec1->SurfaceLabel[i1],
5524 	              SUMA_MAX_LABEL_LENGTH);
5525 
5526     spec1->EmbedDim[i1] = spec0->EmbedDim[i0];
5527 
5528     /* leave N_Surfs, N_States, N_Groups, StateList, SpecFilePath */
5529 
5530     return 0;
5531 }
5532 
5533 /*---------------------------------------------------------------------------
5534  * swap_strings	  		- swap the two strings using the given space
5535  * 								[rickr]
5536  * return:
5537  *   (-1) on failure
5538  *   new N_Surfs on success
5539  *---------------------------------------------------------------------------
5540 */
swap_strings(char * s0,char * s1,char * space,int len)5541 int swap_strings( char * s0, char * s1, char * space, int len )
5542 {
5543     if ( ! s0 || ! s1 || ! space || len < 1 )
5544     {
5545 	fprintf(stderr,"** swap_strings: invalid params (%p,%p,%p,%d)\n",
5546 		s0, s1, space, len);
5547     }
5548 
5549     s0   [len-1] = '\0';		/* now safe using strcpy */
5550     s1   [len-1] = '\0';
5551     space[len-1] = '\0';
5552 
5553     strcpy(space, s0);
5554     strcpy(s0,    s1);
5555     strcpy(s1,    space);
5556 
5557     return 0;
5558 }
copy_strings(char * s0,char * s1,int len)5559 int copy_strings( char * s0, char * s1, int len )
5560 {
5561     if ( ! s0 || ! s1 || len < 1 )
5562     {
5563 	fprintf(stderr,"** copy_strings: invalid params (%p,%p,%d)\n",
5564 		s0, s1, len);
5565     }
5566 
5567     s0   [len-1] = '\0';		/* now safe using strcpy */
5568     s1   [len-1] = '\0';
5569 
5570     strcpy(s1,    s0);
5571 
5572     return 0;
5573 }
5574 
5575 /*---------------------------------------------------------------------------
5576  * SUMA_unique_name_ind		  - check that name exists uniquely [rickr]
5577  *
5578  * return:
5579 
5580  *   -1    on "not found"
5581  *   -2    on "multiple matches"
5582  *   -3    on "bad, horrible failure"
5583  *---------------------------------------------------------------------------
5584 */
SUMA_unique_name_ind(SUMA_SurfSpecFile * spec,char * sname)5585 int SUMA_unique_name_ind( SUMA_SurfSpecFile * spec, char * sname )
5586 {
5587     char * nfile;
5588     int    surf, index = -1;
5589 
5590     if ( ! spec || ! sname )
5591     {
5592 	fprintf(stderr,"** unique_name_ind: bad params (%p, %p)\n",spec,sname);
5593 	return -3;
5594     }
5595 
5596     for ( surf = 0; surf < spec->N_Surfs; surf++ )
5597     {
5598 	nfile = SUMA_coord_file(spec, surf);
5599 
5600 	if ( ! nfile )
5601 	{
5602 	    fprintf(stderr,"** surf %d, no coord file\n", surf);
5603 	    return -3;
5604 	}
5605 
5606 	/* we have a match */
5607 	if ( strstr(nfile, sname) )
5608 	{
5609 	    if ( index >= 0 )
5610 	    {
5611 		fprintf(stderr,"** surf name %d, '%s': multiple matches\n"
5612 			"   '%s' and '%s'\n",
5613 			surf, sname, nfile, SUMA_coord_file(spec,index));
5614 		return -2;
5615 	    }
5616 
5617 	    index = surf;
5618 	}
5619     }
5620 
5621     return index;
5622 }
5623 
5624 /* Like SUMA_unique_name_ind, but return a pointer copy to the
5625    coordfile name instead.
5626    An empty string is retuned in error cases or no match */
SUMA_unique_name(SUMA_SurfSpecFile * spec,char * sname)5627 char * SUMA_unique_name( SUMA_SurfSpecFile * spec, char * sname )
5628 {
5629     char * nfile;
5630     int    surf, index = -1;
5631 
5632     if ( ! spec || ! sname )
5633     {
5634 	fprintf(stderr,"** unique_name_ind: bad params (%p, %p)\n",spec,sname);
5635 	return ("");
5636     }
5637 
5638     for ( surf = 0; surf < spec->N_Surfs; surf++ )
5639     {
5640 	nfile = SUMA_coord_file(spec, surf);
5641 
5642 	if ( ! nfile )
5643 	{
5644 	    fprintf(stderr,"** surf %d, no coord file\n", surf);
5645 	    return ("");
5646 	}
5647 
5648 	/* we have a match */
5649 	if ( strstr(nfile, sname) )
5650 	{
5651 	    if ( index >= 0 )
5652 	    {
5653 		fprintf(stderr,"** surf name %d, '%s': multiple matches\n"
5654 			"   '%s' and '%s'\n",
5655 			surf, sname, nfile, SUMA_coord_file(spec,index));
5656 		return ("");
5657 	    }
5658 
5659 	    index = surf;
5660 	}
5661     }
5662 
5663     if (!(nfile = SUMA_coord_file(spec,index))) return("");
5664     return (nfile);
5665 }
5666 
5667 /*---------------------------------------------------------------------------
5668  * SUMA_coord_file	  - based on the surf type, return coord file
5669  *								[rickr]
5670  * return:
5671  *   on success, pointer to coord file
5672  *   on any failure, NULL
5673  *---------------------------------------------------------------------------
5674 */
SUMA_coord_file(SUMA_SurfSpecFile * spec,int index)5675 char * SUMA_coord_file( SUMA_SurfSpecFile * spec, int index )
5676 {
5677     char * rp;
5678 
5679     if ( ! spec || (index < 0) )
5680     {
5681 	fprintf(stderr,"** coord_file: bad params (%p,%d)\n", spec, index);
5682         return NULL;
5683     }
5684 
5685     /* SurfaceType field must match the TypeCodes              13 Nov 2007 */
5686     switch( SUMA_SurfaceTypeCode((spec->SurfaceType[index])) ){
5687         case SUMA_FT_NOT_SPECIFIED:
5688             return NULL;
5689         case SUMA_VEC:
5690         case SUMA_SUREFIT:
5691             return spec->CoordFile[index];
5692         default: /* FreeSurfer, Ply, etc. */
5693             return spec->SurfaceFile[index];
5694     }
5695 }
5696 
5697 /*!
5698    return 1 if ld# surface, par takes #
5699           2 if rd# surface, par takes #
5700           3 if template spec, par is useless
5701           4 if template surface, par is useless
5702           0 not a prededined surface name
5703 
5704    \sa SUMA_IS_LOADABLE_SO_NAME
5705 */
SUMA_is_predefined_SO_name(char * name,int * upar,char ** pdspec,char ** pdsv,char ** pdsname)5706 int SUMA_is_predefined_SO_name(char *name, int *upar,
5707                                char **pdspec, char **pdsv, char **pdsname)
5708 {
5709    static char FuncName[]={"SUMA_is_predefined_SO_name"};
5710    int ldv = 0, tp = 0, par, StdOK=0, ii=0;
5711    NI_str_array *nisa=NULL;
5712    char *template=NULL, *leftover=NULL, *svname=NULL,
5713          *sname=NULL, *ss=NULL, stmp[64], *specname, *spref=NULL;
5714    SUMA_SO_SIDE side = SUMA_SIDE_ERROR;
5715    SUMA_SurfSpecFile spec;
5716    SUMA_Boolean LocalHead = NOPE;
5717 
5718    SUMA_ENTRY;
5719 
5720    if (!name) SUMA_RETURN(tp);
5721    if (  (pdspec && *pdspec) || (pdsv && *pdsv) || (pdsname && *pdsname)) {
5722       SUMA_S_Err("Must sent pointer to null char * pointer, or just NULL");
5723       SUMA_RETURN(tp);
5724    }
5725 
5726    if (upar) *upar = -1;
5727 
5728    if (!(nisa = SUMA_comp_str_2_NI_str_ar(name, ":"))) SUMA_RETURN(tp);
5729 
5730    if (nisa->num == 0) {
5731       /* this should not happen... */
5732       SUMA_free_NI_str_array(nisa); SUMA_RETURN(tp);
5733    }
5734 
5735    par = -1; tp = 0;
5736    template = NULL; side = SUMA_LR; StdOK = 1;
5737    leftover = NULL;
5738    for (ii=0; ii<nisa->num && StdOK; ++ii) {
5739       if (  (!strncmp(nisa->str[ii],"ld",2) || !strncmp(nisa->str[ii],"rd",2)) &&
5740             (strlen(nisa->str[ii]) <= 5) ) { /* Look for something like ld60 */
5741             ldv = (int)atoi(nisa->str[ii]+2);
5742          if (*nisa->str[ii]=='r' && ldv >= 0 && ldv <=100) {
5743             par = ldv;
5744             tp = 2;
5745          }
5746          if (*nisa->str[ii]=='l' && ldv >= 0 && ldv <=1000) {
5747             par = ldv;
5748             tp = 1;
5749          }
5750          if (par == -1) { /* not that kind of a block, and
5751                              hence not a standard name, leave */
5752             StdOK = 0;
5753          }
5754       } else if ( !strcmp(nisa->str[ii],"MNI_N27") ) {/* A template name */
5755          template = "suma_MNI_N27";
5756          spref = "MNI_N27";
5757       } else if (!strcmp(nisa->str[ii],"TT_N27") ) {/* A template name */
5758          template = "suma_TT_N27";
5759          spref = "TT_N27";
5760       } else if ( !strcasecmp(nisa->str[ii],"l") ||
5761                   !strcasecmp(nisa->str[ii],"lh") ||
5762                   !strcasecmp(nisa->str[ii],"left") ) { /* side */
5763          side = SUMA_LEFT;
5764       } else if ( !strcasecmp(nisa->str[ii],"r") ||
5765                   !strcasecmp(nisa->str[ii],"rh") ||
5766                   !strcasecmp(nisa->str[ii],"right") ) { /* side */
5767          side = SUMA_RIGHT;
5768       } else if ( !strcasecmp(nisa->str[ii],"lr") ||
5769                   !strcasecmp(nisa->str[ii],"both") ||
5770                   !strcasecmp(nisa->str[ii],"rl") ) {  /* side */
5771          side = SUMA_LR;
5772       } else if (!leftover) { /* state/surf name, potentially */
5773          if (nisa->str[ii] && nisa->str[ii][0] != '\0') leftover = nisa->str[ii];
5774       } else { /* Uncool, get out */
5775          StdOK = 0;
5776       }
5777    }
5778 
5779    if (!template && leftover) { /* Not a standard name */
5780       SUMA_free_NI_str_array(nisa); nisa = NULL;
5781       if (upar) *upar = -1;
5782       SUMA_RETURN(0);
5783    }
5784 
5785    if (!template) {
5786       SUMA_free_NI_str_array(nisa); nisa = NULL;
5787       if (upar) *upar = par;
5788       SUMA_LHv("Command line string >>%s<< parsed to:\n"
5789                "par %d, tp = %d\n",
5790                name, par, tp);
5791       SUMA_RETURN(tp);
5792    } else { /* now it gets complicated */
5793       if (par > 0) {
5794          sprintf(stmp, "std.%d.", par);
5795       } else {
5796          stmp[0]='\0';
5797       }
5798       specname = SUMA_append_replace_string(template,stmp,"/",0);
5799       switch (side) {
5800          case SUMA_LEFT:
5801             specname = SUMA_append_replace_string(specname,"_lh.spec",spref,1);
5802             break;
5803          case SUMA_RIGHT:
5804             specname = SUMA_append_replace_string(specname,"_rh.spec",spref,1);
5805             break;
5806          case SUMA_LR:
5807             specname = SUMA_append_replace_string(specname,"_both.spec",spref,1);
5808             break;
5809          default:
5810             SUMA_S_Errv("illegal spec file 'side' == %d\n", side);
5811             specname = SUMA_append_replace_string(specname,"_BAD.spec",spref,1);
5812             break;
5813       }
5814       ss = find_afni_file(specname, 0, NULL);
5815       if (ss[0] == '\0') {
5816          SUMA_S_Errv("Spec file %s not found despite effort\n", specname);
5817          SUMA_ifree(specname); specname = NULL;
5818          SUMA_free_NI_str_array(nisa); nisa = NULL;
5819          if (upar) *upar = -1;
5820          SUMA_RETURN(0);
5821       } else {
5822          SUMA_free(specname); specname = SUMA_copy_string(ss);
5823          tp = 3;
5824       }
5825 
5826       svname = SUMA_append_replace_string(template,spref,"/",0);
5827       svname = SUMA_append_replace_string(svname,"_SurfVol.nii","",1);
5828       ss = find_afni_file(svname, 0, NULL);
5829       if (ss[0] == '\0') {/* try one more time */
5830          svname = SUMA_append_replace_string(svname,".gz","",1);
5831          ss = find_afni_file(svname, 0, NULL);
5832       }
5833       if (ss[0] == '\0') {
5834          SUMA_S_Warnv("No sv found for %s\n", specname);
5835          SUMA_ifree(svname);
5836       } else {
5837          SUMA_free(svname); svname=SUMA_copy_string(ss);
5838       }
5839    }
5840 
5841    /* So now we have a template spec, do we have a request for a particular
5842       surface ? */
5843    if (leftover) {
5844       /* load the spec, identify the surface and set its name */
5845       SUMA_AllocSpecFields(&spec);
5846       if (!SUMA_Read_SpecFile (specname, &spec)) {
5847          SUMA_S_Errv("Failed to read SpecFile %s\n", specname);
5848          SUMA_ifree(specname); specname = NULL;
5849          SUMA_free_NI_str_array(nisa); nisa = NULL;
5850          if (upar) *upar = -1;
5851           SUMA_FreeSpecFields(&spec);
5852          SUMA_RETURN(0);
5853       }
5854       ss = SUMA_unique_name( &spec, leftover );
5855       SUMA_LH("dd %s", ss);
5856       if (ss[0]=='\0') {
5857          SUMA_S_Errv("Failed to get %s from %s\n", leftover, specname);
5858          SUMA_ifree(specname); specname = NULL;
5859          SUMA_free_NI_str_array(nisa); nisa = NULL;
5860          if (upar) *upar = -1;
5861          SUMA_FreeSpecFields(&spec);
5862          SUMA_RETURN(0);
5863       }
5864       /* OK, now we have a full surface name */
5865       sname = SUMA_copy_string(ss);
5866       SUMA_FreeSpecFields(&spec);
5867 
5868       tp = 4;
5869    }
5870 
5871    SUMA_LHv("Command line string >>%s<< parsed to:\n"
5872             "specname %s, svname %s, sname %s, par %d, side %d, tp %d\n",
5873             name, specname?specname:"NULL", svname?svname:"NULL",
5874             sname?sname:"NULL", par, side, tp);
5875 
5876    if (pdspec) *pdspec = specname;
5877    else SUMA_ifree(specname);
5878    if (pdsv) *pdsv = svname;
5879    else SUMA_ifree(svname);
5880    if (pdsname) *pdsname = sname;
5881    else SUMA_ifree(sname);
5882 
5883    SUMA_RETURN(tp);
5884 }
5885 
5886 #define SUMA_CHECK_INPUT_SURF(name, topo, ok) {  \
5887    ok = 0;  \
5888    if (SUMA_is_predefined_SO_name(name, NULL, NULL, NULL, NULL)) {\
5889       ok = 1; \
5890    } else if (SUMA_filexists(name)) {   \
5891       if  (!(topo)) { ok = 1; }   \
5892       else { if (SUMA_filexists(topo)) {ok = 1;}  } \
5893    } \
5894    if (!ok) {  \
5895       if (topo) { \
5896          fprintf(SUMA_STDERR,"Error %s:\nCould not locate surface %s %s\n", FuncName, name, topo); \
5897       } else { \
5898          fprintf(SUMA_STDERR,"Error %s:\nCould not locate surface %s \n", FuncName, name); \
5899       }  \
5900    }  \
5901 }
5902 
5903 #define SUMA_BLANK_NEW_SPEC_SURF(spec)  {\
5904          spec->IDcode[spec->N_Surfs]= NULL;  \
5905          spec->SurfaceLabel[spec->N_Surfs][0] = '\0'; \
5906          spec->EmbedDim[spec->N_Surfs] = 3;  \
5907          strcpy(spec->AnatCorrect[spec->N_Surfs], "Y");  \
5908          spec->Hemisphere[spec->N_Surfs][0] = '\0';   \
5909          spec->DomainGrandParentID[spec->N_Surfs][0] = '\0';   \
5910          strcpy(spec->LocalDomainParent[spec->N_Surfs],"SAME");  \
5911          spec->LocalCurvatureParent[spec->N_Surfs][0] = '\0';  \
5912          spec->OriginatorID[spec->N_Surfs][0] = '\0'; \
5913 }
5914 
SUMA_Show_IO_args(SUMA_GENERIC_ARGV_PARSE * ps)5915 void SUMA_Show_IO_args(SUMA_GENERIC_ARGV_PARSE *ps)
5916 {
5917    static char FuncName[]={"SUMA_Show_IO_args"};
5918    int i;
5919 
5920    SUMA_ENTRY;
5921 
5922    if (!ps) { fprintf(SUMA_STDERR,"NULL ps\n"); SUMA_RETURNe; }
5923 
5924    fprintf(SUMA_STDERR,"%saccepting -t* options\n",
5925       ps->accept_t ? "":"not");
5926    fprintf(SUMA_STDERR,"%saccepting -surf_* options\n",
5927       ps->accept_s ? "":"not");
5928    fprintf(SUMA_STDERR,"%saccepting -i_* options\n",
5929       ps->accept_i ? "":"not");
5930    fprintf(SUMA_STDERR,"%saccepting -ipar_* options\n",
5931       ps->accept_ipar ? "":"not");
5932    fprintf(SUMA_STDERR,"%saccepting -o_* options\n",
5933       ps->accept_o ? "":"not");
5934    fprintf(SUMA_STDERR,"%saccepting -spec option\n",
5935       ps->accept_spec ? "":"not");
5936    fprintf(SUMA_STDERR,"%saccepting -sv option\n",
5937       ps->accept_sv ? "":"not");
5938    fprintf(SUMA_STDERR,"%saccepting -talk_suma options\n",
5939       ps->accept_talk_suma ? "":"not");
5940    fprintf(SUMA_STDERR,"%saccepting -mask options\n",
5941       ps->accept_mask ? "":"not");
5942    fprintf(SUMA_STDERR,"%saccepting -cmap options\n",
5943       ps->accept_cmap ? "":"not");
5944    fprintf(SUMA_STDERR,"%saccepting -dset options\n",
5945       ps->accept_dset ? "":"not");
5946    fprintf(SUMA_STDERR,
5947             "Check for input surface files: %d\n", ps->check_input_surf);
5948    fprintf(SUMA_STDERR,"%d sv:\n", ps->N_sv);
5949    if (ps->N_sv) {
5950       for (i=0; i<ps->N_sv; ++i) {
5951          fprintf(SUMA_STDERR,"   %d: %s\n", i, ps->sv[i]);
5952       }
5953    }
5954    fprintf(SUMA_STDERR,"%d vp:\n", ps->N_vp);
5955    if (ps->N_vp) {
5956       for (i=0; i<ps->N_vp; ++i) {
5957          fprintf(SUMA_STDERR,"   %d: %s\n", i, ps->vp[i]);
5958       }
5959    }
5960    fprintf(SUMA_STDERR,"bmaskname: %s\n", CHECK_NULL_STR(ps->bmaskname));
5961    fprintf(SUMA_STDERR,"nmaskname: %s\n", CHECK_NULL_STR(ps->nmaskname));
5962    fprintf(SUMA_STDERR,"cmask: %s\n", CHECK_NULL_STR(ps->cmask));
5963 
5964    fprintf(SUMA_STDERR,"%d spec names:\n", ps->N_spec_names);
5965    for (i=0; i<ps->N_spec_names; ++i) {
5966       fprintf(SUMA_STDERR,"   %d: %s\n", i, ps->spec_names[i]);
5967    }
5968    fprintf(SUMA_STDERR,"%d s_surfnames from %s\n",
5969                 ps->s_N_surfnames, ps->spec_names[0]);
5970    for (i=0; i<ps->s_N_surfnames; ++i) {
5971       fprintf(SUMA_STDERR,"   %d: %s\n", i, ps->s_surfnames[i]);
5972    }
5973    fprintf(SUMA_STDERR,"%d i_surfnames\n", ps->i_N_surfnames);
5974    for (i=0; i<ps->i_N_surfnames; ++i) {
5975       if (ps->i_surftopo[i])
5976          fprintf(SUMA_STDERR,
5977                   "   %d: %s %s %s %s\n",
5978                   i, ps->i_group[i], ps->i_state[i],
5979                   ps->i_surfnames[i], ps->i_surftopo[i]);
5980       else fprintf(SUMA_STDERR,
5981                   "   %d: %s %s %s\n",
5982                   i, ps->i_group[i], ps->i_state[i],ps->i_surfnames[i]);
5983    }
5984    fprintf(SUMA_STDERR,"%d ipar_surfnames\n", ps->ipar_N_surfnames);
5985    for (i=0; i<ps->ipar_N_surfnames; ++i) {
5986       if (ps->ipar_surftopo[i])
5987          fprintf(SUMA_STDERR,
5988                   "   %d: %s %s %s %s\n",
5989                   i, ps->ipar_group[i], ps->ipar_state[i],
5990                   ps->ipar_surfnames[i], ps->ipar_surftopo[i]);
5991       else fprintf(SUMA_STDERR,
5992                    "   %d: %s %s %s\n",
5993                    i, ps->ipar_group[i], ps->ipar_state[i],
5994                    ps->ipar_surfnames[i]);
5995    }
5996    fprintf(SUMA_STDERR,"%d o_surfnames\n", ps->o_N_surfnames);
5997    for (i=0; i<ps->o_N_surfnames; ++i) {
5998       if (ps->o_surftopo[i])
5999          fprintf(SUMA_STDERR,
6000                   "   %d: %s %s %s %s\n",
6001                   i, ps->o_group[i], ps->o_state[i],
6002                   ps->o_surfnames[i], ps->o_surftopo[i]);
6003       else fprintf(SUMA_STDERR,
6004                   "   %d: %s %s %s\n",
6005                   i, ps->o_group[i], ps->o_state[i], ps->o_surfnames[i]);
6006    }
6007    fprintf(SUMA_STDERR,"%d t_surfnames\n", ps->t_N_surfnames);
6008    for (i=0; i<ps->t_N_surfnames; ++i) {
6009       if (ps->t_surftopo[i])
6010          fprintf(SUMA_STDERR,
6011                   "   %d: %s %s %s %s\n",
6012                   i, ps->o_group[i], ps->t_state[i],
6013                   ps->t_surfnames[i], ps->t_surftopo[i]);
6014       else fprintf(SUMA_STDERR,
6015                   "   %d: %s %s %s\n",
6016                   i, ps->o_group[i], ps->t_state[i], ps->t_surfnames[i]);
6017    }
6018 
6019    if (ps->accept_talk_suma) {
6020       if (!ps->cs) {
6021          fprintf(SUMA_STDERR,"No Talking to SUMA requested\n");
6022       } else {
6023          fprintf(SUMA_STDERR,"Talking to SUMA requested.\n");
6024       }
6025    }
6026    fprintf( SUMA_STDERR,
6027             "%d arguments on command line (+checked, -not checked):\n"
6028             , ps->N_args);
6029    for (i=0; i<ps->N_args; ++i) {
6030       if (ps->arg_checked[i])
6031          fprintf(SUMA_STDERR,
6032                   " %d+   ",i);
6033       else fprintf(SUMA_STDERR," %d-   ",i);
6034    }
6035    fprintf(SUMA_STDERR,"\n");
6036 
6037    SUMA_RETURNe;
6038 }
6039 
6040 /*!
6041    Take a vector of independent surfaces and get a Spec file that goes
6042    with them
6043 */
SUMA_SOGroup_2_Spec(SUMA_SurfaceObject ** SOv,int N_SOv)6044 SUMA_SurfSpecFile *SUMA_SOGroup_2_Spec(SUMA_SurfaceObject **SOv, int N_SOv)
6045 {
6046    static char FuncName[]={"SUMA_SOGroup_2_Spec"};
6047    SUMA_SurfSpecFile *spec = NULL;
6048    int i, nspec;
6049    char si[100];
6050    SUMA_GENERIC_ARGV_PARSE *ps=NULL;
6051    SUMA_Boolean LocalHead = NOPE;
6052 
6053    SUMA_ENTRY;
6054 
6055    ps = SUMA_CreateGenericArgParse("-i;");
6056    ps->check_input_surf = 0;
6057    ps->i_N_surfnames = N_SOv;
6058    for (i=0; i<ps->i_N_surfnames; ++i) {
6059       sprintf(si, "s_%d\n", i);
6060       if (SOv[i]->Label) ps->i_surfnames[i] = SUMA_copy_string(SOv[i]->Label);
6061       else ps->i_surfnames[i] =  SUMA_copy_string(si);
6062       if (SOv[i]->State) ps->i_state[i] = SUMA_copy_string(SOv[i]->State);
6063       if (SOv[i]->Group) ps->i_group[i] = SUMA_copy_string(SOv[i]->Group);
6064       ps->i_FT[i] = SUMA_FT_NOT_SPECIFIED; ps->i_FF[i] = SUMA_FF_NOT_SPECIFIED;
6065    }
6066 
6067    spec = SUMA_IO_args_2_spec(ps, &nspec);
6068    if (nspec != 1) {
6069       SUMA_S_Err( "Expecting one spec struct here!\n"
6070                   "Trouble might befall you ahead.");
6071    }
6072    SUMA_FreeGenericArgParse(ps); ps = NULL;
6073 
6074    SUMA_RETURN(spec);
6075 }
6076 
SUMA_IO_args_2_spec(SUMA_GENERIC_ARGV_PARSE * ps,int * nspec)6077 SUMA_SurfSpecFile *SUMA_IO_args_2_spec(SUMA_GENERIC_ARGV_PARSE *ps, int *nspec)
6078 {
6079    static char FuncName[]={"SUMA_IO_args_2_spec"};
6080    int i=0, ispec0;
6081    byte ok;
6082    char sbuf[SUMA_MAX_LABEL_LENGTH+1];
6083    static char defgroup[]={SUMA_DEF_GROUP_NAME};
6084    SUMA_SurfSpecFile *spec = NULL;
6085    SUMA_Boolean LocalHead = NOPE;
6086 
6087    SUMA_ENTRY;
6088 
6089 
6090    /* first look for virtual spec */
6091    *nspec = 1;
6092    spec = (SUMA_SurfSpecFile *)SUMA_malloc(sizeof(SUMA_SurfSpecFile));
6093    /* initialize the spec ZSS Jan 9 06*/
6094    if (!SUMA_AllocSpecFields(spec)) {
6095       SUMA_S_Err("Failed to initialize spec\n" );
6096       SUMA_RETURN(NULL);
6097    }
6098 
6099    spec->N_Surfs = 0;
6100    spec->N_States = 0;
6101    spec->N_DO = 0;
6102    spec->N_Groups = 1;
6103    strcpy(spec->SpecFilePath, "./");
6104    strcpy(spec->SpecFileName, "FromCommandLine.spec");
6105    SUMA_LHv("Accept_do: %d, %d DOs\n", ps->accept_do, ps->N_DO);
6106    if (ps->accept_do) {
6107       SUMA_LH("Processing -tract/-graph/-vol");
6108       if (ps->N_DO+spec->N_DO >= SUMA_MAX_N_DO_SPEC) {
6109          SUMA_S_Err("Too many DOs to work with.\n");
6110          *nspec = 0; SUMA_RETURN(spec);
6111       }
6112       for (i=0; i<ps->N_DO; ++i) {
6113          spec->DO_type[spec->N_DO] = ps->DO_type[i];
6114          strcpy(spec->DO_name[spec->N_DO], ps->DO_name[i]);
6115          ++spec->N_DO;
6116       }
6117    }
6118 
6119    if (ps->accept_i) {
6120       SUMA_LH("Processing -i");
6121       if (ps->i_N_surfnames+spec->N_Surfs >= SUMA_MAX_N_SURFACE_SPEC) {
6122          SUMA_S_Err("Too many surfaces to work with.\n");
6123          *nspec = 0; SUMA_RETURN(spec);
6124       }
6125       for (i=0; i<ps->i_N_surfnames; ++i) {
6126          if (ps->check_input_surf) {
6127             SUMA_CHECK_INPUT_SURF(ps->i_surfnames[i], ps->i_surftopo[i], ok);
6128             if (!ok) {
6129                SUMA_free(spec); spec = NULL; *nspec = 0; SUMA_RETURN(spec);
6130             }
6131          }
6132          strcpy(  spec->SurfaceType[spec->N_Surfs],
6133                   SUMA_SurfaceTypeString (ps->i_FT[i]));
6134          if (  ps->i_FF[i] == SUMA_BINARY ||
6135                ps->i_FF[i] == SUMA_BINARY_LE ||
6136                ps->i_FF[i] == SUMA_BINARY_BE)
6137             strcpy(spec->SurfaceFormat[spec->N_Surfs], "BINARY");
6138          else if (ps->i_FF[i] == SUMA_XML_SURF ||
6139                   ps->i_FF[i] == SUMA_XML_ASCII_SURF ||
6140                   ps->i_FF[i] == SUMA_XML_B64_SURF ||
6141                   ps->i_FF[i] == SUMA_XML_B64GZ_SURF )
6142                strcpy(spec->SurfaceFormat[spec->N_Surfs], "XML");
6143          else strcpy(spec->SurfaceFormat[spec->N_Surfs], "ASCII");
6144          if (ps->i_FT[i] == SUMA_SUREFIT || ps->i_FT[i] == SUMA_VEC) {
6145             strcpy(spec->TopoFile[spec->N_Surfs], ps->i_surftopo[i]);
6146             strcpy(spec->CoordFile[spec->N_Surfs], ps->i_surfnames[i]);
6147             if (ps->vp[i])
6148                strcpy(spec->SureFitVolParam[spec->N_Surfs], ps->vp[i]);
6149          } else {
6150             strcpy(spec->SurfaceFile[spec->N_Surfs], ps->i_surfnames[i]);
6151          }
6152          if (ps->sv[i])
6153             strcpy(spec->VolParName[spec->N_Surfs], ps->sv[i]);
6154          else spec->VolParName[spec->N_Surfs][0] = '\0';
6155          if (ps->i_state[i])  {
6156             strcpy(spec->State[spec->N_Surfs], ps->i_state[i]);
6157             ++spec->N_States;
6158          } else {
6159             if (!ps->onestate) {
6160                sprintf(spec->State[spec->N_Surfs], "iS_%d", spec->N_States);
6161                ++spec->N_States;
6162             } else {
6163                sprintf(spec->State[spec->N_Surfs], "iS");
6164                spec->N_States = 1;
6165             }
6166          }
6167          if (ps->anatomical == 1) sprintf(spec->AnatCorrect[spec->N_Surfs],"Y");
6168          else if (ps->anatomical == -1)
6169             sprintf(spec->AnatCorrect[spec->N_Surfs],"N");
6170          if (ps->i_group[i])  {
6171             strcpy(spec->Group[spec->N_Surfs], ps->i_group[i]);
6172          } else { strcpy(spec->Group[spec->N_Surfs], defgroup);  }
6173          SUMA_BLANK_NEW_SPEC_SURF(spec);
6174          ++spec->N_Surfs;
6175       }
6176    }
6177 
6178    if (ps->accept_ipar) {
6179       SUMA_LH("Processing -ipar");
6180       if (ps->ipar_N_surfnames+spec->N_Surfs >= SUMA_MAX_N_SURFACE_SPEC) {
6181          SUMA_S_Err("Too many surfaces to work with.\n");
6182          *nspec = 0;
6183          SUMA_RETURN(spec);
6184       }
6185       for (i=0; i<ps->ipar_N_surfnames; ++i) {
6186          if (ps->check_input_surf) {
6187             SUMA_CHECK_INPUT_SURF(  ps->ipar_surfnames[i],
6188                                     ps->ipar_surftopo[i], ok);
6189             if (!ok) {
6190                SUMA_free(spec); spec = NULL; *nspec = 0; SUMA_RETURN(spec);
6191             }
6192          }
6193          strcpy(  spec->SurfaceType[spec->N_Surfs],
6194                   SUMA_SurfaceTypeString (ps->ipar_FT[i]));
6195          if (   ps->ipar_FF[i] == SUMA_BINARY || ps->ipar_FF[i] == SUMA_BINARY_LE
6196              || ps->ipar_FF[i] == SUMA_BINARY_BE)
6197             strcpy(spec->SurfaceFormat[spec->N_Surfs], "BINARY");
6198          else if (ps->ipar_FF[i] == SUMA_XML_SURF ||
6199                   ps->ipar_FF[i] == SUMA_XML_ASCII_SURF ||
6200                   ps->ipar_FF[i] == SUMA_XML_B64_SURF ||
6201                   ps->ipar_FF[i] == SUMA_XML_B64GZ_SURF )
6202                strcpy(spec->SurfaceFormat[spec->N_Surfs], "XML");
6203          else strcpy(spec->SurfaceFormat[spec->N_Surfs], "ASCII");
6204          if (ps->ipar_FT[i] == SUMA_SUREFIT || ps->ipar_FT[i] == SUMA_VEC) {
6205             strcpy(spec->TopoFile[spec->N_Surfs], ps->ipar_surftopo[i]);
6206             strcpy(spec->CoordFile[spec->N_Surfs], ps->ipar_surfnames[i]);
6207             if (ps->vp[i])
6208                strcpy(spec->SureFitVolParam[spec->N_Surfs], ps->vp[i]);
6209          } else {
6210             strcpy(spec->SurfaceFile[spec->N_Surfs], ps->ipar_surfnames[i]);
6211          }
6212          if (ps->sv[i])
6213             strcpy(spec->VolParName[spec->N_Surfs], ps->sv[i]);
6214          else spec->VolParName[spec->N_Surfs][0] = '\0';
6215          if (ps->ipar_state[i])  {
6216             strcpy(spec->State[spec->N_Surfs], ps->ipar_state[i]);
6217             ++spec->N_States;
6218          } else {
6219             sprintf(spec->State[spec->N_Surfs], "iS_%d", spec->N_States);
6220             ++spec->N_States;
6221          }
6222          if (ps->ipar_group[i])  {
6223             strcpy(spec->Group[spec->N_Surfs], ps->ipar_group[i]);
6224          } else { strcpy(spec->Group[spec->N_Surfs], defgroup);  }
6225          SUMA_BLANK_NEW_SPEC_SURF(spec);
6226          ++spec->N_Surfs;
6227       }
6228    }
6229 
6230    if (ps->accept_t) {
6231       SUMA_LH("Processing -t");
6232       if (ps->t_N_surfnames+spec->N_Surfs >= SUMA_MAX_N_SURFACE_SPEC) {
6233          SUMA_S_Err("Too many surfaces to work with.\n");
6234          *nspec = 0;
6235          SUMA_RETURN(spec);
6236       }
6237       for (i=0; i<ps->t_N_surfnames; ++i) {
6238          if (ps->check_input_surf) {
6239             SUMA_CHECK_INPUT_SURF(ps->t_surfnames[i], ps->t_surftopo[i], ok);
6240             if (!ok) {
6241                SUMA_free(spec); spec = NULL; *nspec = 0;
6242                SUMA_RETURN(spec);
6243             }
6244          }
6245          strcpy(  spec->SurfaceType[spec->N_Surfs],
6246                   SUMA_SurfaceTypeString (ps->t_FT[i]));
6247          if (  ps->t_FF[i] == SUMA_BINARY || ps->t_FF[i] == SUMA_BINARY_LE
6248             || ps->t_FF[i] == SUMA_BINARY_BE)
6249                strcpy(spec->SurfaceFormat[spec->N_Surfs], "BINARY");
6250          else if (ps->t_FF[i] == SUMA_XML_SURF ||
6251                   ps->t_FF[i] == SUMA_XML_ASCII_SURF ||
6252                   ps->t_FF[i] == SUMA_XML_B64_SURF ||
6253                   ps->t_FF[i] == SUMA_XML_B64GZ_SURF )
6254                strcpy(spec->SurfaceFormat[spec->N_Surfs], "XML");
6255          else strcpy(spec->SurfaceFormat[spec->N_Surfs], "ASCII");
6256          if (ps->t_FT[i] == SUMA_SUREFIT || ps->t_FT[i] == SUMA_VEC) {
6257             strcpy(spec->TopoFile[spec->N_Surfs], ps->t_surftopo[i]);
6258             strcpy(spec->CoordFile[spec->N_Surfs], ps->t_surfnames[i]);
6259             if (ps->vp[i])
6260                strcpy(spec->SureFitVolParam[spec->N_Surfs], ps->vp[i]);
6261          } else {
6262             strcpy(spec->SurfaceFile[spec->N_Surfs], ps->t_surfnames[i]);
6263          }
6264          if (ps->sv[i]) strcpy(spec->VolParName[spec->N_Surfs], ps->sv[i]);
6265          else spec->VolParName[spec->N_Surfs][0] = '\0';
6266          if (ps->t_state[i])  {
6267             strcpy(spec->State[spec->N_Surfs], ps->t_state[i]);
6268             ++spec->N_States;
6269          } else {
6270             sprintf(spec->State[spec->N_Surfs], "iS_%d", spec->N_States);
6271             ++spec->N_States;
6272          }
6273          if (ps->anatomical == 1) sprintf(spec->AnatCorrect[spec->N_Surfs],"Y");
6274          else if (ps->anatomical == -1)
6275             sprintf(spec->AnatCorrect[spec->N_Surfs],"N");
6276          if (ps->t_group[i])  {
6277             strcpy(spec->Group[spec->N_Surfs], ps->t_group[i]);
6278          } else { strcpy(spec->Group[spec->N_Surfs], defgroup);  }
6279          SUMA_BLANK_NEW_SPEC_SURF(spec);
6280          ++spec->N_Surfs;
6281       }
6282    }
6283 
6284    SUMA_LH("Working States");
6285 
6286    /* now create the states list */
6287    if (spec->N_Surfs || spec->N_DO) {
6288       if (spec->N_Surfs) {
6289          spec->N_States = 1;
6290          sprintf(spec->StateList, "%s|", spec->State[0]);
6291          for (i=1; i<spec->N_Surfs; ++i) {
6292             sprintf(sbuf,"%s|",spec->State[i]);
6293             if (!SUMA_iswordin(spec->StateList, sbuf)) {
6294                sprintf(spec->StateList, "%s|", spec->State[i]);
6295                ++spec->N_States;
6296             }
6297          }
6298          if (LocalHead)
6299             fprintf( SUMA_STDERR,"%s:\n%d distinct states\n%s\n",
6300                      FuncName, spec->N_States, spec->StateList);
6301       }
6302 
6303       if (spec->N_DO) {
6304          spec->N_States = 1;
6305          sprintf(spec->StateList, "ANY|");
6306       }
6307 
6308       if (spec->Group[0][0] == '\0') {
6309          /* Perhaps only DOs loaded, label the group */
6310          strcpy(spec->Group[0], "ANY");
6311       }
6312 
6313       ispec0 = *nspec;
6314    } else {
6315       if (LocalHead) fprintf(SUMA_STDERR,"%s:\n no surfs\n", FuncName);
6316       /* free Spec */
6317       {
6318          int k=0;
6319          for (k=0; k<*nspec; ++k) {
6320             if (!SUMA_FreeSpecFields(&(spec[k]))) {
6321                SUMA_S_Err("Failed to free spec fields");
6322             }
6323          }
6324       }
6325       SUMA_free(spec); spec = NULL; *nspec = 0; ispec0 = 0;
6326    }
6327 
6328    /* Now see if you have explicity define specs on command line */
6329    if (ps->accept_spec || ps->accept_s) {
6330       SUMA_LHv("Working Specs, %d %d\n"
6331                "ispec0 = %d, ps->N_spec_names = %d\n"
6332                "i=%d\n",
6333                ps->accept_spec, ps->accept_s,
6334                ispec0, ps->N_spec_names,
6335                i);
6336       if (ps->N_spec_names) {
6337          *nspec = ispec0 + ps->N_spec_names;
6338          spec = (SUMA_SurfSpecFile *)
6339                   SUMA_realloc(  spec,
6340                                  *nspec * sizeof(SUMA_SurfSpecFile));
6341          SUMA_LH("Here");
6342          for (i=0; i<ps->N_spec_names; ++i) {
6343             if (!SUMA_AllocSpecFields(&(spec[i+ispec0]))) {
6344                SUMA_S_Err("Failed to init spec fields");
6345             }
6346             if (!SUMA_Read_SpecFile (ps->spec_names[i], &(spec[i+ispec0]))) {
6347                SUMA_SL_Err("Failed to read SpecFile");
6348                {
6349                   int k=0;
6350                   for (k=0; k<*nspec; ++k) {
6351                      if (!SUMA_FreeSpecFields(&(spec[k]))) {
6352                         SUMA_S_Err("Failed to free spec fields");
6353                      }
6354                   }
6355                }
6356                SUMA_free(spec); spec = NULL; *nspec = 0;
6357                SUMA_RETURN(spec);
6358             }
6359          }
6360          /* do we have a set of surfaces to read here ?
6361             only works with one spec  */
6362          SUMA_LHv("Have %d surf_\n",ps->s_N_surfnames);
6363          if (ps->s_N_surfnames) {
6364             int n_read;
6365             if (ps->N_spec_names > 1) {
6366                SUMA_S_Err( "Cannot deal with multiple -spec on \n"
6367                            "command line combined with -surf_ selectors.");
6368                {
6369                   int k=0;
6370                   for (k=0; k<*nspec; ++k) {
6371                      if (!SUMA_FreeSpecFields(&(spec[k]))) {
6372                         SUMA_S_Err("Failed to free spec fields");
6373                      }
6374                   }
6375                }
6376                SUMA_free(spec); spec = NULL; *nspec = 0;
6377                SUMA_RETURN(spec);
6378             }
6379             /* purify the spec */
6380             n_read = SUMA_spec_select_surfs( &(spec[0+ispec0]),
6381                                              ps->s_surfnames,
6382                                              ps->s_N_surfnames, LocalHead);
6383             if (n_read < 1) {
6384                SUMA_S_Err("Failed to find surfaces in spec file");
6385                SUMA_free(spec); spec = NULL; *nspec = 0;
6386                SUMA_RETURN(spec);
6387             }
6388             if (LocalHead) {
6389                fprintf( SUMA_STDERR,
6390                         "%s (%s:%d): Selected in %d surfaces\n",
6391                         FuncName, __FILE__, __LINE__, n_read);
6392             }
6393          }
6394 
6395       }
6396    }
6397 
6398    if (LocalHead) {
6399       fprintf( SUMA_STDERR,
6400                "%s: About to return, have %d spec files.\n", FuncName, *nspec);
6401    }
6402    SUMA_RETURN(spec);
6403 }
6404 
6405 /*
6406 Current state of loading CIFTI
6407 
6408 Load dset,
6409 Prep domains
6410 Breakup dset into parts and load them individually onto their respective domains
6411 need some sort of unifying 'yoking' marker for dsets, domains, and overlays so that when user touches them it is known that user is dealing with CIFTI object
6412 
6413 Yoking can be done much like how left/right yoking in suma is handled, except there should be no guess work involved.
6414 
6415 Note that 'what' the user clicked on involve knowing the domain overwhich they clicked in conjunction with the data displayed on that domain. -- do we need this distinction?
6416 */
SUMA_LoadCIFTIDO(char * fname,SUMA_DO_CoordUnits coord_type,SUMA_DSET ** odset,int OkAdopt,int SetupOverlay,int LaunchDisplay,int MakeOverlayCurrent,SUMA_OVERLAYS ** used_over)6417 SUMA_Boolean SUMA_LoadCIFTIDO (char *fname,
6418                         SUMA_DO_CoordUnits coord_type, SUMA_DSET **odset,
6419                         int OkAdopt, int SetupOverlay, int LaunchDisplay,
6420                         int MakeOverlayCurrent, SUMA_OVERLAYS **used_over)
6421 {
6422    static char FuncName[]={"SUMA_LoadCIFTIDO"};
6423    SUMA_CIFTI_SAUX *CSaux=NULL;
6424    SUMA_DSET *cdset=NULL, *sddset=NULL;
6425    SUMA_CIFTI_DO *CO = NULL;
6426    SUMA_ALL_DO *asdo = NULL;
6427    SUMA_DSET_FORMAT tff = SUMA_NIML;
6428    DList *list=NULL;
6429    SUMA_LIST_WIDGET *LW=NULL;
6430    SUMA_DSET *dsetpre = NULL;
6431    SUMA_OVERLAYS *NewColPlane = NULL,  *colplanepre = NULL;
6432    int OverInd=-1, OKdup=-1, loc[2], pre_exist=0, isd=0;
6433    char *dsetcmap=NULL;
6434    SUMA_X_SurfCont *SurfCont=NULL;
6435    SUMA_Boolean LocalHead = NOPE;
6436 
6437    SUMA_ENTRY;
6438 
6439    if (!fname) SUMA_RETURN(NOPE);
6440    /* same value, but SUMA_WORLD should prob be _UNIT  [22 Jun 2021 rickr] */
6441    if (coord_type != SUMA_NORM_SCREEN_UNIT &&
6442        coord_type != SUMA_WORLD_UNIT) coord_type = SUMA_WORLD_UNIT;
6443 
6444    if (!(cdset = SUMA_LoadDset_eng( fname, &tff, 1 ))) {
6445       SUMA_S_Errv("Failed to open %s\n", fname);
6446       SUMA_free(fname); fname = NULL;
6447       SUMA_RETURN(NOPE);
6448    }
6449 
6450    if (!SUMA_isCIFTIDsetNgr(cdset->ngr)) {
6451       SUMA_S_Err("All is bad that starts bad, or is it?\nNot a CIFTIcle.");
6452       SUMA_RETURN(NOPE);
6453    }
6454 
6455    /* Swaps ?*/
6456    if (odset) {
6457       if (*odset == NULL) {
6458          *odset = cdset;
6459       } else {
6460          /* Replace any existing parts of *odset, with those from cdset */
6461          if (!SUMA_FreeDsetContent(*odset)) {
6462             SUMA_S_Err("Failed to free dset content");
6463             SUMA_RETURN(NOPE);
6464          }
6465          (*odset)->ngr = cdset->ngr; cdset->ngr = NULL;
6466          SUMA_FreeDset(cdset);
6467          cdset = *odset;
6468       }
6469    }
6470 
6471    /* Does this dset have a built in colormap?
6472       If it does, then loadit into SCM */
6473    if (!SUMA_Insert_Cmap_of_Dset(cdset)) {
6474       SUMA_S_Err("Failed to insert Cmap");
6475       SUMA_FreeDset(cdset); cdset = NULL;
6476 
6477       SUMA_RETURN(NOPE);
6478    }
6479 
6480 
6481    /* Get domains info from Ngr and create elementary dsets*/
6482    if (!(SUMA_CIFTI_DomainsFromNgr( cdset, SUMAg_CF->DsetList,
6483       	             	      	    SUMAg_CF->Allow_Dset_Replace, NULL))) {
6484       SUMA_S_Err("Failed to get domains from Ngr");
6485       SUMA_FreeDset(cdset);
6486       SUMA_RETURN(NOPE);
6487    }
6488 
6489    /* Can we pile onto an existing domain? (think multiple
6490       datasets over the same surface)                     */
6491 
6492    CO = NULL;
6493    if (OkAdopt && (CO = SUMA_CIFTI_find_matching_domain(cdset, NULL, -1))) {
6494       SUMA_LH("Adopting CO");
6495    } else {
6496       SUMA_LH("Create CO from cdset");
6497       if (!(CO=SUMA_CIFTI_DO_from_dset(cdset))) {
6498          SUMA_S_Err("Failed to create DO from dset");
6499          SUMA_FreeDset(cdset);
6500          SUMA_RETURN(NOPE);
6501       }
6502    }
6503 
6504    SUMA_LH("Do we really need a separate controller for CIFTI?"
6505       	   "Leave it for now, kill CSaux later if we stick with"
6506 	   "current setup...");
6507    if (!(CSaux = CDO_CSAUX(CO))) {
6508       SUMA_S_Warn("That is weird, should this happen?");
6509       if (!SUMA_AddCIFTISaux(CO)) {
6510          SUMA_S_Err("Failed to create Saux struct");
6511          SUMA_RETURN(NOPE);
6512       }
6513       CSaux = CDO_CSAUX(CO);
6514    }
6515 
6516    /* add the dset to the list SUMAg_CF->DsetList, the elementary datasets were
6517       added inside SUMA_CIFTI_DomainsFromNgr */
6518    dsetpre = cdset;
6519    if (LocalHead) {
6520       fprintf( SUMA_STDERR,
6521                "%s: New dset (%s) has pointer %p\n",
6522                FuncName, SDSET_LABEL(cdset), cdset);
6523    }
6524    if (!SUMA_InsertDsetPointer(  &cdset, SUMAg_CF->DsetList,
6525                                  SUMAg_CF->Allow_Dset_Replace)) {
6526       SUMA_SLP_Err("Failed to add new dset to list");
6527       /* is there not a function to replace a dset yet? */
6528       SUMA_FreeDset(cdset); cdset = NULL;
6529       SUMA_RETURN(NOPE);
6530    }
6531    if (LocalHead) {
6532       fprintf( SUMA_STDERR,
6533                "%s: Now dset (%s) is  pointer %p\n",
6534                FuncName, SDSET_LABEL(cdset), cdset);
6535    }
6536 
6537    /*
6538    Note that there is currently no solid way
6539    of attaching a dataset to a displayable object.
6540    That has not been needed so far. There is a meek
6541    attempt to do something with SUMA_SetParent_DsetToLoad()
6542    but only for surface-based datasets, and ONLY for generating
6543    an ID that is based on a combo of filename and parent surface.
6544 
6545    Should we need to find the DO that defines the domain of
6546    a particular CIFTI dataset, we might need to write a function
6547    to search which CDOM_type object contains an overlay for the
6548    dataset in question.
6549    */
6550 
6551    /* There is no one overlay a CIFTI dataset (or should there be a shell
6552    overlay at some point that mereley points to each of the subdomains?
6553    I don't know if that is needed yet. For now I will create a separate
6554    overlay for each of the elementary datasets */
6555    if (SetupOverlay) {
6556       if (cdset != dsetpre) { /* dset was pre-existing in the list */
6557       	 pre_exist = 1;
6558       } else pre_exist = 0;
6559 
6560 
6561       SUMA_LH("Setting up overlay for %d CIFTI elmentary datasets",
6562       	       cdset->Aux->N_doms);
6563 
6564       for (isd=0; isd<cdset->Aux->N_doms; ++isd) {
6565       	 OverInd = -1;
6566       	 {
6567          asdo = SUMA_CIFTI_subdom_ado(CO, isd);
6568 	 if (!(sddset = DSET_FIND(cdset->Aux->doms[isd]->edset_id))) {
6569 	    SUMA_S_Err("Should have found that dset (id %s), "
6570 	               "returning with potential leaks!",
6571 		       cdset->Aux->doms[isd]->edset_id);
6572 	    SUMA_RETURN(NOPE);
6573 	 }
6574 	 if (pre_exist) { /* Parent dset was pre-existing in the list,
6575 	             	     assuming the
6576 	             	     same for all elementrary datasets */
6577             if (LocalHead) {
6578                fprintf( SUMA_STDERR,
6579                         "%s: assuming dset %s (%dth from %s) (%p) pre-existing, "
6580                         "finding its pre-existing overlays.\n",
6581                         FuncName, SDSET_LABEL(sddset), isd,
6582 			SDSET_LABEL(cdset), sddset);
6583             }
6584             if (!(colplanepre = SUMA_Fetch_OverlayPointerByDset (
6585                                            asdo, sddset, &OverInd))) {
6586                SUMA_SLP_Err("Failed to fetch existing dset's "
6587                             "overlay pointer");
6588                SUMA_RETURN(NOPE);
6589             }
6590             /* Here you'd remove coord bias if you end up using it */
6591             /* and set flag to recompute clusters if you support clustering */
6592             OKdup = 1;
6593          } else { /* cdset and therefore its babies are considered new */
6594             SUMA_LH("New overlay for %s", SDSET_LABEL(sddset));
6595             colplanepre = NULL;
6596             /* The overlay index for that plane is SO->N_Overlays */
6597             OverInd = SUMA_ADO_N_Overlays(asdo);
6598             OKdup = 0;
6599          }
6600 
6601          /* set up the colormap for this dset */
6602 	 if (!(NewColPlane = SUMA_CreateOverlayPointer ( SDSET_FILENAME(sddset),
6603                                                    sddset, ADO_ID(asdo),
6604                                                    colplanepre))) {
6605 	    SUMA_S_Err("Failed in SUMA_CreateOverlayPointer for %s\n",
6606 	               SDSET_LABEL(sddset));
6607             SUMA_RETURN(NOPE);
6608          }
6609 
6610             if (SetupOverlay < 0) {
6611                SUMA_LH("Have not pondered how to do 'background' for the "
6612                        "volume part of a CIFTI domain...");
6613                NewColPlane->isBackGrnd = YUP;
6614             } else NewColPlane->isBackGrnd = NOPE;
6615 
6616             /* Add this plane to Overlays */
6617             SUMA_LH("Adding new plane to Overlays");
6618             if (!SUMA_AddNewPlane (asdo, NewColPlane, SUMAg_DOv,
6619                                    SUMAg_N_DOv, OKdup)) {
6620                SUMA_SL_Err("Failed in SUMA_AddNewPlane");
6621                SUMA_FreeOverlayPointer(NewColPlane);
6622                SUMA_S_Warn("Usually I would delete loaded dset, "
6623 	             	   "but here I would have to delete elementary beasts "
6624 			   "also. Leaving it out for now");
6625 
6626                SUMA_RETURN(NOPE);
6627             }
6628       	 }
6629 
6630       	 /* Match old settings? */
6631       	 SUMA_LH("Settings");
6632       	 if (colplanepre == NewColPlane) { /* old col plane found for this dset*/
6633             /* Don't change settings. Before Aug 2012, it would reset as below */
6634       	 } else if ((SurfCont = SUMA_ADO_Cont(asdo)) &&
6635                  SUMA_PreserveOverlaySettings(SurfCont->curColPlane,
6636                                               NewColPlane)) {
6637                            /* attempt to preserve current situation */
6638             SUMA_OVERLAYS *settingPlane = NULL;
6639             settingPlane = SurfCont->curColPlane;
6640             NewColPlane->GlobalOpacity = settingPlane->GlobalOpacity;
6641             NewColPlane->ShowMode = settingPlane->ShowMode;
6642             NewColPlane->OptScl->BrightFact = settingPlane->OptScl->BrightFact;
6643             NewColPlane->OptScl->find = settingPlane->OptScl->find;
6644             NewColPlane->OptScl->tind = settingPlane->OptScl->tind;
6645             NewColPlane->OptScl->bind = settingPlane->OptScl->bind;
6646             NewColPlane->OptScl->UseThr = settingPlane->OptScl->UseThr;
6647             NewColPlane->OptScl->UseBrt = settingPlane->OptScl->UseBrt;
6648             NewColPlane->OptScl->ThrMode = settingPlane->OptScl->ThrMode;
6649             NewColPlane->OptScl->ThreshRange[0] =
6650                                 	  settingPlane->OptScl->ThreshRange[0];
6651             NewColPlane->OptScl->ThreshRange[1] =
6652                                 	  settingPlane->OptScl->ThreshRange[1];
6653             NewColPlane->OptScl->BrightRange[0] =
6654                                 	  settingPlane->OptScl->BrightRange[0];
6655             NewColPlane->OptScl->BrightRange[1] =
6656                                 	  settingPlane->OptScl->BrightRange[1];
6657             NewColPlane->OptScl->BrightMap[0] =
6658                                 	  settingPlane->OptScl->BrightMap[0];
6659             NewColPlane->OptScl->BrightMap[1] =
6660                                 	  settingPlane->OptScl->BrightMap[1];
6661             NewColPlane->SymIrange = settingPlane->SymIrange;
6662             NewColPlane->OptScl->IntRange[0] = settingPlane->OptScl->IntRange[0];
6663             NewColPlane->OptScl->IntRange[1] = settingPlane->OptScl->IntRange[1];
6664             dsetcmap = NI_get_attribute(sddset->ngr,"SRT_use_this_cmap");
6665             if (dsetcmap) {
6666                SUMA_STRING_REPLACE(NewColPlane->cmapname, dsetcmap);
6667             } else {
6668                SUMA_STRING_REPLACE(NewColPlane->cmapname,
6669                                    settingPlane->cmapname);
6670             }
6671             NewColPlane->OptScl->Clusterize = settingPlane->OptScl->Clusterize;
6672             NewColPlane->OptScl->ClustOpt->AreaLim =
6673                settingPlane->OptScl->ClustOpt->AreaLim;
6674             NewColPlane->OptScl->ClustOpt->DistLim =
6675                settingPlane->OptScl->ClustOpt->DistLim;
6676 	 } else {
6677             SUMA_LH("New settings");
6678             /* set the opacity, index column and the range */
6679             NewColPlane->GlobalOpacity = YUP;
6680             NewColPlane->ShowMode = SW_SurfCont_DsetViewCol;
6681             if (!colplanepre) {/* only set this if first time creating plane*/
6682                NewColPlane->OptScl->BrightFact = 0.8;
6683             }
6684             NewColPlane->OptScl->find = 0;
6685             NewColPlane->OptScl->tind = 0;
6686             NewColPlane->OptScl->bind = 0;
6687             SUMA_GetDsetColRange(sddset, 0, NewColPlane->OptScl->IntRange, loc);
6688             if (NewColPlane->SymIrange) {
6689                NewColPlane->OptScl->IntRange[0] =
6690         	  -fabs(SUMA_MAX_PAIR( NewColPlane->OptScl->IntRange[0],
6691                                        NewColPlane->OptScl->IntRange[1]));
6692                NewColPlane->OptScl->IntRange[1] =
6693         	  -NewColPlane->OptScl->IntRange[0];
6694             }
6695 
6696             /* stick a colormap onto that plane ? */
6697             dsetcmap = NI_get_attribute(sddset->ngr,"SRT_use_this_cmap");
6698             if (dsetcmap) {
6699                SUMA_STRING_REPLACE(NewColPlane->cmapname, dsetcmap);
6700             } else {
6701                /* don't worry, there's a default one */
6702             }
6703 	 }
6704 	 if (NewColPlane->OptScl->Clusterize)
6705             NewColPlane->OptScl->RecomputeClust = 1;
6706 	 /* colorize the plane */
6707 	 SUMA_LH("Colorizing Plane");
6708 	 SUMA_ColorizePlane(NewColPlane);
6709 
6710 	 /* SUMA_Show_ColorOverlayPlanes(&NewColPlane, 1, 1); */
6711 
6712 	 if (SurfCont && MakeOverlayCurrent)
6713             SurfCont->curColPlane = SUMA_ADO_Overlay(asdo, OverInd);
6714       }
6715    }
6716 
6717    for (isd=0; isd<cdset->Aux->N_doms; ++isd) {
6718       asdo = SUMA_CIFTI_subdom_ado(CO, isd);
6719       if (!(sddset = DSET_FIND(cdset->Aux->doms[isd]->edset_id))) {
6720 	 SUMA_S_Err("Should had found that dset, returning with potential  "
6721 	            "leaks!");
6722 	 SUMA_RETURN(NOPE);
6723       }
6724       /* Need to get OverInd again */
6725       if (!(SUMA_Fetch_OverlayPointerByDset ( asdo, sddset, &OverInd))) {
6726          SUMA_SLP_Err("How can this possibly happen?");
6727          SUMA_RETURN(NOPE);
6728       }
6729       if ((SurfCont = SUMA_ADO_Cont(asdo)) && LaunchDisplay) {
6730 	 SUMA_LHv("Remix Redisplay %s\n", ADO_LABEL(asdo));
6731 	 /* remix-redisplay  for surface */
6732 	 if (!SUMA_Remixedisplay (asdo)) {
6733             SUMA_RETURN(NOPE);
6734 	 }
6735 
6736 	 SUMA_LH("Refreshing Dset list");
6737 	 /*update the list widget if open */
6738 	 LW = SurfCont->SwitchDsetlst;
6739 	 if (LW) {
6740             if (!LW->isShaded) SUMA_RefreshDsetList (asdo);
6741 	 }
6742 
6743 	 SUMA_LH("Refreshing sub-brick selectors");
6744 	 /* if lists for switching sub-bricks are not shaded, update them too */
6745 	 if (SurfCont->SwitchIntMenu) {
6746             if ((LW = SurfCont->SwitchIntMenu->lw) && !LW->isShaded) {
6747                SUMA_DsetColSelectList(asdo, 0, 0, 1);
6748             }
6749             if ((LW = SurfCont->SwitchThrMenu->lw) && !LW->isShaded) {
6750                SUMA_DsetColSelectList(asdo, 1, 0, 1);
6751             }
6752             if ((LW = SurfCont->SwitchBrtMenu->lw) && !LW->isShaded) {
6753                SUMA_DsetColSelectList(asdo, 2, 0, 1);
6754             }
6755 
6756             if (LocalHead)
6757                fprintf (SUMA_STDERR,
6758 
6759                 	"%s: Updating Dset frame, OverInd=%d\n",
6760                 	FuncName, OverInd);
6761             /* update the Dset frame */
6762             if (OverInd >= 0)
6763                SUMA_InitializeColPlaneShell(asdo,
6764                                             SUMA_ADO_Overlay(asdo, OverInd));
6765 	 }
6766       }
6767    }
6768 
6769    if (used_over) {
6770       SUMA_S_Warn( "Not sure how to use this for CIFTI, at the moment have"
6771       	          "multiple overlays per CO, returning last thing in hand.");
6772       *used_over = SUMA_ADO_Overlay(asdo, OverInd);
6773    }
6774 
6775    SUMA_RETURN(YUP);
6776 
6777 }
6778 
6779 /* Create CIFTI displayable object from the CIFTI dataset
6780 In the current incarnation (Tuesday Aug. 11 2015), the CIFTI DO
6781 will not be a fully fledged DO such as a surface or a volume. It
6782 is a bucket that contains references to "elementary" DOs (to parallel
6783 what happens to a multi-domain CIFTI dataset). It does not look like
6784 it will get its own controller. I am no longer seeing the need for
6785 that.
6786 */
SUMA_CIFTI_DO_from_dset(SUMA_DSET * cdset)6787 SUMA_CIFTI_DO * SUMA_CIFTI_DO_from_dset(SUMA_DSET *cdset)
6788 {
6789    static char FuncName[]={"SUMA_CIFTI_DO_from_dset"};
6790    int k;
6791    char *ss=NULL;
6792    SUMA_ALL_DO *ado=NULL;
6793    SUMA_CIFTI_DO *CO=NULL;
6794    SUMA_DSET *sddset=NULL;
6795    SUMA_Boolean LocalHead = NOPE;
6796 
6797    SUMA_ENTRY;
6798 
6799    if (!SUMA_isCIFTIDset(cdset)) {
6800       SUMA_S_Err("Not for this you don't");
6801       SUMA_RETURN(NULL);
6802    }
6803    if (!cdset || !cdset->Aux || !cdset->Aux->N_doms) {
6804       SUMA_S_Err("Junk in the house");
6805       SUMA_RETURN(NULL);
6806    }
6807    ss = SUMA_ar_string("DO_", ADO_LABEL((SUMA_ALL_DO *)cdset),"",0);
6808    CO = SUMA_CreateCIFTIObject(ss); SUMA_ifree(ss);
6809 
6810    if (CO->N_subdoms < 0) CO->N_subdoms = 0;
6811    for (k=0; k<cdset->Aux->N_doms; ++k) {
6812       if (!cdset->Aux->doms[k]->Source) {
6813          SUMA_S_Err("Null source");
6814          SUMA_FreeCIFTIObject(CO);
6815          SUMA_RETURN(NULL);
6816       }
6817 
6818       SUMA_LH("Loading source[%d]=%s", k, cdset->Aux->doms[k]->Source);
6819       switch (cdset->Aux->doms[k]->ModelType) {
6820          case SO_type: {
6821 	    ado = (SUMA_ALL_DO *)
6822                SUMA_Load_Surface_Object_eng(
6823                      cdset->Aux->doms[k]->Source,
6824                      SUMA_FT_NOT_SPECIFIED, SUMA_FF_NOT_SPECIFIED,
6825                      NULL, 2);
6826 	    SUMA_SurfaceObject *SO=(SUMA_SurfaceObject *)ado;
6827 	    if (!SUMA_ADO_Label(ado)) {
6828 	       SO->Label = SUMA_copy_string(cdset->Aux->doms[k]->Source);
6829 	    }
6830 	    SUMA_ifree(SO->State);
6831 	    SO->State = SUMA_copy_string("ANY_ANATOMICAL");
6832 	    SUMA_ifree(SO->Group);
6833 	    SO->Group = SUMA_copy_string("ANY");
6834 	    if (1) {
6835 	       SUMA_LH("Adding CO %s SOs to objects list",
6836 	             	ADO_LABEL((SUMA_ALL_DO *)CO));
6837 	       if (!SUMA_PrepAddmappableSO(SO, SUMAg_DOv, &SUMAg_N_DOv,
6838 	             	      	           1, SUMAg_CF->DsetList)) {
6839                   SUMA_SL_Err("Failed in SUMA_PrepAddmappableSO.");
6840                   SUMA_FreeCIFTIObject(CO); CO = NULL;
6841         	  SUMA_RETURN(NULL);
6842                }
6843 	    }
6844 	    /* make domain parent of matching dset be SO */
6845 	    if (!(sddset = DSET_FIND(cdset->Aux->doms[k]->edset_id))) {
6846 	       SUMA_S_Err("Should have found that dset (id %s)!",
6847 		       cdset->Aux->doms[k]->edset_id);
6848 	    } else {
6849 	       NI_set_attribute(sddset->ngr,
6850 	             	        "domain_parent_idcode", ADO_ID(ado));
6851             }
6852 	    break; }
6853          case VO_type: {
6854             SUMA_VolumeObject *VO=NULL;
6855 	    SUMA_VOL_SAUX *VSaux = NULL;
6856             SUMA_LH("This requires some additional thinking:\n"
6857                         "1-All is needed for the volume is the grid.\n"
6858                         "  So might want to have LoadVolDO create a \n"
6859                         "  dummy volume from just a grid string (AFNI has\n"
6860                         "  such utilities.\n"
6861                         "  The actual data in the volume is now loaded by\n"
6862                         "  default but it is useless because it is \n"
6863                         "  to be trumped by the data in the CIFTI dataset.\n"
6864                         "2-Even if loading volume, might want to have an\n"
6865                         "  autocrop at loading option. See AFNI convenience\n"
6866                         "  function: THD_autobbox()\n The smaller the grid \n"
6867 			"  the faster the volume rendering.\n");
6868             /* again, SUMA_WORLD should prob be _UNIT  [22 Jun 2021 rickr] */
6869             if (SUMA_LoadVolDO(cdset->Aux->doms[k]->Source,
6870                                SUMA_WORLD_UNIT, &VO, 1)){
6871 	       ado = (SUMA_ALL_DO *)VO;
6872                /* Change the state of the volume so that it is no longer
6873 	       of the default ANY_ANATOMICAL state. (See comment for string
6874 	       'State' definition in SUMA_VOL_SAUX */
6875 	       if (!(VSaux = SUMA_ADO_VSaux(ado))){
6876 	          SUMA_S_Err("No VSaux?");
6877 		  SUMA_FreeCIFTIObject(CO); CO = NULL;
6878 		  SUMA_RETURN(NULL);
6879 	       }
6880 	       SUMA_ifree(VSaux->State);
6881 	       VSaux->State = SUMA_copy_string("ANY_ANATOMICAL");
6882 	       VO = NULL;
6883 
6884 	       VSaux->ShowVrSlc = 1; /* easier for debugging */
6885             }
6886             break; }
6887          default:
6888             SUMA_S_Err("Not ready for domain %d (%s) with CIFTI",
6889                cdset->Aux->doms[k]->ModelType,
6890                SUMA_ObjectTypeCode2ObjectTypeName(
6891                                              cdset->Aux->doms[k]->ModelType));
6892             SUMA_FreeCIFTIObject(CO); CO = NULL;
6893             SUMA_RETURN(NULL);
6894             break;
6895       }
6896       if (!ado) {
6897          SUMA_S_Err("Failed to load %s\n", cdset->Aux->doms[k]->Source);
6898          SUMA_FreeCIFTIObject(CO); CO = NULL;
6899          SUMA_RETURN(NULL);
6900       } else {
6901         ++CO->N_subdoms;
6902          CO->subdoms_id = (char **)SUMA_realloc(CO->subdoms_id,
6903                                                 CO->N_subdoms*sizeof(char *));
6904          CO->subdoms_id[CO->N_subdoms-1] = SUMA_copy_string(ADO_ID(ado));
6905 	 ado = NULL;
6906       }
6907    }
6908 
6909    if (1) {
6910       SUMA_LH("Adding CO %s to objects list", ADO_LABEL((SUMA_ALL_DO *)CO));
6911       if (!SUMA_AddDO(SUMAg_DOv, &(SUMAg_N_DOv), (void *)CO,
6912                CDOM_type, SUMA_WORLD)) {
6913          fprintf(SUMA_STDERR,"Error %s: Error Adding DO\n", FuncName);
6914          SUMA_FreeCIFTIObject(CO); CO = NULL;
6915          SUMA_RETURN(NULL);
6916       }
6917    }
6918 
6919 
6920    SUMA_RETURN(CO);
6921 }
6922 
6923 /* Search all DOs for a CIFTIObject that can be the domain
6924 for a certain CIFTI dataset.
6925 
6926 For now, subdomains indices do not have to match. Might want to
6927 enforce that. */
SUMA_CIFTI_find_matching_domain(SUMA_DSET * cdset,SUMA_DO * dov,int N_dov)6928 SUMA_CIFTI_DO *SUMA_CIFTI_find_matching_domain(SUMA_DSET *cdset,
6929                                                SUMA_DO *dov, int N_dov)
6930 {
6931    static char FuncName[]={"SUMA_CIFTI_find_matching_domain"};
6932    SUMA_CIFTI_DO *CO=NULL;
6933    int i, f, k;
6934    char *sid;
6935 
6936    SUMA_ENTRY;
6937 
6938    if (!dov) { dov = SUMAg_DOv; N_dov = SUMAg_N_DOv; }
6939 
6940    for (i=0; i<N_dov; ++i) {
6941       if (dov[i].ObjectType == CDOM_type) {
6942          CO = (SUMA_CIFTI_DO *)dov[i].OP;
6943          for (f=0,k=0; k<cdset->Aux->N_doms; ++k) {
6944             sid = SUMA_CIFTI_find_sub_domain(CO,
6945                                  cdset->Aux->doms[k]->ModelType,
6946                                  cdset->Aux->doms[k]->ModelSide,
6947                                  cdset->Aux->doms[k]->Max_N_Data, NULL);
6948             if (sid) {++f;}
6949          }
6950          if (f == cdset->Aux->N_doms) {
6951             SUMA_RETURN(CO);
6952          }
6953       }
6954    }
6955    SUMA_RETURN(NULL);
6956 }
6957 
6958 /* Search the sub-domains of a CIFTIObject to match desired parameters */
SUMA_CIFTI_find_sub_domain(SUMA_CIFTI_DO * CO,SUMA_DO_Types ModelType,SUMA_SO_SIDE ModelSide,int Max_N_Data,int * k)6959 char *SUMA_CIFTI_find_sub_domain(SUMA_CIFTI_DO *CO, SUMA_DO_Types ModelType,
6960                                SUMA_SO_SIDE ModelSide,
6961                                int Max_N_Data,
6962                                int *k)
6963 {
6964    static char FuncName[]={"SUMA_CIFTI_find_sub_domain"};
6965    char *sid = NULL;
6966    int i;
6967    SUMA_ALL_DO *ado=NULL;
6968 
6969    SUMA_ENTRY;
6970    if (k) *k = -1;
6971 
6972    for (i=0; i<CO->N_subdoms; ++i) {
6973       ado = SUMA_CIFTI_subdom_ado(CO, i);
6974       if ( ado->do_type == ModelType &&
6975           (    ModelType != SO_type ||
6976                ModelSide == ((SUMA_SurfaceObject *)(ado))->Side ) &&
6977           Max_N_Data == SUMA_ADO_N_Datum(ado) ) {
6978          if (k) *k = i;
6979          SUMA_RETURN(ADO_ID((SUMA_ALL_DO*)CO));
6980       }
6981    }
6982 
6983    SUMA_RETURN(NULL);
6984 }
6985 
6986 /* Search all displayable objects for a CIFTI object containing a particular
6987    domain. */
SUMA_find_CIFTI_subdom_container(char * SD_id,int * ksubdom,SUMA_DO * dov,int N_dov)6988 SUMA_CIFTI_DO *SUMA_find_CIFTI_subdom_container(char *SD_id, int *ksubdom,
6989       	             	      	                SUMA_DO *dov, int N_dov)
6990 {
6991    static char FuncName[]={"SUMA_find_CIFTI_subdom_container"};
6992    int i, k;
6993    SUMA_CIFTI_DO *CO=NULL;
6994 
6995    SUMA_ENTRY;
6996 
6997    if (!dov) {
6998       dov = SUMAg_DOv;
6999       N_dov = SUMAg_N_DOv;
7000    }
7001 
7002    for (i=0; i<N_dov; ++i) {
7003       switch (dov[i].ObjectType) {
7004       	 default:
7005             SUMA_S_Err("invalid ObjectType in container");
7006             SUMA_RETURN(NULL);
7007 	    break;
7008       	 case CDOM_type:
7009 	    CO = (SUMA_CIFTI_DO *)dov[i].OP;
7010 	    for (k=0; k<CO->N_subdoms; ++k) {
7011 	       if (CO->subdoms_id[k] && !strcmp(SD_id, CO->subdoms_id[k])) {
7012 	          /* got it */
7013 		  if (ksubdom) *ksubdom = k;
7014 		  SUMA_RETURN(CO);
7015 	       }
7016 	    }
7017 	    break;
7018       }
7019    }
7020 
7021    SUMA_RETURN(NULL);
7022 }
7023 
SUMA_CIFTI_SubDomFullOffset(SUMA_CIFTI_DO * CO,int ksub)7024 int SUMA_CIFTI_SubDomFullOffset(SUMA_CIFTI_DO *CO, int ksub)
7025 {
7026    static char FuncName[]={"SUMA_CIFTI_SubDomFullOffset"};
7027    int i, N=0;
7028 
7029    for (i=1; i<=ksub; ++i) {
7030       N += SUMA_ADO_N_Datum(SUMA_CIFTI_subdom_ado(CO,i-1));
7031    }
7032    return(N);
7033 }
7034 
SUMA_CIFTI_subdom_ado(SUMA_CIFTI_DO * CO,int ksub)7035 SUMA_ALL_DO *SUMA_CIFTI_subdom_ado(SUMA_CIFTI_DO *CO, int ksub)
7036 {
7037    static char FuncName[]={"SUMA_CIFTI_subdom_ado"};
7038    SUMA_ALL_DO *ado=NULL;
7039 
7040    SUMA_ENTRY;
7041 
7042    if (CO && ksub >=0 && ksub < CO->N_subdoms && CO->subdoms_id[ksub]) {
7043       ado = SUMA_whichADOg(CO->subdoms_id[ksub]);
7044    }
7045 
7046    SUMA_RETURN(ado);
7047 }
7048 
7049