function ds_plumb = cosmo_fmri_deoblique(ds)
% de-oblique a dataset
%
% Input:
% ds fmri dataset struct
%
% Output:
%
% Example:
% % start with a simple dataset
% x=cosmo_synthetic_dataset('size','huge','ntargets',1,'nchunks',1);
% % make dataset oblique (manually)
% x.a.vol.mat(1,1)=.8;
% x.a.vol.mat(2,1)=.6;
% y=cosmo_fmri_deoblique(x);
% cosmo_disp(x.a.vol)
% %|| .mat
% %|| [ 0.8 0 0 -3
% %|| 0.6 2 0 -3
% %|| 0 0 2 -3
% %|| 0 0 0 1 ]
% %|| .dim
% %|| [ 20 17 19 ]
% %|| .xform
% %|| 'scanner_anat'
% cosmo_disp(y.a.vol)
% %|| .mat
% %|| [ 1 0 0 -3.2
% %|| 0 2 0 -2.4
% %|| 0 0 2 -3
% %|| 0 0 0 1 ]
% %|| .dim
% %|| [ 20 17 19 ]
% %|| .xform
% %|| 'scanner_anat'
% %
% % other attributes are unchanged:
% assert(isequal({x.samples x.fa x.sa x.a.fdim},...
% {y.samples y.fa y.sa y.a.fdim}));
% %
% % a plump dataset does not change after de-obliqueing
% z=cosmo_fmri_deoblique(y);
% isequal(y,z)
% %|| true
%
% Notes:
% - Using this function changes the location of the voxels in
% world-space, that is world coordinates (x, y, z).
% - This function is intended for AFNI and BrainVoyager, as these
% programs prefer 'plump' (non-oblique) volumes.
% - When using this function, it is recommended to inspect the result
% visually.
%
% # For CoSMoMVPA's copyright information and license terms, #
% # see the COPYING file distributed with CoSMoMVPA. #
% get canonical orthogonal matrix
[unused, rot_ortho] = cosmo_fmri_orientation(ds);
mat = ds.a.vol.mat;
% convert base1 -> base0
mat(1:3, 4) = mat(1:3, 4) + mat(1:3, 1:3) * [1 1 1]';
% use pixel dimension to set non-zero elements
mat_ortho = mat;
pixdim = sqrt(sum(mat(1:3, 1:3).^2, 1));
mat_ortho(1:3, 1:3) = bsxfun(@times, rot_ortho(1:3, 1:3), pixdim);
% convert base0 -> base1
mat_ortho(1:3, 4) = mat_ortho(1:3, 1:3) * -[1 1 1]' + mat_ortho(1:3, 4);
% ensure single element in rotation part
assert(all(sum(mat_ortho(:, 1:3) ~= 0, 1) == 1));
assert(all(sum(mat_ortho(1:3, 1:3) ~= 0, 2) == 1));
ds_plumb = ds;
ds_plumb.a.vol.mat = mat_ortho;