## Copyright (C) 2017 Carnë Draug <carandraug@octave.org>
## Copyright (C) 2015 Motherboard <cantfind@gmail.com>
##
## This program is free software: you can redistribute it and/or modify
## it under the terms of the GNU General Public License as published by
## the Free Software Foundation, either version 3 of the License, or
## (at your option) any later version.
##
## This program is distributed in the hope that it will be useful,
## but WITHOUT ANY WARRANTY; without even the implied warranty of
## MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
## GNU General Public License for more details.
##
## You should have received a copy of the GNU General Public License
## along with this program.  If not, see <http://www.gnu.org/licenses/>.

## -*- texinfo -*-
## affine3d takes a transpose of the affine matrix as described in
## standard literature it performs the transformation as follows:
## v = (u*T)(1:3)
## where u = [x y z 1] and T = [a b c 0; d e f 0; g h i 0; j k l 1]
## [a b c; d e f; g h i] is a transposed rotation\shear matrix,
## [j k l] is the translation vector, where j = dx, k = dy, l = dz.

classdef affine3d < affine
  methods
    function this = affine3d (T = eye (4))
      if (nargin != 1)
        print_usage ()
      endif
      this@affine (T);
    endfunction

    ## given a bounding cube corner coordinates in xlims, ylims and
    ## zlims (top left front, right bottom back) - return the new
    ## bounding cube after transformation.
    function [limitsX, limitsY, limitsZ] = outputLimits (this, xlims, ylims,
                                                         zlims)
      xlims2 = [xlims(:); xlims(:); xlims(:); xlims(:)];
      ylims2 = [ylims(:); ylims(end:-1:1)(:); ylims(:); ylims(end:-1:1)(:)];
      zlims2 = [zlims(:); zlims(:); zlims(end:-1:1)(:); zlims(end:-1:1)(:)];
      temp = [xlims2 ylims2 zlims2 ones(8,1)];
      temp = temp*this.T;
      limitsX = [min(temp(1:8,1)), max(temp(1:8,1))];
      limitsY = [min(temp(1:8,2)), max(temp(1:8,2))];
      limitsZ = [min(temp(1:8,3)), max(temp(1:8,3))];
    endfunction
  endmethods
endclassdef

%!test
%! Sx = 1.2;
%! Sy = 1.6;
%! Sz = 2.4;
%! A = [Sx 0 0 0; 0 Sy 0 0; 0 0 Sz 0; 0 0 0 1];
%! tform = affine3d (A);
%! [X, Y, Z] = transformPointsForward (tform, 5, 10, 3);
%! assert ([X Y Z], [6 16 7.2], e^-4)
%! [U, V, W] = transformPointsInverse (tform, X, Y, Z);
%! assert ([U V W], [5 10 3], e^-10)
%! assert (! isRigid (tform))
%! assert (! isTranslation (tform))
%! assert (! isSimilarity (tform))

%!test
%! A = [3 1 2 0; 4 5 8 0; 6 2 1 0; 0 0 0 1];
%! tform = affine3d (A);
%! [X, Y, Z] = transformPointsForward (tform, 2, 3, 5);
%! assert (X, 48, e^-10)
%! assert (Y, 27, e^-10)
%! assert (Z, 33, e^-10)
%! [U, V, W] = transformPointsInverse (tform, X, Y, Z);
%! assert (U, 2, e^-10)
%! assert (V, 3, e^-10)
%! assert (W, 5, e^-10)
%! assert (! isRigid (tform))
%! assert (! isTranslation (tform))
%! assert (! isSimilarity (tform))

%!test
%! A = [1 0 0 0; 0 1 0 0; 0 0 1 0; 5 10 1 1];
%! tform = affine3d (A);
%! X = transformPointsForward (tform, [1 2 3; 4 5 6; 7 8 9]);
%! assert (round (X), [6, 12, 4; 9, 15, 7; 12, 18, 10])
%! U = transformPointsInverse (tform, X);
%! assert (round (U), [1 2 3; 4 5 6; 7 8 9])
%! assert (isRigid (tform))
%! assert (isTranslation (tform))
%! assert (isSimilarity (tform))

%!test
%! Sx = 1.2;
%! Sy = 1.6;
%! Sz = 2.4;
%! A = [Sx 0 0 0; 0 Sy 0 0; 0 0 Sz 0; 0 0 0 1];
%! tform = affine3d (A);
%! [xlim, ylim, zlim] = outputLimits (tform, [1 128], [1 128], [1 27]);
%! assert (xlim, [ 1.2000  153.6000],e^-4)
%! assert (ylim, [1.6000  204.8000], e^-4)
%! assert (zlim, [2.4000   64.8000], e^-4)

%!xtest
%! tform = affine3d
%! assert (tform.T, eye (4))
%! assert (tform.Dimensionality, 3)