1 #include "mrilib.h"
2 /** #include "afni.h" **/
3 #include "cs.h"
4 
5 #ifdef KILLTHIS /* Remove all old sections framed by #ifdef KILLTHIS
6                   in the near future.  ZSS May 2011   */
7 /* THESE NEED TO BE WIPED OUT                VVVVVVVVVVVVVVVVVVV*/
8 static int           have_dseTT_old = -1   ;
9 static THD_3dim_dataset * dseTT_old = NULL ;
10 static THD_3dim_dataset * dseTT_big_old = NULL ; /* 01 Aug 2001 */
11 static int           have_dseCA_EZ_MPM_old = -1   ;
12 static THD_3dim_dataset * dseCA_EZ_MPM_old = NULL ;
13 static int           have_dseCA_EZ_PMaps_old = -1   ;
14 static THD_3dim_dataset * dseCA_EZ_PMaps_old = NULL ;
15 static int           have_dseCA_EZ_ML_old = -1   ;
16 static THD_3dim_dataset * dseCA_EZ_ML_old = NULL ;
17 static int           have_dseCA_EZ_LR_old = -1   ;
18 static THD_3dim_dataset * dseCA_EZ_LR_old = NULL ;
19 /* THESE NEED TO BE WIPED OUT                ^^^^^^^^^^^^^^^^^^^*/
20 #endif
21 
22 /* These global arrays should be accessed directly in just a few places:
23       Some of the init_* functions and the get_G_* accessor functions
24       below */
25 static ATLAS_SPACE_LIST *global_atlas_spaces=NULL;
26 static ATLAS_XFORM_LIST *global_atlas_xfl=NULL;
27 static ATLAS_LIST *global_atlas_alist=NULL;
28 static ATLAS_TEMPLATE_LIST *global_atlas_templates=NULL;
29 
30 static THD_string_array *working_atlas_name_list = NULL; /* Names of a set of
31    atlases we'll show in AFNI. There are defaults if users don't override them */
32 static THD_string_array *session_atlas_name_list=NULL; /* a set of atlases found
33            in SessionAtlases.niml, it will get added to working_atlas_name_list */
34 
35 char *old_space_list[] = {"TLRC","MNI","MNI_ANAT"};
36 
37 /* determine if any whereami requests found anything in an atlas */
38 static int wami_web_found = 0;
39 static int wami_web_reqtype = 0;
40 static char wami_url[MAX_URL];
41 static int neurosynth_link = -1;
42 static int sumsdb_link = -1;
43 static int linkrbrain_link = -1;
44 
45 /* atlas name type selected yet for region labels - name, long, both*/
46 static int atlas_name_code = -1;
47 
48 /* global web browser is used here, not sure where else to put it...      */
49 char *GLOBAL_browser = NULL ;   /* 30 Dec 2005, moved 22 Feb 2012 [rickr] */
50 
51 #ifndef TINY_NUMBER
52 /*! A very tiny, infinitessimal number */
53 #  define TINY_NUMBER 1E-10
54 #endif
55 
56 /* minimum probability (0.0-1.0) to consider with probabilistic atlases */
57 static float wami_min_prob = -1.0;
58 
recreate_working_atlas_name_list(void)59 THD_string_array *recreate_working_atlas_name_list(void) {
60    if (working_atlas_name_list) DESTROY_SARR(working_atlas_name_list);
61    return(get_working_atlas_name_list());
62 }
63 
64 /* moved TT_Daemon down the road to the end and switched
65  *  some Eickhoff-Zilles atlases to the MNI version instead of MNI_ANAT */
get_working_atlas_name_list(void)66 THD_string_array *get_working_atlas_name_list(void) {
67    char *min_atlas_list[] = {
68 	  "MNI_Glasser_HCP_v1.0","Brainnetome_1.0",
69 	  "CA_ML_18_MNI", "CA_MPM_22_MNI",
70       "DD_Desai_MPM", "DKD_Desai_MPM",
71       "CA_GW_18_MNIA", "CA_N27_LR",
72       "TT_Daemon", NULL};
73    int i;
74 
75    if (!working_atlas_name_list || working_atlas_name_list->num==0) {
76       INIT_SARR(working_atlas_name_list);
77    } else {
78       return(working_atlas_name_list);
79    }
80    if (session_atlas_name_list) {
81       for (i=0; i<session_atlas_name_list->num; ++i) {
82          ADDUTO_SARR(working_atlas_name_list,
83                      session_atlas_name_list->ar[i]);
84       }
85    }
86    i=0;
87    while (min_atlas_list[i]) {
88       ADDUTO_SARR(working_atlas_name_list, min_atlas_list[i]);
89       ++i;
90    }
91 
92    return(working_atlas_name_list);
93 }
94 
get_G_space_list(void)95 ATLAS_SPACE_LIST *get_G_space_list(void) {
96    static int icall = 0;
97    if (!icall && !global_atlas_spaces) {
98       ++icall;
99       init_global_atlas_list();
100    }
101    return(global_atlas_spaces);
102 }
103 
get_G_xform_list(void)104 ATLAS_XFORM_LIST *get_G_xform_list(void) {
105    static int icall = 0;
106    if (!icall && !global_atlas_xfl) {
107       ++icall;
108       init_global_atlas_list();
109    }
110    return(global_atlas_xfl);
111 }
112 
get_G_atlas_list(void)113 ATLAS_LIST* get_G_atlas_list(void) {
114    static int icall = 0;
115    if (!icall && !global_atlas_alist) {
116       ++icall;
117       init_global_atlas_list();
118    }
119    return(global_atlas_alist);
120 }
121 
get_G_templates_list(void)122 ATLAS_TEMPLATE_LIST *get_G_templates_list(void) {
123    static int icall = 0;
124    if (!icall && !global_atlas_templates) {
125       ++icall;
126       init_global_atlas_list();
127    }
128    return(global_atlas_templates);
129 }
130 
131 
132 #define MAX_FIND_DEFAULT 9            /* max number to find within WAMIRAD  */
133 #define WAMIRAD_DEFAULT  7.5           /* search radius: must not exceed 9.5 */
134 
PMESS(char * sss)135 static void PMESS(char *sss){ return; }
136 static void (*POPUP_MESSAGE)(char *) = PMESS ;
TT_setup_popup_func(void (* pf)(char *))137 void TT_setup_popup_func( void (*pf)(char *) )
138  { POPUP_MESSAGE = (pf==NULL) ? PMESS : pf; return; }
139 
140 static int wami_verb_val = -100; /* Don't access directly */
141 
set_wami_verb(int lev)142 void set_wami_verb(int lev) {
143    wami_verb_val = lev;
144 }
145 
wami_verb(void)146 int wami_verb(void) {
147    if (wami_verb_val < -1) {
148       char * ept = NULL;
149       if( (ept= my_getenv("AFNI_WAMI_DEBUG")) ) {
150          set_wami_verb(atoi(ept));       /* adjust if set */
151       }  else {
152          set_wami_verb(0);
153       }
154    }
155    return(wami_verb_val);
156 }
157 
wami_lh(void)158 int wami_lh(void) { return(wami_verb() > 1 ? wami_verb():0); }
159 
Init_Whereami_Max_Find(void)160 int Init_Whereami_Max_Find(void) {
161 
162    char *eee = getenv("AFNI_WHEREAMI_MAX_FIND");
163    if (eee) {
164       return(atoi(eee));
165    }
166    return(MAX_FIND_DEFAULT);
167 }
168 
Init_Whereami_Max_Rad(void)169 float Init_Whereami_Max_Rad(void) {
170 
171    char *eee = getenv("AFNI_WHEREAMI_MAX_SEARCH_RAD");
172    if (eee) {
173       if (atof(eee) > 9.5) {
174          WARNING_message(
175             "Maximum search radius cannot exceed 9.5. \n"
176             "Complain to authors if you really need this changed.\n"
177             "Clipping search radius to 9.5\n");
178          return(9.5);
179       }
180       return(atof(eee));
181    }
182    return(WAMIRAD_DEFAULT);
183 }
184 
185 static int MAX_FIND = -1;
186 static float WAMIRAD = -1.0;
187 
Set_Whereami_Max_Find(int n)188 void Set_Whereami_Max_Find(int n) {
189    if (n > 0) {
190       MAX_FIND = n;
191    } else {
192       MAX_FIND = Init_Whereami_Max_Find();
193    }
194    return;
195 }
Set_Whereami_Max_Rad(float n)196 void Set_Whereami_Max_Rad(float n) {
197    if (n > 9.5) {
198       WARNING_message("Maximum search radius cannot exceed 9.5");
199       n = 9.5;
200    }
201    if (n > 0.0) {
202       WAMIRAD = n;
203    } else {
204       WAMIRAD = Init_Whereami_Max_Rad();
205    }
206    return;
207 }
208 
209 static MCW_cluster * wamiclust=NULL ;
210 static MCW_cluster * wamiclust_CA_EZ=NULL ;
211 
212 static int TT_whereami_mode = 1;
213 static char lsep = '\n';
214 
215 /*! These atlas lists, used to be in afni.h and only included if
216 Main is defined. That was nice and dandy when only afni and whereami
217 used them. Now, every main has a use for them since input datasets
218 can be a string referring to a particular atlas zone. So they were
219 added to libmri.a and accessible without restrictions. libmri.a and other
220 binaries are fatter as a result. But you dont' get nothin for nothin.
221 ZSS Feb. 2006 with a nod of approval by RickR */
222 /* TTatlas by Jack Lancaster and Peter Fox */
223 #define TTO_COUNT_HARD 241
224 ATLAS_POINT TTO_list_HARD[TTO_COUNT_HARD] = {
225       {  0,"Anterior Commissure.....................",  0, -1, -1,0, -999, "" } ,
226       {  0,"Posterior Commissure....................",  0, 23,  0,0, -999, "" } ,
227       {  0,"Corpus Callosum.........................",  0,  7, 21,0, -999, "" } ,
228       { 68,"Left  Hippocampus.......................", 30, 24, -9,4, -999, "" } ,
229       { 68,"Right Hippocampus.......................",-30, 24, -9,4, -999, "" } ,
230       { 71,"Left  Amygdala..........................", 23,  5,-15,4, -999, "" } ,
231       { 71,"Right Amygdala..........................",-23,  5,-15,4, -999, "" } ,
232       { 20,"Left  Posterior Cingulate...............", 10, 54, 14,2, -999, "" } ,
233       { 20,"Right Posterior Cingulate...............",-10, 54, 14,2, -999, "" } ,
234       { 21,"Left  Anterior Cingulate................",  8,-32,  7,2, -999, "" } ,
235       { 21,"Right Anterior Cingulate................", -8,-32,  7,2, -999, "" } ,
236       { 22,"Left  Subcallosal Gyrus.................", 11,-11,-12,2, -999, "" } ,
237       { 22,"Right Subcallosal Gyrus.................",-11,-11,-12,2, -999, "" } ,
238       { 24,"Left  Transverse Temporal Gyrus.........", 50, 22, 12,2, -999, "" } ,
239       { 24,"Right Transverse Temporal Gyrus.........",-50, 22, 12,2, -999, "" } ,
240       { 25,"Left  Uncus.............................", 25,  2,-28,2, -999, "" } ,
241       { 25,"Right Uncus.............................",-25,  2,-28,2, -999, "" } ,
242       { 26,"Left  Rectal Gyrus......................",  7,-30,-23,2, -999, "" } ,
243       { 26,"Right Rectal Gyrus......................", -7,-30,-23,2, -999, "" } ,
244       { 27,"Left  Fusiform Gyrus....................", 40, 48,-16,2, -999, "" } ,
245       { 27,"Right Fusiform Gyrus....................",-40, 48,-16,2, -999, "" } ,
246       { 28,"Left  Inferior Occipital Gyrus..........", 35, 86, -7,2, -999, "" } ,
247       { 28,"Right Inferior Occipital Gyrus..........",-35, 86, -7,2, -999, "" } ,
248       { 29,"Left  Inferior Temporal Gyrus...........", 56, 39,-13,2, -999, "" } ,
249       { 29,"Right Inferior Temporal Gyrus...........",-56, 39,-13,2, -999, "" } ,
250       { 30,"Left  Insula............................", 39,  7,  9,2, -999, "" } ,
251       { 30,"Right Insula............................",-39,  7,  9,2, -999, "" } ,
252       { 31,"Left  Parahippocampal Gyrus.............", 25, 25,-12,2, -999, "" } ,
253       { 31,"Right Parahippocampal Gyrus.............",-25, 25,-12,2, -999, "" } ,
254       { 32,"Left  Lingual Gyrus.....................", 14, 78, -3,2, -999, "" } ,
255       { 32,"Right Lingual Gyrus.....................",-14, 78, -3,2, -999, "" } ,
256       { 33,"Left  Middle Occipital Gyrus............", 35, 83,  9,2, -999, "" } ,
257       { 33,"Right Middle Occipital Gyrus............",-35, 83,  9,2, -999, "" } ,
258       { 34,"Left  Orbital Gyrus.....................", 11,-39,-25,2, -999, "" } ,
259       { 34,"Right Orbital Gyrus.....................",-11,-39,-25,2, -999, "" } ,
260       { 35,"Left  Middle Temporal Gyrus.............", 52, 39,  0,2, -999, "" } ,
261       { 35,"Right Middle Temporal Gyrus.............",-52, 39,  0,2, -999, "" } ,
262       { 36,"Left  Superior Temporal Gyrus...........", 51, 17,  0,2, -999, "" } ,
263       { 36,"Right Superior Temporal Gyrus...........",-51, 17,  0,2, -999, "" } ,
264       { 37,"Left  Superior Occipital Gyrus..........", 37, 82, 27,2, -999, "" } ,
265       { 37,"Right Superior Occipital Gyrus..........",-37, 82, 27,2, -999, "" } ,
266       { 39,"Left  Inferior Frontal Gyrus............", 44,-24,  2,2, -999, "" } ,
267       { 39,"Right Inferior Frontal Gyrus............",-44,-24,  2,2, -999, "" } ,
268       { 40,"Left  Cuneus............................", 13, 83, 18,2, -999, "" } ,
269       { 40,"Right Cuneus............................",-13, 83, 18,2, -999, "" } ,
270       { 41,"Left  Angular Gyrus.....................", 45, 64, 33,2, -999, "" } ,
271       { 41,"Right Angular Gyrus.....................",-45, 64, 33,2, -999, "" } ,
272       { 42,"Left  Supramarginal Gyrus...............", 51, 48, 31,2, -999, "" } ,
273       { 42,"Right Supramarginal Gyrus...............",-51, 48, 31,2, -999, "" } ,
274       { 43,"Left  Cingulate Gyrus...................", 10, 11, 34,2, -999, "" } ,
275       { 43,"Right Cingulate Gyrus...................",-10, 11, 34,2, -999, "" } ,
276       { 44,"Left  Inferior Parietal Lobule..........", 48, 41, 39,2, -999, "" } ,
277       { 44,"Right Inferior Parietal Lobule..........",-48, 41, 39,2, -999, "" } ,
278       { 45,"Left  Precuneus.........................", 14, 61, 41,2, -999, "" } ,
279       { 45,"Right Precuneus.........................",-14, 61, 41,2, -999, "" } ,
280       { 46,"Left  Superior Parietal Lobule..........", 27, 59, 53,2, -999, "" } ,
281       { 46,"Right Superior Parietal Lobule..........",-27, 59, 53,2, -999, "" } ,
282       { 47,"Left  Middle Frontal Gyrus..............", 37,-29, 26,2, -999, "" } ,
283       { 47,"Right Middle Frontal Gyrus..............",-37,-29, 26,2, -999, "" } ,
284       { 48,"Left  Paracentral Lobule................",  7, 32, 53,2, -999, "" } ,
285       { 48,"Right Paracentral Lobule................", -7, 32, 53,2, -999, "" } ,
286       { 49,"Left  Postcentral Gyrus.................", 43, 25, 43,2, -999, "" } ,
287       { 49,"Right Postcentral Gyrus.................",-43, 25, 43,2, -999, "" } ,
288       { 50,"Left  Precentral Gyrus..................", 44,  8, 38,2, -999, "" } ,
289       { 50,"Right Precentral Gyrus..................",-44,  8, 38,2, -999, "" } ,
290       { 51,"Left  Superior Frontal Gyrus............", 19,-40, 27,2, -999, "" } ,
291       { 51,"Right Superior Frontal Gyrus............",-19,-40, 27,2, -999, "" } ,
292       { 52,"Left  Medial Frontal Gyrus..............",  9,-24, 35,2, -999, "" } ,
293       { 52,"Right Medial Frontal Gyrus..............", -9,-24, 35,2, -999, "" } ,
294       { 70,"Left  Lentiform Nucleus.................", 22,  1,  2,2, -999, "" } ,
295       { 70,"Right Lentiform Nucleus.................",-22,  1,  2,2, -999, "" } ,
296       { 72,"Left  Hypothalamus......................",  4,  3, -9,4, -999, "" } ,
297       { 72,"Right Hypothalamus......................", -4,  3, -9,4, -999, "" } ,
298       { 73,"Left  Red Nucleus.......................",  5, 19, -4,4, -999, "" } ,
299       { 73,"Right Red Nucleus.......................", -5, 19, -4,4, -999, "" } ,
300       { 74,"Left  Substantia Nigra..................", 11, 18, -7,4, -999, "" } ,
301       { 74,"Right Substantia Nigra..................",-11, 18, -7,4, -999, "" } ,
302       { 75,"Left  Claustrum.........................", 32,  1,  5,2, -999, "" } ,
303       { 75,"Right Claustrum.........................",-32,  1,  5,2, -999, "" } ,
304       { 76,"Left  Thalamus..........................", 12, 19,  8,2, -999, "" } ,
305       { 76,"Right Thalamus..........................",-12, 19,  8,2, -999, "" } ,
306       { 77,"Left  Caudate...........................", 11, -7,  9,2, -999, "" } ,
307       { 77,"Right Caudate...........................",-11, -7,  9,2, -999, "" } ,
308       {124,"Left  Caudate Tail......................", 27, 35,  9,4, -999, "" } ,
309       {124,"Right Caudate Tail......................",-27, 35,  9,4, -999, "" } ,
310       {125,"Left  Caudate Body......................", 12, -6, 14,4, -999, "" } ,
311       {125,"Right Caudate Body......................",-12, -6, 14,4, -999, "" } ,
312       {126,"Left  Caudate Head......................",  9,-13,  0,4, -999, "" } ,
313       {126,"Right Caudate Head......................", -9,-13,  0,4, -999, "" } ,
314       {128,"Left  Ventral Anterior Nucleus..........", 11,  6,  9,4, -999, "" } ,
315       {128,"Right Ventral Anterior Nucleus..........",-11,  6,  9,4, -999, "" } ,
316       {129,"Left  Ventral Posterior Medial Nucleus..", 15, 20,  4,4, -999, "" } ,
317       {129,"Right Ventral Posterior Medial Nucleus..",-15, 20,  4,4, -999, "" } ,
318       {130,"Left  Ventral Posterior Lateral Nucleus.", 18, 19,  5,4, -999, "" } ,
319       {130,"Right Ventral Posterior Lateral Nucleus.",-18, 19,  5,4, -999, "" } ,
320       {131,"Left  Medial Dorsal Nucleus.............",  6, 16,  8,4, -999, "" } ,
321       {131,"Right Medial Dorsal Nucleus.............", -6, 16,  8,4, -999, "" } ,
322       {132,"Left  Lateral Dorsal Nucleus............", 12, 20, 16,4, -999, "" } ,
323       {132,"Right Lateral Dorsal Nucleus............",-12, 20, 16,4, -999, "" } ,
324       {133,"Left  Pulvinar..........................", 16, 27,  8,4, -999, "" } ,
325       {133,"Right Pulvinar..........................",-16, 27,  8,4, -999, "" } ,
326       {134,"Left  Lateral Posterior Nucleus.........", 17, 20, 14,4, -999, "" } ,
327       {134,"Right Lateral Posterior Nucleus.........",-17, 20, 14,4, -999, "" } ,
328       {135,"Left  Ventral Lateral Nucleus...........", 14, 12,  9,4, -999, "" } ,
329       {135,"Right Ventral Lateral Nucleus...........",-14, 12,  9,4, -999, "" } ,
330       {136,"Left  Midline Nucleus...................",  7, 18, 16,4, -999, "" } ,
331       {136,"Right Midline Nucleus...................", -7, 18, 16,4, -999, "" } ,
332       {137,"Left  Anterior Nucleus..................",  8,  8, 12,4, -999, "" } ,   /* 04 Mar 2002 */
333       {137,"Right Anterior Nucleus..................", -8,  8, 12,4, -999, "" } ,
334       {138,"Left  Mammillary Body...................", 11, 20,  2,4, -999, "" } ,
335       {138,"Right Mammillary Body...................",-11, 20,  2,4, -999, "" } ,
336       {144,"Left  Medial Globus Pallidus............", 15,  4, -2,4, -999, "" } ,
337       {144,"Right Medial Globus Pallidus............",-15,  4, -2,4, -999, "" } ,
338       {145,"Left  Lateral Globus Pallidus...........", 20,  5,  0,4, -999, "" } ,
339       {145,"Right Lateral Globus Pallidus...........",-20,  5,  0,4, -999, "" } ,
340       {151,"Left  Putamen...........................", 24,  0,  3,4, -999, "" } ,
341       {151,"Right Putamen...........................",-24,  0,  3,4, -999, "" } ,
342       {146,"Left  Nucleus Accumbens.................", 12, -8, -8,4, -999, "" } , /* 20 Aug */
343       {146,"Right Nucleus Accumbens.................",-12, -8, -8,4, -999, "" } , /* 2001 */
344       {147,"Left  Medial Geniculum Body.............", 17, 24, -2,4, -999, "" } ,
345       {147,"Right Medial Geniculum Body.............",-17, 24, -2,4, -999, "" } ,
346       {148,"Left  Lateral Geniculum Body............", 22, 24, -1,4, -999, "" } ,
347       {148,"Right Lateral Geniculum Body............",-22, 24, -1,4, -999, "" } ,
348       {149,"Left  Subthalamic Nucleus...............", 10, 13, -3,4, -999, "" } ,
349       {149,"Right Subthalamic Nucleus...............",-10, 13, -3,4, -999, "" } ,
350       { 81,"Left  Brodmann area 1...................", 53, 19, 50,4, -999, "" } ,
351       { 81,"Right Brodmann area 1...................",-53, 19, 50,4, -999, "" } ,
352       { 82,"Left  Brodmann area 2...................", 49, 26, 43,4, -999, "" } ,
353       { 82,"Right Brodmann area 2...................",-49, 26, 43,4, -999, "" } ,
354       { 83,"Left  Brodmann area 3...................", 39, 23, 50,4, -999, "" } ,
355       { 83,"Right Brodmann area 3...................",-39, 23, 50,4, -999, "" } ,
356       { 84,"Left  Brodmann area 4...................", 39, 18, 49,4, -999, "" } ,
357       { 84,"Right Brodmann area 4...................",-39, 18, 49,4, -999, "" } ,
358       { 85,"Left  Brodmann area 5...................", 16, 40, 57,4, -999, "" } ,
359       { 85,"Right Brodmann area 5...................",-16, 40, 57,4, -999, "" } ,
360       { 86,"Left  Brodmann area 6...................", 29,  0, 50,4, -999, "" } ,
361       { 86,"Right Brodmann area 6...................",-29,  0, 50,4, -999, "" } ,
362       { 87,"Left  Brodmann area 7...................", 16, 60, 48,4, -999, "" } ,
363       { 87,"Right Brodmann area 7...................",-16, 60, 48,4, -999, "" } ,
364       { 88,"Left  Brodmann area 8...................", 24,-30, 44,4, -999, "" } ,
365       { 88,"Right Brodmann area 8...................",-24,-30, 44,4, -999, "" } ,
366       { 89,"Left  Brodmann area 9...................", 32,-33, 30,4, -999, "" } ,
367       { 89,"Right Brodmann area 9...................",-32,-33, 30,4, -999, "" } ,
368       { 90,"Left  Brodmann area 10..................", 24,-56,  6,4, -999, "" } ,
369       { 90,"Right Brodmann area 10..................",-24,-56,  6,4, -999, "" } ,
370       { 91,"Left  Brodmann area 11..................", 17,-43,-18,4, -999, "" } ,
371       { 91,"Right Brodmann area 11..................",-17,-43,-18,4, -999, "" } ,
372       { 93,"Left  Brodmann area 13..................", 39,  4,  8,4, -999, "" } ,
373       { 93,"Right Brodmann area 13..................",-39,  4,  8,4, -999, "" } ,
374       { 94,"Left  Brodmann area 17..................", 10, 88,  5,4, -999, "" } ,
375       { 94,"Right Brodmann area 17..................",-10, 88,  5,4, -999, "" } ,
376       { 95,"Left  Brodmann area 18..................", 19, 85,  4,4, -999, "" } ,
377       { 95,"Right Brodmann area 18..................",-19, 85,  4,4, -999, "" } ,
378       { 96,"Left  Brodmann area 19..................", 34, 80, 18,4, -999, "" } ,
379       { 96,"Right Brodmann area 19..................",-34, 80, 18,4, -999, "" } ,
380       { 97,"Left  Brodmann area 20..................", 47, 21,-23,4, -999, "" } ,
381       { 97,"Right Brodmann area 20..................",-47, 21,-23,4, -999, "" } ,
382       { 98,"Left  Brodmann area 21..................", 58, 18,-10,4, -999, "" } ,
383       { 98,"Right Brodmann area 21..................",-58, 18,-10,4, -999, "" } ,
384       { 99,"Left  Brodmann area 22..................", 57, 23,  5,4, -999, "" } ,
385       { 99,"Right Brodmann area 22..................",-57, 23,  5,4, -999, "" } ,
386       {100,"Left  Brodmann area 23..................",  4, 37, 24,4, -999, "" } ,
387       {100,"Right Brodmann area 23..................", -4, 37, 24,4, -999, "" } ,
388       {101,"Left  Brodmann area 24..................",  6, -6, 30,4, -999, "" } ,
389       {101,"Right Brodmann area 24..................", -6, -6, 30,4, -999, "" } ,
390       {102,"Left  Brodmann area 25..................",  6,-15,-13,4, -999, "" } ,
391       {102,"Right Brodmann area 25..................", -6,-15,-13,4, -999, "" } ,
392       {103,"Left  Brodmann area 27..................", 15, 35,  0,4, -999, "" } ,
393       {103,"Right Brodmann area 27..................",-15, 35,  0,4, -999, "" } ,
394       {104,"Left  Brodmann area 28..................", 22, -2,-24,4, -999, "" } ,
395       {104,"Right Brodmann area 28..................",-22, -2,-24,4, -999, "" } ,
396       {105,"Left  Brodmann area 29..................",  6, 48, 11,4, -999, "" } ,
397       {105,"Right Brodmann area 29..................", -6, 48, 11,4, -999, "" } ,
398       {106,"Left  Brodmann area 30..................", 13, 62, 10,4, -999, "" } ,
399       {106,"Right Brodmann area 30..................",-13, 62, 10,4, -999, "" } ,
400       {107,"Left  Brodmann area 31..................",  9, 47, 32,4, -999, "" } ,
401       {107,"Right Brodmann area 31..................", -9, 47, 32,4, -999, "" } ,
402       {108,"Left  Brodmann area 32..................",  8,-24, 30,4, -999, "" } ,
403       {108,"Right Brodmann area 32..................", -8,-24, 30,4, -999, "" } ,
404       {109,"Left  Brodmann area 33..................",  5,-12, 24,4, -999, "" } ,
405       {109,"Right Brodmann area 33..................", -5,-12, 24,4, -999, "" } ,
406       {110,"Left  Brodmann area 34..................", 18,  0,-16,4, -999, "" } ,
407       {110,"Right Brodmann area 34..................",-18,  0,-16,4, -999, "" } ,
408       {111,"Left  Brodmann area 35..................", 23, 25,-15,4, -999, "" } ,
409       {111,"Right Brodmann area 35..................",-23, 25,-15,4, -999, "" } ,
410       {112,"Left  Brodmann area 36..................", 33, 33,-15,4, -999, "" } ,
411       {112,"Right Brodmann area 36..................",-33, 33,-15,4, -999, "" } ,
412       {113,"Left  Brodmann area 37..................", 48, 55, -7,4, -999, "" } ,
413       {113,"Right Brodmann area 37..................",-48, 55, -7,4, -999, "" } ,
414       {114,"Left  Brodmann area 38..................", 41,-12,-23,4, -999, "" } ,
415       {114,"Right Brodmann area 38..................",-41,-12,-23,4, -999, "" } ,
416       {115,"Left  Brodmann area 39..................", 48, 64, 28,4, -999, "" } ,
417       {115,"Right Brodmann area 39..................",-48, 64, 28,4, -999, "" } ,
418       {116,"Left  Brodmann area 40..................", 51, 40, 38,4, -999, "" } ,
419       {116,"Right Brodmann area 40..................",-51, 40, 38,4, -999, "" } ,
420       {117,"Left  Brodmann area 41..................", 47, 26, 11,4, -999, "" } ,
421       {117,"Right Brodmann area 41..................",-47, 26, 11,4, -999, "" } ,
422       {118,"Left  Brodmann area 42..................", 63, 22, 12,4, -999, "" } ,
423       {118,"Right Brodmann area 42..................",-63, 22, 12,4, -999, "" } ,
424       {119,"Left  Brodmann area 43..................", 58, 10, 16,4, -999, "" } ,
425       {119,"Right Brodmann area 43..................",-58, 10, 16,4, -999, "" } ,
426       {120,"Left  Brodmann area 44..................", 53,-11, 12,4, -999, "" } ,
427       {120,"Right Brodmann area 44..................",-53,-11, 12,4, -999, "" } ,
428       {121,"Left  Brodmann area 45..................", 54,-23, 10,4, -999, "" } ,
429       {121,"Right Brodmann area 45..................",-54,-23, 10,4, -999, "" } ,
430       {122,"Left  Brodmann area 46..................", 50,-38, 16,4, -999, "" } ,
431       {122,"Right Brodmann area 46..................",-50,-38, 16,4, -999, "" } ,
432       {123,"Left  Brodmann area 47..................", 38,-24,-11,4, -999, "" } ,
433       {123,"Right Brodmann area 47..................",-38,-24,-11,4, -999, "" } ,
434       { 53,"Left  Uvula of Vermis...................",  2, 65,-32,2, -999, "" } ,
435       { 53,"Right Uvula of Vermis...................", -2, 65,-32,2, -999, "" } ,
436       { 54,"Left  Pyramis of Vermis.................",  2, 73,-28,2, -999, "" } ,
437       { 54,"Right Pyramis of Vermis.................", -2, 73,-28,2, -999, "" } ,
438       { 55,"Left  Tuber of Vermis...................",  2, 71,-24,2, -999, "" } ,
439       { 55,"Right Tuber of Vermis...................", -2, 71,-24,2, -999, "" } ,
440       { 56,"Left  Declive of Vermis.................",  2, 72,-17,2, -999, "" } ,
441       { 56,"Right Declive of Vermis.................", -2, 72,-17,2, -999, "" } ,
442       { 57,"Left  Culmen of Vermis..................",  3, 63, -3,2, -999, "" } ,
443       { 57,"Right Culmen of Vermis..................", -3, 63, -3,2, -999, "" } ,
444       { 58,"Left  Cerebellar Tonsil.................", 28, 51,-36,2, -999, "" } ,
445       { 58,"Right Cerebellar Tonsil.................",-28, 51,-36,2, -999, "" } ,
446       { 59,"Left  Inferior Semi-Lunar Lobule........", 29, 71,-38,2, -999, "" } ,
447       { 59,"Right Inferior Semi-Lunar Lobule........",-29, 71,-38,2, -999, "" } ,
448       { 60,"Left  Fastigium.........................",  7, 54,-20,2, -999, "" } ,
449       { 60,"Right Fastigium.........................", -7, 54,-20,2, -999, "" } ,
450       { 61,"Left  Nodule............................",  7, 55,-27,2, -999, "" } ,
451       { 61,"Right Nodule............................", -7, 55,-27,2, -999, "" } ,
452       { 62,"Left  Uvula.............................", 21, 76,-26,2, -999, "" } ,
453       { 62,"Right Uvula.............................",-21, 76,-26,2, -999, "" } ,
454       { 63,"Left  Pyramis...........................", 27, 74,-30,2, -999, "" } ,
455       { 63,"Right Pyramis...........................",-27, 74,-30,2, -999, "" } ,
456       { 66,"Left  Culmen............................", 20, 46,-16,2, -999, "" } ,
457       { 66,"Right Culmen............................",-20, 46,-16,2, -999, "" } ,
458       { 65,"Left  Declive...........................", 26, 69,-17,2, -999, "" } ,
459       { 65,"Right Declive...........................",-26, 69,-17,2, -999, "" } ,
460       {127,"Left  Dentate...........................", 14, 54,-23,4, -999, "" } ,
461       {127,"Right Dentate...........................",-14, 54,-23,4, -999, "" } ,
462       { 64,"Left  Tuber.............................", 44, 71,-27,2, -999, "" } ,
463       { 64,"Right Tuber.............................",-44, 71,-27,2, -999, "" } ,
464       { 67,"Left  Cerebellar Lingual................",  4, 45,-13,2, -999, "" } ,
465       { 67,"Right Cerebellar Lingual................", -4, 45,-13,2, -999, "" }
466 } ;
467 
468 int atlas_current_structure = 0 ;  /* last chosen atlas structure index */
469 
470 /*! CA_EZ atlas material is now automatically prepared
471 from a downloaded SPM toolbox. See the matlab function
472 CA_EZ_Prep.m */
473 
474 #include "thd_ttatlas_CA_EZ.c"
475 
476 
477 /*-----------------------------------------------------------------------*/
478 /*
479    szflag controls the number of slices in the atlas for TT_Daemon only:
480        1 --> return Big TT atlas
481       -1 --> return Small TT atlas
482        0 --> Do nothing
483 */
TT_retrieve_atlas_dset(char * aname,int szflag)484 THD_3dim_dataset * TT_retrieve_atlas_dset(char *aname, int szflag) {
485    ATLAS *atlas=NULL;
486    char sbuf[256];
487    THD_3dim_dataset *dset=NULL;
488 
489    if (!(atlas = Atlas_With_Trimming (aname, 1, NULL)) || !ATL_DSET(atlas)) {
490       if (wami_verb())
491          ERROR_message("Failed getting atlas for retrieval");
492       return(NULL);
493    }
494    if (szflag) {
495       /* The big or small option to TT_Daemon. Should not let this be done to
496       other dsets. This is only legit for TT_Daemon and AFNI's interactive
497          usage. A better approach is to use the resampler to match any grid... */
498       if (strcmp(Atlas_Name(atlas),"TT_Daemon")) {
499          if (wami_verb()) {
500             INFO_message(
501          "Nothing to do with szflag for atlases other than TT_Daemon\n"
502          "Returning atlas %s's dset unchanged", Atlas_Name(atlas));
503          }
504          return(ATL_DSET(atlas));
505       }
506       if (szflag == 1 && is_small_TT(atlas)) {
507          /* want big, have small */
508          sprintf(sbuf,"%s_big", DSET_PREFIX(ATL_DSET(atlas)) );
509          if (!(dset = THD_zeropad(ATL_DSET(atlas), 10,0,0,0,0,0 , sbuf , 0 ))) {
510             ERROR_message("Failed to fatten atlas\n");
511             return(NULL);
512          }
513          DSET_delete(ATL_DSET(atlas));
514          atlas->adh->adset = dset; dset = NULL;
515       } else if (szflag == -1 && is_big_TT(atlas)) {
516          char *scut, *spref;
517          /* want small, have big */
518          spref = DSET_PREFIX(ATL_DSET(atlas));
519          scut = strstr(spref, "_big");
520          if (scut) {
521             snprintf(sbuf,strlen(spref)-4,"%s", spref );
522          } else {
523             snprintf(sbuf,255,"%s", spref );
524          }
525          if (!(dset = THD_zeropad(ATL_DSET(atlas), 10,0,0,0,0,0 , sbuf , 0 ))) {
526             ERROR_message("Failed to thin atlas\n");
527             return(NULL);
528          }
529          DSET_delete(ATL_DSET(atlas));
530          atlas->adh->adset = dset; dset = NULL;
531       }
532    }
533    return(ATL_DSET(atlas));
534 }
535 
is_big_TT(ATLAS * atlas)536 int is_big_TT(ATLAS *atlas) {
537    if (ATL_DSET(atlas) &&
538        DSET_NZ(ATL_DSET(atlas)) == TT_ATLAS_NZ_BIG &&
539        !strcmp(Atlas_Name(atlas),"TT_Daemon")) {
540          return(1);
541    }
542    return(0);
543 }
544 
is_small_TT(ATLAS * atlas)545 int is_small_TT(ATLAS *atlas) {
546    if (ATL_DSET(atlas) &&
547        DSET_NZ(ATL_DSET(atlas)) == TT_ATLAS_NZ_SMALL &&
548        !strcmp(Atlas_Name(atlas),"TT_Daemon")) {
549          return(1);
550    }
551    return(0);
552 }
553 
554 
555 
556 #ifdef KILLTHIS /* Remove all old sections framed by #ifdef KILLTHIS
557                   in the near future.  ZSS May 2011   */
TT_retrieve_atlas_old(void)558 THD_3dim_dataset * TT_retrieve_atlas_old(void)
559 {
560    if (wami_verb()) {
561       WARNING_message("Obsolete, use Atlas_With_Trimming instead");
562    }
563    if( have_dseTT_old < 0 ) TT_load_atlas_old() ;
564    return dseTT_old ;                         /* might be NULL */
565 }
566 
567 /*-----------------------------------------------------------------------*/
568 
TT_retrieve_atlas_big_old(void)569 THD_3dim_dataset * TT_retrieve_atlas_big_old(void) /* 01 Aug 2001 */
570 {
571    char sbuf[256];
572 
573    if (wami_verb()) {
574       WARNING_message("Obsolete, use Atlas_With_Trimming instead");
575    }
576    if( dseTT_big_old != NULL ) return dseTT_big_old ;
577    if( have_dseTT_old < 0    ) TT_load_atlas_old() ;
578    if( dseTT_old == NULL     ) return NULL ;
579    sprintf(sbuf,"%s_big", TT_DAEMON_TT_PREFIX);
580    dseTT_big_old = THD_zeropad( dseTT_old , 10,0,0,0,0,0 , sbuf , 0 ) ;
581    DSET_unload( dseTT_old ) ; /* probably won't need again */
582    return dseTT_big_old ;
583 }
584 
585 /*-----------------------------------------------------------------------*/
586 
TT_retrieve_atlas_either_old(void)587 THD_3dim_dataset * TT_retrieve_atlas_either_old(void) /* 22 Aug 2001 */
588 {
589    if (wami_verb()) {
590       WARNING_message("Obsolete, use Atlas_With_Trimming instead");
591    }
592    if( dseTT_big_old != NULL ) return dseTT_big_old ;
593    if( dseTT_old     != NULL ) return dseTT_old     ;
594    if( have_dseTT_old < 0    ) TT_load_atlas_old()  ;
595    return dseTT_old ;
596 }
597 
598 #endif
599 
600 /*-----------------------------------------------------------------------*/
601 /*! Get name of directory contained TTatlas -- if it exists.  Name
602     returned will be NULL (that's bad) or will end in a '/' character.
603 *//*---------------------------------------------------------------------*/
604 
get_atlas_dirname(void)605 char * get_atlas_dirname(void)  /* 31 Jan 2008 -- RWCox */
606 {
607    static char *adnam=NULL ; static int first=1 ;
608    char *epath , *elocal , ename[THD_MAX_NAME] , dname[THD_MAX_NAME] ;
609    int ll , ii , id , epos ;
610 
611    if( !first ) return adnam ;
612    first = 0 ;
613    epath = get_env_atlas_path();
614    if( epath == NULL ) return NULL ;  /* this is bad */
615 
616    ll = strlen(epath) ;
617    elocal = AFMALL(char, sizeof(char) * (ll+2) ) ;
618    strcpy(elocal,epath); elocal[ll] = ' '; elocal[ll+1] = '\0';
619    for( ii=0 ; ii < ll ; ii++ ) if( elocal[ii] == ':' ) elocal[ii] = ' ';
620 
621    epos = 0 ;
622    do{
623      ii = sscanf( elocal+epos, "%s%n", ename, &id ); if( ii < 1 ) break;
624      epos += id ;
625      ii = strlen(ename) ;
626      if( ename[ii-1] != '/' ){ ename[ii] = '/'; ename[ii+1] = '\0'; }
627 /* may want to not rely on this specific atlas for locations of all atlases */
628      strcpy(dname,ename); strcat(dname,"TTatlas+tlrc.HEAD");
629      if( THD_is_file(dname) ){
630        free((void *)elocal); adnam = strdup(ename); return adnam;
631      }
632      strcpy(dname,ename); strcat(dname,"TTatlas.nii.gz");
633      if( THD_is_file(dname) ){
634        free((void *)elocal); adnam = strdup(ename); return adnam;
635      }
636    } while( epos < ll ) ;
637 
638    return NULL ;
639 }
640 
641 /* get preferred path for atlases, potentially containing multiple directories*/
get_env_atlas_path()642 char * get_env_atlas_path()
643 {
644    char *epath;
645                        epath = getenv("AFNI_ATLAS_PATH") ;
646    if( epath == NULL ) epath = getenv("AFNI_PLUGINPATH") ;
647    if( epath == NULL ) epath = getenv("AFNI_PLUGIN_PATH") ;
648    if( epath == NULL ) epath = getenv("PATH") ;
649    return(epath);
650 }
651 
652 /*-----------------------------------------------------------------------*/
653 
get_atlas(char * epath,char * aname)654 THD_3dim_dataset * get_atlas(char *epath, char *aname)
655 {
656    char dname[THD_MAX_NAME], ename[THD_MAX_NAME], *elocal=NULL;
657    THD_3dim_dataset *dset = NULL;
658    int epos=0, ll=0, ii=0, id = 0;
659    int LocalHead = wami_lh();
660 
661    ENTRY("get_atlas");
662 /* change to allow full path in dataset name, or current directory,
663    and not necessarily separate path*/
664    if( epath != NULL ){ /* A path was specified, maybe with a name in it*/
665       if (aname == NULL) { /* all in epath */
666          dset = THD_open_one_dataset( epath ) ;  /* try to open it */
667          if(dset!=NULL) {
668             DSET_mallocize (dset);
669             DSET_load (dset);	                /* load dataset */
670          }
671       } else  {
672          strncpy(dname,epath, (THD_MAX_NAME-2)*sizeof(char)) ;
673          ii = strlen(dname);
674          if (dname[ii-1] != '/') {
675             dname[ii] = '/'; dname[ii+1] = '\0';
676          }
677          strncat(dname,aname, THD_MAX_NAME - strlen(dname)) ;
678                                                 /* add dataset name */
679          dset = THD_open_one_dataset( dname ) ;
680          if(dset!=NULL) {
681             DSET_mallocize (dset);
682             DSET_load (dset);	                /* load dataset */
683          }
684       }
685       if( !dset ){                     /* don't got it!!! */
686          if (wami_verb())
687             ERROR_message("Failed to read dset from %s (aname=%s)\n",
688                           epath, aname?aname:"NULL");
689       }
690       RETURN(dset);   /* return NULL or dset for specified path input */
691    } else { /* no path given */
692       if (aname == NULL) { /* nothing to work with here !*/
693          ERROR_message("No path, no name, no soup for you.\n");
694          RETURN(dset);
695       }
696       /* a name was given, try to open it directly */
697       dset = THD_open_one_dataset( aname ) ;
698       if(dset!=NULL) {
699          DSET_mallocize (dset);
700          DSET_load (dset);	              /* load dataset */
701          RETURN(dset);             /* return the dataset*/
702       }
703 
704       /*----- get path to search -----*/
705       epath = get_env_atlas_path();
706       if( epath == NULL ) RETURN(dset) ;
707 
708       /*----- copy path list into local memory -----*/
709 
710       ll = strlen(epath) ;
711       elocal = AFMALL(char, sizeof(char) * (ll+2) ) ;
712 
713       /*----- put a blank at the end -----*/
714 
715       strcpy( elocal , epath ) ; elocal[ll] = ' ' ; elocal[ll+1] = '\0' ;
716 
717       /*----- replace colons with blanks -----*/
718 
719       for( ii=0 ; ii < ll ; ii++ )
720         if( elocal[ii] == ':' ) elocal[ii] = ' ' ;
721 
722       /*----- extract blank delimited strings;
723               use as directory names to look for atlas -----*/
724 
725       epos = 0 ;
726 
727       do{
728          ii = sscanf( elocal+epos , "%s%n" , ename , &id ); /* next substring */
729          if( ii < 1 ) break ;                               /* none -> done   */
730 
731          epos += id ;                                 /* char after last scanned */
732 
733          ii = strlen(ename) ;                         /* make sure name has   */
734          if( ename[ii-1] != '/' ){                    /* a trailing '/' on it */
735              ename[ii]  = '/' ; ename[ii+1] = '\0' ;
736          }
737          strcpy(dname,ename) ;
738          strcat(dname,aname) ;               /* add dataset name */
739          if(LocalHead)
740              INFO_message("trying to open dataset:%s", dname);
741          dset = THD_open_one_dataset( dname ) ;      /* try to open it */
742 
743          if( dset != NULL ){                         /* got it!!! */
744             DSET_mallocize (dset);
745             DSET_load (dset);	                /* load dataset */
746             free(elocal); RETURN(dset);
747          }
748 
749       } while(( epos < ll ) || (dset!=NULL)) ;  /* scan until 'epos' is after end of epath */
750 
751 
752    } /* No path given */
753 
754    /* should only get here if no dataset found */
755    RETURN(dset);
756 }
757 
758 #ifdef KILLTHIS /* Remove all old sections framed by #ifdef KILLTHIS
759                   in the near future.  ZSS May 2011   */
760 
761 /*-----------------------------------------------------------------------*/
TT_load_atlas_old(void)762 int TT_load_atlas_old(void)
763 {
764    char *epath, sbuf[256] ;
765 
766 ENTRY("TT_load_atlas_old") ;
767 
768    WARNING_message(
769       "Obsolete, use Atlas_With_Trimming(\"TT_Daemon\", .) instead");
770 
771    if( have_dseTT_old >= 0 ) RETURN(have_dseTT_old) ;  /* for later calls */
772 
773    have_dseTT_old = 0 ;  /* don't have it yet */
774 
775    /*----- 20 Aug 2001: see if user specified alternate database -----*/
776 
777    epath = getenv("AFNI_TTATLAS_DATASET") ;   /* suggested path, if any */
778    sprintf(sbuf,"%s+tlrc", TT_DAEMON_TT_PREFIX);
779    dseTT_old = get_atlas( epath, sbuf ) ;  /* try to open it */
780    if (!dseTT_old) { /* try for NIFTI */
781       sprintf(sbuf,"%s.nii.gz", TT_DAEMON_TT_PREFIX);
782       dseTT_old = get_atlas( epath, sbuf) ;
783    }
784    if( dseTT_old != NULL ){                     /* got it!!! */
785       have_dseTT_old = 1; RETURN(1);
786    }
787 
788 
789    RETURN(0) ; /* got here -> didn't find it */
790 }
791 
792 /*----------------------------------------------------------------------
793   Allows the program to purge the memory used by the TT atlas dataset
794 ------------------------------------------------------------------------*/
795 
TT_purge_atlas_old(void)796 void TT_purge_atlas_old(void)
797 {
798   PURGE_DSET(dseTT_old) ; return ;
799 }
800 
TT_purge_atlas_big_old(void)801 void TT_purge_atlas_big_old(void)
802 {
803    if( dseTT_big_old != NULL ){
804       DSET_delete(dseTT_big_old) ; dseTT_big_old = NULL ;
805    }
806    return ;
807 }
808 
809 #endif
810 
811 /* drg - we need more robust way to find left/right than hard-coded CA_N27_LR */
812 /* We should consider these choices:
813     1. Add field to atlas to xref another atlas: lr_atlas_name
814     2. Add field to atlas to determine coordinate split of left/right:
815         lr_x_right
816     3. Always load some atlases like the LR, and refer to global atlas list
817         for those
818     4. In addition to left/right, determine I/S,A/P, Rostral/Caudal,...
819     5. Abandon left/right determination from external source and require
820        encoding in the atlas or by coordinate.
821 
822    At the moment, I'm opting for 5. One problem that we have now is the use
823    of a specific atlas on the whereami command line. The LR atlas is not
824    in the atlas list in that case. Note the MNI_Anatomical_Side is now
825    only used for MNI_ANAT coordinates.
826 
827    Potential solution is to add at the space definition whether left/right, I/S
828    ... are implicit (i.e. coordinate based) or explicitly defined in an atlas
829    named something.
830 */
831 
832 /*! are we on the left or right of Colin? */
MNI_Anatomical_Side(ATLAS_COORD ac,ATLAS_LIST * atlas_list)833 char MNI_Anatomical_Side(ATLAS_COORD ac, ATLAS_LIST *atlas_list)
834 {
835    THD_ivec3 ijk ;
836    THD_fvec3 mmxyz ;
837    int  ix,jy,kz , nx,ny,nxy, ii=0, kk=0;
838    byte *ba=NULL;
839    static int n_warn = 0, lr_notfound = 0;
840    ATLAS *atlas=NULL;
841 
842    ENTRY("MNI_Anatomical_Side");
843 
844    if(lr_notfound)
845       RETURN('u');   /* tried to find LR atlas before but failed */
846 
847    /* ONLY TLRC for now, must allow for others in future */
848    if (!is_Coord_Space_Named(ac, "TLRC")) {
849       ERROR_message("Coordinates must be in 'TLRC' space");
850       RETURN('u');
851    }
852 
853    if (!(atlas = Atlas_With_Trimming("CA_N27_LR", 1, atlas_list))) {
854       if (ii == 0 && !n_warn) {
855          INFO_message("Could not read LR atlas named %s\n"
856 			 "Relying on x coordinate to guess side", "CA_N27_LR");
857          ++n_warn;
858          lr_notfound = 1;
859       }
860    }
861 
862    if (!atlas) {
863       if (ac.x<0.0) {
864          RETURN('r');
865       } else {
866          RETURN('l');
867       }
868    } else {
869       /* where are we in the ijk grid ? */
870       mmxyz = THD_dicomm_to_3dmm( ATL_DSET(atlas) ,
871                          TEMP_FVEC3(ac.x,ac.y,ac.z));
872       ijk = THD_3dmm_to_3dind( ATL_DSET(atlas) , mmxyz ) ;
873       UNLOAD_IVEC3(ijk,ix,jy,kz) ;
874 
875       nx = DSET_NX(ATL_DSET(atlas)) ;  /* size of atlas dataset axes */
876       ny = DSET_NY(ATL_DSET(atlas)) ;
877       nxy = nx*ny ;
878       /*nz = DSET_NZ(ATL_DSET(atlas)) ;*/
879 
880       /*-- check the exact input location --*/
881       ba = DSET_BRICK_ARRAY(ATL_DSET(atlas),0);
882       kk = ix + jy*nx + kz*nxy ;        /* index into brick arrays */
883       if( ba[kk] == 2 ){
884          RETURN('l');
885       }else if( ba[kk] == 1 ){
886          RETURN('r');
887       }else {
888          /* not in mask, use coord */
889          if (ac.x<0.0) {
890             RETURN('r');
891          } else {
892             RETURN('l');
893          }
894       }
895    }
896 
897    /* should not get here */
898    RETURN('u');
899 }
900 
901 /*! What side are we on ?*/
Atlas_Voxel_Side(THD_3dim_dataset * dset,int k1d,byte * lrmask)902 char Atlas_Voxel_Side( THD_3dim_dataset *dset, int k1d, byte *lrmask)
903 {
904    THD_ivec3 ijk ;
905    THD_fvec3 xyz ;
906    int  ix,jy,kz , nx,ny,nxy;
907 
908    ENTRY("Atlas_Voxel_Side");
909 
910 
911    if ( lrmask ) { /* easy */
912       if (lrmask[k1d] == 2 ){
913          RETURN('l');
914       }else if( lrmask[k1d] == 1 ){
915          RETURN('r');
916       } else {
917          RETURN('u');
918       }
919    }
920 
921    if (!dset) {
922       ERROR_message("Need an atlas dset");
923       RETURN('u');
924    }
925 
926    /* based on coords */
927    nx = DSET_NX(dset) ;               /* size of atlas dataset axes */
928    ny = DSET_NY(dset) ;
929    nxy = nx*ny ;
930 /*   nz = DSET_NZ(dset) ;*/
931 
932    kz = (k1d / nxy);
933    jy = (k1d % nxy);
934    ix = (jy  % nx);
935    jy = (jy  / nx);
936 
937    LOAD_IVEC3(ijk, ix, jy, kz);
938    xyz = THD_3dind_to_3dmm(dset, ijk);
939 
940    if (xyz.xyz[0]<0.0) {
941       RETURN('r');
942    } else {
943       RETURN('l');
944    }
945 
946 
947    /* should not get here */
948    RETURN('u');
949 }
950 /*----------------------------------------------------------------------
951    Return a multi-line string of atlas labels near the given point
952    (xx,yy,zz are in Dicom order coordinates).
953    If NULL is returned, an error happened.  If no labels are near the
954    given point, then a null string is returned.
955    The string returned is malloc()-ed and should be free()-ed later.
956    The string will end with a newline '\n' character.
957 ------------------------------------------------------------------------*/
958 
959 #if 0
960 #undef  SS
961 #define SS(c) fprintf(stderr,"sp %c\n",(c))
962 #else
963 #define SS(c) /*nada*/
964 #endif
965 
genx_Atlas_Query_to_String(ATLAS_QUERY * wami,ATLAS_COORD ac,WAMI_SORT_MODES mode,ATLAS_LIST * atlas_list)966 char * genx_Atlas_Query_to_String (ATLAS_QUERY *wami,
967                               ATLAS_COORD ac, WAMI_SORT_MODES mode,
968                               ATLAS_LIST *atlas_list)
969 {
970    char *rbuf = NULL;
971    int max_spaces = 50;
972    char  xlab[max_spaces][32], ylab[max_spaces][32] , zlab[max_spaces][32],
973          clab[max_spaces][256], lbuf[1024], connbuf[1024]  , tmps[1024], pf[10],
974          x_fstr[10], y_fstr[10], z_fstr[10],
975          neurosynth_link_str[256], sumsdb_link_str[320] ;
976    THD_string_array *sar =NULL;
977    ATLAS_COORD *acl=NULL;
978    int iatlas = -1, N_out_spaces=0, it=0;
979    int i, ii, nfind=0, nfind_one = 0, iq=0, il=0, newzone = 0;
980    ATLAS *atlas=NULL;
981    char **out_spaces=NULL;
982    int LocalHead = wami_lh();
983    int dec_places = 1;
984    char histart[16],hiend[16], hmarkstart[16], hmarkend[16];
985 
986    int biggg=0 ;                          /* HTML flourishes by RWCox */
987    const char *nbsp  = " &nbsp; " ;
988    const char *nbspp = " &nbsp;&nbsp; " ;
989    const char *sp = " ";
990    const char *spp = "  ";
991    const char *nsp = NULL;
992    const char *nspp = NULL;
993 
994    ENTRY("genx_Atlas_Query_to_String") ;
995    if (!wami) {
996       ERROR_message("NULL wami");
997       RETURN(rbuf);
998    }
999 
1000    { char *eee ; /* 06 Nov 2018 [RWCox] */
1001                        eee = getenv("AFNI_TTATLAS_FONTSIZE") ;
1002      if( eee == NULL ) eee = getenv("AFNI_FONTSIZE") ;
1003      biggg = ( eee != NULL && toupper(*eee) == 'B' ) ;
1004    }
1005 
1006    /* indent with HTML encoding for web output */
1007    if(AFNI_wami_output_mode()){
1008       nsp = nbsp;    /* use html hard spaces */
1009       nspp = nbspp;
1010       if( biggg ){
1011         sprintf(hmarkstart,"     <h2><b>");
1012         sprintf(histart,"      <h3>");
1013       } else {
1014         sprintf(hmarkstart,"     <h4><b>");
1015         sprintf(histart,"      <h5>");
1016       }
1017       sprintf(hiend,"<br>");
1018       /* these strings go around the html fields for focus point and atlas lines */
1019       sprintf(hmarkend, "</b><br>");
1020   }
1021    else{
1022       nsp = sp;    /* use a regular space. do not use html hard spaces */
1023       nspp = spp;
1024       histart[0] = '\0';
1025       hiend[0] = '\0';
1026       hmarkstart[0] = '\0';
1027       hmarkend[0] = '\0';
1028    }
1029 
1030    if(wami_verb()) {
1031       INFO_message("whereami in web output mode");
1032       INFO_message("start characters %s to %s", histart, hiend);
1033    };
1034    /* get output spaces from an env variable*/
1035    out_spaces = env_space_list(&N_out_spaces);
1036    dec_places = env_dec_places();
1037    if(!out_spaces) {
1038       /* the classic three. */
1039       out_spaces =  add_to_names_list(out_spaces, &N_out_spaces, "TLRC");
1040       out_spaces =  add_to_names_list(out_spaces, &N_out_spaces, "MNI");
1041       out_spaces =  add_to_names_list(out_spaces, &N_out_spaces, "MNI_ANAT");
1042    }
1043 
1044    out_spaces = add_to_names_list(out_spaces, &N_out_spaces, ac.space_name);
1045    if (N_out_spaces > max_spaces) {
1046       ERROR_message("Too many spaces for fixed allocation variables");
1047       RETURN(rbuf);
1048    }
1049    acl = (ATLAS_COORD *)calloc(N_out_spaces, sizeof(ATLAS_COORD));
1050    if (!transform_atlas_coords(ac, out_spaces, N_out_spaces, acl, "RAI")) {
1051       ERROR_message("Failed to transform coords");
1052       RETURN(rbuf);
1053    }
1054 
1055    if (LocalHead) {/* Show me all the coordinates */
1056       INFO_message("Original Coordinates \n");
1057       print_atlas_coord(ac);
1058       for (i=0; i<N_out_spaces; ++i) {
1059          INFO_message("Coordinate xformed to %s\n", out_spaces[i]);
1060          print_atlas_coord(acl[i]);
1061       }
1062    }
1063 
1064    /* find the coordinates that are in TLRC space, just for LR determination */
1065    it = find_coords_in_space(acl, N_out_spaces, "TLRC");
1066 
1067    /* Prep the string toys */
1068    INIT_SARR(sar) ; ADDTO_SARR(sar,WAMI_HEAD) ;
1069    sprintf(lbuf, "Original input data coordinates in %s space\n",
1070             ac.space_name);
1071    ADDTO_SARR(sar, lbuf);
1072 
1073    /* output decimal places */
1074    sprintf(pf, "%%%d.%df",4+dec_places,dec_places);
1075 
1076    /* form the string */
1077    for (i=0; i<N_out_spaces; ++i) {
1078       /* set precision of x,y,z output */
1079       sprintf(x_fstr, "%s", format_value_4print(-acl[i].x, CCALC_CUSTOM, pf));
1080       sprintf(y_fstr, "%s", format_value_4print(-acl[i].y, CCALC_CUSTOM, pf));
1081       sprintf(z_fstr, "%s", format_value_4print(acl[i].z, CCALC_CUSTOM, pf));
1082 
1083       /* the current rendition of this determines L/R from the CA_N27_LR
1084          brain in TLRC space based on the mask dataset with values of 0,1,2 */
1085       /* drg - see notes on MNI_Anatomical_Side at function for discussion */
1086 
1087       if(strcmp(acl[i].space_name,"MNI_ANAT") || (it<0)) {
1088          sprintf(xlab[i],"%s mm [%c]", x_fstr, (acl[i].x<0.0)?'R':'L') ;
1089       } else {
1090          sprintf(xlab[i], "%s mm [%c]", x_fstr,
1091            TO_UPPER(MNI_Anatomical_Side(acl[it], atlas_list))) ;
1092       }
1093 
1094       sprintf(ylab[i],"%s mm [%c]",y_fstr,(acl[i].y<0.0)?'A':'P') ;
1095       sprintf(zlab[i],"%s mm [%c]",z_fstr,(acl[i].z<0.0)?'I':'S') ;
1096       if((strcmp(acl[i].space_name,"MNI")==0) && AFNI_wami_output_mode() &&
1097          (show_neurosynth_link() || show_sumsdb_link() )) {
1098           /* make sure there's a blank string to start */
1099           sumsdb_link_str[0] = '\0';
1100           neurosynth_link_str[0] = '\0';
1101           if(show_sumsdb_link()){
1102               sprintf(sumsdb_link_str, "%s <a href=\"%s\">SumsDB</a>",
1103                    nsp,sumsdb_coords_link(-acl[i].x, -acl[i].y, acl[i].z));
1104           }
1105           if(show_neurosynth_link())
1106               sprintf(neurosynth_link_str, "%s <a href=\"%s\">NeuroSynth</a>",
1107                    nsp,neurosynth_coords_link(-acl[i].x, -acl[i].y, acl[i].z));
1108 
1109           sprintf(clab[i],"{MNI} %s %s", neurosynth_link_str, sumsdb_link_str);
1110       }
1111       else sprintf(clab[i],"{%s}", acl[i].space_name);
1112 
1113    }
1114    free(acl); acl = NULL;
1115 #if 0
1116    if(AFNI_wami_output_mode()){
1117       sprintf(lbuf, "<div style=\"background-color:Gray\">\n");
1118       ADDTO_SARR(sar, lbuf);
1119    }
1120 #endif
1121 
1122    /* form the Focus point part */
1123    switch (mode) {
1124       case CLASSIC_WAMI_ATLAS_SORT:
1125       case CLASSIC_WAMI_ZONE_SORT:
1126             SS('m');
1127             if(AFNI_wami_output_mode()){
1128                sprintf(lbuf, "%s<b>Focus point (LPI) = %c</b>%s", hmarkstart,
1129                   lsep,hmarkend);
1130             }
1131             else
1132                sprintf(lbuf,"Focus point (LPI)=%c", lsep);
1133             for (i=0; i<N_out_spaces; ++i) {
1134                if(strcmp(clab[i],"{Unknown}")!=0){
1135                   sprintf(tmps, "%s   %s, %s, %s %s%s%c",
1136                       histart, xlab[i], ylab[i], zlab[i], clab[i], hiend, lsep);
1137                   strncat(lbuf, tmps, (1023-strlen(lbuf))*sizeof(char));
1138                }
1139             }
1140             ADDTO_SARR(sar,lbuf);
1141          break;
1142       case TAB1_WAMI_ATLAS_SORT:
1143       case TAB1_WAMI_ZONE_SORT:
1144       case TAB2_WAMI_ATLAS_SORT:
1145       case TAB2_WAMI_ZONE_SORT:
1146             SS('o');
1147             sprintf(lbuf,"%-36s\t%-12s", "Focus point (LPI)", "Coord.Space");
1148             ADDTO_SARR(sar,lbuf);
1149             for (ii=0; ii<3; ++ii) {
1150                SS('p');sprintf(tmps,"%s, %s, %s", xlab[ii], ylab[ii], zlab[ii]);
1151                SS('q');sprintf(lbuf,"%-36s\t%-64s", tmps, clab[ii]);
1152                ADDTO_SARR(sar,lbuf);
1153             }
1154          break;
1155       default:
1156          ERROR_message("Bad mode %d", mode);
1157          RETURN(rbuf);
1158    }
1159 
1160    if(AFNI_wami_output_mode()){
1161       sprintf(lbuf, "<hr><p>\n");
1162       ADDTO_SARR(sar, lbuf);
1163    }
1164 
1165 #if 0
1166    if(AFNI_wami_output_mode()){
1167       sprintf(lbuf, "</div>\n");
1168       ADDTO_SARR(sar, lbuf);
1169    }
1170 #endif
1171 
1172 /***********end focus point section **************************************/
1173 
1174 /**********atlas query output ********************************************/
1175    switch (mode) {
1176       case CLASSIC_WAMI_ATLAS_SORT: /* the olde ways */
1177             /*-- assemble output string(s) for each atlas --*/
1178             nfind = 0;
1179             /* for each atlas atcode */
1180             for (iatlas=0; iatlas < atlas_list->natlases; ++iatlas) {
1181                atlas = &(atlas_list->atlas[iatlas]);
1182                nfind_one = 0;
1183                /* for each zone iq */
1184                for (iq=0; iq<wami->N_zone; ++iq) {
1185                   newzone = 1;
1186                   /* for each label in a zone il */
1187                   for (il=0; il<wami->zone[iq]->N_label; ++il) {
1188                      if((wami->zone[iq]->connpage[il]) &&
1189                         (strcmp(wami->zone[iq]->connpage[il],"")!=0))
1190                         sprintf(connbuf, "%s <a href=\"%s\">connections</a>",
1191                             nsp,wami->zone[iq]->connpage[il]);
1192                      else
1193                         sprintf(connbuf," ");
1194 
1195                      if (is_Atlas_Named(atlas, wami->zone[iq]->atname[il]))  {
1196                         if (!nfind_one) {
1197                            SS('r');
1198                            sprintf(lbuf, "%sAtlas %s: %s%s", hmarkstart, ATL_NAME_S(atlas),
1199                              ATL_DESCRIPTION_S(atlas), hmarkend);
1200                            ADDTO_SARR(sar,lbuf);
1201                         }
1202                         if (newzone) {
1203                            if (wami->zone[iq]->radius[il] == 0.0) {
1204                               SS('s');
1205                               /* format webpage links specially */
1206                               if(AFNI_wami_output_mode() &&
1207                                  (wami->zone[iq]->webpage[il]) &&
1208                                  (strcmp(wami->zone[iq]->webpage[il],"")!=0))
1209                               {
1210                                  sprintf(lbuf,
1211                                "%s   Focus point: %s <a href=\"%s\">%s</a>  %s%s",
1212                                     histart,nsp,
1213                                     wami->zone[iq]->webpage[il],
1214                                     Clean_Atlas_Label(wami->zone[iq]->label[il]),
1215                                     connbuf,
1216                                     hiend);
1217                               }
1218                               else
1219                                  sprintf(lbuf,
1220                                 "%s   Focus point: %s%s%s",
1221                                     histart,nsp,
1222                                     Clean_Atlas_Label(wami->zone[iq]->label[il]),
1223                                     hiend);
1224                            } else {
1225                               SS('t');
1226                               if(AFNI_wami_output_mode() &&
1227                                  (wami->zone[iq]->webpage[il]) &&
1228                                  (strcmp(wami->zone[iq]->webpage[il],"")!=0))
1229                               {
1230                                  sprintf(lbuf,
1231                                  "%s * Within %1d mm: %s <a href=\"%s\">%s</a>  %s%s",
1232                                     histart,
1233                                     (int)wami->zone[iq]->radius[il], nsp,
1234                                     wami->zone[iq]->webpage[il],
1235                                     Clean_Atlas_Label(wami->zone[iq]->label[il]),
1236                                     connbuf,
1237                                     hiend);
1238                               }
1239                               else
1240                                  sprintf(lbuf, "%s * Within %1d mm: %s%s",
1241                                     histart,
1242                                     (int)wami->zone[iq]->radius[il],
1243                                     Clean_Atlas_Label(wami->zone[iq]->label[il]),
1244                                     hiend);
1245                            }
1246                            newzone = 0;
1247                         } else {
1248                            SS('u');
1249                            if(AFNI_wami_output_mode() &&
1250                               (wami->zone[iq]->webpage[il]) &&
1251                               (strcmp(wami->zone[iq]->webpage[il],"")!=0))
1252                            {
1253                               sprintf(lbuf,
1254                               "%s%s      -AND-%s <a href=\"%s\">%s</a>  %s%s",
1255                                  histart,nspp,nsp,
1256                                  wami->zone[iq]->webpage[il],
1257                                  Clean_Atlas_Label(wami->zone[iq]->label[il]),
1258                                  connbuf,
1259                                  hiend);
1260                            }
1261                            else
1262                               sprintf(lbuf, "%s%s          -AND-%s %s%s", histart,nspp,nsp,
1263                                  Clean_Atlas_Label(wami->zone[iq]->label[il]), hiend);
1264                         }
1265 
1266 
1267                         if (wami->zone[iq]->prob[il] > 0.0) {
1268                            SS('v');
1269                            sprintf(lbuf+strlen(lbuf), "%s   (p = %s)%s", histart,
1270                                  Atlas_Prob_String(wami->zone[iq]->prob[il]), hiend);
1271                         }
1272                         ADDTO_SARR(sar,lbuf);
1273                         ++nfind; ++nfind_one;
1274                      }
1275                   } /* il */
1276                } /* iq */
1277                if (nfind_one) {
1278                   ADDTO_SARR(sar,"");
1279                   if(AFNI_wami_output_mode()){
1280                      sprintf(lbuf, "<hr><p>\n");
1281                      ADDTO_SARR(sar, lbuf);
1282                   }
1283                }
1284 
1285             } /* iatlas */
1286 
1287          break;
1288       case CLASSIC_WAMI_ZONE_SORT:
1289             /*-- assemble output string(s) for each atlas --*/
1290             nfind = 0;
1291             for (iq=0; iq<wami->N_zone; ++iq) { /* iq */
1292                if (wami->zone[iq]->level == 0) {
1293                   SS('w');sprintf(lbuf, "%sFocus point:%s", histart, hiend);
1294                } else {
1295                   SS('x');sprintf(lbuf, "%s * Within %1d mm:%s%s",histart,
1296                                  (int)wami->zone[iq]->level,nsp, hiend);
1297                }
1298                ADDTO_SARR(sar,lbuf);
1299                for (il=0; il<wami->zone[iq]->N_label; ++il) { /* il */
1300                   SS('y');sprintf(lbuf, "%s   %-32s, Atlas %-15s", histart,
1301                      Clean_Atlas_Label(wami->zone[iq]->label[il]),
1302                                        wami->zone[iq]->atname[il]);
1303 
1304                   if (wami->zone[iq]->prob[il] > 0.0) {
1305                      SS('z');
1306                      sprintf(lbuf+strlen(lbuf),
1307                               ", prob. = %-3s",
1308                               Atlas_Prob_String(wami->zone[iq]->prob[il]));
1309                   }
1310                   sprintf(lbuf+strlen(lbuf), "%s", hiend);
1311 
1312                   ADDTO_SARR(sar,lbuf);
1313                   ++nfind;
1314                } /* il */
1315             } /* iq */
1316 
1317          break;
1318       case TAB1_WAMI_ZONE_SORT:
1319       case TAB2_WAMI_ZONE_SORT:
1320          /*-- assemble output string(s) for each atlas --*/
1321             SS('E');
1322             sprintf(lbuf, "%-3s\t%-15s\t%-32s\t%-3s\t%-3s",
1323                      "Within", "Atlas", "Label", "Prob.", "Code");
1324             ADDTO_SARR(sar,lbuf);
1325             nfind = 0;
1326                for (iq=0; iq<wami->N_zone; ++iq) { /* iq */
1327                   for (il=0; il<wami->zone[iq]->N_label; ++il) { /* il */
1328                      if (1) {
1329                         SS('F');
1330                         sprintf(tmps, "%.1f", wami->zone[iq]->radius[il]);
1331                         SS('G');
1332                         sprintf(lbuf, "%-3s\t%-15s\t%-32s\t%-3s\t%-3d",
1333                           tmps, wami->zone[iq]->atname[il],
1334                           Clean_Atlas_Label(wami->zone[iq]->label[il]),
1335                           Atlas_Prob_String(wami->zone[iq]->prob[il]),
1336                           wami->zone[iq]->code[il]);
1337                         ADDTO_SARR(sar,lbuf);
1338                         ++nfind; ++nfind_one;
1339                      }
1340                   } /* il */
1341                } /* iq */
1342 
1343          break;
1344       case TAB1_WAMI_ATLAS_SORT:
1345       case TAB2_WAMI_ATLAS_SORT: /* like TAB1_WAMI_ATLAS_SORT but more to my
1346                                     liking for easy spreadsheet use */
1347             /*-- assemble output string(s) for each atlas --*/
1348             SS('H');
1349             sprintf( lbuf, "%-15s\t%-3s\t%-32s\t%-3s\t%-3s",
1350                      "Atlas", "Within", "Label", "Prob.", "Code");
1351             ADDTO_SARR(sar,lbuf);
1352             nfind = 0;
1353             for (iatlas=0; iatlas < atlas_list->natlases; ++iatlas){ /* iatlas */
1354                atlas = &(atlas_list->atlas[iatlas]);
1355                nfind_one = 0;
1356                for (iq=0; iq<wami->N_zone; ++iq) { /* iq */
1357                   for (il=0; il<wami->zone[iq]->N_label; ++il) { /* il */
1358                      if (is_Atlas_Named(atlas, wami->zone[iq]->atname[il])) {
1359                         SS('I');
1360                         sprintf(tmps, "%.1f", wami->zone[iq]->radius[il]);
1361                         SS('J');sprintf(lbuf, "%-15s\t%-3s\t%-32s\t%-3s\t%-3d",
1362                                     wami->zone[iq]->atname[il],
1363                                     tmps,
1364                                     Clean_Atlas_Label(wami->zone[iq]->label[il]),
1365                                     Atlas_Prob_String(wami->zone[iq]->prob[il]),
1366                                     wami->zone[iq]->code[il]);
1367                         ADDTO_SARR(sar,lbuf);
1368                         ++nfind; ++nfind_one;
1369                      }
1370                   } /* il */
1371                } /* iq */
1372 
1373             } /* iatlas */
1374 
1375          break;
1376       default:
1377          ERROR_message("Bad mode (%d).", mode);
1378          RETURN(rbuf);
1379    }
1380 
1381    /* anything ? */
1382    if (!nfind) {
1383       ADDTO_SARR(sar,"***** Not near any region stored in databases *****\n");
1384    }
1385    /*- if didn't make any label, must produce something -*/
1386 
1387    if( sar->num == 1 ){    /* shouldn't ever happen */
1388       SS('K');sprintf(lbuf,"Found %d marked but unlabeled regions???\n",nfind) ;
1389       ADDTO_SARR(sar,lbuf) ;
1390    } else if( !AFNI_noenv("AFNI_TTATLAS_CAUTION") ){
1391        if (!AFNI_wami_output_mode())
1392           ADDTO_SARR(sar,WAMI_TAIL) ;  /* cautionary tail */
1393    }
1394 
1395    if (AFNI_wami_output_mode() == 0) {
1396       /*- convert list of labels into one big multi-line string -*/
1397 
1398       for( nfind=ii=0 ; ii < sar->num ; ii++ ) nfind += strlen(sar->ar[ii]) ;
1399       rbuf = AFMALL(char, nfind + 2*sar->num + 32 ) ; rbuf[0] = '\0' ;
1400       for( ii=0 ; ii < sar->num ; ii++ ){
1401          strcat(rbuf,sar->ar[ii]) ; strcat(rbuf,"\n") ;
1402       }
1403    } else {
1404       /*- HTML -*/
1405       char *hhh = biggg ? "h1" : "h3" ;
1406       rbuf =  THD_zzprintf(rbuf,"<head>\n"
1407                "<center><title><%s>AFNI whereami</%s></title></center>\n"
1408                "</head>\n"
1409                "<body>\n"
1410                "<hr><p>\n" , hhh,hhh
1411                );
1412 #if 0
1413                "<a name=\"top\"></a>\n"
1414                "<center><%s>whereami report\n"
1415                " </%s></center>\n"
1416                "<hr><p>\n"
1417                "\n"       , hhh,hhh );
1418 #endif
1419 
1420       /* render each line of the string array,sar, in HTML */
1421       /* note most rendering is done before this, when the query string is built */
1422       for( ii=0 ; ii < sar->num ; ii++ ){
1423          /* if the line begins with 6 pluses, center the line */
1424          if (!strncmp(sar->ar[ii],"++++++",6)) {
1425             rbuf =  THD_zzprintf(rbuf,
1426                  "<p><center>%s\n"
1427                   "</center>\n", sar->ar[ii]);
1428          } else {
1429             rbuf =  THD_zzprintf(rbuf,"%s\n", sar->ar[ii]);
1430          }
1431       }
1432 
1433       rbuf =  THD_zzprintf(rbuf,"</body>\n</html>\n");
1434    }
1435 
1436    DESTROY_SARR(sar) ;
1437 
1438    if (LocalHead) {
1439       INFO_message("Have:\n%s\n", rbuf);
1440    }
1441 
1442    RETURN(rbuf);
1443 
1444 }
1445 
transform_atlas_coords(ATLAS_COORD ac,char ** out_spaces,int N_out_spaces,ATLAS_COORD * acl,char * orcodeout)1446 int transform_atlas_coords(ATLAS_COORD ac, char **out_spaces,
1447                            int N_out_spaces, ATLAS_COORD *acl, char *orcodeout)
1448 {
1449    ATLAS_XFORM_LIST *xfl=NULL, *cxfl=NULL;
1450    int i;
1451    float xout=0.0, yout=0.0, zout=0.0;
1452 
1453    ENTRY("transform_atlas_coords");
1454 
1455    if (!out_spaces || !acl) RETURN(0);
1456 
1457    if (strncmp(ac.orcode, "RAI", 3)) {
1458       ERROR_message(
1459          "AC orientation (%s) not RAI\n"
1460          "Need a function to turn ac to RAI ",
1461                      ac.orcode);
1462       RETURN(0);
1463    }
1464    if (strncmp(orcodeout, "RAI", 3)) {
1465       ERROR_message(
1466          "Output orientation (%s) not RAI\n"
1467          "Need a function to go from RAI to desired output orientation ",
1468                      ac.orcode);
1469       RETURN(0);
1470    }
1471 
1472    for (i=0; i<N_out_spaces; ++i) {
1473       if ((xfl = report_xform_chain(ac.space_name, out_spaces[i], 0))) {
1474          cxfl = calc_xform_list(xfl);
1475          apply_xform_chain(cxfl, ac.x, ac.y, ac.z, &xout, &yout, &zout);
1476          XYZ_to_AtlasCoord(xout, yout, zout, "RAI",
1477                            out_spaces[i], &(acl[i]));
1478          if(xfl)
1479            free_xform_list(xfl);
1480          if(cxfl)
1481            free_xform_list(cxfl);
1482       } else {
1483          if (wami_verb()) {
1484             INFO_message("no route from %s to %s",
1485                         ac.space_name, out_spaces[i]);
1486          }
1487          XYZ_to_AtlasCoord(0.0, 0.0, 0.0, "RAI",
1488                            "Unknown", &(acl[i]));
1489       }
1490    }
1491 
1492    RETURN(1);
1493 }
1494 
1495 /* show links out to neurosynth.org */
1496 int
show_neurosynth_link()1497 show_neurosynth_link()
1498 {
1499   if(neurosynth_link >=0)
1500      return(neurosynth_link);
1501   /* default now shows AFNI_NEUROSYNTH on (YES)
1502      with WEBBY_WAMI also now yes, drg 01/23/2015 */
1503   if (AFNI_noenv("AFNI_NEUROSYNTH"))
1504      neurosynth_link = 0;
1505   else
1506      neurosynth_link = 1;
1507   return(neurosynth_link);
1508 }
1509 
1510 /* format a coordinates link string the Neurosynth website */
1511 char *
neurosynth_coords_link(float x,float y,float z)1512 neurosynth_coords_link(float x, float y, float z)
1513 {
1514    static char neurosynthpage[128];
1515    int ix,iy,iz;
1516 
1517    ix = (int) x; iy = (int) y; iz = (int) z;
1518 
1519    sprintf(neurosynthpage, "http://neurosynth.org/locations/%d_%d_%d",ix,iy,iz);
1520    return(neurosynthpage);
1521 }
1522 
1523 /* show links out to sumsdb at washu */
1524 /* unfortunately, they stopped this service in 2016 at some point DRG - 08 Nov 2017 */
1525 int
show_sumsdb_link()1526 show_sumsdb_link()
1527 {
1528   if(sumsdb_link >=0)
1529      return(sumsdb_link);
1530 
1531   if (AFNI_yesenv("AFNI_SUMSDB"))
1532      sumsdb_link = 1;
1533   else
1534      sumsdb_link = 0;
1535   return(sumsdb_link);
1536 }
1537 
1538 /* format a coordinates link string the SumsDB website */
1539 char *
sumsdb_coords_link(float x,float y,float z)1540 sumsdb_coords_link(float x, float y, float z)
1541 {
1542    static char sumsdbpage[320];
1543    int ix,iy,iz;
1544 
1545    ix = (int) x; iy = (int) y; iz = (int) z;
1546 
1547    if (WAMIRAD < 0.0) {
1548       WAMIRAD = Init_Whereami_Max_Rad();
1549    }
1550 
1551    sprintf(sumsdbpage,
1552            "http://sumsdb.wustl.edu/sums/celldatasearch.do?"
1553            "type=sumsdb_cell_data&xcoord=%d&ycoord=%d&zcoord=%d&distance=%.1f",
1554            ix,iy,iz, WAMIRAD);
1555 
1556    return(sumsdbpage);
1557 }
1558 
1559 /*--------------------------------------------------------------------*/
1560 /* get the name of the linkRbrain web page to use [16 Oct 2015 */
1561 
get_linkrbrain_site(void)1562 char * get_linkrbrain_site(void)
1563 {
1564    char *eee = getenv("AFNI_LINKRBRAIN_SITE") ;
1565    if( eee == NULL ) eee = LINKRBRAIN_SITE ;
1566    return eee ;
1567 }
1568 /*--------------------------------------------------------------------*/
1569 
1570 /* show links out to linkrbrain */
1571 /* linkrbrain server has been down for quite a while.
1572  * Default to not try - DRG 08 Nov 2017 */
1573 int
show_linkrbrain_link()1574 show_linkrbrain_link()
1575 {
1576   if(linkrbrain_link >=0)
1577      return(linkrbrain_link);
1578   if( AFNI_yesenv("AFNI_LINKRBRAIN") )  /* 01 Oct 2015 */
1579      linkrbrain_link = 1;
1580   else
1581      linkrbrain_link = 0;
1582   return(linkrbrain_link);
1583 }
1584 
1585 /* make linkrbrain xml query  - remote query */
1586 /* Prepare input coordinates for transfer to linkRbrain site
1587    the input coordinates should be RAI order */
1588 int
make_linkrbrain_xml(float * coords,int ncoords,char * srcspace,char * destspace,char * linkrbrain_xml,int linkr_corr_type)1589 make_linkrbrain_xml(float *coords, int ncoords, char *srcspace, char *destspace,
1590     char *linkrbrain_xml, int linkr_corr_type)
1591 {
1592    int i;
1593    FILE *tempout;
1594    float *fptr;
1595    float xi,yi,zi,xout,yout,zout;
1596    ATLAS_XFORM_LIST *xfl = NULL, *cxfl = NULL;
1597 
1598    ENTRY("make_linkrbrain_xml");
1599 
1600    if(ncoords<=0)
1601      RETURN(-1);
1602 
1603    tempout = fopen(linkrbrain_xml, "w");
1604    if(!tempout) RETURN(-1);
1605 
1606    if(strcmp(srcspace, destspace)==0){
1607       cxfl = NULL;   /* data already in destination space for linkrbrain (MNI) */
1608 /*      printf("No transformation needed to go to space:%s\n", destspace);*/
1609    }
1610    else {
1611       xfl = report_xform_chain(srcspace, destspace, 0);
1612       cxfl = calc_xform_list(xfl);
1613       if(!cxfl){
1614          WARNING_message("Could not compute xform between spaces for linkrbrain\n");
1615          free(xfl);
1616          RETURN(-1);
1617       }
1618    }
1619 
1620    fprintf(tempout, "xml=<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n");
1621    if(linkr_corr_type == 0)
1622       fprintf(tempout,
1623       "<query title=\"Query importation test\" correlate-with=\"tasks\">\n");
1624    else
1625       fprintf(tempout,
1626       "<query title=\"Query importation test\" correlate-with=\"genes\">\n");
1627 
1628    fprintf(tempout, "  <group title=\"Group test\">\n");
1629    fprintf(tempout, "	 <pointset title=\"Pointset test\">\n");
1630 
1631    /* convert coordinates to LPI */
1632    for(i=0;i<ncoords;i++){
1633          fptr = coords+(i*3);
1634          if(cxfl) {
1635             xi = *fptr++; yi = *fptr++; zi = *fptr;
1636             apply_xform_chain(cxfl, xi, yi, zi, &xout, &yout, &zout);
1637          }
1638          else {
1639             xi = *fptr++; yi = *fptr++; zi = *fptr;
1640             xout = xi; yout = yi; zout = zi;
1641          }
1642 #if 0
1643          if(cxfl) {
1644             xi = *fptr; yi = *fptr+1; zi = *fptr+2;
1645             apply_xform_chain(cxfl, xi, yi, zi, &xout, &yout, &zout);
1646          }
1647          else {
1648             xi = *fptr; yi = *fptr+1; zi = *fptr+2;
1649             xout = *fptr; yout = *fptr+1; zout = *fptr+2;
1650          }
1651 #endif
1652 
1653          /** can add w="%.1f" to include a weight with each point [RWC] **/
1654 
1655          fprintf(tempout, "<point x=\"%.1f\" y=\"%.1f\" z=\"%.1f\" />\n",
1656                 -xout, -yout, zout);
1657    }
1658    fprintf(tempout,"     </pointset>\n");
1659    fprintf(tempout,"   </group>\n");
1660    fprintf(tempout,"</query>\n");
1661 
1662    fclose(tempout);
1663    free(cxfl);
1664    free(xfl);
1665 
1666 /* xml=<?xml version="1.0" encoding="UTF-8"?>
1667 <query title="Query importation test" correlate-with="tasks">
1668 	<group title="Group test">
1669 		<pointset title="Pointset test">
1670 			<point x="-11.0" y="+64.2" z="+25.9" />
1671 			<point x="+29.5" y="+77.0" z="+16.1" />
1672 			<point x="+52.3" y="+7.5" z="+10.1" />
1673 			<point x="-3.5" y="-77.8" z="+11.7" />
1674 			<point x="-60.0" y="-3.4" z="+9.2" />
1675 			<point x="-32.6" y="-47.8" z="+62.2" />
1676 		</pointset>
1677 	</group>
1678 </query>
1679  */
1680    RETURN(0);
1681 }
1682 
1683 /* send linkrbrain xml query  - remote query */
1684 /* redirect output to results file */
1685 int
send_linkrbrain_xml(char * linkrbrain_xml,char * linkrbrain_results)1686 send_linkrbrain_xml(char *linkrbrain_xml, char *linkrbrain_results)
1687 {
1688    char cmd[1234];
1689    int curl_stat, retry = 0;
1690 
1691    while(retry<5) {
1692       fprintf(stderr,"Sending %s request\n",get_linkrbrain_site());
1693       sprintf(cmd,
1694         "curl -y 100 --retry 5 --retry-delay 1 --connect-timeout 5 -m 10"
1695         " --retry-max-time 25 -d @%s http://api.%s/ > %s",
1696              linkrbrain_xml, get_linkrbrain_site(), linkrbrain_results);
1697       curl_stat = system(cmd);
1698       if(curl_stat) retry++;
1699       else return(0);
1700    }
1701 /* --keepalive-time seconds --keepalive */
1702    return(1);
1703 
1704 }
1705 
find_coords_in_space(ATLAS_COORD * acl,int N_acl,char * space_name)1706 int find_coords_in_space(ATLAS_COORD *acl, int N_acl, char *space_name)
1707 {
1708    int i;
1709 
1710    if (!space_name || !acl) return(-1);
1711    for (i=0; i<N_acl; ++i) {
1712       if (!strcmp(acl[i].space_name,space_name)) return(i);
1713    }
1714    return(-1);
1715 }
1716 
Atlas_Query_to_String(ATLAS_QUERY * wami,ATLAS_COORD ac,WAMI_SORT_MODES mode,ATLAS_LIST * atlas_list)1717 char * Atlas_Query_to_String (ATLAS_QUERY *wami,
1718                               ATLAS_COORD ac, WAMI_SORT_MODES mode,
1719                               ATLAS_LIST *atlas_list)
1720 {
1721    char *rbuf = NULL;
1722    char  xlab[5][32], ylab[5][32] , zlab[5][32],
1723          clab[5][32], lbuf[1024]  , tmps[1024] ;
1724    THD_fvec3 t, m;
1725    THD_string_array *sar =NULL;
1726    ATLAS_COORD acv[NUMBER_OF_SPC];
1727    int iatlas = -1;
1728    int i, ii, nfind=0, nfind_one = 0, iq=0, il=0, newzone = 0;
1729    AFNI_STD_SPACES start_space;
1730    ATLAS *atlas=NULL;
1731    int LocalHead = wami_lh();
1732 
1733    ENTRY("Atlas_Query_to_String") ;
1734 
1735    if (wami_verb()) INFO_message("Obsolete, use genx_Atlas_Query_to_String") ;
1736 
1737    if (!wami) {
1738       ERROR_message("NULL wami");
1739       RETURN(rbuf);
1740    }
1741 
1742    /* get the coordinates into as many spaces as possible */
1743    /* first put ac in AFNI_TLRC */
1744    LOAD_FVEC3( m , ac.x, ac.y, ac.z ) ;
1745    /* the original starting space has the coordinates for that space */
1746    start_space = Space_Name_to_Space_Code(ac.space_name);
1747                         /* save the index of the original space */
1748    acv[Space_Name_to_Space_Code(ac.space_name)] = ac;
1749 /* use general transformation among spaces from NIML database here
1750     if possible. Need which output spaces or show all available output spaces */
1751    switch (Space_Name_to_Space_Code(ac.space_name)) {
1752       default: ERROR_message("bad ac.space") ; RETURN(rbuf);
1753       case AFNI_TLRC_SPC:
1754          acv[AFNI_TLRC_SPC].x = ac.x;
1755          acv[AFNI_TLRC_SPC].y = ac.y;
1756          acv[AFNI_TLRC_SPC].z = ac.z;
1757          set_Coord_Space_Name(&(acv[AFNI_TLRC_SPC]), "TLRC");
1758          break;
1759       case MNI_ANAT_SPC:
1760          t = THD_mnia_to_tta_N27(m);
1761          if (t.xyz[0] < -500) { ERROR_message("Failed in xforming the data"); }
1762          acv[AFNI_TLRC_SPC].x = t.xyz[0];
1763          acv[AFNI_TLRC_SPC].y = t.xyz[1];
1764          acv[AFNI_TLRC_SPC].z = t.xyz[2];
1765          set_Coord_Space_Name(&(acv[AFNI_TLRC_SPC]), "TLRC");
1766          break;
1767       case MNI_SPC:
1768          /* function below expects coords in LPI !!!*/
1769          m.xyz[0] = -m.xyz[0]; m.xyz[1] = -m.xyz[1];
1770          t = THD_mni_to_tta(m);  /* Used to be: THD_mni_to_tta_N27 but that
1771                                     is inconsistent with inverse transformation
1772                                     below which used  THD_tta_to_mni to go back
1773                                     to mni space ZSS: Jul. 08*/
1774          if (t.xyz[0] < -500) { ERROR_message("Failed in xforming the data"); }
1775          acv[AFNI_TLRC_SPC].x = t.xyz[0];
1776          acv[AFNI_TLRC_SPC].y = t.xyz[1];
1777          acv[AFNI_TLRC_SPC].z = t.xyz[2];
1778          set_Coord_Space_Name(&(acv[AFNI_TLRC_SPC]), "TLRC");
1779          break;
1780    }
1781 
1782 
1783    if (LocalHead) {/* Show me all the coordinates */
1784       INFO_message("Original Coordinates in %s: %f %f %f\n",
1785                      ac.space_name, ac.x, ac.y, ac.z);
1786       /* got turned to "TLRC" */
1787       INFO_message("Coordinate in %s: %f %f %f\n",
1788                      acv[AFNI_TLRC_SPC].space_name,
1789             acv[AFNI_TLRC_SPC].x, acv[AFNI_TLRC_SPC].y, acv[AFNI_TLRC_SPC].z);
1790    }
1791 
1792    /* Prep the string toys */
1793    INIT_SARR(sar) ; ADDTO_SARR(sar,WAMI_HEAD) ;
1794    sprintf(lbuf, "Original input data coordinates in %s space\n",
1795             ac.space_name);
1796    ADDTO_SARR(sar, lbuf);
1797    ac = acv[AFNI_TLRC_SPC]; /* TLRC from now on */
1798    for (i=UNKNOWN_SPC+1; i<NUMBER_OF_SPC; ++i) {
1799       if(i!=start_space) {  /* if not already set from starting space */
1800          LOAD_FVEC3(m,ac.x, ac.y, ac.z);
1801          t = m;      /* default no transformation of coordinates */
1802          if(i==MNI_SPC) {
1803             t = THD_tta_to_mni(m);   /* returns LPI */
1804             t.xyz[0] = -t.xyz[0]; t.xyz[1] = -t.xyz[1];
1805          }
1806          else
1807             if(i==MNI_ANAT_SPC)
1808                t = THD_tta_to_mnia_N27(m);
1809          acv[i].x = t.xyz[0]; acv[i].y = t.xyz[1]; acv[i].z = t.xyz[2];
1810       }
1811       /* for MNI anatomical output, check TLRC coordinates against L/R volume that is
1812       already in TLRC space. This LR volume had been converted from MNI_Anat space.
1813       The L/R volume is from a particular subject, and it is not completely aligned along
1814       any zero line separating left from right */
1815       if(i!=MNI_ANAT_SPC)
1816          sprintf(xlab[i-1],"%4.0f mm [%c]",-acv[i].x,(acv[i].x<0.0)?'R':'L') ;
1817       else
1818          sprintf(xlab[i-1], "%4.0f mm [%c]",
1819                    -acv[i].x, TO_UPPER(MNI_Anatomical_Side(acv[AFNI_TLRC_SPC],
1820                                atlas_list))) ;
1821       sprintf(ylab[i-1],"%4.0f mm [%c]",-acv[i].y,(acv[i].y<0.0)?'A':'P') ;
1822       sprintf(zlab[i-1],"%4.0f mm [%c]", acv[i].z,(acv[i].z<0.0)?'I':'S') ;
1823       sprintf(clab[i-1],"{%s}", Space_Code_to_Space_Name(i));
1824    }
1825 
1826    /* form the Focus point part */
1827    switch (mode) {
1828       case CLASSIC_WAMI_ATLAS_SORT:
1829       case CLASSIC_WAMI_ZONE_SORT:
1830             SS('m');sprintf(lbuf,"Focus point (LPI)=%c"
1831                          "   %s,%s,%s %s%c"
1832                          "   %s,%s,%s %s%c"
1833                          "   %s,%s,%s %s%c",
1834                          lsep,
1835                          xlab[0], ylab[0], zlab[0], clab[0], lsep,
1836                          xlab[1], ylab[1], zlab[1], clab[1], lsep,
1837                          xlab[2], ylab[2], zlab[2], clab[2], lsep);
1838             ADDTO_SARR(sar,lbuf);
1839          break;
1840       case TAB1_WAMI_ATLAS_SORT:
1841       case TAB1_WAMI_ZONE_SORT:
1842       case TAB2_WAMI_ATLAS_SORT:
1843       case TAB2_WAMI_ZONE_SORT:
1844             SS('o');
1845             sprintf(lbuf,"%-36s\t%-64s", "Focus point (LPI)", "Coord.Space");
1846             ADDTO_SARR(sar,lbuf);
1847             for (ii=0; ii<3; ++ii) {
1848                SS('p');sprintf(tmps,"%s,%s,%s", xlab[ii], ylab[ii], zlab[ii]);
1849                SS('q');sprintf(lbuf,"%-36s\t%-12s", tmps, clab[ii]);
1850                ADDTO_SARR(sar,lbuf);
1851             }
1852          break;
1853       default:
1854          ERROR_message("Bad mode %d", mode);
1855          RETURN(rbuf);
1856    }
1857 
1858 
1859    switch (mode) {
1860       case CLASSIC_WAMI_ATLAS_SORT: /* the olde ways */
1861             /*-- assemble output string(s) for each atlas --*/
1862             nfind = 0;
1863             /* for each atlas atcode */
1864             for (iatlas=0; iatlas < atlas_list->natlases; ++iatlas) {
1865                atlas = &(atlas_list->atlas[iatlas]);
1866                nfind_one = 0;
1867                /* for each zone iq */
1868                for (iq=0; iq<wami->N_zone; ++iq) {
1869                   newzone = 1;
1870                   /* for each label in a zone il */
1871                   for (il=0; il<wami->zone[iq]->N_label; ++il) {
1872                      if (is_Atlas_Named(atlas, wami->zone[iq]->atname[il]))  {
1873                         if (!nfind_one) {
1874                            SS('r');
1875                            sprintf(lbuf, "Atlas %s: %s", ATL_NAME_S(atlas),
1876                              ATL_DESCRIPTION_S(atlas));
1877                            ADDTO_SARR(sar,lbuf);
1878                         }
1879                         if (newzone) {
1880                            if (wami->zone[iq]->radius[il] == 0.0) {
1881                               SS('s');
1882                               sprintf(lbuf, "   Focus point: %s",
1883                                  Clean_Atlas_Label(wami->zone[iq]->label[il]));
1884                            } else {
1885                               SS('t');
1886                               sprintf(lbuf, "   Within %1d mm: %s",
1887                                   (int)wami->zone[iq]->radius[il],
1888                                   Clean_Atlas_Label(wami->zone[iq]->label[il]));
1889                            }
1890                            newzone = 0;
1891                         } else {
1892                            SS('u');
1893                            sprintf(lbuf, "          -AND- %s",
1894                                  Clean_Atlas_Label(wami->zone[iq]->label[il]));
1895                         }
1896                         if (wami->zone[iq]->prob[il] > 0.0) {
1897                            SS('v');
1898                            sprintf(lbuf+strlen(lbuf), "   (p = %s)",
1899                                  Atlas_Prob_String(wami->zone[iq]->prob[il]));
1900                         }
1901                         ADDTO_SARR(sar,lbuf);
1902                         ++nfind; ++nfind_one;
1903                      }
1904                   } /* il */
1905                } /* iq */
1906                if (nfind_one) {
1907                   ADDTO_SARR(sar,"");
1908                }
1909             } /* iatlas */
1910 
1911          break;
1912       case CLASSIC_WAMI_ZONE_SORT:
1913             /*-- assemble output string(s) for each atlas --*/
1914             nfind = 0;
1915             for (iq=0; iq<wami->N_zone; ++iq) { /* iq */
1916                if (wami->zone[iq]->level == 0) {
1917                   SS('w');sprintf(lbuf, "Focus point:");
1918                } else {
1919                   SS('x');sprintf(lbuf, "Within %1d mm:",
1920                                  (int)wami->zone[iq]->level);
1921                }
1922                ADDTO_SARR(sar,lbuf);
1923                for (il=0; il<wami->zone[iq]->N_label; ++il) { /* il */
1924                   SS('y');sprintf(lbuf, "   %-32s, Atlas %-15s",
1925                      Clean_Atlas_Label(wami->zone[iq]->label[il]),
1926                                        wami->zone[iq]->atname[il]);
1927 
1928                   if (wami->zone[iq]->prob[il] > 0.0) {
1929                      SS('z');
1930                      sprintf(lbuf+strlen(lbuf),
1931                               ", prob. = %-3s",
1932                               Atlas_Prob_String(wami->zone[iq]->prob[il]));
1933                   }
1934                   ADDTO_SARR(sar,lbuf);
1935                   ++nfind;
1936                } /* il */
1937             } /* iq */
1938 
1939          break;
1940       case TAB1_WAMI_ZONE_SORT:
1941       case TAB2_WAMI_ZONE_SORT:
1942          /*-- assemble output string(s) for each atlas --*/
1943             SS('E');
1944             sprintf(lbuf, "%-3s\t%-15s\t%-32s\t%-3s\t%-3s",
1945                      "Within", "Atlas", "Label", "Prob.", "Code");
1946             ADDTO_SARR(sar,lbuf);
1947             nfind = 0;
1948                for (iq=0; iq<wami->N_zone; ++iq) { /* iq */
1949                   for (il=0; il<wami->zone[iq]->N_label; ++il) { /* il */
1950                      if (1) {
1951                         SS('F');
1952                         sprintf(tmps, "%.1f", wami->zone[iq]->radius[il]);
1953                         SS('G');
1954                         sprintf(lbuf, "%-3s\t%-15s\t%-32s\t%-3s\t%-3d",
1955                           tmps, wami->zone[iq]->atname[il],
1956                           Clean_Atlas_Label(wami->zone[iq]->label[il]),
1957                           Atlas_Prob_String(wami->zone[iq]->prob[il]),
1958                           wami->zone[iq]->code[il]);
1959                         ADDTO_SARR(sar,lbuf);
1960                         ++nfind; ++nfind_one;
1961                      }
1962                   } /* il */
1963                } /* iq */
1964 
1965          break;
1966       case TAB1_WAMI_ATLAS_SORT:
1967       case TAB2_WAMI_ATLAS_SORT: /* like TAB1_WAMI_ATLAS_SORT but more to my
1968                                     liking for easy spreadsheet use */
1969             /*-- assemble output string(s) for each atlas --*/
1970             SS('H');
1971             sprintf( lbuf, "%-15s\t%-3s\t%-32s\t%-3s\t%-3s",
1972                      "Atlas", "Within", "Label", "Prob.", "Code");
1973             ADDTO_SARR(sar,lbuf);
1974             nfind = 0;
1975             for (iatlas=0; iatlas < atlas_list->natlases; ++iatlas){ /* iatlas */
1976                atlas = &(atlas_list->atlas[iatlas]);
1977                nfind_one = 0;
1978                for (iq=0; iq<wami->N_zone; ++iq) { /* iq */
1979                   for (il=0; il<wami->zone[iq]->N_label; ++il) { /* il */
1980                      if (is_Atlas_Named(atlas, wami->zone[iq]->atname[il])) {
1981                         SS('I');
1982                         sprintf(tmps, "%.1f", wami->zone[iq]->radius[il]);
1983                         SS('J');sprintf(lbuf, "%-15s\t%-3s\t%-32s\t%-3s\t%-3d",
1984                                     wami->zone[iq]->atname[il],
1985                                     tmps,
1986                                     Clean_Atlas_Label(wami->zone[iq]->label[il]),
1987                                     Atlas_Prob_String(wami->zone[iq]->prob[il]),
1988                                     wami->zone[iq]->code[il]);
1989                         ADDTO_SARR(sar,lbuf);
1990                         ++nfind; ++nfind_one;
1991                      }
1992                   } /* il */
1993                } /* iq */
1994 
1995             } /* iatlas */
1996 
1997          break;
1998       default:
1999          ERROR_message("Bad mode (%d).", mode);
2000          RETURN(rbuf);
2001    }
2002 
2003    /* anything ? */
2004    if (!nfind) {
2005       ADDTO_SARR(sar,"***** Not near any region stored in databases *****\n");
2006    }
2007    /*- if didn't make any label, must produce something -*/
2008 
2009    if( sar->num == 1 ){    /* shouldn't ever happen */
2010       SS('K');sprintf(lbuf,"Found %d marked but unlabeled regions???\n",nfind) ;
2011       ADDTO_SARR(sar,lbuf) ;
2012    } else if( !AFNI_noenv("AFNI_TTATLAS_CAUTION") ){
2013       if(!AFNI_wami_output_mode())
2014          ADDTO_SARR(sar,WAMI_TAIL) ;  /* cautionary tail */
2015    }
2016 
2017    /*- convert list of labels into one big multi-line string -*/
2018 
2019    for( nfind=ii=0 ; ii < sar->num ; ii++ ) nfind += strlen(sar->ar[ii]) ;
2020    rbuf = AFMALL(char, nfind + 2*sar->num + 32 ) ; rbuf[0] = '\0' ;
2021    for( ii=0 ; ii < sar->num ; ii++ ){
2022       strcat(rbuf,sar->ar[ii]) ; strcat(rbuf,"\n") ;
2023    }
2024 
2025    DESTROY_SARR(sar) ;
2026 
2027    if (LocalHead) {
2028       INFO_message("Have:\n%s\n", rbuf);
2029    }
2030 
2031    RETURN(rbuf);
2032 }
2033 #undef SS
2034 
TT_whereami_set_outmode(WAMI_SORT_MODES md)2035 void TT_whereami_set_outmode(WAMI_SORT_MODES md)
2036 {
2037 
2038    TT_whereami_mode = md;
2039    switch (md) {
2040       case TAB2_WAMI_ATLAS_SORT:
2041       case TAB2_WAMI_ZONE_SORT:
2042          lsep =  '\t';
2043          break;
2044       case TAB1_WAMI_ATLAS_SORT:
2045       case TAB1_WAMI_ZONE_SORT:
2046          lsep =  '\t';
2047          break;
2048       case CLASSIC_WAMI_ATLAS_SORT:
2049       case CLASSIC_WAMI_ZONE_SORT:
2050          lsep =  '\n';
2051          break;
2052       default:
2053          WARNING_message("Mode not supported.Using Default.");
2054          TT_whereami_mode = CLASSIC_WAMI_ATLAS_SORT;
2055          lsep =  '\n';
2056          break;
2057    }
2058 
2059    return;
2060 }
2061 
2062 
TT_whereami_default_spc_name(void)2063 char * TT_whereami_default_spc_name (void)
2064 {
2065    char *eee = getenv("AFNI_DEFAULT_STD_SPACE");
2066    if (eee) {
2067       if (strncasecmp(eee, "TLRC", 4) == 0) {
2068          return (eee);
2069       } else if (strncasecmp(eee, "MNI_ANAT", 8) == 0) {
2070          return (eee);
2071       } else if (strncasecmp(eee, "MNI", 3) == 0) {
2072          return (eee);
2073       } else {
2074 /*         WARNING_message(  "Bad value for AFNI_DEFAULT_STD_SPACE\n"
2075                            "%s is unrecognized. Assuming TLRC\n", eee);
2076 */
2077          return (eee);
2078       }
2079    } else {
2080       /* no env, return default */
2081       return("TLRC");
2082    }
2083 }
2084 
XYZ_to_AtlasCoord(float x,float y,float z,char * orcode,char * spacename,ATLAS_COORD * ac)2085 int XYZ_to_AtlasCoord(float x, float y, float z, char *orcode,
2086                               char *spacename, ATLAS_COORD *ac)
2087 {
2088    if (!ac) return(0);
2089 
2090    ac->x = x;
2091    ac->y = y;
2092    ac->z = z;
2093    if (orcode) {
2094       ac->orcode[0] = orcode[0];
2095       ac->orcode[1] = orcode[1];
2096       ac->orcode[2] = orcode[2];
2097       ac->orcode[3] = '\0';
2098    } else {
2099       strncpy(ac->orcode,"RAI",3);
2100    }
2101 
2102    if (spacename && spacename[0] != '\0') {
2103       set_Coord_Space_Name(ac, spacename);
2104    } else {
2105       set_Coord_Space_Name(ac, "TT_Daemon");
2106    }
2107 
2108    return(1);
2109 }
2110 
2111 static int atlas_list_version = 2;  /* 1 --> Old style, hard coded atlases and
2112                                              transforms.
2113                                        2 --> Use .niml files defining atlases
2114                                              and transforms */
2115 static int whereami_version = 2;    /* 1 --> Uses mid vintage whereami_9yards
2116                                              function.
2117                                        2 --> Uses whereami_3rdbase
2118                                     */
2119 
set_TT_whereami_version(int atlas_version,int wami_version)2120 void set_TT_whereami_version(int atlas_version, int wami_version) {
2121    if (atlas_version > 0 && wami_version > 0) {
2122       atlas_list_version = atlas_version;
2123       whereami_version = wami_version;
2124    } else {
2125       char *ff = find_atlas_niml_file("AFNI_atlas_spaces.niml",0);
2126       if (ff[0] != '\0') {
2127          atlas_list_version = 2;
2128          whereami_version = 2;
2129       }
2130    }
2131 }
2132 
2133 /*! Load the atlas information from existing NIML files.
2134     Revert to old approach if none were found */
init_global_atlas_list()2135 int init_global_atlas_list () {
2136    ATLAS_LIST *atlas_alist = NULL;
2137    int  iatlas;
2138    /* this list of old atlases is missing "UNKNOWN_ATLAS", first entry
2139       so NUMBER_OF_ATLASES is one too many */
2140    AFNI_ATLAS_CODES TT_whereami_atlas_list[NUMBER_OF_ATLASES] =
2141       {  AFNI_TLRC_ATLAS, CA_EZ_N27_MPM_ATLAS, CA_EZ_N27_ML_ATLAS,
2142          CA_EZ_N27_PMAPS_ATLAS, CA_EZ_N27_LR_ATLAS, CUSTOM_ATLAS };
2143    int i;
2144    int LocalHead = wami_lh();
2145 
2146    ENTRY("init_global_atlas_list");
2147 
2148 
2149    if (global_atlas_alist) {
2150       if (wami_verb()) INFO_message("global_atlas_list initialized already");
2151       RETURN(1);
2152    }
2153 
2154    if (atlas_list_version > 1) {
2155       if (wami_verb()) INFO_message("Forming list from niml files");
2156       if (!init_global_atlas_from_niml_files()) {
2157          if (wami_verb())  INFO_message("No niml files");
2158       }
2159    } else {
2160       if (wami_verb()) {
2161          INFO_message("Forming list the old route");
2162       }
2163    }
2164 
2165    if (!global_atlas_alist) { /* try again */
2166       if (LocalHead) INFO_message("Going old route");
2167       atlas_alist = (ATLAS_LIST *) calloc(1,sizeof(ATLAS_LIST));
2168       if(!atlas_alist){
2169          ERROR_message("Could not initialize atlas list");
2170          RETURN(0);
2171       }
2172       if (LocalHead) INFO_message("Allocating atlas table");
2173 
2174       /* accounting for missing UNKNOWN atlas by subtracting one */
2175       atlas_alist->natlases = NUMBER_OF_ATLASES-1;
2176       atlas_alist->atlas = (ATLAS *) calloc(
2177                               atlas_alist->natlases, sizeof(ATLAS));
2178       for(i=0;i<atlas_alist->natlases;i++) {
2179          atlas_alist->atlas[i].dset_name = NULL;
2180          atlas_alist->atlas[i].space = NULL;
2181          atlas_alist->atlas[i].name = NULL;
2182          atlas_alist->atlas[i].comment = NULL;
2183          atlas_alist->atlas[i].description = NULL;
2184          atlas_alist->atlas[i].orient = NULL;
2185          atlas_alist->atlas[i].atlas_type = NULL;
2186          atlas_alist->atlas[i].adh = NULL;
2187          atlas_alist->atlas[i].atlas_found = 0;
2188       }
2189 
2190       if (LocalHead) INFO_message("Using old way to fill atlas table");
2191       for (iatlas=0; iatlas<atlas_alist->natlases; ++iatlas) {
2192          atlas_alist->atlas[iatlas].dset_name = nifti_strdup(
2193             Atlas_Code_to_Atlas_Dset_Name(TT_whereami_atlas_list[iatlas]));
2194          atlas_alist->atlas[iatlas].name = nifti_strdup(
2195             Atlas_Code_to_Atlas_Name(TT_whereami_atlas_list[iatlas]));
2196          atlas_alist->atlas[iatlas].description = nifti_strdup(
2197             Atlas_Code_to_Atlas_Description(TT_whereami_atlas_list[iatlas]));
2198          atlas_alist->atlas[iatlas].space = nifti_strdup("TLRC");
2199          if (LocalHead) INFO_message("adding atlas %s",
2200               atlas_alist->atlas[iatlas].dset_name);
2201       }
2202       global_atlas_alist = atlas_alist;
2203    }
2204    if (!global_atlas_spaces) {
2205       ATLAS_SPACE_LIST *space_list=NULL;
2206       space_list = (ATLAS_SPACE_LIST *)calloc(1,sizeof(ATLAS_SPACE_LIST));
2207       if(!space_list){
2208          ERROR_message("Could not initialize space list");
2209          RETURN(0);
2210       }
2211       if (LocalHead) INFO_message("Using old way to fill space table");
2212       space_list->nspaces = 3;
2213       space_list->space =
2214              (ATLAS_SPACE *) calloc(space_list->nspaces, sizeof(ATLAS_SPACE));
2215       for(i=0; i<space_list->nspaces; ++i) {
2216          space_list->space[i].atlas_space = nifti_strdup(old_space_list[i]); ;
2217          space_list->space[i].generic_space = nifti_strdup(old_space_list[i]);
2218       }
2219 
2220       global_atlas_spaces = space_list;
2221    }
2222 
2223        /* drg - we don't make use of global_atlas_templates anywhere. Templates
2224           may be any dataset now. If we do eventually provide a list somewhere,
2225           we might create a list using the old defaults. Not sure about the
2226           global_atlas_xfl now. We apparently do something now to transform
2227           among old spaces. It seems both these questions ask about a situation
2228           in the future where the NIML files have been deleted or can not be
2229           found. In that case, what should be the default actions?
2230           Populating global_atlas_xfl might allow elimination of
2231           Atlas_Query_to_String, now made mostly obsolete by
2232           genx_Atlas_Query_to_String, but not worth it for now. */
2233 
2234    if (global_atlas_alist && global_atlas_spaces) RETURN(1);
2235    else RETURN(0);
2236 }
2237 
2238 /* find a NIML file somewhere
2239   search first by original path in name, then the AFNI_PLUGINPATH, then path*/
find_atlas_niml_file(char * nimlname,int niname)2240 char *find_atlas_niml_file(char * nimlname, int niname)
2241 {
2242    static char filestr[5][1024];
2243    static int icall = -1;
2244    char namebuf[1024];
2245    char *fstr, *epath;
2246 
2247    ENTRY("find_atlas_niml_file");
2248 
2249    ++icall; if (icall > 4) icall = 0;
2250    filestr[icall][0]='\0';
2251    namebuf[0] = '\0';
2252 
2253    if(wami_verb() > 1)
2254       INFO_message("trying to open %s \n",nimlname);
2255    snprintf(namebuf, 1000*sizeof(char),
2256              "%s", nimlname);
2257    if (THD_is_file(namebuf)) goto GOTIT;
2258 
2259    if(wami_verb() > 1)
2260       INFO_message("%s not found, trying different paths, if no path is set.\n"
2261                      ,nimlname);
2262 
2263    if (THD_filehaspath(nimlname)) { /* not found and have path, get out */
2264       RETURN(filestr[icall]);
2265    }
2266 
2267    /* okay that didn't work, try the AFNI plugin directory */
2268    namebuf[0]='\0';
2269 
2270 
2271    epath = get_env_atlas_path();
2272    if( epath != NULL ) {
2273       if(wami_verb() > 1)
2274          INFO_message("trying to open %s in AFNI_ATLAS_PATH or AFNI_PLUGINPATH directory %s\n",
2275               nimlname, epath);
2276       fstr = THD_find_regular_file(nimlname, epath);
2277       if(fstr) {
2278          if(wami_verb() > 1)
2279             INFO_message("found %s in %s", nimlname, fstr);
2280          snprintf(namebuf, 1000*sizeof(char), "%s", fstr);
2281          if (THD_is_file(namebuf)) goto GOTIT;
2282          if(wami_verb() > 1)
2283             INFO_message("failed to open %s as %s\n",
2284                          nimlname, namebuf);
2285       }
2286    }
2287 
2288    /* still can't find it. Maybe it's in one of the path directories */
2289    namebuf[0]='\0';
2290    epath = getenv("PATH") ;
2291    if( epath == NULL ) RETURN(filestr[icall]) ;  /* bad-who has no path?*/
2292    if(wami_verb() > 1)
2293       INFO_message("trying to open %s in path as regular file\n  %s\n",
2294                      nimlname, epath);
2295 
2296    fstr = THD_find_regular_file(nimlname, epath);
2297    if(fstr) {
2298       if(wami_verb() > 1)
2299          INFO_message("found %s in %s", nimlname, fstr);
2300       snprintf(namebuf, 1000*sizeof(char), "%s", fstr);
2301       if (THD_is_file(namebuf)) goto GOTIT;
2302       if(wami_verb() > 1)
2303          INFO_message("failed to open %s as %s\n",
2304                       nimlname, namebuf);
2305    }
2306 
2307    RETURN(filestr[icall]);
2308 
2309    GOTIT:
2310    if (niname) {
2311       snprintf(filestr[icall], 1000*sizeof(char),
2312                "file:%s", namebuf);
2313    } else {
2314       snprintf(filestr[icall], 1000*sizeof(char),
2315                "%s", namebuf);
2316    }
2317 
2318    RETURN(filestr[icall]);
2319 }
2320 
2321 /* read various NIML files for atlas information*/
init_global_atlas_from_niml_files()2322 int init_global_atlas_from_niml_files()
2323 {
2324    char *space_niml_file;
2325    int valid_space_niml;
2326    char *ept = NULL;
2327 
2328    if(wami_verb() > 1)
2329       INFO_message("opening AFNI_atlas_spaces.niml");
2330 
2331    space_niml_file = find_atlas_niml_file("AFNI_atlas_spaces.niml", 0);
2332 
2333    if(space_niml_file[0]=='\0'){
2334       if (wami_verb())
2335          WARNING_message("Could not open global AFNI_atlas_spaces.niml\n");
2336       return(0);
2337    }
2338    if(wami_verb() > 1)
2339       INFO_message("\nInitializing structures\n");
2340    if(!init_space_structs(&global_atlas_xfl, &global_atlas_alist,
2341                           &global_atlas_spaces, &global_atlas_templates)) {
2342       ERROR_message("Could not initialize structures for template spaces");
2343       return(0);
2344    }
2345 
2346    /* read atlas info from global atlas file */
2347    if(wami_verb() > 1)
2348       INFO_message("\nReading space niml file\n");
2349    valid_space_niml = read_space_niml_file(space_niml_file, global_atlas_xfl,
2350           global_atlas_alist, global_atlas_spaces, global_atlas_templates, NULL);
2351 
2352    ept = my_getenv("AFNI_SUPP_ATLAS");
2353    if( ept ) {
2354       if(wami_verb() > 1)
2355          INFO_message("opening supplemental atlases in %s", ept);
2356       space_niml_file = find_atlas_niml_file(ept, 0);
2357       if(space_niml_file[0]=='\0'){
2358             WARNING_message("Could not open supplemental atlas niml file %s\n",
2359                            ept);
2360       } else {
2361          /* read atlas info from supplemental atlas file */
2362          /*  adding to existing structures */
2363          valid_space_niml = read_space_niml_file(
2364                 space_niml_file, global_atlas_xfl,
2365                 global_atlas_alist, global_atlas_spaces, global_atlas_templates,
2366                 NULL);
2367       }
2368    }
2369 
2370    ept = THD_custom_atlas_file(NULL);
2371    if (ept[0] != '\0') {
2372       if (!session_atlas_name_list) INIT_SARR(session_atlas_name_list);
2373       if(wami_verb() > 1)
2374          INFO_message("opening CustomAtlases.niml for custom group atlases");
2375       space_niml_file = find_atlas_niml_file(ept, 0);
2376       if(space_niml_file[0]=='\0'){
2377          WARNING_message(
2378             "Bad local atlas niml file %s\n", ept);
2379       } else {
2380          /* read atlas info from local atlas file */
2381          /*  adding to existing structures */
2382          valid_space_niml =
2383             read_space_niml_file(space_niml_file, global_atlas_xfl,
2384                 global_atlas_alist, global_atlas_spaces, global_atlas_templates,
2385                 session_atlas_name_list);
2386       }
2387    }
2388 
2389    /* read default session atlas */
2390    if (THD_is_file("SessionAtlases.niml")) {
2391       if (!session_atlas_name_list) INIT_SARR(session_atlas_name_list);
2392       if(wami_verb() > 1)
2393          INFO_message("opening SessionAtlases.niml for session atlases");
2394       space_niml_file = find_atlas_niml_file("SessionAtlases.niml",0);
2395       if(space_niml_file[0]=='\0'){
2396          WARNING_message(
2397             "Bad local atlas niml file SessionAtlases.niml\n");
2398       } else {
2399          /* read atlas info from local atlas file */
2400          /*  adding to existing structures */
2401          valid_space_niml = read_space_niml_file(
2402                 space_niml_file, global_atlas_xfl,
2403                 global_atlas_alist, global_atlas_spaces, global_atlas_templates,
2404                 session_atlas_name_list);
2405       }
2406    }
2407 
2408    /* read atlas info from local atlas file */
2409    ept = my_getenv("AFNI_LOCAL_ATLAS");
2410    if( ept ) {
2411       if(wami_verb() > 1)
2412          INFO_message("opening AFNI_local_atlas_space.niml");
2413       space_niml_file = find_atlas_niml_file(ept,0);
2414       if(space_niml_file[0]=='\0'){
2415          ERROR_message("Could not open supplemental atlas niml file %s\n",
2416                         ept);
2417       } else {
2418          /* read atlas info from local atlas file */
2419          /*  adding to existing structures */
2420          valid_space_niml = read_space_niml_file(
2421                 space_niml_file, global_atlas_xfl,
2422                 global_atlas_alist, global_atlas_spaces, global_atlas_templates,
2423                 NULL);
2424       }
2425    }
2426 
2427    if(!valid_space_niml) printf("no valid niml files found to define atlases and spaces\n");
2428    /* set up the neighborhood for spaces */
2429    /*  how are the spaces related to each other */
2430    if(wami_verb() > 1)
2431       INFO_message("\nmaking space neighborhoods\n");
2432    if(make_space_neighborhood(global_atlas_spaces, global_atlas_xfl)!=0) {
2433       return(0);
2434    }
2435 
2436    /* all ok */
2437    return(1);
2438 }
2439 
2440 /* free all the static lists */
free_global_atlas_structs()2441 void free_global_atlas_structs()
2442 {
2443    free_xform_list(global_atlas_xfl);
2444    free_atlas_list(global_atlas_alist);
2445    free_space_list(global_atlas_spaces);
2446    free_template_list(global_atlas_templates);
2447 }
2448 
2449 
TT_whereami(float xx,float yy,float zz,char * space_name,void * alist)2450 char * TT_whereami(  float xx , float yy , float zz,
2451                      char *space_name, void *alist)
2452 {
2453    ATLAS_COORD ac;
2454    ATLAS_QUERY *wami = NULL;
2455    char *rbuf = NULL;
2456    ATLAS_LIST *atlas_alist=(ATLAS_LIST *)alist;
2457    ATLAS_SPACE_LIST *asl=get_G_space_list();
2458    int LocalHead = wami_lh();
2459 
2460    ENTRY("TT_whereami") ;
2461 
2462    /* initialize the single custom atlas entry */
2463    if(whereami_version<2)
2464       init_custom_atlas();
2465 
2466    if (!atlas_alist) { /* get global */
2467       atlas_alist = get_G_atlas_list();
2468    }
2469    if (!atlas_alist) {
2470       ERROR_message("No list to work with");
2471       RETURN(rbuf) ;
2472    }
2473 
2474    if (!asl){
2475       ERROR_message("No spaces defined");
2476       RETURN(rbuf) ;
2477    }
2478 
2479    if (!is_known_coord_space(space_name)) {
2480       ERROR_message("Unknown space_name %s", space_name);
2481       RETURN(rbuf) ;
2482    }
2483 
2484    /* build coord structure */
2485    if (!XYZ_to_AtlasCoord( xx, yy, zz, "RAI",
2486                            space_name, &ac)) {
2487       ERROR_message("Failed to get AtlasCoord");
2488       RETURN(rbuf);
2489    }
2490 
2491    /* nothing found from web atlas yet */
2492    set_wami_web_found(0);
2493 
2494    if(LocalHead) {
2495       INFO_message("current list of atlases:");
2496       print_atlas_list(atlas_alist);
2497       print_atlas_coord(ac);
2498    }
2499 
2500 /* ***tbd whereami_9yards converts coordinates among spaces and
2501       looks up coordinates through radius among atlases in atlas list */
2502 /* will need to change this to use new atlas_list from NIML database */
2503 /* modify whereami_9yards to use xform list */
2504    if (whereami_version == 1) {
2505       if (wami_verb() > 1) INFO_message("whereami_9yards");
2506       if (!whereami_9yards( ac, &wami, atlas_alist)) {
2507          INFO_message("whereami_9yards returned error");
2508       }
2509    } else {
2510       if (wami_verb() > 1) INFO_message("whereami_3rdBase");
2511       if (!whereami_3rdBase( ac, &wami, NULL, atlas_alist)) {
2512          INFO_message("whereami_3rdBase returned error");
2513       }
2514    }
2515 
2516    if (!wami) {
2517       if(!get_wami_web_found())
2518          ERROR_message("No atlas regions found.");
2519       RETURN(rbuf) ;
2520    }
2521 
2522    /* Now form the string */
2523    if (atlas_list_version == 1) {
2524       if (wami_verb() > 1) INFO_message("Atlas_Query_to_String");
2525       rbuf =  Atlas_Query_to_String (wami, ac, TT_whereami_mode,
2526                                           atlas_alist);
2527    } else {
2528       if (wami_verb() > 1) INFO_message("genx_Atlas_Query_to_String");
2529       rbuf =  genx_Atlas_Query_to_String (wami, ac, TT_whereami_mode,
2530                                           atlas_alist);
2531    }
2532 
2533    /*cleanup*/
2534    if (wami)  wami = Free_Atlas_Query(wami);
2535 
2536    RETURN(rbuf) ;
2537 }
2538 
2539 #ifdef KILLTHIS /* Remove all old sections framed by #ifdef KILLTHIS
2540                   in the near future.  ZSS May 2011   */
2541 
TT_whereami_old(float xx,float yy,float zz)2542 char * TT_whereami_old( float xx , float yy , float zz ) /* ZSS */
2543 {
2544    int ii,kk , ix,jy,kz , nx,ny,nz,nxy , aa,bb,cc , ff,b2f,b4f,rff ;
2545    THD_ivec3 ijk ;
2546    byte *b2 , *b4 ;
2547    THD_string_array *sar ;
2548    char *b2lab , *b4lab ;
2549    char lbuf[256] , *rbuf ;
2550    int nfind, *b2_find=NULL, *b4_find=NULL, *rr_find=NULL ;
2551    THD_3dim_dataset * dset ; /* 01 Aug 2001 */
2552    ATLAS_POINT_LIST *apl=NULL;
2553 
2554 ENTRY("TT_whereami_old") ;
2555 
2556    apl = atlas_point_list("TT_Daemon");
2557 
2558    if (MAX_FIND < 0) {
2559       Set_Whereami_Max_Find(MAX_FIND);
2560    }
2561    b2_find = (int*)calloc(MAX_FIND, sizeof(int));
2562    b4_find = (int*)calloc(MAX_FIND, sizeof(int));
2563    rr_find = (int*)calloc(MAX_FIND, sizeof(int));
2564    if (!b2_find || !b4_find || !rr_find) {
2565       ERROR_message( "Jiminy Crickets!\n"
2566                      "Failed to allocate for finds!\nMAX_FIND = %d\n", MAX_FIND);
2567       RETURN(NULL);
2568    }
2569 
2570 
2571    /*-- setup stuff: load atlas dataset, prepare search mask --*/
2572 
2573    if( dseTT_old == NULL ){
2574       ii = TT_load_atlas_old() ; if( ii == 0 ) RETURN(NULL) ;
2575    }
2576 
2577    /* 01 Aug 2001: maybe use big dataset (so don't need both in memory) */
2578 
2579    dset = (dseTT_big_old != NULL) ? dseTT_big_old : dseTT_old ;
2580 
2581 
2582    DSET_load(dset) ;
2583    b2 = DSET_BRICK_ARRAY(dset,0) ; if( b2 == NULL ) RETURN(NULL) ;
2584    b4 = DSET_BRICK_ARRAY(dset,1) ; if( b4 == NULL ) RETURN(NULL) ;
2585 
2586    if (WAMIRAD < 0.0) {
2587       WAMIRAD = Init_Whereami_Max_Rad();
2588    }
2589    if( wamiclust == NULL ){
2590       wamiclust = MCW_build_mask( 1.0,1.0,1.0 , WAMIRAD ) ;
2591       if( wamiclust == NULL ) RETURN(NULL) ;  /* should not happen! */
2592 
2593       for( ii=0 ; ii < wamiclust->num_pt ; ii++ )       /* load radius */
2594          wamiclust->mag[ii] = (int)rint(sqrt((double)(
2595                                          wamiclust->i[ii]*wamiclust->i[ii]
2596                                         +wamiclust->j[ii]*wamiclust->j[ii]
2597                                         +wamiclust->k[ii]*wamiclust->k[ii]))) ;
2598 
2599       MCW_sort_cluster( wamiclust ) ;  /* sort by radius */
2600    }
2601 
2602    /*-- find locations near the given one that are in the Atlas --*/
2603 
2604    ijk = THD_3dmm_to_3dind( dset , TEMP_FVEC3(xx,yy,zz) ) ;  /* get indexes */
2605    UNLOAD_IVEC3(ijk,ix,jy,kz) ;                               /* from coords */
2606 
2607    nx = DSET_NX(dset) ;               /* size of TT atlas dataset axes */
2608    ny = DSET_NY(dset) ;
2609    nz = DSET_NZ(dset) ; nxy = nx*ny ;
2610 
2611    nfind = 0 ;
2612 
2613    /*-- check the exact input location --*/
2614 
2615    kk = ix + jy*nx + kz*nxy ;        /* index into brick arrays */
2616    if( b2[kk] != 0 || b4[kk] != 0 ){
2617       b2_find[0] = b2[kk] ;
2618       b4_find[0] = b4[kk] ;
2619       rr_find[0] = 0      ; nfind++ ;
2620    }
2621 
2622    /*-- check locations near it --*/
2623 
2624    for( ii=0 ; ii < wamiclust->num_pt ; ii++ ){
2625 
2626       /* compute index of nearby location, skipping if outside atlas */
2627 
2628       aa = ix + wamiclust->i[ii] ; if( aa < 0 || aa >= nx ) continue ;
2629       bb = jy + wamiclust->j[ii] ; if( bb < 0 || bb >= ny ) continue ;
2630       cc = kz + wamiclust->k[ii] ; if( cc < 0 || cc >= nz ) continue ;
2631 
2632       kk  = aa + bb*nx + cc*nxy ;   /* index into bricks */
2633       b2f = b2[kk] ; b4f = b4[kk] ; /* TT structures markers there */
2634 
2635       if( b2f == 0 && b4f == 0 )                            continue ;
2636 
2637       for( ff=0 ; ff < nfind ; ff++ ){       /* cast out         */
2638          if( b2f == b2_find[ff] ) b2f = 0 ;  /* duplicate labels */
2639          if( b4f == b4_find[ff] ) b4f = 0 ;  /* we already found */
2640       }
2641       if( b2f == 0 && b4f == 0 )                            continue ;
2642 
2643       b2_find[nfind] = b2f ;  /* save what we found */
2644       b4_find[nfind] = b4f ;
2645       rr_find[nfind] = (int) wamiclust->mag[ii] ;
2646       nfind++ ;
2647 
2648       if( nfind == MAX_FIND ) break ;  /* don't find TOO much */
2649    }
2650 
2651    /*-- assemble output string(s) --*/
2652 
2653    if( nfind == 0 ){
2654       char xlab[24], ylab[24] , zlab[24] ;
2655       THD_fvec3 tv , mv ;
2656       float mx,my,mz ;
2657       char mxlab[24], mylab[24] , mzlab[24] ;
2658 
2659       sprintf(xlab,"%4.0f mm [%c]",-xx,(xx<0.0)?'R':'L') ;
2660       sprintf(ylab,"%4.0f mm [%c]",-yy,(yy<0.0)?'A':'P') ;
2661       sprintf(zlab,"%4.0f mm [%c]", zz,(zz<0.0)?'I':'S') ;
2662 
2663       LOAD_FVEC3(tv,xx,yy,zz);
2664       mv = THD_tta_to_mni(tv); UNLOAD_FVEC3(mv,mx,my,mz);
2665       sprintf(mxlab,"%4.0f mm [%c]",mx,(mx>=0.0)?'R':'L') ;
2666       sprintf(mylab,"%4.0f mm [%c]",my,(my>=0.0)?'A':'P') ;
2667       sprintf(mzlab,"%4.0f mm [%c]",mz,(mz< 0.0)?'I':'S') ;
2668 
2669       rbuf = AFMALL(char, 500) ;
2670       sprintf(rbuf,"%s\n"
2671                    "Focus point=%s,%s,%s {T-T Atlas}\n"
2672                    "           =%s,%s,%s {MNI Brain}\n"
2673                    "\n"
2674                    "***** Not near any region stored in database *****\n" ,
2675               WAMI_HEAD , xlab,ylab,zlab , mxlab,mylab,mzlab ) ;
2676       RETURN(rbuf) ;
2677    }
2678 
2679    /*-- bubble-sort what we found, by radius --*/
2680 
2681    if( nfind > 1 ){  /* don't have to sort only 1 result */
2682      int swap, tmp ;
2683      do{
2684         swap=0 ;
2685         for( ii=1 ; ii < nfind ; ii++ ){
2686            if( rr_find[ii-1] > rr_find[ii] ){
2687              tmp = rr_find[ii-1]; rr_find[ii-1] = rr_find[ii]; rr_find[ii] = tmp;
2688              tmp = b2_find[ii-1]; b2_find[ii-1] = b2_find[ii]; b2_find[ii] = tmp;
2689              tmp = b4_find[ii-1]; b4_find[ii-1] = b4_find[ii]; b4_find[ii] = tmp;
2690              swap++ ;
2691            }
2692         }
2693      } while(swap) ;
2694    }
2695 
2696    /*-- find anatomical label for each found marker, make result string --*/
2697 
2698    INIT_SARR(sar) ; ADDTO_SARR(sar,WAMI_HEAD) ;
2699 
2700    /* 04 Apr 2002: print coordinates (LPI) as well (the HH-PB addition) */
2701 
2702    { char lbuf[128], xlab[24], ylab[24] , zlab[24] ;
2703      sprintf(xlab,"%4.0f mm [%c]",-xx,(xx<0.0)?'R':'L') ;
2704      sprintf(ylab,"%4.0f mm [%c]",-yy,(yy<0.0)?'A':'P') ;
2705      sprintf(zlab,"%4.0f mm [%c]", zz,(zz<0.0)?'I':'S') ;
2706      sprintf(lbuf,"Focus point=%s,%s,%s {T-T Atlas}",xlab,ylab,zlab) ;
2707      ADDTO_SARR(sar,lbuf) ;
2708    }
2709 
2710    /* 29 Apr 2002: print MNI coords as well */
2711 
2712    { THD_fvec3 tv , mv ;
2713      float mx,my,mz ;
2714      char mxlab[24], mylab[24] , mzlab[24] , lbuf[128] ;
2715      LOAD_FVEC3(tv,xx,yy,zz);
2716      mv = THD_tta_to_mni(tv); UNLOAD_FVEC3(mv,mx,my,mz);
2717      sprintf(mxlab,"%4.0f mm [%c]",mx,(mx>=0.0)?'R':'L') ;
2718      sprintf(mylab,"%4.0f mm [%c]",my,(my>=0.0)?'A':'P') ;
2719      sprintf(mzlab,"%4.0f mm [%c]",mz,(mz< 0.0)?'I':'S') ;
2720      sprintf(lbuf,"Focus point=%s,%s,%s {MNI Brain}\n",mxlab,mylab,mzlab) ;
2721      ADDTO_SARR(sar,lbuf) ;
2722    }
2723 
2724    rff = -1 ;  /* rff = radius of last found label */
2725 
2726    for( ff=0 ; ff < nfind ; ff++ ){
2727       b2f = b2_find[ff] ; b4f = b4_find[ff] ; b2lab = NULL ; b4lab = NULL ;
2728 
2729       if( b2f != 0 ){                               /* find label     */
2730          for( ii=0 ; ii < apl->n_points ; ii++ )        /* in AFNI's list */
2731             if( b2f == apl->at_point[ii].tdval ) break ;
2732          if( ii < apl->n_points )                       /* always true? */
2733             b2lab = apl->at_point[ii].name ;
2734 
2735          if( b2lab != NULL && xx < 0 && strstr(b2lab,"Left") != NULL ) /* maybe is Right */
2736             b2lab = apl->at_point[ii+1].name ;
2737       }
2738 
2739       if( b4f != 0 ){
2740          for( ii=0 ; ii < apl->n_points ; ii++ )
2741             if( b4f == apl->at_point[ii].tdval ) break ;
2742          if( ii < apl->n_points )
2743             b4lab = apl->at_point[ii].name ;
2744          if( b4lab != NULL && xx < 0 && strstr(b4lab,"Left") != NULL )
2745             b4lab = apl->at_point[ii+1].name ;
2746       }
2747 
2748       if( b2lab == NULL && b4lab == NULL ) continue ;  /* no labels? */
2749 
2750       /* make output label into lbuf */
2751 
2752       lbuf[0] = '\0' ;
2753       if( b2lab != NULL ){
2754          if( rr_find[ff] != rff ){
2755             if( rr_find[ff] > 0 )
2756               sprintf( lbuf , "Within %d mm: %s" , rr_find[ff] , b2lab ) ;
2757             else
2758               sprintf( lbuf , "Focus point: %s" , b2lab ) ;
2759          } else {
2760             sprintf( lbuf , "             %s" , b2lab ) ;
2761          }
2762 
2763          for( kk=strlen(lbuf)-1 ; kk > 0 && lbuf[kk] == '.' ; kk-- )
2764             lbuf[kk] = '\0' ;                  /* trim trailing .'s */
2765       }
2766 
2767       if( b4lab != NULL ){
2768          kk = strlen(lbuf) ;
2769          if( kk > 0 ){
2770             sprintf( lbuf+kk , " -AND- %s" , b4lab ) ;
2771          } else if( rr_find[ff] != rff ){
2772             if( rr_find[ff] > 0 )
2773               sprintf( lbuf , "Within %d mm: %s" , rr_find[ff] , b4lab ) ;
2774             else
2775               sprintf( lbuf , "Focus point: %s" , b4lab ) ;
2776          } else {
2777             sprintf( lbuf , "             %s" , b4lab ) ;
2778          }
2779 
2780          for( kk=strlen(lbuf)-1 ; kk > 0 && lbuf[kk] == '.' ; kk-- )
2781             lbuf[kk] = '\0' ;
2782       }
2783 
2784       ADDTO_SARR(sar,lbuf) ;  /* make a list of labels */
2785 
2786       rff = rr_find[ff] ;  /* save for next time around */
2787    }
2788 
2789    /*- if didn't make any label, must produce something -*/
2790 
2791    if( sar->num == 1 ){    /* shouldn't ever happen */
2792       sprintf(lbuf,"Found %d marked but unlabeled regions???\n",nfind) ;
2793       ADDTO_SARR(sar,lbuf) ;
2794    } else if( !AFNI_noenv("AFNI_TTATLAS_CAUTION") ){
2795       if (!AFNI_wami_output_mode())
2796          ADDTO_SARR(sar,WAMI_TAIL) ;  /* cautionary tail */
2797    }
2798 
2799    /*- convert list of labels into one big multi-line string -*/
2800 
2801    for( nfind=ii=0 ; ii < sar->num ; ii++ ) nfind += strlen(sar->ar[ii]) ;
2802    rbuf = AFMALL(char, nfind + 2*sar->num + 32 ) ; rbuf[0] = '\0' ;
2803    for( ii=0 ; ii < sar->num ; ii++ ){
2804       strcat(rbuf,sar->ar[ii]) ; strcat(rbuf,"\n") ;
2805    }
2806 
2807    free(b2_find); b2_find = NULL; free(b4_find); b4_find = NULL; free(rr_find); rr_find = NULL;
2808 
2809    DESTROY_SARR(sar) ; RETURN(rbuf) ;
2810 }
2811 
2812 #endif
2813 
2814 /* Begin ZSS: Additions for Eickhoff and Zilles Cytoarchitectonic maps */
2815 
2816 
2817 
2818 /*!
2819     l left
2820     u unknown
2821     r right
2822 */
Is_Side_Label(char * str,char * opt)2823 char Is_Side_Label(char *str, char *opt)
2824 {
2825    int k, nc;
2826    char *strd=NULL;
2827    ENTRY("atlas_label_side");
2828 
2829    if (!str) RETURN('u');
2830 
2831    strd = strdup(str);
2832    nc = strlen(strd);
2833    for (k=0; k<nc; ++k) strd[k] = TO_LOWER(strd[k]);
2834 
2835    if (strncmp(strd,"left", 4) == 0) RETURN('l');
2836    else if (strncmp(strd,"right", 5) == 0) RETURN('r');
2837 
2838    free(strd); strd = NULL;
2839    RETURN('u');
2840 }
2841 
2842 /* inverse sort ints */
z_idqsort(int * x,int nx)2843 int *z_idqsort (int *x , int nx )
2844 {/*z_idqsort*/
2845 /*   static char FuncName[]={"z_idqsort"};*/
2846    int *I, k;
2847    Z_QSORT_INT *Z_Q_fStrct;
2848 
2849    ENTRY("z_idqsort");
2850 
2851    /* allocate for the structure */
2852    Z_Q_fStrct = (Z_QSORT_INT *) calloc(nx, sizeof (Z_QSORT_INT));
2853    I = (int *) calloc (nx, sizeof(int));
2854 
2855    if (!Z_Q_fStrct || !I)
2856       {
2857          ERROR_message("Allocation problem");
2858          RETURN (NULL);
2859       }
2860 
2861    for (k=0; k < nx; ++k) /* copy the data into a structure */
2862       {
2863          Z_Q_fStrct[k].x = x[k];
2864          Z_Q_fStrct[k].Index = k;
2865       }
2866 
2867    /* sort the structure by it's field value */
2868    qsort(Z_Q_fStrct, nx, sizeof(Z_QSORT_INT), (int(*) (const void *, const void *)) compare_Z_IQSORT_INT);
2869 
2870    /* recover the index table */
2871    for (k=0; k < nx; ++k) /* copy the data into a structure */
2872       {
2873          x[k] = Z_Q_fStrct[k].x;
2874          I[k] = Z_Q_fStrct[k].Index;
2875       }
2876 
2877    /* free the structure */
2878    free(Z_Q_fStrct);
2879 
2880    /* return */
2881    RETURN (I);
2882 
2883 
2884 }/*z_idqsort*/
2885 
2886 /* sort ints */
z_dqsort(int * x,int nx)2887 int *z_dqsort (int *x , int nx )
2888 {/*z_dqsort*/
2889    int *I, k;
2890    Z_QSORT_INT *Z_Q_fStrct;
2891 
2892    ENTRY("z_idqsort");
2893 
2894    /* allocate for the structure */
2895    Z_Q_fStrct = (Z_QSORT_INT *) calloc(nx, sizeof (Z_QSORT_INT));
2896    I = (int *) calloc (nx, sizeof(int));
2897 
2898    if (!Z_Q_fStrct || !I)
2899       {
2900          ERROR_message("Allocation problem");
2901          RETURN (NULL);
2902       }
2903 
2904    for (k=0; k < nx; ++k) /* copy the data into a structure */
2905       {
2906          Z_Q_fStrct[k].x = x[k];
2907          Z_Q_fStrct[k].Index = k;
2908       }
2909 
2910    /* sort the structure by it's field value */
2911    qsort(Z_Q_fStrct, nx, sizeof(Z_QSORT_INT),
2912          (int(*) (const void *, const void *)) compare_Z_QSORT_INT);
2913 
2914    /* recover the index table */
2915    for (k=0; k < nx; ++k) /* copy the data into a structure */
2916       {
2917          x[k] = Z_Q_fStrct[k].x;
2918          I[k] = Z_Q_fStrct[k].Index;
2919       }
2920 
2921    /* free the structure */
2922    free(Z_Q_fStrct);
2923 
2924    /* return */
2925    RETURN (I);
2926 }/*z_dqsort*/
2927 
2928 /*
2929   give a shuffled series between bot and top inclusive
2930 
2931 */
z_rand_order(int bot,int top,long int seed)2932 int *z_rand_order(int bot, int top, long int seed) {
2933    int i, *s=NULL, n;
2934    float *num=NULL;
2935 
2936    ENTRY("z_rand_order");
2937    if (!seed) seed = (long)time(NULL)+(long)getpid();
2938    srand48(seed);
2939 
2940    if (bot > top) { i = bot; bot = top; top = i; }
2941    n = top-bot+1;
2942 
2943    if (!(num = (float*)calloc(n , sizeof(float)))) {
2944       fprintf(stderr,"Failed to allocate for %d floats.\n", n);
2945       RETURN(s);
2946    }
2947    for (i=0;i<n;++i) num[i] = (float)drand48();
2948 
2949    if (!(s = z_iqsort(num, n))) {
2950       fprintf(stderr,"Failed to sort %d floats.\n", n);
2951       RETURN(s);
2952    }
2953    free(num); num = NULL;
2954 
2955    /* offset numbers to get to bot */
2956    for (i=0;i<n;++i) {
2957       /* fprintf(stderr,"s[%d]=%d (bot=%d)\n", i, s[i], bot); */
2958       s[i] += bot;
2959    }
2960    RETURN(s);
2961 }
2962 
2963 /* inverse sort strings */
z_istrqsort(char ** x,int nx)2964 int *z_istrqsort (char **x , int nx )
2965 {
2966    int *I, k;
2967    Z_QSORT_STRING *Z_Q_sStrct;
2968 
2969    ENTRY("z_istrqsort");
2970 
2971    /* allocate for the structure */
2972    Z_Q_sStrct = (Z_QSORT_STRING *) calloc(nx, sizeof (Z_QSORT_STRING));
2973    I = (int *) calloc (nx, sizeof(int));
2974 
2975    if (!Z_Q_sStrct || !I)
2976       {
2977          ERROR_message("Allocation problem");
2978          RETURN (NULL);
2979       }
2980 
2981    for (k=0; k < nx; ++k) /* copy the data into a structure */
2982       {
2983          Z_Q_sStrct[k].x = x[k];
2984          Z_Q_sStrct[k].Index = k;
2985       }
2986 
2987    /* sort the structure by it's field value */
2988    qsort(Z_Q_sStrct, nx, sizeof(Z_QSORT_STRING),
2989          (int(*) (const void *, const void *)) compare_Z_IQSORT_STRING);
2990 
2991    /* recover the index table */
2992    for (k=0; k < nx; ++k) /* copy the data into a structure */
2993       {
2994          x[k] = Z_Q_sStrct[k].x;
2995          I[k] = Z_Q_sStrct[k].Index;
2996       }
2997 
2998    /* free the structure */
2999    free(Z_Q_sStrct);
3000 
3001    /* return */
3002    RETURN (I);
3003 }
3004 
qmode_int(int * iv,int ni)3005 int qmode_int(int *iv, int ni) {
3006    int mod, modcnt=0, cnt = 0, cur, i;
3007    if (!iv || !ni) return(0);
3008    qsort_int(ni, iv);
3009    mod = cur = iv[0]; cnt = modcnt = 1;
3010    for (i=1; i<ni; ++i) {
3011       if (iv[i] == cur) {
3012          ++cnt;
3013       } else {
3014          if (cnt > modcnt) {
3015             /* fprintf(stderr,"Got: %d of %d, a winner; next up:%d\n",
3016                      cnt, cur, iv[i]); */
3017             modcnt = cnt;
3018             mod = cur;
3019          } else {
3020             /* fprintf(stderr,"Got: %d of %d, a looser; next up:%d\n",
3021                      cnt, cur, iv[i]); */
3022          }
3023          cur = iv[i]; cnt = 1;
3024       }
3025    }
3026    if (cnt > modcnt) {
3027       /* fprintf(stderr,"Got: %d of %d, a winner; nothing left\n",
3028                      cnt, cur); */
3029       modcnt = cnt;
3030       mod = cur;
3031    } else {
3032       /* fprintf(stderr,"Got: %d of %d, a looser; nothing left\n",
3033                      cnt, cur); */
3034    }
3035 
3036    return(mod);
3037 }
3038 
3039 /* inverse sort floats */
z_iqsort(float * x,int nx)3040 int *z_iqsort (float *x , int nx )
3041 {/*z_iqsort*/
3042    int *I, k;
3043    Z_QSORT_FLOAT *Z_Q_fStrct;
3044 
3045    ENTRY("z_iqsort");
3046 
3047    /* allocate for the structure */
3048    Z_Q_fStrct = (Z_QSORT_FLOAT *) calloc(nx, sizeof (Z_QSORT_FLOAT));
3049    I = (int *) calloc (nx, sizeof(int));
3050 
3051    if (!Z_Q_fStrct || !I)
3052       {
3053          ERROR_message("Allocation problem");
3054          RETURN (NULL);
3055       }
3056 
3057    for (k=0; k < nx; ++k) /* copy the data into a structure */
3058       {
3059          Z_Q_fStrct[k].x = x[k];
3060          Z_Q_fStrct[k].Index = k;
3061       }
3062 
3063    /* sort the structure by it's field value */
3064    qsort(Z_Q_fStrct, nx, sizeof(Z_QSORT_FLOAT),
3065          (int(*) (const void *, const void *)) compare_Z_IQSORT_FLOAT);
3066 
3067    /* recover the index table */
3068    for (k=0; k < nx; ++k) /* copy the data into a structure */
3069       {
3070          x[k] = Z_Q_fStrct[k].x;
3071          I[k] = Z_Q_fStrct[k].Index;
3072       }
3073 
3074    /* free the structure */
3075    free(Z_Q_fStrct);
3076 
3077    /* return */
3078    RETURN (I);
3079 
3080 
3081 }/*z_iqsort*/
3082 
3083 /* inverse sort doubles */
z_idoubleqsort(double * x,int nx)3084 int *z_idoubleqsort (double *x , int nx )
3085 {/*z_idoubleqsort*/
3086    static char FuncName[]={"z_idoubleqsort"};
3087    int *I, k;
3088    Z_QSORT_DOUBLE *Z_Q_doubleStrct;
3089 
3090    ENTRY("z_idoubleqsort");
3091 
3092    /* allocate for the structure */
3093    Z_Q_doubleStrct = (Z_QSORT_DOUBLE *) calloc(nx, sizeof (Z_QSORT_DOUBLE));
3094    I = (int *) calloc (nx, sizeof(int));
3095 
3096    if (!Z_Q_doubleStrct || !I)
3097       {
3098          ERROR_message("Error %s: Allocation problem", FuncName);
3099          RETURN (NULL);
3100       }
3101 
3102    for (k=0; k < nx; ++k) /* copy the data into a structure */
3103       {
3104          Z_Q_doubleStrct[k].x = x[k];
3105          Z_Q_doubleStrct[k].Index = k;
3106       }
3107 
3108    /* sort the structure by it's field value */
3109    qsort(Z_Q_doubleStrct, nx, sizeof(Z_QSORT_DOUBLE),
3110          (int(*) (const void *, const void *)) compare_Z_IQSORT_DOUBLE);
3111 
3112    /* recover the index table */
3113    for (k=0; k < nx; ++k) /* copy the data into a structure */
3114       {
3115          x[k] = Z_Q_doubleStrct[k].x;
3116          I[k] = Z_Q_doubleStrct[k].Index;
3117       }
3118 
3119    /* free the structure */
3120    free(Z_Q_doubleStrct);
3121 
3122    /* return */
3123    RETURN (I);
3124 }/*z_idoubleqsort*/
3125 
3126 /* return the unique values in y
3127    y : Vector of values
3128    ysz: Number of elements in y
3129    kunq: (int *) pointer to number of unique values
3130    Sorted: (1 means values in y are sorted)
3131 */
UniqueInt(int * y,int ysz,int * kunq,int Sorted)3132 int * UniqueInt (int *y, int ysz, int *kunq, int Sorted )
3133 {/*UniqueInt*/
3134    int  *xunq, *x;
3135    int k;
3136    static char FuncName[]={"UniqueInt"};
3137 
3138    ENTRY("UniqueInt");
3139    *kunq = 0;
3140 
3141    if (!ysz) {
3142       RETURN(NULL);
3143    }
3144    if (!Sorted)
3145     {/* must sort y , put in a new location so that y is not disturbed*/
3146       x = (int *)calloc(ysz, sizeof(int));
3147       if (!x)
3148          {
3149             fprintf (stderr,"Error %s: Failed to allocate for x.", FuncName);
3150             RETURN (NULL);
3151          }
3152       for (k=0; k < ysz; ++k)
3153          x[k] = y[k];
3154       qsort(x,ysz,sizeof(int),
3155             (int(*) (const void *, const void *)) compare_int);
3156    }
3157    else
3158       x = y;
3159 
3160    xunq = (int *) calloc(ysz,sizeof(int));
3161    if (xunq == NULL)
3162     {
3163       fprintf (stderr,"Error %s: Could not allocate memory", FuncName);
3164       RETURN (NULL);
3165    }
3166 
3167    *kunq = 0;
3168    xunq[0] = x[0];
3169    for (k=1;k<ysz;++k)
3170     {
3171       if ((x[k] != x[k - 1]))
3172          {
3173             ++*kunq;
3174             xunq[*kunq] = x[k];
3175          }
3176    }
3177    ++*kunq;
3178 
3179 
3180    /* get rid of extra space allocated */
3181    xunq = (int *) realloc(xunq, *kunq*sizeof(int));
3182 
3183    if (!Sorted)
3184       free (x);
3185 
3186    RETURN (xunq);
3187 }/*UniqueInt*/
3188 
3189 /* return the unique values in y
3190    y : Vector of values
3191    ysz: Number of elements in y
3192    kunq: (int *) pointer to number of unique values
3193    Sorted: (1 means values in y are sorted)
3194 */
UniqueShort(short * y,int ysz,int * kunq,int Sorted)3195 short * UniqueShort (short *y, int ysz, int *kunq, int Sorted )
3196 {/*UniqueShort*/
3197    short  *xunq, *x;
3198    int k;
3199    static char FuncName[]={"UniqueShort"};
3200 
3201    ENTRY("UniqueShort");
3202    *kunq = 0;
3203 
3204    if (!ysz) {
3205       RETURN(NULL);
3206    }
3207    if (!Sorted)
3208     {/* must sort y , put in a new location so that y is not disturbed*/
3209       x = (short *)calloc(ysz, sizeof(short));
3210       if (!x)
3211          {
3212             fprintf (stderr,"Error %s: Failed to allocate for x.", FuncName);
3213             RETURN (NULL);
3214          }
3215       for (k=0; k < ysz; ++k)
3216          x[k] = y[k];
3217       qsort(x,ysz,sizeof(short), (int(*) (const void *, const void *)) compare_short);
3218    }
3219    else
3220       x = y;
3221 
3222    xunq = (short *) calloc(ysz,sizeof(short));
3223    if (xunq == NULL)
3224     {
3225       fprintf (stderr,"Error %s: Could not allocate memory", FuncName);
3226       RETURN (NULL);
3227    }
3228 
3229    *kunq = 0;
3230    xunq[0] = x[0];
3231    for (k=1;k<ysz;++k)
3232     {
3233       if ((x[k] != x[k - 1]))
3234          {
3235             ++*kunq;
3236             xunq[*kunq] = x[k];
3237          }
3238    }
3239    ++*kunq;
3240 
3241 
3242    /* get rid of extra space allocated */
3243    xunq = (short *) realloc(xunq, *kunq*sizeof(short));
3244 
3245    if (!Sorted)
3246       free (x);
3247 
3248    RETURN (xunq);
3249 }/*UniqueShort*/
3250 
3251 /* return the unique values in y
3252    y : Vector of values
3253    ysz: Number of elements in y
3254    kunq: (int *) pointer to number of unique values
3255    Sorted: (1 means values in y are sorted)
3256 */
UniqueByte(byte * y,int ysz,int * kunq,int Sorted)3257 byte * UniqueByte (byte *y, int ysz, int *kunq, int Sorted )
3258 {/*UniqueByte*/
3259    byte  *xunq, *x;
3260    int k;
3261    static char FuncName[]={"UniqueByte"};
3262 
3263    ENTRY("UniqueByte");
3264    *kunq = 0;
3265 
3266    if (!ysz) {
3267       RETURN(NULL);
3268    }
3269 
3270    if (!Sorted)
3271     {/* must sort y , put in a new location so that y is not disturbed*/
3272       x = (byte *)calloc(ysz, sizeof(byte));
3273       if (!x)
3274          {
3275             fprintf (stderr,"Error %s: Failed to allocate for x.", FuncName);
3276             RETURN (NULL);
3277          }
3278       for (k=0; k < ysz; ++k)
3279          x[k] = y[k];
3280       qsort(x,ysz,sizeof(byte), (int(*) (const void *, const void *)) compare_char);
3281    }
3282    else
3283       x = y;
3284 
3285    xunq = (byte *) calloc(ysz,sizeof(byte));
3286    if (xunq == NULL)
3287     {
3288       fprintf (stderr,"Error %s: Could not allocate memory", FuncName);
3289       RETURN (NULL);
3290    }
3291 
3292    *kunq = 0;
3293    xunq[0] = x[0];
3294    for (k=1;k<ysz;++k)
3295     {
3296       if ((x[k] != x[k - 1]))
3297          {
3298             ++*kunq;
3299             xunq[*kunq] = x[k];
3300          }
3301    }
3302    ++*kunq;
3303 
3304 
3305    /* get rid of extra space allocated */
3306    xunq = (byte *) realloc(xunq, *kunq*sizeof(byte));
3307 
3308    if (!Sorted)
3309       free (x);
3310 
3311    RETURN (xunq);
3312 }/*UniqueByte*/
3313 
3314 static int AtlasShowMode = 0; /* 0 = nice mode, 1 = debug mode  */
Set_Show_Atlas_Mode(int md)3315 void Set_Show_Atlas_Mode(int md)
3316 {
3317    AtlasShowMode = md;
3318    return;
3319 }
3320 
Show_Atlas_Region(AFNI_ATLAS_REGION * aar)3321 void Show_Atlas_Region (AFNI_ATLAS_REGION *aar)
3322 {
3323    int k = 0;
3324 
3325    ENTRY("Show_Atlas_Region") ;
3326 
3327    if (!aar) {
3328       WARNING_message("NULL atlas region structure");
3329       EXRETURN;
3330    }
3331 
3332    if (AtlasShowMode) {
3333       fprintf(stdout,""
3334                      "Atlas_name: %s\n"
3335                      "Side      : %c\n"
3336                      "orig_label: %s\n"
3337                      "id        : %d\n"
3338                      "N_chnks     : %d\n",
3339                      STR_PRINT(aar->atlas_name), aar->side,
3340                      STR_PRINT(aar->orig_label), aar->id, aar->N_chnks);
3341       for (k=0; k<aar->N_chnks; ++k) {
3342          fprintf(stdout,"aar->chnks[%d] = %s\n", k, STR_PRINT(aar->chnks[k]));
3343       }
3344       fprintf(stdout,"\n");
3345    } else {
3346       /* if there is a long name and the long name isn't the same as the regular name */
3347       if((aar->longname) && (strlen(aar->longname)!=0) && (strcmp(aar->orig_label,aar->longname)))
3348          fprintf(stdout,"%c:%s:%-3d [%s]\n",
3349                      aar->side, STR_PRINT(aar->orig_label), aar->id, aar->longname);
3350       else
3351          fprintf(stdout,"%c:%s:%-3d\n",
3352                      aar->side, STR_PRINT(aar->orig_label), aar->id);
3353    }
3354 
3355    EXRETURN;
3356 }
3357 
3358 
Free_Atlas_Region(AFNI_ATLAS_REGION * aar)3359 AFNI_ATLAS_REGION * Free_Atlas_Region (AFNI_ATLAS_REGION *aar)
3360 {
3361    int k = 0;
3362 
3363    ENTRY("Free_Atlas_Region");
3364 
3365    if (!aar) {
3366       WARNING_message("NULL aar");
3367       RETURN(NULL);
3368    }
3369 
3370    if (aar->chnks) {
3371       for (k=0; k<aar->N_chnks; ++k) {
3372          if (aar->chnks[k]) free(aar->chnks[k]);
3373       }
3374       free(aar->chnks);
3375    }
3376 
3377    if (aar->orig_label) free(aar->orig_label);
3378    if (aar->atlas_name) free(aar->atlas_name);
3379    if (aar->longname) free(aar->longname);
3380    free(aar);
3381 
3382    RETURN(NULL);
3383 }
3384 
Same_Chunks(AFNI_ATLAS_REGION * aar1,AFNI_ATLAS_REGION * aar2)3385 byte Same_Chunks(AFNI_ATLAS_REGION *aar1, AFNI_ATLAS_REGION *aar2)
3386 {
3387    int i;
3388 
3389    ENTRY("Same_Chunks");
3390    if (!aar1 || !aar2) RETURN(0);
3391    if (aar1->N_chnks != aar2->N_chnks) RETURN(0);
3392    for (i=0; i<aar1->N_chnks; ++i) {
3393       if (strcmp(aar1->chnks[i], aar2->chnks[i])) RETURN(0);
3394    }
3395    RETURN(1);
3396 }
3397 
3398 /*!
3399    given a string, chunk it
3400 */
Atlas_Chunk_Label(char * lbli,int id,char * atlas_name,char * longname)3401 AFNI_ATLAS_REGION * Atlas_Chunk_Label(char *lbli, int id, char *atlas_name, char *longname)
3402 {
3403    AFNI_ATLAS_REGION *aar = NULL;
3404    char lachunk[500], sd, *lbl = NULL;
3405    int ic = 0, nc = 0, k = 0, block = 0;
3406    int LocalHead = wami_lh();
3407 
3408    ENTRY("Atlas_Chunk_Label") ;
3409    if (!lbli) {
3410       ERROR_message("NULL label");
3411       RETURN(aar) ;
3412    }
3413 
3414    nc = strlen(lbli);
3415 
3416    if (lbli[0] == '\0') {
3417       ERROR_message("Empty label");
3418       RETURN(aar) ;
3419    }
3420 
3421    lbl = strdup(lbli);
3422 
3423    aar = (AFNI_ATLAS_REGION*) calloc(1,sizeof(AFNI_ATLAS_REGION));
3424    aar->side = 'u';
3425    aar->orig_label = strdup(lbl);
3426    if(longname) aar->longname = strdup(longname);
3427    else  aar->longname = NULL;
3428    aar->atlas_name = NULL;
3429    if (atlas_name) aar->atlas_name = nifti_strdup(atlas_name); /* for clarity*/
3430    aar->id = id;
3431    aar->N_chnks = 0;
3432    aar->chnks = NULL;
3433 
3434 #if 0
3435 took out number checking and processing for D99 macaque atlas
3436 not sure why it was there in the first place!
3437    int  isnum=0;
3438    /* is this all numbers ? */
3439    isnum = 1;
3440    for (k=0; k<nc; ++k) {
3441       if (!IS_NUMBER(lbl[k])) isnum = 0;
3442    }
3443   /* it is an integer, stop the machines */
3444    if (isnum) {
3445 /* printf("atlas is all numbers %s, %d\n", lbl,aar->id);*/
3446 
3447 /*       isnum = atoi(lbl);
3448       free(lbl); lbl = NULL;
3449       if (aar->id && isnum != aar->id) {
3450          ERROR_message("Information conflict!");
3451          RETURN(Free_Atlas_Region(aar)) ;
3452       }
3453       aar->id = isnum;
3454       if (LocalHead) fprintf(stderr,"Have number (%d), will travel\n", aar->id);
3455       RETURN(aar);
3456   */
3457   }
3458 
3459    /* change any '.' surrounded by digits to a 0 */
3460    for (k=1; k<nc-1; ++k) {
3461       if (  lbl[k] == '.' &&
3462             IS_NUMBER(lbl[k+1]) &&
3463             IS_NUMBER(lbl[k-1]) ) lbl[k] = '0';
3464    }
3465 #endif
3466 
3467    ic = 0;
3468    k = 0;
3469    block = 0;
3470    while (!IS_LETTER(lbl[k]) && !IS_NUMBER(lbl[k]) &&  !IS_PERIOD(lbl[k]) && k < nc) ++k;
3471    if (IS_LETTER(lbl[k])) block = 1;
3472    else if (IS_NUMBER(lbl[k]) || IS_PERIOD(lbl[k])) block = 2;
3473    else block = 0;
3474 
3475    while (k < nc) {
3476       if (IS_LETTER(lbl[k]) && block == 1) {
3477          lachunk[ic] = TO_LOWER(lbl[k]); ++ic;
3478          ++k;
3479       } else if ((IS_NUMBER(lbl[k])||IS_PERIOD(lbl[k])) && block == 2) {
3480          lachunk[ic] = TO_LOWER(lbl[k]); ++ic;
3481          ++k;
3482       } else {
3483          lachunk[ic] = '\0'; /* seal */
3484          if (LocalHead) fprintf(stderr,"Have chunk %s, will eat...\n", lachunk);
3485          sd = '\0';
3486          if (aar->N_chnks == 0) { /* check on side */
3487             sd = Is_Side_Label(lachunk, NULL);
3488             if (LocalHead)
3489                fprintf(stderr,"Side check on %s returned %c\n", lachunk, sd);
3490             if (sd == 'l' || sd == 'r' || sd == 'b') {
3491                aar->side = sd;
3492             } else {
3493                /* unknown */
3494                sd = '\0';
3495             }
3496          }
3497          if (sd == '\0') { /* new, non left/right chunk */
3498             /* store lachunk, skip to next char or number */
3499             aar->chnks = (char **)realloc(aar->chnks,
3500                                           sizeof(char*)*(aar->N_chnks+1));
3501             aar->chnks[aar->N_chnks] = strdup(lachunk);
3502             ++ aar->N_chnks;
3503          }
3504          ic = 0; lachunk[ic] = '\0'; /* seal */
3505          while (!IS_LETTER(lbl[k]) && !IS_NUMBER(lbl[k]) && k < nc) ++k;
3506          if (IS_LETTER(lbl[k])) block = 1;
3507          else if (IS_NUMBER(lbl[k])) block = 2;
3508          else block = 0;
3509       }
3510    }
3511 
3512    /* add last chunk */
3513    if (lachunk[0] != '\0') {
3514       lachunk[ic] = '\0';
3515       /* first check on side */
3516       sd = '\0';
3517       if (aar->N_chnks == 0) { /* check on side */
3518          sd = Is_Side_Label(lachunk, NULL);
3519          if (LocalHead)
3520             fprintf(stderr,"Side check on %s returned %c\n", lachunk, sd);
3521          if (sd == 'l' || sd == 'r' || sd == 'b') {
3522             aar->side = sd;
3523          } else {
3524             /* unknown */
3525             sd = '\0';
3526          }
3527       }
3528       if (sd == '\0') { /* new, non left/right chunk */
3529          aar->chnks = (char **)realloc(aar->chnks,
3530                                        sizeof(char*)*(aar->N_chnks+1));
3531          aar->chnks[aar->N_chnks] = strdup(lachunk);
3532          ++ aar->N_chnks;
3533       }
3534       ic = 0; lachunk[ic] = '\0'; /* seal */
3535    }
3536 
3537    if (LocalHead) {
3538       fprintf(stderr,"Atlas_Chunk_Label:\n" );
3539       Show_Atlas_Region (aar);
3540    }
3541    free(lbl); lbl = NULL;
3542    RETURN(aar) ;
3543 }
3544 
Build_Atlas(char * aname,ATLAS_LIST * atlas_list)3545 AFNI_ATLAS *Build_Atlas (char *aname, ATLAS_LIST *atlas_list)
3546 {
3547    AFNI_ATLAS *aa=NULL;
3548    int k = 0;
3549    int LocalHead = wami_lh();
3550    ATLAS *atlas=NULL;
3551 
3552    ENTRY("Build_Atlas") ;
3553 
3554    /* Load the dataset */
3555    if (LocalHead) fprintf(stderr,"Building AFNI ATLAS %s\n", aname);
3556    if (!(atlas = Atlas_With_Trimming(aname, 1, atlas_list))) {
3557       ERROR_message("Failed to get %s", aname);
3558       RETURN(NULL);
3559    }
3560    /* Call this function just to force TT_Daemon to end up in BIG format*/
3561    TT_retrieve_atlas_dset(aname, 1);
3562 
3563    if (LocalHead) fprintf(stderr,"%s loaded\n", aname);
3564 
3565    aa = (AFNI_ATLAS *)calloc(1,sizeof(AFNI_ATLAS));
3566    aa->atlas_name = strdup(atlas->name);
3567    aa->N_regions = MAX_ELM(atlas->adh->apl2);
3568    aa->reg = (AFNI_ATLAS_REGION **)
3569                   calloc(aa->N_regions, sizeof(AFNI_ATLAS_REGION *));
3570    for (k=0; k<aa->N_regions; ++k) {
3571       aa->reg[k] = Atlas_Chunk_Label(atlas->adh->apl2->at_point[k].name,
3572                                      atlas->adh->apl2->at_point[k].tdval,
3573                                      Atlas_Name(atlas),
3574                                      atlas->adh->apl2->at_point[k].longname);
3575       /* Show_Atlas_Region (aa->reg[k]); */
3576    }
3577 
3578    RETURN(aa);
3579 }
3580 
Show_Atlas(AFNI_ATLAS * aa)3581 void Show_Atlas (AFNI_ATLAS *aa)
3582 {
3583    int k = 0;
3584 
3585    ENTRY("Show_Atlas");
3586 
3587    if (!aa) {
3588       WARNING_message("NULL atlas");
3589       EXRETURN;
3590    }
3591 
3592    if (AtlasShowMode) {
3593       fprintf(stdout,"\n"
3594                      "Atlas     :%s\n"
3595                      "N_regions :%d\n"
3596                      "----------- Begin regions for %s atlas-----------\n"
3597                      , STR_PRINT(aa->atlas_name), aa->N_regions, STR_PRINT(aa->atlas_name));
3598       for (k=0; k<aa->N_regions; ++k) {
3599          fprintf(stdout,"%d%s region:\n", k, COUNTER_SUFFIX(k));
3600          Show_Atlas_Region(aa->reg[k]);
3601       }
3602       fprintf(stdout,"----------- End regions for %s atlas --------------\n\n", STR_PRINT(aa->atlas_name));
3603    } else {
3604       fprintf(stdout,"\n"
3605                      "Atlas %s,      %d regions\n"
3606                      "----------- Begin regions for %s atlas-----------\n"
3607                      , STR_PRINT(aa->atlas_name), aa->N_regions, STR_PRINT(aa->atlas_name));
3608       for (k=0; k<aa->N_regions; ++k) {
3609          Show_Atlas_Region(aa->reg[k]);
3610       }
3611       fprintf(stdout,"----------- End regions for %s atlas --------------\n\n", STR_PRINT(aa->atlas_name));
3612    }
3613    EXRETURN;
3614 }
3615 
Free_Atlas(AFNI_ATLAS * aa)3616 AFNI_ATLAS *Free_Atlas(AFNI_ATLAS *aa)
3617 {
3618    int k = 0;
3619 
3620    ENTRY("Free_Atlas");
3621 
3622    if (!aa) {
3623       ERROR_message("NULL atlas");
3624       RETURN(aa);
3625    }
3626 
3627    if (aa->atlas_name) free(aa->atlas_name);
3628    for (k=0; k<aa->N_regions; ++k) {
3629       if (aa->reg[k]) Free_Atlas_Region(aa->reg[k]);
3630    }
3631    free(aa->reg);
3632    free(aa);
3633 
3634    RETURN(NULL);
3635 }
3636 static int SpeakEasy = 1;
Set_ROI_String_Decode_Verbosity(byte lvl)3637 void Set_ROI_String_Decode_Verbosity(byte lvl)
3638 {
3639    SpeakEasy = lvl;
3640    return;
3641 }
3642 /*!
3643    Decode a given ROI specifying string
3644 
3645 */
ROI_String_Decode(char * str,ATLAS_LIST * atlas_list)3646 AFNI_ATLAS_REGION *ROI_String_Decode(char *str, ATLAS_LIST *atlas_list)
3647 {
3648    AFNI_ATLAS_REGION *aar = NULL;
3649    int nc=0, k, icol[10], shft=0, ncol = 0;
3650    char *lbl = NULL;
3651    char atlas_name[64]={""};
3652    int LocalHead = wami_lh();
3653 
3654    ENTRY("ROI_String_Decode");
3655 
3656    if (!str) {
3657       if (LocalHead || SpeakEasy) ERROR_message("NULL input");
3658       RETURN(aar) ;
3659    }
3660    atlas_name[0] = '\0';
3661 
3662    nc = strlen(str);
3663    if (nc < 3) {
3664       if (LocalHead || SpeakEasy) ERROR_message("Get Shorty");
3665       RETURN(aar) ;
3666    }
3667 
3668    /* find my ':' */
3669    icol[0] = 0;
3670    ncol = 0;
3671    k = 0;
3672    while (k<nc) {
3673       if (str[k] == ':') {
3674          if (ncol < 2) {
3675             ++ncol;
3676             icol[ncol] = k;
3677          } else {
3678             if (LocalHead || SpeakEasy)
3679                ERROR_message("Too many ':' in ROI string");
3680             RETURN(aar) ;
3681          }
3682       }
3683       ++k;
3684    }
3685 
3686 
3687    if (!ncol){
3688       if (LocalHead || SpeakEasy)
3689          ERROR_message("Failed to find ':'\nin '%s'\n", str);
3690       RETURN(aar) ;
3691    }
3692 
3693    if (icol[1]-icol[0] > 62) {
3694       ERROR_message("Atlas name in %s more than 62 characters. Not good.\n",
3695                      str);
3696       RETURN(aar) ;
3697    }
3698    /* by now, we have at least one colon */
3699    /* get the atlas name, 1st item*/
3700    for (k=icol[0]; k<icol[1]; ++k) atlas_name[k] = str[k];
3701    atlas_name[icol[1]] = '\0';
3702    if (wami_verb() > 2)
3703       fprintf(stderr,"atlas_name from %s is: %s\n", str, atlas_name);
3704    /* is this an OK atlas ?*/
3705    if (!get_Atlas_Named(atlas_name, atlas_list)){
3706       if (LocalHead || SpeakEasy) {
3707          ERROR_message( "Atlas %s not recognized in specified atlas_list\n"
3708                         "Available atlas names are:\n", atlas_name);
3709          print_atlas_list(atlas_list);
3710       }
3711       WARNING_message("Proceeding with hope for an impossible miracle...\n");
3712    }
3713 
3714    /* get the label, last item */
3715    lbl = (char*)calloc((nc+1), sizeof(char));
3716    shft = icol[ncol]+1;
3717    for (k=shft; k<nc; ++k) lbl[k-shft] = str[k];
3718    lbl[nc-shft] = '\0';
3719    if (wami_verb() > 2)
3720       fprintf(stderr,"lbl from %s(%d to %d) is : '%s'\n", str, shft, nc, lbl);
3721 
3722    /* Now get aar */
3723    if (!(aar = Atlas_Chunk_Label(lbl, 0, atlas_name,NULL))) {
3724       if (LocalHead || SpeakEasy) ERROR_message("Failed in processing label");
3725       RETURN(aar) ;
3726    }
3727 
3728    free(lbl); lbl = NULL;
3729 
3730    /* set the side if possible */
3731    if (ncol == 2 && (icol[2] - icol[1] > 1)) {
3732       aar->side = TO_LOWER(str[icol[1]+1]);
3733       if (  aar->side != 'l' && aar->side != 'r'
3734             &&  aar->side != 'u'  &&  aar->side != 'b') {
3735          if (LocalHead || SpeakEasy) ERROR_message("Bad side specifier");
3736          aar = Free_Atlas_Region(aar);
3737          RETURN(aar) ;
3738       }
3739    }
3740 
3741    RETURN(aar) ;
3742 }
3743 
Report_Found_Regions(AFNI_ATLAS * aa,AFNI_ATLAS_REGION * ur,ATLAS_SEARCH * as,int * nexact)3744 char *Report_Found_Regions(AFNI_ATLAS *aa, AFNI_ATLAS_REGION *ur ,
3745                            ATLAS_SEARCH *as, int *nexact)
3746 {
3747    char *rbuf = NULL, lbuf[500];
3748    THD_string_array *sar = NULL;
3749    int nfind = 0, ii = 0, k= 0;
3750 
3751    ENTRY("Report_Found_Regions");
3752 
3753    if (!as || !ur || !aa) {
3754       ERROR_message("NULL input");
3755       RETURN(rbuf);
3756    }
3757    /* Prep the string toys */
3758    INIT_SARR(sar) ;
3759 
3760    *nexact = 0;
3761    /* do we have a search by number ? */
3762    if (ur->id > 0 && ur->N_chnks == 0) {
3763       if (as->nmatch) {
3764          if((ur->longname) && (strlen(ur->longname)!=0))
3765             snprintf (lbuf, 480*sizeof(char),
3766                      "Best match for %s [%s] (code %-3d):", ur->orig_label, ur->longname, ur->id);
3767          else
3768             snprintf (lbuf, 480*sizeof(char),
3769                      "Best match for %s (code %-3d):", ur->orig_label, ur->id);
3770          for (ii=0; ii<as->nmatch; ++ii) {
3771             /* show long name if it exists and different from regular name */
3772             if((aa->reg[as->iloc[ii]]->longname) && (strlen(aa->reg[as->iloc[ii]]->longname)!=0) &&
3773                (strcmp(aa->reg[as->iloc[ii]]->longname,aa->reg[as->iloc[ii]]->orig_label)))
3774                 snprintf (lbuf, 480*sizeof(char), "%s\n   %s [%s]", lbuf,
3775                      aa->reg[as->iloc[ii]]->orig_label, aa->reg[as->iloc[ii]]->longname);
3776             else
3777             snprintf (lbuf, 480*sizeof(char), "%s\n   %s", lbuf,
3778                      aa->reg[as->iloc[ii]]->orig_label);
3779          }
3780          *nexact = as->nmatch;
3781       }else {
3782          snprintf (lbuf, 480*sizeof(char),
3783                   "No match for integer code %-3d", ur->id);
3784       }
3785       ADDTO_SARR(sar,lbuf) ;
3786       goto PACK_AND_GO;
3787    }
3788 
3789    /* the whole deal */
3790    if (!as->nmatch) {
3791       snprintf (lbuf, 480*sizeof(char),
3792                   "No exact match for %s", ur->orig_label);
3793       ADDTO_SARR(sar,lbuf) ;
3794       if (as->score[0] > 0 && as->score[0] > as->score[5]) {
3795                                  /* maybe some useful suggestions */
3796          snprintf (lbuf, 480*sizeof(char),  "Closest few guesses:");
3797          ADDTO_SARR(sar,lbuf) ;
3798          k = 0;
3799          while (as->score[k] == as->score[0] && k < 5) {
3800             snprintf (lbuf, 480*sizeof(char),  "   %s, as->score %.3f",
3801                      aa->reg[as->iloc[0]]->orig_label, as->score[k]);
3802             ADDTO_SARR(sar,lbuf) ;
3803             ++k;
3804          }
3805       } else {
3806          snprintf (lbuf, 480*sizeof(char),
3807                            "   I don't even have good suggestions.\n"
3808                            "   Try to be more explicit.");
3809          ADDTO_SARR(sar,lbuf) ;
3810       }
3811    } else {
3812       if (as->score[0] > as->score[1]) { /* unique best fit */
3813          snprintf (lbuf, 480*sizeof(char),
3814                      "Best match for %s:\n   %s (code %-3d)",
3815                      ur->orig_label, aa->reg[as->iloc[0]]->orig_label,
3816                      aa->reg[as->iloc[0]]->id);
3817          ADDTO_SARR(sar,lbuf) ;
3818          *nexact = 1;
3819       } else if ( as->score[0] == as->score[1] &&
3820                   (as->N > 2 && as->score[1] > as->score[2]) &&
3821                   Same_Chunks(aa->reg[as->iloc[0]], aa->reg[as->iloc[1]])) {
3822                                                             /* LR unspecified  */
3823          snprintf (lbuf, 480*sizeof(char),
3824             "Best match for %s:\n   %s (code %-3d)\n   %s (code %-3d)",
3825             ur->orig_label,
3826             aa->reg[as->iloc[0]]->orig_label, aa->reg[as->iloc[0]]->id,
3827             aa->reg[as->iloc[1]]->orig_label, aa->reg[as->iloc[1]]->id);
3828          ADDTO_SARR(sar,lbuf) ;
3829          *nexact = 2;
3830       } else {
3831          k=0;
3832          snprintf (lbuf, 480*sizeof(char),
3833                    "%d potential matches for %s:", as->nmatch, ur->orig_label);
3834          ADDTO_SARR(sar,lbuf) ;
3835          while (as->score[k] == as->score[0] && k<aa->N_regions) {
3836             snprintf (lbuf, 480*sizeof(char),
3837                   "         %s (code %-3d):",
3838                   aa->reg[as->iloc[k]]->orig_label, aa->reg[as->iloc[k]]->id);
3839             ADDTO_SARR(sar,lbuf) ;
3840             ++k;
3841          }
3842       }
3843    }
3844 
3845 
3846    PACK_AND_GO:
3847    /*- convert list of labels into one big multi-line string -*/
3848    for( nfind=ii=0 ; ii < sar->num ; ii++ ) nfind += strlen(sar->ar[ii]) ;
3849    rbuf = AFMALL(char, nfind + 2*sar->num + 32 ) ; rbuf[0] = '\0' ;
3850    for( ii=0 ; ii < sar->num ; ii++ ){
3851       strcat(rbuf,sar->ar[ii]) ; strcat(rbuf,"\n") ;
3852    }
3853 
3854    DESTROY_SARR(sar) ;  sar = NULL;
3855 
3856    if (0) {
3857       INFO_message("Have:\n%s\n", rbuf);
3858    }
3859 
3860    RETURN(rbuf);
3861 }
3862 
Free_Atlas_Search(ATLAS_SEARCH * as)3863 ATLAS_SEARCH *Free_Atlas_Search(ATLAS_SEARCH *as)
3864 {
3865    ENTRY("Free_Atlas_Search");
3866    if (!as) RETURN(NULL);
3867 
3868    if (as->iloc) free(as->iloc);
3869    if (as->score) free(as->score);
3870    free(as);
3871    RETURN(NULL);
3872 }
3873 
3874 /***
3875    Functions for approximate string matching
3876 
3877    Still need to add scoring method used in Find_Atlas_Regions()
3878 ***/
3879 
init_str_diff_weights(APPROX_STR_DIFF_WEIGHTS * Dwi)3880 APPROX_STR_DIFF_WEIGHTS *init_str_diff_weights(APPROX_STR_DIFF_WEIGHTS *Dwi)
3881 {
3882    APPROX_STR_DIMS i=0;
3883    if (!Dwi)
3884       Dwi = (APPROX_STR_DIFF_WEIGHTS*)malloc(sizeof(APPROX_STR_DIFF_WEIGHTS));
3885    memset (Dwi, 0, sizeof(APPROX_STR_DIFF_WEIGHTS));
3886    for (i=0; i<N_APPROX_STR_DIMS; ++i) {
3887       switch (i) {
3888          case LEV:
3889             Dwi->w[i] = 2.0;
3890             break;
3891          case PMD:
3892             Dwi->w[i] = 5.0;
3893             break;
3894          case FCD:
3895             Dwi->w[i] = 5.0;
3896             break;
3897          case FLD:
3898             Dwi->w[i] = 1.0;
3899             break;
3900          case MWI:
3901             Dwi->w[i] = 1.0;
3902             break;
3903          default:
3904             Dwi->w[i] = 0.1;
3905             break;
3906       }
3907    }
3908    return(Dwi);
3909 }
3910 
init_str_diff(APPROX_STR_DIFF * Dw)3911 APPROX_STR_DIFF *init_str_diff(APPROX_STR_DIFF *Dw) {
3912    int i;
3913    if (!Dw)
3914       Dw = (APPROX_STR_DIFF*)malloc(sizeof(APPROX_STR_DIFF));
3915    for (i=0; i<N_APPROX_STR_DIMS; ++i) {
3916       Dw->d[i] = 100000;
3917    }
3918    Dw->srcfile[0]='\0';
3919    return(Dw);
3920 }
3921 
3922 /*!
3923    An approximate string matching technique based on the Levenshtein distance.
3924    Based on Pseudocode from: http://en.wikipedia.org/wiki/Levenshtein_distance
3925 
3926    ci =1 for case insensitive searches.
3927 
3928    Not terribly efficient, but easy to read
3929 
3930    s2 is considered to be the string you're searching for.
3931 */
LevenshteinStringDistance(char * s1,char * s2,byte ci)3932 APPROX_STR_DIFF LevenshteinStringDistance(char *s1, char *s2, byte ci)
3933 {
3934    int ns1=0, ns2=0, i, j, m, ks1, ks2, imatch, ks1t, verb=0;
3935    byte eqs=0;
3936    int **d=NULL;
3937    char *spart=NULL;
3938    APPROX_STR_DIFF D;
3939 
3940    ENTRY("LevenshteinStringDistance");
3941 
3942    init_str_diff(&D);
3943 
3944    if (!s1 && !s2) RETURN(D);
3945    if (!s1 || !s2) RETURN(D);
3946 
3947    ns1 = strlen(s1);
3948    ns2 = strlen(s2);
3949 
3950    spart=NULL;
3951    {
3952       char *ss, *sl;
3953       int ns;
3954       if (ns2 < ns1) {
3955          ss = s2; sl = s1;
3956          ns = ns2; /* nl = ns1;*/
3957       } else {
3958          ss = s1; sl = s2;
3959          ns = ns1; /* nl = ns2;*/
3960       }
3961       /* Don't accpet this search if the smallest word is too small.
3962       For example Saad and S will get a super high match (0), but
3963       Saad and Sad will get a 9, given the weight I usually give
3964       to partial matches, this would hurt a lot with this constraint */
3965       D.d[PMD] = 9;
3966       if (ns > 3 ||
3967           /* allow it if it looks like we're looking for options */
3968           (ns > 1 && s1[0] == '-' && s2[0] == '-')) {
3969          if (ci) spart = strcasestr(sl, ss);
3970          else spart = strstr(sl, ss);
3971 
3972          if (spart) {
3973             D.d[PMD] = (int)((float)(spart-sl)/strlen(sl)*10.0);
3974                if (D.d[PMD] > 5) D.d[PMD]=5;
3975             if (D.d[PMD] < 0) fprintf(stderr,"Holy Toledo Batman: %s\n"
3976                                              "                    %s\n",
3977                                              s1, s2);
3978          }
3979       }
3980       if (verb) {
3981          fprintf(stderr,"Holy Toledo Batman: %s\n"
3982                         "                    %s\n"
3983                         "D.d[PMD] = %d\n",
3984                                           s1, s2, D.d[PMD]);
3985       }
3986    }
3987 
3988    /* counting number of similar characters with direction*/
3989    ks1=0;
3990    ks2=0;
3991    imatch=0;
3992    while (ks2<ns2) {
3993       if (ci) {
3994          /* search forward for s2[ks2] in s1 */
3995          ks1t = ks1;
3996          while (ks1t < ns1) {
3997             if ((s1[ks1t] == s2[ks2]) ||
3998                 (ci && TO_LOWER(s1[ks1t]) == TO_LOWER(s2[ks2]))) {
3999                ++imatch; ks1t++; ks1 = ks1t;
4000                if (verb) {
4001                   fprintf(stderr,"Got %c in %s at %d (%d)\n",
4002                            s2[ks2], s1, ks1t, imatch);
4003                }
4004                break;
4005             }else{
4006                ks1t++;
4007             }
4008          }
4009       }
4010       ++ks2;
4011    }
4012    D.d[FCD] = (int)((ns2-imatch)/(float)ns2*10.0); if (D.d[FCD] > 9) D.d[FCD]=9;
4013    if (verb) {
4014       fprintf(stderr,"D.d[FCD]= %d\n", D.d[FCD]);
4015    }
4016 
4017    d = (int **)calloc(ns1+1, sizeof(int*));
4018    for (i=0; i<=ns1; ++i) {
4019       d[i] = (int *)calloc(ns2+1, sizeof(int));
4020    }
4021    for (i=0; i<=ns1; ++i) d[i][0]=i;
4022    for (j=0; j<=ns2; ++j) d[0][j]=j;
4023 
4024    for (j=1; j<=ns2; ++j) {
4025       for (i=1; i<=ns1; ++i) {
4026          if (ci) eqs = (TO_LOWER(s1[i-1]) == TO_LOWER(s2[j-1]));
4027          else eqs = (s1[i-1] == s2[j-1]);
4028          if (eqs) {
4029             d[i][j] = d[i-1][j-1];
4030          } else {
4031             d[i][j] = d[i-1][j]+1;
4032             m = d[i][j-1]+1; if (m < d[i][j]) d[i][j] = m;
4033             m = d[i-1][j-1]+1; if (m < d[i][j]) d[i][j] = m;
4034          }
4035       }
4036    }
4037    D.d[LEV] = d[ns1][ns2];
4038    if (D.d[LEV] > 9) D.d[LEV] = 9;
4039    for (i=0; i<=ns1; ++i) {
4040       free(d[i]);
4041    }
4042    free(d); d = NULL;
4043 
4044    /* modulate D by string length difference, preference is given to ns2 */
4045    D.d[FLD] = (int)(ns2-ns1);
4046    if (D.d[FLD] < 0) D.d[FLD] = -D.d[FLD]; if (D.d[FLD] > 9) D.d[FLD] = 9;
4047 
4048    RETURN(D);
4049 }
4050 
magnitude_str_diff(APPROX_STR_DIFF * D,APPROX_STR_DIFF_WEIGHTS * Dwi)4051 float magnitude_str_diff(APPROX_STR_DIFF *D, APPROX_STR_DIFF_WEIGHTS *Dwi)
4052 {
4053    float d=0.0;
4054    int i=0;
4055    for (i=0; i<N_APPROX_STR_DIMS; ++i) {
4056       d += D->d[i]*Dwi->w[i];
4057    }
4058    return(d);
4059 }
4060 
copy_str_diff(APPROX_STR_DIFF * Din,APPROX_STR_DIFF * Dout)4061 APPROX_STR_DIFF *copy_str_diff(APPROX_STR_DIFF *Din, APPROX_STR_DIFF *Dout)
4062 {
4063    int i=0;
4064    if (!Din) return(NULL);
4065    if (!Dout) Dout = init_str_diff(NULL);
4066    for (i=0; i<N_APPROX_STR_DIMS; ++i) {
4067       Dout->d[i] = Din->d[i];
4068    }
4069    strncpy(Dout->srcfile, Din->srcfile, SRCFILE_MAX*sizeof(char));
4070    return(Dout);
4071 }
4072 
approx_str_diff_swap(APPROX_STR_DIFF * Din,APPROX_STR_DIFF * Dout)4073 int approx_str_diff_swap(APPROX_STR_DIFF *Din, APPROX_STR_DIFF *Dout)
4074 {
4075    int i=0, dd;
4076    char srcfile[256];
4077 
4078    if (!Din || !Dout) return(0);
4079 
4080    strncpy(srcfile, Dout->srcfile, SRCFILE_MAX*sizeof(char));
4081    strncpy(Dout->srcfile, Din->srcfile, SRCFILE_MAX*sizeof(char));
4082    strncpy(Din->srcfile, srcfile, SRCFILE_MAX*sizeof(char));
4083    for (i=0; i<N_APPROX_STR_DIMS; ++i) {
4084       dd = Dout->d[i];
4085       Dout->d[i] = Din->d[i];
4086       Din->d[i] = dd;
4087    }
4088    return(1);
4089 }
name_approx_string_diff_dim(APPROX_STR_DIMS i)4090 char *name_approx_string_diff_dim(APPROX_STR_DIMS i) {
4091    switch (i) {
4092       case  LEV:
4093          return("LEV");
4094       case FLD:
4095          return("FLD");
4096       case FCD:
4097          return("FCD");
4098       case PMD:
4099          return("PMD");
4100       case MWI:
4101          return("MWI");
4102       case MWL:
4103          return("MWL");
4104       case IWD:
4105          return("IWD");
4106       case N_APPROX_STR_DIMS:
4107          return("N_DIMS");
4108       default:
4109          return("FOOL, initialize me!");
4110    }
4111    return("Very bad situation");
4112 }
4113 
approx_string_diff_info(APPROX_STR_DIFF * D,APPROX_STR_DIFF_WEIGHTS * Dwi)4114 char *approx_string_diff_info(APPROX_STR_DIFF *D, APPROX_STR_DIFF_WEIGHTS *Dwi)
4115 {
4116    static char res[10][512];
4117    static int icall=-1;
4118    char sbuf[40];
4119    int i;
4120 
4121    if (!Dwi) Dwi = init_str_diff_weights(Dwi);
4122 
4123    ++icall; if (icall > 9) icall=0;
4124 
4125    snprintf(res[icall],SRCFILE_MAX*sizeof(char),"(%s ", D->srcfile);
4126    for (i=0; i<N_APPROX_STR_DIMS; ++i) {
4127       sprintf(sbuf,"%s %dx%.2f ",
4128                name_approx_string_diff_dim(i), D->d[i], Dwi->w[i]);
4129       strcat(res[icall], sbuf);
4130    }
4131    strcat(res[icall],")");
4132    return(res[icall]);
4133 }
4134 
set_smallest_str_diff(APPROX_STR_DIFF * D0,APPROX_STR_DIFF D1,APPROX_STR_DIFF D2,APPROX_STR_DIFF_WEIGHTS Dw,int * iminp)4135 float set_smallest_str_diff(APPROX_STR_DIFF *D0,
4136                               APPROX_STR_DIFF D1, APPROX_STR_DIFF D2,
4137                               APPROX_STR_DIFF_WEIGHTS Dw, int *iminp)
4138 {
4139    int imin=0;
4140    float d1, d2, d;
4141 
4142    if (!D0) return(-1.0);
4143 
4144    d1 = magnitude_str_diff(&D1, &Dw);
4145    d2 = magnitude_str_diff(&D2, &Dw);
4146    if (d1 < d2) {
4147       d = d1; imin = 1;
4148       D0 = copy_str_diff(&D1, D0);
4149    } else {
4150       d = d2; imin = 2;
4151       D0 = copy_str_diff(&D2, D0);
4152    }
4153    if (iminp) *iminp=imin;
4154    return(d);
4155 }
4156 
str_in_line_distance(char * line,char * str,byte ci,APPROX_STR_DIFF_WEIGHTS * Dwi)4157 APPROX_STR_DIFF str_in_line_distance(char *line, char *str, byte ci,
4158                                      APPROX_STR_DIFF_WEIGHTS *Dwi)
4159 {
4160    int iword = 0;
4161    char *sword=NULL, *brk=NULL, lsep[] = " \t";
4162    APPROX_STR_DIFF_WEIGHTS *Dw = Dwi;
4163    APPROX_STR_DIFF Dtmp, Dmin ;
4164    float dtmp;
4165 
4166    if (!Dw) Dw = init_str_diff_weights(Dw);
4167    init_str_diff(&Dmin);
4168    init_str_diff(&Dtmp);
4169    for ( sword=strtok_r(line,lsep, &brk);
4170          sword; sword = strtok_r(NULL, lsep, &brk)) {
4171       deblank_name(sword); depunct_name(sword);
4172       if (sword[0] != '\0') {
4173          Dtmp = LevenshteinStringDistance(sword, str, ci);
4174          Dtmp.d[MWI]=iword;
4175          dtmp = set_smallest_str_diff(&Dmin, Dtmp, Dmin, *Dw, NULL);
4176          /* fprintf(stderr,"ZSS: compare %s to %s %f (%f %f) %d %d\n",
4177                   sword, str, dtmp,
4178             magnitude_str_diff(&Dtmp, Dw), magnitude_str_diff(&Dmin,Dw),
4179             Dmin.d[MWI], iword); */
4180          ++iword;
4181       }
4182    }
4183 
4184    if (Dw != Dwi) free(Dw); Dw=NULL;
4185 
4186    return(Dmin);
4187 }
4188 
4189 
sort_str_diffs(APPROX_STR_DIFF ** Di,int N_words,APPROX_STR_DIFF_WEIGHTS * Dwi,float ** sorted_score,int direct,byte sort_D)4190 int *sort_str_diffs (APPROX_STR_DIFF **Di, int N_words,
4191                      APPROX_STR_DIFF_WEIGHTS *Dwi,
4192                      float **sorted_score, int direct,
4193                      byte sort_D)
4194 {
4195    int *isi = NULL, i=0;
4196    float *d=NULL;
4197    APPROX_STR_DIFF *D = *Di, *Ds=NULL;
4198    APPROX_STR_DIFF_WEIGHTS *Dw = Dwi;
4199 
4200    ENTRY("sort_str_diffs");
4201 
4202    if (sorted_score && *sorted_score) {
4203       ERROR_message("If sorted_score then *sorted_score should be NULL!\n");
4204       RETURN(isi);
4205    }
4206 
4207    if (!Dw) Dw = init_str_diff_weights(Dw);
4208 
4209    /* combine all distance dimentions, no fancy options yet*/
4210    d = (float *)calloc(N_words, sizeof(float));
4211    for (i=0; i<N_words; ++i) {
4212       d[i] = magnitude_str_diff(D+i, Dw);
4213    }
4214 
4215    /* sort the result */
4216    if (direct == -1) for (i=0; i<N_words; ++i) d[i] *= -1;
4217    isi = z_iqsort(d, N_words);
4218    if (direct == -1) for (i=0; i<N_words; ++i) d[i] *= -1;
4219 
4220    if (!sorted_score) {
4221       free(d); d=NULL;
4222    } else {
4223       *sorted_score=d;
4224    }
4225 
4226    if (sort_D) {
4227       Ds = (APPROX_STR_DIFF *)calloc(N_words, sizeof(APPROX_STR_DIFF));
4228       for (i=0; i<N_words;++i) {
4229          copy_str_diff(D+isi[i], Ds+i);
4230       }
4231       free(*Di); *Di=Ds; Ds = NULL;
4232    }
4233 
4234    if (Dw != Dwi) free(Dw); Dw=NULL;
4235 
4236    RETURN(isi);
4237 }
4238 
4239 /*
4240    Sort array of strings by the approximate similarity to str
4241    Best match first.
4242 */
approx_str_sort(char ** words,int N_words,char * str,byte ci,float ** sorted_score,byte wsplit,APPROX_STR_DIFF_WEIGHTS * Dwi,APPROX_STR_DIFF ** Dout)4243 char **approx_str_sort(char **words, int N_words, char *str, byte ci,
4244                        float **sorted_score, byte wsplit,
4245                        APPROX_STR_DIFF_WEIGHTS *Dwi,
4246                        APPROX_STR_DIFF **Dout)
4247 {
4248    char **ws=NULL;
4249    char *line=NULL;
4250    APPROX_STR_DIFF *is=NULL;
4251    APPROX_STR_DIFF_WEIGHTS *Dw = Dwi;
4252    int direct = -1; /* -1 best match first, 1 best match last */
4253    int i;
4254    int *isi=NULL;
4255 
4256    ENTRY("approx_str_sort");
4257 
4258    if (!words || !N_words || !str) RETURN(ws);
4259    if (sorted_score && *sorted_score) {
4260       ERROR_message("If sorted_score then *sorted_score should be NULL\n");
4261       RETURN(ws);
4262    }
4263    if (Dout && *Dout) {
4264       ERROR_message("If Dout then *Dout should be NULL\n");
4265       RETURN(ws);
4266    }
4267    if (!Dw) Dw = init_str_diff_weights(Dw);
4268    ws = (char **)calloc(N_words, sizeof(char *));
4269    is = (APPROX_STR_DIFF *)calloc(N_words, sizeof(APPROX_STR_DIFF));
4270 
4271    for (i=0; i<N_words; ++i) {
4272       if (!wsplit) {
4273          is[i] = LevenshteinStringDistance(words[i], str, ci);
4274       } else { /* split line into words */
4275          line = strdup(deblank_name(words[i]));
4276          init_str_diff(is+i);
4277          if (!strlen(words[i]) || !strlen(deblank_name(line))) {
4278             /* empty line, leave at max */
4279          } else {
4280             is[i] = str_in_line_distance(line, str, ci, Dw);
4281          }
4282          if (line) free(line);
4283       }
4284    }
4285 
4286    /* sort scores */
4287    isi = sort_str_diffs (&is, N_words, Dwi, sorted_score, direct, 1);
4288 
4289    /* create sorted output, best match last */
4290    for (i=0; i<N_words; ++i) {
4291       ws[i] = strdup(words[isi[i]]);
4292    }
4293 
4294    /* clean up and return */
4295    free(isi); isi = NULL;
4296    if (Dw != Dwi) free(Dw); Dw=NULL;
4297    if (Dout) {
4298       *Dout = is;
4299    } else {
4300       free(is);
4301    }
4302    is = NULL;
4303 
4304    RETURN(ws);
4305 }
4306 
4307 /*!
4308    \brief Return unique set of strings, NULL strings in words are OK.
4309       char **unique_str(char **words, int N_words, byte ci,
4310                   byte noae, int *N_unq, int **isort_out);
4311 
4312    \param words (char **): Array of strings to be sorted
4313    \param N_words (int): Number of strings in words
4314    \param ci (byte): 1 == case insensitive matching
4315    \param noae (byte): 0 == leave words as they are
4316                        1 == remove known AFNI extensions
4317                        2 == remove known AFNI extensions AND +VIEW string
4318    \param N_unq (int *): To contain number of unique non-null strings found
4319    \param isort_out (int **): To contain a mapping from the unique strings
4320                               array to the initial words array.
4321    \return unique_words (char **): Array of unique strings found. Returned
4322                                    strings are trimmed according to noae.
4323                                    They will be lower case if ci == 1.
4324                          Note that unique_words is an array of N_words strings
4325                          though some (beyond *N_unq) are likely NULL.
4326                          Check for NULL before freeing each string.
4327    \sa MCW_wildcards()
4328    See also apsearch's options -wild_* and -test_unique_str
4329        for examples on how to use unique_str along with wildcard matching.
4330 */
unique_str(char ** words,int N_words,byte ci,byte noae,int * N_unq,int ** isort_out)4331 char **unique_str(char **words, int N_words, byte ci,
4332                   byte noae, int *N_unq, int **isort_out)
4333 {
4334    char **ws=NULL;
4335 /*   char *line=NULL;*/
4336 /*   int direct = -1;*/ /* -1 best match first, 1 best match last */
4337    int i, c, n_null;
4338    int *isrt=NULL;
4339 
4340    ENTRY("unique_str");
4341 
4342    if (!words || !N_words) RETURN(ws);
4343    if (N_unq) *N_unq = -1;
4344    if (isort_out && *isort_out) {
4345       ERROR_message("If you want isort_out, you must pass *isort_out = NULL");
4346       RETURN(ws);
4347    }
4348 
4349    if (!(ws = (char **)calloc(N_words, sizeof(char *)))) {
4350       ERROR_message("Failed to allocate for %d words");
4351       RETURN(ws);
4352    }
4353 
4354    /* preprocess list */
4355    n_null = 0;
4356    for (i=0; i<N_words; ++i) {
4357       if (words[i]) {
4358          switch (noae) {
4359             case 1:
4360                ws[i] = strdup(without_afni_filename_extension(words[i]));
4361                break;
4362             case 2:
4363                ws[i] =
4364                   strdup(without_afni_filename_view_and_extension(words[i]));
4365                break;
4366             default:
4367             case 0:
4368                ws[i] = strdup(words[i]);
4369                break;
4370          }
4371          if (ci) {
4372             c= 0;
4373             while (ws[i][c] != '\0') { ws[i][c] = TO_LOWER(ws[i][c]);++c; }
4374          }
4375       } else {
4376          ws[i] = NULL; ++n_null;
4377       }
4378    }
4379 
4380    /* sort and kill the dups */
4381    if (n_null == N_words || !(isrt = z_istrqsort (ws, N_words ))) {
4382       ERROR_message("All null or Failed to sort input.");
4383       for (i=0; i<N_words; ++i) if (ws[i]) free(ws[i]); free(ws);
4384       RETURN(NULL);
4385    }
4386    /* skip nulls */
4387    i = 0;
4388    while (i<N_words && !ws[i]) ++i;
4389    /* initialize 1st entry */
4390    if (i>0 && i<N_words) {
4391       ws[0] = ws[i];
4392       isrt[0] = isrt[i];
4393       ws[i] = NULL;
4394    } else {
4395       i = 1;
4396    }
4397    c = 1;
4398    while(i<N_words) {
4399       if (ws[i] && ws[c-1] && strcmp(ws[i], ws[c-1])){
4400                               /* new non-null string, keep it */
4401          if (i != c) {
4402             if (ws[c]) free(ws[c]);
4403             ws[c] = ws[i];
4404             isrt[c] = isrt[i];
4405             ws[i]=NULL;
4406          }
4407          ++c;
4408       } else { /* repeat, just delete it */
4409          if (i != c && ws[i] ) free(ws[i]); ws[i]=NULL;
4410       }
4411       ++i;
4412    }
4413 
4414    if (!isort_out) free(isrt);
4415    else *isort_out = isrt;
4416    isrt=NULL;
4417 
4418    if (N_unq) *N_unq = c;
4419 
4420    RETURN(ws);
4421 }
4422 
4423 
4424 typedef struct {
4425    char *txt_src; /* Such as file name */
4426    char *orig_txt; /* Original text */
4427    int N_lines; /* Total number of lines in orig_txt */
4428    char **lines; /*  Lines in orig_txt, eventually in a sorted order
4429                      Have N_lines strings */
4430    int *line_index; /* lines[i] is line line_index[i] in orig_txt */
4431    APPROX_STR_DIFF *D; /* Distance of best matching word in lines.
4432                              One value for each line in 'lines' */
4433    APPROX_STR_DIFF_WEIGHTS *Dw; /* Weights vector for distance computation */
4434    char *word; /* The actual word being sought */
4435 } AFNI_TEXT_SORT;
4436 
free_text_sort(AFNI_TEXT_SORT * ats)4437 AFNI_TEXT_SORT *free_text_sort(AFNI_TEXT_SORT *ats)
4438 {
4439    int i;
4440    if (!ats) return(NULL);
4441    if (ats->word) free(ats->word);
4442    if (ats->Dw) free(ats->Dw);
4443    if (ats->D) free(ats->D);
4444    if (ats->line_index) free(ats->line_index);
4445    if (ats->lines) {
4446       for (i=0; i<ats->N_lines; ++i) {
4447          if (ats->lines[i]) free(ats->lines[i]);
4448       }
4449       free(ats->lines);
4450    }
4451    if (ats->orig_txt) free(ats->orig_txt);
4452    if (ats->txt_src) free(ats->txt_src);
4453    return(NULL);
4454 }
4455 
4456 
approx_str_sort_text(char * text,int * N_ws,char * str,byte ci,float ** sorted_score,APPROX_STR_DIFF_WEIGHTS * Dwi,APPROX_STR_DIFF ** Dout,char join_breaks)4457 char **approx_str_sort_text(char *text, int *N_ws, char *str,
4458                             byte ci, float **sorted_score,
4459                             APPROX_STR_DIFF_WEIGHTS *Dwi,
4460                             APPROX_STR_DIFF **Dout,
4461                             char join_breaks)
4462 {
4463    char **ws=NULL;
4464    int N_lines=0, N_alloc=0, line_continue=0, ln=0;
4465    char *brk=NULL, lsep[] = "\n\r", *line=NULL;
4466    APPROX_STR_DIFF_WEIGHTS *Dw = Dwi;
4467 
4468    ENTRY("approx_str_sort_text");
4469 
4470    *N_ws=0;
4471 
4472    if (!text || !str) RETURN(ws);
4473    if (sorted_score && *sorted_score) {
4474       ERROR_message("If sorted_score then *sorted_score should be NULL\n");
4475       RETURN(ws);
4476    }
4477    if (Dout && *Dout) {
4478       ERROR_message("If Dout then *Dout should be NULL\n");
4479       RETURN(ws);
4480    }
4481    if (!Dw) Dw = init_str_diff_weights(Dw);
4482    /* turn text into multi lines. Combine at '\' ? */
4483    N_lines = 0;
4484    line_continue=0;
4485    for (line=strtok_r(text,lsep, &brk); line; line = strtok_r(NULL, lsep, &brk))
4486    {
4487       if (!line_continue || !N_lines) {
4488          ++N_lines;
4489          if (N_lines > N_alloc) {
4490             N_alloc += 50;
4491             ws = (char **)realloc(ws, N_alloc*sizeof(char *));
4492          }
4493          ws[N_lines-1] = strdup(line);
4494       } else {
4495          /* fprintf(stderr,"ZSS:       Appending -->%s<-->%s<--\n"
4496                         , ws[N_lines-1], line); */
4497          ws[N_lines-1] = (char *)realloc(ws[N_lines-1],
4498                             sizeof(char)*(strlen(ws[N_lines-1])+strlen(line)+1));
4499          strcat(ws[N_lines-1], line);
4500       }
4501       deblank_name(ws[N_lines-1]);
4502       ln = strlen(ws[N_lines-1]);
4503       if (ln && *(ws[N_lines-1]+ln-1) == join_breaks) {
4504          line_continue = 1;
4505       } else {
4506          line_continue = 0;
4507       }
4508       /* fprintf(stderr,"ZSS: %d -->%s<-- (join_breaks=%c, continue=%d)\n",
4509                      N_lines, ws[N_lines-1], join_breaks, line_continue); */
4510    }
4511 
4512    *N_ws=N_lines;
4513 
4514    /* fprintf(stderr,"ZSS: %d lines\n", N_lines); */
4515 
4516    if (str && N_lines) { /* sort */
4517       ws = approx_str_sort(ws, *N_ws, str, ci, sorted_score, 1, Dw, Dout);
4518    }
4519 
4520    /* fprintf(stderr,"ZSS: %d lines post sort\n", *N_ws);    */
4521 
4522    if (Dw != Dwi) free(Dw); Dw=NULL;
4523 
4524    RETURN(ws);
4525 }
4526 
approx_str_sort_Ntfile(char ** fnames,int N_names,char * str,byte ci,float ** sorted_score,APPROX_STR_DIFF_WEIGHTS * Dwi,APPROX_STR_DIFF ** Doutp,int verb,char join_breaks)4527 THD_string_array *approx_str_sort_Ntfile(
4528                   char **fnames, int N_names, char *str,
4529                             byte ci, float **sorted_score,
4530                             APPROX_STR_DIFF_WEIGHTS *Dwi,
4531                             APPROX_STR_DIFF **Doutp, int verb, char join_breaks)
4532 {
4533    char **ws=NULL, *text=NULL, *fname=NULL;
4534    APPROX_STR_DIFF_WEIGHTS *Dw = Dwi;
4535    THD_string_array *sar=NULL, *sars=NULL;
4536    APPROX_STR_DIFF *Dout=NULL;
4537    int N_ws=-1, inm=0, ii=0, *isi=NULL;
4538    int direct = -1; /* -1 best match first, 1 best match last */
4539 
4540    ENTRY("approx_str_sort_Ntfile");
4541 
4542    if (!fnames || !str) RETURN(sar);
4543    if (sorted_score && *sorted_score) {
4544       ERROR_message("If sorted_score then *sorted_score should be NULL.\n");
4545       RETURN(sar);
4546    }
4547    if (Doutp && *Doutp) {
4548       ERROR_message("If Doutp then *Doutp should be NULL\n");
4549       RETURN(sar);
4550    }
4551 
4552    if (!Dw) Dw = init_str_diff_weights(Dw);
4553 
4554    for (inm=0; inm < N_names; ++inm) {
4555       fname = fnames[inm];
4556       if (!(ws = approx_str_sort_tfile(fname, 0, &N_ws, str, ci,
4557                                 NULL, Dw, &Dout, verb, join_breaks))) {
4558          if (verb) WARNING_message("Failed to process %s\n", fname);
4559          continue;
4560       }
4561       if (!sar) INIT_SARR( sar ) ;
4562       for (ii=0; ii<N_ws; ++ii) {
4563          ADDTO_SARR(sar, ws[ii]); free(ws[ii]); ws[ii]=NULL;
4564       }
4565       if (Doutp) {
4566          *Doutp = (APPROX_STR_DIFF *)realloc((*Doutp),
4567                         sar->num* sizeof(APPROX_STR_DIFF));
4568          memcpy(((*Doutp)+sar->num-N_ws), Dout, N_ws*sizeof(APPROX_STR_DIFF));
4569       }
4570       free(Dout); Dout = NULL;
4571       free(ws); free(text); text=NULL;
4572    }
4573    if (Dw != Dwi) free(Dw); Dw=NULL;
4574 
4575    /* Now that we have all files read, sort the final result
4576       This is weak here, sort_str_diffs should also take into
4577       account the frequency with which good matches are found
4578       in a particular file.
4579       Someday perhaps...*/
4580    isi = sort_str_diffs (Doutp, sar->num, Dwi, sorted_score, direct, 1);
4581 
4582    /* create sorted output, best match last */
4583    INIT_SARR(sars);
4584    for (ii=0; ii<sar->num; ++ii) {
4585       ADDTO_SARR(sars,sar->ar[isi[ii]]);
4586    }
4587    DESTROY_SARR(sar); sar = sars; sars=NULL;
4588    free(isi); isi=NULL;
4589 
4590    RETURN(sar);
4591 }
4592 
4593 
4594 /*
4595    See function approx_str_sort_all_popts() for warning about
4596    setting textinname to 1
4597 */
approx_str_sort_tfile(char * fname,int textinname,int * N_ws,char * str,byte ci,float ** sorted_score,APPROX_STR_DIFF_WEIGHTS * Dwi,APPROX_STR_DIFF ** Dout,int verb,char join_breaks)4598 char **approx_str_sort_tfile(char *fname, int textinname, int *N_ws, char *str,
4599                             byte ci, float **sorted_score,
4600                             APPROX_STR_DIFF_WEIGHTS *Dwi,
4601                             APPROX_STR_DIFF **Dout, int verb, char join_breaks)
4602 {
4603    char **ws=NULL, *text=NULL;
4604    APPROX_STR_DIFF_WEIGHTS *Dw = Dwi;
4605    APPROX_STR_DIFF *ddout = NULL;
4606    int ii=0;
4607 
4608    ENTRY("approx_str_sort_tfile");
4609 
4610    if (!fname || !str) RETURN(ws);
4611    if (sorted_score && *sorted_score) {
4612       ERROR_message("If sorted_score then *sorted_score should be NULL\n");
4613       RETURN(ws);
4614    }
4615    if (Dout && *Dout) {
4616       ERROR_message("If Dout then *Dout should be NULL\n");
4617       RETURN(ws);
4618    }
4619 
4620    if (!textinname) {
4621       /* suck text and send it to approx_str_sort_text */
4622       if (!(text = AFNI_suck_file(fname))) {
4623          if (verb) ERROR_message("File %s could not be read\n", fname);
4624          RETURN(ws);
4625       }
4626    } else {
4627       text = fname;
4628    }
4629 
4630    if (!Dw) Dw = init_str_diff_weights(Dw);
4631    ws = approx_str_sort_text(text, N_ws, str, ci,
4632                              sorted_score, Dw, Dout, join_breaks);
4633    if (Dout && *Dout) {
4634       ddout = *Dout;
4635       for (ii=0; ii<*N_ws; ++ii) {
4636          if (!textinname) {
4637             snprintf(ddout[ii].srcfile,SRCFILE_MAX*sizeof(char),
4638                             "%s", THD_trailname(fname,0));
4639          } else {
4640             snprintf(ddout[ii].srcfile,SRCFILE_MAX*sizeof(char),
4641                             "%s", "NoFnameGiven");
4642          }
4643       }
4644    }
4645 
4646    if (text != fname) free(text); text=NULL;
4647 
4648    if (Dw != Dwi) free(Dw); Dw=NULL;
4649 
4650    RETURN(ws);
4651 }
4652 
4653 /*
4654    Beware setting textinname to 1
4655    ==============================
4656    You can set textinname to 1 to indicate that the string prog
4657    actually contains the text rather than a filename to that text.
4658    However, realize that the string in prog will get modified by
4659    this function and might be of little use to you upon returning.
4660 */
approx_str_sort_all_popts(char * prog,int textinname,int * N_ws,byte ci,float ** sorted_score,APPROX_STR_DIFF_WEIGHTS * Dwi,APPROX_STR_DIFF ** Dout,int uopts,int verb,char join_breaks)4661 char **approx_str_sort_all_popts(char *prog, int textinname, int *N_ws,
4662                             byte ci, float **sorted_score,
4663                             APPROX_STR_DIFF_WEIGHTS *Dwi,
4664                             APPROX_STR_DIFF **Dout,
4665                             int uopts, int verb, char join_breaks)
4666 {
4667    int i, inn, c, *isrt=NULL;
4668    char **ws=NULL, *dpun=NULL, *blnk, *wild;
4669    char *str="-";
4670    float *sc=NULL, ff= 0.0;
4671    APPROX_STR_DIFF *D=NULL;
4672 
4673    ENTRY("approx_str_sort_all_popts");
4674 
4675    Dwi = init_str_diff_weights(NULL);
4676    Dwi->w[MWI]=1000; /* give a lot of weight to the order in the sentence */
4677    if (!(ws = approx_str_sort_phelp(prog, textinname, N_ws, str,
4678                       ci, sorted_score,
4679                       Dwi, Dout, verb, join_breaks))) {
4680       if (verb && !textinname) {
4681          if (THD_filesize(prog)) {
4682             ERROR_message("Failed to get phelp for '%s', word '%s'", prog,str);
4683          } else {
4684             INFO_message("Empty help for '%s'", prog);
4685          }
4686       }
4687       RETURN(NULL);
4688    }
4689    free(Dwi); Dwi=NULL;
4690    if (sorted_score) sc = *sorted_score;
4691    if (Dout) D = *Dout;
4692 
4693    /* a little cleanup */
4694    for (i=0; i<*N_ws; ++i) {
4695       /* remove brackets and such */
4696       dpun = strdup(ws[i]);
4697       depunct_name(dpun);
4698       deblank_name(dpun); /* to catch things like * -option in 3dclust */
4699       if (dpun[0] != '-' || strlen(dpun) < 2 || isspace(dpun[1]) ||
4700           !strncmp(dpun,"-- ",3) || !strncmp(dpun,"--- ",4)) {
4701          free(dpun); dpun=NULL;
4702       } else if ((wild = strchr(ws[i],'*')) || (wild = strchr(ws[i],'*'))){
4703                         /* have wildcard, but is it in 1st word? */
4704          blnk = strchr(ws[i],' ');
4705          if (!blnk || blnk > wild) { /* wildcard in 1st word, ignore */
4706             free(dpun); dpun=NULL;
4707          }
4708       } else {
4709          /* remove '----------' */
4710          c=1;
4711          while(dpun[c] !='\0' && dpun[c]=='-') ++c;
4712          if (dpun[c] == '\0'   || (
4713               (IS_BLANK(dpun[c]) ||
4714                IS_PUNCT(dpun[c]) ||
4715                IS_QUOTE(dpun[c])) && (c > 3) )) {
4716             free(dpun); dpun=NULL;
4717          }
4718       }
4719       if (!dpun) {
4720          free(ws[i]); ws[i]=NULL;
4721       } else {
4722          free(dpun); dpun=NULL;
4723       }
4724    }
4725    /* Now get rid of nullness */
4726    for (i=0, inn=0; i<*N_ws; ++i) {
4727       if (ws[i]) {
4728          ws[inn] = ws[i];
4729          if (i!=inn) { ws[i]=NULL; }
4730          if (sc) {
4731             ff = sc[inn];
4732             sc[inn] = sc[i];
4733             sc[i] = ff;
4734          }
4735          if (D) {
4736             approx_str_diff_swap(D+inn,D+i);
4737          }
4738          ++inn;
4739       }
4740    }
4741 
4742    if(uopts && inn) { /* now get rid anything but the option and kill the dups */
4743       for (i=0; i<inn; ++i) {
4744          if (ws[i]) {
4745             c = 0;
4746             while (ws[i][c] != '\0' && !IS_BLANK(ws[i][c])) ++c;
4747             ws[i][c]='\0';
4748             ws[i] = (depunct_name(ws[i]));
4749          }
4750       }
4751       /* alphabetically sort that thing */
4752       isrt = z_istrqsort (ws, inn );
4753       if (isrt) free(isrt); isrt=NULL;
4754 
4755       c = 1;
4756       for (i=1; i<inn; ++i) {
4757          if (ws[i]){
4758             if (strcmp(ws[i], ws[c-1])) {/* new string, keep it */
4759                if (i != c) {
4760                   if (ws[c]) free(ws[c]);
4761                   ws[c] = ws[i];
4762                   ws[i]=NULL;
4763                }
4764                ++c;
4765             } else { /* repeat, just delete it */
4766                if (i != c) free(ws[i]); ws[i]=NULL;
4767             }
4768          }
4769       }
4770    }
4771 
4772    RETURN(ws);
4773 }
4774 
4775 /*
4776    See function approx_str_sort_all_popts() for warning about
4777    setting textinname to 1
4778 */
approx_str_sort_phelp(char * prog,int textinname,int * N_ws,char * str,byte ci,float ** sorted_score,APPROX_STR_DIFF_WEIGHTS * Dwi,APPROX_STR_DIFF ** Dout,int verb,char join_breaks)4779 char **approx_str_sort_phelp(char *prog, int textinname, int *N_ws, char *str,
4780                             byte ci, float **sorted_score,
4781                             APPROX_STR_DIFF_WEIGHTS *Dwi,
4782                             APPROX_STR_DIFF **Dout, int verb, char join_breaks)
4783 {
4784    char **ws=NULL;
4785    APPROX_STR_DIFF_WEIGHTS *Dw = Dwi;
4786    char cmd[512], tout[128], *stout=NULL;
4787 
4788    ENTRY("approx_str_sort_phelp");
4789 
4790    if (!prog || !str) RETURN(ws);
4791    if (sorted_score && *sorted_score) {
4792       ERROR_message("If sorted_score then *sorted_score should be NULL\n");
4793       RETURN(ws);
4794    }
4795 
4796    if (!textinname) {
4797       if (!phelp_cmd(prog, SPX, cmd, tout, verb )) {
4798          ERROR_message("Failed to get help command");
4799          RETURN(ws);
4800       }
4801       if (system(cmd)) {
4802          if (0){/*many programs finish help and set status afterwards. Naughty.*/
4803             ERROR_message("Failed to get help for %s\nCommand: %s\n", prog, cmd);
4804             return 0;
4805          }
4806       }
4807       stout = tout;
4808    } else {
4809       stout = prog;
4810    }
4811    ws = approx_str_sort_tfile(stout, textinname, N_ws, str, ci,
4812                               sorted_score, Dw, Dout, verb,  join_breaks);
4813 
4814    if (!textinname) {
4815       snprintf(cmd,500*sizeof(char),"\\rm -f %s", tout);
4816       system(cmd);
4817    }
4818    RETURN(ws);
4819 }
4820 
approx_str_sort_readmes(char * str,int * N_r)4821 char **approx_str_sort_readmes(char *str, int *N_r)
4822 {
4823    char **ws=NULL, strn[256]={"README."};
4824    THD_string_array *progs=NULL;
4825 
4826    ENTRY("approx_str_sort_readmes");
4827 
4828    *N_r=0;
4829 
4830    if (!str) RETURN(ws);
4831    if (strstr(str,strn)) str += strlen(strn);
4832    else if (str[0] == '.') str += 1;
4833 
4834    strncat(strn, str, (200-strlen(strn))*sizeof(char));
4835    if (!(progs = THD_get_all_afni_readmes())) {
4836       RETURN(ws);
4837    }
4838    ws = approx_str_sort(progs->ar, progs->num, strn,
4839                         1, NULL, 0, NULL, NULL);
4840    *N_r = progs->num;
4841    DESTROY_SARR(progs);
4842    RETURN(ws);
4843 }
4844 
suggest_best_prog_option(char * prog,char * str)4845 void suggest_best_prog_option(char *prog, char *str)
4846 {
4847    char **ws=NULL;
4848    int N_ws=0, i, isug, skip=0, isuglog=0, logit=0;
4849    float *ws_score=NULL;
4850    APPROX_STR_DIFF *D=NULL;
4851    char *cwsi=NULL;
4852    FILE *logfout=NULL;
4853 
4854    if (getenv("AFNI_NO_OPTION_HINT")) return;
4855    if (AFNI_yesenv("AFNI_LOG_BEST_PROG_OPTION")) logit = 1;
4856 
4857    if (str[0] != '-') {
4858       if (0) { /* leave it alone ... */
4859          fprintf(stderr,"'%s' might have be a parameter that is missing\n"
4860                         "a proper option flag preceding it.\n"
4861                         "Also make sure all preceding options have\n"
4862                         "the proper number of parameters.\n", str);
4863          return;
4864       }
4865    }
4866 
4867    /* prevent recursion of system commands if we are searching for a
4868     * non-existent -help (or similar) option     12 Apr 2017 [rickr] */
4869    if( ! strcmp(str, "-help") || ! strcmp(str, "-HELP") ) {
4870       fprintf(stderr,"** program %s does not seem to have a -help option...\n",
4871               prog);
4872       return;
4873    } else if( ! strncmp(str, "-h_", 3) ) {
4874       fprintf(stderr,"** suggest option: will not search for any '-h_' opts\n"
4875                      "   to recommend match for '%s %s'\n", prog, str);
4876       return;
4877    }
4878 
4879    ws = approx_str_sort_phelp(prog, 0, &N_ws, str,
4880                    1, &ws_score,
4881                    NULL, &D, 0, '\\');
4882    isug = 0; isuglog = 6;
4883    for (i=0; i<N_ws && (isug < 3 || isuglog < 6); ++i) {
4884       skip=0;
4885       if (str[0]=='-') { /* skip results that do not begin with - */
4886          cwsi = strdup(ws[i]);
4887          depunct_name(cwsi);
4888          if (cwsi[0]!='-') skip = 1;
4889          else if (!strncmp(cwsi,"- ",2) || !strncmp(cwsi,"---",3) ||
4890                  (strlen(str)>1 && str[1] != '-' && !strncmp(cwsi,"--",2)))
4891                      skip=1;
4892          free(cwsi); cwsi=NULL;
4893       }
4894 
4895       /* log before you decide on match quality skipping */
4896       if (logit) {
4897          if ((!logfout || isuglog < 6) && !skip) {
4898             if (!logfout) {
4899                if (!(logfout = fopen(THD_helpsearchlog(1),"a"))) logit = 0;
4900                isuglog = 0;
4901             }
4902             if (logfout) {
4903                if (!isuglog) {
4904                   char *tdate = tross_datetime();
4905                   fprintf(logfout,"popt(%s,%s); %s\n",prog,str, tdate);
4906                   free(tdate); tdate=NULL;
4907                }
4908                fprintf(logfout,"   %s: %s\n",
4909                   approx_string_diff_info(D+i, NULL),
4910                   ws[i]);
4911             }
4912             ++isuglog;
4913          }
4914       }
4915 
4916       /* Now do some crude match quality based skipping */
4917       if (!skip) {
4918          /* See if you have lousy scores */
4919          if ( (D[i].d[LEV] > 5 && D[i].d[PMD] > 5 && D[i].d[FCD] > 5) ) skip = 1;
4920       }
4921 
4922       if (isug<3 && !skip)  {
4923          if (!isug)
4924             fprintf(stderr,
4925       "   Here's hoping these excerpts from '%s -help' enlighten:\n",
4926                prog);
4927          fprintf(stderr,"        '%s'\n", ws[i]);
4928          ++isug;
4929       }
4930       free(ws[i]); ws[i]=NULL;
4931    } free(ws); ws = NULL;
4932    if (!isug) {
4933       fprintf(stderr,
4934    "   Could not suggest an option from '%s -help' and sleep well at night.\n"
4935    "   Try finding your option with '%s -all_opts',\n"
4936    "                                '%s -h_view',\n"
4937    "                or the good old '%s -help'\n",
4938                prog, prog, prog, prog);
4939    }
4940 
4941    if (logfout) fclose(logfout);
4942    if (ws_score) free(ws_score); ws_score=NULL;
4943    return;
4944 }
4945 
4946 
get_updated_help_file(int force_recreate,byte verb,char * progname,int shtp)4947 char *get_updated_help_file(int force_recreate, byte verb, char *progname,
4948                             int shtp)
4949 {
4950       static char hout[512]={""};
4951       char scomm[1024], *etr=NULL, *hdir=NULL, *etm=NULL, houtc[128];
4952       long long ml, mn;
4953       int cnt = 0;
4954 
4955       if (!(hdir = THD_get_helpdir(0))) {
4956          ERROR_message("Have no help directory\n");
4957          RETURN(hout);
4958       }
4959 
4960       etr = THD_trailname( progname , 0 ) ;
4961       if (!etr || strlen(etr) < 2) {
4962          WARNING_message("Fishy executable named %s\n",progname);
4963          return(hout);
4964       }
4965       etm = THD_filetime(progname);
4966       if (etm[0] == '\0') {
4967          etm = "NoTimeStamp";
4968       }
4969 
4970       snprintf(hout, 500*sizeof(char),
4971                "%s/%s.%s.help", hdir, etr, etm);
4972       snprintf(houtc, 120*sizeof(char),
4973                "%s/%s.complete", hdir, etr);
4974       if (!force_recreate && THD_is_file(hout)) {
4975          if (verb) fprintf(stderr,"Reusing %s \n", hout);
4976          if (!THD_is_file(houtc)) { /* this check will fail for bash completion,
4977                                        but that's not important */
4978             prog_complete_command(etr, houtc, shtp);
4979          }
4980       } else {
4981          if (verb) fprintf(stderr,"Creating %s \n", hout);
4982          /* The echo below is there to make programs that
4983             don't like -help and expect stdin to shut up and quit
4984             As a result, it is hard to get the status of -help
4985             command and use it wisely here without risking
4986             trouble */
4987          if (THD_is_file( hout)) {
4988             snprintf(scomm, 1000*sizeof(char),
4989                "chmod u+w %s > /dev/null 2>&1", hout);
4990             system(scomm);
4991          }
4992          snprintf(scomm, 1000*sizeof(char),
4993                "\\echo '' 2>&1 | %s -help > %s 2>&1 &", etr, hout);
4994          system(scomm);
4995 
4996          /* wait a little to finish writing*/
4997          mn = THD_filesize(hout); cnt = 0;
4998          do {
4999             ml = mn;
5000             NI_sleep(50);
5001             mn = THD_filesize(hout);
5002             ++cnt;
5003          } while (ml != mn && cnt < 20);
5004 
5005          snprintf(scomm, 1000*sizeof(char),
5006                "chmod a-w %s > /dev/null 2>&1", hout);
5007          system(scomm);
5008          prog_complete_command(etr, houtc, shtp);
5009       }
5010       return(hout);
5011 }
5012 
5013 
5014 /* Trim string lbl to a maximum of mxlen characters.
5015    If mxlen <= 0 mxlen = 20
5016    Do not free what you get back, it might be lbl if
5017    nothing needs to be done.*/
5018 #define MaxTrim 128
TrimString(char * lbl,int mxlen)5019 char *TrimString(char *lbl, int mxlen)
5020 {
5021    char *shrtit = NULL, *shrtitp = NULL, *eee=NULL;
5022    int meth = 0, strt=0;
5023    static int icall=0;
5024    static char res[5][MaxTrim+1];
5025 
5026    ENTRY("TrimString");
5027 
5028    ++icall;
5029    if (icall > 4) icall = 0;
5030    res[icall][0]='\0';
5031    res[icall][MaxTrim]='\0'; /* be safe */
5032 
5033    if (mxlen <= 0) mxlen = 20;
5034    if (mxlen > MaxTrim) {
5035       WARNING_message(
5036                "Max trim length is 128. Ignoring your wishes of %d\n"
5037                "What kind of a trim is this? What is wrong with you?\n",
5038                       mxlen);
5039       mxlen = MaxTrim;
5040    }
5041    if (!lbl) RETURN(res[icall]);
5042    if (strlen(lbl) > mxlen) {
5043       shrtit = strdup(lbl);
5044       shrtitp = shrtit;
5045       meth = 0;
5046       do {
5047          /* fprintf(stderr,"ZSS: meth %d, shrtit=>%s<%d (mx%d)\n",
5048                         meth, shrtit, (int)strlen(shrtit), mxlen); */
5049          switch (meth) {
5050             case 0: /* remove the path */
5051                shrtit = THD_trailname(shrtit,0);
5052                break;
5053             case 1: /* trim up to blank, starting from end */
5054                if ((eee = strchr(shrtit,' '))) {
5055                   strt = strlen(shrtit)-1;
5056                   while (strt > mxlen || (strt > 0 && strlen(shrtit) > mxlen)) {
5057                      if (shrtit[strt]==' ') {
5058                         shrtit[strt] = '\0';
5059                         strt = strlen(shrtit)-1;
5060                      } else {
5061                         --strt;
5062                      }
5063                   }
5064                }
5065                break;
5066             case 2: /* get rid of extension */
5067                if ((eee =  find_filename_extension(shrtit))) {
5068                   shrtit[strlen(shrtit)-strlen(eee)]='\0';
5069                }
5070                break;
5071             case 3: /* get rid of view */
5072                shrtit = THD_deplus_prefix(shrtit);
5073                free(shrtitp); shrtitp=shrtit;
5074                break;
5075             case 4: /* get rid of characters from the left */
5076                shrtit = shrtit+(strlen(shrtit)-mxlen);
5077                shrtit[0]='~';
5078                break;
5079             default:
5080                meth=-12345;
5081                break;
5082          }
5083          ++meth;
5084       } while (strlen(shrtit) > mxlen && meth >= 0);
5085 
5086       /* fill up the result and free what is not yours to keep*/
5087       strncpy(res[icall], shrtit, mxlen);
5088       res[icall][mxlen]='\0';/* lazy strncpy might not bother to terminate*/
5089       if (shrtitp) free(shrtitp); shrtitp=NULL;
5090    } else {
5091       RETURN(lbl);
5092    }
5093    RETURN(res[icall]);
5094 }
5095 
print_prog_options(char * prog)5096 void print_prog_options(char *prog)
5097 {
5098    char **ws=NULL;
5099    int N_ws=0, i;
5100    float *ws_score=NULL;
5101 
5102    if (!(ws = approx_str_sort_all_popts(prog, 0, &N_ws,
5103                    1, &ws_score,
5104                    NULL, NULL, 0, 1, '\\'))) {
5105       return;
5106    }
5107    for (i=0; i<N_ws; ++i) {
5108       if (ws[i]) {
5109          fprintf(stdout, "   %s\n", ws[i]);
5110          free(ws[i]); ws[i]=NULL;
5111       }
5112    } free(ws); ws = NULL;
5113 
5114    if (ws_score) free(ws_score); ws_score=NULL;
5115    return;
5116 }
5117 
5118 
5119 
best_approx_str_match(char ** words,int N_words,char * str,byte ci,APPROX_STR_DIFF_WEIGHTS * Dwi)5120 float best_approx_str_match(char **words, int N_words, char *str,
5121                           byte ci, APPROX_STR_DIFF_WEIGHTS *Dwi)
5122 {
5123    int i;
5124    float dm=388923774899384.0;
5125    APPROX_STR_DIFF D, Dm;
5126    APPROX_STR_DIFF_WEIGHTS *Dw = Dwi;
5127 
5128    ENTRY("best_approx_str_match");
5129 
5130    if (!words || !N_words || !str) RETURN(dm);
5131    if (!Dw) Dw = init_str_diff_weights(Dw);
5132    init_str_diff(&D); init_str_diff(&Dm);
5133    for (i=0; i<N_words; ++i) {
5134       D = LevenshteinStringDistance(words[i], str, ci);
5135       dm = set_smallest_str_diff(&Dm, D, Dm, *Dw, NULL);
5136    }
5137    if (Dw != Dwi) free(Dw); Dw=NULL;
5138 
5139    RETURN(dm);
5140 }
5141 
5142 /*!
5143    A demo function to illustrate the use of approximate string matching
5144 */
test_approx_str_match(void)5145 void test_approx_str_match(void)
5146 {
5147    char *lot[] = { "Bafni", "avni", "afjni", "aifn", "AfNi", NULL };
5148    char key[64]={"afni"};
5149    char **slot=NULL;
5150    int i=0, n_lot=0;
5151    float *slot_score=NULL;
5152    char text[]={"The quick brown fox\n"
5153                 " Jumped over the lazy dog\n"
5154                 "\n"
5155                 "did he?\n"
5156                 "He did he did\n"
5157                 "\n"
5158                 " I tell you   \n"
5159                 "\n "};
5160    APPROX_STR_DIFF_WEIGHTS *Dw = NULL;
5161    APPROX_STR_DIFF D, *Dv=NULL;
5162 
5163    while (lot[n_lot]) ++n_lot;
5164 
5165    if (!Dw) Dw = init_str_diff_weights(Dw);
5166 
5167    i=0;
5168    while (lot[i]) {
5169       D = LevenshteinStringDistance(lot[i],key,0);
5170       fprintf(stdout,"Score %03f: %s v.s. %s\n",
5171             magnitude_str_diff(&D, Dw),
5172             lot[i],key);
5173       ++i;
5174    }
5175 
5176    i=0;
5177    while (lot[i]) {
5178       D = LevenshteinStringDistance(lot[i],key,1);
5179       fprintf(stdout,"CI Score %03f: %s v.s. %s\n",
5180             magnitude_str_diff(&D, Dw),
5181             lot[i],key);
5182       ++i;
5183    }
5184 
5185    fprintf(stdout,"Score   Strings (sorted)\n");
5186    slot = approx_str_sort(lot, n_lot, key, 0, &slot_score, 0, NULL, NULL);
5187    for (i=0; i<n_lot; ++i) {
5188       fprintf(stdout,"%02f- %s\n", slot_score[i], slot[i]);
5189       free(slot[i]);
5190    } free(slot);  free(slot_score); slot_score=NULL;
5191 
5192    fprintf(stdout,"Score   Strings (CI sorted)\n");
5193    slot = approx_str_sort(lot, n_lot, key, 1, &slot_score, 0, NULL, NULL);
5194    for (i=0; i<n_lot; ++i) {
5195       fprintf(stdout,"%02f- %s\n", slot_score[i], slot[i]);
5196       free(slot[i]);
5197    } free(slot);  free(slot_score); slot_score=NULL;
5198 
5199    /* Sort multi-line text string */
5200    sprintf(key,"dib");
5201    slot = approx_str_sort_text(text, &n_lot, key, 1,
5202                                &slot_score, NULL, &Dv, '\0');
5203    for (i=0; i<n_lot; ++i) {
5204       fprintf(stdout,"%02f- %s\n", slot_score[i], slot[i]);
5205       free(slot[i]);
5206    }
5207    free(slot);  free(slot_score); slot_score=NULL;
5208    free(Dv); Dv = NULL;
5209 
5210 }
5211 
5212 /***
5213    END Functions for approximate string matching
5214 ***/
5215 
5216 /*!
5217    Return a byte mask for a particular atlas region
5218 */
Atlas_Region_Mask(AFNI_ATLAS_REGION * aar,int * codes,int n_codes,ATLAS_LIST * atlas_list)5219 THD_3dim_dataset *Atlas_Region_Mask(AFNI_ATLAS_REGION *aar,
5220                                     int *codes, int n_codes,
5221                                     ATLAS_LIST *atlas_list)
5222 {
5223    short *ba=NULL;
5224    int LocalHead = wami_lh();
5225    byte *bba = NULL;
5226    float *fba = NULL;
5227    byte *bmask = NULL;
5228    int ii=0, sb, nxyz, kk, ll = 0, fnd = -1, fnd2=-1;
5229    int ba_val, dset_kind, have_brik;
5230    THD_3dim_dataset * maskset = NULL;
5231    char madeupname[500], madeuplabel[40];
5232    ATLAS *atlas=NULL;
5233    float fval;
5234 
5235    ENTRY("Atlas_Region_Mask");
5236 
5237    if (!codes || n_codes == 0 || !aar || !aar->atlas_name) {
5238       ERROR_message("Nothing to do");
5239       RETURN(NULL);
5240    }
5241 
5242    if (LocalHead) {
5243       fprintf(stderr,"Looking for %d codes: \n   ", n_codes);
5244       for (kk=0; kk<n_codes; ++kk) {
5245          fprintf(stderr,"%d   ", codes[kk]);
5246       }
5247       fprintf(stderr,"\n");
5248    }
5249 
5250    if (!(atlas = Atlas_With_Trimming (aar->atlas_name, 1, atlas_list))) {
5251       ERROR_message("Failed getting atlas for mask");
5252       RETURN(NULL);
5253    }
5254 
5255    if (LocalHead)
5256       fprintf(stderr,"Found atlas for mask\n   ");
5257 
5258    nxyz = DSET_NX(ATL_DSET(atlas)) *
5259           DSET_NY(ATL_DSET(atlas)) * DSET_NZ(ATL_DSET(atlas));
5260    if (!(bmask = (byte *)calloc(nxyz, sizeof(byte)))) {
5261       ERROR_message("Failed to allocate for mask");
5262       RETURN(maskset);
5263    }
5264 
5265    if (!is_probabilistic_atlas(atlas)) {
5266       for (sb=0; sb < DSET_NVALS(ATL_DSET(atlas)); ++sb) {
5267          dset_kind = DSET_BRICK_TYPE(ATL_DSET(atlas),sb);
5268          if (DSET_BRICK_FACTOR(ATL_DSET(atlas),sb) != 0.0 &&
5269              DSET_BRICK_FACTOR(ATL_DSET(atlas),sb) != 1.0) {
5270             ERROR_message("Atlas dset %s'[%d]' has a brick factor of %f!\n",
5271                   Atlas_Name(atlas), sb, DSET_BRICK_FACTOR(ATL_DSET(atlas),sb));
5272             free(bmask); bmask = NULL;
5273             RETURN(maskset);
5274          }
5275          switch(dset_kind) {
5276             case MRI_short :
5277                ba = DSET_BRICK_ARRAY(ATL_DSET(atlas),sb); /* short type */
5278                if (!ba) {
5279                   ERROR_message("Unexpected NULL array");
5280                   free(bmask); bmask = NULL;
5281                   RETURN(maskset);
5282                }
5283                break;
5284             case MRI_byte:
5285                bba = DSET_BRICK_ARRAY(ATL_DSET(atlas),sb); /* byte array */
5286                if (!bba) {
5287                   ERROR_message("Unexpected NULL array");
5288                   free(bmask); bmask = NULL;
5289                   RETURN(maskset);
5290                }
5291                break;
5292             case MRI_float:
5293                if (LocalHead)
5294                   fprintf(stderr,"A float typed atlas? What's the big idea?\n");
5295                fba = DSET_BRICK_ARRAY(ATL_DSET(atlas),sb); /* byte array */
5296                if (!fba) {
5297                   ERROR_message("Unexpected NULL array");
5298                   free(bmask); bmask = NULL;
5299                   RETURN(maskset);
5300                }
5301                break;
5302             default:
5303                ERROR_message("Bad dset type (%d) for %s", Atlas_Name(atlas));
5304                free(bmask); bmask = NULL;
5305                RETURN(maskset);
5306          }
5307 
5308          for (kk=0; kk < n_codes; ++kk) {
5309             for (ii=0; ii< nxyz; ++ii) {
5310                if (dset_kind == MRI_short)
5311                   ba_val = (int) ba[ii];
5312                else if (dset_kind == MRI_byte)
5313                   ba_val = (int) bba[ii];
5314                else if (dset_kind == MRI_float)
5315                   ba_val = (int) fba[ii];
5316                else {
5317                   ERROR_message("Bad dset type (%d) for %s. Should not be here!",                                 Atlas_Name(atlas));
5318                   free(bmask); bmask = NULL;
5319                   RETURN(maskset);
5320                }
5321                /* if voxel value matches code value
5322                   make byte mask 1 at that voxel */
5323                if (ba_val == codes[kk]) bmask[ii] = 1;
5324                 /* used to assign bmask[ii] = codes[kk]; */
5325             }
5326          }
5327 
5328       }
5329    } else { /* got to dump a particular sub-brick for probability maps*/
5330       if (LocalHead) INFO_message("Speciality");
5331 
5332       /* assume all sub-bricks are the same type */
5333       dset_kind = DSET_BRICK_TYPE(ATL_DSET(atlas),0);
5334 
5335       for (kk=0; kk < n_codes; ++kk) {
5336          /* find label to go with code */
5337          ll = 0;
5338          fnd = -1;
5339          while (ll<DSET_NVALS(ATL_DSET(atlas)) && fnd < 0) {
5340             if (atlas->adh->apl2->at_point[ll].tdval == codes[kk]) fnd = ll;
5341             else ++ll;
5342          }
5343          if (fnd < 0) {
5344             ERROR_message("Unexpected negative find");
5345             free(bmask); bmask = NULL; RETURN(maskset); }
5346 
5347          if (LocalHead)
5348             INFO_message("Looking for sub-brick labeled %s\n",
5349                 Clean_Atlas_Label(atlas->adh->apl2->at_point[fnd].sblabel));
5350          fnd2 = -1;
5351          sb = 0;
5352          while (sb < DSET_NVALS(ATL_DSET(atlas)) && fnd2 < 0) {
5353             /* sb in question should be nothing but fnd.
5354                But be careful nonetheless */
5355             if (DSET_BRICK_LAB(ATL_DSET(atlas),sb) &&
5356              !strcmp(DSET_BRICK_LAB(ATL_DSET(atlas),sb),
5357                Clean_Atlas_Label(atlas->adh->apl2->at_point[fnd].sblabel)))
5358                  fnd2 = sb;
5359             else ++sb;
5360          }
5361          if (fnd2 < 0) {
5362              ERROR_message("Unexpected negative find");
5363              free(bmask); bmask = NULL; RETURN(maskset);
5364          }
5365 
5366          /* fill byte mask with values wherever probability is non-zero */
5367          have_brik = 0;
5368          switch(dset_kind) {
5369            case MRI_short :
5370               ba = DSET_BRICK_ARRAY(ATL_DSET(atlas),fnd2); /* short type */
5371               if (ba) {
5372                  have_brik = 1;
5373                  for (ii=0; ii< nxyz; ++ii) {
5374                     fval = (float) ba[ii];
5375                     if(fval>1.0) fval = fval / Get_PMap_Factor(); /* if >1.0, must be old pmap atlases*/
5376                     if(fval<get_wami_minprob()) fval = 0.0; /* check against minimum probability */
5377                     if (fval>0.0) bmask[ii] = ba[ii];
5378                  }
5379               }
5380               break;
5381            case MRI_byte :
5382               bba = DSET_BRICK_ARRAY(ATL_DSET(atlas),fnd2); /* byte array */
5383               if (bba) {
5384                  have_brik = 1;
5385                  for (ii=0; ii< nxyz; ++ii) {
5386                     fval = (float) bba[ii];
5387                     if(fval>1.0) fval = fval / Get_PMap_Factor(); /* if >1.0, must be old pmap atlases*/
5388                     if(fval<get_wami_minprob()) fval = 0.0; /* check against minimum probability */
5389                     if (fval>0.0) bmask[ii] = bba[ii];
5390                  }
5391               }
5392               break;
5393            case MRI_float : /* floating point probability */
5394               fba = DSET_BRICK_ARRAY(ATL_DSET(atlas),fnd2);/* float array */
5395               if (fba) {
5396                  have_brik = 1;
5397                  for (ii=0; ii< nxyz; ++ii) {
5398                     fval = (float) fba[ii];
5399                     if(fval<get_wami_minprob()) fval = 0.0; /* check against minimum probability */
5400                     if (fval>0.0) bmask[ii] = 1;
5401                  }
5402               }
5403               break;
5404            default :
5405               ERROR_message("Unexpected data type for probability maps");
5406          }
5407 
5408          if(have_brik==0){
5409              ERROR_message("Could not get sub-brick from probability atlas");
5410              free(bmask); bmask = NULL; RETURN(maskset);
5411          }
5412       }
5413    }
5414 
5415    /* Now trim the LR business, if required. */
5416    if (aar->side == 'l' || aar->side == 'r') {
5417       for (ii=0; ii<nxyz; ++ii) {
5418          if ( bmask[ii] &&
5419         Atlas_Voxel_Side(ATL_DSET(atlas), ii,
5420                          atlas->adh->lrmask) != aar->side )
5421             bmask[ii] = 0;
5422       }
5423       snprintf(madeupname, 400*sizeof(char), "%s.%s.%c",
5424                atlas->name,
5425                Clean_Atlas_Label_to_Prefix(
5426                         Clean_Atlas_Label(aar->orig_label)), aar->side);
5427       snprintf(madeuplabel, 36*sizeof(char), "%c.%s", aar->side,
5428             Clean_Atlas_Label_to_Prefix(Clean_Atlas_Label(aar->orig_label)));
5429    } else {
5430       snprintf(madeupname, 400*sizeof(char), "%s.%s",
5431               atlas->name,
5432               Clean_Atlas_Label_to_Prefix(Clean_Atlas_Label(
5433                                                    aar->orig_label)));
5434       snprintf(madeuplabel, 36*sizeof(char), "%s",
5435             Clean_Atlas_Label_to_Prefix(Clean_Atlas_Label(aar->orig_label)));
5436    }
5437 
5438    /* Now form the output mask dataset */
5439 
5440    maskset = EDIT_empty_copy( ATL_DSET(atlas) ) ;
5441    EDIT_dset_items(  maskset,
5442                        ADN_prefix    , madeupname ,
5443                        ADN_datum_all , MRI_byte ,
5444                        ADN_nvals     , 1 ,
5445                        ADN_ntt       , 0 ,
5446                        ADN_func_type ,
5447                         ISANAT(ATL_DSET(atlas)) ?
5448                                        atlas->adh->adset->func_type
5449                                        : FUNC_FIM_TYPE ,
5450                        ADN_brick_label_one, madeuplabel,
5451                        ADN_directory_name , "./" ,
5452                        ADN_none ) ;
5453 
5454    EDIT_substitute_brick( maskset , 0 , MRI_byte , bmask ) ;
5455 
5456    /* all done */
5457    RETURN(maskset);
5458 }
5459 
5460 /*!
5461    Try to locate a region in an atlas.
5462 
5463    "left" and "right" strings are not used in the matching.
5464 
5465    Returns a search struct containing
5466    array (as->iloc) of integers that is aa->N_regions long
5467    aa->reg[as->iloc[0]]->orig_label is the best match if as->nmatch is > 0
5468    aa->reg[as->iloc[1]]->orig_label is the second best match, etc.
5469 
5470    if ur->id > 0 && ur->N_chnks == 0 : An exact search is done based on ur->id
5471 
5472    Returned struct must be freed by the user (Free_Atlas_Search), but can be re-used by
5473    passing it as the last parameter.
5474 */
Find_Atlas_Regions(AFNI_ATLAS * aa,AFNI_ATLAS_REGION * ur,ATLAS_SEARCH * reusethis)5475 ATLAS_SEARCH * Find_Atlas_Regions(AFNI_ATLAS *aa, AFNI_ATLAS_REGION *ur , ATLAS_SEARCH *reusethis )
5476 {
5477    int chnk_match[500], bs = 0;
5478    int k = 0, iu=0, lu=0, lr=0, ir=0, MinAcc=0, ngood = 0;
5479    ATLAS_SEARCH *as=NULL;
5480 
5481    ENTRY("Find_Atlas_Regions");
5482 
5483    if (!aa || !ur) {
5484       ERROR_message("NULL input");
5485       RETURN(as);
5486    }
5487 
5488    if (reusethis) as = reusethis;
5489    else {
5490       as = (ATLAS_SEARCH *)calloc(1, sizeof(ATLAS_SEARCH));
5491       as->iloc = (int *)calloc(aa->N_regions, sizeof(int));
5492       as->score = (float *)calloc(aa->N_regions, sizeof(float));
5493       as->N = aa->N_regions;
5494       as->nmatch = 0;
5495    }
5496 
5497    if (as->N < aa->N_regions) {
5498       ERROR_message("Reused as structure too small for this atlas!");
5499       RETURN(Free_Atlas_Search(as));
5500    }
5501 
5502    /* do we have a search by number ? */
5503    if (ur->id > 0 && ur->N_chnks == 0) {
5504       /* search by id */
5505       as->nmatch = 0;
5506       for (k=0; k<aa->N_regions; ++k) {/* aa->N_regions */
5507          if (aa->reg[k]->id == ur->id) { /* found */
5508             as->iloc[as->nmatch] = k;
5509             ++as->nmatch;
5510          }
5511       }
5512       RETURN(as);
5513    }
5514 
5515 
5516    /* Compare each region to input */
5517    for (k=0; k<aa->N_regions; ++k) {/* aa->N_regions */
5518       as->score[k] = 0.0; /* as->score of match for particular region */
5519       for (iu=0; iu < ur->N_chnks; ++iu) {  /* for each chunk in the user input */
5520          /* find best chunk match in atlas region, no regard for ordering of chunks */
5521          lu = strlen(ur->chnks[iu]);
5522          for (ir=0; ir < aa->reg[k]->N_chnks; ++ir) {
5523             chnk_match[ir] = 0; /* how well does atlas region chunk ir match with user chunk */
5524             lr = strlen(aa->reg[k]->chnks[ir]);
5525             if (strncmp(ur->chnks[iu], aa->reg[k]->chnks[ir], MIN_PAIR( lu, lr)) == 0) {
5526                /* one of the strings is inside the other */
5527                if (lu == lr) { /* identical match */
5528                     chnk_match[ir] = 4;
5529                } if (lu < lr) { /* user provided subset */
5530                   chnk_match[ir] = 2;
5531                } if (lu > lr) { /* user provided superset */
5532                   chnk_match[ir] = 1;
5533                }
5534                if (iu == ir )   /* matching on the same chunk counts more! */
5535                  chnk_match[ir]++;
5536 
5537                /* fprintf(stderr,"User string %s, Region %s: match = %d\n",
5538                   ur->chnks[iu], aa->reg[k]->chnks[ir],chnk_match[ir]);*/
5539             }
5540          }
5541          /* keep the best match for iu */
5542          bs = 0;
5543          for (ir=0; ir < aa->reg[k]->N_chnks; ++ir) {
5544             if (bs < chnk_match[ir]) bs = chnk_match[ir];
5545          }
5546          if (!bs) {
5547             /* user provided a chunk that matched nothing, penalize!
5548                (you might want to skip penalty for first chunks,
5549                if they are l,r, left, or right ...) */
5550             if (  0 && iu == 0 &&
5551                   (  strcmp("l",ur->chnks[0]) == 0 ||
5552                      strcmp("l",ur->chnks[0]) == 0 ||
5553                      strcmp("l",ur->chnks[0]) == 0 ||
5554                      strcmp("l",ur->chnks[0]) == 0 ) ) {
5555                /* clemency please*/
5556                bs = 0;
5557             } else { /* big penalty if user provides bad clues */
5558                bs = -4;
5559             }
5560          }
5561 
5562          /* add the as->score contribution for this chunk */
5563          as->score[k] += (float)bs;
5564       }
5565       /* small penalty if number of chunks is larger in label */
5566       if (aa->reg[k]->N_chnks - ur->N_chnks > 0) {
5567          as->score[k] -= (aa->reg[k]->N_chnks - ur->N_chnks);
5568       }
5569       /* bias by side matching */
5570       if (SIDE_MATCH(ur->side, aa->reg[k]->side)) {
5571          ++as->score[k];
5572       }
5573       /* fprintf (stderr,"Region %s as->scored %f with %s\n",  aa->reg[k]->orig_label, as->score[k], ur->orig_label);  */
5574    }
5575 
5576    /* sort the as->scores, largest to smallest */
5577    {
5578       int *itmp = NULL;
5579       itmp = z_iqsort(as->score, aa->N_regions);
5580       if (itmp) {
5581          memcpy((void*)as->iloc, (void *)itmp, aa->N_regions*sizeof(int));
5582          free(itmp); itmp = NULL;
5583       }else {
5584          ERROR_message("Error sorting!");
5585          RETURN(Free_Atlas_Search(as));
5586       }
5587    }
5588 
5589    /* show results where at least all chunks had partial match */
5590    k = 0;
5591    ngood = 0;
5592    MinAcc = 2*ur->N_chnks; /* the least acceptable value should be a partial match for user supplied chunk */
5593    while (as->score[k] >= MinAcc && k < aa->N_regions) {
5594       /* fprintf (stderr,"Match %d for %s is %s at as->score %f\n", k, ur->orig_label, aa->reg[as->iloc[k]]->orig_label, as->score[k]); */
5595       ++ngood;
5596       ++k;
5597    }
5598 
5599    if (!ngood) {
5600       /* fprintf (stderr,  "No match for %s\n", ur->orig_label); */
5601       if (as->score[0] > 0 && as->score[0] > as->score[5]) { /* maybe some useful suggestions */
5602          /* fprintf (stderr,  "Closest few guesses:\n"); */
5603          k = 0;
5604          while (as->score[k] == as->score[0] && k < 5) {
5605             /* fprintf (stderr,  "   %s, as->score %f\n", aa->reg[as->iloc[0]]->orig_label, as->score[k]); */
5606             ++k;
5607          }
5608       } else {
5609          /* fprintf (stderr,  "   I don't even have good suggestions.\n"
5610                            "   Try to be more explicit.\n"); */
5611       }
5612 
5613       as->nmatch = 0;
5614    } else {
5615       if (as->score[0] > as->score[1]) { /* unique best fit */
5616          /* fprintf (stderr,"Best match for %s is %s (code %d)\n",
5617                      ur->orig_label, aa->reg[as->iloc[0]]->orig_label, aa->reg[as->iloc[0]]->id); */
5618          as->nmatch = 1;
5619       } else {
5620          k=0;
5621          /* fprintf (stderr,"Potential match for %s:\n", ur->orig_label); */
5622          while (as->score[k] == as->score[0] && k<aa->N_regions) {
5623             /* fprintf (stderr,"         %s (code %d):\n", aa->reg[as->iloc[k]]->orig_label, aa->reg[as->iloc[k]]->id); */
5624             as->nmatch += 1;
5625             ++k;
5626          }
5627       }
5628    }
5629 
5630 
5631    RETURN(as);
5632 }
5633 
Atlas_Prob_String(float p)5634 char * Atlas_Prob_String(float p)
5635 {
5636    static char probs[256];
5637 
5638    if (p == -2.0) {
5639       sprintf(probs," MPM");
5640    } else if (p == -1.0) {
5641       sprintf(probs," ---");
5642    } else {
5643       sprintf(probs,"%.2f", p);
5644    }
5645    return(probs);
5646 
5647 }
5648 
Atlas_Code_String(int c)5649 char * Atlas_Code_String(int c)
5650 {
5651    static char codes[256];
5652 
5653    if (c == -1) {
5654       sprintf(codes,"---");
5655    } else {
5656       sprintf(codes,"%3d", c);
5657    }
5658    return(codes);
5659 
5660 }
5661 
5662 /* this function strips off trailing periods ......
5663  * and puts the result in a static string.
5664  * this was relevant for the original hard coded atlases like the Talairach Daemon
5665 * not so interesting today */
Clean_Atlas_Label(char * lb)5666 char * Clean_Atlas_Label( char *lb)
5667 {
5668    static char lab_buf[256];
5669    int nlab=0, nn=0;
5670 
5671    ENTRY("Clean_Atlas_Label");
5672 
5673    lab_buf[0] = '\0';
5674 
5675    if (!lb) {
5676       ERROR_message("NULL input!\n");
5677       RETURN(lab_buf);
5678    }
5679 
5680    nlab = strlen(lb);
5681    if (nlab > 250) {
5682       ERROR_message("Dset labels too long!\n");
5683       RETURN(lab_buf);
5684    }
5685 
5686    nn = nlab-1;
5687    while (nn >=0 && lb[nn] == '.') --nn;
5688 
5689 
5690    nlab = nn;
5691    nn = 0;
5692    if (nlab) {
5693       while (nn<=nlab) {
5694          lab_buf[nn] = lb[nn];
5695          ++nn;
5696       }
5697       lab_buf[nn] = '\0';
5698    }
5699 
5700    /* fprintf(stderr,"lbl = %s, clean = %s\n", lb, lab_buf); */
5701    RETURN(lab_buf);
5702 }
5703 
Clean_Atlas_Label_to_Prefix(char * lb)5704 char * Clean_Atlas_Label_to_Prefix( char *lb)
5705 {
5706    static char lab_buf[256];
5707    int nn=0, cnt=0, nlab=0, notnum = 0;
5708 
5709    ENTRY("Clean_Atlas_Label_to_Prefix");
5710 
5711    lab_buf[0] = '\0';
5712 
5713    nlab = strlen(lb);
5714    if (nlab > 250) {
5715       ERROR_message("Dset labels too long!\n");
5716       RETURN(lab_buf);
5717    }
5718 
5719    /* do we have an integer label ? */
5720    notnum=0;
5721    nn=0;
5722    while (lb[nn] != '\0' && !notnum) {
5723       if (!IS_NUMBER(lb[nn])) notnum = 1;
5724       ++nn;
5725    }
5726    if (!notnum) {
5727       sprintf(lab_buf,"%d",atoi(lb));
5728       RETURN(lab_buf);
5729    }
5730 
5731    /* Not an integer label ... */
5732    cnt=0;
5733    for (nn=0; nn<nlab; ++nn) {
5734       if (!IS_LETTER(lb[nn]) && lb[nn] != '-' && lb[nn] != '_' && lb[nn] != '.') {
5735          if (cnt==0 || lab_buf[cnt-1] != '_') {
5736             lab_buf[cnt] = '_';
5737             ++cnt;
5738          }
5739       } else {
5740          lab_buf[cnt] = lb[nn];
5741          ++cnt;
5742       }
5743    }
5744 
5745    lab_buf[cnt] = '\0';
5746 
5747    RETURN(lab_buf);
5748 }
5749 
Space_Code_to_Space_Name(AFNI_STD_SPACES cod)5750 const char *Space_Code_to_Space_Name (AFNI_STD_SPACES cod)
5751 {
5752    ENTRY("Space_Code_to_Space_Name");
5753 
5754    switch(cod) {
5755       case UNKNOWN_SPC:
5756          RETURN("Unknown");
5757       case AFNI_TLRC_SPC:
5758          RETURN("TLRC");
5759       case MNI_SPC:
5760          RETURN("MNI");
5761       case MNI_ANAT_SPC:
5762          RETURN("MNI_ANAT");
5763       case NUMBER_OF_SPC:
5764          RETURN("Flag for number of spaces");
5765       default:
5766          RETURN("Willis?");
5767    }
5768 
5769    RETURN("No way Willis.");
5770 }
5771 
Atlas_Code_to_Atlas_Dset_Name(AFNI_ATLAS_CODES cod)5772 const char *Atlas_Code_to_Atlas_Dset_Name (AFNI_ATLAS_CODES cod)
5773 {
5774    ENTRY("Atlas_Code_to_Atlas_Dset_Name");
5775 
5776    /* this function should only be called when no global niml file exists*/
5777    if (wami_verb()) WARNING_message("OBSOLETE, do NOT use anymore");
5778 
5779    switch(cod) {
5780       case UNKNOWN_ATLAS:
5781          RETURN("Unknown ");
5782       case AFNI_TLRC_ATLAS:
5783          RETURN(TT_DAEMON_TT_PREFIX);
5784       case CA_EZ_N27_MPM_ATLAS:
5785          RETURN(CA_EZ_N27_MPM_TT_PREFIX);
5786       case CA_EZ_N27_ML_ATLAS:
5787          RETURN(CA_EZ_N27_ML_TT_PREFIX);
5788       case CA_EZ_N27_LR_ATLAS:
5789          RETURN(CA_EZ_N27_LR_TT_PREFIX);
5790       case CA_EZ_N27_PMAPS_ATLAS:
5791          RETURN(CA_EZ_N27_PMaps_TT_PREFIX);
5792       case CUSTOM_ATLAS :
5793         RETURN(CUSTOM_ATLAS_PREFIX);
5794       case NUMBER_OF_ATLASES:
5795          RETURN("Flag for number of atlases");
5796       default:
5797          RETURN("Bert?");
5798    }
5799 
5800    RETURN("No way Bert.");
5801 }
5802 
Atlas_Dset_Name_to_Atlas_Code(char * dset_name)5803 AFNI_ATLAS_CODES Atlas_Dset_Name_to_Atlas_Code (char *dset_name)
5804 {
5805    int LocalHead = wami_lh();
5806 
5807    ENTRY("Atlas_Dset_Name_to_Atlas_Code");
5808 
5809    if( ! dset_name ) RETURN(UNKNOWN_ATLAS);
5810 
5811    INFO_message("OBsoLETE, do NOT use anymore");
5812 
5813    if (LocalHead)
5814       INFO_message("Finding code from dataset name >%s<"
5815                    "Pick from: %s,%s,%s,%s,%s,%s\n",
5816                    dset_name, TT_DAEMON_TT_PREFIX, CA_EZ_N27_MPM_TT_PREFIX,
5817                    CA_EZ_N27_ML_TT_PREFIX, CA_EZ_N27_LR_TT_PREFIX,
5818                    CA_EZ_N27_PMaps_TT_PREFIX, CUSTOM_ATLAS_PREFIX);
5819    if(strstr(dset_name, TT_DAEMON_TT_PREFIX)){
5820       if(LocalHead)
5821          INFO_message("%s for AFNI_TLRC_ATLAS %d",dset_name,AFNI_TLRC_ATLAS);
5822       RETURN(AFNI_TLRC_ATLAS);
5823    }
5824    if(strstr(dset_name, CA_EZ_N27_MPM_TT_PREFIX))
5825       RETURN(CA_EZ_N27_MPM_ATLAS);
5826    if(strstr(dset_name, CA_EZ_N27_ML_TT_PREFIX))
5827       RETURN(CA_EZ_N27_ML_ATLAS);
5828    if(strstr(dset_name, CA_EZ_N27_LR_TT_PREFIX))
5829       RETURN(CA_EZ_N27_LR_ATLAS);
5830    if(strstr(dset_name, CA_EZ_N27_PMaps_TT_PREFIX))
5831       RETURN(CA_EZ_N27_PMAPS_ATLAS);
5832    if(strstr(dset_name, CUSTOM_ATLAS_PREFIX))
5833       RETURN(CUSTOM_ATLAS);
5834    RETURN(UNKNOWN_ATLAS);
5835 }
5836 
Atlas_Code_to_Atlas_Name(AFNI_ATLAS_CODES cod)5837 char *Atlas_Code_to_Atlas_Name (AFNI_ATLAS_CODES cod)
5838 {
5839    int LocalHead = wami_lh();
5840 
5841    ENTRY("Atlas_Code_to_Atlas_Name");
5842 
5843    if (wami_verb())
5844       WARNING_message("Only for old style loading (no niml)."
5845                       "Don't allow ATLAS_LIST *");
5846 
5847    if (LocalHead) fprintf(stderr,"code in: %d (%d)\n", cod, AFNI_TLRC_ATLAS);
5848    switch(cod) {
5849       case UNKNOWN_ATLAS:
5850          RETURN("Unknown");
5851       case AFNI_TLRC_ATLAS:
5852          RETURN("TT_Daemon");
5853       case CA_EZ_N27_MPM_ATLAS:
5854          RETURN("CA_N27_MPM");
5855       case CA_EZ_N27_ML_ATLAS:
5856          RETURN("CA_N27_ML");
5857       case CA_EZ_N27_LR_ATLAS:
5858          RETURN("CA_N27_LR");
5859       case CA_EZ_N27_PMAPS_ATLAS:
5860          RETURN("CA_N27_PM");
5861       case CUSTOM_ATLAS:
5862          RETURN(CUSTOM_ATLAS_PREFIX);
5863       case NUMBER_OF_ATLASES:
5864          RETURN("Flag for number of atlases");
5865       default:
5866          RETURN("Bert?");
5867    }
5868 
5869    RETURN("No way Bert.");
5870 }
5871 
5872 
5873 /* This function could be made to return an integer into
5874 the global space list. The 'Code' term should be changed
5875 to an index  */
Space_Name_to_Space_Code(char * nm)5876 AFNI_STD_SPACES Space_Name_to_Space_Code(char *nm)
5877 {
5878    ENTRY("Atlas_Space_Name_to_Atlas_Space_Code");
5879 
5880         if (!nm || !strcmp(nm,"Unknown")) RETURN(UNKNOWN_SPC);
5881    else if (!strcmp(nm,"TLRC")) RETURN(AFNI_TLRC_SPC);
5882    else if (!strcmp(nm,"MNI")) RETURN(MNI_SPC);
5883    else if (!strcmp(nm,"MNI_ANAT")) RETURN(MNI_ANAT_SPC);
5884 
5885    RETURN(UNKNOWN_SPC);
5886 }
5887 
Atlas_Name(ATLAS * atl)5888 char *Atlas_Name(ATLAS *atl)
5889 {
5890    static char aname[10][65];
5891    static int icall=0;
5892 
5893    ENTRY("Atlas_Name");
5894    ++icall; if (icall > 9) icall = 0;
5895    aname[icall][0] = '\0';
5896 
5897 
5898    if (atl->name &&
5899        atl->name[0] != '\0') RETURN(atl->name);
5900 
5901    /* nothing to do now but go via old route */
5902    WARNING_message("Reverting to old name nonesense."
5903                    " This option should be turned off. Use atlas_name directly");
5904    strncpy( aname[icall],
5905             Atlas_Code_to_Atlas_Name(
5906                Atlas_Dset_Name_to_Atlas_Code(atl->dset_name)),
5907             64);
5908 
5909    RETURN(aname[icall]);
5910 }
5911 
is_Coord_Space_Named(ATLAS_COORD ac,char * name)5912 int is_Coord_Space_Named(ATLAS_COORD ac, char *name)
5913 {
5914    if (strlen(ac.space_name) && !strcmp(ac.space_name,name)) return(1);
5915    return(0);
5916 }
5917 
set_Coord_Space_Name(ATLAS_COORD * ac,char * name)5918 int set_Coord_Space_Name (ATLAS_COORD *ac, char *name)
5919 {
5920    if (!name || strlen(name) > 63) {
5921       ERROR_message("Bad space name of >>%s<<", STR_PRINT(name));
5922       return(0);
5923    }
5924    strncpy(ac->space_name, name, 64);
5925    return(1);
5926 }
5927 
is_Atlas_Named(ATLAS * atl,char * name)5928 int is_Atlas_Named(ATLAS *atl, char *name)
5929 {
5930    if (!strcmp(Atlas_Name(atl),name)) return(1);
5931    return(0);
5932 }
5933 
is_Dset_Space_Named(THD_3dim_dataset * dset,char * name)5934 int is_Dset_Space_Named(THD_3dim_dataset *dset, char *name)
5935 {
5936    char *spc = THD_get_space(dset);
5937    if (!spc) return(-1); /* no definition */
5938    if (!strcmp(spc,name)) return(1);
5939    return(0);
5940 }
5941 
5942 
Atlas_Code_to_Atlas_Description(AFNI_ATLAS_CODES cod)5943 char *Atlas_Code_to_Atlas_Description (AFNI_ATLAS_CODES cod)
5944 {
5945    ENTRY("Atlas_Code_to_Atlas_Description");
5946 
5947    if (wami_verb()) {
5948       WARNING_message("Only old style (no niml), do not allow ATLAS_LIST here");
5949    }
5950 
5951    switch(cod) {
5952       case UNKNOWN_ATLAS:
5953          RETURN("Unknown");
5954       case AFNI_TLRC_ATLAS:
5955          RETURN("Talairach-Tournoux Atlas");
5956       case CA_EZ_N27_MPM_ATLAS:
5957          RETURN("Cytoarch. Max. Prob. Maps (N27)");
5958       case CA_EZ_N27_ML_ATLAS:
5959          RETURN("Macro Labels (N27)");
5960       case CA_EZ_N27_LR_ATLAS:
5961          RETURN("Left/Right (N27)");
5962       case CA_EZ_N27_PMAPS_ATLAS:
5963          RETURN("Cytoarch. Probabilistic Maps (N27)");
5964       case CUSTOM_ATLAS:
5965          RETURN(CUSTOM_ATLAS_PREFIX);
5966       case NUMBER_OF_ATLASES:
5967          RETURN("Flag for number of atlases");
5968       default:
5969          RETURN("Bert?");
5970    }
5971 
5972    RETURN("No way Bert.");
5973 }
5974 
5975 /* initialize custom atlas from environment variable */
5976 /* this is not used at all with the newer NIML table method of
5977    specifying atlases */
5978 void
init_custom_atlas()5979 init_custom_atlas()
5980 {
5981    char *cust_atlas_str;
5982    int LocalHead = wami_lh();
5983 
5984    ENTRY("init_custom_atlas");
5985 
5986    cust_atlas_str = getenv("AFNI_CUSTOM_ATLAS");
5987 
5988    if(cust_atlas_str)
5989       snprintf(CUSTOM_ATLAS_PREFIX, 255*sizeof(char), "%s", cust_atlas_str);
5990    if(LocalHead)
5991       INFO_message("CUSTOM_ATLAS_PREFIX = %s", CUSTOM_ATLAS_PREFIX);
5992    EXRETURN;
5993 }
5994 
5995 /*!
5996    Locate or create a zone of a particular level.
5997    \param aq (ATLAS_QUERY *)
5998    \param level (int)
5999    \return zn (ATLAS_ZONE) a new zone if none was
6000                found in aq at the proper level. Or
6001                whatever was found in aq.
6002 */
Get_Atlas_Zone(ATLAS_QUERY * aq,int level)6003 ATLAS_ZONE *Get_Atlas_Zone(ATLAS_QUERY *aq, int level)
6004 {
6005    int ii=0, fnd=0;
6006    ATLAS_ZONE *zn=NULL;
6007 
6008    ENTRY("Get_Atlas_Zone");
6009 
6010    if (!aq) {
6011       ERROR_message("NULL atlas query");
6012       RETURN(zn);
6013    }
6014 
6015    /* fprintf(stderr,"Looking for zone level %d\n", level); */
6016 
6017    ii = 0;
6018    while (ii<aq->N_zone) {
6019       if (aq->zone[ii]->level == level) {
6020          if (fnd) {
6021             WARNING_message(
6022                "More than one (%d) zone of level %d found in query.\n"
6023                "Function will ignore duplicates.\n", fnd, level ) ;
6024          }else {
6025             /* fprintf(stderr,"Zone with level %d found\n", level);  */
6026             zn = aq->zone[ii];
6027          }
6028          ++fnd;
6029       }
6030       ++ii;
6031    }
6032 
6033    if (!zn) {
6034       /* fprintf(stderr,"Zone with level %d NOT found\n", level);  */
6035       zn = (ATLAS_ZONE *)calloc(1, sizeof(ATLAS_ZONE));
6036       zn->level = level;
6037       zn->N_label = 0;
6038       zn->label = NULL;
6039       zn->code = NULL;
6040       zn->atname = NULL;
6041       zn->prob = NULL;
6042       zn->radius = NULL;
6043       zn->webpage = NULL;
6044       zn->connpage = NULL;
6045    }
6046 
6047    RETURN(zn);
6048 }
6049 
6050 /*!
6051    Create or Add to an Atlas Zone
6052    \param zn (ATLAS_ZONE *) If null then create a new one.
6053                             If a zone is given then add new labels to it
6054    \param level (int) a classifier of zones, in a way.
6055                       In most cases, it is the equivalent of the within
6056                       parameter.
6057    \param label (char *) a label string for this zone
6058    \param code (int) the integer code for this zone (not added if label is NULL)
6059    \param prob (float) the probability of that zone being label
6060                         (not added if label is NULL)
6061    \param within (float) radius of label's occurrence
6062    \return zno (ATLAS_ZONE *) either a new structure (if zn == NULL)
6063                   or a modified one (if zn != NULL)
6064 
6065    \sa free with Free_Atlas_Zone
6066 */
Atlas_Zone(ATLAS_ZONE * zn,int level,char * label,int code,float prob,float within,char * aname,char * webpage,char * connpage)6067 ATLAS_ZONE *Atlas_Zone( ATLAS_ZONE *zn, int level, char *label,
6068                         int code, float prob, float within,
6069                         char *aname, char *webpage, char *connpage)
6070 {
6071    ATLAS_ZONE *zno = NULL;
6072 
6073    ENTRY("Atlas_Zone");
6074 
6075    if ( (prob < 0 && prob != -1.0 && prob != -2.0) || prob > 1) {
6076       ERROR_message( "Probability must be 0<=prob<=1 or -1.0 or -2.0\n"
6077                      "You sent %f\n", prob);
6078       RETURN(zno);
6079    }
6080    if (within < 0 && within != -1.0 ) {
6081       ERROR_message( "'Within' must be > 0 or -1.0\n"
6082                      "You sent %f\n", within);
6083       RETURN(zno);
6084    }
6085    if (!zn) {
6086       zno = (ATLAS_ZONE *)calloc(1, sizeof(ATLAS_ZONE));
6087       zno->level = level;
6088       zno->N_label = 0;
6089       zno->label = NULL;
6090       zno->code = NULL;
6091       zno->atname = NULL;
6092       zno->prob = NULL;
6093       zno->radius = NULL;
6094       zno->webpage = NULL;
6095       zno->connpage = NULL;
6096    } else {
6097       zno = zn;
6098       if (zno->level != level) {
6099          ERROR_message( "When zn is not null\n"
6100                         "level (%d) must be equal to zn->level (%d)\n",
6101                         level, zn->level);
6102          RETURN(zno);
6103       }
6104    }
6105    if (label) {
6106       /* add label */
6107       ++zno->N_label;
6108       zno->label = (char **)realloc(zno->label, sizeof(char *)*zno->N_label);
6109       zno->label[zno->N_label-1] = strdup(label);
6110       zno->code = (int *)realloc(zno->code, sizeof(int)*zno->N_label);
6111       zno->code[zno->N_label-1] = code;
6112       zno->atname = (char **)realloc(zno->atname, sizeof(char*)*zno->N_label);
6113       zno->atname[zno->N_label-1] = nifti_strdup(aname);
6114       zno->prob = (float *)realloc(zno->prob, sizeof(float)*zno->N_label);
6115       zno->prob[zno->N_label-1] = prob;
6116       zno->radius = (float *)realloc(zno->radius, sizeof(float)*zno->N_label);
6117       zno->radius[zno->N_label-1] = within;
6118       zno->webpage = (char **)realloc(zno->webpage, sizeof(char *)*zno->N_label);
6119       if(webpage) {
6120          zno->webpage[zno->N_label-1] = nifti_strdup(webpage);
6121       }
6122       else
6123          zno->webpage[zno->N_label-1] = NULL;
6124       zno->connpage = (char **)realloc(zno->connpage, sizeof(char *)*zno->N_label);
6125       if(connpage) {
6126          zno->connpage[zno->N_label-1] = nifti_strdup(connpage);
6127       }
6128       else
6129          zno->connpage[zno->N_label-1] = NULL;
6130    }
6131 
6132    RETURN(zno);
6133 }
6134 
Free_Atlas_Zone(ATLAS_ZONE * zn)6135 ATLAS_ZONE *Free_Atlas_Zone(ATLAS_ZONE *zn)
6136 {
6137    int k=0;
6138 
6139    ENTRY("Free_Atlas_Zone");
6140 
6141    if (!zn) RETURN(NULL);
6142 
6143    if (zn->label) {
6144       for (k=0; k<zn->N_label; ++k) if (zn->label[k]) free(zn->label[k]);
6145       free(zn->label);
6146    }
6147    if (zn->atname) {
6148       for (k=0; k<zn->N_label; ++k) if (zn->atname[k]) free(zn->atname[k]);
6149       free(zn->atname);
6150    }
6151    if (zn->webpage) {
6152       for (k=0; k<zn->N_label; ++k) if (zn->webpage[k]) free(zn->webpage[k]);
6153       free(zn->webpage);
6154    }
6155    if (zn->connpage) {
6156       for (k=0; k<zn->N_label; ++k) if (zn->connpage[k]) free(zn->connpage[k]);
6157       free(zn->connpage);
6158    }
6159    free(zn->code);
6160    free(zn->prob);
6161    free(zn->radius);
6162    free(zn);
6163 
6164    RETURN(NULL);
6165 }
6166 
Show_Atlas_Zone(ATLAS_ZONE * zn,ATLAS_LIST * atlas_list)6167 void Show_Atlas_Zone(ATLAS_ZONE *zn, ATLAS_LIST *atlas_list)
6168 {
6169    int k=0;
6170    char probs[16], codes[16], radiuss[16];
6171 
6172    ENTRY("Show_Atlas_Zone");
6173 
6174    if (!zn) { fprintf(stderr,"NULL zone"); EXRETURN;}
6175 
6176    fprintf(stderr,
6177             "     level     :   %d\n"
6178             "     N_label(s):   %d\n",
6179             zn->level, zn->N_label);
6180    if (zn->label) {
6181       for (k=0; k<zn->N_label; ++k) {
6182          sprintf(probs, "%s", Atlas_Prob_String(zn->prob[k]));
6183          sprintf(codes, "%s", Atlas_Code_String(zn->code[k]));
6184 
6185          sprintf(radiuss,"%.1f", zn->radius[k]);
6186 
6187          fprintf(stderr,
6188       "     %d: label=%-32s, prob=%-3s, rad=%-3s, code=%-3s, atlas=%-10s\n",
6189                   k, Clean_Atlas_Label(zn->label[k]), probs, radiuss, codes,
6190                   zn->atname[k]);
6191          if(zn->connpage[k])
6192             fprintf(stderr,"     Connection Webpage: %s\n", zn->connpage[k]);
6193 
6194       }
6195    } else {
6196       fprintf(stderr,"     label (NULL");
6197    }
6198 
6199    EXRETURN;
6200 }
6201 
Show_Atlas_Query(ATLAS_QUERY * aq,ATLAS_LIST * atlas_list)6202 void Show_Atlas_Query(ATLAS_QUERY *aq, ATLAS_LIST *atlas_list)
6203 {
6204    int k=0;
6205 
6206    ENTRY("Show_Atlas_Query");
6207 
6208    if (!aq) { fprintf(stderr,"NULL query\n"); EXRETURN;}
6209 
6210    fprintf(stderr,
6211             "----------------------\n"
6212             "Atlas_Query: %d zones\n",
6213             aq->N_zone);
6214    if (aq->zone) {
6215       for (k=0; k<aq->N_zone; ++k) {
6216          fprintf(stderr,"  zone[%d]:\n", k);
6217          Show_Atlas_Zone(aq->zone[k], atlas_list);
6218          fprintf(stderr,"\n");
6219       }
6220    } else {
6221       fprintf(stderr,"  zone (NULL)\n");
6222    }
6223    fprintf(stderr,
6224             "----------------------\n");
6225    EXRETURN;
6226 }
6227 
Add_To_Atlas_Query(ATLAS_QUERY * aq,ATLAS_ZONE * zn)6228 ATLAS_QUERY *Add_To_Atlas_Query(ATLAS_QUERY *aq, ATLAS_ZONE *zn)
6229 {
6230    int i, fnd=0;
6231    ATLAS_QUERY *aqo;
6232 
6233    ENTRY("Add_To_Atlas_Query");
6234 
6235    if (!aq) {
6236       aqo = (ATLAS_QUERY *)calloc(1, sizeof(ATLAS_QUERY));
6237       aqo->N_zone = 0;
6238       aqo->zone = NULL;
6239    }else{
6240       aqo = aq;
6241    }
6242 
6243    if (zn) {
6244       /* make sure this one does not exist already */
6245       for (i=0; i<aqo->N_zone; ++i) {
6246          if (aqo->zone[i] == zn) {
6247             fnd = 1;
6248             break;
6249          }
6250       }
6251       if (!fnd) {
6252          /* add zone */
6253          ++aqo->N_zone;
6254          aqo->zone = (ATLAS_ZONE **)realloc( aqo->zone,
6255                                              sizeof(ATLAS_ZONE*)*aqo->N_zone);
6256          aqo->zone[aqo->N_zone-1] = zn;
6257       }
6258    }
6259    RETURN(aqo);
6260 }
6261 
Free_Atlas_Query(ATLAS_QUERY * aq)6262 ATLAS_QUERY *Free_Atlas_Query(ATLAS_QUERY *aq)
6263 {
6264    int k=0;
6265 
6266    ENTRY("Free_Atlas_Query");
6267 
6268    if (!aq) RETURN(NULL);
6269 
6270    if (aq->zone) {
6271       for (k=0; k<aq->N_zone; ++k) if (aq->zone[k]) Free_Atlas_Zone(aq->zone[k]);
6272       free(aq->zone);
6273    }
6274    free(aq);
6275 
6276    RETURN(NULL);
6277 }
6278 
Check_Version_Match(THD_3dim_dataset * dset,char * atname)6279 int Check_Version_Match(THD_3dim_dataset * dset, char *atname)
6280 {
6281    ATR_int *notecount;
6282    int num_notes, i, j, mmm ;
6283    char *chn , *chd, *mt ;
6284    char *ver=NULL;
6285 
6286    ENTRY("Check_Version_Match");
6287 
6288    if (!dset) RETURN(0); /* not good */
6289 
6290    ver = atlas_version_string(atname);
6291 
6292    if (!ver) RETURN(1); /* no versions here */
6293    if (!strcmp(atname,"CA_N27_MPM") ||
6294        !strcmp(atname,"CA_N27_PM")  ||
6295        !strcmp(atname,"CA_N27_LR") ||
6296        !strcmp(atname,"CA_N27_ML") ) {   /* CA atlases, good */
6297      notecount = THD_find_int_atr(dset->dblk, "NOTES_COUNT");
6298      if( notecount != NULL ){
6299         num_notes = notecount->in[0] ;
6300         mmm = 4000 ;
6301         for (i=1; i<= num_notes; i++) {
6302            chn = tross_Get_Note( dset , i ) ;
6303            if( chn != NULL ){
6304               j = strlen(chn) ; if( j > mmm ) chn[mmm] = '\0' ;
6305               chd = tross_Get_Notedate(dset,i) ;
6306               if( chd == NULL ){ chd = AFMALL(char,16) ; strcpy(chd,"no date") ; }
6307               /* fprintf(stderr,"\n----- NOTE %d [%s] (searching for %s) -----\n%s\n",i,chd, CA_EZ_VERSION_STR, chn ) ; */
6308               /* search for matching versions */
6309               mt = strstr(chn, ver);
6310               free(chn) ; free(chd) ;
6311               if (mt) {
6312                RETURN(1); /* excellent */
6313               }
6314            }
6315         }
6316      }
6317 
6318    }
6319 
6320    RETURN(0); /* not good */
6321 }
6322 
6323 #ifdef KILLTHIS /* Remove all old sections framed by #ifdef KILLTHIS
6324                   in the near future.  ZSS May 2011   */
6325 
6326 static int N_VersionMessage = 0;
6327 
VersionMessage(void)6328 static char *VersionMessage(void)
6329 {
6330    static char verr[1000];
6331    ENTRY("VersionMessage");
6332    sprintf( verr, "Mismatch of Anatomy Toolbox Versions.\n"
6333                   "Version in AFNI is %s and appears\n"
6334                   "different from version string in atlas' notes.\n"
6335                   "See whereami -help for more info.\n", CA_EZ_VERSION_STR_HARD);
6336    RETURN(verr);
6337 }
6338 
CA_EZ_ML_load_atlas_old(void)6339 int CA_EZ_ML_load_atlas_old(void)
6340 {
6341    char *epath ;
6342    char atpref[256];
6343 
6344    ENTRY("CA_EZ_ML_load_atlas_old");
6345 
6346    WARNING_message("Obsolete, use Atlas_With_Trimming(\"CA_EZ_ML\", .) instead");
6347 
6348    if( have_dseCA_EZ_ML_old >= 0 )
6349       RETURN(have_dseCA_EZ_ML_old) ;  /* for later calls */
6350 
6351    have_dseCA_EZ_ML_old = 0 ;  /* don't have it yet */
6352 
6353    /*----- 20 Aug 2001: see if user specified alternate database -----*/
6354 
6355    epath = getenv("AFNI_CA_EZ_N27_ML_ATLAS_DATASET") ;   /* suggested path, if any */
6356    snprintf(atpref, 255*sizeof(char), "%s+tlrc", CA_EZ_N27_ML_TT_PREFIX);
6357    dseCA_EZ_ML_old = get_atlas( epath, atpref ) ;  /* try to open it */
6358    if (!dseCA_EZ_ML_old) { /* try for NIFTI */
6359       snprintf(atpref, 255*sizeof(char), "%s.nii.gz", CA_EZ_N27_ML_TT_PREFIX);
6360       dseCA_EZ_ML_old = get_atlas( epath, atpref) ;
6361    }
6362    if( dseCA_EZ_ML_old != NULL ){                     /* got it!!! */
6363       /* check on version */
6364       if (!Check_Version_Match(dseCA_EZ_ML_old, "CA_N27_ML")) {
6365          if (!N_VersionMessage) { POPUP_MESSAGE( VersionMessage() ); ++N_VersionMessage; }
6366          ERROR_message( VersionMessage() );
6367          /* dump the load */
6368          /* CA_EZ_ML_purge_atlas();, not good enough will get reloaded elsewhere */
6369          DSET_delete(dseCA_EZ_ML_old) ;  dseCA_EZ_ML_old = NULL;
6370          RETURN(0) ;
6371       }
6372       have_dseCA_EZ_ML_old = 1; RETURN(1);
6373    }
6374 
6375    RETURN(0) ; /* got here -> didn't find it */
6376 }
6377 
CA_EZ_LR_load_atlas_old(void)6378 int CA_EZ_LR_load_atlas_old(void)
6379 {
6380    char *epath ;
6381    char atpref[256];
6382 
6383    ENTRY("CA_EZ_LR_load_atlas_old");
6384 
6385    WARNING_message("Obsolete, use Atlas_With_Trimming(\"CA_EZ_LR\", .) instead");
6386 
6387    if( have_dseCA_EZ_LR_old >= 0 )
6388       RETURN(have_dseCA_EZ_LR_old) ;  /* for later calls */
6389 
6390    have_dseCA_EZ_LR_old = 0 ;  /* don't have it yet */
6391 
6392    /*----- 20 Aug 2001: see if user specified alternate database -----*/
6393 
6394    epath = getenv("AFNI_CA_EZ_N27_LR_ATLAS_DATASET") ;   /* suggested path, if any */
6395    snprintf(atpref, 255*sizeof(char), "%s+tlrc", CA_EZ_N27_LR_TT_PREFIX);
6396    dseCA_EZ_LR_old = get_atlas( epath, atpref ) ;  /* try to open it */
6397    if (!dseCA_EZ_LR_old) { /* try for NIFTI */
6398       snprintf(atpref, 255*sizeof(char), "%s.nii.gz", CA_EZ_N27_LR_TT_PREFIX);
6399       dseCA_EZ_LR_old = get_atlas( epath, atpref) ;
6400    }
6401    if( dseCA_EZ_LR_old != NULL ){                     /* got it!!! */
6402       /* check on version */
6403       if (!Check_Version_Match(dseCA_EZ_LR_old, "CA_N27_LR")) {
6404          if (!N_VersionMessage) { POPUP_MESSAGE( VersionMessage() ); ++N_VersionMessage; }
6405          ERROR_message(  VersionMessage() );
6406          /* dump the load */
6407          /* CA_EZ_LR_purge_atlas();, not good enough will get reloaded elsewhere */
6408          DSET_delete(dseCA_EZ_LR_old) ; dseCA_EZ_LR_old = NULL;
6409          RETURN(0) ;
6410       }
6411       have_dseCA_EZ_LR_old = 1; RETURN(1);
6412    }
6413 
6414    RETURN(0) ; /* got here -> didn't find it */
6415 }
6416 
CA_EZ_MPM_load_atlas_old(void)6417 int CA_EZ_MPM_load_atlas_old(void)
6418 {
6419    char *epath ;
6420    char atpref[256];
6421 
6422    ENTRY("CA_EZ_MPM_load_atlas_old");
6423    WARNING_message(
6424       "Obsolete, use Atlas_With_Trimming(\"CA_EZ_MPM\", .) instead");
6425 
6426    if( have_dseCA_EZ_MPM_old >= 0 )
6427       RETURN(have_dseCA_EZ_MPM_old) ;  /* for later calls */
6428 
6429    have_dseCA_EZ_MPM_old = 0 ;  /* don't have it yet */
6430 
6431    /*----- 20 Aug 2001: see if user specified alternate database -----*/
6432 
6433    epath = getenv("AFNI_CA_EZ_N27_MPM_ATLAS_DATASET") ;   /* suggested path, if any */
6434    snprintf(atpref, 255*sizeof(char), "%s+tlrc", CA_EZ_N27_MPM_TT_PREFIX);
6435    dseCA_EZ_MPM_old = get_atlas( epath, atpref ) ;  /* try to open it */
6436    if (!dseCA_EZ_MPM_old) { /* try for NIFTI */
6437       snprintf(atpref, 255*sizeof(char), "%s.nii.gz", CA_EZ_N27_MPM_TT_PREFIX);
6438       dseCA_EZ_MPM_old = get_atlas( epath, atpref) ;
6439    }
6440    if( dseCA_EZ_MPM_old != NULL ){                     /* got it!!! */
6441       /* check on version */
6442       if (!Check_Version_Match(dseCA_EZ_MPM_old, "CA_N27_MPM")) {
6443          if (!N_VersionMessage) { POPUP_MESSAGE( VersionMessage() ); ++N_VersionMessage; }
6444          ERROR_message( VersionMessage() );
6445          /* dump the load */
6446          /*CA_EZ_MPM_purge_atlas();, not good enough will get reloaded elsewhere */
6447          DSET_delete(dseCA_EZ_MPM_old) ; dseCA_EZ_MPM_old = NULL;
6448          RETURN(0) ;
6449       }
6450       have_dseCA_EZ_MPM_old = 1; RETURN(1);
6451    }
6452 
6453    RETURN(0) ; /* got here -> didn't find it */
6454 }
6455 
6456 
CA_EZ_PMaps_load_atlas_old(void)6457 int CA_EZ_PMaps_load_atlas_old(void)
6458 {
6459    char *epath ;
6460    char atpref[256];
6461 
6462    ENTRY("CA_EZ_PMaps_load_atlas_old");
6463 
6464    WARNING_message("Obsolete, use Atlas_With_Trimming(\"CA_EZ_PM\", .) instead");
6465 
6466    if( have_dseCA_EZ_PMaps_old >= 0 )
6467       RETURN(have_dseCA_EZ_PMaps_old) ;  /* for later calls */
6468 
6469    have_dseCA_EZ_PMaps_old = 0 ;  /* don't have it yet */
6470 
6471    /*----- 20 Aug 2001: see if user specified alternate database -----*/
6472 
6473    epath = getenv("AFNI_CA_EZ_N27_PMAPS_ATLAS_DATASET") ;   /* suggested path, if any */
6474    snprintf(atpref, 255*sizeof(char), "%s+tlrc", CA_EZ_N27_PMaps_TT_PREFIX) ;
6475    dseCA_EZ_PMaps_old = get_atlas( epath, atpref ) ;  /* try to open it */
6476    if (!dseCA_EZ_PMaps_old) { /* try for NIFTI */
6477       snprintf(atpref, 255*sizeof(char),
6478                "%s.nii.gz", CA_EZ_N27_PMaps_TT_PREFIX) ;
6479       dseCA_EZ_PMaps_old = get_atlas( epath, atpref) ;
6480    }
6481    if( dseCA_EZ_PMaps_old != NULL ){                     /* got it!!! */
6482       /* check on version */
6483       if (!Check_Version_Match(dseCA_EZ_PMaps_old, "CA_N27_PM")) {
6484          if (!N_VersionMessage) { POPUP_MESSAGE( VersionMessage() ); ++N_VersionMessage; }
6485          ERROR_message(  VersionMessage() );
6486          /* dump the load */
6487          /* CA_EZ_PMaps_purge_atlas();, not good enough will get reloaded elsewhere */
6488          DSET_delete(dseCA_EZ_PMaps_old) ; dseCA_EZ_PMaps_old = NULL;
6489          RETURN(0) ;
6490       }
6491       have_dseCA_EZ_PMaps_old = 1; RETURN(1);
6492    }
6493 
6494    RETURN(0) ; /* got here -> didn't find it */
6495 }
6496 #endif
6497 
6498 /* load any atlas (ignoring different environment variables
6499    for alternate locations) */
load_atlas_dset(char * dsetname)6500 THD_3dim_dataset *load_atlas_dset(char *dsetname)
6501 {
6502    char *fstr,*epath ;
6503    char atpref[256];
6504    char filestr[RPMAX];
6505    THD_3dim_dataset *dset=NULL;
6506    int LocalHead = wami_lh();
6507 
6508    ENTRY("load_atlas_dset");
6509 
6510 
6511    /* maybe the dsetname includes a full path or the dset is in the current
6512       directory */
6513    dset = get_atlas( NULL, dsetname);
6514    if(dset) RETURN(dset);
6515 
6516    /* try environment variable location for TTATLAS */
6517    epath = getenv("AFNI_ATLAS_PATH") ;
6518    /* try dsetname first */
6519    if (!dset) {
6520       if(LocalHead)
6521          INFO_message("load_atlas: epath %s, name %s", epath, dsetname);
6522       dset = get_atlas( epath, dsetname ) ;  /* try to open it */
6523       if(dset) RETURN(dset);
6524    }
6525 
6526    /* try environment variable location for TTATLAS */
6527    epath = getenv("AFNI_SUPP_ATLAS_DIR") ;
6528    /* try dsetname first */
6529    if (!dset) {
6530       if(LocalHead)
6531          INFO_message("load_atlas: epath %s, name %s", epath, dsetname);
6532       dset = get_atlas( epath, dsetname ) ;  /* try to open it */
6533       if(dset) RETURN(dset);
6534    }
6535 
6536    /* try environment variable location for TTATLAS */
6537    epath = getenv("AFNI_TTATLAS_DATASET") ;
6538    /* try dsetname first */
6539    if (!dset) {
6540       if(LocalHead)
6541          INFO_message("load_atlas: epath %s, name %s", epath, dsetname);
6542       dset = get_atlas( epath, dsetname ) ;  /* try to open it */
6543       if(dset) RETURN(dset);
6544    }
6545 
6546    if (!dset) { /* try the AFNI format with +tlrc in the name */
6547       snprintf(atpref, 255*sizeof(char), "%s+tlrc", dsetname);
6548       if(LocalHead)
6549          INFO_message("load_atlas: epath %s, name %s", epath, atpref);
6550       dset = get_atlas( epath, atpref ) ;  /* try to open it */
6551       if(dset) RETURN(dset);
6552    }
6553 
6554 
6555    /* okay that didn't work, try the AFNI plugin directory */
6556    epath = get_env_atlas_path();
6557    if( epath != NULL ) {
6558       if(epath[strlen(epath)-1]!='/') {
6559          if(strlen(epath)<RPMAX){
6560              sprintf(filestr, "%s/", epath);
6561              dset = get_atlas(filestr, dsetname);
6562          }
6563       }
6564       else
6565           dset = get_atlas( epath, dsetname);
6566 
6567       if(dset) RETURN(dset);
6568    }
6569 
6570    /* still can't find it. Maybe it's in one of the path directories */
6571    epath = getenv("PATH") ;
6572    if( epath == NULL ) RETURN(NULL) ;  /* this is bad-who doesn't have a path?*/
6573 
6574    /* use function that looks for regular files in path */
6575    fstr = THD_find_regular_file(dsetname, epath);
6576    if(fstr) {
6577       dset = get_atlas( NULL, fstr);
6578       if(dset) RETURN(dset);
6579    }
6580 
6581    if (!dset) {
6582       if(LocalHead)
6583          INFO_message("load_atlas: atlas %s not found in any directory",
6584                        dsetname);
6585    }
6586    RETURN(dset) ;
6587 
6588 }
6589 
6590 
AddLeftRight(char * name,char lr)6591 char *AddLeftRight(char *name, char lr)
6592 {
6593    static char namesave[500];
6594 
6595    ENTRY("AddLeftRight");
6596 
6597    if (lr == 'l' || lr == 'L') sprintf(namesave,"Left %s", name);
6598    else if (lr == 'r' || lr == 'R') sprintf(namesave,"Right %s", name);
6599    else RETURN(name);
6600 
6601    RETURN(namesave);
6602 }
6603 
6604 /* removes one occurence of left or right in name , search is case insensitive*/
NoLeftRight(char * name)6605 char *NoLeftRight (char *name)
6606 {
6607    char *nolr0=NULL, namesave[500];
6608    int i;
6609    ENTRY("NoLeftRight");
6610 
6611    if (!name) RETURN(name);
6612 
6613    snprintf(namesave,499*sizeof(char), "%s", name);
6614 
6615    for (i=0; i<strlen(name); ++i) name[i] = TO_UPPER(name[i]);
6616    nolr0 = strstr(name, "LEFT");
6617    /*if (nolr0) fprintf(stderr,"%s\n%s\n", name, nolr0+4); */
6618    if (!nolr0) { /* left not found, remove right */
6619       nolr0 = strstr(name, "RIGHT");
6620      /* if (nolr0) fprintf(stderr,"%s\n%s\n", name, nolr0+5); */
6621      if (nolr0) {
6622          nolr0 += 5; /* jump beyond right */
6623       }
6624    }else {
6625       nolr0 += 4; /* jump beyond left */
6626    }
6627 
6628    /* deblank */
6629    if (nolr0) {
6630       while (nolr0[0] != '\0' && IS_BLANK(nolr0[0]))  {
6631          ++nolr0;
6632       }
6633    }
6634 
6635    /* put it back */
6636    sprintf(name,"%s", namesave);
6637 
6638    if (nolr0) RETURN(nolr0);
6639    else RETURN(name);
6640 }
6641 
6642 
6643 /* get atlas name type - show either short name, long name or both together
6644  * This applies to individual region labels like
6645 *   amyl, amygdala or "amyl amygdala" */
Atlas_name_type()6646 int Atlas_name_type()
6647 {
6648    char *nametype;
6649 
6650    /* see if type is already set. Use environment only once */
6651    if(atlas_name_code!=-1)
6652       return(atlas_name_code);
6653 
6654    /* maybe name something else? */
6655    nametype = my_getenv("AFNI_ATLAS_NAME_TYPE");
6656 
6657 //   atlas_name_code = 0;
6658    atlas_name_code = 2;  /* make default - show both name - short name and long name */
6659 
6660    if(nametype!=NULL) {
6661       if(!strcasecmp(nametype, "longname")) {
6662          atlas_name_code = 1;
6663       }
6664       else if(!strcasecmp(nametype, "bothnames"))
6665          atlas_name_code = 2;
6666       else if(!strcasecmp(nametype, "name"))
6667          atlas_name_code = 0;
6668    }
6669 
6670    return(atlas_name_code);
6671 }
6672 
set_atlas_name_code(int code)6673 void set_atlas_name_code(int code)
6674 {
6675    atlas_name_code = code;
6676 }
6677 
6678 /* return region name, long region name, or both combined */
Atlas_name_choice(ATLAS_POINT * atp)6679 char *Atlas_name_choice(ATLAS_POINT *atp)
6680 {
6681    static char tmps[600];
6682 
6683    /* get environment setting for name, long name or both names */
6684    switch(Atlas_name_type()){
6685      /* just the long name */
6686       case 1:
6687           if (strlen(atp->longname))
6688              sprintf(tmps, "%s", atp->longname);
6689           else
6690              sprintf(tmps, "%s", atp->name);
6691           break;
6692       /* combination - both name and long name with brackets around long name*/
6693       case 2:
6694           if (strlen(atp->longname) && strcmp(atp->longname, atp->name))
6695              sprintf(tmps, "%s\n[%s]", atp->name, atp->longname);
6696           else
6697              sprintf(tmps, "%s", atp->name);
6698           break;
6699       /* just the short, original name */
6700       case 0:
6701       default:
6702           sprintf(tmps, "%s", atp->name);
6703    }
6704 
6705    return(tmps);
6706 }
6707 
6708 /* See also atlas_key_label */
6709 /* this function used only by whereami overlap mask computation for now */
Atlas_Val_Key_to_Val_Name(ATLAS * atlas,int tdval)6710 const char *Atlas_Val_Key_to_Val_Name(ATLAS *atlas, int tdval)
6711 {
6712    int ii, cmax = 600;
6713    static char tmps[600];
6714    ATLAS_POINT *aptr;
6715 
6716    ENTRY("Atlas_Val_Key_to_Val_Name");
6717 
6718    tmps[0] = '\0';
6719    if (tdval > atlas->adh->maxkeyval || tdval < atlas->adh->minkeyval) {
6720       ERROR_message( "integer code %d outside [%d %d]!",
6721                      tdval, atlas->adh->minkeyval, atlas->adh->maxkeyval);
6722       RETURN(NULL);
6723    }
6724    if (!atlas->adh->apl2 || !atlas->adh->apl2->at_point) {
6725       ERROR_message("No list for this atlas, fool!");
6726       RETURN(NULL);
6727    }
6728 
6729    if (!atlas->adh->duplicateLRentries) {
6730       /* quicky */
6731       if (tdval < MAX_ELM(atlas->adh->apl2)) {
6732          if (atlas->adh->apl2->at_point[tdval].tdval == tdval){
6733                aptr = &atlas->adh->apl2->at_point[tdval];
6734                RETURN(Atlas_name_choice(aptr));
6735 /*               RETURN(Clean_Atlas_Label(atlas->adh->apl2->at_point[tdval].name));*/
6736          }
6737       }
6738       /* longy */
6739       for( ii=0 ; ii < MAX_ELM(atlas->adh->apl2) ; ii++ ) {
6740          if (atlas->adh->apl2->at_point[ii].tdval == tdval) {
6741                aptr = &atlas->adh->apl2->at_point[ii];
6742                RETURN(Atlas_name_choice(aptr));
6743 /*               RETURN(Clean_Atlas_Label(atlas->adh->apl2->at_point[ii].name));*/
6744          }
6745       }
6746    } else {
6747       int fnd[30], nfnd =0;
6748       /* search for all, for safety */
6749       for( ii=0 ; ii < MAX_ELM(atlas->adh->apl2) ; ii++ ) {
6750          if (atlas->adh->apl2->at_point[ii].tdval == tdval) {
6751             fnd[nfnd] = ii; ++nfnd;
6752          }
6753       }
6754 
6755       if ( nfnd == 0) RETURN(NULL);
6756 
6757       if ( nfnd == 1) {
6758          aptr = &atlas->adh->apl2->at_point[fnd[0]];
6759          RETURN(NoLeftRight(Atlas_name_choice(aptr)));
6760 /*                Clean_Atlas_Label(atlas->adh->apl2->at_point[fnd[0]].name)));*/
6761       }
6762 
6763       if (nfnd > 2) {
6764          /* too many entries, return them all */
6765          snprintf(tmps,sizeof(char)*(int)((cmax-6*nfnd)/nfnd), "%s",
6766                      Clean_Atlas_Label(atlas->adh->apl2->at_point[fnd[0]].name));
6767          for( ii=1 ; ii < nfnd; ++ii) {
6768             snprintf(tmps,sizeof(char)*(int)((cmax-6*nfnd)/nfnd), "-AND-%s",
6769                   Clean_Atlas_Label(atlas->adh->apl2->at_point[fnd[ii]].name));
6770          }
6771       } else {
6772          /* get rid of the LR business */
6773          if (!strcmp(NoLeftRight(
6774                    Clean_Atlas_Label(atlas->adh->apl2->at_point[fnd[0]].name)),
6775                      NoLeftRight(
6776                    Clean_Atlas_Label(atlas->adh->apl2->at_point[fnd[1]].name)))){
6777             RETURN(NoLeftRight(
6778                     Clean_Atlas_Label(atlas->adh->apl2->at_point[fnd[0]].name)));
6779          }else{
6780             snprintf(tmps,sizeof(char)*cmax, "%s-AND-%s",
6781                      Clean_Atlas_Label(atlas->adh->apl2->at_point[fnd[0]].name),
6782                      Clean_Atlas_Label(atlas->adh->apl2->at_point[fnd[1]].name));
6783             RETURN(tmps);
6784          }
6785       }
6786    }
6787 
6788    RETURN(NULL);
6789 }
6790 
get_Atlas_Named(char * atname,ATLAS_LIST * atlas_list)6791 ATLAS *get_Atlas_Named(char *atname, ATLAS_LIST *atlas_list)
6792 {
6793    int i=0;
6794 
6795    ENTRY("get_Atlas_Named");
6796 
6797    if (!atlas_list && !(atlas_list = get_G_atlas_list())) {
6798       ERROR_message("I don't have an atlas list");
6799       RETURN(NULL);
6800    }
6801    if (!atname) {
6802       ERROR_message("NULL name");
6803       RETURN(NULL);
6804    }
6805 
6806    for (i=0; i<atlas_list->natlases;++i) {
6807       if (!strcmp(atname, atlas_list->atlas[i].name)) {
6808          RETURN(&(atlas_list->atlas[i]));
6809       }
6810    }
6811 
6812    RETURN(NULL);
6813 }
6814 
suggest_Atlas_Named(char * atname,ATLAS_LIST * atlas_list)6815 char *suggest_Atlas_Named(char *atname, ATLAS_LIST *atlas_list)
6816 {
6817    int i = 0;
6818    char **ws=NULL;
6819    static char sugg[128]={""};
6820 
6821    if (!atname || !atlas_list) return(NULL);
6822 
6823    ws = (char **)calloc(atlas_list->natlases, sizeof(char *));
6824    for (i=0; i<atlas_list->natlases;++i) {
6825       ws[i] = strdup(atlas_list->atlas[i].name);
6826    }
6827    ws = approx_str_sort(ws, atlas_list->natlases, atname,
6828                         1, NULL, 1, NULL, NULL);
6829    snprintf(sugg,124*sizeof(char),"%s", ws[0]);
6830    for (i=0; i<atlas_list->natlases;++i) free(ws[i]);
6831    free(ws);
6832 
6833    return(sugg);
6834 }
6835 
get_Atlas_ByDsetID(char * dsetid,ATLAS_LIST * atlas_list)6836 ATLAS *get_Atlas_ByDsetID(char *dsetid, ATLAS_LIST *atlas_list)
6837 {
6838    int i=0;
6839 
6840    ENTRY("get_Atlas_ByDsetID");
6841 
6842    if (!atlas_list && !(atlas_list = get_G_atlas_list())) {
6843       ERROR_message("I don't have an atlas list");
6844       RETURN(NULL);
6845    }
6846    if (!dsetid) {
6847       ERROR_message("NULL dsetid");
6848       RETURN(NULL);
6849    }
6850 
6851    for (i=0; i<atlas_list->natlases;++i) {
6852       if (  atlas_list->atlas[i].adh && ATL_DSET(atlas_list->atlas+i) &&
6853             !strcmp(dsetid, DSET_IDCODE_STR(ATL_DSET(atlas_list->atlas+i))) ) {
6854          RETURN(&(atlas_list->atlas[i]));
6855       }
6856    }
6857    RETURN(NULL);
6858 }
6859 
6860 /* Return 1 if dset can be taken in as an atlas
6861    If atlas_alist is not null, add the successful candidate
6862    to the list.
6863 
6864    NOTE: Once added to the atlas_list, the atlas dataset is
6865    read anew from disk. Therefore there will be two copies
6866    of dset in AFNI memory.
6867    We'll need to discuss this.   */
is_Dset_Atlasy(THD_3dim_dataset * dset,ATLAS_LIST * atlas_alist)6868 int is_Dset_Atlasy(THD_3dim_dataset *dset, ATLAS_LIST *atlas_alist)
6869 {
6870    NI_element *nel=NULL;
6871    NI_stream ns=NULL;
6872    char *str=NULL;
6873    int OK = 0;
6874 
6875    ENTRY("is_Dset_Atlasy");
6876 
6877    if (!dset) RETURN(0);
6878    if (!THD_find_string_atr( dset->dblk , "ATLAS_LABEL_TABLE" )) {
6879       RETURN(0);
6880    }
6881    if (!atlas_alist) { /* nothing else to do, return */
6882       RETURN(1);
6883    }
6884 
6885    /* have candidate, and want to add to list */
6886    if (get_Atlas_ByDsetID(DSET_IDCODE_STR(dset), atlas_alist)) {
6887       /* already in, get out */
6888       RETURN(1);
6889    }
6890 
6891    /* Add that baby by creating a little niml ATLAS element for it */
6892    nel = NI_new_data_element("ATLAS", 0);
6893    str = DSET_prefix_noext(dset);
6894    NI_set_attribute(nel, "atlas_name", str); free(str); str = NULL;
6895    NI_set_attribute(nel, "dset_name", dset->dblk->diskptr->brick_name);
6896    NI_set_attribute(nel, "template_space", THD_get_space(dset));
6897    NI_set_attribute(nel, "description","session atlas");
6898    NI_set_attribute(nel, "comment","local discovery");
6899 
6900    if (!session_atlas_name_list) INIT_SARR(session_atlas_name_list);
6901    if (!add_atlas_nel(nel, NULL,
6902                       atlas_alist, NULL, NULL, session_atlas_name_list, NULL)) {
6903       ERROR_message("Failed to add to atlaslist");
6904       goto CLEAN;
6905    }
6906    /* and reset the working list */
6907    recreate_working_atlas_name_list();
6908 
6909    /* Now get the atlas loaded (duplication here) */
6910    if (!Atlas_With_Trimming(NI_get_attribute(nel,"atlas_name"),1,atlas_alist)) {
6911       ERROR_message("Unexpected failure to setup atlas");
6912       goto CLEAN;
6913    }
6914 
6915    OK = 1;
6916 
6917    CLEAN:
6918    if (ns) NI_stream_close(ns);
6919    if (nel) NI_free_element(nel);
6920    if (str) NI_free(str);
6921 
6922    RETURN(OK);
6923 }
6924 
Atlas_Names_to_List(char ** atnames,int natlases)6925 ATLAS_LIST *Atlas_Names_to_List(char **atnames, int natlases)
6926 {
6927    ATLAS *atl = NULL;
6928    ATLAS_LIST *atlas_list = NULL, *reduced_list = NULL;
6929    int i=0, reduced_n=0;
6930 
6931    ENTRY("Atlas_Names_to_List");
6932 
6933    atlas_list = get_G_atlas_list();
6934    if(!atlas_list){
6935       ERROR_message("Can not find global atlas list");
6936       RETURN(NULL);
6937    }
6938 
6939    if (!atnames) {
6940       ERROR_message("NULL names");
6941       RETURN(NULL);
6942    }
6943 
6944    for (i=0; i<natlases; ++i) {
6945       if(get_Atlas_Named(atnames[i], atlas_list))
6946          reduced_n++;
6947       else
6948          ERROR_message("No atlas named %s found in global atlas list",
6949                         atnames[i]);
6950    }
6951 
6952    if(!reduced_n) {
6953       ERROR_message("No atlases given were found in global atlas list\n"
6954         "Please see whereami help and AFNI_atlas_spaces.niml for information\n"
6955         "on how to add atlases to AFNI");
6956       RETURN(NULL);
6957    }
6958    /* initialize the reduced list - may be only one atlas in list */
6959    reduced_list = (ATLAS_LIST *) calloc(1, sizeof(ATLAS_LIST));
6960    reduced_list->natlases = reduced_n;
6961    reduced_list->atlas = (ATLAS *) calloc(
6962                             reduced_n, sizeof(ATLAS));
6963    for (i=0; i<natlases; ++i) {
6964       if((atl = get_Atlas_Named(atnames[i], atlas_list))) {
6965          if(wami_verb()){
6966             INFO_message("Atlas, %s,matched in reduced list:",Atlas_Name(atl));
6967          }
6968          atlas_dup_atlas(atl, reduced_list->atlas+i);
6969      }
6970    }
6971 
6972 
6973    RETURN(reduced_list);
6974 }
6975 
Free_Atlas_Dset_Holder(ATLAS_DSET_HOLDER * adh)6976 ATLAS_DSET_HOLDER *Free_Atlas_Dset_Holder(ATLAS_DSET_HOLDER *adh)
6977 {
6978    if (!adh) return(NULL);
6979    if (adh->apl2) free_atlas_point_list(adh->apl2);
6980    if (adh->adset) DSET_delete(adh->adset);
6981    free(adh);
6982    return(NULL);
6983 }
6984 
Init_Atlas_Dset_Holder(ATLAS * atlas)6985 int Init_Atlas_Dset_Holder(ATLAS *atlas)
6986 {
6987    ENTRY("New_Atlas_Dset_Holder");
6988 
6989    if (!atlas) RETURN(0);
6990 
6991    if (atlas->adh) {
6992       ERROR_message("Non NULL ADH this is not allowed here");
6993       RETURN(0);
6994    }
6995 
6996    /* initialize atlas dataset holder, adh, to null defaults */
6997    atlas->adh = (ATLAS_DSET_HOLDER *)calloc(1, sizeof(ATLAS_DSET_HOLDER));
6998    atlas->adh->adset = NULL;
6999    atlas->adh->params_set = 0;
7000    atlas->adh->mxlablen = -1;
7001    atlas->adh->lrmask = NULL;
7002    atlas->adh->maxkeyval = -1;
7003    atlas->adh->minkeyval = 1000000;
7004    atlas->adh->duplicateLRentries = 0;
7005                  /* Are LR labels listed in atlas->adh->apl2->at_point and
7006                  under the same code?
7007                   (only case I know of is in old  TTO_list ) */
7008    atlas->adh->apl2 = NULL;
7009    atlas->adh->build_lr = 0;
7010                /* assume we do *not* need to figure out left,right*/
7011    atlas->adh->mxlablen = ATLAS_CMAX;
7012    atlas->adh->probkey = -2;
7013 
7014    RETURN(1);
7015 }
7016 
Atlas_With_Trimming(char * atname,int LoadLRMask,ATLAS_LIST * atlas_list)7017 ATLAS *Atlas_With_Trimming(char *atname, int LoadLRMask,
7018                                        ATLAS_LIST *atlas_list)
7019 {
7020 
7021    int ii, pmap;
7022    int LocalHead = wami_lh();
7023    static int n_warn = 0, lr_notfound = 0;
7024    ATR_int *pmap_atr;
7025    ATLAS *atlas=NULL;
7026    ATLAS *atlas_lr = NULL;
7027 
7028    ENTRY("Atlas_With_Trimming");
7029 
7030    if (!atlas_list && !(atlas_list = get_G_atlas_list())) {
7031       ERROR_message("Cannot get me an atlas list");
7032       RETURN(NULL);
7033    }
7034 
7035    /* Get the atlas structure from the list */
7036    if (!(atlas = get_Atlas_Named(atname, atlas_list))) {
7037       if (wami_verb()) {
7038          ERROR_message("Cannot find atlas %s", atname);
7039       }
7040       RETURN(NULL);
7041    }
7042 
7043    if(ATL_WEB_TYPE(atlas)) {
7044       if(ATL_FOUND(atlas)){
7045          if(wami_verb()) {
7046             INFO_message("reusing web atlas in atlas with trimming");
7047          }
7048          RETURN(atlas);
7049       }
7050       if(wami_verb()) {
7051          INFO_message("using web atlas in atlas with trimming");
7052          INFO_message("adh is %d", atlas->adh);
7053       }
7054       atlas->atlas_found = 1;
7055       if (!Init_Atlas_Dset_Holder(atlas)) {
7056          ERROR_message("Failed to initialize ADH for atlas %s",
7057                         Atlas_Name(atlas));
7058          RETURN(NULL);
7059       }
7060 
7061       RETURN(atlas);
7062    }
7063 
7064 
7065    /* Now get dset if it is missing */
7066    if (!ATL_DSET(atlas)) {
7067       if (LocalHead)
7068          fprintf(stderr,"Loading %s\n", atname);
7069       if (ATL_FOUND(atlas)==-1)   /* already tried to load and failed */
7070          RETURN(NULL);            /* don't try again */
7071 
7072       if (!(genx_load_atlas_dset(atlas))) {   /* initialize atlas structures (adh) */
7073          atlas->atlas_found = -1; /* could not find atlas, don't try again*/
7074          if (wami_verb()) {
7075              if (!n_warn || wami_verb()>1) {
7076                WARNING_message(  "Could not read atlas dset: %s \n"
7077                       "See whereami -help for help on installing atlases. ",
7078                       ATL_NAME_S(atlas),
7079           (wami_verb() > 1) ? "":"\nOther similar warnings are now muted\n" );
7080             ++(n_warn);
7081             }
7082          }
7083          RETURN(NULL);
7084       }
7085       atlas->atlas_found = 1; /* found the atlas okay */
7086 
7087    } else {
7088       if (LocalHead) INFO_message("Reusing dset");
7089       /* reload, in case it was purged */
7090       for (ii=0; ii<DSET_NVALS(ATL_DSET(atlas)); ++ii) {
7091          if (DSET_BRICK_IS_PURGED(ATL_DSET(atlas), ii)) {
7092             DSET_load(ATL_DSET(atlas)) ;
7093             break;
7094          }
7095       }
7096    }
7097 
7098    /* Now the trimming */
7099    if (!ATL_ADH_SET(atlas)) {
7100       if (LocalHead) {
7101          INFO_message("Filling ADH");
7102          fprintf(stderr,"Getting NIML attribute segmentation\n");
7103       }
7104       if (atlas->adh->apl2) {
7105          if (wami_verb()) INFO_message("Recreating apl2");
7106          free_atlas_point_list(atlas->adh->apl2);
7107          atlas->adh->apl2 = NULL;
7108       }
7109       /* check to see if atlas dataset has NIML attributes for segmentation */
7110       atlas->adh->apl2 = dset_niml_to_atlas_list(ATL_DSET(atlas));
7111       if(atlas->adh->apl2 == NULL) {
7112          if (LocalHead) fprintf(stderr,"No NIML attributes.\n"
7113                              "Getting hard-coded segmentation\n");
7114 
7115          if(set_adh_old_way(atlas->adh, Atlas_Name(atlas)))
7116             WARNING_message(  "Could not read atlas dset4 %s \n"
7117                                "See whereami -help for help on installing "
7118                                "atlases.\n", atlas->dset_name );
7119       } else {
7120          if (LocalHead) fprintf(stderr,"NIML attributes being used.\n");
7121 
7122          for (ii=0; ii<MAX_ELM(atlas->adh->apl2); ++ii) {
7123             if(atlas->adh->apl2->at_point[ii].tdval > atlas->adh->maxkeyval)
7124                 atlas->adh->maxkeyval = atlas->adh->apl2->at_point[ii].tdval;
7125             if(atlas->adh->apl2->at_point[ii].tdval < atlas->adh->minkeyval)
7126                 atlas->adh->minkeyval = atlas->adh->apl2->at_point[ii].tdval;
7127          }
7128          atlas->adh->duplicateLRentries = 0;
7129          atlas->adh->build_lr = 0;
7130          if (LocalHead) print_atlas_point_list(atlas->adh->apl2);
7131          pmap_atr = THD_find_int_atr(atlas->adh->adset->dblk,"ATLAS_PROB_MAP") ;
7132          if(pmap_atr!=NULL) {
7133             pmap = pmap_atr->in[0] ;
7134             if (pmap==1)
7135                atlas->adh->probkey = 0;
7136             else
7137                atlas->adh->probkey = -1;
7138             if (LocalHead) fprintf(stderr, "probability map %d\n", pmap);
7139          }
7140 
7141       }
7142 
7143       /* have LR mask ? */
7144       /* check to see if dataset has to be distinguished
7145          left-right based on LR atlas */
7146       if (atlas->adh->build_lr && LoadLRMask) {
7147             /* DO NOT ask Atlas_With_Trimming to load LRMask in next call !! */
7148          atlas_lr = NULL;
7149          if(lr_notfound==0)
7150             atlas_lr = Atlas_With_Trimming("CA_N27_LR", 0, atlas_list);
7151          if (!atlas_lr) {
7152             lr_notfound = 1;
7153             if (wami_verb()) {
7154                ERROR_message("Could not read LR atlas\n"
7155                              "LR decision will be based on coordinates.");
7156             }
7157          } else {
7158             atlas->adh->lrmask = DSET_BRICK_ARRAY(ATL_DSET(atlas_lr),0);
7159             if (!atlas->adh->lrmask) {
7160                lr_notfound = 1;
7161                ERROR_message("Unexpected NULL array.\n"
7162                              "Proceeding without LR mask");
7163             }
7164          }
7165       }
7166 
7167       atlas->adh->params_set = 1;   /* mark as initialized */
7168    } else {
7169       if (LocalHead) INFO_message("Reusing ADH");
7170    }
7171 
7172    RETURN(atlas);
7173 }
7174 
7175 /*! Fills in the ATLAS structure if it needs filling */
genx_load_atlas_dset(ATLAS * atlas)7176 int genx_load_atlas_dset(ATLAS *atlas)
7177 {
7178    int LocalHead = wami_lh();
7179 
7180    ENTRY("genx_load_atlas_dset");
7181 
7182    /* Load the dataset */
7183    if(ATL_DSET(atlas) == NULL) {
7184       /* initialize holder */
7185       if (!Init_Atlas_Dset_Holder(atlas)) {
7186          ERROR_message("Failed to initialize ADH for atlas %s",
7187                         Atlas_Name(atlas));
7188          RETURN(0);
7189       }
7190       if (LocalHead)
7191          fprintf(stderr,"genx loading dset %s\n", atlas->dset_name);
7192       atlas->adh->adset = load_atlas_dset(atlas->dset_name);
7193       if (ATL_DSET(atlas) == NULL) {
7194          if (LocalHead) {
7195             WARNING_message("Could not read atlas dataset: %s \n"
7196                          "See whereami -help for help on installing atlases.\n",
7197                           atlas->dset_name);
7198          }
7199          /* For the moment, cleanup and return. */
7200          atlas->adh = Free_Atlas_Dset_Holder(atlas->adh);
7201          RETURN(0);
7202       }
7203    } else {
7204       if (LocalHead)
7205          fprintf(stderr,"genx dset %s already loaded\n", atlas->dset_name);
7206    }
7207 
7208    RETURN(1);
7209 }
7210 
7211 /* purge atlas to save memory */
purge_atlas(char * atname)7212 int purge_atlas(char *atname) {
7213    ATLAS *atlas=NULL;
7214    THD_3dim_dataset *dset=NULL;
7215 
7216    ENTRY("purge_atlas");
7217 
7218    /* Get the atlas structure from the list */
7219    if (!(atlas = get_Atlas_Named(atname, NULL))) {
7220       if (wami_verb()) {
7221          INFO_message("Cannot find atlas %s for purging", atname);
7222       }
7223       RETURN(1);
7224    }
7225    if (!(dset=ATL_DSET(atlas))) {
7226       if (wami_verb()) {
7227          INFO_message("Atlas %s's dset not loaded", atname);
7228       }
7229       RETURN(1);
7230    }
7231 
7232    PURGE_DSET(dset);
7233    RETURN(1);
7234 }
7235 
7236 
atlas_point_to_atlas_point_list(ATLAS_POINT * apl,int n_pts)7237 ATLAS_POINT_LIST *atlas_point_to_atlas_point_list(ATLAS_POINT * apl, int n_pts)
7238 {
7239    ATLAS_POINT_LIST *apl2 = NULL;
7240    int i;
7241 
7242    if (!apl) return(NULL);
7243 
7244    apl2 = (ATLAS_POINT_LIST *)calloc(1,sizeof(ATLAS_POINT_LIST));
7245    apl2->n_points = n_pts;
7246    apl2->at_point = (ATLAS_POINT *)calloc(n_pts, sizeof(ATLAS_POINT));
7247    for (i=0; i<n_pts; ++i) {
7248       NI_strncpy(apl2->at_point[i].name,apl[i].name,ATLAS_CMAX);
7249       NI_strncpy(apl2->at_point[i].sblabel,apl[i].sblabel,ATLAS_CMAX);
7250       NI_strncpy(apl2->at_point[i].longname,apl[i].longname,ATLAS_CMAX);
7251       apl2->at_point[i].tdval = apl[i].tdval;
7252       apl2->at_point[i].okey = apl[i].okey;
7253       apl2->at_point[i].tdlev = apl[i].tdlev;
7254       apl2->at_point[i].xx = apl[i].xx;
7255       apl2->at_point[i].yy = apl[i].yy;
7256       apl2->at_point[i].zz = apl[i].zz;
7257    }
7258    return(apl2);
7259 }
7260 
set_adh_old_way(ATLAS_DSET_HOLDER * adh,char * aname)7261 int set_adh_old_way(ATLAS_DSET_HOLDER *adh, char *aname)
7262 {
7263    int ii;
7264    ATLAS_POINT_LIST *apl=NULL;
7265 
7266    ENTRY("set_adh_old_way");
7267 
7268    if (!aname) RETURN(1);
7269       /* DO NOT CALL atlas_point_list or you will cause recursion
7270          with Atlas_With_Trimming */
7271    if (!(apl = atlas_point_list_old_way(aname))) {
7272       ERROR_message(
7273          "Malheur de malheur >%s< is an atlas with no atlas points!", aname);
7274       RETURN(1);
7275    }
7276    adh->apl2 = NULL;
7277    adh->probkey = -2;
7278 
7279           if (!strcmp(aname,"CA_N27_MPM")) {
7280      adh->mxlablen = ATLAS_CMAX;
7281      adh->probkey = -2;
7282      adh->apl2 = atlas_point_to_atlas_point_list(apl->at_point, apl->n_points);
7283      /* Are LR labels listed in adh->apl and under the same code?
7284        (only case I know of is in TTO_list - this will not be allowed */
7285      adh->duplicateLRentries = 0;
7286    } else if(!strcmp(aname,"CA_N27_ML")) {
7287      /* Load the MacroLabels */
7288      adh->mxlablen = ATLAS_CMAX;
7289      adh->probkey = -1;
7290      adh->apl2 = atlas_point_to_atlas_point_list(apl->at_point, apl->n_points);
7291      adh->duplicateLRentries = 0;
7292    } else if(!strcmp(aname,"CA_N27_LR")) {
7293      adh->mxlablen = ATLAS_CMAX;
7294      adh->probkey = -1;
7295      adh->apl2 = atlas_point_to_atlas_point_list(apl->at_point, apl->n_points);
7296      /* Are LR labels listed in adh->apl and under the same code?
7297          (only case I know of is in TTO_list*/
7298      adh->duplicateLRentries = 0;
7299    } else if(!strcmp(aname,"CA_N27_PM")) {
7300      adh->mxlablen = ATLAS_CMAX;
7301      adh->maxkeyval = -1; /* not appropriate */
7302      adh->minkeyval = INT_MAX; /* not appropriate */
7303      adh->probkey = 0;
7304 
7305      adh->apl2= atlas_point_to_atlas_point_list(apl->at_point, apl->n_points);
7306                ; /* use cytoarchitectonic list for probability maps*/
7307      adh->duplicateLRentries = 0;
7308    } else if(!strcmp(aname,"TT_Daemon")) {
7309      adh->mxlablen = ATLAS_CMAX;
7310      adh->probkey = -1;
7311      adh->apl2 = atlas_point_to_atlas_point_list(apl->at_point, apl->n_points);
7312      adh->duplicateLRentries = 1;
7313    } else {
7314      RETURN(1); /* no old type atlas like this */
7315    }
7316 
7317     if(adh->probkey == 0) RETURN(0);
7318 
7319     adh->maxkeyval = -1;
7320     adh->minkeyval = INT_MAX;
7321     for (ii=0; ii<MAX_ELM(adh->apl2); ++ii) {
7322        if(adh->apl2->at_point[ii].tdval > adh->maxkeyval)
7323            adh->maxkeyval = adh->apl2->at_point[ii].tdval;
7324        if(adh->apl2->at_point[ii].tdval < adh->minkeyval)
7325            adh->minkeyval = adh->apl2->at_point[ii].tdval;
7326     }
7327 
7328    RETURN(0);
7329 }
7330 
7331 
7332 /* return 1 if a key should have a label in the atlas */
is_atlas_key_labeled(ATLAS * atlas,int key)7333 byte is_atlas_key_labeled(ATLAS *atlas, int key) {
7334    if (!key) return(0);
7335    if (  key < atlas->adh->minkeyval ||
7336          key > atlas->adh->maxkeyval) return(0);
7337    else return(1);
7338 }
7339 
7340 /* return 1 if atlas has integer key labels, 0 otherwise*/
is_integral_atlas(ATLAS * atlas)7341 byte is_integral_atlas(ATLAS *atlas) {
7342 /* drg - not sure this function is really useful. It seems is_probabilistic()
7343    below is good enough for where it's used as equivalent to not probabilisic.
7344    I think I had used the existence of the point list as a flag of whether
7345    to consider looking for values. Now if the future holds a third or other
7346    types of atlases, then we might use this or something more complicated. */
7347    /* New atlases should have apl2, but not old ones*/
7348    if (atlas->adh->apl2) return(1);
7349    return(0);
7350 }
7351 
is_probabilistic_atlas(ATLAS * atlas)7352 byte is_probabilistic_atlas(ATLAS *atlas) {
7353    if (wami_verb()) {
7354       WARNING_message(
7355          "Checking for probabilistic atlas probkey and apl2 pointer (%f, %p)",
7356                   atlas->adh->probkey, atlas->adh->apl2);
7357    }
7358    if (atlas->adh->probkey != 0.0) return(0);
7359    return(1);
7360 }
7361 
7362 /* return the label associated with a key,
7363    see also Atlas_Val_Key_to_Val_Name
7364 *  main function to get label from index key*/
atlas_key_label(ATLAS * atlas,int key,ATLAS_COORD * ac)7365 char *atlas_key_label(ATLAS *atlas, int key, ATLAS_COORD *ac) {
7366    char *klab = NULL;
7367    int ii;
7368    if( key != 0 ){            /* find label     */
7369       for( ii=0 ; ii < MAX_ELM(atlas->adh->apl2) ; ii++ ) {
7370          if( key == atlas->adh->apl2->at_point[ii].tdval ) break ;
7371       }
7372       if( ii < MAX_ELM(atlas->adh->apl2) )  {          /* always true? */
7373          // klab = atlas->adh->apl2->at_point[ii].name;
7374          klab = Atlas_name_choice(&atlas->adh->apl2->at_point[ii]);
7375          if( atlas->adh->duplicateLRentries && ac ) {
7376                klab =
7377                   AddLeftRight( NoLeftRight(atlas->adh->apl2->at_point[ii].name),
7378                                  (ac->x<0.0)?'R':'L');
7379          }
7380       }
7381    }
7382    return(klab);
7383 }
7384 
7385 /* Return the label (and key) of the area corresponding
7386    to the sub-brick in the probability atlas */
prob_atlas_sb_to_label(ATLAS * atlas,int sb,int * key)7387 char *prob_atlas_sb_to_label(ATLAS *atlas, int sb, int *key)
7388 {
7389    int i, nlab;
7390    char *lab_buf=NULL; /* no free please */
7391 
7392    ENTRY("prob_atlas_sb_to_label");
7393 
7394    *key = -1;
7395 
7396    if (!atlas->adh->apl2) {
7397       ERROR_message("Have no apl2");
7398       RETURN(NULL);
7399    }
7400 
7401    nlab = strlen(atlas->adh->adset->dblk->brick_lab[sb]);
7402 
7403    if (nlab > atlas->adh->mxlablen) {
7404       ERROR_message("Dset labels too long! Max allowed is %d, proceeding...",
7405                     atlas->adh->mxlablen);
7406    }
7407 
7408    if(wami_verb()>1)
7409       INFO_message("Trying to find a match for sub-brick label in atlas point list %s\n",
7410                   atlas->adh->adset->dblk->brick_lab[sb]);
7411 
7412    for (i=0; i<atlas->adh->apl2->n_points; ++i) {
7413       lab_buf = atlas->adh->apl2->at_point[i].sblabel;
7414 /*      lab_buf = Clean_Atlas_Label(atlas->adh->apl2->at_point[i].sblabel);*/
7415       if(wami_verb()>1)
7416          INFO_message("struct %d has label %s", i, lab_buf);
7417       if ( (nlab == strlen(lab_buf)) &&
7418             !strcmp(lab_buf, atlas->adh->adset->dblk->brick_lab[sb])) {
7419          *key = atlas->adh->apl2->at_point[i].tdval;
7420          if (wami_verb()>1) {
7421             INFO_message(" Matched %s with %s\n",
7422                      atlas->adh->adset->dblk->brick_lab[sb],
7423                      atlas->adh->apl2->at_point[i].sblabel);
7424          }
7425          break;
7426       }
7427    }
7428    if (*key >= 0) {
7429       RETURN(atlas->adh->apl2->at_point[i].name);
7430    }
7431    RETURN(NULL);
7432 }
7433 
Atlas_Voxel_Value(ATLAS * atlas,int sb,int ijk)7434 int Atlas_Voxel_Value(ATLAS *atlas, int sb, int ijk)
7435 {
7436    byte *ba=NULL;
7437    short *sa=NULL;
7438    float *fa=NULL, sbf=1.0;
7439    int ival = -1;
7440 
7441    switch(DSET_BRICK_TYPE(ATL_DSET(atlas), sb)) {
7442       case MRI_byte:
7443          ba = (byte *)DSET_ARRAY(ATL_DSET(atlas), sb);
7444          ival = (int)ba[ijk];
7445          break;
7446       case MRI_short:
7447          sa = (short *)DSET_ARRAY(ATL_DSET(atlas), sb);
7448          ival = (int)sa[ijk];
7449          break;
7450       case MRI_float:
7451          fa = (float *)DSET_ARRAY(ATL_DSET(atlas), sb);
7452          sbf = DSET_BRICK_FACTOR(ATL_DSET(atlas), sb);
7453          if (sbf == 0.0) sbf = 1.0;
7454          ival = (int)(fa[ijk]*sbf);
7455          break;
7456       default:
7457          ERROR_message("Bad Atlas dset brick type %d\n",
7458                         DSET_BRICK_TYPE(ATL_DSET(atlas), sb));
7459          break;
7460    }
7461    return(ival);
7462 
7463 }
7464 
7465 /*! get floating point value at ijk index in sub-brick sb of atlas dataset*/
Atlas_Voxel_fValue(ATLAS * atlas,int sb,int ijk)7466 float Atlas_Voxel_fValue(ATLAS *atlas, int sb, int ijk)
7467 {
7468    byte *ba=NULL;
7469    short *sa=NULL;
7470    float *fa=NULL, sbf=1.0;
7471    float fval = 0.0;
7472 
7473    switch(DSET_BRICK_TYPE(ATL_DSET(atlas), sb)) {
7474       case MRI_byte:
7475          ba = (byte *)DSET_ARRAY(ATL_DSET(atlas), sb);
7476          fval = (float)ba[ijk];
7477          break;
7478       case MRI_short:
7479          sa = (short *)DSET_ARRAY(ATL_DSET(atlas), sb);
7480          fval = (float)sa[ijk];
7481          break;
7482       case MRI_float:
7483          fa = (float *)DSET_ARRAY(ATL_DSET(atlas), sb);
7484          fval = (float)fa[ijk];
7485          break;
7486       default:
7487          ERROR_message("Bad Atlas dset brick type %d\n",
7488                         DSET_BRICK_TYPE(ATL_DSET(atlas), sb));
7489          return(0.0);
7490          break;
7491    }
7492    sbf = DSET_BRICK_FACTOR(ATL_DSET(atlas), sb);
7493    if ((sbf == 0.0) || (sbf==1.0)) return(fval);
7494 
7495    fval = fval*sbf;
7496 
7497    return(fval);
7498 }
7499 
7500 /*! for now, always return 250 as factor to scale PMap values
7501    old PMap atlases used byte values from 0-250.
7502    Dividing by 250 gives scaled values from 0-1.
7503    New scale factor from dataset in Atlas_Voxel_fValue should
7504    take care of general cases
7505 */
7506 float
Get_PMap_Factor()7507 Get_PMap_Factor()
7508 {
7509   return(250.0);
7510 }
7511 
7512 /*!
7513    \brief Returns a whereami query from just one atlas
7514    \param atlas ATLAS *
7515    \param Xrai (float[3]) x,y,z in RAI
7516    \param wami append results to this wami
7517    \return wami the query results
7518 */
whereami_in_atlas(char * aname,ATLAS_COORD ac,ATLAS_QUERY ** wamip)7519 int whereami_in_atlas(  char *aname,
7520                         ATLAS_COORD ac,
7521                         ATLAS_QUERY **wamip)
7522 {
7523    int nfind, *b_find=NULL, *rr_find=NULL ;
7524    int ii, kk, ix,jy,kz , nx,ny,nz,nxy ,sb=0;
7525    int aa,bb,cc , ff,baf;
7526    char *blab ;
7527    ATLAS_ZONE *zn = NULL;
7528    THD_ivec3 ijk ;
7529    THD_fvec3 mmxyz ;
7530    ATLAS *atlas=NULL;
7531    int LocalHead = wami_lh();
7532    float fval = 0;
7533    static char find_warn = 0, nolabel_warn = 1;
7534    char *webpage = NULL;
7535    char *connpage = NULL;
7536 
7537    ENTRY("whereami_in_atlas");
7538       if (wami_verb()){
7539         INFO_message("whereami_in_atlas %s", aname);
7540       }
7541 
7542    if (!aname) {
7543       ERROR_message("No name");
7544       RETURN(0);
7545    }
7546    if (!wamip ) {
7547       ERROR_message("Need wamip != NULL");
7548       RETURN(0);
7549    }
7550    if (!(atlas = Atlas_With_Trimming(aname, 1, NULL))) {
7551       if (LocalHead) ERROR_message("Could not load atlas %s", aname);
7552       RETURN(0);
7553    }
7554 
7555    if (LocalHead) {
7556       INFO_message("Wami on atlas %s", aname);
7557       INFO_message(" integral? %d", is_integral_atlas(atlas));
7558       INFO_message(" probabilistic? %d", is_probabilistic_atlas(atlas));
7559       INFO_message(" atlas type ? %s", ATL_TYPE_S(atlas));
7560    }
7561 
7562    if (strcmp(atlas->space, ac.space_name)) {
7563       ERROR_message("Atlas space names mismatch: %s != %s",
7564                      atlas->space, ac.space_name);
7565       RETURN(0);
7566    }
7567 
7568    if (strncmp(ac.orcode, "RAI", 3)) {
7569       ERROR_message("AC orientation (%s) not RAI",
7570                      ac.orcode);
7571       RETURN(0);
7572    }
7573 
7574 
7575    if (MAX_FIND < 0) {
7576       Set_Whereami_Max_Find(MAX_FIND);
7577    }
7578 
7579    b_find = (int*)calloc(MAX_FIND, sizeof(int));
7580    rr_find = (int*)calloc(MAX_FIND, sizeof(int));
7581    if (!b_find || !rr_find) {
7582       ERROR_message( "Jimney Crickets!\nFailed to allocate for finds!\n"
7583                      "MAX_FIND = %d\n", MAX_FIND);
7584       RETURN(0);
7585    }
7586 
7587    if (!*wamip) { /* A new query structure, if necessary*/
7588       if (LocalHead) INFO_message("New wami");
7589       *wamip = Add_To_Atlas_Query(NULL, NULL);
7590    }
7591 
7592    if (LocalHead) {
7593       INFO_message("Coords: %f %f %f (%s, %s):\n",
7594                      ac.x, ac.y, ac.z, ac.orcode, ac.space_name);
7595       print_atlas(atlas,0);
7596    }
7597 
7598    if ((Atlas_Name(atlas))[0] == '\0') {
7599       ERROR_message("An atlas with no name\n");
7600       print_atlas(atlas, 0);
7601       RETURN(0);
7602    }
7603    if (LocalHead)
7604       INFO_message(  "Now whereaming atlas %s, is_integral %d, is_prob %d\n",
7605                      atlas->dset_name,
7606                      is_integral_atlas(atlas), is_probabilistic_atlas(atlas));
7607 
7608    if (  is_integral_atlas(atlas) &&
7609          !is_probabilistic_atlas(atlas) &&
7610          !ATL_WEB_TYPE(atlas) ) {                    /* the multi-radius searches */
7611       nfind = 0 ;
7612       for (sb=0; sb < DSET_NVALS(ATL_DSET(atlas)); ++sb) {
7613          if (LocalHead)
7614             fprintf(stderr,
7615                "Processing sub-brick %d of atlas %s\n",
7616                sb,  Atlas_Name(atlas));
7617          if (!DSET_BRICK_ARRAY(ATL_DSET(atlas),sb)) {
7618             ERROR_message("Unexpected NULL array");
7619             RETURN(0);
7620          }
7621          if (WAMIRAD < 0.0) {
7622             WAMIRAD = Init_Whereami_Max_Rad();
7623          }
7624          if( wamiclust == NULL ){
7625             wamiclust = MCW_build_mask( 1.0,1.0,1.0 , WAMIRAD ) ;
7626             if( wamiclust == NULL )
7627                RETURN(0) ;  /* should not happen! */
7628 
7629             for( ii=0 ; ii < wamiclust->num_pt ; ii++ ) /* set radius */
7630                wamiclust->mag[ii] =
7631                   (int)rint(sqrt((double)
7632                         (wamiclust->i[ii]*wamiclust->i[ii] +
7633                          wamiclust->j[ii]*wamiclust->j[ii] +
7634                          wamiclust->k[ii]*wamiclust->k[ii]) )) ;
7635 
7636             MCW_sort_cluster( wamiclust ) ;  /* sort by radius */
7637          }
7638 
7639          /*-- find locations near the given one that are in the Atlas --*/
7640          mmxyz = THD_dicomm_to_3dmm( ATL_DSET(atlas) ,
7641                                   TEMP_FVEC3(ac.x,ac.y,ac.z));
7642          ijk = THD_3dmm_to_3dind( ATL_DSET(atlas) ,
7643                                   mmxyz);
7644          UNLOAD_IVEC3(ijk,ix,jy,kz) ;
7645 
7646          nx = DSET_NX(ATL_DSET(atlas)) ;   /* size of atlas dataset axes */
7647          ny = DSET_NY(ATL_DSET(atlas)) ;
7648          nz = DSET_NZ(ATL_DSET(atlas)) ; nxy = nx*ny ;
7649 
7650          /*-- check the exact input location --*/
7651          kk = ix + jy*nx + kz*nxy ;        /* index into brick arrays */
7652          if( nfind >= MAX_FIND ) {
7653            if (!getenv("AFNI_WHEREAMI_NO_WARN") && (!find_warn)) {
7654             INFO_message(
7655       "Potentially more regions could be found than the %d reported.\n"
7656       "Set the environment variable AFNI_WHEREAMI_MAX_FIND to higher\n"
7657       "than %d if you desire a larger report.\n"
7658       "It behooves you to also checkout AFNI_WHEREAMI_MAX_SEARCH_RAD\n"
7659       "and AFNI_WHEREAMI_NO_WARN. See whereami -help for detail.\n",
7660                               MAX_FIND, MAX_FIND);
7661            find_warn = 1;
7662            }
7663            break ;  /* don't find TOO much */
7664          }
7665          else {
7666              b_find[nfind] = Atlas_Voxel_Value(atlas, sb, kk);
7667              if( is_atlas_key_labeled(atlas, b_find[0] )) {
7668                 rr_find[0] = 0     ;
7669                 if (LocalHead)
7670                    fprintf(stderr,"Adding b_find[%d]=%d rr_find[%d]=%d\n",
7671                                nfind, b_find[nfind], nfind, rr_find[nfind]);
7672                 nfind++ ;
7673              }
7674          }
7675 
7676          /*-- check locations near it --*/
7677 
7678          for( ii=0 ; ii < wamiclust->num_pt ; ii++ ){
7679 
7680             /* compute index of nearby location, skipping if outside atlas */
7681 
7682             aa = ix + wamiclust->i[ii] ;
7683                if( aa < 0 || aa >= nx ) continue ;
7684             bb = jy + wamiclust->j[ii] ;
7685                if( bb < 0 || bb >= ny ) continue ;
7686             cc = kz + wamiclust->k[ii] ;
7687                if( cc < 0 || cc >= nz ) continue ;
7688 
7689             kk  = aa + bb*nx + cc*nxy ;   /* index into bricks */
7690             baf = Atlas_Voxel_Value(atlas, sb, kk) ; /* Atlas marker there */
7691 
7692             if( baf == 0 )                            continue ;
7693 
7694             for( ff=0 ; ff < nfind ; ff++ ){       /* cast out         */
7695                if( baf == b_find[ff] ) baf = 0 ;  /* duplicate labels  */
7696             }
7697 
7698             if (!is_atlas_key_labeled(atlas, baf)) baf = 0;
7699 
7700             if( baf == 0 )                            continue ;
7701 
7702             if(nfind < MAX_FIND) {
7703                b_find[nfind] = baf ;  /* save what we found */
7704                rr_find[nfind] = (int) wamiclust->mag[ii] ;
7705                if (LocalHead)
7706                   fprintf(stderr,"Adding b_find[%d]=%d rr_find[%d]=%d\n",
7707                               nfind, b_find[nfind], nfind, rr_find[nfind]);
7708                nfind++ ;
7709             }
7710 
7711             if( nfind >= MAX_FIND ) {
7712               if (!getenv("AFNI_WHEREAMI_NO_WARN") && (!find_warn)) {
7713                INFO_message(
7714          "Potentially more regions could be found than the %d reported.\n"
7715          "Set the environment variable AFNI_WHEREAMI_MAX_FIND to higher\n"
7716          "than %d if you desire a larger report.\n"
7717          "It behooves you to also checkout AFNI_WHEREAMI_MAX_SEARCH_RAD\n"
7718          "and AFNI_WHEREAMI_NO_WARN. See whereami -help for detail.\n",
7719                                  MAX_FIND, MAX_FIND);
7720               find_warn = 1;
7721               }
7722               break ;  /* don't find TOO much */
7723             }
7724          }
7725 
7726          /*-- bubble-sort what we found, by radius --*/
7727 
7728          if( nfind > 1 ){  /* don't have to sort only 1 result */
7729            int swap, tmp ;
7730            do{
7731               swap=0 ;
7732               for( ii=1 ; ii < nfind ; ii++ ){
7733                  if( rr_find[ii-1] > rr_find[ii] ){
7734                    tmp = rr_find[ii-1];
7735                      rr_find[ii-1] = rr_find[ii];
7736                         rr_find[ii] = tmp;
7737                    tmp = b_find[ii-1];
7738                      b_find[ii-1] = b_find[ii];
7739                         b_find[ii] = tmp;
7740                    swap++ ;
7741                  }
7742               }
7743            } while(swap) ;
7744          }
7745 
7746          /* build query results */
7747          /*rff = -1 ; */ /* rff = radius of last found label */
7748 
7749       } /* for each sub-brick */
7750       if (LocalHead) INFO_message("   %d findings...\n", nfind);
7751 
7752       for( ff=0 ; ff < nfind ; ff++ ){
7753          baf = b_find[ff] ; blab = NULL ;
7754          blab = atlas_key_label(atlas, baf, &ac);
7755 
7756          if( blab == NULL && is_atlas_key_labeled(atlas, baf)) {
7757             if(nolabel_warn) {
7758                WARNING_message(
7759                "No label found for code %d in atlas %s\n"
7760                "Similar missing labels will be ignored. Continuing...",
7761                             baf, Atlas_Name(atlas));
7762               nolabel_warn = 0;
7763             }
7764             continue ;  /* no labels? */
7765          }
7766 
7767          zn = Get_Atlas_Zone (*wamip, (int)rr_find[ff] );
7768                   /* zone levels are based on search radius */
7769 
7770          webpage = atlas_suppinfo_webpage(atlas,blab);
7771          connpage = atlas_suppinfo_connpage(atlas,blab);
7772          zn = Atlas_Zone(  zn, zn->level,
7773                            blab, baf, atlas->adh->probkey, rr_find[ff],
7774                            Atlas_Name(atlas), webpage, connpage);
7775          if(webpage) free(webpage);
7776          if(connpage) free(connpage);
7777 
7778          if (LocalHead)
7779             INFO_message("Adding zone on %s to wami\n",
7780                             Atlas_Name(atlas));
7781          *wamip = Add_To_Atlas_Query(*wamip, zn);
7782 
7783          /*rff = rr_find[ff] ;*/  /* save for next time around */
7784       }
7785 
7786    }
7787 
7788    if (is_probabilistic_atlas(atlas) && !ATL_WEB_TYPE(atlas)) { /* the PMAPS */
7789       if (LocalHead)
7790          fprintf(stderr,"Processing with probabilistic atlas %s\n",
7791                         atlas->dset_name);
7792 
7793       /*-- find locations near the given one that are in the Atlas --*/
7794       mmxyz = THD_dicomm_to_3dmm( ATL_DSET(atlas) ,
7795                          TEMP_FVEC3(ac.x,ac.y,ac.z));
7796       ijk = THD_3dmm_to_3dind( ATL_DSET(atlas) , mmxyz ) ;
7797       UNLOAD_IVEC3(ijk,ix,jy,kz) ;
7798 
7799       nx = DSET_NX(ATL_DSET(atlas)) ;        /* size of atlas dataset axes */
7800       ny = DSET_NY(ATL_DSET(atlas)) ;
7801       nz = DSET_NZ(ATL_DSET(atlas)) ; nxy = nx*ny ;
7802       kk = ix + jy*nx + kz*nxy ;        /* index into brick arrays */
7803 
7804       zn = Get_Atlas_Zone(*wamip, 0);    /* get the zero level zone */
7805       for (sb=0; sb<DSET_NVALS(ATL_DSET(atlas)); ++sb) {
7806          if (!DSET_BRICK_ARRAY(ATL_DSET(atlas),sb)) {
7807             ERROR_message("Unexpected NULL array");
7808             RETURN(0);
7809          }
7810          fval = Atlas_Voxel_fValue(atlas, sb, kk);
7811          if (LocalHead)
7812             fprintf(stderr,"  ++ Sub-brick %d in %s fval=%f\n",
7813                            sb, atlas->dset_name, fval);
7814          if( fval != 0.0 ){
7815             if(fval>1.0) fval = fval / Get_PMap_Factor(); /* if >1.0, must be old pmap atlases*/
7816             if(fval<get_wami_minprob()) fval = 0.0; /* check against minimum probability */
7817          }
7818 
7819          /* check again with adjusted probability */
7820          if( fval != 0.0 ){
7821             if( atlas->adh->adset->dblk->brick_lab == NULL ||
7822                 atlas->adh->adset->dblk->brick_lab[sb] == NULL) {
7823                if (LocalHead)  fprintf(stderr,"  ++ No Label!\n");
7824                zn = Atlas_Zone(zn, 0, "No Label", -1,
7825                               fval, 0,
7826                               Atlas_Name(atlas), NULL, NULL); /* null for no webpage here */
7827             } else {
7828                if( atlas->adh->adset->dblk->brick_lab[sb] &&
7829                    atlas->adh->adset->dblk->brick_lab[sb][0] != '\0' ){
7830                   blab = prob_atlas_sb_to_label(atlas, sb, &baf);
7831                   if (blab) {
7832                      if (LocalHead) fprintf(stderr," blabing: %s\n", blab);
7833                      webpage = atlas_suppinfo_webpage(atlas,blab);
7834                      connpage = atlas_suppinfo_connpage(atlas,blab);
7835                      zn = Atlas_Zone(zn, 0, blab, baf ,
7836                                     fval, 0,
7837                             Atlas_Name(atlas), webpage, connpage);
7838                      if(webpage) free(webpage);
7839                      if(connpage) free(connpage);
7840                   } else {
7841                      if (LocalHead) fprintf(stderr," no blabing:\n");
7842                      zn = Atlas_Zone(  zn, 0, "Unexpected trouble.",
7843                                        -1, -1.0, 0,
7844                             Atlas_Name(atlas), NULL,NULL); /* null for no webpage here */
7845                   }
7846                } else {
7847                   zn = Atlas_Zone(zn, 0, "Empty Label", -1,
7848                                   fval, 0,
7849                            Atlas_Name(atlas), NULL,NULL); /* null for no webpage here */
7850                }
7851             }
7852             *wamip = Add_To_Atlas_Query(*wamip, zn);
7853          }
7854       }
7855    }
7856 
7857    if (ATL_WEB_TYPE(atlas)) {
7858       wami_query_web(atlas, ac, *wamip);
7859    }
7860 
7861    /* not sure what should be done with this atlas if no known type */
7862    if (!is_integral_atlas(atlas) &&
7863        !is_probabilistic_atlas(atlas) &&
7864        !ATL_WEB_TYPE(atlas))
7865    {
7866       ERROR_message("dunno what to do for atlas %s\n",
7867                      atlas->dset_name);
7868       RETURN(0);
7869    }
7870 
7871    /* Show_Atlas_Query(wami); */
7872 
7873    free(b_find); b_find = NULL; free(rr_find); rr_find = NULL;
7874 
7875    RETURN(1);
7876 }
7877 
7878 /*!
7879    \brief A newer version of whereami_9yards
7880    \param asl (atlas_space_list *) list of atlas spaces to query
7881                If null, then function determines all those
7882                accessible
7883 */
whereami_3rdBase(ATLAS_COORD aci,ATLAS_QUERY ** wamip,ATLAS_SPACE_LIST * asli,ATLAS_LIST * aali)7884 int whereami_3rdBase( ATLAS_COORD aci, ATLAS_QUERY **wamip,
7885                         ATLAS_SPACE_LIST *asli, ATLAS_LIST *aali)
7886 {
7887    ATLAS_QUERY *wami = NULL;
7888    ATLAS_COORD ac;
7889    ATLAS_XFORM_LIST *xfl=NULL, *cxfl=NULL;
7890    ATLAS_SPACE_LIST *asl=get_G_space_list();
7891    ATLAS *atlas=NULL;
7892    int *iatl=NULL, ii;
7893    int N_iatl=0, ia=0;
7894    float xout=0.0, yout=0.0, zout = 0.0;
7895    int LocalHead = wami_lh();
7896 
7897    ENTRY("whereami_3rdBase");
7898    /* initialized ? */
7899    if (!aali) aali = get_G_atlas_list();
7900    if (!aali || aali->natlases == 0) {
7901       ERROR_message("No atlas_alist, or empty one.");
7902       RETURN(0);
7903    }
7904 
7905    /* find list of atlases whose spaces are reachable from aci.spacename */
7906    if (LocalHead) {
7907       print_atlas_list(aali); print_space_list(asl);
7908    }
7909    for (ia=0; ia<aali->natlases; ++ia) {
7910       xfl = report_xform_chain(aci.space_name, aali->atlas[ia].space, 0);
7911       if (xfl) {
7912          ++N_iatl;
7913          iatl = (int*)realloc(iatl, N_iatl*sizeof(int));
7914          iatl[N_iatl-1]=ia;
7915          free_xform_list(xfl); xfl=NULL;
7916       }
7917       else {
7918          if(LocalHead)
7919             WARNING_message(
7920             "No xform chain from space, %s, to atlas %s in space %s",
7921             aci.space_name, aali->atlas[ia].name,
7922             aali->atlas[ia].space);
7923      }
7924    }
7925    if (LocalHead) {
7926       INFO_message("Have %d reachable atlases\n", N_iatl);
7927    }
7928    if (N_iatl<1) {
7929       ERROR_message("No reachable atlases from %s\n", aci.space_name);
7930       ERROR_message("Set AFNI_ATLAS_LIST and/or AFNI_TEMPLATE_SPACE_LIST "
7931                     "to include atlases and spaces for this dataset");
7932       ERROR_message("Alternatively, make sure dataset has space associated "
7933                     "with a known space");
7934       RETURN(0);
7935    }
7936 
7937    /* for each reachable atlas, get query */
7938    for (ia=0; ia<N_iatl; ++ia) {
7939       atlas = &(aali->atlas[iatl[ia]]);
7940       /* get xform, and apply it to coords at input */
7941       if (!(xfl = report_xform_chain(aci.space_name, atlas->space, 0))) {
7942          ERROR_message("Should not happen here");
7943          RETURN(0);
7944       }
7945       cxfl = calc_xform_list(xfl);
7946       apply_xform_chain(cxfl, aci.x, aci.y, aci.z, &xout, &yout, &zout);
7947       if(cxfl)
7948         free_xform_list(cxfl);
7949       if(xfl)
7950         free_xform_list(xfl);
7951 /*      apply_xform_chain(xfl, aci.x, aci.y, aci.z, &xout, &yout, &zout);*/
7952       if (wami_verb() > 1)
7953          INFO_message(
7954            "Coords in: %f, %f, %f (%s) -> out: %f, %f, %f (%s - %s)\n",
7955              aci.x,aci.y,aci.z, aci.space_name, xout,yout,zout,
7956              Atlas_Name(atlas),
7957              atlas->space);
7958 
7959 
7960       /* for web atlases, open up separate query */
7961       /* do specific web request here for non-struct type
7962          and skip regular whereami call */
7963       if(ATL_WEB_TYPE(atlas) && (get_wami_web_reqtype() != WAMI_WEB_STRUCT)){
7964          if (wami_verb() > 1)
7965             INFO_message("trying to access web-based atlas");
7966          elsevier_query_request(xout, yout, zout, atlas, get_wami_web_reqtype());
7967       }
7968       else{  /* regular (non-web) atlas request for local dataset */
7969          XYZ_to_AtlasCoord(xout, yout, zout, "RAI", atlas->space, &ac);
7970          if (!whereami_in_atlas(Atlas_Name(atlas), ac , &wami)) {
7971                if (LocalHead)
7972                   INFO_message("Failed at whereami for %s", Atlas_Name(atlas));
7973             }
7974       }
7975    }
7976 
7977    /* sort the query by zone levels, be nice */
7978    if( wami && wami->N_zone > 1 ){  /* don't have to sort only 1 result */
7979      int swap;
7980      ATLAS_ZONE *tmp ;
7981      do{
7982         swap=0 ;
7983         for( ii=1 ; ii < wami->N_zone ; ii++ ){
7984            if( wami->zone[ii-1]->level > wami->zone[ii]->level ){
7985              tmp = wami->zone[ii-1];
7986              wami->zone[ii-1] = wami->zone[ii];
7987              wami->zone[ii] = tmp;
7988              swap++ ;
7989            }
7990         }
7991      } while(swap) ;
7992    }
7993 
7994 
7995    if (LocalHead) {
7996       Show_Atlas_Query(wami,aali);
7997    }
7998 
7999    *wamip = wami;
8000 
8001    RETURN(1);
8002 }
8003 
whereami_9yards(ATLAS_COORD aci,ATLAS_QUERY ** wamip,ATLAS_LIST * atlas_alist)8004 int whereami_9yards(  ATLAS_COORD aci, ATLAS_QUERY **wamip,
8005                       ATLAS_LIST *atlas_alist)
8006 {
8007    int   ii,kk , ix,jy,kz , nx,ny,nz,nxy ,
8008          aa,bb,cc , ff,baf,rff, iatlas=0, sb = 0 ;
8009    THD_ivec3 ijk ;
8010    short *ba = NULL ;
8011    byte *bba = NULL ;
8012    char *blab ;
8013    int nfind, *b_find=NULL, *rr_find=NULL ;
8014    ATLAS_QUERY *wami = NULL;
8015    ATLAS_ZONE *zn = NULL;
8016    THD_fvec3 vn3, vo3;
8017    THD_fvec3 mmxyz;
8018    ATLAS_COORD ac;
8019    ATLAS *atlas=NULL;
8020    int LocalHead = wami_lh();
8021    int dset_kind;
8022    char *webpage = NULL;
8023    char *connpage = NULL;
8024    float fbaf;
8025    static int iwarn = 0;
8026 
8027    ENTRY("whereami_9yards");
8028 
8029    if (0 && *wamip) { /* Could be building on other wamis */
8030       ERROR_message("Send me a null wamip baby\n");
8031       RETURN(0);
8032    }
8033 
8034    if (!atlas_alist || atlas_alist->natlases == 0) {
8035       ERROR_message("Send me a non null or non empty atlaslist\n");
8036       RETURN(0);
8037    }
8038 
8039    /* check on coord system (!!have to change coord system depending on atlas) */
8040    if (wami_verb()) {
8041       INFO_message("Using the old coord xform method, space name >%s<",
8042                 aci.space_name);
8043    }
8044    if (is_Coord_Space_Named(aci, "MNI_ANAT")) {
8045       LOAD_FVEC3(vo3, aci.x, aci.y, aci.z);
8046       vn3 = THD_mnia_to_tta_N27(vo3);
8047       ac.x = vn3.xyz[0]; ac.y = vn3.xyz[1]; ac.z = vn3.xyz[2];
8048       set_Coord_Space_Name(&ac, aci.space_name);
8049    } else if (is_Coord_Space_Named(aci, "MNI")) {
8050       LOAD_FVEC3(vo3, aci.x, aci.y, aci.z);
8051       vn3 = THD_mni_to_tta_N27(vo3);
8052       ac.x = vn3.xyz[0]; ac.y = vn3.xyz[1]; ac.z = vn3.xyz[2];
8053       set_Coord_Space_Name(&ac, aci.space_name);
8054    } else if (is_Coord_Space_Named(aci, "TLRC")) {
8055       ac.x = aci.x; ac.y = aci.y; ac.z = aci.z;
8056       set_Coord_Space_Name(&ac, aci.space_name);
8057    } else {
8058       ERROR_message("Coordinates in bad space %s.", aci.space_name);
8059       print_atlas_coord(aci);
8060       RETURN(0);
8061    }
8062 
8063    if (MAX_FIND < 0) {
8064       Set_Whereami_Max_Find(MAX_FIND);
8065    }
8066    b_find = (int*)calloc(MAX_FIND, sizeof(int));
8067    rr_find = (int*)calloc(MAX_FIND, sizeof(int));
8068    if (!b_find || !rr_find) {
8069       ERROR_message( "Jimney Crickets!\nFailed to allocate for finds!\n"
8070                      "MAX_FIND = %d\n", MAX_FIND);
8071       RETURN(0);
8072    }
8073 
8074    if (!*wamip) { /* A new query structure, if necessary*/
8075       if (LocalHead) INFO_message("New wami");
8076       wami = Add_To_Atlas_Query(NULL, NULL);
8077    }
8078 
8079    if (LocalHead)
8080       INFO_message("Coords: %f %f %f (%s)\n", ac.x, ac.y, ac.z, ac.space_name);
8081 
8082    for (iatlas=0; iatlas < atlas_alist->natlases; ++iatlas) {/* iatlas loop */
8083       if (wami_verb())
8084          INFO_message(  "Now Processing atlas %s (%d)",
8085                         atlas_alist->atlas[iatlas].dset_name);
8086       if(!ATL_WEB_TYPE(atlas))
8087          atlas = Atlas_With_Trimming(  atlas_alist->atlas[iatlas].name,
8088                                           1, atlas_alist);
8089       if (!atlas) {
8090          if (wami_verb()) {
8091             if (!iwarn || wami_verb() > 1) {
8092                INFO_message("No atlas dataset %s found for whereami location"
8093                             "%s",
8094                        atlas_alist->atlas[iatlas].name,
8095                         wami_verb() < 2 ?
8096                            "\nWarnings for other atlases will be muted.":"");
8097                ++iwarn;
8098             }
8099          }
8100          continue;
8101       }
8102 
8103       dset_kind = (int)DSET_BRICK_TYPE(ATL_DSET(atlas),0) ;
8104 
8105       /* the multi-radius searches - not for probability maps*/
8106       if(atlas->adh->probkey!=0) {
8107             if(dset_kind != MRI_short && dset_kind != MRI_byte ) {
8108                ERROR_message("Atlas dataset %s may only be byte or short,"
8109                              "not data type '%s'",
8110                   DSET_BRIKNAME(ATL_DSET(atlas)) , MRI_TYPE_name[dset_kind] ) ;
8111                RETURN(0);
8112             }
8113 
8114          for (sb=0; sb < DSET_NVALS(ATL_DSET(atlas)); ++sb) {
8115             if (LocalHead)
8116                fprintf(stderr,"Processing sub-brick %d with %s\n",
8117                        sb, atlas->dset_name);
8118             /* make dataset sub-brick integer - change from previous byte
8119                 to allow values > 255 */
8120             if(dset_kind == MRI_short) {
8121                ba = DSET_BRICK_ARRAY(ATL_DSET(atlas),sb); /* short type */
8122                if (!ba) { ERROR_message("Unexpected NULL array"); RETURN(0); }
8123             }
8124             else {
8125                bba = DSET_BRICK_ARRAY(ATL_DSET(atlas),sb); /* byte array */
8126                if (!bba) { ERROR_message("Unexpected NULL array"); RETURN(0); }
8127                if (LocalHead) {
8128 		            fprintf(stderr,"++ have bba = %p, kind = %d\n",
8129                      bba, DSET_BRICK_TYPE(ATL_DSET(atlas),sb));
8130                   fprintf(stderr,"   (byte = %d, short = %d)\n",
8131                      MRI_byte, MRI_short);
8132                }
8133             }
8134 
8135             if (WAMIRAD < 0.0) {
8136                WAMIRAD = Init_Whereami_Max_Rad();
8137             }
8138             if( wamiclust_CA_EZ == NULL ){
8139                wamiclust_CA_EZ = MCW_build_mask( 1.0,1.0,1.0 , WAMIRAD ) ;
8140                if( wamiclust_CA_EZ == NULL )
8141                   RETURN(0) ;  /* should not happen! */
8142 
8143                for( ii=0 ; ii < wamiclust_CA_EZ->num_pt ; ii++ ) /* set radius */
8144                   wamiclust_CA_EZ->mag[ii] =
8145                      (int)rint(sqrt((double)
8146                            (wamiclust_CA_EZ->i[ii]*wamiclust_CA_EZ->i[ii] +
8147                             wamiclust_CA_EZ->j[ii]*wamiclust_CA_EZ->j[ii] +
8148                             wamiclust_CA_EZ->k[ii]*wamiclust_CA_EZ->k[ii]) )) ;
8149 
8150                MCW_sort_cluster( wamiclust_CA_EZ ) ;  /* sort by radius */
8151             }
8152 
8153             /*-- find locations near the given one that are in the Atlas --*/
8154             mmxyz = THD_dicomm_to_3dmm( ATL_DSET(atlas) ,
8155                          TEMP_FVEC3(ac.x,ac.y,ac.z));
8156             ijk = THD_3dmm_to_3dind( ATL_DSET(atlas) ,
8157                                      mmxyz ) ;
8158             UNLOAD_IVEC3(ijk,ix,jy,kz) ;
8159 
8160             nx = DSET_NX(ATL_DSET(atlas)) ;    /* size of atlas dataset axes */
8161             ny = DSET_NY(ATL_DSET(atlas)) ;
8162             nz = DSET_NZ(ATL_DSET(atlas)) ; nxy = nx*ny ;
8163 
8164             nfind = 0 ;
8165 
8166             /*-- check the exact input location --*/
8167 
8168             kk = ix + jy*nx + kz*nxy ;        /* index into brick arrays */
8169 
8170             if(dset_kind == MRI_short)
8171               baf = ba[kk];
8172             else {
8173               baf = bba[kk];
8174               if (LocalHead)  fprintf(stderr,
8175    "Byte value at focus point %d, %d, %d, %f, %f, %f, %d, %d, %d, %d, baf=%d\n",
8176                     ix,jy,kz, ac.x, ac.y, ac.z, nx, ny, nz, kk, baf);
8177             }
8178 
8179             if( baf != 0){
8180                b_find[0] = baf ;
8181                rr_find[0] = 0     ;
8182                if (LocalHead)
8183                   fprintf(stderr,"Adding b_find[%d]=%d rr_find[%d]=%d\n",
8184                               nfind, b_find[nfind], nfind, rr_find[nfind]);
8185                nfind++ ;
8186             }
8187             else{
8188                if (LocalHead)  fprintf(stderr,
8189                   "No value at focus point %d, %d, %d, ba=%d\n", ix,jy,kz, baf);
8190             }
8191             /*-- check locations near it --*/
8192 
8193             for( ii=0 ; ii < wamiclust_CA_EZ->num_pt ; ii++ ){
8194 
8195                /* compute index of nearby location, skipping if outside atlas */
8196 
8197                aa = ix + wamiclust_CA_EZ->i[ii] ;
8198                   if( aa < 0 || aa >= nx ) continue ;
8199                bb = jy + wamiclust_CA_EZ->j[ii] ;
8200                   if( bb < 0 || bb >= ny ) continue ;
8201                cc = kz + wamiclust_CA_EZ->k[ii] ;
8202                   if( cc < 0 || cc >= nz ) continue ;
8203 
8204                kk  = aa + bb*nx + cc*nxy ;   /* index into bricks */
8205 
8206                /* Atlas structure marker there - value at coordinate in atlas */
8207                if(dset_kind == MRI_short)
8208                  baf = ba[kk];
8209                else
8210                  baf = bba[kk];
8211 
8212 
8213                if( baf == 0 )                            continue ;
8214 
8215                for( ff=0 ; ff < nfind ; ff++ ){       /* cast out         */
8216                   if( baf == b_find[ff] ) baf = 0 ;  /* duplicate labels  */
8217                }
8218 
8219                if( baf == 0 )                            continue ;
8220 
8221                b_find[nfind] = baf ;  /* save what we found */
8222                rr_find[nfind] = (int) wamiclust_CA_EZ->mag[ii] ;
8223                if (LocalHead)
8224                   fprintf(stderr,"Adding b_find[%d]=%d rr_find[%d]=%d\n",
8225                               nfind, b_find[nfind], nfind, rr_find[nfind]);
8226                nfind++ ;
8227 
8228                if( nfind == MAX_FIND ) {
8229                  if (wami_verb() || !getenv("AFNI_WHEREAMI_NO_WARN")) {
8230                   INFO_message(
8231             "Potentially more regions could be found than the %d reported.\n"
8232             "Set the environment variable AFNI_WHEREAMI_MAX_FIND to higher\n"
8233             "than %d if you desire a larger report.\n"
8234             "It behooves you to also checkout AFNI_WHEREAMI_MAX_SEARCH_RAD\n"
8235             "and AFNI_WHEREAMI_NO_WARN. See whereami -help for detail.\n",
8236                                     MAX_FIND, MAX_FIND);
8237                  }
8238                  break ;  /* don't find TOO much */
8239                }
8240             }
8241 
8242             /*-- bubble-sort what we found, by radius --*/
8243 
8244             if( nfind > 1 ){  /* don't have to sort only 1 result */
8245               int swap, tmp ;
8246               do{
8247                  swap=0 ;
8248                  for( ii=1 ; ii < nfind ; ii++ ){
8249                     if( rr_find[ii-1] > rr_find[ii] ){
8250                       tmp = rr_find[ii-1];
8251                         rr_find[ii-1] = rr_find[ii];
8252                            rr_find[ii] = tmp;
8253                       tmp = b_find[ii-1];
8254                         b_find[ii-1] = b_find[ii];
8255                            b_find[ii] = tmp;
8256                       swap++ ;
8257                     }
8258                  }
8259               } while(swap) ;
8260             }
8261 
8262             /* build query results */
8263             rff = -1 ;  /* rff = radius of last found label */
8264 
8265             if (LocalHead)
8266                INFO_message("   %d findings on atlas named %s ...\n",
8267                             nfind, Atlas_Name(atlas) );
8268 
8269             for( ff=0 ; ff < nfind ; ff++ ){
8270                baf = b_find[ff] ; blab = NULL ;
8271                blab = atlas_key_label(atlas, baf, &ac);
8272 
8273                if( blab == NULL &&
8274                    is_atlas_key_labeled(atlas,baf) ) {
8275                   if (LocalHead)
8276                      WARNING_message(
8277                        "No label found for code %d in atlas %s\n"
8278                        "Continuing...",
8279                        baf, atlas->dset_name);
8280                   continue ;  /* no labels? */
8281                }
8282                /* zone levels are based on search radius */
8283                if(LocalHead)
8284                    INFO_message("Getting atlas %s zone %d for finds",
8285                                 Atlas_Name(atlas), (int)rr_find[ff]);
8286                zn = Get_Atlas_Zone (wami, (int)rr_find[ff] );
8287                if(LocalHead)
8288                    INFO_message("Adding zone to query results (%d, %s, %d)",
8289                                  baf, STR_PRINT(blab),
8290                                  is_atlas_key_labeled(atlas,baf));
8291                webpage = atlas_suppinfo_webpage(atlas,blab);
8292                connpage = atlas_suppinfo_connpage(atlas,blab);
8293 
8294                zn = Atlas_Zone(  zn, zn->level,
8295                      blab, baf, (float) atlas->adh->probkey,
8296                      rr_find[ff], Atlas_Name(atlas), webpage, connpage);
8297                if(webpage) free(webpage);
8298                if(connpage) free(connpage);
8299                wami = Add_To_Atlas_Query(wami, zn);
8300                rff = rr_find[ff] ;  /* save for next time around */
8301             }
8302          } /* for each sub-brick */
8303       } else { /* the PMAPS */
8304          if (LocalHead)  fprintf(stderr,
8305             "Processing with %s for probability maps\n",
8306             atlas->dset_name);
8307 
8308          /*-- find locations near the given one that are in the Atlas --*/
8309          mmxyz = THD_dicomm_to_3dmm( ATL_DSET(atlas) ,
8310                          TEMP_FVEC3(ac.x,ac.y,ac.z));
8311          ijk = THD_3dmm_to_3dind( ATL_DSET(atlas) ,
8312                                   mmxyz ) ;
8313          UNLOAD_IVEC3(ijk,ix,jy,kz) ;
8314 
8315          nx = DSET_NX(ATL_DSET(atlas)) ;   /* size of atlas dataset axes */
8316          ny = DSET_NY(ATL_DSET(atlas)) ;
8317          nz = DSET_NZ(ATL_DSET(atlas)) ; nxy = nx*ny ;
8318          kk = ix + jy*nx + kz*nxy ;        /* index into brick arrays */
8319 
8320          zn = Get_Atlas_Zone(wami, 0);    /* get the zero level zone */
8321          for (ii=0; ii<DSET_NVALS(ATL_DSET(atlas)); ++ii) {
8322             fbaf = Atlas_Voxel_fValue(atlas, ii, kk);
8323             if (LocalHead)  fprintf(stderr,
8324                               "  ++ Sub-brick %d in %s ba[kk]=%d\n",
8325                               ii, atlas->dset_name,
8326                               (int)fbaf);
8327             if( fbaf != 0 ){
8328                if( atlas->adh->adset->dblk->brick_lab == NULL ||
8329                    atlas->adh->adset->dblk->brick_lab[ii] == NULL) {
8330                   if (LocalHead)  fprintf(stderr,"  ++ No Label!\n");
8331                   zn = Atlas_Zone(zn, 0, "No Label", -1,
8332                         fbaf, 0, Atlas_Name(atlas), NULL, NULL);
8333                } else {
8334                   if( atlas->adh->adset->dblk->brick_lab[ii] &&
8335                       atlas->adh->adset->dblk->brick_lab[ii][0] != '\0' ){
8336                      if (LocalHead)
8337                         fprintf(stderr,
8338                               "  ++ Checking area label against sub-brick.\n");
8339                      blab = prob_atlas_sb_to_label(atlas, ii, &baf);
8340                      if (blab) {
8341                         if (LocalHead) fprintf(stderr," blabing: %s\n", blab);
8342                         webpage = atlas_suppinfo_webpage(atlas,blab);
8343                         connpage = atlas_suppinfo_connpage(atlas,blab);
8344 
8345                         zn = Atlas_Zone(  zn, 0, blab, baf ,
8346                                           fbaf, 0,
8347                                           Atlas_Name(atlas), webpage, connpage);
8348                         if(webpage) free(webpage);
8349                         if(connpage) free(connpage);
8350                      } else {
8351                         if (LocalHead) fprintf(stderr," no blabing:\n");
8352                         zn = Atlas_Zone(zn, 0, "Unexpected trouble.",
8353                               -1, -1.0, 0, Atlas_Name(atlas), NULL, NULL);
8354                      }
8355                   } else {
8356                      zn = Atlas_Zone(zn, 0, "Empty Label", -1,
8357                              fbaf, 0, Atlas_Name(atlas), NULL, NULL);
8358                   }
8359                }
8360                wami = Add_To_Atlas_Query(wami, zn);
8361             }
8362          }
8363 
8364       }
8365       /* Show_Atlas_Query(wami); */
8366    } /* iatlas loop */
8367 
8368 
8369    /* sort the query by zone levels, be nice */
8370    if( wami && wami->N_zone > 1 ){  /* don't have to sort only 1 result */
8371      int swap;
8372      ATLAS_ZONE *tmp ;
8373      do{
8374         swap=0 ;
8375         for( ii=1 ; ii < wami->N_zone ; ii++ ){
8376            if( wami->zone[ii-1]->level > wami->zone[ii]->level ){
8377              tmp = wami->zone[ii-1];
8378              wami->zone[ii-1] = wami->zone[ii];
8379              wami->zone[ii] = tmp;
8380              swap++ ;
8381            }
8382         }
8383      } while(swap) ;
8384    }
8385 
8386 
8387    if (LocalHead) {
8388       Show_Atlas_Query(wami, atlas_alist);
8389    }
8390 
8391    *wamip = wami;
8392 
8393    free(b_find); b_find = NULL; free(rr_find); rr_find = NULL;
8394    RETURN(1);
8395 }
8396 
THD_3dim_G_from_ROIstring(char * shar)8397 THD_3dim_dataset *THD_3dim_G_from_ROIstring(char *shar) {
8398    return(THD_3dim_from_ROIstring(shar, get_G_atlas_list()));
8399 }
8400 
THD_3dim_from_ROIstring(char * shar,ATLAS_LIST * atlas_list)8401 THD_3dim_dataset *THD_3dim_from_ROIstring(char *shar, ATLAS_LIST *atlas_list)
8402 {
8403    THD_3dim_dataset *maskset = NULL;
8404    AFNI_ATLAS_REGION *aar= NULL;
8405    AFNI_ATLAS *aa = NULL;
8406    ATLAS_SEARCH *as=NULL;
8407    char *string=NULL;
8408    int nbest = 0, codes[3], n_codes;
8409    int LocalHead = wami_lh();
8410 
8411    ENTRY("THD_3dim_from_ROIstring");
8412 
8413    if (!shar) RETURN(maskset);
8414    if (strlen(shar) < 3) RETURN(maskset);
8415    Set_ROI_String_Decode_Verbosity(0); /* must be discreet here */
8416 
8417    if (!(aar = ROI_String_Decode(shar, atlas_list))) {
8418       if (LocalHead) ERROR_message("ROI string decoding failed.");
8419       RETURN(maskset);
8420    }
8421 
8422    if (LocalHead) {
8423       fprintf( stderr,
8424                "User seeks the following region in atlas %s:\n",
8425                aar->atlas_name);
8426       Show_Atlas_Region(aar);
8427    }
8428 
8429    /* is this an OK atlas */
8430    if (!get_Atlas_Named(aar->atlas_name, atlas_list)) {
8431       if (LocalHead) ERROR_message("Atlas not found");
8432       RETURN(maskset);
8433    }
8434    if (aar->N_chnks < 1 && aar->id <= 0) {
8435       if (LocalHead) ERROR_message("bad or empty label");
8436       RETURN(maskset);
8437    }
8438    if (!(aa = Build_Atlas(aar->atlas_name, atlas_list))) {
8439       if (LocalHead) ERROR_message("Failed to build atlas");
8440       RETURN(maskset);
8441    }
8442    if (wami_verb() > 1) Show_Atlas(aa);
8443    as = Find_Atlas_Regions(aa,aar, NULL);
8444 
8445    /* analyze the matches,*/
8446    string = Report_Found_Regions(aa, aar, as, &nbest);
8447    if (string) {
8448       if (LocalHead) fprintf(stderr,"%s\n", string);
8449       free(string); string = NULL;
8450    } else {
8451       if (LocalHead) ERROR_message("NULL string returned");
8452             /* something went wrong, although I care not for string ... */
8453       RETURN(maskset);
8454    }
8455    /* Now we know what matches, give me a mask */
8456    if (nbest) {
8457       if (nbest > 2) {
8458          ERROR_message( "More than 2 choices available. I am not used to this.\n"
8459                         "Please post a message explaining how you generated \n"
8460                         "this on the AFNI message board");
8461          RETURN(maskset);
8462       }
8463       n_codes = 1;
8464       codes[0] = aa->reg[as->iloc[0]]->id;
8465       if (nbest == 2) {
8466          if (aa->reg[as->iloc[0]]->id != aa->reg[as->iloc[1]]->id) {
8467             n_codes = 2;
8468             codes[1] = aa->reg[as->iloc[1]]->id;
8469          }
8470       }
8471       if (!(maskset = Atlas_Region_Mask(aar, codes,
8472                                         n_codes, atlas_list))) {
8473          ERROR_message("Failed to create mask");
8474          RETURN(maskset);
8475       }
8476    }
8477 
8478    if (aar) aar = Free_Atlas_Region(aar);
8479    if (as) as = Free_Atlas_Search(as);
8480    if (string) free(string); string = NULL;
8481    if (aa) aa = Free_Atlas(aa);
8482 
8483    RETURN(maskset);
8484 }
8485 
8486 static char *outspace_str = NULL; /* default templace space not set */
8487 
8488 /* set up a few accessor functions for default template space manipulation*/
8489 /* set default template space of output */
set_out_space(char * space_str)8490 void set_out_space(char *space_str)
8491 {
8492    if(!outspace_str) {
8493       free(outspace_str);
8494       outspace_str = NULL;
8495    }
8496 
8497    outspace_str = nifti_strdup(space_str);
8498 }
8499 
8500 /* get default template space of output */
get_out_space()8501 char *get_out_space()
8502 {
8503    return(outspace_str);
8504 }
8505 
8506 /* compare space with default template space of output */
equivalent_space(char * inspace_str)8507 int equivalent_space(char *inspace_str)
8508 {
8509    char *gen_inspace_str, *gen_outspace_str;
8510 
8511    if(!outspace_str)   /* check if the output space has not been set yet */
8512       return(1);
8513    if(strcmp(inspace_str, outspace_str)==0) /* space matches default - good */
8514       return(1);
8515    /* now check if the inspace_str or the generic version of the inspace_str
8516       matches the generic version of the outspace_str */
8517    gen_inspace_str = gen_space_str(inspace_str);
8518    if(!gen_inspace_str)
8519       return(0);   /* no generic space for input string */
8520 
8521    gen_outspace_str = gen_space_str(outspace_str);
8522    if(!gen_outspace_str)
8523       return(0);   /* no generic space for output string */
8524 
8525    if(strcmp(gen_inspace_str, gen_outspace_str)==0)
8526       return(1);   /* generic space strings match */
8527 
8528    return(0);
8529 }
8530 
gen_space_str(char * space_str)8531 char *gen_space_str(char *space_str)
8532 {
8533    int i;
8534    ATLAS_SPACE_LIST *asl=get_G_space_list();
8535    ATLAS_SPACE *at_space;
8536 
8537    ENTRY("gen_space_str");
8538 
8539    if( space_str == NULL || *space_str == '\0' ) RETURN(NULL) ;
8540 
8541    if(asl==NULL){
8542       ERROR_message("can not load spaces\n");
8543       RETURN(NULL);
8544    }
8545 
8546    for(i=0;i<asl->nspaces;i++){
8547       at_space = asl->space+i;
8548       if(strcmp(at_space->atlas_space, space_str)==0)
8549          RETURN(at_space->generic_space);
8550    }
8551 
8552    if(strcmp(space_str, "ORIG")==0)
8553       RETURN("ORIG");
8554 
8555    if(strcmp(space_str, "ACPC")==0)
8556       RETURN("ACPC");
8557 
8558    RETURN(NULL);
8559 }
8560 
find_in_names_list(char ** nl,int N_nl,char * name)8561 int find_in_names_list(char **nl, int N_nl, char *name) {
8562    int i = -1;
8563 
8564    if (!name || !nl || N_nl < 1) return(i);
8565    for (i=0; i<N_nl; ++i) {
8566       if (nl[i] && !strcmp(nl[i],name)) return(i);
8567    }
8568    return(-1);
8569 }
8570 
add_to_names_list(char ** nl,int * N_nl,char * name)8571 char **add_to_names_list(char **nl, int *N_nl, char *name) {
8572 
8573    if (!name) return(nl);
8574 
8575    if (!nl) *N_nl = 0;
8576    if (find_in_names_list(nl, *N_nl, name) >= 0) return(nl); /* got it already */
8577 
8578    /* new one */
8579    nl = (char **)realloc(nl, (*N_nl+1)*sizeof(char *));
8580    nl[*N_nl] = nifti_strdup(name);
8581    *N_nl = *N_nl+1;
8582 
8583    return(nl);
8584 }
8585 
free_names_list(char ** nl,int N_nl)8586 char **free_names_list(char **nl, int N_nl) {
8587    int i;
8588    if (!nl) return(NULL);
8589    for (i=0; i<N_nl; ++i) {
8590       if (nl[i]) free(nl[i]);
8591    }
8592 /*   free(nl[i]); */
8593    return(NULL);
8594 }
8595 
atlas_n_points(char * atname)8596 int atlas_n_points(char *atname) {
8597    ATLAS *atlas;
8598    if (!(atlas = Atlas_With_Trimming (atname, 1, NULL)) || !ATL_ADH_SET(atlas)) {
8599       if (wami_verb())
8600          ERROR_message("Failed getting atlas for n_points");
8601       if (wami_verb())
8602          WARNING_message("Old style n_points retrieval for %s", atname);
8603       if (!strcmp(atname,"TT_Daemon")) {
8604          return(TTO_COUNT_HARD);
8605       } if (!strcmp(atname,"CA_N27_MPM") ||
8606             !strcmp(atname,"CA_N27_PM") ) {
8607          return(CA_EZ_COUNT_HARD);
8608       } if (!strcmp(atname,"CA_N27_LR")) {
8609          return(LR_EZ_COUNT_HARD);
8610       } if (!strcmp(atname,"CA_N27_ML")) {
8611          return(ML_EZ_COUNT_HARD);
8612       }
8613       return(0);
8614    }
8615    return(atlas->adh->apl2->n_points);
8616 }
8617 
atlas_points(char * atname)8618 ATLAS_POINT *atlas_points(char *atname) {
8619    ATLAS *atlas;
8620    if (!(atlas = Atlas_With_Trimming (atname, 1, NULL)) || !ATL_ADH_SET(atlas)) {
8621       if (wami_verb())
8622          ERROR_message("Failed getting atlas for atlas_points");
8623       if (wami_verb())
8624          WARNING_message("Old style atlas_points retrieval for %s", atname);
8625       if (!strcmp(atname,"TT_Daemon")) {
8626          return(TTO_list_HARD);
8627       } else if ( !strcmp(atname,"CA_N27_MPM") ||
8628                   !strcmp(atname,"CA_N27_PM") ) {
8629          return(CA_EZ_list_HARD);
8630       } else if (!strcmp(atname,"CA_N27_LR")) {
8631          return(LR_EZ_list_HARD);
8632       } else if (!strcmp(atname,"CA_N27_ML")) {
8633          return(ML_EZ_list_HARD);
8634       }
8635       return(NULL);
8636    }
8637    return(atlas->adh->apl2->at_point);
8638 }
8639 
atlas_point_list_old_way(char * atname)8640 ATLAS_POINT_LIST *atlas_point_list_old_way(char *atname)
8641 {
8642    static ATLAS_POINT_LIST apl[1];
8643 
8644    if (wami_verb())
8645          WARNING_message("Old style atlas_point_list_old_way for %s", atname);
8646 
8647    if (!strcmp(atname,"TT_Daemon")) {
8648       apl->at_point = TTO_list_HARD;
8649       apl->n_points = TTO_COUNT_HARD;
8650       return(apl);
8651    } else if ( !strcmp(atname,"CA_N27_MPM")||
8652                !strcmp(atname,"CA_N27_PM") ) {
8653       apl->at_point = CA_EZ_list_HARD;
8654       apl->n_points = CA_EZ_COUNT_HARD;
8655       return(apl);
8656    }  else if (!strcmp(atname,"CA_N27_LR")) {
8657       apl->at_point = LR_EZ_list_HARD;
8658       apl->n_points = LR_EZ_COUNT_HARD;
8659       return(apl);
8660    }  else if (!strcmp(atname,"CA_N27_ML")) {
8661       apl->at_point = ML_EZ_list_HARD;
8662       apl->n_points = ML_EZ_COUNT_HARD;
8663       return(apl);
8664    }
8665    return(NULL);
8666 }
8667 
atlas_point_list(char * atname)8668 ATLAS_POINT_LIST *atlas_point_list(char *atname)
8669 {
8670    ATLAS *atlas;
8671 
8672    if (!(atlas = Atlas_With_Trimming (atname, 1, NULL)) || !ATL_ADH_SET(atlas)) {
8673       if (wami_verb())
8674          ERROR_message("Failed getting atlas for atlas_point_list\n");
8675       return(atlas_point_list_old_way(atname));
8676    }
8677    return(atlas->adh->apl2);
8678 }
8679 
atlas_version_string(char * atname)8680 char *atlas_version_string(char *atname) {
8681    ATLAS *atlas;
8682 
8683    if (1 || !(atlas = Atlas_With_Trimming(atname, 1, NULL))) {
8684       if (wami_verb())
8685          ERROR_message("Failed getting atlas for atlas_version_string");
8686       if (!strcmp(atname,"CA_N27_MPM") ||
8687           !strcmp(atname,"CA_N27_PM")  ||
8688           !strcmp(atname,"CA_N27_LR") ||
8689           !strcmp(atname,"CA_N27_ML")) {
8690          if (wami_verb())
8691             WARNING_message("Old style retrieval of version string for %s",
8692                            atname);
8693          return(CA_EZ_VERSION_STR_HARD);
8694       }
8695    }
8696 
8697    return(NULL);
8698 }
8699 
8700 /* only used for no NIML comment */
atlas_reference_string_list(char * atname,int * N_refs)8701 char **atlas_reference_string_list(char *atname, int *N_refs) {
8702    ATLAS *atlas;
8703    char **slist=NULL;
8704    int i = 0;
8705 
8706    *N_refs = 0;
8707 
8708    if (1 || !(atlas = Atlas_With_Trimming(atname, 1, NULL))) {
8709       if (wami_verb())
8710          ERROR_message("Failed getting atlas for atlas_reference_string_list");
8711       if (!strcmp(atname,"CA_N27_MPM") ||
8712           !strcmp(atname,"CA_N27_PM")  ||
8713           !strcmp(atname,"CA_N27_LR") ||
8714           !strcmp(atname,"CA_N27_ML")) {
8715          if (wami_verb())
8716             WARNING_message("Old style retrieval of reference string for %s",
8717                               atname);
8718          i = 0;
8719          while (CA_EZ_REF_STR_HARD[i][0]!='\0') {
8720             slist = add_to_names_list(slist,
8721                               N_refs, CA_EZ_REF_STR_HARD[i]);
8722             ++i;
8723          }
8724          return(slist);
8725       }
8726    }
8727 
8728    return(NULL);
8729 }
8730 
atlas_chooser_formatted_labels(char * atname,int flipxy)8731 char **atlas_chooser_formatted_labels(char *atname, int flipxy ) {
8732    char **at_labels=NULL;
8733    ATLAS_POINT_LIST *apl=NULL;
8734    int ii;
8735    int sgnxy = (flipxy) ? -1 : 1 ;  /* 10 Jan 2017 */
8736 
8737    if (!(apl = atlas_point_list(atname))) {
8738       if (wami_verb()) {
8739          ERROR_message("Failed getting atlas point list for %s", atname);
8740       }
8741       return(NULL);
8742    }
8743    at_labels = (char **) calloc(apl->n_points, sizeof(char*));
8744    for( ii=0 ; ii < apl->n_points ; ii++ ){
8745       at_labels[ii] = (char *) malloc( sizeof(char) * TTO_LMAX ) ;
8746       sprintf( at_labels[ii] , TTO_FORMAT , Atlas_name_choice(&apl->at_point[ii]),
8747          sgnxy*(apl->at_point[ii].xx) , sgnxy*(apl->at_point[ii].yy) , apl->at_point[ii].zz ) ;
8748    }
8749 
8750    return(at_labels);
8751 }
8752 
deblank_name(char * name)8753 char * deblank_name (char *name) {
8754    int nch = 0, bb=0, ibb=0, BB=0;
8755 
8756    if (!name) return(name);
8757 
8758    nch = strlen(name);
8759    /* deblank it, leave spaces in middle */
8760    bb=0;
8761    while (name[bb] != '\0' && isspace(name[bb])) {
8762       ++bb;
8763    }
8764    BB = nch-1;
8765    while (BB > 0 && name[BB] != '\0' && isspace(name[BB])) {
8766       --BB;
8767    }
8768    for (ibb=bb; ibb<=BB; ++ibb) {
8769       name[ibb-bb] = name[ibb];
8770    }
8771    name[ibb-bb] = '\0';
8772 
8773    return(name);
8774 }
8775 
deblank_allname(char * name,char fill)8776 char *deblank_allname(char *name, char fill)
8777 {
8778    int bb=0;
8779 
8780    if (!name) return(name);
8781 
8782    name = deblank_name(name);
8783 
8784 /*   nch = strlen(name);*/
8785    bb=0;
8786    while (name[bb] != '\0') {
8787       if (isspace(name[bb])) name[bb]=fill;
8788       ++bb;
8789    }
8790 
8791    return(name);
8792 }
8793 
deslash_allname(char * name,char fill)8794 char *deslash_allname(char *name, char fill)
8795 {
8796    int bb=0;
8797 
8798    if (!name) return(name);
8799 
8800       bb=0;
8801    while (name[bb] != '\0') {
8802       if (name[bb] == '\\' || name[bb] == '/') name[bb]=fill;
8803       ++bb;
8804    }
8805 
8806    return(name);
8807 }
8808 
8809 
8810 /* deblank and compress (reduce successive blanks to
8811    just one blank */
cdeblank_allname(char * name,char fill)8812 char *cdeblank_allname(char *name, char fill)
8813 {
8814    int bb=0, block=0, bbo=0;
8815 
8816    if (!name) return(name);
8817 
8818    name = deblank_name(name);
8819 
8820 /*   nch = strlen(name);*/
8821    bb=0; bbo=0;
8822    while (name[bb] != '\0') {
8823       if (isspace(name[bb])) {
8824          if (!block) name[bbo++]=fill;
8825          block=1;
8826       } else {
8827          name[bbo++]=name[bb];
8828          block=0;
8829       }
8830       ++bb;
8831    }
8832    name[bbo]='\0';
8833    return(name);
8834 }
8835 
depunct_name(char * name)8836 char *depunct_name (char *name) {
8837    int nch = 0, bb=0, ibb=0, BB=0;
8838 
8839    if (!name) return(name);
8840 
8841    nch = strlen(name);
8842    /* depunct it, leave spaces in middle */
8843    bb=0;
8844    while (name[bb] != '\0' && IS_PUNCT(name[bb])) {
8845       ++bb;
8846    }
8847    BB = nch-1;
8848    while (BB > 0 && name[BB] != '\0' && IS_PUNCT(name[BB])) {
8849       --BB;
8850    }
8851    for (ibb=bb; ibb<=BB; ++ibb) {
8852       name[ibb-bb] = name[ibb];
8853    }
8854    name[ibb-bb] = '\0';
8855 
8856    return(name);
8857 }
8858 
dequote_name(char * name,char qo)8859 char * dequote_name (char *name, char qo) {
8860    int nch = 0, bb=0;
8861 
8862    if (!name) return(name);
8863 
8864    nch = strlen(name);
8865 
8866    if (nch < 2) return(name);
8867    if (qo == '\0') {
8868       qo = name[0]; if (qo != '\'' && qo != '"') return(name);
8869    }
8870 
8871    /* dequote */
8872    if (name[nch-1] == qo) {
8873       for(bb=0; bb<nch-2; ++bb) name[bb]=name[bb+1];
8874       name[bb] = '\0';
8875    }
8876 
8877    return(name);
8878 }
8879 
8880 /* search arguments array for arguments starting with the opening
8881 quote and ending in the closing quote */
begins_with(char * name,char * quote,int debl)8882 int begins_with(char *name, char *quote, int debl)
8883 {
8884    if (!name || !quote) return(0);
8885    if (debl) deblank_name(name);
8886    if (af_strnstr(name,quote,strlen(quote))) return(1);
8887    return(0);
8888 }
8889 
ends_with(char * name,char * quote,int debl)8890 int ends_with(char *name, char *quote, int debl)
8891 {
8892    int nch=0, nqo=0;
8893    if (!name || !quote) return(0);
8894    if (debl) deblank_name(name);
8895    nch = strlen(name);
8896    nqo = strlen(quote);
8897    if (nch < nqo) return(0);
8898    if (af_strnstr(name+nch-nqo,quote,nqo)) return(1);
8899    return(0);
8900 }
8901 
8902 /* return the list of atlases set by the environment variable,
8903    AFNI_ATLAS_LIST */
env_atlas_list()8904 ATLAS_LIST * env_atlas_list()
8905 {
8906    char *envlist = NULL;
8907    char *atlas_str_ptr;
8908    char **atlas_names=NULL;
8909    int N_atlas_names = 0;
8910    ATLAS_LIST *atlas_rlist = NULL;
8911    char atlas_name_str[256], ch;
8912    int ai, strind, nch;
8913    THD_string_array *sar=NULL;
8914 
8915    envlist= my_getenv("AFNI_ATLAS_LIST");
8916    if(envlist==NULL) {
8917       sar = get_working_atlas_name_list();
8918       atlas_rlist = Atlas_Names_to_List(sar->ar, sar->num);
8919       return(atlas_rlist);
8920    }
8921    nch = strlen(envlist);
8922    strind = 0; ai =0;
8923    atlas_str_ptr = envlist;
8924 
8925    if(wami_verb()){
8926       INFO_message("AFNI_ATLAS_LIST set to %s with %d chars", envlist, nch);
8927    }
8928 
8929    if(!strcmp(envlist, "ALL")) {
8930       if(wami_verb()){
8931          INFO_message("AFNI_ATLAS_LIST is ALL atlases");
8932       }
8933       atlas_rlist = get_G_atlas_list();
8934       return(atlas_rlist);
8935    }
8936 
8937 
8938    while(strind<=nch) {
8939       ch = *(atlas_str_ptr+strind);
8940       /* reached the end of a string with end of string, comma or semicolon */
8941       if((ch=='\0')||(ch==',')||(ch==';')||(strind==nch)) {
8942          if(ai>0){
8943             *(atlas_name_str+ai) = '\0'; /* null terminate the name */
8944             deblank_name(atlas_name_str);
8945             /* add the name to the list of atlas names (an array of strings) */
8946             /* the name is duplicated into the new list */
8947             atlas_names =
8948               add_to_names_list (atlas_names, &N_atlas_names, atlas_name_str);
8949             ai = 0; /* reset the offset index for each atlas name */
8950             if(wami_verb()){
8951                INFO_message("AFNI_ATLAS_LIST name: %s", atlas_name_str);
8952             }
8953          }
8954       }
8955       else {
8956          *(atlas_name_str+ai) = ch;
8957          ai++;
8958       }
8959       strind++;
8960    }
8961 
8962    if (N_atlas_names == 0) {
8963       return(NULL);
8964    }
8965 
8966    atlas_rlist = Atlas_Names_to_List(atlas_names, N_atlas_names);
8967    if(wami_verb()){
8968       INFO_message("reduced list of atlases");
8969       print_atlas_list(atlas_rlist);
8970    }
8971 
8972    atlas_names = free_names_list(atlas_names, N_atlas_names);
8973 
8974    return(atlas_rlist);
8975 
8976 }
8977 
8978 /* return the list of spaces (as a array of strings) set by the
8979    environment variable, AFNI_TEMPLATE_SPACE_LIST */
env_space_list(int * nspaces)8980 char ** env_space_list(int *nspaces)
8981 {
8982    char *envlist = NULL;
8983    char *atlas_str_ptr;
8984    char **atlas_space_list=NULL;
8985    int N_atlas_spaces = 0;
8986    char atlas_name_str[256], ch;
8987    int ai, strind, nch, i ;
8988    ATLAS_SPACE_LIST *asl;
8989 
8990    *nspaces = 0;
8991    envlist= my_getenv("AFNI_TEMPLATE_SPACE_LIST");
8992    if(envlist==NULL) return(NULL);
8993 
8994    nch = strlen(envlist);
8995    strind = 0; ai =0;
8996    atlas_str_ptr = envlist;
8997 
8998    if(wami_verb()){
8999       INFO_message("AFNI_TEMPLATE_SPACE_LIST set to %s with %d chars",
9000                    envlist, nch);
9001    }
9002 
9003    /* if environment variable is set to "ALL", display in all output spaces */
9004    if(!strcmp(envlist, "ALL")) {
9005       if(wami_verb()){
9006          INFO_message("AFNI_TEMPLATE_SPACE_LIST is ALL template spaces");
9007       }
9008       asl = get_G_space_list();
9009       for(i=0;i<asl->nspaces;i++){
9010          atlas_space_list = add_to_names_list( atlas_space_list,
9011             &N_atlas_spaces, asl->space[i].atlas_space);
9012       }
9013       *nspaces = N_atlas_spaces;
9014 
9015       return(atlas_space_list);
9016    }
9017 
9018    while(strind<=nch) {
9019       ch = *(atlas_str_ptr+strind);
9020       /* reached the end of a string with end of string, comma or semicolon */
9021       if((ch=='\0')||(ch==',')||(ch==';')||(strind==nch)) {
9022          if(ai>0){
9023             *(atlas_name_str+ai) = '\0'; /* null terminate the name */
9024             /* add the name to the list of atlas names (an array of strings) */
9025             /* the name is duplicated into the new list */
9026             atlas_space_list =
9027               add_to_names_list (atlas_space_list, &N_atlas_spaces,
9028                                 atlas_name_str);
9029             ai = 0; /* reset the offset index for each atlas name */
9030             if(wami_verb()){
9031                INFO_message("AFNI_TEMPLATE_SPACE_LIST name: %s", atlas_name_str);
9032             }
9033          }
9034       }
9035       else {
9036          *(atlas_name_str+ai) = ch;
9037          ai++;
9038       }
9039       strind++;
9040    }
9041 
9042    if (N_atlas_spaces == 0) {
9043       return(NULL);
9044    }
9045 
9046    *nspaces = N_atlas_spaces;
9047 
9048    return(atlas_space_list);
9049 }
9050 
9051 
9052 /* return the number of decimal places to use in wami output.
9053    set by the environment variable, AFNI_WHEREAMI_DEC_PLACES */
env_dec_places()9054 int env_dec_places()
9055 {
9056    char *envplaces = NULL;
9057    int decplaces = 0, tp;
9058 
9059    envplaces= my_getenv("AFNI_WHEREAMI_DEC_PLACES");
9060    if(!envplaces) return(decplaces);
9061    tp = atoi(envplaces);
9062    if((tp<0)||(tp>10))
9063       return(decplaces);
9064    decplaces = tp;
9065    return(decplaces);
9066 }
9067 
9068 
9069 /* uses string from environment copy, or default - don't free */
Current_Atlas_Default_Name()9070 char *Current_Atlas_Default_Name()
9071 {
9072    char *ept;
9073 
9074    ept = getenv( "AFNI_ATLAS_COLORS" ) ;
9075    if(ept != NULL) return(search_quotes(ept)); /* remove any extra quotes*/
9076    if( ept != NULL ) return( ept ) ;
9077 
9078    return("TT_Daemon");
9079 }
9080 
9081 
9082 /* return list of atlas names */
Atlas_Names_List(ATLAS_LIST * atl)9083 char **Atlas_Names_List(ATLAS_LIST *atl)
9084 {
9085    char **atlas_names = NULL;
9086    int k, natl=0;
9087 
9088    if (atl->natlases == 0)
9089       return(NULL);
9090 
9091    /* use all atlases */
9092    for (k=0; k<atl->natlases; ++k) {
9093       atlas_names = add_to_names_list(atlas_names, &natl,
9094           Atlas_Name(&(atl->atlas[k])));
9095    }
9096    return(atlas_names);
9097 }
9098 
9099 /*
9100    Put the label associated with value val in string str
9101       (64 chars are copied into str)
9102 */
AFNI_get_dset_val_label_maybeCR(THD_3dim_dataset * dset,double val,char * str)9103 int AFNI_get_dset_val_label_maybeCR(THD_3dim_dataset *dset, double val, char *str)
9104 {
9105    char *str_lab1=NULL, *str_lab2=NULL, sval[128]={""};
9106    ATLAS_LIST *atlas_alist=NULL;
9107    ATLAS *atlas=NULL;
9108 
9109    ENTRY("AFNI_get_dset_val_label") ;
9110 
9111    if (!str) RETURN(1);
9112 
9113    str[0]='\0';
9114 
9115    if (!dset) RETURN(1);
9116 
9117 
9118   if ((dset->Label_Dtable = DSET_Label_Dtable(dset))) {
9119       /* Have hash, will travel */
9120       sprintf(sval,"%d", (int)val);
9121       str_lab1 = findin_Dtable_a(sval,
9122                                 dset->Label_Dtable);
9123       /* fprintf(stderr,"ZSS: Have label '%s' for value '%s'\n",
9124                      str_lab1 ? str_lab1:"NULL", sval); */
9125    }
9126 
9127    atlas_alist = get_G_atlas_list();
9128    if (is_Dset_Atlasy(dset, atlas_alist)) {
9129       if ((atlas = get_Atlas_ByDsetID(DSET_IDCODE_STR(dset), atlas_alist))) {
9130          /* Now get the name of the value */
9131          str_lab2 = atlas_key_label(atlas, (int)val,NULL);
9132          /* fprintf(stderr,"ZSS: Have atlas label '%s' for value %d\n",
9133                         str_lab2 ? str_lab2:"NULL", (int)val);  */
9134       }
9135    }
9136 
9137    if (str_lab1 && str_lab2 && strcmp(str_lab1,str_lab2)) {
9138       char *eee = getenv("AFNI_LABEL_PRIORITY");
9139       if(eee){
9140          if(strcasecmp(eee,"BOTH")==0) /* put pipe between labels - old default */
9141             snprintf(str,64, "%s|%s",str_lab1,str_lab2);
9142          else if (strcasecmp(eee,"LABEL")==0) {   /* labeltable label */
9143             snprintf(str,64, "%s",str_lab1);
9144          }
9145          else if (strcasecmp(eee,"ATLAS")==0) {   /* atlas points label */
9146             snprintf(str,64, "%s",str_lab2);
9147          }
9148       }
9149       else snprintf(str,64,"%s",str_lab2);  /* atlas label is the default for now */
9150    } else if (str_lab1) {  /* if only one take that label */
9151       snprintf(str,64, "%s",str_lab1);  /* labeltable */
9152    } else if (str_lab2) {
9153       snprintf(str,64, "%s",str_lab2);  /* atlas points label */
9154    }
9155 
9156    RETURN(0);
9157 }
9158 
9159 /* get the label for index in a dataset but remove newlines */
AFNI_get_dset_val_label(THD_3dim_dataset * dset,double val,char * str)9160 int AFNI_get_dset_val_label(THD_3dim_dataset *dset, double val, char *str)
9161 {
9162    int i;
9163 
9164    ENTRY("AFNI_get_dset_val_label_noCR");
9165    AFNI_get_dset_val_label_maybeCR(dset, val, str);
9166    for (i=0;i<strlen(str);i++) {
9167       // replace newline character with space
9168       if(str[i] == '\n') {
9169         str[i] = ' ';
9170       }
9171    }
9172    RETURN(0);
9173 }
9174 
9175 /*
9176    Put the value associated with label in val
9177    Unlike AFNI_get_dset_val_label,
9178    This function has not been tested.
9179 
9180    NEEDS MODIFICATION to deal with ATLAS datasets.
9181 */
AFNI_get_dset_label_val(THD_3dim_dataset * dset,double * val,char * str)9182 int AFNI_get_dset_label_val(THD_3dim_dataset *dset, double *val, char *str)
9183 {
9184 /*   MCW_pbar *pbar = NULL;*/
9185    ATR_string *atr=NULL;
9186 /*   char *pbar_name=NULL;*/
9187    char *str_lab=NULL;
9188    int ival;
9189 
9190    ENTRY("AFNI_get_dset_label_val") ;
9191 
9192    if (!str) RETURN(1);
9193 
9194    *val = 0;
9195 
9196    if (!dset) RETURN(1);
9197 
9198    if (!dset->Label_Dtable &&
9199        (atr = THD_find_string_atr( dset->dblk ,
9200                               "VALUE_LABEL_DTABLE" ))) {
9201       dset->Label_Dtable = Dtable_from_nimlstring(atr->ch);
9202    }
9203 
9204    if (dset->Label_Dtable) {
9205       /* Have hash, will travel */
9206       str_lab = findin_Dtable_b(str,
9207                                 dset->Label_Dtable);
9208       /* fprintf(stderr,"ZSS: Have value '%s' for label '%s'\n",
9209                      str_lab ? str_lab:"NULL", str); */
9210       if (str_lab) *val = strtol(str_lab,NULL, 10);
9211    }
9212 
9213    /* check for exact match against atlas labels too */
9214    ival = dset_atlas_label_index(dset, str);
9215    if(ival) *val = (double) ival;
9216 
9217    RETURN(0);
9218 }
9219 
9220 
9221 /* An integer version of AFNI_get_dset_label_val(), which assumes ints
9222  * to begin with.                                  30 Nov 2016 [rickr]
9223  *
9224  * NOTE: the return values have been expanded in this version
9225  *
9226  * return  1 if found
9227  *         0 if not
9228  *        -1 on error
9229 */
AFNI_get_dset_label_ival(THD_3dim_dataset * dset,int * val,char * str)9230 int AFNI_get_dset_label_ival(THD_3dim_dataset *dset, int *val, char *str)
9231 {
9232    ATR_string * atr=NULL;
9233    char       * str_lab=NULL;
9234    int          found;
9235 
9236    ENTRY("AFNI_get_dset_label_ival") ;
9237 
9238    if (!dset || !val || !str) {
9239       ERROR_message("AGDLIv: missing params, have %p, %p, %p\n",dset,val,str);
9240       RETURN(-1);
9241    }
9242 
9243    *val = 0;
9244    found = 0;
9245 
9246    /* initialize hash table */
9247    if (!dset->Label_Dtable &&
9248        (atr = THD_find_string_atr( dset->dblk , "VALUE_LABEL_DTABLE" ))) {
9249       dset->Label_Dtable = Dtable_from_nimlstring(atr->ch);
9250    }
9251 
9252    /* try to find label in dataset */
9253    if (dset->Label_Dtable) {
9254       str_lab = findin_Dtable_b(str, dset->Label_Dtable);
9255       /* fprintf(stderr,"ZSS: Have value '%s' for label '%s'\n",
9256                      str_lab ? str_lab:"NULL", str); */
9257       if (str_lab) {
9258          *val = strtol(str_lab, NULL, 10);
9259          RETURN(1);
9260       }
9261    }
9262 
9263    /* check for exact match against atlas labels too */
9264    *val = dset_atlas_label_index(dset, str);
9265    if (val) RETURN(1);
9266 
9267    RETURN(0);
9268 }
9269 
9270 
9271 /* Fill the int_list with a single label value or an expanded list
9272  *
9273  * return: -1 on error, else number of ints found
9274  *
9275  * needs expanding
9276 */
thd_LT_label_to_int_list(THD_3dim_dataset * dset,int_list * ilist,char * str)9277 int thd_LT_label_to_int_list(THD_3dim_dataset *dset, int_list *ilist, char *str)
9278 {
9279    int ival, rv;
9280 
9281    ENTRY("thd_LT_label_to_int_list") ;
9282 
9283    if (!dset || !ilist || !str) {
9284       ERROR_message("TLLTIL: missing params, have %p, %p, %p\n",dset,ilist,str);
9285       RETURN(-1);
9286    }
9287 
9288    /* empty the list, but do not free it */
9289    ilist->num = 0;
9290 
9291    /* see if this is a single label in the dataset label table */
9292    rv = AFNI_get_dset_label_ival(dset, &ival, str);
9293    if( rv < 0 ) RETURN(-1);
9294    if( rv > 0 ) {
9295       /* if there was a match, insert into list and return */
9296       if( add_to_int_list(ilist, ival, 16) < 0 ) {
9297          ERROR_message("TLLTIL: failed to add 1 val to int list, n=%d\n",
9298                        ilist->num);
9299          RETURN(-1);
9300       }
9301       RETURN(1); /* returning 1 value */
9302    }
9303 
9304    /* no match yet, try string as globally known label */
9305 
9306    if( known_atlas_label_to_int_list(ilist, str) < 0 )
9307       RETURN(-1);  /* error */
9308 
9309    /* further ponder ilist->num == 0 ? */
9310 
9311    RETURN(ilist->num);
9312 }
9313 
9314 
9315 /* top-level function for converting globally known labels to a corresponding
9316  * list of ints
9317  *
9318  * e.g. AFNI_GLAB_FS5_WM might expand to a list of FreeSurfer 5 WM values
9319  * e.g. AFNI_GLAB_FS6_WM might be useful if FreeSurfer 6 changes the numbers
9320  *
9321  * This should realy be done using a hash table (or a list of them), akin to
9322  * how findin_Dtable_b() works.
9323  *
9324  * return -1 on error, else num returned values           30 Nov 2016 [rickr]
9325  */
known_atlas_label_to_int_list(int_list * ilist,char * str)9326 int known_atlas_label_to_int_list(int_list * ilist, char * str)
9327 {
9328    ENTRY("known_atlas_label_to_int_list");
9329 
9330    if( !ilist || !str ) {
9331       ERROR_message("KALTIL: missing params, have %p, %p\n", ilist, str);
9332       RETURN(-1);
9333    }
9334 
9335    ilist->num = 0;
9336 
9337 
9338    /* display this list via some verbosity flag (wami_verb()?) */
9339 
9340    RETURN(ilist->num);
9341 }
9342 
9343 
9344 /* open Elsevier's BrainNavigator in webpage */
9345 /* xyz input should be in RAI in the same space as atlas,
9346    but BrainNavigator takes "RSA" as xyz order, so coords need
9347    to be reordered. atlas specification now includes coordinate
9348    order and XML base http page in the dataset name.
9349    Returns XML string
9350 */
9351 char *
elsevier_query(float xx,float yy,float zz,ATLAS * atlas)9352 elsevier_query(float xx, float yy, float zz, ATLAS *atlas)
9353 {
9354     size_t nread;
9355     char wamiqurl[512], *page=NULL;
9356 /*     char upath[]={"http://mrqlan.dyndns.org/bnapi/models/whereami.xml?"};*/
9357     THD_coorder CL_cord ;
9358     if(wami_verb()>2)
9359        fprintf(stdout,"Trying to get to Elsevier for coords %f %f %f\n", xx, yy,zz);
9360 
9361     THD_coorder_fill(atlas->orient , &CL_cord ) ; /* fill structure from atlas string */
9362     THD_dicom_to_coorder(&CL_cord , &xx , &yy , &zz);  /* put the coords in Elseviers order */
9363 
9364     /* Get Elsevier XML whereami short response */
9365     /* Elsevier's short response includes structure information in the following format
9366        that includes a link for the BrainNavigator webpage in the bn_uri field of the XML
9367        code */
9368 /*
9369       <?xml version="1.0" encoding="UTF-8"?>
9370      <structure>
9371          <space_name>paxinos_rat_2007</space_name>
9372          <structure_name>caudomedial entorhinal cortex</structure_name>
9373          <structure_abbr>CEnt</structure_abbr>
9374 
9375          <structure_parent>entorhinal cortex</structure_parent>
9376          <structure_grandparent>medial pallium (the hippocampal formation)</structure_grandparent>
9377          <structure_greatgrandparent>pallium</structure_greatgrandparent>
9378          <structure_greatgreatgrandparent>telencephalon</structure_greatgreatgrandparent>
9379          <bn_uri>http://www.brainnav.com/browse?highlight=9681a3&amp;specId=2</bn_uri>
9380          <x_loc>3.900000</x_loc>
9381          <y_loc>4.500000</y_loc>
9382          <z_loc>-8.500000</z_loc>
9383          <species>rat</species>
9384          <atlas_plates>None found</atlas_plates>
9385 
9386      </structure>
9387 */
9388 
9389      sprintf(wamiqurl,"%sspace=%s&x=%f&y=%f&z=%f&scope=full",
9390            atlas->dset_name,atlas->space, xx, yy, zz);
9391 
9392      if(wami_verb())
9393         fprintf(stdout,"Trying to open:\n%s\n", wamiqurl);
9394 
9395      #ifdef USE_CURL
9396         /* fprintf(stderr,"Using curl to read:\n%s\n", wamiqurl); */
9397         nread = CURL_read_URL_http( wamiqurl , &page );
9398      #else
9399         /* fprintf(stderr,"Using read_URL to read:\n%s\n", wamiqurl); */
9400         set_HTTP_11(1);
9401         nread = read_URL_http( wamiqurl , 15000 , &page );
9402 /*         nread = read_URL_http( wamiqurl , 4448 , &page );*/
9403 
9404      #endif
9405      if(wami_verb() && page==NULL)
9406         fprintf(stdout,"***************No response from Elsevier\n");
9407      return(page);
9408 
9409 }
9410 
9411 /* act on requests to Elsevier - show XML, open browser or just show one structure name */
9412 char *
elsevier_query_request(float xx,float yy,float zz,ATLAS * atlas,int el_req_type)9413 elsevier_query_request(float xx, float yy, float zz, ATLAS *atlas, int el_req_type)
9414 {
9415    char *page = NULL;
9416    char *sss = NULL, *temppage;
9417 
9418    ENTRY("elsevier_query_request");
9419 
9420    if(wami_verb())
9421       fprintf(stdout, "Elsevier request type %d\n", el_req_type);
9422 
9423    /* reset wami webpage */
9424    set_wami_webpage(NULL);
9425 
9426    page = elsevier_query(xx,yy,zz,atlas);
9427    if (!page) {
9428       set_wami_web_found(0);
9429       RETURN(NULL);
9430    }
9431 
9432    set_wami_web_found(1);
9433    switch(el_req_type) {
9434 
9435       /* Show page - just print XML as one string */
9436       case(WAMI_WEB_PRINT_XML):
9437          fprintf(stdout,"Elsevier XML Whereami:\n%s\n\n",
9438                   page);
9439          break;
9440 
9441       /* open browser*/
9442       case(WAMI_WEB_BROWSER):
9443          if ((sss = whereami_XML_get(page, "bn_uri",NULL))) {
9444             if(wami_verb())
9445                fprintf(stdout, "open %s\n", sss);
9446             whereami_browser(sss);
9447             free(sss);
9448          }
9449          break;
9450 
9451       /* print structure only at xyz */
9452       default:
9453       case(WAMI_WEB_STRUCT):
9454          if ((sss = whereami_XML_get(page, "structure_name", NULL))) {
9455             if(wami_verb())
9456                fprintf(stdout, "BrainNavigator Structure: %s\n", sss);
9457             /* flag string for no ROI there */
9458             /* otherwise, don't free string, this is returned */
9459             if((sss == NULL) || (strlen(sss)==0) ||
9460                 strcmp(sss, "b0ffff")==0 ) {
9461                if(wami_verb())
9462                   fprintf(stdout, "No structure at location\n");
9463                set_wami_web_found(0);
9464                free(sss);
9465                sss = NULL;
9466             }
9467 
9468             /* update url with string in XML code - even if bad location */
9469             temppage = whereami_XML_get(page,"bn_uri", NULL);
9470             set_wami_webpage(temppage);
9471             free(temppage);
9472          }
9473     }
9474    free(page); page = NULL;
9475 
9476    RETURN(sss);
9477 }
9478 
9479 
9480 /* query Elsevier for whereami at select locations */
9481 void
wami_query_web(ATLAS * atlas,ATLAS_COORD ac,ATLAS_QUERY * wami)9482 wami_query_web(ATLAS *atlas, ATLAS_COORD ac, ATLAS_QUERY *wami)
9483 {
9484    char *blab = NULL;
9485    ATLAS_ZONE *zn = NULL;
9486    int LocalHead = wami_lh();
9487 
9488    ENTRY("wami_query_web");
9489    if (WAMIRAD < 0.0) {
9490       WAMIRAD = Init_Whereami_Max_Rad();
9491    }
9492 
9493    blab = elsevier_query_request(ac.x, ac.y, ac.z, atlas, WAMI_WEB_STRUCT);
9494    if(blab == NULL)
9495        EXRETURN;
9496 
9497    if(strlen(blab)== 0)
9498        EXRETURN;
9499 
9500    zn = Get_Atlas_Zone (wami, 0 ); /* new 0-level zone */
9501    zn = Atlas_Zone(  zn, zn->level, /* put label in zone finding */
9502                      blab, 1, -1, 0,
9503                      Atlas_Name(atlas), get_wami_webpage(), NULL);
9504    if (LocalHead)
9505       INFO_message("Adding zone on %s to wami\n",
9506                       Atlas_Name(atlas));
9507    wami = Add_To_Atlas_Query(wami, zn); /* add the zone finding to wami query */
9508 
9509 
9510    EXRETURN;
9511 }
9512 
9513 #ifdef USE_CURL
9514    /* Some demo code to show how curl can be used to read a URL
9515       At the moment, we're not using it because we'd become
9516       dependent on libcurl .
9517       To toy with curl, replace the call to read_URL_http with
9518       CURL_read_URL_http and just add -libcurl to whereami's compile
9519       command */
9520    #include <curl/curl.h>
9521 
9522    typedef struct {
9523       char *page;
9524       size_t size; /* page is null terminated, and page[size]='\0'; */
9525    } CURL_BUFFER_DATA;
9526 
CURL_buffer2data(void * buffer,size_t size,size_t nmemb,void * ud)9527    size_t CURL_buffer2data( void *buffer, size_t size, size_t nmemb,
9528                               void *ud)
9529    {
9530       CURL_BUFFER_DATA *cbd=(CURL_BUFFER_DATA *)ud;
9531       fprintf(stderr,"Curling %zu, %zu\n", size*nmemb, cbd->size);
9532       if (!(cbd->page =
9533             (char *)realloc(cbd->page, cbd->size+(size*nmemb)+sizeof(char)))) {
9534          ERROR_message("Failed to realloc for cbd->page (%d)\n",
9535                   cbd->size+(size*nmemb));
9536          return(-1);
9537       }
9538       memcpy(cbd->page+cbd->size, buffer, size*nmemb);
9539       cbd->size = cbd->size+(size*nmemb);
9540       cbd->page[cbd->size] = '\0';
9541       fprintf(stderr,"Returning\n");
9542       return(size*nmemb);
9543    }
9544 
CURL_read_URL_http(char * url,char ** data)9545    size_t CURL_read_URL_http ( char *url, char **data)
9546    {
9547       CURL *curl;
9548       CURLcode res;
9549       CURL_BUFFER_DATA cbd;
9550 
9551       curl = curl_easy_init();
9552       cbd.page = (char *)calloc(1, sizeof(char)); cbd.size = 0;
9553       curl_easy_setopt(curl, CURLOPT_URL, url);
9554       curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, CURL_buffer2data);
9555       curl_easy_setopt(curl, CURLOPT_WRITEDATA, (void *)&cbd);
9556       res = curl_easy_perform(curl);
9557       curl_easy_cleanup(curl);
9558 
9559       *data = cbd.page;
9560       return(cbd.size);
9561    }
9562 #endif /* CURL illustration */
9563 
whereami_XML_get(char * data,char * name,char ** next)9564 char * whereami_XML_get(char *data, char *name, char **next) {
9565    char n0[512], n1[512], *s0, *s1, *sout=NULL;
9566 
9567    *next = data;
9568 
9569    if (strlen(name) > 500) return(NULL);
9570    snprintf(n0,510,"<%s>", name);
9571    snprintf(n1,510,"</%s>", name);
9572    if (!(s0 = strstr(data, n0))) {
9573       /* no XML field with closing '>', look for "<field " with space instead */
9574       snprintf(n0,510,"<%s ", name);
9575       if (!(s0 = strstr(data, n0))) {
9576 /** INFO_message("whereami_XML_get failed to find '%s' in data",n0) ; **/
9577          return(NULL);
9578       }
9579    }
9580    if (!(s1 = strstr(s0, n1))){
9581 /** INFO_message("whereami_XML_get found '%s' in data -- BUT",n0); **/
9582 /** INFO_message("whereami_XML_get failed to find '%s' in data",n1) ; **/
9583      return(NULL);
9584    }
9585    s0 = s0+strlen(n0);
9586    if (s1 > s0) {
9587       sout = (char *)calloc(s1-s0+1, sizeof(char));
9588       memcpy(sout,s0,sizeof(char)*(s1-s0));
9589       sout[s1-s0]='\0';
9590 /** INFO_message("whereami_XML_get found %d bytes of '%s' in data",(int)(s1-s0),n1) ; **/
9591    }
9592 
9593    /* advance to next entry */
9594 /*   if(strlen(data)>(s1-s0+1))*/
9595       *next = s1+1;
9596 /*   else
9597       next = NULL;*/
9598    return(sout);
9599 }
9600 
9601 /* find first sub-string that starts and ends in quotes and
9602    return copy of the string between the quotes
9603 *  return string or string after first quotes */
search_quotes(char * in_str)9604 char * search_quotes(char *in_str)
9605 {
9606    char qt ='\"';
9607    char *s0,*s1, *sout=NULL;
9608 
9609    if (!(s0 = strchr(in_str, qt))) {
9610       /* no starting quote */
9611          return(in_str);
9612    }
9613    s0++;
9614 
9615    if (!(s1 = strchr(s0, qt))){
9616       return(s0);
9617    }
9618    sout = (char *)calloc(s1-s0+1, sizeof(char));
9619    memcpy(sout,s0,sizeof(char)*(s1-s0));
9620    sout[s1-s0]='\0';
9621    return(sout);
9622 }
9623 
9624 /* print columns of preset, correlation values from linkrbrain results*/
linkrbrain_XML_simple_report(char * xml_results_file,int linkr_corr_type)9625 int linkrbrain_XML_simple_report(char *xml_results_file,
9626     int linkr_corr_type)
9627 {
9628    FILE *xml_file;
9629    char *task_str, tempbuffer[2049];
9630    char *preset, *corr_str_ptr, *tempstr = NULL, *next = NULL;
9631    float corr;
9632    int len, found_correlation, temp;
9633    char tasktype_str[] = "Task type";
9634    char genetype_str[] = "Gene";
9635    char corr_str[] = "Correlation";
9636    int found_atleast_one = 0;
9637 
9638    ENTRY("linkrbrain_XML_simple_report");
9639    xml_file = fopen(xml_results_file, "r");
9640    if(!xml_file){
9641       printf("No response from %s\n",get_linkrbrain_site());
9642       RETURN(1);
9643    }
9644    /* try to read the first 2048 bytes from the XML file */
9645    len = fread(tempbuffer,1,2048,xml_file);
9646    if(len<=0) {
9647       printf("Response from %s is zero length\n",get_linkrbrain_site());
9648       RETURN(1);   /* take what we can get */
9649    }
9650    tempstr = tempbuffer; tempstr[len] = '\0' ;
9651    if(linkr_corr_type)
9652       printf("%-25s %-7s\n", genetype_str, corr_str);
9653    else
9654       printf("%-25s %-7s\n", tasktype_str, corr_str);
9655    printf("--------------------------------------\n");
9656 
9657    found_correlation = 1;
9658 /* find "correlation" fields */
9659    while(found_correlation) {
9660       found_correlation = 0;
9661       if(tempstr)
9662          corr_str_ptr = whereami_XML_get(tempstr, "correlation", &next);
9663       else
9664          corr_str_ptr = NULL;
9665       if(corr_str_ptr) {
9666           preset = strstr(corr_str_ptr, "preset=");
9667 /** if( preset == NULL ) ININFO_message("failed to find 'preset=' in data") ; **/
9668           if(preset) {
9669              preset += strlen("preset=");
9670              task_str = search_quotes(preset);
9671 /** if( task_str == NULL ) ININFO_message("failed to find quoted data after 'preset='") ; **/
9672              preset = strstr(preset, "overall score=");
9673 /** if( preset   == NULL ) ININFO_message("failed to find 'overall score=' in data") ; **/
9674              if(task_str && preset) {
9675                 preset += 1+ strlen("overall score=");
9676                 temp = sscanf(preset,"%f", &corr);
9677 
9678 /*                corr = strtod(preset, NULL); */
9679                 if(temp) {
9680                      printf("%-25s  %5.5f\n", task_str, corr);
9681                    if((corr>0.0) &&  (corr<=1.0)) {
9682                       found_atleast_one = 1;
9683                       found_correlation = 1;
9684                    }
9685                 }
9686                 free(task_str);
9687              }
9688           }
9689           tempstr = next;  /* advance buffer past current corr.value */
9690           free(corr_str_ptr);
9691       }
9692    }
9693    fclose(xml_file);
9694 
9695    if(found_atleast_one==0)
9696       printf("Didn't find any matches in %s's databases\n",get_linkrbrain_site());
9697    printf("\nFor more information, please visit %s\n",get_linkrbrain_site());
9698 
9699    RETURN(0);
9700 }
9701 
9702 /* get the correlation group "preset" and correlation value
9703    from the linkrbrain text */
linkrbrain_XML_get(char * data,FILE * fp,int offset)9704 char *linkrbrain_XML_get(char *data, FILE *fp, int offset)
9705 {
9706 
9707    return("linkrbrain_corr");
9708 }
9709 
9710 extern int afni_uses_selenium(void) ;
9711 extern int selenium_open_webpage(char *) ;
9712 
whereami_browser(char * url)9713 int whereami_browser(char *url)
9714 {
9715    char cmd[2345] ;
9716    static int icall=0;
9717 
9718    if( (url==NULL) || (strlen(url)==0)) return(-1);
9719 
9720    /* open a webpage using selenium webdriver */
9721    if( afni_uses_selenium() ) {
9722       selenium_open_webpage(url);
9723       return(0);
9724    }
9725    else{  /* open a webpage with regular system browser call */
9726       if (!GLOBAL_browser && !icall) {
9727          if (!(GLOBAL_browser = GetAfniWebBrowser())) {
9728             ERROR_message("Have no browser set. "
9729               "Specify one by adding the environment variable AFNI_WEB_BROWSER to\n"
9730               "your ~/.afnirc. For example:  AFNI_WEB_BROWSER firefox\n"
9731               "On a MAC you can also do: AFNI_WEB_BROWSER open\n");
9732          }
9733          icall = 1;
9734       }
9735       if (!GLOBAL_browser) return(0);
9736 
9737       sprintf(cmd ,
9738              "%s '%s' &" ,
9739              GLOBAL_browser, url ) ;
9740       if(wami_verb())
9741          printf("system command to send to browser is:\n%s\n",cmd);
9742 
9743       return(system(cmd));
9744   }
9745 }
9746 
9747 /* return copy of input url with special characters escaped */
9748 char *
cleanup_url(char * url)9749 cleanup_url(char *url)
9750 {
9751    int i, bad_count=0;
9752    char *clean_url = NULL;
9753    char *clean_ptr;
9754 
9755    if(url==NULL) return(NULL);
9756 
9757    for(i=0;i<strlen(url);i++){
9758       if(url[i]=='&'){
9759          bad_count++;
9760       }
9761       if(url[i]==';'){
9762          bad_count++;
9763       }
9764    }
9765    if(bad_count==0){
9766       NI_strncpy(clean_url, url, strlen(url));
9767       return(clean_url);
9768    }
9769    clean_url = (char *)calloc(strlen(url)+bad_count, sizeof(char));
9770    clean_ptr = clean_url;
9771    for(i=0;i<strlen(url);i++){
9772       if(url[i]=='&'){
9773          *clean_ptr++ = '\\';
9774          *clean_ptr++ = '&';
9775       }
9776       if(url[i]==';'){
9777          *clean_ptr++ = '\\';
9778          *clean_ptr++ = ';';
9779       }
9780       else{
9781          *clean_ptr++ = url[i];
9782       }
9783    }
9784    *clean_ptr = '\0';
9785    return(clean_url);
9786 }
9787 
9788 /* set static variable to show something was found/not found on a web atlas */
set_wami_web_found(int found)9789 void set_wami_web_found(int found)
9790 {
9791    wami_web_found = found;
9792 }
9793 
9794 /* find out if something was found */
get_wami_web_found()9795 int get_wami_web_found()
9796 {
9797    return(wami_web_found);
9798 }
9799 
9800 /* set static variable for output type for web atlas */
set_wami_web_reqtype(int web_reqtype)9801 void set_wami_web_reqtype(int web_reqtype)
9802 {
9803    wami_web_reqtype = web_reqtype;
9804 }
9805 
9806 /* output type */
get_wami_web_reqtype()9807 int get_wami_web_reqtype()
9808 {
9809    return(wami_web_reqtype);
9810 }
9811 
9812 /* set current webpage for whereami web request if needed */
set_wami_webpage(char * url)9813 void set_wami_webpage(char *url)
9814 {
9815 /*   char *tempurl;*/
9816 
9817    if(url==NULL){
9818       wami_url[0] = '\0';
9819    }
9820    else {
9821 /*      tempurl = cleanup_url(url);*/
9822       strcpy(wami_url, url);
9823 /*      free(tempurl);*/
9824    }
9825 }
9826 
9827 /* get the current webpage as a string */
get_wami_webpage()9828 char * get_wami_webpage()
9829 {
9830    return(wami_url);
9831 }
9832 
9833 /* open the current webpage */
open_wami_webpage()9834 void open_wami_webpage()
9835 {
9836    char *temppage;
9837 
9838    temppage = get_wami_webpage();
9839    if(temppage == NULL)
9840       return;
9841    if(strlen(temppage)==0)
9842       return;
9843    whereami_browser(temppage);
9844 }
9845 
AFNI_wami_output_mode(void)9846 int AFNI_wami_output_mode(void)
9847 {
9848    #ifdef DONT_USE_HTMLWIN
9849       return(0);
9850    #endif
9851    if( AFNI_yesenv("AFNI_DONT_USE_HTMLWIN") ){
9852       return(0);
9853    }
9854 
9855    /* changed default of AFNI_WEBBY_WAMI to be YES */
9856    /* now show whereami html GUI by default  - drg 01/23/2015 */
9857    if ( AFNI_noenv("AFNI_WEBBY_WAMI") ) { return (0); }
9858    else {   return(1);  }
9859 
9860    return(1);
9861 }
9862 
9863 /* set output of AFNI whereami to be in AFNI's HTML browser */
set_AFNI_wami_output_mode(int webflag)9864 void set_AFNI_wami_output_mode(int webflag)
9865 {
9866    if(webflag)
9867       AFNI_setenv("AFNI_WEBBY_WAMI=YES");
9868    else
9869       AFNI_setenv("AFNI_WEBBY_WAMI=NO");
9870 }
9871 
9872 /* return webpage name with supplemental information for a particular label -
9873    the name is based on label itself and the atlas supp_web_info base site name and
9874    an extension type (.pdf, .html, ...) */
atlas_suppinfo_webpage(ATLAS * atlas,char * blab)9875 char * atlas_suppinfo_webpage(ATLAS *atlas, char *blab)
9876 {
9877 /*    static char webpage[256];*/
9878 
9879    char *webpage;
9880 
9881     if(ATL_SUPP_WEB_INFO(atlas) == 0) return(NULL);
9882 
9883 /*    webpage = calloc(strlen(atlas->supp_web_info)+strlen(blab)+strlen(atlas->supp_web_type),sizeof(char));*/
9884     webpage = calloc(256,sizeof(char));
9885     if(webpage==NULL) return(NULL);
9886 
9887     if(atlas->supp_web_type != NULL)
9888        sprintf(webpage, "%s%s%s", atlas->supp_web_info, blab, atlas->supp_web_type);
9889     else
9890        sprintf(webpage, "%s%s.html", atlas->supp_web_info, blab);
9891     return (webpage);
9892 }
9893 
9894 /* return webpage name with supplemental information for a particular label -
9895    the name is based on label itself and the atlas supp_conn_info base site name and
9896    an extension type (.pdf, .html, ...) */
atlas_suppinfo_connpage(ATLAS * atlas,char * blab)9897 char * atlas_suppinfo_connpage(ATLAS *atlas, char *blab)
9898 {
9899 /*    static char webpage[256];*/
9900 
9901    char *webpage;
9902 
9903     if(ATL_SUPP_CONN_INFO(atlas) == 0) return(NULL);
9904 
9905     webpage = calloc(256,sizeof(char));
9906     if(webpage==NULL) return(NULL);
9907 
9908     if(atlas->supp_conn_type != NULL)
9909        sprintf(webpage, "%s%s%s", atlas->supp_conn_info, blab, atlas->supp_conn_type);
9910     else
9911        sprintf(webpage, "%s%s.html", atlas->supp_conn_info, blab);
9912     return (webpage);
9913 }
9914 
9915 /* return longname, if available and environment requested, for atlas region blab
9916  *  in newly allocated string */
atlas_suppinfo_longname(ATLAS * atlas,char * blab)9917 char * atlas_suppinfo_longname(ATLAS *atlas, char *blab)
9918 {
9919 /*    static char webpage[256];*/
9920 
9921    char *longname, *slongptr;
9922 
9923     if(Atlas_name_type() == 0) return(NULL);
9924 
9925     longname = calloc(256,sizeof(char));
9926     if(longname==NULL) return(NULL);
9927     slongptr = atlas_point_long_name_named(atlas->adh->apl2, blab);
9928     if(slongptr)
9929        sprintf(longname, "%s", slongptr);
9930     return (longname);
9931 }
9932 
9933 /* set minimum probabilty to use in probabilistic atlases */
set_wami_minprob(float val)9934 void set_wami_minprob(float val)
9935 {
9936    if((val>0) && (val<=1.0))
9937       wami_min_prob = val;
9938 }
9939 
9940 /* get minimum probability to use in probabilistic atlases */
get_wami_minprob()9941 float get_wami_minprob()
9942 {
9943    if(wami_min_prob>0)
9944       return(wami_min_prob);
9945    /* set wami_min_prob to environment value if it exists, otherwise tiny number */
9946    wami_min_prob = (float) AFNI_numenv_def("AFNI_WHEREAMI_PROB_MIN", TINY_NUMBER);
9947    if(wami_min_prob<=0)
9948       wami_min_prob = TINY_NUMBER;
9949    return(wami_min_prob);
9950 }
9951 
9952 int
wami_xform_coords_print(float * coords,int ncoords,char * srcspace,char * destspace,char * outfile)9953 wami_xform_coords_print(float *coords, int ncoords,
9954    char *srcspace, char *destspace, char *outfile)
9955 {
9956    int i;
9957    FILE *tempout;
9958    float *fptr;
9959    float xi,yi,zi,xout,yout,zout;
9960    ATLAS_XFORM_LIST *xfl = NULL, *cxfl = NULL;
9961 
9962    ENTRY("wami_xform_coords_print");
9963 
9964    if(ncoords<=0)
9965      RETURN(-1);
9966 
9967    if(outfile!=NULL) {   /* null output, print to stdout */
9968       tempout = fopen(outfile, "w");
9969       if(!tempout) RETURN(-1);
9970    }
9971    else tempout = stdout;
9972 
9973    if(strcmp(srcspace, destspace)==0)
9974       cxfl = NULL;   /* data already in destination space*/
9975    else {
9976       xfl = report_xform_chain(srcspace, destspace, 0);
9977       cxfl = calc_xform_list(xfl);
9978       if(!cxfl){
9979          WARNING_message("Could not compute xform between spaces\n");
9980          free(xfl);
9981          RETURN(-1);
9982       }
9983    }
9984 
9985    /* convert coordinates to LPI */
9986    for(i=0;i<ncoords;i++){
9987          fptr = coords+(i*3);
9988          if(cxfl) {
9989             xi = *fptr++; yi = *fptr++; zi = *fptr;
9990             apply_xform_chain(cxfl, xi, yi, zi, &xout, &yout, &zout);
9991          }
9992          else {
9993             xi = *fptr++; yi = *fptr++; zi = *fptr;
9994             xout = xi; yout = yi; zout = zi;
9995          }
9996 
9997          fprintf(tempout, "%.3f %.3f %.3f\n", xout, yout, zout);
9998 
9999    }
10000 
10001    fclose(tempout);
10002    free(cxfl);
10003    free(xfl);
10004    RETURN(0);
10005 }
10006 
10007 
10008 int
wami_xform_xyz(float xi,float yi,float zi,float * xout,float * yout,float * zout,char * srcspace,char * destspace)10009 wami_xform_xyz(float xi, float yi, float zi,
10010    float *xout, float *yout, float *zout,
10011    char *srcspace, char *destspace)
10012 {
10013    ATLAS_XFORM_LIST *xfl = NULL, *cxfl = NULL;
10014 
10015    ENTRY("wami_xform_coords_xyz");
10016 
10017 
10018    if(strcmp(srcspace, destspace)==0)
10019       cxfl = NULL;   /* data already in destination space*/
10020    else {
10021       xfl = report_xform_chain(srcspace, destspace, 0);
10022       cxfl = calc_xform_list(xfl);
10023       if(!cxfl){
10024          WARNING_message("Could not compute xform between spaces\n");
10025          free(xfl);
10026          RETURN(-1);
10027       }
10028    }
10029 
10030    if(cxfl) {
10031       apply_xform_chain(cxfl, xi, yi, zi, xout, yout, zout);
10032    }
10033    else {
10034       *xout = xi; *yout = yi; *zout = zi;
10035    }
10036 
10037    free(cxfl);
10038    free(xfl);
10039    RETURN(0);
10040 }
10041