1 #include "mrilib.h"
2 #include "cs.h"
3 
4 /*----------------------------------------------------------------------
5    Begin coordinate transformation functions
6    [moved from thd_ttatlas_query.c on 13 Jul 2020 - RWC]
7 ------------------------------------------------------------------------*/
8 
9 /*------------------------------------------------------------------------
10    Forward transform a vector following a warp
11    Don't mess with this function, many programs use it. ZSS Feb 06
12 --------------------------------------------------------------------------*/
13 
AFNI_forward_warp_vector(THD_warp * warp,THD_fvec3 old_fv)14 THD_fvec3 AFNI_forward_warp_vector( THD_warp * warp , THD_fvec3 old_fv )
15 {
16    THD_fvec3 new_fv ;
17 
18    if( warp == NULL ) return old_fv ;
19 
20    switch( warp->type ){
21 
22       default: new_fv = old_fv ; break ;
23 
24       case WARP_TALAIRACH_12_TYPE:{
25          THD_linear_mapping map ;
26          int iw ;
27 
28          /* forward transform each possible case,
29             and test if result is in bot..top of defined map */
30 
31          for( iw=0 ; iw < 12 ; iw++ ){
32             map    = warp->tal_12.warp[iw] ;
33             new_fv = MATVEC_SUB(map.mfor,old_fv,map.bvec) ;
34 
35             if( new_fv.xyz[0] >= map.bot.xyz[0] &&
36                 new_fv.xyz[1] >= map.bot.xyz[1] &&
37                 new_fv.xyz[2] >= map.bot.xyz[2] &&
38                 new_fv.xyz[0] <= map.top.xyz[0] &&
39                 new_fv.xyz[1] <= map.top.xyz[1] &&
40                 new_fv.xyz[2] <= map.top.xyz[2]   ) break ;  /* leave loop */
41          }
42       }
43       break ;
44 
45       case WARP_AFFINE_TYPE:{
46          THD_linear_mapping map = warp->rig_bod.warp ;
47          new_fv = MATVEC_SUB(map.mfor,old_fv,map.bvec) ;
48       }
49       break ;
50 
51    }
52    return new_fv ;
53 }
54 
55 /*------------------------------------------------------------------------
56    Backward transform a vector following a warp
57    Don't mess with this function, many programs use it. ZSS Feb 06
58 --------------------------------------------------------------------------*/
AFNI_backward_warp_vector(THD_warp * warp,THD_fvec3 old_fv)59 THD_fvec3 AFNI_backward_warp_vector( THD_warp * warp , THD_fvec3 old_fv )
60 {
61    THD_fvec3 new_fv ;
62 
63    if( warp == NULL ) return old_fv ;
64 
65    switch( warp->type ){
66 
67       default: new_fv = old_fv ; break ;
68 
69       case WARP_TALAIRACH_12_TYPE:{
70          THD_linear_mapping map ;
71          int iw ;
72 
73          /* test if input is in bot..top of each defined map */
74 
75          for( iw=0 ; iw < 12 ; iw++ ){
76             map = warp->tal_12.warp[iw] ;
77 
78             if( old_fv.xyz[0] >= map.bot.xyz[0] &&
79                 old_fv.xyz[1] >= map.bot.xyz[1] &&
80                 old_fv.xyz[2] >= map.bot.xyz[2] &&
81                 old_fv.xyz[0] <= map.top.xyz[0] &&
82                 old_fv.xyz[1] <= map.top.xyz[1] &&
83                 old_fv.xyz[2] <= map.top.xyz[2]   ) break ;  /* leave loop */
84          }
85          new_fv = MATVEC_SUB(map.mbac,old_fv,map.svec) ;
86       }
87       break ;
88 
89       case WARP_AFFINE_TYPE:{
90          THD_linear_mapping map = warp->rig_bod.warp ;
91          new_fv = MATVEC_SUB(map.mbac,old_fv,map.svec) ;
92       }
93       break ;
94 
95    }
96    return new_fv ;
97 }
98 
99 /*!
100    Coordinate transformation between N27 MNI
101    and AFNI's TLRC. Transform was obtained by manually AFNI TLRCing
102    the N27 dset supplied in Eickhoff & Zilles' v12 dbase before
103    the volume itself was placed in MNI Anatomical space as was done in v13.
104    Input and output are in RAI
105 */
THD_mni__tta_N27(THD_fvec3 mv,int dir)106 THD_fvec3 THD_mni__tta_N27( THD_fvec3 mv, int dir )
107 {
108    static THD_talairach_12_warp *ww=NULL;
109    float tx,ty,tz ;
110    int iw, ioff;
111    THD_fvec3 tv2;
112 
113    tx = ty = tz = -9000.0;
114 /*   LOAD_FVEC3( tv , tx,ty,tz ) ;*/
115    LOAD_FVEC3( tv2 , tx,ty,tz ) ;
116 
117    /* Meth 2, xform in code, more fool proof*/
118    if (!ww) {
119       /* load the transform */
120       ww = myRwcNew( THD_talairach_12_warp ) ;
121       ww->type = WARP_TALAIRACH_12_TYPE;
122       ww->resam_type = 0;
123       for (iw=0; iw < 12; ++iw) {
124          ww->warp[iw].type = MAPPING_LINEAR_TYPE ;
125 
126          ioff = iw * MAPPING_LINEAR_FSIZE ;
127          COPY_INTO_STRUCT( ww->warp[iw] ,
128                            MAPPING_LINEAR_FSTART ,
129                            float ,
130                            &(MNI_N27_to_AFNI_TLRC_WRP_VEC[ioff]) ,
131                            MAPPING_LINEAR_FSIZE ) ;
132 
133       }
134    }
135 
136    if (!ww) {
137       ERROR_message("Failed to form built-in warp.");
138       return tv2;
139    } else {
140       if (dir > 0) tv2 = AFNI_forward_warp_vector((THD_warp *)ww, mv);
141       else tv2 = AFNI_backward_warp_vector((THD_warp *)ww, mv);
142    }
143 
144    return tv2 ;
145 }
146 
THD_mni_to_tta_N27(THD_fvec3 mv)147 THD_fvec3 THD_mni_to_tta_N27( THD_fvec3 mv )
148 {
149    return (THD_mni__tta_N27( mv , 1));
150 }
151 
THD_tta_to_mni_N27(THD_fvec3 mv)152 THD_fvec3 THD_tta_to_mni_N27( THD_fvec3 mv )
153 {
154    return (THD_mni__tta_N27( mv , -1));
155 }
156 
THD_mnia_to_tta_N27(THD_fvec3 mv)157 THD_fvec3 THD_mnia_to_tta_N27( THD_fvec3 mv )
158 {
159    THD_fvec3 mva;
160    /*go from MNI Anat to MNI (remember, shift is in RAI space, not LPI. See also script @Shift_volume)*/
161    mva.xyz[0] = mv.xyz[0] + 0.0 ;
162    mva.xyz[1] = mv.xyz[1] - 4.0 ;
163    mva.xyz[2] = mv.xyz[2] - 5.0 ;
164 
165    return (THD_mni__tta_N27( mva , 1));
166 }
167 
THD_tta_to_mnia_N27(THD_fvec3 mv)168 THD_fvec3 THD_tta_to_mnia_N27( THD_fvec3 mv )
169 {
170    THD_fvec3 mva;
171 
172    mva = THD_mni__tta_N27( mv , -1);
173 
174    /*go from MNI to MNI Anat (remember, shift is in RAI space, not LPI. See also script @Shift_volume)*/
175    mva.xyz[0] = mva.xyz[0] + 0.0 ;
176    mva.xyz[1] = mva.xyz[1] + 4.0 ;
177    mva.xyz[2] = mva.xyz[2] + 5.0 ;
178 
179    return (mva);
180 }
181