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 = " " ;
988 const char *nbspp = " " ;
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&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