1 #undef MAIN
2
3 #include "afni.h"
4
5 /*-----------------------------------------------------------------------*/
6 /*! Create a nodal color overlay from a voxel map.
7 - Input ks is surface index to use from im3d->ss_now session
8 - Return value is number of nodes overlaid:
9 - 0 return ==> no overlay was computed
10 - -1 return ==> some error (e.g., no surface nodes on this dataset)
11 = positive ==> can use *map and *nvused
12 - *map is set to a newly malloc()-ed array (if return > 0)
13 - *nvused is set to the number of functional dataset voxels used to
14 make the map (e.g., those that got some color)
15 - im3d->ss_now[ks]->vn->nvox will have the total number of
16 functional dataset voxels that intersected the surface
17
18 Sample usage:
19 - SUMA_irgba *map ;
20 - int nmap , nvox ;
21 - nmap = AFNI_vnlist_func_overlay( im3d , 0 , &map , &nvox ) ;
22 - if( nmap < 0 ){ ** error ** }
23 - else if( nmap == 0 ){ ** nothing to show ** }
24 - else { ** show map[0..nmap-1] ** }
25
26 Much of this function is a 3D-ification of AFNI_func_overlay().
27 -------------------------------------------------------------------------*/
28
AFNI_vnlist_func_overlay(Three_D_View * im3d,int ks,SUMA_irgba ** map,int * nvused)29 int AFNI_vnlist_func_overlay( Three_D_View *im3d, int ks ,
30 SUMA_irgba **map, int *nvused )
31 {
32 MRI_IMAGE *im_thr , *im_fim ;
33 short fim_ovc[NPANE_MAX+1] ;
34 byte ovc_r[NPANE_MAX+1], ovc_g[NPANE_MAX+1], ovc_b[NPANE_MAX+1] ;
35 int ii,jj,nn , lp , num_lp , ival ;
36 float scale_factor , scale_thr=1.0 , scale_fim=1.0 ;
37 MCW_pbar * pbar ;
38 int simult_thr , need_thr ;
39 THD_3dim_dataset *fdset ;
40 SUMA_irgba *mmm ;
41 SUMA_ixyz *ixyz ;
42 int nvox,nnod,nout , *numnod , *voxijk , *nlist ;
43 int *vlist ;
44 int nvout ; /* 13 Mar 2002 */
45
46 int bm , zbot=0 , kk ; /* 02 Feb 2003: colorscale stuff */
47 float fbot=0.0,ftop=0.0,ffac=0.0 , val ;
48 rgbyte *cmap=NULL ;
49
50 THD_session *ss ; /* 22 Jan 2004 */
51 SUMA_surface *surf ;
52 SUMA_vnlist *vn ;
53
54 ENTRY("AFNI_vnlist_func_overlay") ;
55
56 /* check inputs for goodness sakes */
57
58 if( map == NULL || !IM3D_VALID(im3d) ) RETURN(-1) ; /* that was easy */
59
60 if( nvused != NULL ) *nvused = 0 ; /* set default return value here */
61
62 /* check datasets for goodness */
63 /* 12 Dec 2002: ks is now input (we used to compute it) */
64
65 ss = im3d->ss_now ; /* session must */
66 if( ss == NULL || /* have surface #ks */
67 ss->su_num == 0 ||
68 ks < 0 ||
69 ss->su_num <= ks ||
70 ss->su_surf[ks] == NULL ) RETURN(-1) ;
71
72 surf = ss->su_surf[ks] ; /* the surface in question */
73
74 fdset = im3d->fim_now ; if( !ISVALID_DSET(fdset) ) RETURN(-1) ;
75
76 ival = im3d->vinfo->thr_index ; /* threshold sub-brick index */
77
78 /* get the component images */
79
80 need_thr = (im3d->vinfo->func_threshold > 0.0) && im3d->vinfo->thr_onoff ;
81
82 if( need_thr ) im_thr = DSET_BRICK(fdset,ival) ;
83 else im_thr = NULL ;
84
85 if( im_thr != NULL && !AFNI_GOOD_FUNC_DTYPE(im_thr->kind) ) im_thr = NULL ;
86
87 if( im_thr != NULL ){
88 scale_thr = DSET_BRICK_FACTOR(fdset,ival) ;
89 if( scale_thr == 0.0 || im_thr->kind == MRI_float ) scale_thr = 1.0 ;
90 }
91
92 { int ind ;
93
94 ind = im3d->vinfo->fim_index ;
95 if( ind >= DSET_NVALS(fdset) )
96 ind = DSET_NVALS(fdset) - 1 ;
97
98 im_fim = DSET_BRICK(fdset,ind) ; /* the sub-brick to show */
99 scale_factor = im3d->vinfo->fim_range ;
100 if( scale_factor == 0.0 ) scale_factor = im3d->vinfo->fim_autorange ;
101 if( scale_factor == 0.0 ) scale_factor = 1.0 ;
102
103 scale_fim = DSET_BRICK_FACTOR(fdset,ind) ;
104 if( scale_fim == 0.0 ) scale_fim = 1.0 ;
105
106 }
107
108 /* if component images not good, quit now */
109
110 if( im_fim == NULL ) RETURN(-1) ; /* no function!? */
111
112 if( !AFNI_GOOD_FUNC_DTYPE(im_fim->kind) ){
113 RETURN(-1) ; /* bad function - no soup for you */
114 }
115
116 /* maybe need to build a voxel-to-node list for func dataset */
117 /* (this is where the 3D-to-2D mapping is encapsulated, Ziad) */
118
119 if( surf->vn == NULL ||
120 !EQUIV_DATAXES(surf->vn->dset->daxes,fdset->daxes) ){
121
122 /* if have an old one
123 (that doesn't match current dataset grid),
124 then delete it from the Universe */
125
126 if( surf->vn != NULL ) SUMA_destroy_vnlist( surf->vn ) ;
127
128 /* make the new list */
129
130 surf->vn = SUMA_make_vnlist( surf , fdset ) ;
131 if( surf->vn == NULL ) RETURN(-1) ;
132 }
133
134 vn = surf->vn ; /* voxel-to-node list for this surface */
135
136 /* create array of voxel indexes (vlist);
137 will put in there the voxels that are above threshold */
138
139 nvox = vn->nvox ; if( nvox < 1 ) RETURN(0);
140 voxijk = vn->voxijk ; /* list of voxels with surface nodes */
141 numnod = vn->numnod ; /* number of nodes in each voxel */
142
143 nnod = surf->num_ixyz ; if( nnod < 1 ) RETURN(0);
144 ixyz = surf->ixyz ; /* array of surface nodes */
145
146 DSET_load(fdset) ; /* if isn't in memory now */
147 if( !DSET_LOADED(fdset) ) RETURN(-1) ; /* what the hell? */
148
149 /** if don't have threshold, will process all voxels for color **/
150
151 if( im_thr == NULL ){
152
153 vlist = voxijk ; /* list of voxels to process = all voxels */
154 nout = nnod ; /* number of output nodes */
155
156 /** if have threshold, cut out voxels below threshold (set vlist[]=-1) **/
157
158 } else {
159
160 vlist = (int *) malloc(sizeof(int)*nvox) ; /* copy voxel list */
161 memcpy( vlist , voxijk , sizeof(int)*nvox ) ; /* then prune it */
162
163 switch( im_thr->kind ){
164 default: break ; /* should not happen */
165
166 case MRI_short:{
167 float thresh = im3d->vinfo->func_threshold
168 * im3d->vinfo->func_thresh_top / scale_thr ;
169 short *ar_thr = MRI_SHORT_PTR(im_thr) ;
170 for( ii=0 ; ii < nvox ; ii++ ){ /* voxel cutting time */
171 jj = vlist[ii] ; /* actual voxel index in func brick */
172 if( ar_thr[jj] > -thresh && ar_thr[jj] < thresh ) vlist[ii] = -1 ;
173 }
174 }
175 break ;
176
177 case MRI_byte:{
178 float thresh = im3d->vinfo->func_threshold
179 * im3d->vinfo->func_thresh_top / scale_thr ;
180 byte *ar_thr = MRI_BYTE_PTR(im_thr) ;
181 for( ii=0 ; ii < nvox ; ii++ ){
182 jj = vlist[ii] ;
183 if( ar_thr[jj] < thresh ) vlist[ii] = -1 ;
184 }
185 }
186 break ;
187
188 case MRI_float:{
189 float thresh = im3d->vinfo->func_threshold
190 * im3d->vinfo->func_thresh_top / scale_thr ;
191 float *ar_thr = MRI_FLOAT_PTR(im_thr) ;
192 for( ii=0 ; ii < nvox ; ii++ ){
193 jj = vlist[ii] ;
194 if( ar_thr[jj] > -thresh && ar_thr[jj] < thresh ) vlist[ii] = -1 ;
195 }
196 }
197 break ;
198 } /* end of switch on threshold sub-brick type */
199
200 /* count surviving voxels; exit if there aren't any */
201
202 for( jj=ii=0 ; ii < nvox ; ii++ )
203 if( vlist[ii] >= 0 ) jj++ ;
204 if( jj == 0 ){ free(vlist) ; RETURN(0) ; }
205
206 /* count output nodes inside each surviving voxel */
207
208 for( nout=ii=0 ; ii < nvox ; ii++ )
209 if( vlist[ii] >= 0 ) nout += numnod[ii] ;
210
211 } /* end of if on existence of threshold sub-brick */
212
213 /** allocate output structure (maybe too big, but will clip it later) **/
214
215 mmm = (SUMA_irgba *) malloc( sizeof(SUMA_irgba) * nout ) ;
216
217 /** set overlay colors **/
218
219 pbar = im3d->vwid->func->inten_pbar ;
220 num_lp = pbar->num_panes ;
221 bm = pbar->bigmode ; /* 02 Feb 2003 */
222
223 if( !bm ){ /* indexed colors */
224 for( lp=0 ; lp < num_lp ; lp++ ) /* overlay color indexes */
225 fim_ovc[lp] = pbar->ov_index[lp] ; /* run from top of pbar down */
226
227 /* overlay color index for values below bottom of pbar */
228
229 fim_ovc[num_lp] = (im3d->vinfo->use_posfunc) ? (0) : (fim_ovc[num_lp-1]) ;
230
231 /* get the actual RGB colors of each pane on the pbar */
232
233 for( lp=0 ; lp <= num_lp ; lp++ ){
234 ovc_r[lp] = DCOV_REDBYTE (im3d->dc,fim_ovc[lp]) ;
235 ovc_g[lp] = DCOV_GREENBYTE(im3d->dc,fim_ovc[lp]) ;
236 ovc_b[lp] = DCOV_BLUEBYTE (im3d->dc,fim_ovc[lp]) ;
237 }
238
239 } else { /* colorscale colors - 02 Feb 2003 */
240 fbot = (scale_factor/scale_fim)*pbar->bigbot ;
241 ftop = (scale_factor/scale_fim)*pbar->bigtop ;
242 ffac = NPANE_BIG / (ftop-fbot) ;
243 cmap = pbar->bigcolor ;
244 zbot = (fbot == 0.0) ;
245 }
246
247 /** process im_fim into overlay, depending on data type **/
248
249 switch( im_fim->kind ){
250
251 default: nvout = nout = 0 ; break ; /* should never happen! */
252
253 case MRI_rgb:{ /* 17 Apr 2002 */
254 byte *ar_fim = MRI_RGB_PTR(im_fim); /* colors direct from fim */
255 byte r,g,b ;
256
257 nvout = nout = 0 ; /* num output nodes & voxels */
258 for( ii=0 ; ii < nvox ; ii++ ){
259 jj = vlist[ii] ; if( jj < 0 ) continue ; /* skip voxel? */
260 r = ar_fim[3*jj]; g = ar_fim[3*jj+1]; b = ar_fim[3*jj+2];
261 if( r == 0 && g ==0 && b == 0 ) continue ; /* uncolored */
262 nlist = vn->nlist[ii] ; /* list of nodes */
263 for( nn=0 ; nn < numnod[ii] ; nn++ ){ /* loop over nodes */
264 mmm[nout].id = ixyz[nlist[nn]].id ;
265 mmm[nout].r = r ; mmm[nout].g = g ;
266 mmm[nout].b = b ; mmm[nout].a = 255 ; nout++ ;
267 }
268 nvout++ ; /* number of voxels used */
269 }
270 }
271 break ;
272
273 case MRI_short:{
274 short * ar_fim = MRI_SHORT_PTR(im_fim) ;
275 float fim_thr[NPANE_MAX] ;
276 byte r,g,b ;
277
278 if( !bm ){ /* indexed colors from panes */
279 for( lp=0 ; lp < num_lp ; lp++ ) /* thresholds for each pane */
280 fim_thr[lp] = (scale_factor/scale_fim) * pbar->pval[lp+1] ;
281 }
282
283 nvout = nout = 0 ; /* num output nodes & voxels */
284 for( ii=0 ; ii < nvox ; ii++ ){
285 jj = vlist[ii] ; if( jj < 0 ) continue ; /* skip voxel? */
286 if( ar_fim[jj] == 0 ) continue ; /* no func? */
287 if( !bm ){ /* find pane this voxel is in */
288 for( lp=0; lp < num_lp && ar_fim[jj] < fim_thr[lp]; lp++ ) ; /*nada*/
289 if( fim_ovc[lp] == 0 ) continue ; /* uncolored pane */
290 r = ovc_r[lp]; g = ovc_g[lp]; b = ovc_b[lp];
291 } else { /* colorscale - 02 Feb 2003 */
292 if( zbot && ar_fim[jj] < 0 ) continue ;
293 val = ffac*(ftop-ar_fim[jj]) ;
294 if( val < 0.0 ) val = 0.0;
295 kk = (int)(val+0.49); if( kk >= NPANE_BIG ) kk = NPANE_BIG-1;
296 r = cmap[kk].r; g = cmap[kk].g; b = cmap[kk].b;
297 if( r == 0 && g ==0 && b == 0 ) continue ; /* black == uncolored */
298 }
299 nlist = vn->nlist[ii] ; /* list of nodes */
300 for( nn=0 ; nn < numnod[ii] ; nn++ ){ /* loop over nodes */
301 mmm[nout].id = ixyz[nlist[nn]].id ;
302 mmm[nout].r = r ; mmm[nout].g = g ;
303 mmm[nout].b = b ; mmm[nout].a = 255 ; nout++ ;
304 }
305 nvout++ ; /* number of voxels used */
306 }
307 }
308 break ;
309
310 case MRI_byte:{
311 byte * ar_fim = MRI_BYTE_PTR(im_fim) ;
312 float fim_thr[NPANE_MAX] ;
313 byte r,g,b ;
314
315 if( !bm ){ /* indexed colors from panes */
316 for( lp=0 ; lp < num_lp ; lp++ )
317 if( pbar->pval[lp+1] <= 0.0 )
318 fim_thr[lp] = 0 ;
319 else
320 fim_thr[lp] = (scale_factor/scale_fim) * pbar->pval[lp+1] ;
321 }
322
323 nvout = nout = 0 ; /* num output nodes */
324 for( ii=0 ; ii < nvox ; ii++ ){
325 jj = vlist[ii] ; if( jj < 0 ) continue ; /* skip voxel? */
326 if( ar_fim[jj] == 0 ) continue ; /* no func? */
327 if( !bm ){ /* find pane this voxel is in */
328 for( lp=0; lp < num_lp && ar_fim[jj] < fim_thr[lp]; lp++ ) ; /*nada*/
329 if( fim_ovc[lp] == 0 ) continue ; /* uncolored pane */
330 r = ovc_r[lp]; g = ovc_g[lp]; b = ovc_b[lp];
331 } else { /* colorscale - 02 Feb 2003 */
332 val = ffac*(ftop-ar_fim[jj]) ;
333 if( val < 0.0 ) val = 0.0;
334 kk = (int)(val+0.49); if( kk >= NPANE_BIG ) kk = NPANE_BIG-1;
335 r = cmap[kk].r; g = cmap[kk].g; b = cmap[kk].b;
336 if( r == 0 && g ==0 && b == 0 ) continue ; /* black == uncolored */
337 }
338 nlist = vn->nlist[ii] ; /* list of nodes */
339 for( nn=0 ; nn < numnod[ii] ; nn++ ){ /* loop over nodes */
340 mmm[nout].id = ixyz[nlist[nn]].id ;
341 mmm[nout].r = r ; mmm[nout].g = g ;
342 mmm[nout].b = b ; mmm[nout].a = 255 ; nout++ ;
343 }
344 nvout++ ; /* number of voxels used */
345 }
346 }
347 break ;
348
349 case MRI_float:{
350 float * ar_fim = MRI_FLOAT_PTR(im_fim) ;
351 float fim_thr[NPANE_MAX] ;
352 byte r,g,b ;
353
354 if( !bm ){ /* indexed colors from panes */
355 for( lp=0 ; lp < num_lp ; lp++ )
356 fim_thr[lp] = (scale_factor/scale_fim) * pbar->pval[lp+1] ;
357 }
358
359 nvout = nout = 0 ; /* num output nodes */
360 for( ii=0 ; ii < nvox ; ii++ ){
361 jj = vlist[ii] ; if( jj < 0 ) continue ; /* skip voxel? */
362 if( ar_fim[jj] == 0.0 ) continue ; /* no func? */
363 if( !bm ){ /* find pane this voxel is in */
364 for( lp=0; lp < num_lp && ar_fim[jj] < fim_thr[lp]; lp++ ) ; /*nada*/
365 if( fim_ovc[lp] == 0 ) continue ; /* uncolored pane */
366 r = ovc_r[lp]; g = ovc_g[lp]; b = ovc_b[lp];
367 } else { /* colorscale - 02 Feb 2003 */
368 if( zbot && ar_fim[jj] < 0.0 ) continue ;
369 val = ffac*(ftop-ar_fim[jj]) ;
370 if( val < 0.0 ) val = 0.0;
371 kk = (int)(val+0.49); if( kk >= NPANE_BIG ) kk = NPANE_BIG-1;
372 r = cmap[kk].r; g = cmap[kk].g; b = cmap[kk].b;
373 if( r == 0 && g ==0 && b == 0 ) continue ; /* black == uncolored */
374 }
375 nlist = vn->nlist[ii] ; /* list of nodes */
376 for( nn=0 ; nn < numnod[ii] ; nn++ ){ /* loop over nodes */
377 mmm[nout].id = ixyz[nlist[nn]].id ;
378 mmm[nout].r = r ; mmm[nout].g = g ;
379 mmm[nout].b = b ; mmm[nout].a = 255 ; nout++ ;
380 }
381 nvout++ ; /* number of voxels used */
382 }
383 }
384 break ;
385
386 } /* end of switch on fim data type */
387
388 /** finished: clean up and exit **/
389
390 if( vlist != voxijk ) free(vlist) ; /* toss trash, if it is trash */
391
392 if( nout == 0 ){ free(mmm); RETURN(0); } /* no overlay? */
393
394 /* map gets the array of node IDs + colors */
395
396 *map = (SUMA_irgba *) realloc( mmm , sizeof(SUMA_irgba)*nout ) ;
397
398 /* nvused gets the number of voxels used */
399
400 if( nvused != NULL ) *nvused = nvout ; /* 13 Mar 2002 */
401
402 RETURN(nout) ; /* number of entries in map */
403 }
404
405 /*-----------------------------------------------------------------------*/
406 /*! Find node in surface closest to given DICOM vector, with limitation
407 that node's x is in range xbot..xtop, etc. Return value is node
408 index into ixyz array (not necessarily node ID), -1 if none is found.
409 -------------------------------------------------------------------------*/
410
AFNI_find_closest_node(int num_ixyz,SUMA_ixyz * ixyz,float xtarg,float ytarg,float ztarg,float xbot,float xtop,float ybot,float ytop,float zbot,float ztop)411 int AFNI_find_closest_node( int num_ixyz , SUMA_ixyz *ixyz ,
412 float xtarg, float ytarg, float ztarg,
413 float xbot , float xtop ,
414 float ybot , float ytop ,
415 float zbot , float ztop )
416 {
417 int ii , ibest=-1 ;
418 float x,y,z , dbest=0.0f, d ;
419
420 ENTRY("AFNI_find_closest_node") ;
421
422 if( num_ixyz <= 0 || ixyz == NULL ) RETURN(-1) ; /* bad inputs */
423
424 /* if search ranges are incoherent, make them very wide */
425
426 if( xbot >= xtop ){ xbot = -WAY_BIG; xtop = WAY_BIG; }
427 if( ybot >= ytop ){ ybot = -WAY_BIG; ytop = WAY_BIG; }
428 if( zbot >= ztop ){ zbot = -WAY_BIG; ztop = WAY_BIG; }
429
430 for( ii=0 ; ii < num_ixyz ; ii++ ){
431 x = ixyz[ii].x; y = ixyz[ii].y; z = ixyz[ii].z;
432 if( x < xbot || x > xtop ||
433 y < ybot || y > ytop ||
434 z < zbot || z > ztop ) continue ; /* outside box */
435
436 d = (xtarg-x)*(xtarg-x) + (ytarg-y)*(ytarg-y) + (ztarg-z)*(ztarg-z) ;
437 if( ibest < 0 || d < dbest ){ ibest = ii; dbest = d; }
438 }
439
440 RETURN(ibest) ;
441 }
442
443 /*---------------------------------------------------------------------------*/
444 /*-------- Stuff below here is for surface control panel [19 Aug 2002] ------*/
445
446 static int swid_ncol = 0 ; /* 06 Sep 2006 */
447 static int *swid_boxcol = NULL ;
448 static int *swid_lincol = NULL ;
449
450 /*---------------------------------------------------------------------------*/
451 /*! Get an initial color for surface things. */
452
AFNI_get_suma_color(int ss,rgbyte * bcolor,rgbyte * lcolor)453 void AFNI_get_suma_color( int ss , rgbyte *bcolor , rgbyte *lcolor )
454 {
455 Three_D_View *im3d = AFNI_find_open_controller() ;
456
457 if( bcolor == NULL || lcolor == NULL ) return ;
458
459 if( ss >= 0 && ss < swid_ncol ){
460 int bb , ll ;
461 bb = swid_boxcol[ss] ; ll = swid_lincol[ss] ;
462 if( bb > 0 ){
463 bcolor->r = DCOV_REDBYTE (im3d->dc,bb) ;
464 bcolor->g = DCOV_GREENBYTE(im3d->dc,bb) ;
465 bcolor->b = DCOV_BLUEBYTE (im3d->dc,bb) ;
466 } else {
467 bcolor->r = bcolor->g = bcolor->b = 1 ;
468 }
469 if( ll > 0 ){
470 lcolor->r = DCOV_REDBYTE (im3d->dc,ll) ;
471 lcolor->g = DCOV_GREENBYTE(im3d->dc,ll) ;
472 lcolor->b = DCOV_BLUEBYTE (im3d->dc,ll) ;
473 } else {
474 lcolor->r = lcolor->g = lcolor->b = 1 ;
475 }
476 } else {
477 char *eee ; float rr,gg,bb ;
478 eee = getenv("AFNI_SUMA_BOXCOLOR") ;
479 if( eee != NULL ){
480 if( strcmp(eee,"none") == 0 || strcmp(eee,"skip") == 0 ){
481 bcolor->r = bcolor->g = bcolor->b = 1 ;
482 } else {
483 DC_parse_color( im3d->dc , eee , &rr,&gg,&bb ) ;
484 bcolor->r = (byte)(rr*255.666f) ;
485 bcolor->g = (byte)(gg*255.666f) ;
486 bcolor->b = (byte)(bb*255.666f) ;
487 }
488 } else {
489 bcolor->r = 254 ; bcolor->g = bcolor->b = 0 ;
490 }
491 eee = getenv("AFNI_SUMA_LINECOLOR") ;
492 if( eee != NULL ){
493 if( strcmp(eee,"none") == 0 || strcmp(eee,"skip") == 0 ){
494 lcolor->r = lcolor->g = lcolor->b = 1 ;
495 } else {
496 DC_parse_color( im3d->dc , eee , &rr,&gg,&bb ) ;
497 lcolor->r = (byte)(rr*255.666f) ;
498 lcolor->g = (byte)(gg*255.666f) ;
499 lcolor->b = (byte)(bb*255.666f) ;
500 }
501 } else {
502 lcolor->r = 100 ; lcolor->g = 0 ; lcolor->b = 199 ;
503 }
504 }
505 return ;
506 }
507
508 /*---------------------------------------------------------------------------*/
509 /*! Set initial colors for surface menu items,
510 for use later when the surface menus are actually created. */
511
AFNI_init_suma_color(int ss,char * bcol,char * lcol)512 void AFNI_init_suma_color( int ss , char *bcol , char *lcol ) /* 06 Sep 2006 */
513 {
514 int lin_col , box_col ;
515
516 if( ss < 0 ) return ;
517
518 box_col = DC_find_closest_overlay_color( GLOBAL_library.dc , bcol ) ;
519 if( box_col < 0 ) box_col = 0 ; /* == "none" */
520
521 lin_col = DC_find_closest_overlay_color( GLOBAL_library.dc , lcol ) ;
522 if( lin_col < 0 ) lin_col = MIN(6,GLOBAL_library.dc->ovc->ncol_ov-1) ;
523
524 if( ss >= swid_ncol ){
525 swid_boxcol = (int *)realloc( (void *)swid_boxcol, sizeof(int)*(ss+1) ) ;
526 swid_lincol = (int *)realloc( (void *)swid_lincol, sizeof(int)*(ss+1) ) ;
527 memset( swid_boxcol+swid_ncol , 0 , sizeof(int)*(ss+1-swid_ncol) ) ;
528 memset( swid_lincol+swid_ncol , 0 , sizeof(int)*(ss+1-swid_ncol) ) ;
529 swid_ncol = ss+1 ;
530 }
531 swid_boxcol[ss] = box_col ;
532 swid_lincol[ss] = lin_col ;
533 return ;
534 }
535
536 /*---------------------------------------------------------------------------*/
537
538 static void AFNI_surf_done_CB( Widget,XtPointer,XtPointer ) ;
539 static void AFNI_surf_redraw_CB( MCW_arrowval *,XtPointer ) ;
540 static void AFNI_make_surface_widgets( Three_D_View *, int ) ;
541 static void AFNI_surf_bbox_CB( Widget,XtPointer,XtPointer ) ; /* 19 Feb 2003 */
542
543 /*---------------------------------------------------------------------------*/
544 /*! Make the widgets for one row of the surface control panel.
545 The row itself will not be managed at this time; that comes later. */
546
547 #undef MAKE_SURF_ROW
548 #define MAKE_SURF_ROW(ii) \
549 do{ Widget rc ; char *str[1]={"abcdefghijklmn: "} ; int bs=0 ; \
550 rc = swid->surf_rc[ii] = \
551 XtVaCreateWidget( \
552 "dialog" , xmRowColumnWidgetClass , swid->rowcol , \
553 XmNpacking , XmPACK_TIGHT , \
554 XmNorientation , XmHORIZONTAL , \
555 XmNtraversalOn , True , \
556 NULL ) ; \
557 swid->surf_bbox[ii] = new_MCW_bbox( rc , 1 , str , \
558 MCW_BB_check, MCW_BB_noframe, \
559 AFNI_surf_bbox_CB , im3d ) ; \
560 bs = ! AFNI_noenv("AFNI_SUMA_START_ON") ; \
561 MCW_set_bbox( swid->surf_bbox[ii] , bs ) ; \
562 MCW_reghelp_children( swid->surf_bbox[ii]->wrowcol , \
563 "Use this toggle to turn the\n" \
564 "overlay drawing for this surface\n" \
565 "off and back on." ) ; \
566 swid->surf_node_av[ii] = new_MCW_colormenu( rc , \
567 "Nodes" , im3d->dc , \
568 0 , im3d->dc->ovc->ncol_ov-1 , \
569 box_col , \
570 AFNI_surf_redraw_CB , im3d ) ; \
571 swid->surf_line_av[ii] = new_MCW_colormenu( rc , \
572 "Lines" , im3d->dc , \
573 0 , im3d->dc->ovc->ncol_ov-1 , \
574 line_col , \
575 AFNI_surf_redraw_CB , im3d ) ; \
576 swid->surf_ledg_av[ii] = new_MCW_colormenu( rc , \
577 "+/-" , im3d->dc , \
578 0 , im3d->dc->ovc->ncol_ov-1 , 0 , \
579 AFNI_surf_redraw_CB , im3d ) ; \
580 MCW_reghint_children( swid->surf_node_av[ii]->wrowcol , \
581 "Color of node boxes" ) ; \
582 MCW_reghelp_children( swid->surf_node_av[ii]->wrowcol , \
583 "If this is not 'none', then\n" \
584 "a box will be drawn around the\n" \
585 "location of each surface node\n" \
586 "inside the slice volume." ) ; \
587 MCW_reghint_children( swid->surf_line_av[ii]->wrowcol , \
588 "Color of triangle lines" ) ; \
589 MCW_reghelp_children( swid->surf_line_av[ii]->wrowcol , \
590 "If this is not 'none', then\n" \
591 "line segments will be drawn for the\n" \
592 "intersection of each surface facet\n" \
593 "with the slice center plane." ); \
594 MCW_reghelp_children( swid->surf_ledg_av[ii]->wrowcol , \
595 "If this is not 'none', then\n" \
596 "line segments will be drawn for the\n" \
597 "intersection of each surface facet\n" \
598 "with the slice edge planes (+/-)." ) ; \
599 } while(0)
600
601 /*------------------------------------------------------------------------*/
602 /*! Make surface widgets for an AFNI controller [19 Aug 2002].
603 Called only once to create the initial set of widgets.
604 AFNI_update_surface_widgets() is used to update the list
605 when something changes.
606 --------------------------------------------------------------------------*/
607
AFNI_make_surface_widgets(Three_D_View * im3d,int num)608 static void AFNI_make_surface_widgets( Three_D_View *im3d, int num )
609 {
610 AFNI_surface_widgets *swid ;
611 Widget ww , rc ;
612 XmString xstr ;
613 char str[32] , *eee ;
614 int ii , line_col, box_col , lincol_default , boxcol_default ;
615
616 ENTRY("AFNI_make_surface_widgets") ;
617
618 if( im3d == NULL ) EXRETURN ;
619
620 im3d->vwid->view->swid = swid = myXtNew( AFNI_surface_widgets ) ;
621
622 /* shell to hold it all */
623
624 sprintf(str,"AFNI Surface Controls %s",AFNI_controller_label(im3d)) ;
625
626 swid->wtop = XtVaAppCreateShell(
627 "AFNI" , "AFNI" ,
628 topLevelShellWidgetClass , im3d->dc->display ,
629 XmNallowShellResize , True ,
630 XmNtitle , str ,
631 XmNmappedWhenManaged , False , /* manage manually */
632 XmNdeleteResponse , XmDO_NOTHING , /* deletion handled below */
633 XmNkeyboardFocusPolicy , XmEXPLICIT ,
634 NULL ) ;
635 DC_yokify( swid->wtop , im3d->dc ) ;
636
637 XtVaSetValues( swid->wtop ,
638 XmNmwmDecorations , MWM_DECOR_ALL | MWM_DECOR_MAXIMIZE ,
639 NULL ) ;
640
641 XmAddWMProtocolCallback( /* make "Close" window menu work */
642 swid->wtop ,
643 XmInternAtom( im3d->dc->display , "WM_DELETE_WINDOW" , False ) ,
644 AFNI_surf_done_CB , im3d ) ;
645
646 /* vertical rowcol to hold it all */
647
648 swid->rowcol =
649 XtVaCreateWidget(
650 "dialog" , xmRowColumnWidgetClass , swid->wtop ,
651 XmNpacking , XmPACK_TIGHT ,
652 XmNorientation , XmVERTICAL ,
653 XmNtraversalOn , True ,
654 NULL ) ;
655
656 /* top label to say what session we are dealing with */
657
658 xstr = XmStringCreateLtoR( "xxxxxxxxxAxxxxxxxxxAxxxxxxxxxAxxxxxxxxxAxxxxxxxxxA [x] " ,
659 XmFONTLIST_DEFAULT_TAG ) ;
660 swid->top_lab = XtVaCreateManagedWidget(
661 "dialog" , xmLabelWidgetClass , swid->rowcol ,
662 XmNrecomputeSize , False ,
663 XmNlabelString , xstr ,
664 XmNtraversalOn , True ,
665 NULL ) ;
666 XmStringFree(xstr) ;
667
668 /* Separator from other widgets */
669
670 (void) XtVaCreateManagedWidget( "dialog", xmSeparatorWidgetClass,swid->rowcol,
671 XmNseparatorType , XmSHADOW_ETCHED_IN ,
672 XmNshadowThickness , 5 ,
673 NULL ) ;
674
675 /* horiz rowcol for top controls [23 Feb 2003] */
676
677 rc = XtVaCreateWidget(
678 "dialog" , xmRowColumnWidgetClass , swid->rowcol ,
679 XmNpacking , XmPACK_TIGHT ,
680 XmNorientation , XmHORIZONTAL ,
681 XmNtraversalOn , True ,
682 NULL ) ;
683
684 /* boxsize control [23 Feb 2003] */
685
686 swid->boxsize_av = new_MCW_optmenu( rc , "BoxSize" ,
687 1,19,2,0 ,
688 AFNI_surf_redraw_CB , im3d ,
689 NULL , NULL ) ;
690 MCW_reghint_children( swid->boxsize_av->wrowcol ,
691 "Size of boxes drawn at nodes" ) ;
692 MCW_reghelp_children( swid->boxsize_av->wrowcol ,
693 "This sets the size of the\n"
694 "boxes used to draw the\n"
695 "surface nodes that are\n"
696 "in the current slice volume." ) ;
697
698 /* linewidth control [23 Feb 2003] */
699
700 (void) XtVaCreateManagedWidget( "dialog", xmSeparatorWidgetClass, rc ,
701 XmNorientation , XmVERTICAL ,
702 XmNseparatorType , XmDOUBLE_LINE ,
703 NULL ) ;
704
705 swid->linewidth_av = new_MCW_optmenu( rc , "LineWidth" ,
706 0,19,0,0 ,
707 AFNI_surf_redraw_CB , im3d ,
708 NULL , NULL ) ;
709 MCW_reghint_children( swid->linewidth_av->wrowcol ,
710 "Width of lines drawn for surface" ) ;
711 MCW_reghelp_children( swid->linewidth_av->wrowcol ,
712 "This sets the thickness of\n"
713 "the lines used to draw the\n"
714 "intersection of the surface\n"
715 "with the slice plane." ) ;
716
717
718 /* Done button */
719
720 (void) XtVaCreateManagedWidget( "dialog", xmSeparatorWidgetClass, rc ,
721 XmNorientation , XmVERTICAL ,
722 XmNseparatorType , XmDOUBLE_LINE ,
723 NULL ) ;
724
725 xstr = XmStringCreateLtoR( "Done" , XmFONTLIST_DEFAULT_TAG ) ;
726 swid->done_pb =
727 XtVaCreateManagedWidget(
728 "dialog" , xmPushButtonWidgetClass , rc ,
729 XmNlabelString , xstr ,
730 XmNtraversalOn , True ,
731 NULL ) ;
732 XmStringFree(xstr) ;
733 XtAddCallback( swid->done_pb, XmNactivateCallback, AFNI_surf_done_CB, im3d );
734 MCW_set_widget_bg( swid->done_pb, MCW_hotcolor(swid->done_pb), 0 ) ;
735 MCW_register_hint( swid->done_pb, "Close window" ) ;
736
737 XtManageChild(rc) ;
738
739 /* Separator from other widgets */
740
741 (void) XtVaCreateManagedWidget( "dialog", xmSeparatorWidgetClass,swid->rowcol,
742 XmNseparatorType , XmSHADOW_ETCHED_IN ,
743 XmNshadowThickness , 5 ,
744 NULL ) ;
745
746 /* Now create rows of widgets to control the surfaces */
747
748 swid->nall = num ;
749 swid->nrow = 0 ; /* none are managed at this time */
750
751 swid->surf_rc = (Widget *) XtCalloc( num , sizeof(Widget) ) ;
752 swid->surf_bbox = (MCW_bbox **) XtCalloc( num , sizeof(MCW_bbox *) ) ;
753 swid->surf_node_av = (MCW_arrowval **) XtCalloc( num , sizeof(MCW_arrowval *) ) ;
754 swid->surf_line_av = (MCW_arrowval **) XtCalloc( num , sizeof(MCW_arrowval *) ) ;
755 swid->surf_ledg_av = (MCW_arrowval **) XtCalloc( num , sizeof(MCW_arrowval *) ) ;
756
757 eee = getenv( "AFNI_SUMA_LINECOLOR" ) ;
758 line_col = DC_find_closest_overlay_color( im3d->dc, eee ) ;
759 if( line_col < 0 ) line_col = MIN(6,im3d->dc->ovc->ncol_ov-1) ;
760
761 eee = getenv( "AFNI_SUMA_BOXCOLOR" ) ;
762 box_col = DC_find_closest_overlay_color( im3d->dc, eee ) ;
763 if( box_col < 0 ) box_col = 0 ;
764
765 if( AFNI_noenv("AFNI_SUMA_START_ON") ) line_col = box_col = 0 ;
766
767 lincol_default = line_col ; boxcol_default = box_col ; /* 06 Sep 2006 */
768
769 for( ii=0 ; ii < num ; ii++ ){
770 if( ii < swid_ncol ){ line_col = swid_lincol[ii]; box_col = swid_boxcol[ii]; }
771 else { line_col = lincol_default ; box_col = boxcol_default ; }
772 if( AFNI_noenv("AFNI_SUMA_START_ON") ) line_col = box_col = 0 ;
773 MAKE_SURF_ROW(ii) ;
774 }
775
776 XtManageChild(swid->rowcol) ;
777 XtRealizeWidget(swid->wtop) ; NI_sleep(1) ;
778 EXRETURN ;
779 }
780
781 /*------------------------------------------------------------------------*/
782 /*! Update surface widgets for this controller;
783 that is, set labels, manage/unmanage widget rows, et cetera. */
784
AFNI_update_surface_widgets(Three_D_View * im3d)785 void AFNI_update_surface_widgets( Three_D_View *im3d )
786 {
787 AFNI_surface_widgets *swid ;
788 int num , ii , nwid,nall ;
789 char str[64] , nam[THD_MAX_NAME] , *tnam ;
790
791 ENTRY("AFNI_update_surface_widgets") ;
792
793 if( !IM3D_OPEN(im3d) || im3d->ss_now == NULL ) EXRETURN ; /* bad */
794
795 num = im3d->ss_now->su_num ; /* # of surfaces in current session */
796 swid = im3d->vwid->view->swid ; /* pointer to surface widget struct */
797
798 STATUS("sensitizing") ;
799
800 SENSITIZE( im3d->vwid->view->choose_surf_pb , (RwcBoolean)(num > 0) ) ;
801
802 if( swid == NULL ) EXRETURN ; /* nothing to update */
803
804 /* put session label in top of panel */
805
806 strcpy( nam , im3d->ss_now->sessname ) ;
807 tnam = THD_trailname(nam,SESSTRAIL+1) ;
808 ii = strlen(tnam) ; if( ii > 50 ) tnam += (ii-50) ;
809 sprintf(str ,"%-.50s %s" , tnam, AFNI_controller_label(im3d) ) ;
810 MCW_set_widget_label( swid->top_lab , str ) ;
811
812 /* make more widget rows? (1 per surface is needed) */
813
814 if( swid->nall < num ){
815 char *eee ; int line_col,box_col ;
816
817 swid->surf_rc = (Widget *) XtRealloc( (char *)swid->surf_rc ,num*sizeof(Widget) );
818 swid->surf_bbox = (MCW_bbox **) XtRealloc( (char *)swid->surf_bbox ,num*sizeof(MCW_bbox *) );
819 swid->surf_node_av = (MCW_arrowval **) XtRealloc( (char *)swid->surf_node_av,num*sizeof(MCW_arrowval *) );
820 swid->surf_line_av = (MCW_arrowval **) XtRealloc( (char *)swid->surf_line_av,num*sizeof(MCW_arrowval *) );
821 swid->surf_ledg_av = (MCW_arrowval **) XtRealloc( (char *)swid->surf_line_av,num*sizeof(MCW_arrowval *) );
822
823 eee = getenv( "AFNI_SUMA_LINECOLOR" ) ;
824 line_col = DC_find_closest_overlay_color( im3d->dc, eee ) ;
825 if( line_col < 0 ) line_col = MIN(6,im3d->dc->ovc->ncol_ov-1) ;
826
827 eee = getenv( "AFNI_SUMA_BOXCOLOR" ) ;
828 box_col = DC_find_closest_overlay_color( im3d->dc, eee ) ;
829 if( box_col < 0 ) box_col = 0 ;
830
831 for( ii=swid->nall ; ii < num ; ii++ ){
832 MAKE_SURF_ROW(ii) ;
833 }
834 swid->nall = num ;
835 }
836
837 /* map or unmap widget rows? (1 per surface is needed) */
838
839 if( swid->nrow < num ){
840 for( ii=swid->nrow ; ii < num ; ii++ )
841 XtManageChild( swid->surf_rc[ii] ) ;
842 } else if( swid->nrow > num ){
843 for( ii=num ; ii < swid->nrow ; ii++ )
844 XtUnmanageChild( swid->surf_rc[ii] ) ;
845 }
846 swid->nrow = num ; /* # of managed rows */
847
848 /* change labels for each row */
849
850 for( ii=0 ; ii < num ; ii++ ){
851 sprintf(str,"%-14.14s: ",im3d->ss_now->su_surf[ii]->label) ;
852 MCW_set_widget_label( swid->surf_bbox[ii]->wbut[0] , str ) ;
853
854 sprintf(str,"%d Nodes; %d Triangles", /* 20 Aug 2002: */
855 im3d->ss_now->su_surf[ii]->num_ixyz , /* put a hint */
856 im3d->ss_now->su_surf[ii]->num_ijk ) ; /* on each label */
857 MCW_register_hint( swid->surf_bbox[ii]->wbut[0] , str ) ;
858 }
859
860 EXRETURN ;
861 }
862
863 /*------------------------------------------------------------------------*/
864 /*! Update all surface widgets everywhere that touch this session. */
865
AFNI_update_all_surface_widgets(THD_session * sess)866 void AFNI_update_all_surface_widgets( THD_session *sess )
867 {
868 int ii ;
869 Three_D_View *im3d ;
870 ENTRY("AFNI_update_all_surface_widgets") ;
871 for( ii=0 ; ii < MAX_CONTROLLERS ; ii++ ){
872 im3d = GLOBAL_library.controllers[ii] ;
873 if( IM3D_OPEN(im3d) && im3d->ss_now == sess )
874 AFNI_update_surface_widgets( im3d ) ;
875 }
876 EXRETURN ;
877 }
878
879 /*------------------------------------------------------------------------*/
880 /*! Callback for Switch Surface pushbutton [19 Aug 2002].
881 --------------------------------------------------------------------------*/
882
AFNI_choose_surface_CB(Widget w,XtPointer cd,XtPointer cbs)883 void AFNI_choose_surface_CB( Widget w , XtPointer cd, XtPointer cbs )
884 {
885 Three_D_View *im3d = (Three_D_View *) cd ;
886 AFNI_surface_widgets *swid ;
887 int num , ii , nwid,nall ;
888
889 ENTRY("AFNI_choose_surface_CB") ;
890
891 if( !IM3D_OPEN(im3d) || im3d->ss_now == NULL ) EXRETURN ; /* bad */
892
893 num = im3d->ss_now->su_num ;
894 swid = im3d->vwid->view->swid ;
895
896 /* no surfaces ==> nothing to do */
897
898 if( num == 0 ) EXRETURN ;
899
900 /* make widgets? */
901
902 if( swid == NULL ){
903 AFNI_make_surface_widgets(im3d,num) ;
904 swid = im3d->vwid->view->swid ;
905 }
906
907 /* make control panel visible, if it isn't already */
908
909 XtMapWidget( swid->wtop ) ;
910 XRaiseWindow( XtDisplay(swid->wtop), XtWindow(swid->wtop) ) ;
911
912 /* put proper labels on widgets, etc. */
913
914 AFNI_update_surface_widgets(im3d) ;
915
916 /* Mac OS X mangles up the widgets on first display,
917 so unmanage and remanage them -- this solves that problem */
918
919 WAIT_for_window( swid->rowcol ) ;
920 XtUnmanageChild( swid->rowcol ) ; NI_sleep(1) ;
921 WAIT_for_window( swid->rowcol ) ;
922 XtManageChild ( swid->rowcol ) ; NI_sleep(1) ;
923
924 /* wait for user to press some button */
925
926 EXRETURN ;
927 }
928
929 /*---------------------------------------------------------------------------*/
930 /*! Callback for "Done" button for surface control panel. */
931
AFNI_surf_done_CB(Widget w,XtPointer cd,XtPointer cbs)932 static void AFNI_surf_done_CB( Widget w , XtPointer cd, XtPointer cbs )
933 {
934 Three_D_View *im3d = (Three_D_View *) cd ;
935 AFNI_surface_widgets *swid ;
936
937 ENTRY("AFNI_surf_done_CB") ;
938
939 if( !IM3D_OPEN(im3d) ) EXRETURN ;
940 swid = im3d->vwid->view->swid ;
941 if( swid != NULL ) XtUnmapWidget( swid->wtop ) ;
942 EXRETURN ;
943 }
944
945 /*---------------------------------------------------------------------------*/
946 /* Callback for press of an arrowval on the surface controls.
947 All this does is to redraw the images, since that is where
948 the actual info will be grabbed from the swid arrowvals. */
949
AFNI_surf_redraw_CB(MCW_arrowval * av,XtPointer cd)950 static void AFNI_surf_redraw_CB( MCW_arrowval *av , XtPointer cd )
951 {
952 Three_D_View *im3d = (Three_D_View *) cd ;
953 AFNI_surface_widgets *swid ;
954
955 ENTRY("AFNI_surf_redraw_CB") ;
956
957 if( im3d == NULL ) EXRETURN ;
958 swid = im3d->vwid->view->swid ;
959 if( swid == NULL ) EXRETURN ; /* should be impossible */
960
961 if( !IM3D_OPEN(im3d) ){ /* bad user, bad bad bad! */
962 XtUnmapWidget( swid->wtop ) ;
963 EXRETURN ;
964 }
965
966 AFNI_set_viewpoint( im3d , -1,-1,-1 , REDISPLAY_OVERLAY ) ;
967
968 EXRETURN ;
969 }
970
971 /*---------------------------------------------------------------------------*/
972 /*! Callback for press of a toggle button on the surface controls.
973 All this does is to force a redraw of the images. */
974
AFNI_surf_bbox_CB(Widget w,XtPointer cd,XtPointer qd)975 static void AFNI_surf_bbox_CB( Widget w , XtPointer cd , XtPointer qd )
976 {
977 Three_D_View *im3d = (Three_D_View *) cd ;
978 AFNI_surface_widgets *swid ;
979
980 ENTRY("AFNI_surf_bbox_CB") ;
981
982 if( im3d == NULL ) EXRETURN ;
983 swid = im3d->vwid->view->swid ;
984 if( swid == NULL ) EXRETURN ; /* should be impossible */
985
986 if( !IM3D_OPEN(im3d) ){ /* bad user! */
987 XtUnmapWidget( swid->wtop ) ;
988 EXRETURN ;
989 }
990
991 AFNI_set_viewpoint( im3d , -1,-1,-1 , REDISPLAY_OVERLAY ) ;
992
993 EXRETURN ;
994 }
995