function ModelViewer(varargin)
% Dr. A. I. Hanna (2005) CMP, UEA, 2005.
error(nargchk(0,inf,nargin));
ad.options.pdm = '';
ad.options.sfam = '';
ad.options.PMdirectory = '';
ad.options.ImageDirectory = '';
ad.options.savePDM = 0;
ad.pdm = [];
ad.edges = [];
ad.options.ref_image = [];
ad.pmpts = [];
ad.indices =[];
if isProject3D(pwd)
    ad.dim = 3;
else
    ad.dim = 2;
end
if mod(length(varargin),2) ~= 0
    % input args have not com in pairs, woe is me
    error('Arguments to ModelViewer must come param/value in pairs.')
end
for i=1:2:length(varargin)
    switch lower(varargin{i})
        case 'pdmfile'
            ad.options.pdm = varargin{i+1};
        case 'sfamfile'
            ad.options.sfam = varargin{i+1};
        case 'pmdirectory'
            ad.options.PMdirectory = varargin{i+1};
        case 'imdirectory'
            ad.options.ImageDirectory = varargin{i+1};
        case 'edges'
            ad.edges = varargin{i+1};
        case 'details'
            ad.details = varargin{i+1};
        case 'indices'
            ad.indices = varargin{i+1};
        case 'facets'
            ad.Facets = varargin{i+1};
        otherwise
            error(['Unknown parameter name passed to ModelViewer.  Name was ' varargin{i}])
    end
end
if isempty(ad.options.pdm)
    ad = manualInitialization(ad); 
end
% Open, move, and get the handles from the figure file.
fig = openfig(mfilename, 'reuse');
customtoolbar(fig);
% Move the gui and then show it, rather than have it jump all over the
% place.
movegui(fig, 'center');
set(fig, 'visible', 'on');
handles = guihandles(fig);
set(handles.modelPanel, 'BackgroundColor',  [0.8314, 0.8157, 0.7843]);
handles = SetGUILevel(handles, getGUILevelInfo);

[modelDirec, pdmfile, ext, vers] = fileparts(ad.options.pdm);
if findstr(modelDirec, pwd)==1
    modelDirec = modelDirec(length(pwd)+1:end);
end

set(handles.modelNameTxt, 'String', modelDirec);
set(fig, 'Color', get(handles.modelPanel, 'BackgroundColor'))
handles.app_modes_val = [];
handles.shape_modes_val = [];

% Set all the callback functions
set(handles.XY_Z_up,'callback',{@doSelectView_XY_Z_up});
set(handles.View_1,'callback',{@doSelectView_1});
set(handles.View_2,'callback',{@doSelectView_2});
set(handles.SetView_1,'callback',{@doSetView_1});
set(handles.SetView_2,'callback',{@doSetView_2});
set(handles.shape_pc_slider, 'callback', {@doUpdateShapeMode});
set(handles.app_pc_slider, 'callback', {@doUpdateAppMode});

% The shape controls
set(handles.walk_curr_shape_pc_btn, 'callback', {@doWalkCurrentShapePC});
set(handles.walk_all_shape_pc_btn, 'callback', {@doWalkAllShapePC});
set(handles.reset_shape_btn, 'callback', {@doResetShape});
set(handles.reset_all_shape_btn, 'callback', {@doResetAllShape});
set(handles.shapeslider, 'callback', {@doSlideModes, handles.shapelevels});
set(handles.shapelevels, 'ButtonDownFcn', {@doSelectMode, handles.shapeslider, 'shape'});

% The appearance controls
set(handles.walk_curr_app_pc_btn, 'callback', {@doWalkCurrentAppPC});
set(handles.walk_all_app_pc_btn, 'callback', {@doWalkAllAppPC});
set(handles.reset_app_btn, 'callback', {@doResetApp});
set(handles.reset_all_app_btn, 'callback', {@doResetAllApp});
set(handles.appslider, 'callback', {@doSlideModes, handles.applevels});
set(handles.applevels, 'ButtonDownFcn', {@doSelectMode, handles.appslider, 'app'});

% Handles to the rest of the GUI
set([handles.orient_ij_rad, handles.orient_xy_rad], 'callback', {@doUpdateDisplay});
set([handles.edges_chk, handles.show_landmarks_chk, handles.show_app_model_chk, ...
    handles.tps_chk, handles.Surface_chk], 'callback', {@doUpdateDisplay});
set([handles.Surface_chk,handles.show_app_model_chk],'Value',0);
if ~isfield(ad,'Facets')
    set([handles.Surface_chk],'String','No facets xls file','Enable','off');
end
set(handles.save_image_btn, 'callback', {@doSaveImage});
set(handles.load_pm_file_btn, 'callback', {@doLoadPointModelFile});
set(handles.calc_weights_btn, 'callback', {@doCalcWeights});
set(handles.import_mean_shape_btn, 'callback', {@doImportMeanShape});
set(handles.add_rand_axis_btn, 'callback', {@doAddRandomShapeAxis});
set(handles.reload_model_btn, 'callback', {@doReloadModel});
set([handles.shape_range, handles.app_range], 'callback', {@doUpdateWalkerLimits});
set([handles.cart_axes_chk], 'callback', {@doChangeAxes});
set(handles.offsetchk, 'callback', {@doToggleOffset});


% Handles to the menus
set(handles.importshapepcmenu, 'callback', {@doImportShapePCMenu});
set(handles.exportshapepcmenu, 'callback', {@doExportShapePCMenu});
set(handles.flipshapepcmenuitem, 'callback', {@doFlipShapePC});
set(handles.importrefimage, 'callback', {@doImportRefImage});
set(handles.exportpmmenu, 'callback', {@doExportPointModel});
set(handles.MatlabFigureofWholeInterface, 'callback', {@doScreenShot});
set(handles.SnapshotModelOnly, 'callback', {@doScreenShot});
set(handles.SnapshotWholeInterface, 'callback', {@doScreenShot});
set(handles.MakeMovie, 'callback', {@doMakeMovie});

cameratoolbar(handles.figure1,'NoReset');
% Handles to the 3D plot and control routines (J. Andrew Bangham 
% and Richard Kennaway
m=get(0,'MonitorPositions');
if 1 %size(m,1)==2
%     set(handles.Zero3D, 'callback', {@Zero3D},'Enable','on');
    set(handles.View3D, 'callback', {@View3D},'Enable','on');
    set(handles.Rotate3D, 'callback', {@Rotate3D},'Enable','on');
    set(handles.Rock3D, 'callback', {@Rock3D},'Enable','on');
else
    set(handles.Zero3D, 'callback', {@Zero3D},'Enable','off');
    set(handles.View3D, 'callback', {@View3D},'Enable','off');
    set(handles.Rotate3D, 'callback', {@Rotate3D},'Enable','off');
    set(handles.Rock3D, 'callback', {@Rock3D},'Enable','off');
end
% Initialize the application data structure
ad.figMain = fig;
ad.handles = handles;
ad.app_levels_plot_handle = [];
ad.currentShapeMode = [];
ad.currentAppMode = [];

ad.data.edgehandle = [];
ad.data.shape_pts_handle = [];
ad.data.appearancehandle = [];
ad.data.surface_pts_handle=[];

ad.currentImage = [];
[ad.segmentPoint, ad.offsets] = isAugmentedProject;
ad.dy= 15;
ad.shapewalkerlim = 3;
ad.appwalkerlim = 3;

ad.View3DFlag=false;
ad.moviename='';
ad = loadModels(ad);

% Begin change by js, 080114
% Begin original code
 
% No replacement in this case 
 
% End original code
% Begin replacement code
 
menuTargetFigure = fig;
 
% When high resolution screenshots of the main axes are needed it is best
% to plot the main axes in a separate figure which can be maximised on the
% display. Furthermore then screenshots can be taken by using the file menu
% options
% Position is [left, bottom, width, height], where left and bottom is the
% distance of the lower left corner of the figure to the lower left corner
% of the screen
% Also when making figure we do not want the stretch-to-fill behaviour as
% in the user GUI. To override the automatic scaling use axis vis3d. To
% keep the axis within the boundaries of the figure we also need view(3)

% Uncomment the following lines for detached axis figure
% f = figure('Position', [0, 0, 1461, 1096]); % Original figure size
% f = figure('Position', [0, 0, 1000, 1000]); % Reduced figure size
% f = figure('Position', [0, 0, 800, 800]); % Further reduced figure size
% The following is supposed to have the effect that in print in a 3 column
% composite image the resulting MATLAB plot line width and font size is
% equivalent to the resulting properties when using 1000x1000 images and
% making a composite 3 column image as done in the 3D growth estimation
% section js thesis.
% f = figure('Position', [0, 0, 660, 660]); % Reduced figure size
% movegui(f, 'northwest'); % With the above results in [4, 33, 1461, 1096]
% ad.handles.mainAxes = gca;
% menuTargetFigure = f;
   
axisColour = [0, 0, 0];
%axisColour = [1, 1, 1];
gridColour = [0, 0, 0];
set(ad.handles.mainAxes, 'Color', axisColour);

if ad.dim == 3
    % It appears that we have to name the axes explicitly in this
    % particular instance
    set(ad.handles.mainAxes, 'XColor', gridColour, 'YColor', gridColour, 'ZColor', gridColour);
    box(ad.handles.mainAxes, 'on');
    axis(ad.handles.mainAxes, 'equal');
    view(ad.handles.mainAxes, 3);
    axis(ad.handles.mainAxes, 'vis3d');
end

% Add a menu and item to the figure to do screenshots of main axes
movegui(fig, 'northeast');

ad.handles.figuresMenu = uimenu(menuTargetFigure, 'Tag', 'figuresMenu', 'Label', 'Figures');
ad.handles.screenshotMainAxesMenuItem = uimenu(ad.handles.figuresMenu, ...
    'Tag', 'screenshotMainAxesMenuItem', 'Label', 'Screenshot Main Axes');
set(ad.handles.screenshotMainAxesMenuItem, 'Callback', {@screenshotMainAxesCallback});

set(handles.isosurface_chk, 'callback', {@doUpdateDisplay}); 

% Ad menu items to set a default viewpoints
ad.handles.lateralViewpointMenuItem = uimenu(ad.handles.figuresMenu, ...
    'Tag', 'lateralViewpointMenuItem', 'Label', 'Lateral angle Viewpoint');
set(ad.handles.lateralViewpointMenuItem, 'Callback', {@lateralViewpointCallback});

ad.handles.adaxialViewpointMenuItem = uimenu(ad.handles.figuresMenu, ...
    'Tag', 'adaxialViewpointMenuItem', 'Label', 'Adaxial angle Viewpoint');
set(ad.handles.adaxialViewpointMenuItem, 'Callback', {@adaxialViewpointCallback});

ad.handles.view3ViewpointMenuItem = uimenu(ad.handles.figuresMenu, ...
    'Tag', 'view3ViewpointMenuItem', 'Label', 'view(3) Viewpoint');
set(ad.handles.view3ViewpointMenuItem, 'Callback', {@view3ViewpointCallback});


% Set to OpenGL explicitly otherwise the AutoMode may select a painter
set(fig, 'Renderer', 'OpenGL');

% ad.surfaceData = initialiseSurfaceData(ad);
pmDirectory = ad.options.PMdirectory;

% Get leaf directory name using strtok. This requires flipping of the
% string since strtok proceeds left to right
[token, remain] = strtok(fliplr(pmDirectory), filesep);
name = fliplr(token);
surfaceDirectory = fullfile(pwd, 'Templates');

ad.surfaceData = getSurfaceData('name', name, 'mode', 'template', ...
    'surfaceDirectory', surfaceDirectory);
 
% End replacement code
% End change by js, 080114

setappdata(0,'ModelViewerData',ad);

initgui;

% Lets try replicating the entire GUI for Matlab stereo display
% This would make life a lot easier since we could use the GUI
% as in mono mode
% This is highly experimental, some buttons do work, but the check boxes
% Don't in the second figure. Also the plot only gets updated in the first
% figure. This makes sense as the update routines only consider one plot
%
% fig2 = copyobj(fig, 0);
% 
% try
%     uiwait(fig2);
% catch
%     if ishandle(fig2)
%         delete(fig2)
%     end
% end
% CONTROL THE GUI
% try
%     uiwait(fig);
% catch
%     if ishandle(fig)
%         delete(fig)
%     end
% end
return
if isappdata(0,'ModelViewerData')
    ad = getappdata(0,'ModelViewerData');
    if ad.options.savePDM
        ad = savePDM(ad);
    end
%     if isfield(ad,'View3D')
%         close(ad.View3D.plotaxis(1));
%         close(ad.View3D.plotaxis(2));        
%     end
    rmappdata(0,'ModelViewerData')
else
    % figure was deleted
    selection = [];
    value = 0;
end
return;
 

% Begin change by js, 080114
% Begin original code
 
% No replacement in this case 
 
% End original code
% Begin replacement code

% Set default viewpoints
% 
% set(handles.View_1,'callback',{doSelectView_1});
function doSelectView_XY_Z_up(cbo, event)
ad =getappdata(0, 'ModelViewerData');
h=ad.handles.mainAxes;
set(h,'CameraPosition',[-449.5399 -737.9569   56.6131]);% -442.9419  623.1329  439.5396
set(h,'CameraTarget',[26.2806   11.6302   -5.4717]);
set(h,'CameraUpVector',[0,0,1]);%[0.0374    0.0589    0.9976]
set(h,'CameraViewAngle',9.9);


function doSelectView_1(cbo, event)
    ad =getappdata(0, 'ModelViewerData');
    h=ad.handles.mainAxes;
    % read view from file
    if exist('ViewData1.mat')==2
        % read data
        ans=load('ViewData1.mat');
        v=ans.v;
        t=ans.t;
        u=ans.u;
        a=ans.a;
        set(h,'CameraPosition',v);
        set(h,'CameraTarget',t);
        set(h,'CameraUpVector',u);
        set(h,'CameraViewAngle',a);
    end
function doSelectView_2(cbo, event)
    ad =getappdata(0, 'ModelViewerData');
    h=ad.handles.mainAxes;
    % read view from file
    if exist('ViewData2.mat')==2
        % read data
        ans=load('ViewData2.mat');
        v=ans.v;
        t=ans.t;
        u=ans.u;
        a=ans.a;
        set(h,'CameraPosition',v);
        set(h,'CameraTarget',t);
        set(h,'CameraUpVector',u);
        set(h,'CameraViewAngle',a);
    end

function doSelectView_3(cbo, event)
    ad =getappdata(0, 'ModelViewerData');
    h=ad.handles.mainAxes;
    % read view from file
    if exist('ViewData3.mat')==2
        % read data
        ans=load('ViewData3.mat');
        v=ans.v;
        t=ans.t;
        u=ans.u;
        a=ans.a;
        set(h,'CameraPosition',v);
        set(h,'CameraTarget',t);
        set(h,'CameraUpVector',u);
        set(h,'CameraViewAngle',a);
    end

function doSetView_1(cbo, event)
    ad =getappdata(0, 'ModelViewerData');
    h=ad.handles.mainAxes;
    v=get(h,'CameraPosition');
    t=get(h,'CameraTarget');
    u=get(h,'CameraUpVector');
    a=get(h,'CameraViewAngle');
    save('ViewData1.mat','v','t','u','a');
    
function doSetView_2(cbo, event)
    ad =getappdata(0, 'ModelViewerData');
    h=ad.handles.mainAxes;
    v=get(h,'CameraPosition');
    t=get(h,'CameraTarget');
    u=get(h,'CameraUpVector');
    a=get(h,'CameraViewAngle');
    save('ViewData2.mat','v','t','u','a');
function doSetView_3(cbo, event)
    ad =getappdata(0, 'ModelViewerData');
    h=ad.handles.mainAxes;
    v=get(h,'CameraPosition');
    t=get(h,'CameraTarget');
    u=get(h,'CameraUpVector');
    a=get(h,'CameraViewAngle');
    save('ViewData3.mat','v','t','u','a');

% set(handles.SetView_2,'callback',{doSetView_2});

function lateralViewpointCallback(cbo, event)

display('ModelViewer::lateralViewpointCallback: start executing.');

view(264, 10); % Prevents vertical stacking of z axis labels

function adaxialViewpointCallback(cbo, event)

display('ModelViewer::adaxialViewpointCallback: start executing.');

view(-6, 10);

function view3ViewpointCallback(cbo, event)

display('ModelViewer::view3ViewpointCallback: start executing.');

view(3);


% Make figure screenshot
function screenshotMainAxesCallback(cbo, event)

display('ModelViewer::screenshotMainAxesCallback: start executing.');

ad =getappdata(0, 'ModelViewerData');
f = getframe(ad.handles.mainAxes);
image = f.cdata;

imreadSupportedFileTypes = getImreadSupportedTypesFilterSpec();

% Get the project name from the working directory
projectName = fliplr(strtok(fliplr(pwd), filesep));
[fileName, pathName, filterIndex] = uiputfile(imreadSupportedFileTypes, ...
    'Save frame', projectName);

if ischar(fileName) && ischar(projectName)
   imwrite(image, fullfile(pathName, fileName)); 
end

function ad = plotTemplateSurface(ad)

if ad.dim ~= 3
   return; 
end

if isempty(ad.pdm)
    return;
end
if get(ad.handles.isosurface_chk, 'Value')==0
    return;
end
pts = getCurrShapeModel(ad.pdm, ad.handles.shape_modes_val, ad.dim);
if ~isempty(ad.segmentPoint)
    pts = splitPoints(pts, ad.segmentPoint, ad.offsets);
end

if isempty(ad.surfaceData.templatePoints)
    disp('Template isosurface data empty. Operation not available.');
    return;
end

tPoints = ad.surfaceData.templatePoints;
tSurface = ad.surfaceData.templateSurface;
mPoints = pts;
edges = ad.edges;

% Now warp this surface using AIH general motion coherence code.
% Align template points and surface with model points to get a better warp

% Define colours for visualisation of alignment and warping if desired
% sourceColours = ['b'; 'g'];
% targetColours = ['y'; 'r'];
% alignedColours = ['g'; 'b'];

% sourceColours = ['r'; 'k'];
% targetColours = ['b'; 'k'];
% alignedColours = ['g'; 'k'];


sourceColours = [1, 0.5, 0.5; 0, 0, 0];
targetColours = [0.5, 1, 0.5; 0, 0, 0];
% targetColours = [0, 0.5, 1; 0, 0, 0];
alignedColours = [0.5, 0.5, 1; 0, 0, 0];

axesHandle = -1;
verbose = 1;

% [tPoints, tSurface] = alignWithTargetPoints(mPoints, tPoints, tSurface, ...
%     verbose, axesHandle, targetColours, sourceColours, alignedColours, ...
%     'Target Point Set', 'Source Point Set', 'Aligned Point Set');

[tPoints, tSurface] =  alignWithTargetPoints('targetPoints', mPoints, ...
    'sourcePoints', tPoints, 'sourceSurface', tSurface, 'method', 'svd', ...
    'verbose', verbose, 'axesHandle', axesHandle, 'targetColours', targetColours, ...
    'sourceColours', sourceColours, 'alignedColours', alignedColours, ...
    'targetLabel', 'Target Point Set', 'sourceLabel', 'Source Point Set', ...
    'alignedLabel', 'Aligned Point Set', 'edges', edges);

ad.surfaceData.currentModelSurface =  warpSurface('targetPoints', mPoints, ...
    'sourcePoints', tPoints, 'sourceSurface', tSurface, 'method', 'closed', ...
    'sigma', 1, 'lambda', 0.01, 'verbose', verbose, 'axesHandle', axesHandle, ...
    'targetColours', targetColours, 'sourceColours', alignedColours, ...
    'targetLabel', 'Target Point Set', 'sourceLabel', 'Aligned Point Set', 'edges', edges);

parent = ad.handles.mainAxes;

% We have to set the axis to xy otherwise the face normals calculated are
% wrong
% axis(parent, 'xy');
% Render warped surface
ad.surfaceData.colour = [0, 1, 0]
ad.surfaceData.handle = patch('Faces', ad.surfaceData.currentModelSurface.faces, ...
    'Vertices', ad.surfaceData.currentModelSurface.vertices, ...
    'EdgeColor', 'none', 'FaceColor', ad.surfaceData.colour, 'FaceLighting', 'gouraud',...
    'Parent', ad.handles.mainAxes);

% ad.surfaceData.handle = patch('Faces', ad.surfaceData.currentModelSurface.faces, ...
%     'Vertices', ad.surfaceData.currentModelSurface.vertices, ...
%     'EdgeColor', 'none', 'FaceColor', ad.surfaceData.colour,...
%     'Parent', parent);

% Setup light
lightPos = [1 0 1];
ad.surfaceData.lightHandles(1) = light('Position', lightPos, 'Parent', parent);
ad.surfaceData.lightHandles(2) = light('Position', -lightPos, 'Parent', parent);

% Development testing code
% handle = patch('Faces', ad.surfaceData.currentModelSurface.faces, ...
%     'Vertices', ad.surfaceData.currentModelSurface.vertices, ...
%     'EdgeColor', 'none', 'FaceColor', ad.surfaceData.colour,
%     'FaceLighting', 'gouraud', ...
%     'Parent', gca);
% 
% axis tight;
% axis equal;
% view(3);
% axis vis3d;
% box on;
% 
% lightPos = [1 0 1];
% lightHandles(1) = light('Position', lightPos, 'Parent', gca);
% lightHandles(2) = light('Position', -lightPos, 'Parent', gca);

% Update axes limits based on the surface's vertex data
ad = updateAxisLimitsFromSurface(ad, ad.surfaceData.currentModelSurface);
axis(ad.handles.mainAxes, [ad.xrange(1) ad.xrange(2), ad.yrange(1) ad.yrange(2), ad.zrange(1) ad.zrange(2)]);
return


function ad = updateTemplateSurface(ad)
if isempty(ad.pdm)
    return;
end
if get(ad.handles.isosurface_chk, 'Value')==0
    return;
end
pts = getCurrShapeModel(ad.pdm, ad.handles.shape_modes_val, ad.dim);
if ~isempty(ad.segmentPoint)
    pts = splitPoints(pts, ad.segmentPoint, ad.offsets);
end

tPoints = ad.surfaceData.templatePoints;
tSurface = ad.surfaceData.templateSurface;
mPoints = pts;

% Now warp this surface using AIH general motion coherence code.
% Align template points and surface with model points to get a better warp

% Define colours for visualisation of alignment and warping if desired
sourceColours = ['b'; 'g'];
targetColours = ['y'; 'r'];
alignedColours = ['g'; 'b'];
axesHandle = -1;
verbose = 0;

[tPoints, tSurface] =  alignWithTargetPoints('targetPoints', mPoints, ...
    'sourcePoints', tPoints, 'sourceSurface', tSurface, 'method', 'svd', ...
    'verbose', verbose, 'axesHandle', axesHandle, 'targetColours', targetColours, ...
    'sourceColours', sourceColours, 'alignedColours', alignedColours, ...
    'targetLabel', 'Target Point Set', 'sourceLabel', 'Aligned Point Set', ...
    'alignedLabel', 'Aligned Point Set');

ad.surfaceData.currentModelSurface =  warpSurface('targetPoints', mPoints, ...
    'sourcePoints', tPoints, 'sourceSurface', tSurface, 'method', 'closed', ...
    'sigma', 1, 'lambda', 0.01, 'verbose', verbose, 'axesHandle', axesHandle, ...
    'targetColours', targetColours, 'sourceColours', alignedColours, ...
    'targetLabel', 'Target Point Set', 'sourceLabel', 'Aligned Point Set');

% Update surface plot
set(ad.surfaceData.handle, 'Faces', ad.surfaceData.currentModelSurface.faces, ...
    'Vertices', ad.surfaceData.currentModelSurface.vertices);

% Update axes limits based on the surface's vertex data
ad = updateAxisLimitsFromSurface(ad, ad.surfaceData.currentModelSurface);
axis(ad.handles.mainAxes, [ad.xrange(1) ad.xrange(2), ad.yrange(1) ad.yrange(2), ad.zrange(1) ad.zrange(2)]);

return


function ad = updateAxisLimitsFromSurface(ad, surface)

xrange = [min(surface.vertices(:, 1)), max(surface.vertices(:, 1))];
yrange = [min(surface.vertices(:, 2)), max(surface.vertices(:, 2))];
zrange = [min(surface.vertices(:, 3)), max(surface.vertices(:, 3))];

if xrange(1) < ad.xrange(1); ad.xrange(1) = xrange(1); end;
if xrange(2) > ad.xrange(2); ad.xrange(2) = xrange(2); end;
if yrange(1) < ad.yrange(1); ad.yrange(1) = yrange(1); end;
if yrange(2) > ad.yrange(2); ad.yrange(2) = yrange(2); end;
if zrange(1) < ad.zrange(1); ad.zrange(1) = zrange(1); end;
if zrange(2) > ad.zrange(2); ad.zrange(2) = zrange(2); end;

% End replacement code
% End change by js, 080114


%%%%%
%
%
%%%%%
function doUpdateDisplay(axis_radio, evd) %#ok<INUSD,INUSD>
ad = getappdata(0,'ModelViewerData');
set(ad.figMain, 'Pointer', 'watch');
drawnow;
plotModel;
title(ad.handles.mainAxes, '', 'Interpreter', 'none');

set(ad.figMain, 'Pointer', 'arrow');
return;
%%%%%
%
%
%%%%%
function ad = loadModels(ad)
opt = ad.options;
% Load the pdm if it exists
pdmfile = opt.pdm;
ad.pdmfilename = pdmfile;
if exist(ad.pdmfilename, 'file')
    ad.pdm = load(ad.pdmfilename);
    ad.pdm = ad.pdm.pdm;
    if isfield(ad.pdm, 'edges') && isempty(ad.edges)
        ad.edges = ad.pdm.edges;
    end
    if get(ad.handles.cart_axes_chk, 'Value')
        ad.pdm.P = eye(size(ad.pdm.P,1));
        ad.pdm.b = ones(size(ad.pdm.P,1), 1);
    end
    ad.handles.shape_modes_val = zeros(length(ad.pdm.b),1);
    ad.currentShapeModel = getCurrShapeModel(ad.pdm,  ad.handles.shape_modes_val, ad.dim);
end

% Load the sfam if it exists
sfamfile = opt.sfam;
if ~isempty(sfamfile)
    ad.sfamfilename = sfamfile;
    set(ad.handles.no_app_txt, 'Visible', 'off');
    if exist(ad.sfamfilename, 'file')
        ad.sfam = load(ad.sfamfilename);
        ad.sfam = ad.sfam.sfam;
        ad.handles.app_modes_val = zeros(length(ad.sfam.b),1);
    end
else
    ad.handles = toggleAppearanceGUI(ad.handles, 'off');
end
ad = setupSliderLimits(ad);
return;
%%%%%
%
%
%%%%%
function ad = setupSliderLimits(ad)
app_y_lim = length(ad.handles.app_modes_val) - ad.dy;
shape_y_lim = length(ad.handles.shape_modes_val) - ad.dy;
if -app_y_lim>=-1
    set(ad.handles.appslider, 'Enable', 'off');
else
    set(ad.handles.appslider, 'Min', -app_y_lim-1);
end
if -shape_y_lim>=-1
    set(ad.handles.shapeslider, 'Enable', 'off');
else
    set(ad.handles.shapeslider, 'Min', -shape_y_lim-1);
end
ad.currentShapeMode = 1;
ad.currentAppMode = 1;
return;
%%%%%
%
%
%%%%%
function togglePlotView
ad =getappdata(0, 'ModelViewerData');
if get(ad.handles.orient_xy_rad, 'Value');
    axis(ad.handles.mainAxes, 'xy');
else
    axis(ad.handles.mainAxes, 'ij');
end
setappdata(0, 'ModelViewerData', ad);
%%%%%
%
%
%%%%%
function ad = updateAxisLimits(ad, pts)
xrange = [min(pts(:,1)), max(pts(:,1))];
yrange = [min(pts(:,2)), max(pts(:,2))];
if xrange(1)<ad.xrange(1); ad.xrange(1) = xrange(1); end;
if xrange(2)>ad.xrange(2); ad.xrange(2) = xrange(2); end;
if yrange(1)<ad.yrange(1); ad.yrange(1) = yrange(1); end;
if yrange(2)>ad.yrange(2); ad.yrange(2) = yrange(2); end;
% Begin change by js, 070705
% Begin original code
 
% No replacement in this case 
 
% End original code
% Begin replacement code
 
if ad.dim == 3
    zrange = [min(pts(:,3)), max(pts(:,3))];
    if zrange(1)<ad.zrange(1); ad.zrange(1) = zrange(1); end;
    if zrange(2)>ad.zrange(2); ad.zrange(2) = zrange(2); end;
end
 
% End replacement code
% End change by js, 070705

return;
%%%%%
%
%
%%%%%
function initgui
ad =getappdata(0, 'ModelViewerData');
if isempty(ad.pdm)
    uiwait(msgbox('Could not find a shape model. Aborting.','No PDM.','modal'));
    close(ad.figMain);
    return;
end
Xm = ad.pdm.Xm;
mean_pts = reshape(Xm, ad.dim , length(Xm)/ad.dim )';
ad.xrange = [min(mean_pts(:,1)), max(mean_pts(:,1))];
ad.yrange = [min(mean_pts(:,2)), max(mean_pts(:,2))];
% Begin change by js, 070705
% Begin original code
 
% No replacement in this case 
 
% End original code
% Begin replacement code
 
if ad.dim == 3
    ad.zrange = [min(mean_pts(:,3)), max(mean_pts(:,3))];
end
 
% End replacement code
% End change by js, 070705
displayModes(ad.handles.shapelevels, ad.handles.shape_modes_val, ad.handles.shapeslider, 'shape');
ad = updateShapeWalkerLimits(ad);
if ~isempty(ad.options.sfam)
    displayModes(ad.handles.applevels, ad.handles.app_modes_val, ad.handles.appslider, 'app');
    ad = updateAppWalkerLimits(ad);
end
setappdata(0,'ModelViewerData',ad);
plotModel;
ad =getappdata(0, 'ModelViewerData');
axis(ad.handles.mainAxes, 'tight');
ad.xrange = get(ad.handles.mainAxes, 'Xlim');
ad.yrange = get(ad.handles.mainAxes, 'Ylim');
% Begin change by js, 070705
% Begin original code
 
% No replacement in this case 
 
% End original code
% Begin replacement code
 
if ad.dim == 3
    ad.zrange = get(ad.handles.mainAxes, 'Zlim')
end
 
% End replacement code
% End change by js, 070705


setappdata(0,'ModelViewerData',ad);
%%%%%
%
%
%%%%%
function doFlipShapePC(flippcmenu, evd) %#ok<INUSD,INUSD>
ad =getappdata(0, 'ModelViewerData');
if isempty(ad.pdm)
    uiwait(msgbox('The is no shape model currently loaded, aborting.','Error','modal'));
    return;
end
N = size(ad.pdm.P, 2);
str = cell(N,1);
for i=1:N; str{i} = num2str(i); end;
[s,v] = listdlg('Name', 'Direction Flip', 'PromptString','Select PC''s to flip', 'ListSize', [400, 200], 'SelectionMode','multiple', 'ListString',str);
if isempty(s)
    return;
end
ad.pdm.P(:,s) = -1*ad.pdm.P(:,s);
ad.pdm.pca.P(:,s) = -1*ad.pdm.pca.P(:,s);
ad.options.savePDM = 1;
setappdata(0, 'ModelViewerData', ad);
%%%%%
%
%
%%%%%
function doExportPointModel(exportpmmenu, evd) %#ok<INUSD,INUSD>
ad =getappdata(0, 'ModelViewerData');
[filename, pathname] = uiputfile('*.mat', 'Save as...');
if isequal(filename,0) || isequal(pathname,0)
    disp('User pressed cancel')
    return;
end
pts = getCurrShapeModel(ad.pdm, ad.handles.shape_modes_val, ad.dim)';
pts = pts(:);
[junk, filename] = fileparts(filename);
filename = [pathname, filesep, filename, '_pm.mat'];
save(filename, 'pts');
%%%%%
%
%
%%%%%
function doScreenShot(exportpmmenu, evd) %#ok<INUSD,INUSD>
ad =getappdata(0, 'ModelViewerData');
name=get(gcbo,'Tag');
projectname=ad.options.PMdirectory(1:strfind(ad.options.PMdirectory,'PointModels')-2);
snapshotsdir=fullfile(projectname,'snapshots');
if exist(snapshotsdir)~=7
    mkdir('snapshots');
end
datetime=['-',datestr(now,31)];
datetime(findstr(datetime,' '))='t';
datetime(findstr(datetime,':'))='-';
switch name
    case 'SnapshotWholeInterface'
        F=getframe(ad.figMain);
        [filename, pathname] = uiputfile(fullfile('snapshots','*.png'), 'Save as...');
        imwrite(F.cdata,fullfile(pathname,filename));
    case 'SnapshotModelOnly'
        F=getframe(ad.handles.mainAxes);
        [filename, pathname] = uiputfile(fullfile('snapshots','*.png'), 'Save as...');
        imwrite(F.cdata,fullfile(pathname,filename));
    case 'MatlabFigureofWholeInterface'
        [filename, pathname] = uiputfile(fullfile('snapshots','*.fig'), 'Save as...');
        saveas(ad.handles.mainAxes,fullfile(pathname,filename));
    otherwise
        error('doScreenShot: calling object not recognised');
end
%%%%%
%
%
%%%%%
function doMakeMovie(exportpmmenu, evd) %#ok<INUSD,INUSD>
ad =getappdata(0, 'ModelViewerData');
name=get(gcbo,'Tag');
projectname=ad.options.PMdirectory(1:strfind(ad.options.PMdirectory,'PointModels')-2);
snapshotsdir=fullfile(projectname,'movies');
if exist(snapshotsdir)~=7
    mkdir('movies');
end
datetime=['-',datestr(now,31)];
datetime(findstr(datetime,' '))='t';
datetime(findstr(datetime,':'))='-';
if strcmp(get(gcbo,'checked'),'off')
    set(gcbo,'checked','on');
    ad.moviename=fullfile(projectname,'movies',['movie',datetime]);
    if isempty(which('avifile'))
        path(path,genpath('C:\Program Files\MATLAB\R2010a\toolbox\matlab\audiovideo'));
    end
    ad.moviefilehandle=avifile(ad.moviename,'compression','none');
    % Jake added 16/06/2011 - Won't write first frame unless this is here
    h=findobj(ad.figMain,'tag','mainAxes');
    F=getframe(h);%ad.figMain); %mainFig);
    ad.moviefirstframe=F;
    ad.moviefilehandle=addframe(ad.moviefilehandle,F);
else
    set(gcbo,'checked','off');
    ad.moviename='';
    ad.moviefilehandle=close(ad.moviefilehandle);
end
setappdata(0, 'ModelViewerData', ad);
%%%%%
%
%
%%%%%
function doExportShapePCMenu(exportshapemenu, evd) %#ok<INUSD,INUSD>
ad =getappdata(0, 'ModelViewerData');
[filename, pathname] = uiputfile('*.xls', 'Save as...');
if isequal(filename,0) || isequal(pathname,0)
    disp('User pressed cancel')
    return;
end
b = ad.handles.shape_modes_val.*sqrt(ad.pdm.b);
I = cell(length(b),1);
for i=1:length(b)
    I{i,1} = b(i);
end
[success, message] = xlswrite([pathname, filesep, filename], I);
%%%%%
%
%
%%%%%
function doImportShapePCMenu(importshapemenu, evd) %#ok<INUSD,INUSD>
ad =getappdata(0, 'ModelViewerData');
[filename, pathname] = uigetfile('*.xls', 'Pick an Excel file');
if isequal(filename,0) || isequal(pathname,0)
    disp('User pressed cancel')
    return;
end
pcvals = xlsread([pathname, filesep, filename]);
pcvals = pcvals(:,1);
N = length(ad.handles.shape_modes_val);
if length(pcvals)>N
    pcvals = pcvals(1:N);
end
b = zeros(N,1);
b(1:length(pcvals)) = pcvals;
ad.handles.shape_modes_val = b./sqrt(ad.pdm.b);
%ad.handles.shape_modes_val = b;
doPlotModes(ad.handles.shapelevels, ad.handles.shape_modes_val, 'shape');
setappdata(0, 'ModelViewerData', ad);
plotModel;
%%%%%
%
%
%%%%%
function doChangeAxes(cartchk, evd) %#ok<INUSD,INUSD>
ad =getappdata(0, 'ModelViewerData');
ad = loadModels(ad);
setappdata(0, 'ModelViewerData', ad);
initgui;
%%%%
%
%
%%%%
function doToggleOffset(offsetchk, evd) %#ok<INUSD,INUSD>
ad =getappdata(0, 'ModelViewerData');
if get(ad.handles.offsetchk, 'Value')
    [ad.segmentPoint, ad.offsets] = isAugmentedProject;
else
    ad.offsets = zeros(length(ad.segmentPoint)+1, 3);

end
setappdata(0, 'ModelViewerData', ad);
updatePlot;
ad =getappdata(0, 'ModelViewerData');
axis(ad.handles.mainAxes, 'tight');
ad.xrange = get(ad.handles.mainAxes, 'Xlim');
ad.yrange = get(ad.handles.mainAxes, 'Ylim');
% Begin change by js, 070705
% Begin original code
 
% No replacement in this case 
 
% End original code
% Begin replacement code
 
if ad.dim == 3
    ad.zrange = get(ad.handles.mainAxes, 'Zlim')
end
 
% End replacement code
% End change by js, 070705

setappdata(0, 'ModelViewerData', ad);

%%%%%
%
%
%%%%%
function doUpdateWalkerLimits(txt, evd) %#ok<INUSD,INUSD>
ad =getappdata(0, 'ModelViewerData');
ad = updateShapeWalkerLimits(ad);
ad = updateAppWalkerLimits(ad);
setappdata(0, 'ModelViewerData', ad);
plotModel;

%%%%%
%
%
%%%%%
function ad = updateShapeWalkerLimits(ad)
lim = str2num(get(ad.handles.shape_range, 'String')); %#ok<ST2NM>
ad.shapewalkerlim = lim;
sh = ad.handles.shape_pc_slider;
val = get(sh, 'Value');
set(sh, 'Min', -abs(lim), 'Max', abs(lim));
if abs(val)>=abs(lim)
    set(sh, 'Value', sign(val)*lim);
end
%%%%%
%
%
%%%%%
function ad = updateAppWalkerLimits(ad)
lim = str2num(get(ad.handles.app_range, 'String')); %#ok<ST2NM>
ad.appwalkerlim = lim;
sh = ad.handles.app_pc_slider;
val = get(sh, 'Value');
set(sh, 'Min', -abs(lim), 'Max', abs(lim));
if abs(val)>=abs(lim)
    set(sh, 'Value', sign(val)*lim);
end
%%%%%
%
%
%%%%%
function doReloadModel(reloadModelbtn, evd) %#ok<INUSD,INUSD>
ad =getappdata(0, 'ModelViewerData');
ad = loadModels(ad);
ad.options.ref_image = [];
ad.FLIPIND = [];
setappdata(0,'ModelViewerData',ad);
initgui;
%%%%%
%
%
%%%%%
function doAddRandomShapeAxis(randaxisbtn, evd) %#ok<INUSD,INUSD>
ad =getappdata(0, 'ModelViewerData');
P = ad.pdm.pca.P;
b = ad.pdm.b;
p = P*randn(size(P,2),1);
p = p/norm(p);
ad.pdm.P = [ad.pdm.P, p];
ad.pdm.b = [b; b(1)];
ad.handles.shape_modes_val = [ad.handles.shape_modes_val; 0];
setappdata(0, 'ModelViewerData', ad);
ad = setupSliderLimits(ad);
axis_h = ad.handles.shapelevels;
doPlotModes(axis_h, ad.handles.shape_modes_val, 'shape');
%%%%%
%
%
%%%%%
function doImportMeanShape(importmeanshpbtn, evd) %#ok<INUSD,INUSD>
ad =getappdata(0, 'ModelViewerData');
pmdir = [ad.options.PMdirectory];
[filename, pathname] = uigetfile('*_pm.mat', 'Pick an PM-file', [pmdir, filesep]);
if isequal(filename,0) || isequal(pathname,0)
    disp('User pressed cancel');
    return;
else
    meanshape = load([pathname, filesep, filename]);
    meanshape = meanshape.pts;
    disp(['User selected ', fullfile(pathname, filename)])
end
ad.pdm.Xm = meanshape;
setappdata(0, 'ModelViewerData', ad);
plotModel;
%%%%%
%
%
%%%%%
function doCalcWeights(calcweightsbtn, evd) %#ok<INUSD,INUSD>
ad =getappdata(0, 'ModelViewerData');
%%%%%%%%
% Take care of the shape first
%%%%%%%%
if isempty(ad.pmpts)
    uiwait(msgbox('Please load a point model file first','No pm file loaded','modal'));
    return;
end
details = ad.details;
original_pts = ad.pmpts;
%[ad.pmpts] = pcalib_GPA('data', ad.pmpts, 'opts', [details.scaling,details.rotation,details.translation], 'dimension', ad.dim, 'template', ad.pdm.Xm);
[ad.pmpts] = pcalib_GPA('data', ad.pmpts, 'opts', details, 'dimension', ad.dim, 'template', ad.pdm.Xm);
%ad.pmpts=pmalign(ad.pmpts,[details.scaling,details.rotation,details.translation],ad.pdm.Xm);
b = ad.pdm.P'*(ad.pmpts - ad.pdm.Xm);
ad.handles.shape_modes_val = ((b./ (sqrt(ad.pdm.b))));
doPlotModes(ad.handles.shapelevels, (ad.handles.shape_modes_val), 'shape');
%%%%%%%%
% Now its time for the appearance
%%%%%%%%
original_pts = reshape(original_pts, ad.dim , length(original_pts)/ad.dim );
if isfield(ad, 'sfam')
    if ~isempty(ad.sfam)
        meansize_im = triwarp(ad.pmimage, original_pts', ad.sfam.ompts); %warped image
        sz = ad.sfam.siz;
        Am = ad.sfam.Am;
        P = ad.sfam.P;
        b = ad.sfam.b;
        ompts = ad.sfam.ompts;
        model_b = P'*(meansize_im(:) - Am);
        ad.handles.app_modes_val = model_b./sqrt(ad.sfam.b);
        doPlotModes(ad.handles.applevels, ad.handles.app_modes_val, 'app');
        setappdata(0, 'ModelViewerData', ad);
    end
end
setappdata(0, 'ModelViewerData', ad);
plotModel;
title(ad.handles.mainAxes, ['Model - ', ad.modelledimagename], 'Interpreter', 'none');

%%%%%
%
%
%%%%%
function doLoadPointModelFile(loadpmfilebtn, evd) %#ok<INUSD,INUSD>
ad =getappdata(0, 'ModelViewerData');
pmdirectory = ad.options.PMdirectory;

%[filename, pathname] = uigetfile({'*.mat'}, 'Pick an PM file', [pmdirectory, filesep]);
[filename, pathname] = uigetfile({'*.jpg;*.JPG';'*.jpeg;*.JPEG'}, 'Pick an JPEG-file', ['Cropped', filesep]);

if isequal(filename,0) || isequal(pathname,0)
    disp('User pressed cancel')
    return;
else
    disp(['User selected ', fullfile(pathname, filename)])
end
pmdirectory = ad.options.PMdirectory;
pmfile = getPMFile(filename, pmdirectory);
%pmfile = filename;
if isempty(pmfile)
    uiwait(msgbox('There is no PM file for your chosen image','No pm file found','modal'));
    return;
end

pts = load([pmdirectory, filesep, pmfile]);
ad.pmpts = pts.pts;
if ~isempty(ad.indices)
    ad.pmpts = reshape(ad.pmpts, ad.dim, length(ad.pmpts)/ad.dim);
    ad.pmpts = ad.pmpts(:, ad.indices);
    ad.pmpts = ad.pmpts(:);
end
[pmdir, pmfile, ext, vers] = fileparts(pmfile);
pmfile = pmfile(1:end-3);
imname = ['Cropped', filesep, pmfile, '.jpg'];
if exist(imname, 'file')
    ad.pmimage = double(imread(imname));
    fig = figure;
    imshow(uint8(ad.pmimage));
    title(gca, ['Original - ', pmfile], 'Interpreter', 'none');
    set(fig, 'Position', [0 0 500 500]);

else
    ad.pmimage = [];
end
ad.modelledimagename = pmfile;
setappdata(0, 'ModelViewerData', ad);
%%%%%
%
%
%%%%%
function pmfilename = getPMFile(imname, D)
files = dir([D, filesep, '*_pm.mat']);
files = {files.name};
pmfilename = [];
[impath, imname, ext, vers] = fileparts(imname);
for i=1:length(files)
    pmfile = files{i};
    [pmpath, pmfile, ext, vers] = fileparts(pmfile);
    pmfile = pmfile(1:end-3);
    if strcmp(imname, pmfile)
        pmfilename = files{i};
        return;
    end
end
return;
%%%%%
%
%
%%%%%
function doSaveImage(savebtn, evd) %#ok<INUSD,INUSD>
ad =getappdata(0, 'ModelViewerData');

[filename, pathname] = uiputfile({'*.tiff', 'TIFF Image (*.tiff)'}, 'Save as...');
if isequal(filename,0) || isequal(pathname,0)
    disp('User pressed cancel')
else
    disp(['User selected ', fullfile(pathname, filename)])
    %set(ad.figMain, 'InvertHardcopy', 'off');
    %print(ad.figMain,'-dtiffnocompression',[pathname, filesep, filename]);
    I = frame2im(getframe(ad.handles.mainAxes));
    imwrite(I, [pathname, filesep, filename], 'TIFF');
end
setappdata(0, 'ModelViewerData', ad);
%%%%%
%
%
%%%%%
function displayModes(axis_h, modes_val, slider_h, type)
doPlotModes(axis_h, modes_val, type);
highlightMode(1, axis_h);
doSlideModes(slider_h, [], axis_h);
%%%%%
%
%
%%%%%
function doResetShape(reset, evd) %#ok<INUSD,INUSD>
ad =getappdata(0, 'ModelViewerData');
val = ad.currentShapeMode;
ad.handles.shape_modes_val(val) = 0;
set(ad.handles.shape_pc_slider, 'Value', 0);
setappdata(0, 'ModelViewerData', ad);
plotModel;
doPlotModes(ad.handles.shapelevels, ad.handles.shape_modes_val, 'shape');
if val<=length(ad.handles.shape_modes_val)
    highlightMode(val, ad.handles.shapelevels);
end
% if ad.View3DFlag
%     UpdatePlotsTo3D;
% end

%%%%%
%
%
%%%%%
function doResetApp(reset, evd) %#ok<INUSD,INUSD>
ad =getappdata(0, 'ModelViewerData');
val = ad.currentAppMode;
ad.handles.app_modes_val(val) = 0;
set(ad.handles.app_pc_slider, 'Value', 0);
setappdata(0, 'ModelViewerData', ad);
plotModel;
ad =getappdata(0, 'ModelViewerData');
doPlotModes(ad.handles.applevels, ad.handles.app_modes_val, 'app');
if val<=length(ad.handles.app_modes_val)
    highlightMode(val, ad.handles.applevels);
end
setappdata(0, 'ModelViewerData', ad);
% if ad.View3DFlag
%     UpdatePlotsTo3D;
% end
%%%%%
%
%
%%%%%
function doResetAllShape(reset, evd) %#ok<INUSD,INUSD>
ad =getappdata(0, 'ModelViewerData');
val = ad.currentShapeMode;
ad.handles.shape_modes_val = zeros(size(ad.handles.shape_modes_val));
set(ad.handles.shape_pc_slider, 'Value', 0);
setappdata(0, 'ModelViewerData', ad);
plotModel;
ad =getappdata(0, 'ModelViewerData');
doPlotModes(ad.handles.shapelevels, ad.handles.shape_modes_val, 'shape');
if val<=length(ad.handles.shape_modes_val)
    highlightMode(val, ad.handles.shapelevels);
end
setappdata(0, 'ModelViewerData', ad);
% if ad.View3DFlag
%     UpdatePlotsTo3D;
% end
%%%%%
%
%
%%%%%
function doResetAllApp(reset, evd) %#ok<INUSD,INUSD>
ad =getappdata(0, 'ModelViewerData');
val = ad.currentAppMode;
ad.handles.app_modes_val = zeros(size(ad.handles.app_modes_val));
set(ad.handles.app_pc_slider, 'Value', 0);
setappdata(0, 'ModelViewerData', ad);
plotModel;
ad =getappdata(0, 'ModelViewerData');
doPlotModes(ad.handles.applevels, ad.handles.app_modes_val, 'app');
if val<=length(ad.handles.app_modes_val)
    highlightMode(val, ad.handles.applevels);
end
setappdata(0, 'ModelViewerData', ad);
% if ad.View3DFlag
%     UpdatePlotsTo3D;
% end
%%%%%
%
%
%%%%%
function doWalkCurrentShapePC(walkcurrbtn, evd) %#ok<INUSD>
ad =getappdata(0, 'ModelViewerData');
slider = ad.handles.shape_pc_slider;
minval = get(slider, 'Min');
maxval = get(slider, 'Max');
step = get(slider, 'SliderStep');
step = step(2);
direction = 1;
val = 0;
while get(walkcurrbtn, 'value') == 1
    ad =getappdata(0, 'ModelViewerData');
    set(slider, 'Value', val);
    val = val + direction*step;
    if val>=maxval  || val<=minval
        direction = direction*-1;
        val = val + direction*step;
    end
    ad.handles.shape_pc_slider = slider;
    setappdata(0, 'ModelViewerData', ad);
    doUpdateShapeMode(ad.handles.shape_pc_slider);
end
return;
%%%%%
%
%
%%%%%
function doWalkCurrentAppPC(walkcurrbtn, evd) %#ok<INUSD>
ad =getappdata(0, 'ModelViewerData');
slider = ad.handles.app_pc_slider;
minval = get(slider, 'Min');
maxval = get(slider, 'Max');
step = get(slider, 'SliderStep');
step = step(2);
direction = 1;
val = 0;
while get(walkcurrbtn, 'value') == 1
    ad =getappdata(0, 'ModelViewerData');
    set(slider, 'Value', val);
    val = val + direction*step;
    if val>=maxval  || val<=minval
        direction = direction*-1;
        val = val + direction*step;
    end
    ad.handles.app_pc_slider = slider;
    setappdata(0, 'ModelViewerData', ad);
    doUpdateAppMode(ad.handles.app_pc_slider);
end
return;
%%%%%
%
%
%%%%%
function doWalkAllShapePC(walkallbtn, evd) %#ok<INUSD>
ad =getappdata(0, 'ModelViewerData');
slider = ad.handles.shape_pc_slider;
minval = get(slider, 'Min');
maxval = get(slider, 'Max');
step = get(slider, 'SliderStep');
step = step(2);
direction = 1;
val = 0;
num_modes = length(ad.handles.shape_modes_val);
walksteps = [0:step:maxval, maxval:-step:minval, minval:step:0];
broken = 0;
for i=ad.currentShapeMode:num_modes
    if get(walkallbtn, 'value')==0
        broken = 1;
        break
    end
    ad.currentShapeMode = i;
    setappdata(0, 'ModelViewerData', ad);
    for ii=walksteps
        if get(walkallbtn, 'value')==0
            break
        end
        ad =getappdata(0, 'ModelViewerData');
        set(slider, 'Value', ii);
        val = val + direction*step;
        if val>=maxval  || val<=minval
            direction = direction*-1;
            val = val + direction*step;
        end
        ad.handles.shape_pc_slider = slider;
        setappdata(0, 'ModelViewerData', ad);
        doUpdateShapeMode(ad.handles.shape_pc_slider);
    end
    ad.handles.shape_modes_val = zeros(size(ad.handles.shape_modes_val));
    setappdata(0, 'ModelViewerData', ad);
end
if broken==0
    set(walkallbtn, 'Value', 0);
end
return;
%%%%%
%
%
%%%%%
function doWalkAllAppPC(walkallbtn, evd) %#ok<INUSD>
ad =getappdata(0, 'ModelViewerData');
slider = ad.handles.app_pc_slider;
minval = get(slider, 'Min');
maxval = get(slider, 'Max');
step = get(slider, 'SliderStep');
step = step(2);
direction = 1;
val = 0;
num_modes = length(ad.handles.app_modes_val);
walksteps = [0:step:maxval, maxval:-step:minval, minval:step:0];
broken = 0;
for i=1:num_modes
    if get(walkallbtn, 'value')==0
        broken = 1;
        break
    end
    ad.currentAppMode = i;
    setappdata(0, 'ModelViewerData', ad);
    for ii=walksteps
        if get(walkallbtn, 'value')==0
            break
        end
        ad =getappdata(0, 'ModelViewerData');
        set(slider, 'Value', ii);
        val = val + direction*step;
        if val>=maxval  || val<=minval
            direction = direction*-1;
            val = val + direction*step;
        end
        ad.handles.app_pc_slider = slider;
        setappdata(0, 'ModelViewerData', ad);
        doUpdateAppMode(ad.handles.app_pc_slider);
    end
    ad.handles.app_modes_val = zeros(size(ad.handles.app_modes_val));
    setappdata(0, 'ModelViewerData', ad);
end
if broken==0
    set(walkallbtn, 'Value', 0);
end
return;
%%%%%
%
%
%%%%%
function doUpdateShapeMode(slider, evd) %#ok<INUSD>
ad =getappdata(0, 'ModelViewerData');
val = ad.currentShapeMode;
if isempty(val) || (val>length(ad.handles.shape_modes_val))
    return;
end
ad.handles.shape_modes_val(val) = get(slider, 'Value');
set(ad.handles.shape_pc_num_txt, 'String', num2str(val));
set(ad.handles.shape_pc_value_txt, 'String', num2str(ad.handles.shape_modes_val(val)));
setappdata(0,'ModelViewerData',ad);
updatePlot;
doPlotModes(ad.handles.shapelevels, ad.handles.shape_modes_val, 'shape');
if val<=length(ad.handles.shape_modes_val)
    highlightMode(val, ad.handles.shapelevels);
end

%%%%%
%
%
%%%%%
function doUpdateAppMode(slider, evd) %#ok<INUSD>
ad =getappdata(0, 'ModelViewerData');
val = ad.currentAppMode;
if isempty(val) || (val>length(ad.handles.app_modes_val))
    return;
end
ad.handles.app_modes_val(val) = get(slider, 'Value');
set(ad.handles.app_pc_num_txt, 'String', num2str(val));
set(ad.handles.app_pc_value_txt, 'String', num2str(ad.handles.app_modes_val(val)));
setappdata(0,'ModelViewerData',ad);
plotModel;
doPlotModes(ad.handles.applevels, ad.handles.app_modes_val, 'app');
if val<=length(ad.handles.app_modes_val)
    highlightMode(val, ad.handles.applevels);
end
%%%%%
%
%
%%%%%

function plotModel
ad =getappdata(0, 'ModelViewerData');
drawnow;
cla(ad.handles.mainAxes);
ad = plotReferenceImage(ad);

hold(ad.handles.mainAxes, 'on');
if get(ad.handles.show_app_model_chk, 'Value')
    ad = plotAppearanceModel(ad);
    hold(ad.handles.mainAxes, 'on');    
end
hold(ad.handles.mainAxes, 'on');
%ad = plotLandmarkNumbers(ad);
ad = plotEdges(ad);
ad = plotShapeModel(ad);
if isfield(ad,'Facets')
    ad = plotSurface(ad,ad.handles.mainAxes,ad.Facets.facs,ad.Facets.labels,ad.Facets.type);
end
hold(ad.handles.mainAxes, 'off');
togglePlotView;
axis(ad.handles.mainAxes, 'equal');


% Begin change by js, 070814
% Begin original code
 
%axis(ad.handles.mainAxes, [ad.xrange(1) ad.xrange(2), ad.yrange(1), ad.yrange(2)]);
% set(ad.handles.mainAxes, 'Color', [0 0 0]);
 
% End original code
% Begin replacement code
 
switch ad.dim
    case 3
        % Plot the isosurface
        ad = plotTemplateSurface(ad);
        axis(ad.handles.mainAxes, [ad.xrange(1) ad.xrange(2), ad.yrange(1) ad.yrange(2), ad.zrange(1) ad.zrange(2)]);
    case 2
        axis(ad.handles.mainAxes, [ad.xrange(1) ad.xrange(2), ad.yrange(1) ad.yrange(2)]);
end
%set(ad.data.edgehandle,'color','k','linewidth',10)
% End replacement code
% End change by js, 070814

setappdata(0, 'ModelViewerData', ad);

if isfield(ad,'View3D')
    if isfield(ad.View3D,'plotaxis')
        cla(ad.View3D.plotaxis(1));
        cla(ad.View3D.plotaxis(2));
    end
    CopyPlotsTo3D;
end
title(ad.handles.mainAxes, '', 'Interpreter', 'none');
drawnow;
%%%%%
%
%
%%%%%
function updatePlot
ad =getappdata(0, 'ModelViewerData');
ad = updateReferenceImage(ad);
if get(ad.handles.show_app_model_chk, 'Value')
    ad = updateAppearanceModel(ad);
end
ad = updateEdges(ad);
ad = updateShapeModel(ad);
if isfield(ad,'Facets')
    ad = updateSurface(ad,ad.handles.mainAxes,ad.Facets.facs);
end
togglePlotView;
axis(ad.handles.mainAxes, 'equal');

% Begin change by js, 070705
% Begin original code
 
% axis(ad.handles.mainAxes, [ad.xrange(1) ad.xrange(2), ad.yrange(1) ad.yrange(2)]);
% set(ad.handles.mainAxes, 'Color', [0 0 0]);
 
% End original code
% Begin replacement code
 
switch ad.dim
    case 3
        ad = updateTemplateSurface(ad);
        axis(ad.handles.mainAxes, [ad.xrange(1) ad.xrange(2), ad.yrange(1) ad.yrange(2), ad.zrange(1) ad.zrange(2)]);
%         set(ad.handles.mainAxes, 'Color', [0 0 0]);
    case 2
        axis(ad.handles.mainAxes, [ad.xrange(1) ad.xrange(2), ad.yrange(1) ad.yrange(2)]);
%         set(ad.handles.mainAxes, 'Color', [0 0 0]);
end
 
% End replacement code
% End change by js, 070705

setappdata(0, 'ModelViewerData', ad);
if isfield(ad,'View3D')
    UpdatePlotsTo3D;
end
title(ad.handles.mainAxes, '', 'Interpreter', 'none');
drawnow;
if ~isempty(ad.moviename)
    h=findobj(ad.figMain,'tag','mainAxes');
    F=getframe(h);%ad.figMain); %mainFig);
    F2=F;
    siz=size(ad.moviefirstframe.cdata);
    F2.cdata=imresize(F.cdata,[siz(1),siz(2)]);
    ad.moviefilehandle=addframe(ad.moviefilehandle,F2);
end
setappdata(0, 'ModelViewerData', ad); % Added by Jake 16/06/2011
%%%%%
%
%
%%%%%
% function setShapeSliders(b)
% ad =getappdata(0, 'ModelViewerData');
% setappdata(0, 'ModelViewerData', ad);
%%%%%
%
%
%%%%%
function ad = plotShapeModel(ad)
if isempty(ad.pdm)
    return;
end
if get(ad.handles.show_landmarks_chk, 'Value')==0
    return;
end
pts = getCurrShapeModel(ad.pdm, ad.handles.shape_modes_val, ad.dim);
X = pts';
X = X(:);

% Calculate the Euclidean Distance from the formed shape to the mean.
diff = norm(ad.pdm.Xm - X(:));
set(ad.handles.eucdisttxt, 'String', num2str(diff));
if ~isempty(ad.segmentPoint)
    pts = splitPoints(pts, ad.segmentPoint, ad.offsets);
end
ad.currentShapeModel = pts;
ad = updateAxisLimits(ad, pts);
switch ad.dim
    case 3
%         ad.data.shape_pts_handle = plot3(ad.handles.mainAxes, pts(:,1), pts(:,2), pts(:,3),...
%             'o', 'MarkerFaceColor', 'y', 'MarkerEdgeColor', 'r');
        blue = [0, 0.5, 1];
        ad.data.shape_pts_handle = plot3(ad.handles.mainAxes, pts(:,1), pts(:,2), pts(:,3),...
            'o', 'MarkerFaceColor', blue, 'MarkerEdgeColor', 'k', 'MarkerSize', 5);
    case 2
        ad.data.shape_pts_handle = plot(ad.handles.mainAxes, pts(:,1), pts(:,2),...
            'o', 'MarkerFaceColor', 'y', 'MarkerEdgeColor', 'r');
        set(ad.data.shape_pts_handle,'MarkerFaceColor', 'k', 'MarkerEdgeColor', 'b','Markersize',5,'linewidth',5);
        %set(ad.handles.mainAxes,'Color','w');% temporary
        %set(ad.figMain,'Color','w');% temporary
        %h=findobj(ad.figMain,'type','uipanel');% temporary
       % set(h,'BackgroundColor','w')% temporary
end

%%%%%
%
%
%%%%%
function ad = updateShapeModel(ad)
if isempty(ad.pdm)
    return;
end
if get(ad.handles.show_landmarks_chk, 'Value')==0
    return;
end
pts = getCurrShapeModel(ad.pdm, ad.handles.shape_modes_val, ad.dim);
X = pts';
X = X(:);
% Calculate the Euclidean Distance from the formed shape to the mean.
diff = norm(ad.pdm.Xm - X(:));
set(ad.handles.eucdisttxt, 'String', num2str(diff));
if ~isempty(ad.segmentPoint)
    pts = splitPoints(pts, ad.segmentPoint, ad.offsets);
end
ad.currentShapeModel = pts;
ad = updateAxisLimits(ad, pts);

switch ad.dim
    case 3
        set(ad.data.shape_pts_handle, ...
            'XData', pts(:,1), ...
            'YData', pts(:,2),...
            'ZData', pts(:,3));
    case 2
        set(ad.data.shape_pts_handle, ...
            'XData', pts(:,1), ...
            'YData', pts(:,2));
end

%%%%%
%
%
%%%%%
function ad = plotLandmarkNumbers(ad);
if isempty(ad.pdm)
    return;
end
if get(ad.handles.edges_chk, 'Value')==0
    return;
end
pts = getCurrShapeModel(ad.pdm, ad.handles.shape_modes_val, ad.dim);
hold on
for i=1:size(pts,1)
    text('parent',ad.handles.mainAxes,'position',pts(i,:),'string',num2str(i),'color','w');
end
return

function ad = plotEdges(ad)
if isempty(ad.pdm)
    return;
end
if get(ad.handles.edges_chk, 'Value')==0
    return;
end
pts = getCurrShapeModel(ad.pdm, ad.handles.shape_modes_val, ad.dim);
if ~isempty(ad.segmentPoint)
    pts = splitPoints(pts, ad.segmentPoint, ad.offsets);
end
if max(ad.edges(:))<=size(pts,1)
    if ad.dim==3
        for i=1:size(ad.edges,1)
%             ad.data.edgehandle(i) = plot3(ad.handles.mainAxes, [pts(ad.edges(i,1),1), pts(ad.edges(i,2), 1)],...
%                 [pts(ad.edges(i,1),2), pts(ad.edges(i,2),2)], [pts(ad.edges(i,1),3), pts(ad.edges(i,2),3)], ...
%                 '-', 'Color', 'w', 'LineWidth', 3, 'MarkerFaceColor', 'y', 'MarkerEdgeColor', 'r');
            ad.data.edgehandle(i) = plot3(ad.handles.mainAxes, [pts(ad.edges(i,1),1), pts(ad.edges(i,2), 1)],...
                [pts(ad.edges(i,1),2), pts(ad.edges(i,2),2)], [pts(ad.edges(i,1),3), pts(ad.edges(i,2),3)], ...
                '-', 'Color', [1, 0, 0], 'LineWidth', 2, 'MarkerFaceColor', 'y', 'MarkerEdgeColor', 'r');
           % ad.data.edgehandle(i) = plot(ad.handles.mainAxes, [pts(ad.edges(i,1),1), pts(ad.edges(i,2), 1)], [pts(ad.edges(i,1),2), pts(ad.edges(i,2),2)], '-', 'Color', 'w', 'LineWidth', 3, 'MarkerFaceColor', 'y', 'MarkerEdgeColor', 'r');
        end
    else
        for i=1:size(ad.edges,1)
            ad.data.edgehandle(i) = plot(ad.handles.mainAxes, [pts(ad.edges(i,1),1), pts(ad.edges(i,2), 1)], [pts(ad.edges(i,1),2), pts(ad.edges(i,2),2)], '-', 'Color', 'w', 'LineWidth', 3, 'MarkerFaceColor', 'y', 'MarkerEdgeColor', 'r');
        end
    end
end
return
%%%%%
%
%
%%%%%
function ad = updateEdges(ad)
if isempty(ad.pdm)
    return;
end
if get(ad.handles.edges_chk, 'Value')==0
    return;
end
pts = getCurrShapeModel(ad.pdm, ad.handles.shape_modes_val, ad.dim);
if ~isempty(ad.segmentPoint)
    pts = splitPoints(pts, ad.segmentPoint, ad.offsets);
end
if ad.dim==3
    for i=1:size(ad.edges,1)
        set(ad.data.edgehandle(i), ...
            'XData', [pts(ad.edges(i,1),1), pts(ad.edges(i,2), 1)],...
            'YData', [pts(ad.edges(i,1),2), pts(ad.edges(i,2),2)],...
            'ZData', [pts(ad.edges(i,1),3), pts(ad.edges(i,2),3)]);
    end
else
    for i=1:size(ad.edges,1)
        set(ad.data.edgehandle(i), ...
            'XData', [pts(ad.edges(i,1),1), pts(ad.edges(i,2), 1)],...
            'YData', [pts(ad.edges(i,1),2), pts(ad.edges(i,2),2)]);
    end
end

return
%%%%%
%
%
%%%%%
function ad=plotSurface(ad,plotaxes,facs,facs_labels,facet_type)
    % either plot or update previously plotted surface model
    % fac, facet definition, one row per triangle facet labelled clockwise
    % vert, vertices referenced by fac, one row per vertex
    % colour, of facet
    % plotaxes, the axes in which the surfaces are to be plotted
    %           there are two if working in 3D
    % M, structure containing handles to the two surfaces
    % J. Andrew Bangham, 2007-8
    if nargin<4
        facs_labels=[];
    end
    if nargin<5
        facet_type='';
    end
    if isempty(ad.pdm)
        return;
    end
    if get(ad.handles.Surface_chk, 'Value')==0
        return;
    end
    if isempty(facs) %~isfield(ad,'fac')
        return;
    end
    pts = getCurrShapeModel(ad.pdm, ad.handles.shape_modes_val, ad.dim);
    X = pts';
    X = X(:);
    % Calculate the Euclidean Distance from the formed shape to the mean.
    diff = norm(ad.pdm.Xm - X(:));
    set(ad.handles.eucdisttxt, 'String', num2str(diff));
    if ~isempty(ad.segmentPoint)
        pts = splitPoints(pts, ad.segmentPoint, ad.offsets);
    end
    ad.currentShapeModel = pts;
    ad = updateAxisLimits(ad, pts);
    colour=[0.9,0.4,0.4];
    pts=pts';
    switch ad.dim
        case 3
%             ad.data.surface_pts_handle =trisurf(facs,pts(1,:),pts(2,:),pts(3,:),...
%                 'FaceColor',colour,'Parent',plotaxes(1),'EdgeColor',colour/1.3);
            
            % Make it green for the thesis
%             colour = [0, 1, 0];
%             ad.data.surface_pts_handle =trisurf(facs,pts(1,:),pts(2,:),pts(3,:),...
%                 'FaceColor', colour ,'Parent',plotaxes(1),'EdgeColor', [0, 0, 0], ...
%                 'FaceLighting', 'flat');
%  
             %
             % Facet colours depend on the model type
             if strcmpi(facet_type,'KarenLeaf')
                 botincludes=[28:40,58,59,55,56];
                 topincludes=[41:53,62,63,65,66];
                 indD=[];
                 indV=[];
                 for i=1:size(facs,1)
                     if ~isempty(intersect(facs(i,:),botincludes))
                         indD(end+1)=i;
                     end
                     if ~isempty(intersect(facs(i,:),topincludes))
                         indV(end+1)=i;
                     end
                 end
                 %tempfacs=facs(indD,:);
                 colour = [0.1, 1, 0.1];
                 cdata = repmat(colour, size(facs, 1), 1);
                 %cdata = repmat(colour, size(tempfacs, 1), 1);
%                  if isfield(ad.data,'surface_pts_handle')
%                      % then clear
%                      set(ad.data.surface_pts_handle,'position',tempfacs);
%                  else
%                      ad.data.surface_pts_handle =trisurf(tempfacs,pts(1,:),pts(2,:),pts(3,:),...
%                          'FaceVertexCData', cdata,'Parent',plotaxes(1),'EdgeColor',colour*0.6, ... colour,...%[0, 0, 0], ...
%                          'FaceLighting', 'flat');
%                  end
                 %tempfacs=facs(indV,:);
                 colour = [0.2, 0.5, 0.3];
                 %cdata = repmat(colour, size(tempfacs, 1), 1);
                 cdata(indV,:)=repmat(colour, size(indV, 2), 1);
%                  if isfield(ad.data,'surface_pts_handle')
%                      % then clear
%                  else
                     ad.data.surface_pts_handle =trisurf(facs,pts(1,:),pts(2,:),pts(3,:),...
                         'FaceVertexCData', cdata,'Parent',plotaxes(1),'EdgeColor',colour*0.9, ... colour,... %[0, 0, 0], ...
                         'FaceLighting', 'flat');
%                  end
                 %axis(gca,'off')
             else
                 indD=[];
                 indV=[];
                 for i=1:size(facs,1)
                     if facs_labels{i,1}=='D'
                         indD(end+1)=i;
                     else
                         indV(end+1)=i;
                     end
                 end
                 tempfacs=facs(indD,:);
                 colour = [0, 1, 0];
                 cdata = repmat(colour, size(tempfacs, 1), 1);
                 ad.data.surface_pts_handle =trisurf(tempfacs,pts(1,:),pts(2,:),pts(3,:),...
                     'FaceVertexCData', cdata,'Parent',plotaxes(1),'EdgeColor', [0, 0, 0], ...
                     'FaceLighting', 'flat');
                 tempfacs=facs(indV,:);
                 colour = [0, 0, 1];
                 cdata = repmat(colour, size(tempfacs, 1), 1);
                 ad.data.surface_pts_handle =trisurf(tempfacs,pts(1,:),pts(2,:),pts(3,:),...
                     'FaceVertexCData', cdata,'Parent',plotaxes(1),'EdgeColor', [0, 0, 0], ...
                     'FaceLighting', 'flat');
             end

%              colour = [0, 1, 0];
%              cdata = repmat(colour, size(facs, 1), 1);
%              ad.data.surface_pts_handle =trisurf(facs,pts(1,:),pts(2,:),pts(3,:),...
%                  'FaceVertexCData', cdata,'Parent',plotaxes(1),'EdgeColor', [0, 0, 0], ...
%                  'FaceLighting', 'flat');
             
            % Add camera head light manually, camlight does not seem to
            % work in this context, which is probably due to the fact that
            % this function, when the check box is being activated, is
            % executed as a callback which prevents any axis other than one
            % in the current figure from being the current axis
%             lightPos  = get(plotaxes(1), 'CameraPosition');
%             light('Position', lightPos, 'Parent', plotaxes(1));
%             light('Position', -lightPos, 'Parent', plotaxes(1));

%             camlight('headlight');
%             drawnow;
            
        case 2

    end
    ad.updated_pts=pts;
%     shading(plotaxes(1),'faceted');
return;
%%%%%
%
%
%%%%%
function ad=updateSurface(ad,plotaxes,facs)
    % either plot or update previously plotted surface model
    % fac, facet definition, one row per triangle facet labelled clockwise
    % vert, vertices referenced by fac, one row per vertex
    % colour, of facet
    % plotaxes, the axes in which the surfaces are to be plotted
    %           there are two if working in 3D
    % M, structure containing handles to the two surfaces
    % J. Andrew Bangham, 2007-8
    if isempty(ad.pdm)
        return;
    end
    if get(ad.handles.Surface_chk, 'Value')==0
        return;
    end
    if isempty(facs) %~isfield(ad,'fac')
        return;
    end
    pts = getCurrShapeModel(ad.pdm, ad.handles.shape_modes_val, ad.dim);
    X = pts';
    X = X(:);
    % Calculate the Euclidean Distance from the formed shape to the mean.
    diff = norm(ad.pdm.Xm - X(:));
    set(ad.handles.eucdisttxt, 'String', num2str(diff));
    if ~isempty(ad.segmentPoint)
        pts = splitPoints(pts, ad.segmentPoint, ad.offsets);
    end
    ad.currentShapeModel = pts;
    ad = updateAxisLimits(ad, pts);
    colour=[0.9,0.4,0.4];
    switch ad.dim
        case 3
            set(ad.data.surface_pts_handle,'Vertices',pts);
        case 2     
    end
    ad.updated_pts=pts;
return;

%%%%%               J.A. Bangham
%                   Updated to view
%                   1) 3D images in 3D
%                   2) 3D mesh model to visualise shapes in 2D and 3D
%
%%%%%

function View3D(View3DBtn,option)
    % Turns 3D view on and off
    % needs 
    %function UpdatePlotsTo3D
    %function CopyPlotsTo3D

    ad =getappdata(0, 'ModelViewerData');
    if get(View3DBtn,'Value')
        ad.View3DFlag=true;
        if isfield(ad,'View3D')
        else
            m=get(0,'MonitorPositions');
            sizepos=700;
            if size(m,1)==1
                ad.View3D.leftPlotFigureh=figure(1);
                set(ad.View3D.leftPlotFigureh,'position',[1,m(1,4)-sizepos-70,sizepos,sizepos]);
                ad.View3D.plotaxis(1)=axes;
                ad.View3D.RightPlotFigureh=figure(2);
                set(ad.View3D.RightPlotFigureh,'position',[sizepos+1,m(1,4)-sizepos-70,sizepos,sizepos]);
                ad.View3D.plotaxis(2)=axes;
            else
                ad.View3D.leftPlotFigureh=figure(1);
                set(ad.View3D.leftPlotFigureh,'position',[1,m(1,4)-sizepos-70,sizepos,sizepos]);
                ad.View3D.plotaxis(1)=axes;
                ad.View3D.RightPlotFigureh=figure(2);
                set(ad.View3D.RightPlotFigureh,'position',[m(2,1),m(1,4)-sizepos-70,sizepos,sizepos]);
                ad.View3D.plotaxis(2)=axes;
            end
            ad.View3D.plotaxis
            setappdata(0, 'ModelViewerData', ad);
            % copy the objects in the GUI axes to these new axes
            CopyPlotsTo3D;
%             UpdatePlotsTo3D;
            ad =getappdata(0, 'ModelViewerData');
        end
    else
        ad.View3DFlag=false;
        if isfield(ad,'View3D')
            if get(ad.handles.Rotate3D,'Value')
                cancel_trackball=true;
                eventData=[];
                trackballButtonDownFcn( ad.View3D.plotaxis(1), eventData,  cancel_trackball);
            end
            set(ad.handles.Rotate3D,'Value',0);
            if isfield(ad.View3D,'leftPlotFigureh')
                if ishandle(ad.View3D.leftPlotFigureh)
                    close(ad.View3D.leftPlotFigureh);
                end
                if ishandle(ad.View3D.RightPlotFigureh)
                    close(ad.View3D.RightPlotFigureh);
                end
            end
            ad=rmfield(ad,'View3D');
        end
    end
    setappdata(0, 'ModelViewerData', ad);
return

function Rotate3D(Rotate3DBtn,option)    % Bangham
    % Turns 3D rotation on (press left button and drag) and off (right
    % button)
    %This is all that is needed to run the stereo 3D rotate
    ad =getappdata(0, 'ModelViewerData');
    last_point=[];
    leftaxis=ad.View3D.plotaxis(1); %AppData.handles.axes1;
    rightaxis=ad.View3D.plotaxis(2);%AppData.handles.axes2;
    disp('Rotate')
    if get(gco,'Value')
        vergence=0.02 %get(AppData.handles.Disparity,'Value'); %1/12;
        trackball=true;
        %set mouse button callbacks ... WindowButtonDownFcn which should
        Initialise_stereoPairAxes( leftaxis, rightaxis, vergence, trackball, gco );
    else
        %clear mouse button callbacks
        cancel_trackball=true;
        eventData=[];
        trackballButtonDownFcn( leftaxis, eventData,  cancel_trackball);
    end
    setappdata(0, 'ModelViewerData', ad);
return;

function UpdatePlotsTo3D
    ad =getappdata(0, 'ModelViewerData');
    %     h=get(ad.handles.mainAxes,'children');
    if length(ad.View3D.NonPatchObjects.h)>0
        h=ad.View3D.NonPatchObjects.h;
        hc1=ad.View3D.NonPatchObjects.lefth;
        hc2=ad.View3D.NonPatchObjects.righth;
        for i=1:length(h)
            xd=get(h(i),'Xdata');
            yd=get(h(i),'Ydata');
            zd=get(h(i),'Zdata');
            set(hc1(i),'Xdata',xd);
            set(hc2(i),'Xdata',xd);
            set(hc1(i),'Ydata',yd);
            set(hc2(i),'Ydata',yd);
            set(hc1(i),'Zdata',zd);
            set(hc2(i),'Zdata',zd);
        end
    end
    if length(ad.View3D.PatchObjects.h)>0
        h=ad.View3D.PatchObjects.h;
        hc1=ad.View3D.PatchObjects.lefth;
        hc2=ad.View3D.PatchObjects.righth;
        facs=ad.Facets.facs;
        %for i=1:length(h)
            xp=ad.updated_pts(:,1);%,:); %get(ad.View3D.PatchObjects.h(k),'XData');
            yp=ad.updated_pts(:,2);%,:); %get(ad.View3D.PatchObjects.h(k),'YData');
            zp=ad.updated_pts(:,3);%,:); %get(ad.View3D.PatchObjects.h(k),'ZData');
            if iscell(hc1(1))
                colour=get(hc1{1},'FaceColor');
                delete(hc1{1});
            else
                colour=get(hc1(i),'FaceColor');
                delete(hc1(1));
            end
            hold(ad.View3D.plotaxis(1),'on');

            % Begin change by JS 140808
            % Begin original code

            %             handle=trisurf(facs,xp,yp,zp,colour,...
            %                 'FaceColor',colour,'Parent',ad.View3D.plotaxis(1),'EdgeColor',colour/1.3);

            % End original code
            % Begin replacement code

            % The shading(plotaxes(1),'faceted'); command on line 1486
            % has caused the 'Color' property to be set to 'flat' which
            % leads to problems in the above statement. Hence I have
            % omitted all the colour related arguments

            handle=trisurf(facs,xp,yp,zp,...
                'Parent',ad.View3D.plotaxis(1));

            % Also update the axis limits
%             axis(ad.View3D.plotaxis(1), [ad.xrange(1) ad.xrange(2), ad.yrange(1) ad.yrange(2)]);


            % End replacement code
            %Begin change by JS 140808

            ad.View3D.PatchObjects.lefth{1}=handle;

            if iscell(hc2(1))
                colour=get(hc2{1},'FaceColor');
                delete(hc2{1});
            else
                colour=get(hc2(1),'FaceColor');
                delete(hc2(1));
            end
            hold(ad.View3D.plotaxis(2),'on');
            
            % Begin change by JS 140808
            % Begin original code

            %             handle=trisurf(facs,xp,yp,zp,colour,...
            %                 'FaceColor',colour,'Parent',ad.View3D.plotaxis(2),'EdgeColor',colour/1.3);
            %
            % End original code
            % Begin replacement code

            handle=trisurf(facs,xp,yp,zp,...
                'Parent',ad.View3D.plotaxis(2));
            
            % Also update the axis limits
%             axis(ad.View3D.plotaxis(2), [ad.xrange(1) ad.xrange(2), ad.yrange(1) ad.yrange(2)]);

            % End replacement code
            %Begin change by JS 140808

            ad.View3D.PatchObjects.righth{1}=handle;
            %end
    end
    setappdata(0, 'ModelViewerData', ad);
return;
%             xd=ad.updated_pts(:,1); %get(h(i),'Xdata');
%             yd=ad.updated_pts(:,2); %get(h(i),'Ydata');
%             zd=ad.updated_pts(:,3); %get(h(i),'Xdata');
%             if iscell(hc1(i))
%                 set(hc1{i},'Vertices',ad.updated_pts);
%                 set(hc2{i},'Vertices',ad.updated_pts);
% %                 set(hc1{i},'Xdata',xd);
% %                 set(hc2{i},'Xdata',xd);
% %                 set(hc1{i},'Ydata',yd);
% %                 set(hc2{i},'Ydata',yd);
% %                 set(hc1{i},'Xdata',zd);
% %                 set(hc2{i},'Xdata',zd);
%             else
%                 set(hc1(i),'Vertices',ad.updated_pts);
%                 set(hc2(i),'Vertices',ad.updated_pts);
% %                 set(hc1(i),'Xdata',xd);
% %                 set(hc2(i),'Xdata',xd);
% %                 set(hc1(i),'Ydata',yd);
% %                 set(hc2(i),'Ydata',yd);
% %                 set(hc1(i),'Xdata',zd);
% %                 set(hc2(i),'Xdata',zd);


% %     x=get(h(1),'XData');
%     hc1=ad.View3D.Objects{1};
%     disp(sprintf('i=%d h=%f',1, hc1(1)));
% %     x1=get(hc1(1),'XData');
% %     for i=1:min(5,length(x1))
% %         disp(sprintf('i=%d x=%d x1=%d',i,round(x(i)),round(x1(i))))
% %     end
%     hc2=ad.View3D.Objects{2};
% 
%     for i=1:length(h)
%         xd=get(h(i),'Xdata');
%         set(hc1(i),'Xdata',xd);
%         set(hc2(i),'Xdata',xd);
%         yd=get(h(i),'Ydata');
%         set(hc1(i),'Ydata',yd);
%         set(hc2(i),'Ydata',yd);
%         zd=get(h(i),'Xdata');
%         set(hc1(i),'Xdata',zd);
%         set(hc2(i),'Xdata',zd);
%     end

function CopyPlotsTo3D
    % copy everything in the GUI plot axis to the two Figs needed for 3D
    % stores the relevant data in field View3D
    % once plotted, the data is updated inplace, see UpdatePlotsTo3D
    % Also sets up the two viewpoints needed for 3D
    ad =getappdata(0, 'ModelViewerData');
    h=get(ad.handles.mainAxes,'children');
%     x=get(h(1),'XData');
    color=get(ad.handles.mainAxes,'Color');
    set(ad.View3D.plotaxis(1),'Color',color);
    set(ad.View3D.plotaxis(2),'Color',color);
    types=get(h,'type');
    ind=strfind(types,'patch');
    patch_ind=[];
    for j=1:length(ind)
        if iscell(ind)
            if ~isempty(ind{j})
                patch_ind(end+1)=j;
            end
        else
            if ~isempty(ind(j))
                patch_ind(end+1)=j;
            end                
        end
    end
    notpatch_ind=setdiff(1:length(ind),patch_ind);
    if length(notpatch_ind)>0
        ad.View3D.NonPatchObjects.h=h(notpatch_ind);
        ad.View3D.NonPatchObjects.lefth=copyobj(ad.View3D.NonPatchObjects.h,ad.View3D.plotaxis(1));
        ad.View3D.NonPatchObjects.righth=copyobj(ad.View3D.NonPatchObjects.h,ad.View3D.plotaxis(2));
    else
        ad.View3D.NonPatchObjects.h=[];
    end
    % one can copy a patch,
    % but apparently not update vertices in the copy
    % so create new patches using data fresh vertex coordinates
    if length(patch_ind)
        ad.View3D.PatchHandles=h(patch_ind);
        if length(ad.View3D.PatchHandles)>0
            ad.View3D.PatchObjects.h=ad.View3D.PatchHandles;
            ad.View3D.PatchObjects.lefth=[];
            ad.View3D.PatchObjects.righth=[];
            facs=ad.Facets.facs;
            for k=1:length(ad.View3D.PatchObjects.h)
                xp=ad.updated_pts(1,:);
                yp=ad.updated_pts(2,:);
                zp=ad.updated_pts(3,:);
                colour=get(ad.View3D.PatchObjects.h(k),'FaceColor');
                hold(ad.View3D.plotaxis(2),'on');

                % Begin change by JS 140808
                % Begin original code
                
%                 handle=trisurf(facs,xp,yp,zp,colour,...
%                     'FaceColor',colour,'Parent',ad.View3D.plotaxis(2),'EdgeColor',colour/1.3);
                
                % End original code
                % Begin replacement code
                
                % The shading(plotaxes(1),'faceted'); command on line 1486
                % has caused the 'Color' property to be set to 'flat' which
                % leads to problems in the above statement. Since the
                % the initial colour is not preserved anyway I omitted all
                % the colour related arguments that lead to errors
                
                handle=trisurf(facs,xp,yp,zp,...
                    'Parent',ad.View3D.plotaxis(2));
                
                % Also update the axis limits
%                 axis(ad.View3D.plotaxis(2), [ad.xrange(1) ad.xrange(2), ad.yrange(1) ad.yrange(2)]);


                % End replacement code
                % End change by JS 140808

                ad.View3D.PatchObjects.righth{end+1}=handle;
                hold(ad.View3D.plotaxis(1),'on');

                % Begin change by JS 140808
                % Begin original code
                %                 handle=trisurf(facs,xp,yp,zp,colour,...
                %                     'FaceColor',colour,'Parent',ad.View3D.plotaxis(1),'EdgeColor',colour/1.3);

                % End original code
                % Begin replacement code

                % As above
                handle=trisurf(facs,xp,yp,zp,...
                    'Parent',ad.View3D.plotaxis(1));
                
                % Also update the axis limits
%                 axis(ad.View3D.plotaxis(2), [ad.xrange(1) ad.xrange(2), ad.yrange(1) ad.yrange(2)]);

                % End replacement code
                % End change by JS 140808

                ad.View3D.PatchObjects.lefth{end+1}=handle;
            end
        end
    else
        ad.View3D.PatchObjects.h=[];
    end
%     ad.View3D.Objects(1)={newh};
%     newh=copyobj(h,ad.View3D.plotaxis(2));
%     ad.View3D.Objects(2)={newh};
    plotaxes=ad.View3D.plotaxis;
    CameraPosition=get(ad.handles.mainAxes,'CameraPosition');
    CameraTarget=get(ad.handles.mainAxes,'CameraTarget');
    CameraUpVector=get(ad.handles.mainAxes,'CameraUpVector');
    CameraViewAngle=3*get(ad.handles.mainAxes,'CameraViewAngle');
    XLim=3*get(ad.handles.mainAxes,'XLim');
    YLim=3*get(ad.handles.mainAxes,'YLim');
    ZLim=3*get(ad.handles.mainAxes,'ZLim');
    XLimMode=get(ad.handles.mainAxes,'XLimMode');
    YLimMode=get(ad.handles.mainAxes,'YLimMode');
    ZLimMode=get(ad.handles.mainAxes,'ZLimMode');
    
    % Begin change by JS 140808
    
    % Do axis equal here. Previously this was done after plotting which
    % lead to an implicit axis tight
    axis(plotaxes(1), 'equal');
    axis(plotaxes(2), 'equal');
    % End change by JS 140808
    
    set(plotaxes(1),'CameraPosition',CameraPosition,'CameraTarget',CameraTarget,...
        'CameraUpVector',CameraUpVector,'CameraViewAngle',CameraViewAngle,...
        'XLim',XLim,'YLim',YLim,'ZLim',ZLim,...
        'XLimMode',XLimMode,'YLimMode',YLimMode,'ZLimMode',ZLimMode)
    set(plotaxes(2),'CameraPosition',CameraPosition,'CameraTarget',CameraTarget,...
        'CameraUpVector',CameraUpVector,'CameraViewAngle',CameraViewAngle,...
        'XLim',XLim,'YLim',YLim,'ZLim',ZLim,...
        'XLimMode',XLimMode,'YLimMode',YLimMode,'ZLimMode',ZLimMode)
    ad.View3D.disparity=0.03;
        
    % Begin change by JS 140808
    % Don't axis equal here as it somehow leads to an implicit axis tight
%     axis(plotaxes(1), 'equal');
%     axis(plotaxes(2), 'equal');
 	% End change by JS 140808
    
%     q=1.8;
%     m=max(abs([ad.xrange,ad.yrange,ad.zrange]));
%     axis(plotaxes(1), [-m m, -m m, -m m]);
%     axis(plotaxes(2), [-m m, -m m, -m m]);
    for ii=1:length(plotaxes)
        hold(plotaxes(ii),'off');
        if ii==1
            disparity=0; %get(AppData.handles.Disparity,'Value');
        elseif ii==2
            disparity=ad.View3D.disparity;
        end
        stereoTransfer( plotaxes(ii), ...
            get( plotaxes(1),'CameraPosition'), ...
            get( plotaxes(1),'CameraTarget'), ...
            get( plotaxes(1),'CameraUpVector'), ...
            disparity );
    end
    setappdata(0, 'ModelViewerData', ad);
return;

function Zero3D(Zero3DBtn,option) % 38 40
%     Disparity=get(AppData.handles.Disparity,'Value');
    plotaxes(1)=AppData.handles.axes1;
    if ~isempty(AppData.handles.axes2)
        plotaxes(2)=AppData.handles.axes2;
    end
    AppData.axis=[-AppData.MaxLim/3 AppData.MaxLim/3 -AppData.MaxLim/3 AppData.MaxLim/3 -(+1000) (AppData.MaxLim-0)];
    if option==0
        set(AppData.handles.axes1,'View',[90 0]);
    else
        set(AppData.handles.axes1,'View',[38 40]);
    end
    AppData.axis=[-AppData.MaxLim/3 AppData.MaxLim/3 -AppData.MaxLim/3 AppData.MaxLim/3 -(+1000) (AppData.MaxLim-0)];
    for ii=1:length(plotaxes)
        set(plotaxes(ii),'XGrid','off','YGrid','off','ZGrid','off','View',[90 0],...
                    'XLim',AppData.axis(1:2),'YLim',AppData.axis(1:2),'ZLim',AppData.axis(5:6))
        if ii==1
            disparity=0; %get(AppData.handles.Disparity,'Value');
        elseif ii==2
            disparity=get(AppData.handles.Disparity,'Value');
        end
        stereoTransfer( plotaxes(ii), ...
            get( plotaxes(1),'CameraPosition'), ...
            get( plotaxes(1),'CameraTarget'), ...
            get( plotaxes(1),'CameraUpVector'), ...
            disparity );
    end
return

function Rock3D(Rock3DBtn,option)
    ad =getappdata(0, 'ModelViewerData');
   plotaxis(1)=ad.handles.mainAxes;
   if isfield(ad,'View3D')
       if isfield(ad.View3D,'plotaxis')
           for i=1:length(ad.View3D.plotaxis)
               if ishandle(ad.View3D.plotaxis(i))
                   plotaxis(end+1)=ad.View3D.plotaxis(i);
               end
           end
       end
   end
    if get(ad.handles.Rock3D,'Value')
        set(ad.handles.View3D,'Enable','off');
        ad.View3D.RockDone=false;
        tic;
        i=0;
        j=0;
        di=0.07;
        dj=di*0.95;
        Ramp=0.1;
        while ad.View3D.RockDone==false
            t=toc;
            amp=0.05; %Ramp*get(AppData.handles.RockAmp,'Value');
            si=sin(i)*amp;
            sj=cos(j)*amp;
            for i=1:length(plotaxis)
                camorbit(plotaxis(i),si,sj,'data',[0 0 1]);
            end
%             if ~isempty(plotaxis(2))
%                 camorbit(plotaxis(2),si,sj,'data',[0 0 1]);
%             end
            i=i+di;
            j=j+dj;
            drawnow;
            while t<0.01
                t=toc;
            end
            ad.View3D.RockDone=~get(ad.handles.Rock3D,'Value');
            tic;
        end
    else
        set(ad.handles.View3D,'Enable','on');
        ad.View3D.RockDone=true;
    end
    setappdata(0, 'ModelViewerData',ad);
return

%------ what follows is stereo view and trackball control ------


function Initialise_stereoPairAxes( ax1, ax2, vergence, trackball, rotate_check_handle )
%Entirely based on JRK stereoPairAxes
%
%Initialise_stereoPairAxes( ax1, ax2, vergence, trackball )
% ax1, ax2 axes to be made a stereo pair
% vergence, typically 1/12
% trackball, default is false, else true and trackball will install
%            i.e. left click and drag to rotate axes
%                 right click to cancel rotate until next initialisation
%
%stereoPairAxes( ax1, ax2, vergence, trackball )
%   Make the two axes objects into a stereo trackball pair, by storing in
%   the guidata of each a reference to the other and the angle of
%   convergence.  ax1 is assumed to be the left eye view and ax2 the right
%   eye view, in which case vergence should be positive.
%
%   The trackball argument is optional and defaults to false.  If true,
%   trackballButtonDownFcn is installed as the ButtonDownFcn in both axes
%   objects and all their children.  Clicking and dragging on either
%   window will rotate both views together.  If you only want trackball
%   functionality part of the time, then you should not install it here, but
%   call trackballButtonDownFcn from your own ButtonDownFcn when you want
%   trackball behaviour.
    if nargin < 4
        trackball = false;
    end
    gd1 = guidata( ax1 );
    old_ButtonDownFcn=get(ax1,'ButtonDownFcn');
    child_old_ButtonDownFcn=get(get(ax1,'Children'),'ButtonDownFcn');
    gd1.stereodata = struct( 'otheraxes', ax2, 'vergence', vergence );
    gd1.old_ButtonDownFcn=old_ButtonDownFcn;
    gd1.child_old_ButtonDownFcn=child_old_ButtonDownFcn;
    gd1.rotate_check_handle=rotate_check_handle;
    guidata( ax1, gd1 );
    if trackball
        set( ax1, 'ButtonDownFcn', @trackballButtonDownFcn );
        set( get(ax1,'Children'), 'ButtonDownFcn', @trackballButtonDownFcn );
    end
    if ~isempty(ax2)
        gd2 = guidata( ax2 );
        old_ButtonDownFcn=get(ax2,'ButtonDownFcn');
        child_old_ButtonDownFcn=get(get(ax2,'Children'),'ButtonDownFcn');
        gd2.stereodata = struct( 'otheraxes', ax1, 'vergence', -vergence );
        gd2.old_ButtonDownFcn=old_ButtonDownFcn;
        gd2.child_old_ButtonDownFcn=child_old_ButtonDownFcn;
        gd2.rotate_check_handle=rotate_check_handle;
        guidata( ax2, gd2 );
        if trackball
            set( ax2, 'ButtonDownFcn', @trackballButtonDownFcn );
            set( get(ax2,'Children'), 'ButtonDownFcn', @trackballButtonDownFcn );
        end
    end
return;

function trackballButtonDownFcn( hObject, eventData, cancel_trackball )
%trackballButtonDownFcn( hObject, eventData, cancel_trackball)
%   Installing this as the ButtonDownFcn for an axes object or its children
%   will cause a click on the object to produce trackball-like behaviour
%   when the mouse is dragged.
%
%   The trackball feature is cancelled either by clicking the right button
%   or by making a call with hObject set to the left (or only) axis
%   and cancel_trackball set to true.

%   This routine temporarily stores all the information it needs to process the
%   mouse movement, in the field 'trackballData' of the guidata of the figure.
%   The field is deleted when the mouse button is released.
%   As a side-effect, all of the camera mode properties of the axes are set
%   to manual.
%
%   There is more than one way to map mouse movement to rotation, and the
%   choice is a matter of design.  Three mappings are implemented, and the choice
%   can be specified by setting the 'trackballMode' field of guidata.
%   'global' (the default) maps trackball coordinates [x,y] to a rotation about
%   an axis perpendicular to that vector in the (cameraright,cameraup) plane, by
%   an amount proportional to the length of the vector.
%   'local' maps incremental motion of the mouse to incremental rotation in
%   the same way.
%   'upright' maps trackball coordinates [x,y] to azimuth and elevation,
%   maintaining the camera up vector equal to [0 0 1].  This is equivalent
%   to the trackball mode available from the standard camera toolbar,
%   except that the scaling may be different.
%
%   Global and Upright mode have the advantage that mouse positions are uniquely
%   mapped to rotations: moving the mouse back to its starting point
%   restores the axes to its original orientation.
%   Local mode has the advantage that the current rotation axis is always
%   perpendicular to the current mouse velocity.
%   There is no mapping of trackball data to axes rotation that allows both
%   of these.
%
%   The scaling factor is currently set so that movement by a distance
%   equal to the smaller of the width and height of the axes object rotates
%   it by 2 radians.  A different value can be set by setting the
%   'trackballScale' field of the figure's guidata to the requried value.

% Find the axes.
if nargin<3
    cancel_trackball=false
end
while ~(isempty(hObject)) && ishandle(hObject) && ~strcmp(get(hObject,'Type'), 'axes')
    hObject = get( hObject, 'Parent' );
end
if ~ishandle(hObject), return; end

% Find the figure.
hFigure = get( hObject, 'Parent' );
while ishandle(hFigure) && ~strcmp(get(hFigure,'Type'), 'figure')
    hFigure = get( hFigure, 'Parent' );
end
if ~ishandle(hFigure), return; end
if cancel_trackball || strcmp(get( hFigure,'SelectionType'),'alt')
    % right button click to disable rotate until next time system is
    % initialised
    gd=guidata(hObject);
    ax1=gd.old_ButtonDownFcn;
    ax2=gd.child_old_ButtonDownFcn;
    if ~any(ishandle(ax2))
        ax2='';
    end
    set(gd.rotate_check_handle,'Value',0);
    set( hObject, 'ButtonDownFcn', ax1 );
    set( get(hObject,'Children'), 'ButtonDownFcn', ax2 );
    if isfield( gd, 'stereodata' )
        if ~isempty(gd.stereodata.otheraxes)
            gd2=guidata(gd.stereodata.otheraxes);
            ax1=gd2.old_ButtonDownFcn;
            ax2=gd2.child_old_ButtonDownFcn;
            if ~any(ishandle(ax2))
                ax2='';
            end
            set(gd2.rotate_check_handle,'Value',0);
            set( gd.stereodata.otheraxes, 'ButtonDownFcn', ax1 );
            set( get(gd.stereodata.otheraxes,'Children'), 'ButtonDownFcn', ax2 );
        end
    end
else
    % Get all the information we need.
    hitPointParent = get( hFigure, 'CurrentPoint' );
    oldUnits = get( hObject, 'Units' );
    set( hObject, 'Units', 'pixels' );
    axespos = get( hObject, 'Position' );
    set( hObject, 'Units', oldUnits );
    axessize = min(axespos([3 4]));

    cameraTarget = get( hObject, 'CameraTarget' );
    cameraPosition = get( hObject, 'CameraPosition' );
    [cameraLook, cameraUp, cameraRight] = cameraFrame( ...
        cameraPosition, ...
        cameraTarget, ...
        get( hObject, 'CameraUpVector' ) );

    % Store it in guidata.
    gd = guidata(hFigure);
    if isfield( gd, 'trackballScale' )
        trackballScale = gd.trackballScale;
    else
        trackballScale = 2;
    end
    if isfield( gd, 'trackballMode' )
        trackballMode = gd.trackballMode;
    else
        trackballMode = 'global';
    end
    gd.trackballData = struct( 'axes', hObject, ...
        'startpoint', hitPointParent, ...
        'currentpoint', hitPointParent, ...
        'axessize', axessize, ...
        'cameraLook', cameraLook, ...
        'cameraUp', cameraUp, ...
        'cameraRight', cameraRight, ...
        'cameraTarget', cameraTarget, ...
        'cameraPosition', cameraPosition, ...
        'trackballScale', trackballScale, ...
        'trackballMode', trackballMode, ...
        'oldWindowButtonMotionFcn', get( hFigure, 'WindowButtonMotionFcn' ), ...
        'oldWindowButtonUpFcn', get( hFigure, 'WindowButtonUpFcn' ) );
    guidata( hFigure, gd );
    set( hFigure, ...
        'WindowButtonMotionFcn', @trackballButtonMotionFcn, ...
        'WindowButtonUpFcn', @trackballButtonUpFcn );
    set( hObject, ...
        'CameraPositionMode', 'manual', ...
        'CameraTargetMode', 'manual', ...
        'CameraUpVector', cameraUp, ...
        'CameraUpVectorMode', 'manual', ...
        'CameraViewAngleMode', 'manual' );
    if isfield( gd, 'stereodata' )
        stereoTransfer( hObject, gd.stereodata.otheraxes, gd.stereodata.vergence );
    end
end
return;

function trackballButtonMotionFcn( hObject, eventData )
    gd = guidata( hObject );
    if isempty( gd ) || ~isfield( gd, 'trackballData' ), return; end
    currentpoint = get( hObject, 'CurrentPoint' );
    switch gd.trackballData.trackballMode
        case 'global'
            delta = (currentpoint - gd.trackballData.startpoint)/gd.trackballData.axessize;
        otherwise % case { 'local', 'upright' }
            delta = (currentpoint - gd.trackballData.currentpoint)/gd.trackballData.axessize;
    end
    [cameraPos,cameraUp,cameraRight] = ...
        trballView( gd.trackballData, [-delta(1), delta(2)], ...
                    gd.trackballData.trackballScale );
    if strcmp( gd.trackballData.trackballMode, 'upright' )
        cameraUp = [0 0 1];
    end
    gd.trackballData.currentpoint = currentpoint;
    switch gd.trackballData.trackballMode
        case 'global'
            %nothing
        otherwise % case { 'local', 'upright' }
            gd.trackballData.cameraPosition = cameraPos;
            gd.trackballData.cameraUp = cameraUp;
            gd.trackballData.cameraRight = cameraRight;
    end
    set( gd.trackballData.axes, ...
        'CameraPosition', cameraPos, ...
        'CameraPositionMode', 'manual', ...
        ... % 'CameraTarget', ??, ...
        'CameraTargetMode', 'manual', ...
        'CameraUpVector', cameraUp, ...
        'CameraUpVectorMode', 'manual', ...
        ... % 'CameraViewAngle', ??, ...
        'CameraViewAngleMode', 'manual' );
    if isfield( gd, 'stereodata' )
        stereoTransfer( gd.stereodata.otheraxes, ...
                        cameraPos, ...
                        get( gd.trackballData.axes, 'CameraTarget' ), ...
                        cameraUp, ...
                        gd.stereodata.vergence );
    end
    guidata( hObject, gd );
return;

function trackballButtonUpFcn( hObject, eventData )
    % Process the final mouse position.
    % Tests indicate that this is not necessary -- the final mouse position
    % always generates a ButtonMotion event.
    % trackballButtonMotionFcn( hObject, eventData )

    % Restore the original ButtonMotion and ButtonUp functions.
    % Delete the trackball data.
    gd = guidata( hObject );
    if ~isempty(gd) && isfield( gd, 'trackballData' )
        set( hObject, 'WindowButtonMotionFcn', gd.trackballData.oldWindowButtonMotionFcn );
        set( hObject, 'WindowButtonUpFcn', gd.trackballData.oldWindowButtonUpFcn );
        gd = rmfield( gd, 'trackballData' );
        guidata( hObject, gd );
    end
return;

function [cameraPos,cameraUp,cameraRight] = trballView( trdata, trball, trballscale )
%[cameraPos,cameraUp] = trballView( initview, trball, trballscale )
%   initview is a structure containing
%       cameraRight
%       cameraUp
%   trball is a pair of real numbers indicating the amount of trackball
%   movement in two dimensions.  These represent a rotation about an axis
%   in the view plane perpendicular to the trball vector.  The scaling is 1
%   unit = trballscale radians. cameraPos and cameraUp are set to the new
%   camera position and up-vector specified by the trackball value.

    if all(trball==0)
        cameraPos = trdata.cameraPosition;
        cameraUp = trdata.cameraUp;
        cameraRight = trdata.cameraRight;
    else
        rotAxis = trball(2)*trdata.cameraRight + trball(1)*trdata.cameraUp;
        rotAxis = rotAxis/norm(rotAxis);
        rotAmount = norm(trball) * trballscale;

        % Rotate cameraPosition about rotAxis through cameraTarget by
        % rotAmount.
        cameraPos = rotVec( trdata.cameraPosition, trdata.cameraTarget, rotAxis, rotAmount );

        % Rotate cameraPosition about rotAxis by rotAmount.
        cameraUp = rotVec( trdata.cameraUp, [0 0 0], rotAxis, rotAmount );

        % Rotate cameraRight about rotAxis by rotAmount.
        cameraRight = rotVec( trdata.cameraRight, [0 0 0], rotAxis, rotAmount );
    end
return;

function [CameraPosition, CameraTarget, CameraUpVector] = stereoTransfer( varargin )
%stereoTransfer( varargin )
%   Set the viewpoint of one axes to that of another, rotated about the
%   camera up vector.
%
%   stereoTransfer(AX) will transfer the view of the axes AX to the axes
%       contained in AX's guidata element stereodata.otheraxes, rotated by
%       stereodata.vergence (an angle in radians).
%   stereoTransfer() is equivalent to stereoTransfer(gca).
%   stereoTransfer( AX1, AX2, VERGENCE ) will transfer the view from AX1 to
%       AX2, offset by the angle VERGENCE.
%   stereoTransfer( AX, POSITION, TARGET, UP, VERGENCE ) will set the view
%       of the axes AX to the result of offsetting the view by a rotation
%       about UP by VERGENCE, from the view specified by the given camera
%       POSITION, TARGET, and UP vectors.
%
%   In all cases, vergence must be an angle in radians.  If the view is
%   being transferred from the left eye to the right eye, vergence should
%   be positive.  If the distance between someone's eye is E and they are
%   a distance D from the screen, vergence should be E/D radians.
%
%   The resulting view is returned in the output arguments.

    error(nargchk(0, 5, nargin, 'struct'));
    theaxes = [];
    switch nargin
        case { 0, 1 }
            if nargin==0
                theaxes = gca;
            else
                theaxes = varargin{1};
            end
            CameraPosition = get( theaxes,'CameraPosition' );
            CameraTarget = get( theaxes,'CameraTarget' );
            CameraUpVector = get( theaxes,'CameraUpVector' );
            gd = guidata( theaxes );
            if isempty(gd), return; end
            if ~isfield( gd, 'stereodata' ), return; end
            sd = gd.stereodata;
            otheraxes = sd.otheraxes;
            vergence = sd.vergence;
        case 3
            theaxes = varargin{1};
            CameraPosition = get( theaxes,'CameraPosition' );
            CameraTarget = get( theaxes,'CameraTarget' );
            CameraUpVector = get( theaxes,'CameraUpVector' );
            otheraxes = varargin{2};
            vergence = varargin{3};
        case 5
            otheraxes = varargin{1};
            CameraPosition = varargin{2};
            CameraTarget = varargin{3};
            CameraUpVector = varargin{4};
            vergence = varargin{5};
        otherwise
            error( 'stereoTransfer: wrong number of arguments, 3 or 5 expected.' );
    end
    CameraUpVector = makeperp( CameraTarget-CameraPosition, CameraUpVector );
    CameraUpVector = CameraUpVector/norm(CameraUpVector);

    % Rotate Position about Up by vergence
    CameraPosition = rotVec( CameraPosition, CameraTarget, CameraUpVector, vergence );
    set( otheraxes, ...
        'CameraPosition', CameraPosition, ...
        'CameraTarget', CameraTarget, ...
        'CameraUpVector', CameraUpVector, ...
        'CameraPositionMode', 'manual', ...
        'CameraTargetMode', 'manual', ...
        'CameraUpVectorMode', 'manual', ...
        'CameraViewAngleMode', 'manual' );
    if theaxes
        set( theaxes, 'CameraUpVector', CameraUpVector );
        set( otheraxes, 'CameraViewAngle', get( theaxes,'CameraViewAngle' ) );
    end
return;

function stereoPairAxes( ax1, ax2, vergence, trackball )
%stereoPairAxes( ax1, ax2, vergence, trackball )
%   Make the two axes objects into a stereo trackball pair, by storing in
%   the guidata of each a reference to the other and the angle of
%   convergence.  ax1 is assumed to be the left eye view and ax2 the right
%   eye view, in which case vergence should be positive.
%
%   The trackball argument is optional and defaults to false.  If true,
%   trackballButtonDownFcn is installed as the ButtonDownFcn in both axes
%   objects and all their children.  Clicking and dragging on either
%   window will rotate both views together.  If you only want trackball
%   functionality part of the time, then you should not install it here, but
%   call trackballButtonDownFcn from your own ButtonDownFcn when you want
%   trackball behaviour.

    if nargin < 4
        trackball = false;
    end
    gd1 = guidata( ax1 );
    ax1_old_ButtonDownFcn=get(ax1,'ButtonDownFcn');
    child_old_ButtonDownFcn=get(get(ax1,'Children'),'ButtonDownFcn');
    gd1.stereodata = struct( 'otheraxes', ax2, 'vergence', vergence );
    gd1.old_ButtonDownFcn=old_ButtonDownFcn;
    gd1.child_old_ButtonDownFcn=child_old_ButtonDownFcn;
    guidata( ax1, gd1 );
    gd2 = guidata( ax2 );
    old_ButtonDownFcn=get(ax2,'ButtonDownFcn');
    child_old_ButtonDownFcn=get(get(ax2,'Children'),'ButtonDownFcn');
    gd2.stereodata = struct( 'otheraxes', ax1, 'vergence', -vergence );
    gd2.old_ButtonDownFcn=old_ButtonDownFcn;
    gd2.child_old_ButtonDownFcn=child_old_ButtonDownFcn;
    guidata( ax2, gd2 );
    if trackball
        set( ax1, 'ButtonDownFcn', @trackballButtonDownFcn );
        set( get(ax1,'Children'), 'ButtonDownFcn', @trackballButtonDownFcn );
        set( ax2, 'ButtonDownFcn', @trackballButtonDownFcn );
        set( get(ax2,'Children'), 'ButtonDownFcn', @trackballButtonDownFcn );
    end
return;

function [cameraPosition, cameraRight] = stereoOffset( cameraPosition, cameraTarget, cameraUp, cameraRight, offset )
%[cameraPosition, cameraRight] = ...
%   stereoOffset( cameraPosition, cameraTarget, cameraUp, cameraRight, offset )
% Rotate cameraPosition and cameraRight by offset about cameraUp through cameraTarget.
% offset is in degrees.  The vectors should be row vectors.

    m = matRot( cameraUp, offset*pi/180 )';
    cameraPosition = (cameraPosition - cameraTarget)*m + cameraTarget;
    cameraRight = cameraRight*m;
return;

function v = rotVec( v, centre, rotAxis, rotAmount )
%v = rotVec( v, centre, rotAxis, rotAmount )
%   Rotate v about the axis rotAxis passing through centre by rotAmount in
%   radians.
%   v may be a 3-element row vector or an N*3 matrix.

    m = matRot( rotAxis, rotAmount );
    v = (v-centre)*m'+centre;
return;

function m = matRot( rotAxis, rotAmount )
%m = matRot( rotAxis, rotAmount )
%   Calculate the rotation matrix that rotates about the given axis by the
%   given amount in radians.  The axis must be a unit vector.
%   Formula cribbed from Wikipedia.

    x = rotAxis(1);  y = rotAxis(2);  z = rotAxis(3);
    c = cos(rotAmount);  s = sin(rotAmount);  C = 1-c;
    xs = x*s; ys = y*s; zs = z*s;
    xC = x*C; yC = y*C; zC = z*C;
    xyC = x*yC; yzC = y*zC; zxC = z*xC;
    m = [ [ x*xC+c, xyC-zs, zxC+ys ]; ...
          [ xyC+zs, y*yC+c, yzC-xs ]; ...
          [ zxC-ys, yzC+xs, z*zC+c ] ];
return;

function v2p = makeperp( v1, v2 )
%v2p = makeperp( v1, v2 )
%   Construct the vector v2p which is orthogonal to v1 and in the same plane
%   as v2.

    v2p = v2 - v1*dot(v2,v1)/dot(v1,v1);
return;

function [cameraLook, cameraUp, cameraRight] = cameraFrame( CameraPosition, CameraTarget, CameraUp )
%[cameraLook, cameraUp, cameraRight] = cameraFrame( ...
%       CameraPosition, CameraTarget, CameraUp )
%   Construct the camera orthonormal frame of reference.  The arguments are
%   fields of an axes object.
%   If called as [cameraLook, cameraUp, cameraRight] = cameraFrame( axes ),
%   the position, target, and up vectors are taken from the axes object.
%   Calling it with no arguments is equivalent to cameraFrame( gca ).
%   Note that cameraUp will not necessarily coincide with CameraUp, since
%   cameraUp is constrained to be orthogonal to the look direction, while
%   CameraUp is not.

    if nargin <= 1
        if nargin==0
            theaxes = gca;
        else
            theaxes = CameraPosition;
        end
        CameraPosition = get( theaxes,'CameraPosition' );
        CameraTarget = get( theaxes,'CameraTarget' );
        CameraUp = get( theaxes,'CameraUp' );
    end

    cameraLook = CameraTarget - CameraPosition;
    cameraLook = cameraLook/norm(cameraLook);

    cameraUp = makeperp( cameraLook, CameraUp );
    cameraUp = cameraUp/norm(cameraUp);

    cameraRight = cross( cameraLook, cameraUp );
return;

%------ end of stereo view and trackball control ------

%%%%%
%
%
%%%%%
function model = getCurrShapeModel(pdm, modes_val, dim)
ad =getappdata(0, 'ModelViewerData');
Xm =pdm.Xm;
P = pdm.P;
b = pdm.b;
model_b = modes_val.*sqrt(b);
X = Xm + P*model_b;
model = reshape(X, dim , length(X)/dim )';
% if we have an appearance model then we should keep all the points
% positive
if isfield(ad, 'options')
    if ~isempty(ad.options.sfam)
        model = model - ones(size(model,1),1)*min(model);
    end
end
return;
%%%%%
%
%
%%%%%
function ad = plotAppearanceModel(ad)    
if ~isfield(ad, 'sfam')
    return;
end
if isempty(ad.sfam)
    return;
end
sz = ad.sfam.siz;
Am = ad.sfam.Am;
P = ad.sfam.P;
b = ad.sfam.b;
ompts = ad.sfam.ompts;
model_b = ad.handles.app_modes_val.*sqrt(b);
A = Am + P*model_b;
I = reshape(A, [sz(2) sz(1) sz(3)]);
shape_model = getCurrShapeModel(ad.pdm, ad.handles.shape_modes_val, ad.dim);
if get(ad.handles.tps_chk, 'Value')
    fprintf('Calculating TPS warp...');
    %ad.currentImage = uint8(tpswarp_c(I,ompts,shape_model, 1.1));
    ad.currentImage = TPS_im_warp(I,shape_model,ompts);
    fprintf('done.\n');
else

    ad.currentImage = uint8(triwarp(I,ompts,shape_model));
end
ad.data.appearancehandle = imagesc(ad.currentImage, 'Parent', ad.handles.mainAxes);
return;
%%%%%
%
%
%%%%%
function ad = plotReferenceImage(ad)
if isempty(ad.options.ref_image)
    return;
end
I = ad.options.ref_image.image;
ompts = ad.options.ref_image.pts;
ompts = reshape(ompts, ad.dim , length(ompts)/ad.dim )';
shape_model = getCurrShapeModel(ad.pdm, ad.handles.shape_modes_val, ad.dim);
ad.currentImage = uint8(warp_to_mean_shape(ompts', shape_model,I));
%ad.currentImage = uint8(triwarp(I,ompts,shape_model));
ad.data.appearancehandle = imagesc(ad.currentImage, 'Parent', ad.handles.mainAxes);
return;
%%%%%
%
%
%%%%%
function ad = updateAppearanceModel(ad)
if ~isfield(ad, 'sfam')
    return;
end
if isempty(ad.sfam)
    return;
end
sz = ad.sfam.siz;
Am = ad.sfam.Am;
P = ad.sfam.P;
b = ad.sfam.b;
ompts = ad.sfam.ompts;
model_b = ad.handles.app_modes_val.*sqrt(b);
A = Am + P*model_b;
I = reshape(A, [sz(2) sz(1) sz(3)]);
shape_model = getCurrShapeModel(ad.pdm, ad.handles.shape_modes_val, ad.dim);
if get(ad.handles.tps_chk, 'Value')
    fprintf('Calculating TPS warp...');
    %ad.currentImage = uint8(tpswarp_c(I,ompts,shape_model, 1.1));
    ad.currentImage = TPS_im_warp(I,shape_model,ompts);
    fprintf('done.\n');
else
    ad.currentImage = uint8(triwarp(I,ompts,shape_model));
end
set(ad.data.appearancehandle, 'CData', ad.currentImage);
return;
%%%%%
%
%
%%%%%
function ad = updateReferenceImage(ad)
if isempty(ad.options.ref_image)
    return;
end
I = ad.options.ref_image.image;
ompts = ad.options.ref_image.pts;
ompts = reshape(ompts, ad.dim , length(ompts)/ad.dim )';
shape_model = getCurrShapeModel(ad.pdm, ad.handles.shape_modes_val, ad.dim);
ad.currentImage = uint8(warp_to_mean_shape(ompts', shape_model,I));
%ad.currentImage = uint8(triwarp(I,ompts,shape_model));
set(ad.data.appearancehandle, 'CData', ad.currentImage);
return;
%%%%%
%
%
%%%%%
% function [pts] = collectPoints(flipind, pts)
% for i=1:length(flipind)
%     p = flipind(i).point;
%     n = flipind(i).neighbours;
%     v1 = (pts(n(1),:) - pts(n(2),:))';
%     v2 = (pts(p,:) - pts(n(2),:))';
%     if (v1'*v1)>0
%         pts(p,:) = pts(n(2),:) + ((v1'*v2)/(v1'*v1))*v1';
%     end
% end
% return

% function showFlipped(ipts, opts)
% tri = delaunay(ipts(:,1), ipts(:,2),{'QJ','QJ','QJ'});
% flipped_tri_ind = find_flipped_triangles(tri, ipts, opts);
% 
% figure(1); clf; hold on;
% triplot(tri, opts(:,1), opts(:,2)); axis image ij;
% 
% for i=1:length(flipped_tri_ind);
%     ind = flipped_tri_ind(i);
%     pts = opts(tri(ind,:),:);
%     p = patch(pts(:,1), pts(:,2), 'r');
% end
% switch ad.dim
%     case 3
%         plot3(opts(:,1), opts(:,2), opts(:,3), 'rs');
%     case 2
%         plot(opts(:,1), opts(:,2), 'rs');
% end
% return;
%%%%%
%
%
%%%%%
function doSlideModes(slider, evd, axes_h) %#ok<INUSL>
ad =getappdata(0, 'ModelViewerData');
YLIM = -get(slider,'value')+sort([0 ad.dy])-.5;
set(axes_h,'ylim',YLIM);
return;
%%%%%
%
%
%%%%%
function showShapeModeInfo(mode)
ad =getappdata(0, 'ModelViewerData');
if isempty(mode) || (mode>length(ad.handles.shape_modes_val))
    return;
end
set(ad.handles.shape_pc_num_txt, 'String', num2str(mode));
set(ad.handles.shape_pc_value_txt, 'String', num2str(ad.handles.shape_modes_val(mode)));
val = max(abs(ad.handles.shape_modes_val));
if val>2
    set(ad.handles.shape_pc_slider, 'Max', val, 'Min', -val);
else
    set(ad.handles.shape_pc_slider, 'Max', 2, 'Min', -2);
end
set(ad.handles.shape_pc_slider, 'Value', ad.handles.shape_modes_val(mode));
setappdata(0,'ModelViewerData',ad);
return;
%%%%%
%
%
%%%%%
function showAppModeInfo(mode)
ad =getappdata(0, 'ModelViewerData');
if isempty(mode) || (mode>length(ad.handles.app_modes_val))
    return;
end
set(ad.handles.app_pc_num_txt, 'String', num2str(mode));
set(ad.handles.app_pc_value_txt, 'String', num2str(ad.handles.app_modes_val(mode)));
set(ad.handles.app_pc_slider, 'Value', ad.handles.app_modes_val(mode));
setappdata(0,'ModelViewerData',ad);
return;
%%%%%
%
%
%%%%%
function doSelectMode(axis_h, evd, slider_h, str) %#ok<INUSL,INUSL>
ad =getappdata(0, 'ModelViewerData');
p = get(axis_h, 'CurrentPoint');
y = round(p(1,2));
switch str
    case 'shape'
        modes_val = ad.handles.shape_modes_val;
        ad.currentShapeMode = y;
        showShapeModeInfo(y);
        doPlotModes(axis_h, modes_val, 'shape');

    case 'app'
        modes_val = ad.handles.app_modes_val;
        ad.currentAppMode = y;
        showAppModeInfo(y);
        doPlotModes(axis_h, modes_val, 'app');
    otherwise
        disp('Unknown model type');
end
hold(axis_h, 'on');
if y<=length(modes_val)
    highlightMode(y, axis_h);
end
setappdata(0, 'ModelViewerData', ad);
return;
%%%%%
%
%
%%%%%
function doPlotModes(axis_h, modes_val, type)
ad =getappdata(0, 'ModelViewerData');
width = 6;
height = 10;
xoffset = 4;
switch type
    case 'shape'
        walkerlim = ad.shapewalkerlim;
    case 'app'
        walkerlim = ad.appwalkerlim;
end
modes_val = real(modes_val);
YLIM = get(axis_h, 'YLim');
cla(axis_h);
hold(axis_h, 'on');
N = length(modes_val);
maxval = max(abs(modes_val));
%if maxval>2
    %xpos = modes_val./maxval;
%    set(ad.handles.shape_range, 'String', num2str(maxval));
%else
%    set(ad.handles.shape_range, 'String', num2str(2));
    xpos = (modes_val./walkerlim);
%end
for i=1:N
    str = sprintf('%s', 'PC ', num2str(i));
    text(1, i, str,  'Color', 'k', 'HitTest', 'off', 'Clipping', 'on', 'Parent', axis_h, 'FontSize', 8);
    if modes_val(i)>0
        color = 'r';
    else
        color = 'b';
    end
    X = [xoffset xoffset+xpos(i)];
    plot(axis_h, X,[i i], '-', 'Color', color, 'LineWidth', 4);
end
axis(axis_h, [1-.2 width .5 height+.5], 'ij');
set(axis_h, 'XMinorGrid', 'on');
set(axis_h, 'XTick', [], 'YTick', [], 'Clipping', 'on', 'Box', 'on');
set(axis_h, 'YLim', YLIM);
%%%%%
%
%
%%%%%
function highlightMode(mode, axis_h)
width = 2.5;
X = [1 width-.2 width-.2 1];
Y = [mode-.4 mode-.4 mode+.4 mode+.4];
C = [0.1412    0.3137    1];
%patch(X, Y, C, 'FaceAlpha', .1, 'Parent', axis_h, 'EdgeColor', 'k', 'MarkerSize', .1, 'LineWidth', 0.01, 'LineStyle', ':', 'Clipping', 'on');
patch(X, Y, C, 'Parent', axis_h, 'Clipping', 'on');
str = sprintf('%s', 'PC ', num2str(mode));
text(1, mode, str, 'Clipping', 'on', 'Parent', axis_h, 'FontSize', 8, 'HitTest', 'off', 'Color', 'w');
return;
%%%%%%%%%%%%%%%%%%%%
%
% Disable Appearance buttons
%
%%%%%%%%%%%%%%%%%%%%
function handles = toggleAppearanceGUI(handles, enablestr)
set(handles.applevels, 'Visible', enablestr);
set(handles.appslider, 'Enable', enablestr);
set(handles.app_pc_slider, 'Enable', enablestr);
set(handles.walk_curr_app_pc_btn, 'Enable', enablestr);
set(handles.walk_all_app_pc_btn, 'Enable', enablestr);
set(handles.reset_app_btn, 'Enable', enablestr);
set(handles.reset_all_app_btn, 'Enable', enablestr);
set(handles.app_range, 'Enable', enablestr);


%%%%%%%%%%%%%%%%%%%%
%
% SetGUILevel
%
%%%%%%%%%%%%%%%%%%%%
function handles = SetGUILevel(handles, level)
if level==1
    set(handles.gen_opts_panel, 'Visible', 'off');
    set(handles.add_rand_axis_btn, 'Visible', 'off');
    set(handles.reload_model_btn, 'Visible', 'off'); 
end
%%%%
%
%%%%
function ad = savePDM(ad)
queststr = sprintf('Do you want to save the changes to your shape model?');
savebtn = questdlg(queststr, 'Save shape model', 'Yes', 'No','Yes');
if strcmpi(savebtn, 'yes')
    pdm = ad.pdm;
    save(ad.options.pdm, 'pdm');
    fprintf('Saved pdm to %s\n', ad.options.pdm);
end
return;
%%%
%
%%%
function ad = manualInitialization(ad)
%directoryname = uigetdir(pwd, 'Please choose the directory where your model resides');
[filename, directoryname] = uigetfile('*.mat', 'Pick PDM model to open');
if isequal(filename,0) || isequal(directoryname,0)
    disp('User pressed cancel');
    return
end

pdmname = [directoryname, filesep, filename];
sfamname = [directoryname, filesep, 'mod_sfam.mat'];
aamfile = [directoryname, filesep, 'model.aam_dat'];
if exist(pdmname, 'file')
    ad.options.pdm = pdmname;
end
if exist(sfamname, 'file')
    ad.options.sfam = sfamname;
end
if exist(aamfile, 'file')
    aam = load(aamfile, '-mat');
    aam = aam.aam;
    template = get(aam, 'PointModelTemplate');
    edges = get(template, 'loops');
    if ~isempty(edges)
        ad.edges = edges{1};
    end
    templatename = get(template, 'name');
    [temppath, templatename, ext, vers] = fileparts(templatename);
    pmdir = ['PointModels', filesep, templatename];
  %  if exist(pmdir, 'dir')
   % else
   %     ad.options.PMdirectory = uigetdir(pwd, 'Please choose the directory where your point models live');
   % end
%else
%    ad.options.PMdirectory = uigetdir(pwd, 'Please choose the directory where your point models live');
end
%%%
%
%%%
function doImportRefImage(refimagemenu, evd) %#ok<INUSD>
ad =getappdata(0, 'ModelViewerData');
imdir = [ad.options.ImageDirectory];
pmdir = [ad.options.PMdirectory];
if isempty(pmdir)
    pmdir = uigetdir(pwd, 'Choose your point model directory');
    ad.options.PMdirectory = pmdir;
end
[filename, pathname] = uigetfile('*.jpg', 'Pick a Reference Image', [imdir, filesep]);
if isequal(filename,0) || isequal(pathname,0)
    disp('User pressed cancel');
    return;
else
    ref_image.image = imread([pathname, filesep, filename]);
     ref_image.image = double(ref_image.image);
%     ref_image.image = ref_image.image./max(ref_image.image(:));
    [pathname, filename, ext, vers] = fileparts(filename);
    pmfilename = [pmdir, filesep, filename, '_pm.mat'];
    if ~exist(pmfilename, 'file')
        uiwait(msgbox('There is no point model to match this image. Please try again.','File not found','modal'));
        return;
    end
    pts = load(pmfilename);
    ref_image.pts = pts.pts;
    disp(['User selected ', fullfile(pathname, filename)])
end
ad.options.ref_image = ref_image;
setappdata(0, 'ModelViewerData', ad);
plotModel;
return;
%%%
%
%%%
function customtoolbar(figh)
hA = findall(figh);
openfileh=findobj(hA,'TooltipString','Open File');
%set(openfileh, 'ClickedCallback', {@doOpenGrid});
%set(openfileh, 'TooltipString', 'Open Grid File');
newgridh=findobj(hA,'TooltipString','New Figure');
%set(newgridh, 'ClickedCallback', {@doNewGrid});
%set(newgridh, 'TooltipString', 'New Grid');
saveh=findobj(hA,'TooltipString','Save Figure');
%set(saveh, 'ClickedCallback', {@doSaveGrid});
%set(saveh, 'TooltipString', 'Save Grid');
roth=findobj(hA,'TooltipString','Rotate 3D');
datah=findobj(hA,'TooltipString','Data Cursor');
colbarh=findobj(hA,'TooltipString','Insert Colorbar');
legh=findobj(hA,'TooltipString','Insert Legend');
hideh=findobj(hA,'TooltipString','Hide Plot Tools');
showh=findobj(hA,'TooltipString','Show Plot Tools and Dock Figure');
delete([newgridh, saveh, openfileh, datah, colbarh, legh, hideh, showh]); 