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