function volume_visualization_gui(volume)
%VOLUME_VISUALIZATION_GUI   Interactive volume visualization
%
% VOLUME_VISUALIZATION_GUI(VOLUME)
%
% VOLUME, input volume, may be uint8 or 0-to-1 double
% Keyboard controls:
%   leftarrow and rightarrow - move x slice
%   pageup and pagedown - move y slice
%   downarrow and uparrow - move z slice
%   space - change coloring scheme
%
% Author: vand@dtu.dk, 2015

if nargin<1
    volume = load('fluidtemp.mat','temp');
    volume = volume.temp;
end

% GUI LAYOUT
fmar = [0.2 0.2]; % discance from screen edge to figure (x and y)
amar = [0.05 0.1]; % distance from figure edge to axes, relative to figure
menw = 0.045; % width of the menu column
div = 0.005; % distance from the axes to menu

adim = 0.5*(1-3*amar-2*[menw+div 0]); % axes dimensions (all free space)
menh = adim(2)/7; % height of the menu buttoms

% bottom left point of the three axes (x,y,z)
axepos = [2*amar+adim+[menw+div,0];...
    2*amar(1)+adim(1)+menw+div,amar(2);...
    amar];

% bottom left point of the three menu pannels
menpos = [2*(amar(1)+adim(1)+div)+menw,2*amar(2)+adim(2);...
    2*(amar(1)+adim(1)+div)+menw,amar(2);...
    amar+[adim(1)+div,0]];

%%%%%%%%%% INITIALIZATION %%%%%%%%%%
dim = size(volume); % dimensions
clim = [min(volume(:)),max(volume(:))]; % color limits
POINT  = round(0.5*(dim+1)); % initialized in the ceter of the volume
COLORS = set_colors(false); % initial colors
[box,FRAMES] = make_patches(dim); % initial box, frames and axes
xyz = 'xyz';
linewidth = 2;

fig = figure('Units','Normalized','Position',[fmar,1-2*fmar],...
    'KeyPressFcn',@key_press);
menustr = {'end','+10','+1','mid','-1','-10','1'};

xyz_axes = cell(3,1);
for i=1:3 % creating x,y and z axes
    xyz_axes{i} = axes('Units','Normalized','Position',[axepos(i,:),adim]);
    show_XYZ(i), axis image xy off, colormap gray, hold on
    for j=1:7
        uicontrol('Style','pushbutton','String',menustr{j},...
            'UserData',[i,j],'Units','Normalized',...
            'Position',[menpos(i,:)+[0,(j-1)*menh],menw,menh],...
            'Callback',@button_click);
    end
end
frames_axes = axes('Units','Normalized','Projection','perspective',...
    'Position',[amar(1),2*amar(2)+adim(2),adim]);
show_frames, axis vis3d equal off, view(20,15)

set(zoom(fig),'ActionPostCallback',@adjust_limits)
set(pan(fig),'ActionPostCallback',@adjust_limits)

%%%%%%%%%% CALLBACKS AND HELPING FUNCTIONS %%%%%%%%%%
    function key_press(~,object)
        % response to pressing a key
        if any(strcmp(object.Modifier,'shift'))
            minus_move = 7;
            plus_move = 1;
        else
            minus_move = 5;
            plus_move = 3;
        end
        switch object.Key
            case 'leftarrow'
                move_slice(1,minus_move)
            case 'rightarrow'
                move_slice(1,plus_move)
            case 'pageup'
                move_slice(2,minus_move)
            case 'pagedown'
                move_slice(2,plus_move)
            case 'downarrow'
                move_slice(3,minus_move)
            case 'uparrow'
                move_slice(3,plus_move)
            case 'space'
                COLORS = set_colors(~COLORS.color_axes);
                for k=1:3
                    show_XYZ(k);
                end
                show_frames
        end
    end

    function button_click(source,~)
        % response to clicking a button
        ij = get(source,'UserData');
        move_slice(ij(1),ij(2));
    end

    function adjust_limits(~,~)
        % response to zooming and panning
        cw = [1,2,4,3];
        ccw = [1,3,2,4];
        FRAMES{1}.vertices(ccw,2) = repmat(get(xyz_axes{1},'XLim'),[1,2]);
        FRAMES{1}.vertices(cw,3) = repmat(get(xyz_axes{1},'YLim'),[1,2]);
        FRAMES{2}.vertices(cw,1) = repmat(get(xyz_axes{2},'XLim'),[1,2]);
        FRAMES{2}.vertices(ccw,3) = repmat(get(xyz_axes{2},'YLim'),[1,2]);
        FRAMES{3}.vertices(ccw,1) = repmat(get(xyz_axes{3},'XLim'),[1,2]);
        FRAMES{3}.vertices(cw,2) = repmat(get(xyz_axes{3},'YLim'),[1,2]);
        for k=1:3 % showing all slices, instead of figuring out which changed
            show_XYZ(k);
        end
        show_frames % showing box and frames
    end

    function move_slice(k,d)
        % moving a slice k (1,2,3 for x,y,z)
        % to a place given by d (1:7 for end,+10,+1,mid,-1,-10,1)
        switch d
            case 1
                POINT(k) = dim(k);
            case 2
                POINT(k) = min(POINT(k)+10,dim(k));
            case 3
                POINT(k) = min(POINT(k)+1,dim(k));
            case 4
                POINT(k) = round(0.5*(dim(k)+1));
            case 5
                POINT(k) = max(POINT(k)-1,1);
            case 6
                POINT(k) = max(POINT(k)-10,1);
            case 7
                POINT(k) = 1;
        end
        FRAMES{k}.vertices(:,k) = POINT(k); % updating frame
        show_XYZ(k); % showing slice
        show_frames % showing box and frames
    end

    function show_XYZ(k)
        % show a current x, y or z slice
        axes(xyz_axes{k}), cla
        switch k
            case 1
                imagesc(permute(volume(POINT(k),:,:),[3,2,1]),clim)
            case 2
                imagesc(permute(volume(:,POINT(k),:),[3,1,2]),clim);
            case 3
                imagesc(permute(volume(:,:,POINT(k)),[2,1,3]),clim);
        end
        patch('Faces',1:4,'Vertices',...
            FRAMES{k}.vertices(:,setdiff(1:3,k)),...
            'FaceColor','none','EdgeColor',COLORS.edge_color{k},...
            'FaceVertexCData',COLORS.cdata{k},'LineWidth',linewidth)
        title([xyz(k),'=',num2str(POINT(k))])
    end

    function show_frames
        % show current frames
        axes(frames_axes), cla
        patch(box,'FaceColor','none','EdgeColor',[0.3,0.3,0.3]);
        for k=1:3
            patch(FRAMES{k},...
                'FaceColor','none','EdgeColor',COLORS.edge_color{k},...
                'FaceVertexCData',COLORS.cdata{k},'LineWidth',linewidth);
        end
    end

    function [box,patch_xyz] = make_patches(dim)
        % initialization of the box and the frames
        box.vertices = [0 0 0; 0 0 1; 0 1 0; 0 1 1; 1 0 0; 1 0 1;...
            1 1 0; 1 1 1]*diag(dim)+0.5;
        box.faces = [1 2 4 3; 3 4 8 7; 1 3 7 5; 2 6 8 4; 1 5 6 2; 5 7 8 6];
        patch_xyz = cell(3,1);
        for l=1:3
            patch_xyz{l}.vertices = box.vertices(box.faces(l,:),:);
            patch_xyz{l}.faces = [1 2 3 4];
            patch_xyz{l}.vertices(:,l) = (dim(l)+1)/2;
        end
        %rgb_axes.vertices = box.vertices([1,5,3,2],:);
        %rgb_axes.faces = [2,1;3,1;4,1];
        %rgb_axes.facevertexcdata = [0.3,0.3,0.3;eye(3)];
    end

    function colors = set_colors(color_flag)
        % changing between two color options
        colors.color_axes = color_flag;
        if color_flag % four colors per frame
            col = repmat([0;0;0.5;0.5],[1,3]);
            colors.cdata = {col,col,col};
            for k=1:3
                colors.cdata{k}(:,k) = [1;0.5;0.5;1];
                colors.edge_color{k} = 'interp';
            end
        else % one color per frame
            col = [0,0,0];
            colors.edge_color = {col,col,col};
            for k=1:3
                colors.edge_color{k}(k) = 1;
                colors.cdata{k} = [];
            end
        end
    end

end