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