%MDL_IR140 Create model of the ABB IRB 140 manipulator
%
% MDL_IRB140_MOD is a script that creates the workspace variable irb140 which
% describes the kinematic characteristics of an ABB IRB 140 manipulator
% using modified DH conventions.
%
% Also define the workspace vectors:
%   qz         zero joint angle configuration
%
% Reference::
% - ABB IRB 140 data sheet
% - "The modeling of a six degree-of-freedom industrial robot for
%   the purpose of efficient path planning",
%   Master of Science Thesis, Penn State U, May 2009,
%   Tyler Carter
%
% See also mdl_irb140, mdl_puma560, mdl_stanford, mdl_twolink, SerialLink.
%
% Notes::
% - SI units of metres are used.
% - The tool frame is in the centre of the tool flange.
% - Zero angle configuration has the upper arm vertical and lower arm
%   horizontal.

% MODEL: ABB, IRB140, 6DOF, modified_DH

% Copyright (C) 1993-2017, by Peter I. Corke
%
% This file is part of The Robotics Toolbox for MATLAB (RTB).
%
% RTB is free software: you can redistribute it and/or modify
% it under the terms of the GNU Lesser General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% RTB is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU Lesser General Public License for more details.
%
% You should have received a copy of the GNU Leser General Public License
% along with RTB.  If not, see <http://www.gnu.org/licenses/>.
%
% http://www.petercorke.com

clear L

% joint angle limits from
% A combined optimization method for solving the inverse kinematics problem...
% Wang & Chen
% IEEE Trans. RA 7(4) 1991 pp 489-
L(1) = Revolute('d', 0.352, 'a', 0, 'alpha', 0, 'offset', 0, 'modified');
L(2) = Revolute('d', 0, 'a', 0.070, 'alpha', pi/2, 'offset', 0, 'modified');
L(3) = Revolute('d', 0, 'a', 0.360, 'alpha', 0, 'offset', 0, 'modified');
L(4) = Revolute('d', 0.380, 'a', 0, 'alpha', pi/2, 'offset', 0, 'modified');
L(5) = Revolute('d', 0, 'a', 0, 'alpha', -pi/2, 'offset', 0, 'modified');
L(6) = Revolute('d', 0, 'a', 0, 'alpha', pi/2, 'offset', 0, 'modified');

L(1).m = 34655.36e-3;
L(1).r = [27.87 43.12 -89.03]*1e-3;
L(1).I = [
    512052539.74 1361335.88 51305020.72
    1361335.88 464074688.59 70335556.04
    51305020.72 70335556.04 462745526.12]*1e-9;

L(2).m = 15994.59e-3;
L(2).r = [ 198.29 9.73 92.43]*1e03;
L(2).I = [
    94817914.40 -3859712.77 37932017.01
    -3859712.77 328604163.24 -1088970.86
    37932017.01 -1088970.86 277463004.88]*1e-9;

L(3).m = 20862.05e-3;
L(3).r = [ -4.56 -79.96 -5.86];
L(3).I = [
    500060915.95 -1863252.17 934875.78
    -1863252.17 75152670.69 -15204130.09
    934875.78 -15204130.09 515424754.34]*1e-9;

irb140 = SerialLink(L, 'name', 'IRB 140', ...
    'manufacturer', 'ABB', 'comment', 'modified DH');

%
% some useful poses
%
qz = [0 0 0 0 0 0]; % zero angles, L shaped pose

clear L


function [Va_idx, gamma_idx, R_idx] = Td2idx(Td)
% Td2idx

Va_trim = Td(1);
gamma_trim = Td(2);
R_trim = Td(3);

if ~exist('P_Td', 'var')
    param_table_T
end
Va_idx = floor((Va_trim - P_Td.Va_min) / P_Td.Va_step)+1;
gamma_idx = floor((gamma_trim - P_Td.gamma_min) / P_Td.gamma_step)+1;
if ~isfinite(R_trim)
    R_idx = 1;
else
    R_idx = floor((R_trim - P_Td.R_min) / P_Td.R_step)+2;
end

if Va_idx > P_Td.Va_n_steps
    Va_idx = P_Td.Va_n_steps;
    str = ['Va_trim ' num2str(Va_trim) 'm/s too big.'];
    disp(str)
elseif Va_idx < 1
    Va_idx = 1;
    str = ['Va_trim ' num2str(Va_trim) 'm/s too small.'];
    disp(str)
end

if gamma_idx > P_Td.gamma_n_steps
    gamma_idx = P_Td.gamma_n_steps;
    str = ['gamma_trim ' num2str(rad2deg(gamma_trim)) ' too big.'];
    disp(str)
elseif gamma_idx < 1
    gamma_idx = 1;
    str = ['gamma_trim ' num2str(rad2deg(gamma_trim)) ' too small.'];
    disp(str)
end

if R_idx > P_Td.R_n_steps
    R_idx = P_Td.R_n_steps;
    str = ['R_trim ' num2str(R_trim) 'm too big.'];
    disp(str)
elseif R_idx < 1
    R_idx = 1;
    str = ['R_trim ' num2str(R_trim) 'm too small.'];
    disp(str)
end

end


function [ferns,hsPr] = fernsClfChangeFernDepth( data, hs, ferns, Snew, varargin )
% Train random fern classifier.
%
% See "Fast Keypoint Recognition in Ten Lines of Code" by Mustafa Ozuysal,
% Pascal Fua and Vincent Lepetit, CVPR07.
%
% Dimensions:
%  M - number ferns
%  S - fern depth
%  F - number features
%  N - number input vectors
%  H - number classes
%
% USAGE
%  [ferns,hsPr] = fernsClfTrain( data, hs, [varargin] )
%
% INPUTS
%  data     - [NxF] N length F feature vectors
%  hs       - [Nx1] target output labels in [1,H]
%  varargin - additional params (struct or name/value pairs)
%   .S        - [10] fern depth (ferns are exponential in S)
%   .M        - [50] number of ferns to train
%   .thrr     - [0 1] range for randomly generated thresholds
%   .bayes    - [1] if true combine probs using bayes assumption
%   .ferns    - [] if given reuse previous ferns (recompute pFern)
%
% OUTPUTS
%  ferns    - learned fern model w the following fields
%   .fids     - [MxS] feature ids for each fern for each depth
%   .thrs     - [MxS] threshold corresponding to each fid
%   .pFern    - [2^SxHxM] learned log probs at fern leaves
%   .bayes    - if true combine probs using bayes assumption
%   .inds     - [NxM] cached indices for original training data
%   .H        - number classes
%  hsPr     - [Nx1] predicted output labels
%
% EXAMPLE
%  N=5000; H=5; d=2; [xs0,hs0,xs1,hs1]=demoGenData(N,N,H,d,1,1);
%  fernPrm=struct('S',4,'M',50,'thrr',[-1 1],'bayes',1);
%  tic, [ferns,hsPr0]=fernsClfTrain(xs0,hs0,fernPrm); toc
%  tic, hsPr1 = fernsClfApply( xs1, ferns ); toc
%  e0=mean(hsPr0~=hs0); e1=mean(hsPr1~=hs1);
%  fprintf('errors trn=%f tst=%f\n',e0,e1); figure(1);
%  subplot(2,2,1); visualizeData(xs0,2,hs0);
%  subplot(2,2,2); visualizeData(xs0,2,hsPr0);
%  subplot(2,2,3); visualizeData(xs1,2,hs1);
%  subplot(2,2,4); visualizeData(xs1,2,hsPr1);
%
% See also fernsClfApply, fernsInds
%
% Piotr's Image&Video Toolbox      Version 2.50
% Copyright 2010 Piotr Dollar.  [pdollar-at-caltech.edu]
% Please email me if you find bugs, or have suggestions or questions!
% Licensed under the Lesser GPL [see external/lgpl.txt]

% get additional parameters and check dimensions
dfs={'thrr',[0 1],'tmp',''};
[thrr,~]=getPrmDflt(varargin,dfs,1);

[M,Sold] = size(ferns.fids);
[N,F]=size(data); assert(length(hs)==N);
H=max(hs); assert(all(hs>0)); assert(Snew<=20);

if Snew == Sold,
elseif Snew < Sold,
  Sremove = Sold - Snew;

  % remove classifiers from ferns
  ferns.thrs(:,Snew+1:Sold) = [];
  ferns.fids(:,Snew+1:Sold) = [];

  % remove corresponding bits from inds
  ferns.inds = bitshift(ferns.inds,-Sremove);

  % accumulate counts into parent nodes
  ferns.counts = reshape(sum(reshape(ferns.counts,[2^Snew,2^Sremove,H,M]),2),[2^Snew,H,M]);

  % convert fern leaf class counts into probabilities
  if( ferns.bayes<=0 )
    norm = 1./sum(ferns.counts,2);
    ferns.pFern = bsxfun(@times,ferns.counts,norm);
  else
    norm = 1./sum(ferns.counts,1);
    ferns.pFern = bsxfun(@times,ferns.counts,norm);
    ferns.pFern=log(ferns.pFern);
  end
else

  Sadd = Snew - Sold;

  % generate some new classifiers for each fern
  ferns.thrs(:,Sold+1:Snew) = rand(M,Sadd)*(thrr(2)-thrr(1))+thrr(1);
  ferns.fids(:,Sold+1:Snew) = uint32(floor(rand(M,Sadd)*F+1));

  % new lower bits to inds
  indsadd=fernsInds(data,ferns.fids(:,Sold+1:Snew),ferns.thrs(:,Sold+1:Snew));
  ferns.inds = bitshift(ferns.inds,Sadd) + indsadd;

  % re-histogram
  ferns.counts = zeros(2^Snew,H,M);
  edges = 1:2^Snew;
  for h=1:H,
    inds1=ferns.inds(hs==h,:);
    for m=1:M,
      ferns.counts(:,h,m)=histc(inds1(:,m),edges);
    end
  end
  ferns.counts = ferns.counts + ferns.bayes;

  % convert fern leaf class counts into probabilities
  if( ferns.bayes<=0 )
    norm = 1./sum(ferns.counts,2);
    ferns.pFern = bsxfun(@times,ferns.counts,norm);
  else
    norm = 1./sum(ferns.counts,1);
    ferns.pFern = bsxfun(@times,ferns.counts,norm);
    ferns.pFern=log(ferns.pFern);
  end
end

if(nargout==2), hsPr=fernsClfApply([],ferns,inds); end

end


function [Y, G] = rbfOut(model, X);

% RBFOUT Output of an RBF model.
% FORMAT
% DESC gives the output of a radial basis function model, the function is
% a wrapper for rbffwd.
% ARG model : the model for which the output is required.
% ARG X : the input data for which the output is required.
% RETURN Y : the output.
%
% FORMAT
% DESC gives the output of a radial basis function model.
% ARG model : the model for which the output is required.
% ARG X : the input data for which the output is required.
% RETURN Y : the output.
% RETURN G : the hidden layer activations.
%
% SEEALSO : rbffwd, rbf, modelOut
%
% COPYRIGHT : Neil D. Lawrence, 2006, 2007, 2008

% MLTOOLS

  if nargout > 1
    [Y, G] = rbffwd(model, X);
  else
    Y = rbffwd(model, X);
  end


function obj=stat_summary(obj,varargin)
% stat_summary Display summarized data for each value of X
%
% Example syntax (default arguments): gramm_object.stat_summary('type','ci','geom','lines','setylim',false)
% For each unique value of x, this can display various estimates of
% the location and variability of the corresponding y distribution.
% The optional 'name',value pairs can ne the following:
% - 'type':
%       - 'ci' : display the mean and the 95% confidence
%       interval of the mean (based on the assumption of a normal
%       distribution)
%       - 'bootci' : display the mean and the 95% confidence
%       interval of the mean computed by bootstrap
%       - 'sem' : display the mean and the standard error of
%       the mean
%       - 'std' : display the mean and the standard deviation
%       and the mean
%       - 'quartile': display the 25% 50% (median) and 75%
%       percentiles
%       - '95percentile': display the median and 2.5 and 97.5
%       percentiles
%       - 'fitnormalci'
%       - 'fitpoissonci'
%       - 'fitbinomialci'
%       - 'fit95percentile'
%       - @function : provide a the handle to a custom function that takes
%       y values (as an n_repetitions x n_data_points matrix) and returns
%       both the central value and the CI with a matrix [y_central ; yc_CI_low ; y_CI_high]
%       (with y_central, and y_CIs being 1 x n_data_points arrays).
%       Example that uses the trimmed mean instead of regular mean:
%
%       custom_statfun = @(y)([trimmean(y,2.5);bootci(500,{@(ty)trimmean(ty,2.5),y},'alpha',0.05)]);
%       gramm_object.stat_summary('type', custom_statfun)
%
% - 'geom' (possibility to combine them using a cellstr, e.g. 'geom',{'bar','black_errorbar'} ):
%       - 'line': displays a line that connects the central locations
%       (mean,median)
%       - 'lines': displays a line that connects the central locations
%       and lighter lines for the variabilities
%       - 'area': displays a line that connects the central locations
%       and a transparent area for the variabilities. WARNING:
%       this changes the renderer to opengl and disables proper
%       vector output on older matlab versions
%       - 'area_only': displays the variabilities only, using a transparent area
%       - 'solid_area': displays a line that connects the locations
%       and a solid area for the variabilities. Use this for
%       export to vector output.
%       - 'errorbar': displays error bars for variabilities.
%       - 'black_errorbar': displays black error bars for variabilities.
%       - 'bar': displays the locations as bars
%       - 'edge_bar': displays the locations as bars with black edge
%       - 'point': displays the locations as points
% - 'setylim': set to true if you want the y axis limits to be
% set by the summarized data instead of the underlying data
% points.
% - 'interp': Use to interpolate the output, takes the same parameters as
% interp1 in order to specify the interpolation type. When the
% polar mode is specified as closed, or when 'interp','polar' is used
% the interpolation uses interpft, which supposes regular sampling around the circle.
% - 'interp_in': Use to (linearly) interpolate the input. This is intended
% for input given as cells when the x value is different for
% each cell and not aligned. The argument corresponds to the
% number of points used to generate the interpolation. Ideally
% for this the number of number of points should be higher than
% the x resolution of the data, otherwise some data will be
% unused.
% - 'bin_in': Use to bin the input. This is intended for input
% given as a 1-D array, creates bins over x and computes the summary
% over the binned data. Argument corresponds to the number of
% bins
% - 'dodge': use to dodge the plotted elements depending on
% color (recommended for 'bar', 'errorbar', 'black_errorbar').
% A value of 0 deactivates dodging. Other values set the space
% between the dodged elements as ratio of the x intervals.
% - 'width': use to set the width of bars and error bars (error
% bars are 1/4 th the width of bars).
%
% A setting of 'dodge',1,'width',1 will create bars that are
% fully dodged (ie don't overlap, but are not separated) and where
% all bars occupy the full interval between the x values, e.g.:
% * __    *
% *|  |__ *
% *|  |  |*
% *|__|__|*
%
% A setting of 'dodge',0.8,'width',0.8 will have fully dodged bars that are
% not separated, but only occupy 50% of the space between x
% values, e.g.:
% *  _    *
% * | |_  *
% * | | | *
% * |_|_| *
%
%A setting of 'dodge',0.8,'width',0.6 will add some
% spacing between the bars, e.g.:
% *  _      *
% * | |  _  *
% * | | | | *
% * |_| |_| *
%
% A setting of 'dodge',0.8,'width',1 will create dodged but overlapping
% bars, e.g.:
% *  ___    *
% * |  _|_  *
% * | |   | *
% * |_|___| *

p=inputParser;
my_addParameter(p,'type','ci'); %'95percentile'
my_addParameter(p,'geom','area');
my_addParameter(p,'dodge',[]);
my_addParameter(p,'width',[]);
my_addParameter(p,'setylim',false);
my_addParameter(p,'interp','none');
my_addParameter(p,'interp_in',-1);
my_addParameter(p,'bin_in',-1);
parse(p,varargin{:});

obj.geom=vertcat(obj.geom,{@(dobj,dd)my_summary(dobj,dd,p.Results)});
obj.results.stat_summary={};
end

function hndl=my_summary(obj,draw_data,params)

%Advanced defaults
if isempty(params.dodge)
    if sum(strcmp(params.geom,'bar'))>0 && draw_data.n_colors>1 %If we have a bar as geom, we dodge
        params.dodge=0.6;
    else
        params.dodge=0;
    end
end

if isempty(params.width) %If no width given
    if params.dodge>0 %Equal to dodge if dodge given
        params.width=params.dodge*0.8;
    else
        params.width=0.5;
    end
end

if iscell(draw_data.x) || iscell(draw_data.y) %If input was provided as cell/matrix

    if params.interp_in>0
        %If requested we interpolate the input
        uni_x=linspace(obj.var_lim.minx,obj.var_lim.maxx,params.interp_in);
        [x,y]=cellfun(@(x,y)deal(uni_x,interp1(x,y,uni_x,'linear')),draw_data.x,draw_data.y,'UniformOutput',false,'ErrorHandler',@(st,a,b)deal([],[]));
        y=padded_cell2mat(y);
        if isempty(y) %likely because we had only single points
            y = nan(size(uni_x));
            disp('Error in summary input interpolation... nothing plotted')
        end
    else
        %If not we just make a padded matrix for fast
        %computations (we'll assume that X are roughly at the
        %same location for the same indices)
        x=padded_cell2mat(draw_data.x);
        y=padded_cell2mat(draw_data.y);
        uni_x=nanmean(x);
        %Add a check for X alignment
        x_diff=max(x)-min(x);
        if  size(x,1)>1 && any(x_diff(1:end-1)>diff(uni_x)/10) %More than a tenth of delta x variation
            warning(['some repeated X values are misaligned (max ' num2str(max(x_diff)) '), use ''interp_in'' in stat_summary() or live with the consequences'])
        end
    end

    if params.bin_in>0
        warning('bin_in in stat_summary() not supported for Matrix/Cell X/Y inputs');
    end

    if ischar(params.type) && ~isempty(strfind(params.type,'fit'))
        %If we have a params.type using distributions fits we
        %can't vectorize the call to computeci so we do it in a for
        %loop
        ymean=zeros(length(uni_x),1);
        yci=zeros(length(uni_x),2);
        for ind_x=1:length(uni_x)
            [ymean(ind_x),yci(ind_x,:)]=computeci(y(:,ind_x),params.type,obj.stat_options.alpha,obj.stat_options.nboot);
        end
    else
        if size(y,1)==1
            ymean=y;
            yci=nan(length(uni_x),2);
        else
            [ymean,yci]=computeci(y,params.type,obj.stat_options.alpha,obj.stat_options.nboot);
        end
    end

else %If input was provided as 1D array

    x=comb(draw_data.x);
    y=comb(draw_data.y);

    if params.bin_in>0
        %If X binning was requested we do it
        binranges=linspace(obj.var_lim.minx,obj.var_lim.maxx,params.bin_in+1);
        bincenters=(binranges(1:(end-1))+binranges(2:end))/2;
        [~,binind]=my_histcounts(x,binranges,'count');
        uni_x=bincenters;
        sel=binind~=0; %histcounts can return zero as bin index if NaN data we remove them here
        x=bincenters(binind(sel));
        y=y(sel);
    else
        %         if sum(strcmp(params.geom,'area'))>0 || sum(strcmp(params.geom,'line'))>0 ||...
        %                 sum(strcmp(params.geom,'lines'))>0  || sum(strcmp(params.geom,'solid_area'))>0
        %             %To avoid interruptions in line and area plots we
        %             %compute uniques over current data only
        %             uni_x=unique(x); %Sorted is the default
        %         else
        %             if obj.x_factor
        %                 %If x is a factor we space everything as one
        %                 uni_x=obj.var_lim.minx:1:obj.var_lim.maxx;
        %             else
        %                 %compute unique Xs at the facet level to avoid
        %                 %weird bar sizing issues when dodging and when
        %                 %colors are missing
        %                 facet_x=comb(draw_data.facet_x);
        %                 uni_x=unique(facet_x);
        %             end
        %         end

        uni_x=unique(x);

        %Here we need to implement a loose 'unique' because of
        %potential numerical errors
        uni_x(diff(uni_x)<1e-10)=[];
    end

    if params.interp_in>0
        warning('interp_in in stat_summary() not supported for non Matrix/Cell X/Y inputs');
    end

    ymean=nan(length(uni_x),1);
    yci=nan(length(uni_x),2);

    %Loop over unique X values
    for ind_x=1:length(uni_x)
        %And here we have a loose selection also because of
        %potential numerical errors
        ysel=y(abs(x-uni_x(ind_x))<1e-10);

        if ~isempty(ysel)
            [ymean(ind_x),yci(ind_x,:)]=computeci(ysel,params.type,obj.stat_options.alpha,obj.stat_options.nboot);
        end
    end
end

%Do we set the y limits according to the smoothed curves or to
%the original data ?
if params.setylim
    if sum(sum(isnan(yci)))~=numel(yci) %We only do this if yci is not weird
        if obj.firstrun(obj.current_row,obj.current_column) %Initialize for the first run in the subplot
            obj.plot_lim.maxy(obj.current_row,obj.current_column)=max(max(yci));
            obj.plot_lim.miny(obj.current_row,obj.current_column)=min(min(yci));
        else %Update for subsequent runs in the subplot
            if max(max(yci))>obj.plot_lim.maxy(obj.current_row,obj.current_column)
                obj.plot_lim.maxy(obj.current_row,obj.current_column)=max(max(yci));
            end
            if min(min(yci))<obj.plot_lim.miny(obj.current_row,obj.current_column)
                obj.plot_lim.miny(obj.current_row,obj.current_column)=min(min(yci));
            end
        end
    end
end

%When we do bar plots we want to have zero in the y axis anyway
if sum(strcmp(params.geom,'bar'))>0
    if obj.plot_lim.miny(obj.current_row,obj.current_column)>0 %Values above zero -> change miny
        obj.plot_lim.miny(obj.current_row,obj.current_column)=0;
    end
    if obj.plot_lim.maxy(obj.current_row,obj.current_column)<0 %Values below zero -> change maxy
        obj.plot_lim.maxy(obj.current_row,obj.current_column)=0;
    end
end

%Do we interpolate the summary results for display ?
if ~strcmp(params.interp,'none')
    if size(yci,1)>2
        yci=yci';
    end

    if obj.polar.is_polar && obj.polar.is_polar_closed && ~strcmp(params.interp,'polar')
        disp([params.interp ' interpolation overriden, ''polar'' used']);
        params.interp='polar'; %%If the plot is polar we override the interpolation type do an optimal fft interpolation
    end

    if strcmp(params.interp,'polar')
        %Perform checks on uni_x
        dx=unique_no_nan(diff([uni_x ; uni_x(1)+2*pi])); %compute step
        if any(abs(diff(dx))>1e-12) %handle numerical precision problems (exact version would be length(dx)>1 )
            disp('ERROR: ''polar'' interpolation requires periodic sampling, displayed results are incorrect');
        end
        uni_x=uni_x(1):pi/50:uni_x(1)+99*pi/50;
        ymean=interpft(ymean,100);
        tmp_yci1=interpft(yci(1,:),100);
        tmp_yci2=interpft(yci(2,:),100);
        yci=[tmp_yci1 ; tmp_yci2];
    else
        %For non polar plots we do a regular interpolation
        new_x=linspace(min(uni_x),max(uni_x),100);
        ymean=interp1(uni_x,ymean,new_x,params.interp);
        tmp_yci1=interp1(uni_x,yci(1,:),new_x,params.interp);
        tmp_yci2=interp1(uni_x,yci(2,:),new_x,params.interp);
        yci=[tmp_yci1 ; tmp_yci2];
        uni_x=new_x;
    end
end

%If X were modified
if params.bin_in>0 || params.interp_in>0 || ~strcmp(params.interp,'none')
    %We reinitialize dodging parameters for plotci to work correctly
    draw_data.dodge_avl_w=uni_x(2)-uni_x(1);
    draw_data.dodge_fallback=true;
    draw_data.dodge_x=1;
    draw_data.dodge_n=draw_data.n_colors;
    draw_data.dodge_ind=draw_data.color_index;

    %draw_data.dodge_x=shiftdim(uni_x);
    %draw_data.dodge_n=repmat(draw_data.n_colors,length(uni_x),1);
    %draw_data.dodge_ind=repmat(draw_data.color_index,length(uni_x),1);
end

%Store results
obj.results.stat_summary{obj.result_ind,1}.x=uni_x;
obj.results.stat_summary{obj.result_ind,1}.y=ymean;
obj.results.stat_summary{obj.result_ind,1}.yci=yci;

%Do the actual plotting
hndl=plotci(obj,uni_x,ymean,yci,draw_data,params.geom,params.dodge,params.width);

%Copy handles
if isstruct(hndl)
    hnames=fieldnames(hndl);
    for k=1:length(hnames)
        obj.results.stat_summary{obj.result_ind,1}.(hnames{k})=hndl.(hnames{k});
    end
else
    disp('Nothing plotted... Error in summary computation?')
end
end

function [ymean,yci]=computeci(y,type,alpha,nboot)

ymean=nanmean(y);

%Check number of samples
nsamp=size(y,1);
if nsamp<3 && strcmp(type,'bootci')
    disp('Less than 3 samples for bootstrap CI computation...Skipping')
    yci=repmat([NaN NaN],size(y,2));
    return;
end
if nsamp<2
    disp('Less than 2 samples for CI computation...Skipping')
    yci=repmat([NaN NaN],size(y,2));
    return;
end

if isa(type,'function_handle')
    try
        temp=type(y);
        ymean=temp(1,:);
        yci=temp(2:3,:);
    catch ME
        disp(['Error in custom summary computation: ' ME.message ' ...skipping']);
        yci=repmat([NaN NaN],size(y,2));
        ymean=nan(size(y,2),1);
    end
    return;
end

try
    switch type
        case 'bootci'
            yci=bootci(nboot,{@(ty)nanmean(ty),y},'alpha',alpha);
        case 'ci'
            %ci=1.96*nanstd(y)./sqrt(sum(~isnan(y)));
            %Correction for small samples (equivalent to fitnormalci)
            ci=tinv(1-alpha/2,sum(~isnan(y))-1).*nanstd(y)./sqrt(sum(~isnan(y)));
            yci=bsxfun(@plus,ymean,[-ci;ci]);
        case 'std'
            ci=nanstd(y);
            yci=bsxfun(@plus,ymean,[-ci;ci]);
        case 'sem'
            ci=nanstd(y)./sqrt(sum(~isnan(y)));
            yci=bsxfun(@plus,ymean,[-ci;ci]);
        case 'quartile'
            ymean=nanmedian(y);
            yci=prctile(y,[25 75]);
        case '95percentile'
            ymean=nanmedian(y);
            yci=prctile(y,[2.5 97.5]);
        case 'fitnormalci'
            pd=fitdist(y,'Normal');
            ymean=pd.mean();
            ci=paramci(pd,alpha);
            yci=ci(:,1)';
        case 'fitpoissonci'
            pd=fitdist(y,'Poisson');
            ymean=pd.mean();
            ci=paramci(pd,alpha);
            yci=ci(:,1)';
        case 'fitnegbinomialci'
            pd=fitdist(y,'NegativeBinomial');
            ymean=pd.mean();
            ci=paramci(pd,alpha);
            yci=ci(:,1)';
        case 'fitbinomialci'
            pd=fitdist(y,'Binomial');
            ymean=pd.mean;
            ci=paramci(pd,alpha);
            yci=ci(:,2)';
        case 'fit95percentile'
            pd=fitdist(y,'Normal');
            ymean=pd.icdf(0.5);
            yci=pd.icdf([0.025 0.975]);
        otherwise
            warning(['Unknown CI type ' type]);
    end
catch ME
    disp(['Error in CI computation: ' ME.message ' ...skipping']);
    yci=repmat([NaN NaN],size(y,2));
end
end


function rimgs = slresizeimg(imgs, newsiz, interpker)
%SLRESIZEIMG Resizes the images by interpolation
%
% $ Syntax $
%   - rimgs = slresizeimg(imgs, newsiz, interpker)
%
% $ Arguments $
%   - imgs:         The set of images
%   - newsiz:       The new image size to be resized to
%                   It can be in two forms:
%                   - [new_height, new_width]
%                   - ratio to the original size
%   - interpker:    The interpolation kernel (default = 'linear')
%   - rimgs:        The resized images
%
% $ Description $
%   - rimgs = slresizeimg(imgs, newsiz, interpker) resizes the image
%     to new size by interpolation.
%
% $ Remarks $
%   - The implementation is based on slimginterp.
%
% $ History $
%   - Created by Dahua Lin, on Sep 3, 2006
%

%% parse and verify input

if nargin < 2
    raise_lackinput('slresizeimg', 2);
end
h0 = size(imgs, 1);
w0 = size(imgs, 2);

if isnumeric(newsiz)
    if length(newsiz) == 1
        h = newsiz * h0;
        w = newsiz * w0;
    elseif length(newsiz) == 2
        [h, w] = sltakeval(newsiz);
    else
        error('sltoolbox:invalidarg', 'The newsiz is invalid');
    end
else
    error('sltoolbox:invalidarg', 'The newsiz is invalid');
end

if nargin < 3 || isempty(interpker)
    interpker = 'linear';
end

%% generate coordinate map

I = linspace(1, h0, h)';
J = linspace(1, w0, w);
I = I(:, ones(1, w));
J = J(ones(h, 1), :);

%% Do interpolation

rimgs = slimginterp(imgs, I, J, interpker);


function f2 = p06_f2 ( x )

%*****************************************************************************80
%
%% P06_F2 evaluates the second derivative for problem 6.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    26 February 2002
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    LE Scales,
%    Introduction to Non-Linear Optimization,
%    Springer, 1985.
%
%  Parameters:
%
%    Input, real X, the values of the variables.
%
%    Output, real F2, the second derivative.
%
  f2 = 0.0;

  return
end


function out = WL_dwtcoeff(y,wname,level)
% WL_dwtcoeff   Discrete wavelet transform coefficients.
%
% Decomposes the time series using a given wavelet and outputs statistics on the
% coefficients obtained up to a maximum level, level.
%
%---INPUTS:
%
% y, the input time series
%
% wname, the mother wavelet, e.g., 'db3', 'sym2' (see Wavelet Toolbox
%           Documentation)
%
% level, the level of wavelet decomposition (can be set to 'max' for the maximum
%               level determined by wmaxlev)

% ------------------------------------------------------------------------------
% Copyright (C) 2020, Ben D. Fulcher <ben.d.fulcher@gmail.com>,
% <http://www.benfulcher.com>
%
% If you use this code for your research, please cite the following two papers:
%
% (1) B.D. Fulcher and N.S. Jones, "hctsa: A Computational Framework for Automated
% Time-Series Phenotyping Using Massive Feature Extraction, Cell Systems 5: 527 (2017).
% DOI: 10.1016/j.cels.2017.10.001
%
% (2) B.D. Fulcher, M.A. Little, N.S. Jones, "Highly comparative time-series
% analysis: the empirical structure of time series and their methods",
% J. Roy. Soc. Interface 10(83) 20130048 (2013).
% DOI: 10.1098/rsif.2013.0048
%
% This function is free software: you can redistribute it and/or modify it under
% the terms of the GNU General Public License as published by the Free Software
% Foundation, either version 3 of the License, or (at your option) any later
% version.
%
% This program is distributed in the hope that it will be useful, but WITHOUT
% ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
% FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
% details.
%
% You should have received a copy of the GNU General Public License along with
% this program. If not, see <http://www.gnu.org/licenses/>.
% ------------------------------------------------------------------------------

% ------------------------------------------------------------------------------
%% Check that a Wavelet Toolbox license is available:
% ------------------------------------------------------------------------------
BF_CheckToolbox('wavelet_toolbox')

% ------------------------------------------------------------------------------
%% Check Inputs
% ------------------------------------------------------------------------------
doPlot = false; % Plot results to figures
N = length(y); % Length of the time series

if nargin < 2 || isempty(wname)
    wname = 'db3'; % Daubechies wavelet filter
end
if nargin < 3 || isempty(level)
    level = 3; % level of wavelet decomposition
end
if strcmp(level,'max')
    level = wmaxlev(N,wname);
end

maxLevelAllowed = wmaxlev(N,wname);
if maxLevelAllowed < level
    fprintf(1,'Chosen level is too large for this wavelet on this signal...\n');
end

% ------------------------------------------------------------------------------
%% Perform Wavelet Decomposition
% ------------------------------------------------------------------------------
% Computes the following:
%   (*) Wavelet decomposition vector, c
%   (*) Bookkeeping vector, l

if maxLevelAllowed < level
    [c, l] = wavedec(y, maxLevelAllowed, wname);
else
    [c, l] = wavedec(y, level, wname);
end

%% Expand DWT coefficients for visualization
% nbcol = 64; % color discretization steps
%
% cfd = zeros(level,N); % detail coefficients
% for k = 1:level
%     d = detcoef(c,l,k);
%     d = d(:)';
%     d = d(ones(1,2^k),:);
%     cfd(k,:) = wkeep1(d(:)',N);
% end
%
% cfd =  cfd(:);
% I = find(abs(cfd)<sqrt(eps));
% cfd(I) = zeros(size(I));
% cfd = reshape(cfd,level,N);
% cfd = wcodemat(cfd,nbcol,'row');

%-------------------------------------------------------------------------------
%% Plotting
%-------------------------------------------------------------------------------
if doPlot
    figure('color','w'); box('on');
    colormap(pink(nbcol));
    image(cfd);
    tics = 1:level;
    labs = int2str((1:level)');
    set(gca,'YTicklabelMode','manual','Ydir','normal', 'Box','On','Ytick',tics,'YTickLabel',labs);
    title('Discrete Wavelet Transform, Absolute Coefficients.');
    xlabel('Time (or Space)')
    ylabel('Level');
end

% ------------------------------------------------------------------------------
%% Get statistics on coefficients
% ------------------------------------------------------------------------------
for k = 1:level
    if k <= maxLevelAllowed
        d = detcoef(c,l,k); % detail coefficients at level k
        % maximum coefficient at this level:
        out.(sprintf('maxd_l%u',k)) = max(d);
        % minimum coefficient at this level:
        out.(sprintf('mind_l%u',k)) = min(d);
        % std coefficients at this level:
        out.(sprintf('stdd_l%u',k)) = std(d);
        % 1-D noise coefficient estimate (estimate of the noise std):
        out.(sprintf('noisestd_l%u',k)) = wnoisest(c,l,k);
    else
        out.(sprintf('maxd_l%u',k)) = NaN;
        out.(sprintf('mind_l%u',k)) = NaN;
        out.(sprintf('stdd_l%u',k)) = NaN;
        out.(sprintf('noisestd_l%u',k)) = NaN;
    end
end

% %% Compress Signal
% % Set approximation coefficients to zero
% % nc = wthcoef('a',c,l);
% NC = wthcoef('t',c,l,N,T,SORH);
%
%
% %% Single Level Reconstruction
% X = waverec(c,l,wname);
% plot(X);
% keyboard

%% Extract Approximation Coefficients from wavelet decomposition structure

% CA = appcoef(C,L,wname,level);

end


function G = greens_function_mono(x,y,z,xs,src,f,conf)
%GREENS_FUNCTION_MONO Green's function in the frequency domain
%
%   Usage: G = greens_function_mono(x,y,z,xs,src,f,conf)
%
%   Input options:
%       x,y,z   - x,y,z points for which the Green's function should be
%                 calculated / m
%       xs      - position of the source
%       src     - source model of the Green's function. Valid models are:
%                   'ps'  - point source
%                   'ls'  - line source
%                   'pw'  - plane wave
%                   'dps' - dipole point source
%       f       - frequency of the source / Hz
%       conf    - configuration struct (see SFS_config)
%
%   Output parameters:
%       G       - Green's function evaluated at the points x,y,z
%
%   GREENS_FUNCTION_MONO(x,y,z,xs,src,f,conf) calculates the Green's function
%   for the given source model located at xs for the given points x,y and the
%   frequency f.
%
%   See also: sound_field_mono

%*****************************************************************************
% The MIT License (MIT)                                                      *
%                                                                            *
% Copyright (c) 2010-2019 SFS Toolbox Developers                             *
%                                                                            *
% Permission is hereby granted,  free of charge,  to any person  obtaining a *
% copy of this software and associated documentation files (the "Software"), *
% to deal in the Software without  restriction, including without limitation *
% the rights  to use, copy, modify, merge,  publish, distribute, sublicense, *
% and/or  sell copies of  the Software,  and to permit  persons to whom  the *
% Software is furnished to do so, subject to the following conditions:       *
%                                                                            *
% The above copyright notice and this permission notice shall be included in *
% all copies or substantial portions of the Software.                        *
%                                                                            *
% THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR *
% IMPLIED, INCLUDING BUT  NOT LIMITED TO THE  WARRANTIES OF MERCHANTABILITY, *
% FITNESS  FOR A PARTICULAR  PURPOSE AND  NONINFRINGEMENT. IN NO EVENT SHALL *
% THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER *
% LIABILITY, WHETHER  IN AN  ACTION OF CONTRACT, TORT  OR OTHERWISE, ARISING *
% FROM,  OUT OF  OR IN  CONNECTION  WITH THE  SOFTWARE OR  THE USE  OR OTHER *
% DEALINGS IN THE SOFTWARE.                                                  *
%                                                                            *
% The SFS Toolbox  allows to simulate and  investigate sound field synthesis *
% methods like wave field synthesis or higher order ambisonics.              *
%                                                                            *
% https://sfs.readthedocs.io                            sfstoolbox@gmail.com *
%*****************************************************************************

%% ===== Checking of input  parameters ==================================
% Disabled checking for performance reasons

%% ===== Configuration ==================================================
c = conf.c;
phase = conf.phase;

%% ===== Computation =====================================================
% Frequency
omega = 2*pi*f;
% Calculate Green's function for the given source model
if strcmp('ps',src)
    % Source model for a point source: 3D Green's function.
    %
    %              1  e^(-i w/c |x-xs|)
    % G(x-xs,w) = --- -----------------
    %             4pi      |x-xs|
    %
    % https://sfs.rtfd.io/en/3.2/sources/#equation-fd-point
    %
    G = 1/(4*pi) * exp(-1i*omega/c .* sqrt((x-xs(1)).^2+(y-xs(2)).^2+(z-xs(3)).^2)) ./ ...
            sqrt((x-xs(1)).^2+(y-xs(2)).^2+(z-xs(3)).^2);

elseif strcmp('dps',src)
    % Source model for a dipole point source: derivative of 3D Green's function.
    %
    %  d                1   / iw       1    \   (x-xs) ns
    % ---- G(x-xs,w) = --- | ----- + ------- | ----------- e^(-i w/c |x-xs|)
    % d ns             4pi  \  c     |x-xs| /   |x-xs|^2
    %
    % r = |x-xs|
    r = sqrt((x-xs(1)).^2+(y-xs(2)).^2+(z-xs(3)).^2);
    % scalar = (x-xs) nxs
    scalar = xs(4).*(x-xs(1)) + xs(5).*(y-xs(2))  + xs(6).*(z-xs(3));
    %
    G = 1/(4*pi) .* (1i*omega/c + 1./r) .* scalar./r.^2 .* exp(-1i*omega/c.*r);

elseif strcmp('ls',src)
    % Source model for a line source: 2D Green's function.
    %
    %                i   (2) / w        \
    % G(x-xs,w) =  - -  H0  |  - |x-xs|  |
    %                4       \ c        /
    %
    % https://sfs.rtfd.io/en/3.2/sources/#equation-fd-line
    %
    G = -1i/4 * besselh(0,2,omega/c* ...
        sqrt( (x-xs(1)).^2 + (y-xs(2)).^2 + (z-xs(3)).^2 ));

elseif strcmp('pw',src)
    % Source model for a plane wave:
    %
    % G(x,w) = e^(-i w/c n x)
    %
    % https://sfs.rtfd.io/en/3.2/sources/#equation-fd-plane
    %
    % Direction of plane wave
    nxs = xs(:,1:3) / norm(xs(:,1:3));
    % Calculate sound field
    G = exp(-1i*omega/c.*(nxs(1).*x+nxs(2).*y+nxs(3).*z));
else
    error('%s: %s is not a valid source model for the Green''s function', ...
        upper(mfilename),src);
end

% Add phase to be able to simulate different time steps
G = G .* exp(-1i*phase);


classdef MimImageCoordinateUtilities
    % MimImageCoordinateUtilities. Utility functions related to processing 3D
    % image coordinates
    %
    %
    %     Licence
    %     -------
    %     Part of the TD MIM Toolkit. https://github.com/tomdoel
    %     Author: Tom Doel, Copyright Tom Doel 2014.  www.tomdoel.com
    %     Distributed under the MIT licence. Please see website for details.
    %

    methods (Static)

        % In Matlab, matrices can be represented as a linear vector. So every
        % point in a 3D matrix has a linear index as well as an i-j-k
        % coordinate. This function returns the 'offset' values which can be
        % added to the linear index of any point to return the linear indices of
        % its nearest neighbours.
        function [linear_offsets, linear_offsets27] = GetLinearOffsets(image_size)
            % Compute linear index offsets for diretion vectors
            dirs = [5, 23, 11, 17, 13, 15];
            linear_offsets = MimImageCoordinateUtilities.GetLinearOffsetsForDirections(dirs, image_size);

            dirs = 1:27;
            linear_offsets27 = MimImageCoordinateUtilities.GetLinearOffsetsForDirections(dirs, image_size);
        end

        function linear_offsets = GetLinearOffsetsForDirections(dirs, image_size)
            direction_vectors = MimImageCoordinateUtilities.CalculateDirectionVectors;
            linear_offsets = zeros(1, numel(dirs));
            for n = 1 : length(dirs)
                direction = dirs(n);
                direction_vector = direction_vectors(direction, :);
                start_point = [2 2 2];
                i_end_point = start_point + direction_vector;
                i = [start_point(1); i_end_point(1)];
                j = [start_point(2); i_end_point(2)];
                k = [start_point(3); i_end_point(3)];
                linear_indices = sub2ind(image_size, i, j, k);
                linear_offsets(n) = linear_indices(2) - linear_indices(1);
            end
        end

        % Returns the coordinates of each point in a 3x3x3 matrix relative to
        % its centre
        function direction_vectors = CalculateDirectionVectors
            [i, j, k] = ind2sub([3 3 3], 1:27);
            direction_vectors = [i' - 2, j' - 2, k' - 2];
        end

        % This function alters matrix indices to transform from a smaller matrix to
        % a bigger one
        function new_indices = OffsetIndices(indices, offset, size_small, size_big)
            indices_i = (indices - 1);
            div1 = (size_small(1));
            div2 = (size_small(1)*size_small(2));

            k_mod = rem(indices_i, div2);

            k = (indices_i - k_mod)/div2; % Equivalent to idivide but quicker

            i = mod(k_mod, div1);

            j = (k_mod - i)/div1; % Equivalent to idivide but quicker

            i = i + offset(1);
            j = j + offset(2);
            k = k + offset(3);

            % Note that i,j,k can be negative, in the case where a border has
            % been added to the image so its coordinates extend beyond the
            % boundaries of the original image

            new_indices = 1 + (i) + (j)*size_big(1) + (k)*size_big(1)*size_big(2);
        end

        % Creates an image cropped to the smallest box size that encloses all
        % the points specified by their linear indices.
        function [offset reduced_image reduced_image_size] = GetMinimalImageForIndices(indices, image_size)
            if size(indices, 1) > 1
                error('GetMinimalImageForIndices requires indices to be in a row vector');
            end
            indices = int32(indices);
            [i, j, k] = MimImageCoordinateUtilities.FastInd2sub(image_size, indices);

            voxel_coordinates = [i' j' k'];
            mins = min(voxel_coordinates, [], 1);
            maxs = max(voxel_coordinates, [], 1);
            reduced_image_size = maxs - mins + int32([1 1 1]);
            reduced_image = false(reduced_image_size);
            offset = mins - 1;
            i = MimImageCoordinateUtilities.FastSub2ind(reduced_image_size, voxel_coordinates(:,1)-offset(1), voxel_coordinates(:,2)-offset(2), voxel_coordinates(:,3)-offset(3));

            reduced_image(i) = true;
        end

        % A faster alternative to Ind2sub
        function [i, j, k] = FastInd2sub(im_size, indices)
            indices = indices - 1;
            div1 = (im_size(1));
            div2 = ((im_size(1)*im_size(2)));

            k_mod = rem(indices, div2);

            k = 1 + (indices - k_mod)/div2; % Equivalent to idivide but quicker
            i = 1 + mod(k_mod, im_size(1));
            j = 1 + (k_mod - i + 1)/div1; % Equivalent to idivide but quicker
        end

        function indices = FastSub2ind(im_size, i, j, k)
            indices = i + (j-1)*im_size(1) + (k-1)*im_size(1)*im_size(2);
        end

        function rot_matrix = GetEulerRotationMatrix(phi, theta, psi)
            rot_matrix = zeros(3,3);

            rot_matrix(1, 1) = cos(psi)*cos(phi) - cos(theta)*sin(phi)*sin(psi);
            rot_matrix(1, 2) = cos(psi)*sin(phi) + cos(theta)*cos(phi)*sin(psi);
            rot_matrix(1, 3) = sin(psi)*sin(theta);

            rot_matrix(2, 1) = -sin(psi)*cos(phi) - cos(theta)*sin(phi)*cos(psi);
            rot_matrix(2, 2) = -sin(psi)*sin(phi) + cos(theta)*cos(phi)*cos(psi);
            rot_matrix(2, 3) = cos(psi)*sin(theta);

            rot_matrix(3, 1) =  sin(theta)*sin(phi);
            rot_matrix(3, 2) = -sin(theta)*cos(psi);
            rot_matrix(3, 3) = cos(theta);
        end

        function affine_matrix = CreateAffineMatrix(x)
            affine_matrix = zeros(3, 4, 'single');
            affine_matrix(:) = x(:);
            affine_matrix = [affine_matrix; [0 0 0 1]];
        end

        function affine_matrix = CreateAffineTranslationMatrix(x)
            affine_matrix = zeros(3, 4, 'single');
            affine_matrix(1, 1) = 1;
            affine_matrix(2, 2) = 1;
            affine_matrix(3, 3) = 1;
            affine_matrix(4, 4) = 1;
            affine_matrix(1:3, 4) = x;
        end

        function affine_matrix = CreateRigidAffineMatrix(x)
            affine_matrix = zeros(3, 4, 'single');

            euler_rot_matrix = MimImageCoordinateUtilities.GetEulerRotationMatrix(x(1), x(2), x(3));
            affine_matrix(1:3, 1:3) = euler_rot_matrix;
            affine_matrix(1:3, 4) = x(4:6);

            affine_matrix = [affine_matrix; [0 0 0 1]];
        end

        function [i, j, k] = TransformCoordsAffine(i, j, k, augmented_matrix)
            [j, i, k] = MimImageCoordinateUtilities.TranslateAndRotateMeshGrid(j, i, k, augmented_matrix(1:3,1:3), augmented_matrix(1:3,4));
        end

        function [i, j, k] = TransformCoordsFluid(i, j, k, deformation_field)
            i = i - deformation_field.RawImage(:,:,:,1);
            j = j - deformation_field.RawImage(:,:,:,2);
            k = k - deformation_field.RawImage(:,:,:,3);
        end

        function [X, Y, Z] = TranslateAndRotateMeshGrid(X, Y, Z, rot_matrix, trans_matrix)
            % Rotates and translates meshgrid generated coordinates in 3D
            % Note coordinates are [XYZ] NOT [IJK]
            [X, Y, Z] = MimImageCoordinateUtilities.RotateMeshGrid(X + trans_matrix(1), Y + trans_matrix(2), Z + trans_matrix(3), rot_matrix);
        end

        function [X, Y, Z] = RotateMeshGrid(X, Y, Z, rot_matrix)
            % Rotates coordinates that are given in 3D meshgrid matrices
            coords = rot_matrix * [ ...
                reshape(X, 1, numel(X)); ...
                reshape(Y, 1, numel(Y)); ...
                reshape(Z, 1, numel(Z)) ...
                ];

            X = reshape(coords(1, :), size(X));
            Y = reshape(coords(2, :), size(Y));
            Z = reshape(coords(3, :), size(Z));
        end

        function affine_matrix = GetAffineTranslationFromPatientPosition(image_1, image_2)

            % Get the coordinates of the centre of the first voxel in image1,
            % relative to the centre of image1
            [i1, j1, k1] = image_1.GlobalCoordinatesToCoordinatesMm([1, 1, image_1.OriginalImageSize(3)]);
            [i1, j1, k1] = image_1.GlobalCoordinatesMmToCentredGlobalCoordinatesMm(i1, j1, k1);
            image_1_origin_coordinates = [i1, j1, k1];
            image_1_centre_coordinates = image_1.GlobalOrigin - image_1_origin_coordinates;

            % Get the coordinates of the centre of the first voxel in image2,
            % relative to centre of image2
            [i2, j2, k2] = image_2.GlobalCoordinatesToCoordinatesMm([1, 1, image_2.OriginalImageSize(3)]);
            [i2, j2, k2] = image_2.GlobalCoordinatesMmToCentredGlobalCoordinatesMm(i2, j2, k2);
            image_2_origin_coordinates = [i2, j2, k2];
            image_2_centre_coordinates = image_2.GlobalOrigin - image_2_origin_coordinates;

            translation = image_1_centre_coordinates - image_2_centre_coordinates;

            translation = translation([2 1 3]);
            translation(3) = - translation(3);
            affine_matrix = MimImageCoordinateUtilities.CreateAffineTranslationMatrix(translation);
        end

        function deformation_field = AdjustDeformationFieldForInitialAffineTransformation(deformation_field, affine_initial_matrix)
            % To combine a rigid transformation with a nonrigid deformation field,
            % compute the change in image coordinates after applying the
            % deformation field and then the rigid affine transformation.

            [df_i, df_j, df_k] = deformation_field.GetCentredGlobalCoordinatesMm;
            [df_i, df_j, df_k] = ndgrid(df_i, df_j, df_k);
            [df_i_t, df_j_t, df_k_t] = MimImageCoordinateUtilities.TransformCoordsFluid(df_i, df_j, df_k, deformation_field);
            [df_i_t, df_j_t, df_k_t] = MimImageCoordinateUtilities.TransformCoordsAffine(df_i_t, df_j_t, df_k_t, affine_initial_matrix);

            deformation_field_raw = zeros(deformation_field.ImageSize);
            deformation_field_raw(:,:,:,1) = df_i - df_i_t;
            deformation_field_raw(:,:,:,2) = df_j - df_j_t;
            deformation_field_raw(:,:,:,3) = df_k - df_k_t;
            deformation_field2 = deformation_field.BlankCopy;
            deformation_field2.ChangeRawImage(deformation_field_raw);
            deformation_field = deformation_field2;
        end

        function [permutation_vector, flip] = GetDimensionPermutationVectorFromDicomOrientation(orientation, reporting)
            % Returns a vector which defines the order in which the dimensions of an
            % DICOM image volume should be permuted in order to align it with the
            % PTK coordinate system

            % DICOM coordinates are XYZ but Matlab's coordinates are YXZ. We
            % convert the orientation to Matlab coordinates, which we refer to as IJK.
            orientation_1 = orientation([5, 4, 6])'; % Direction of first image axis in ijk (=yxz) coordinates
            orientation_2 = orientation([2, 1, 3])'; % Direction of second image axis in ijk (=yxz) coordinates

            % By switching the i and j axes we have inverted the coordinate
            % system, so we need to flip the k dimension
            orientation_1(3) = - orientation_1(3);
            orientation_2(3) = - orientation_2(3);

            % Determine the PTK dimensions to which each of these vectors correspond
            [permutation_vector, dimension_1, dimension_2, dimension_3] = MimImageCoordinateUtilities.GetPermutationFromOrientations(orientation_1, orientation_2, reporting);

            % Calculate flip for each dimension, based on whether the
            % dimension axis lies in the same or opposite direction to the
            % image axis
            orientation_3 = cross(orientation_2, orientation_1);
            flip = MimImageCoordinateUtilities.GetFlipFromOrientations(orientation_1, orientation_2, orientation_3, dimension_1, dimension_2, dimension_3);

            % Check the resulting vector is valid
            if (sum(permutation_vector == 1) ~= 1) || (sum(permutation_vector == 2) ~= 1) || (sum(permutation_vector == 3) ~= 1) || ...
                    ~isempty(setdiff(permutation_vector, [1,2,3]))
                reporting.Error('MimImageCoordinateUtilities:InvalidPermutationVector', 'GetDimensionPermutationVectorFromDicomOrientation() resulted in an invalid permutation vector');
            end
        end

        function [permutation_vector, flip] = GetDimensionPermutationVectorFromNiiOrientation(header, reporting)
            % Returns a vector which defines the order in which the dimensions of a
            % nii image volume should be permuted in order to align it with the
            % PTK coordinate system

            if header.SformCode > 0
                d1 = [-1; -1; 1].*header.SrowX(1:3);
                d2 = [-1; -1; 1].*header.SrowY(1:3);
                [permutation_vector, flip] = MimImageCoordinateUtilities.GetDimensionPermutationVectorFromDicomOrientation([d1; d2], reporting);
            elseif header.QformCode > 0
                B = header.QuaternB;
                C = header.QuaternC;
                D = header.QuaternD;
                A = sqrt(1 - B^2 - C^2 - D^2);
                d1 = [-1; -1; 1].*[A^2+B^2-C^2-D^2; 2*(B*C - A*D); 2*(B*D+A*C)];
                d2 = [-1; -1; 1].*[2*(B*C + A*D); A^2 + C^2 - B^2 - D^2; 2*(C*D - A*B)];
                d3 = [-1; -1; 1].*[2*(B*D - A*C); 2*(C*D + A*B); A^2 + D^2 - B^2 - C^2];
                [permutation_vector, flip] = MimImageCoordinateUtilities.GetDimensionPermutationVectorFromDicomOrientation([d1; d2], reporting);
            else
                d1 = [-1; -1; 1].*[1; 0; 0];
                d2 = [-1; -1; 1].*[0; 1; 0];
                [permutation_vector, flip] = MimImageCoordinateUtilities.GetDimensionPermutationVectorFromDicomOrientation([d1; d2], reporting);
            end
        end

        function [permutation_vector, flip] = GetDimensionPermutationVectorForAnalyze(orientation, reporting)
            permutation_vector = [2, 1, 3];
            flip = [false, false, true];
        end

        function [permutation_vector, dimension_1, dimension_2, dimension_3] = GetPermutationFromOrientations(orientation_1, orientation_2, reporting)
            [dimension_1, dimension_2, dimension_3] = MimImageCoordinateUtilities.GetDimensionIndicesFromOrientations(orientation_1, orientation_2, reporting);

            permutation_vector = [3, 3, 3];
            permutation_vector(dimension_1) = 1;
            permutation_vector(dimension_2) = 2;
        end

        function flip = GetFlipFromOrientations(orientation_1, orientation_2, orientation_3, dimension_1, dimension_2, dimension_3)
            flip = [false, false, false];
            flip(dimension_1) = orientation_1(dimension_1) < 0;
            flip(dimension_2) = orientation_2(dimension_2) < 0;
            flip(dimension_3) = orientation_3(dimension_3) < 0;
        end

        function dicom_cosine = AnatomicalOrientationToDicomCosine(anatomical_orientation_char, reporting)
            switch anatomical_orientation_char
                case 'R'
                    dicom_cosine = [1, 0, 0];
                case 'L'
                    dicom_cosine = [-1, 0, 0];
                case 'A'
                    dicom_cosine = [0, 1, 0];
                case 'P'
                    dicom_cosine = [0, -1, 0];
                case 'I'
                    dicom_cosine = [0, 0, 1];
                case 'S'
                    dicom_cosine = [0, 0, -1];
                otherwise
                    reporting.Error('MimImageCoordinateUtilities:UnknownAnatomicalOrientation', ['MimImageCoordinateUtilities: WARNING: no implementation yet for anatomical orientation ' anatomical_orientation_char '.']);
            end
        end

        function [permutation_vector, flip_orientation] = GetDimensionPermutationVectorFromAnatomicalOrientation(anatomical_orientation_string, reporting)
            direction_cosine_1 = MimImageCoordinateUtilities.AnatomicalOrientationToDicomCosine(anatomical_orientation_string(1), reporting);
            direction_cosine_2 = MimImageCoordinateUtilities.AnatomicalOrientationToDicomCosine(anatomical_orientation_string(2), reporting);
            direction_cosine_3 = MimImageCoordinateUtilities.AnatomicalOrientationToDicomCosine(anatomical_orientation_string(3), reporting);

            [permutation_vector, flip_orientation] = MimImageCoordinateUtilities.GetDimensionPermutationVectorFromMhdCosines(direction_cosine_1, direction_cosine_2, direction_cosine_3, reporting);
        end

        function [permutation_vector, flip_orientation] = GetDimensionPermutationVectorFromMhdCosines(direction_cosine_1, direction_cosine_2, direction_cosine_3, reporting)
            % Determines the permutation and flip transformations required
            % to convert MetaIO data to PTK data

            % DICOM coordinates are XYZ but Matlab's coordinates are YXZ. We
            % convert the orientation to Matlab coordinates, which we refer to as IJK.
            orientation_1 = direction_cosine_2([2, 1, 3])'; % Direction of first image axis in ijk (=yxz) coordinates
            orientation_2 = direction_cosine_1([2, 1, 3])'; % Direction of second image axis in ijk (=yxz) coordinates
            orientation_3 = direction_cosine_3([2, 1, 3])'; % Direction of third image axis in ijk (=yxz) coordinates

            % By switching the i and j axes we have inverted the coordinate
            % system, so we need to flip the k dimension
            orientation_1(3) = - orientation_1(3);
            orientation_2(3) = - orientation_2(3);
            orientation_3(3) = - orientation_3(3);

            % Determine the PTK dimensions to which each of these vectors correspond
            [permutation_vector, dimension_1, dimension_2, dimension_3] = MimImageCoordinateUtilities.GetPermutationFromOrientations(orientation_1, orientation_2, reporting);

            % Calculate flip for each dimension, based on whether the
            % dimension axis lies in the same or opposite direction to the
            % image axis
            flip_orientation = MimImageCoordinateUtilities.GetFlipFromOrientations(orientation_1, orientation_2, orientation_3, dimension_1, dimension_2, dimension_3);

            % Check the resulting vector is valid
            if (sum(permutation_vector == 1) ~= 1) || (sum(permutation_vector == 2) ~= 1) || (sum(permutation_vector == 3) ~= 1) || ...
                    ~isempty(setdiff(permutation_vector, [1,2,3]))
                reporting.Error('MimImageCoordinateUtilities:InvalidPermutationVector', 'GetDimensionPermutationVectorFromAnatomicalOrientation() resulted in an invalid permutation vector');
            end
        end

        function [dimension_number_1, dimension_number_2, dimension_number_3] = GetDimensionIndicesFromOrientations(orientation_vector_1, orientation_vector_2, reporting)
            % The orientation vector is formed of cosines. Typically these will
            % be 1s and 0s but we allow for small variations in the angles.

            [~, dimension_number_1] = max(abs(orientation_vector_1(:)));
            remaining_dimensions = setdiff([1,2,3], dimension_number_1);
            reduced_orientation_vector_2 = orientation_vector_2(remaining_dimensions);
            [~, dimension_number_2_from_reduced_set] = max(abs(reduced_orientation_vector_2(:)));
            dimension_number_2 = remaining_dimensions(dimension_number_2_from_reduced_set);
            dimension_number_3 = setdiff([1, 2, 3], [dimension_number_1, dimension_number_2]);
        end

        function spline_points = CreateSplineCurve(points, num_points)
            number_of_points = size(points, 1);
            number_of_coordinates = size(points, 2);
            extended_points = zeros(number_of_points + 2, number_of_coordinates);
            extended_points(2 : number_of_points + 1, :) = points;
            extended_points(1, :) = extended_points(2, :) - (extended_points(3, :) - extended_points(2, :));
            extended_points(end, :) = extended_points(end - 1, :) - (extended_points(end - 2, : ) - extended_points(end - 1, :));

            extended_number_of_points = size(extended_points, 1);
            interval_values = linspace(0, 1, num_points + 1);
            interval_values2 = interval_values.^2;
            interval_values3 = interval_values.^3;

            for index = 2 : extended_number_of_points - 2
                coeffs = (1/6).*[...
                        extended_points(index - 1,:)  + 4*extended_points(index, :) + extended_points(index + 1, :); ...
                    - 3*extended_points(index - 1, :) + 3*extended_points(index + 1, :); ...
                      3*extended_points(index - 1, :) - 6*extended_points(index, :) + 3*extended_points(index + 1, :); ...
                    -   extended_points(index - 1, :) + 3*extended_points(index, :) - 3*extended_points(index + 1, :) + extended_points(index+2, :) ...
                ]';

                interval = [ones(size(interval_values)); interval_values; interval_values2; interval_values3];
                spline_points(:, (index - 2)*num_points + 1 : (index - 1)*num_points + 1) = coeffs*interval;
            end
        end

        function dicom_coordinates = PTKToDicomCoordinates(ptk_coordinates, template_image)
            offset = template_image.GetDicomOffset;
            dicom_coordinates = ptk_coordinates + repmat(offset, size(ptk_coordinates, 1), 1);
        end

        function [d_x, d_y, d_z] = PTKToDicomCoordinatesCoordwise(p_x, p_y, p_z, template_image)
            offset = template_image.GetDicomOffset;
            d_x = p_x + offset(1);
            d_y = p_y + offset(2);
            d_z = p_z + offset(3);
        end

        function ptk_coordinates = DicomToPTKCoordinates(dicom_coordinates, template_image)
            offset = template_image.GetDicomOffset;
            ptk_coordinates = dicom_coordinates - repmat(offset, size(dicom_coordinates, 1), 1);
        end

        function dicom_coordinates = PTKToCornerCoordinates(ptk_coordinates, template_image)
            offset = template_image.GetCornerOffset;
            dicom_coordinates = ptk_coordinates + repmat(offset, size(ptk_coordinates, 1), 1);
        end

        function [d_x, d_y, d_z] = PTKToCornerCoordinatesCoordwise(p_x, p_y, p_z, template_image)
            offset = template_image.GetCornerOffset;
            d_x = p_x + offset(1);
            d_y = p_y + offset(2);
            d_z = p_z + offset(3);
        end

        function ptk_coordinates = CornerToPTKCoordinates(corner_coordinates, template_image)
            offset = template_image.GetCornerOffset;
            ptk_coordinates = corner_coordinates - repmat(offset, size(corner_coordinates, 1), 1);
        end

        function [ptk_x, ptk_y, ptk_z] = CoordinatesMmToPTKCoordinates(ic, jc, kc)
            ptk_x = jc;
            ptk_y = ic;
            ptk_z = -kc;
        end

        function coordinates_mm = PTKCoordinatesToCoordinatesMm(ptk_coordinates)
            coordinates_mm = [ptk_coordinates(:, 2), ptk_coordinates(:, 1), - ptk_coordinates(:, 3)];
        end

        function dicom_coordinates = PTKCoordinatesToCornerCoordinates(ptk_coordinates, template_image)
            offset = template_image.GetCornerOffset;
            dicom_coordinates = ptk_coordinates + repmat(offset, size(ptk_coordinates, 1), 1);
        end

        function dicom_coordinates = CoordinatesMmToCornerCoordinates(ptk_coordinates, template_image)
            voxel_size = template_image.VoxelSize;

            % Adjust to coordinates at centre of first voxel
            offset = -voxel_size/2;
            offset = [offset(2), offset(1), -offset(3)];

            % Shift the global origin to the first slice of the image
            global_origin = [0, 0, 0];

            % Adjust to Dicom origin
            offset = offset + global_origin;

            dicom_coordinates = [ptk_coordinates(:, 2), ptk_coordinates(:, 1), - ptk_coordinates(:, 3)];
            dicom_coordinates = dicom_coordinates + repmat(offset, size(ptk_coordinates, 1), 1);
        end

        function ptk_coordinates = CornerToCoordinatesMm(dicom_coordinates, template_image)
            voxel_size = template_image.VoxelSize;

            offset = -voxel_size/2;
            offset = [offset(2), offset(1), -offset(3)];

            dicom_coordinates = dicom_coordinates - repmat(offset, size(dicom_coordinates, 1), 1);

            ptk_coordinates = [dicom_coordinates(:, 2), dicom_coordinates(:, 1), - dicom_coordinates(:, 3)];
        end

        function ptk_coordinates = ConvertToPTKCoordinates(coordinates, coordinate_system, template_image)
            switch coordinate_system
                case MimCoordinateSystem.PTK
                    ptk_coordinates = coordinates;
                case MimCoordinateSystem.Dicom
                    ptk_coordinates = MimImageCoordinateUtilities.DicomToPTKCoordinates(coordinates, template_image);
                case MimCoordinateSystem.DicomUntranslated
                    ptk_coordinates = MimImageCoordinateUtilities.CornerToPTKCoordinates(coordinates, template_image);
                otherwise
                    reporting.Error('MimImageCoordinateUtilities:UnsupportedCoordinateSystem', 'The coordinate system specified by parameter coordinate_system is not supported');
            end
        end

        function coordinates = ConvertFromPTKCoordinates(ptk_coordinates, coordinate_system, template_image)
            switch coordinate_system
                case MimCoordinateSystem.PTK
                    coordinates = ptk_coordinates;
                case MimCoordinateSystem.Dicom
                    coordinates = MimImageCoordinateUtilities.PTKToDicomCoordinates(ptk_coordinates, template_image);
                case MimCoordinateSystem.DicomUntranslated
                    coordinates = MimImageCoordinateUtilities.PTKToCornerCoordinates(ptk_coordinates, template_image);
                otherwise
                    reporting.Error('MimImageCoordinateUtilities:UnsupportedCoordinateSystem', 'The coordinate system specified by parameter coordinate_system is not supported');
            end
        end

        function [c_x, c_y, c_z] = ConvertFromPTKCoordinatesCoordwise(p_x, p_y, p_z, coordinate_system, template_image)
            switch coordinate_system
                case MimCoordinateSystem.PTK
                    c_x = p_x;
                    c_y = p_y;
                    c_z = p_z;
                case MimCoordinateSystem.Dicom
                    [c_x, c_y, c_z] = MimImageCoordinateUtilities.PTKToDicomCoordinatesCoordwise(p_x, p_y, p_z, template_image);
                case MimCoordinateSystem.DicomUntranslated
                    [c_x, c_y, c_z] = MimImageCoordinateUtilities.PTKToCornerCoordinatesCoordwise(p_x, p_y, p_z, template_image);
                otherwise
                    reporting.Error('MimImageCoordinateUtilities:UnsupportedCoordinateSystem', 'The coordinate system specified by parameter coordinate_system is not supported');
            end
        end

        function voxel_indices = AddNearestNeighbours(voxel_indices, template_image)
            if isempty(voxel_indices)
                return;
            end
            [~, linear_offsets27] = MimImageCoordinateUtilities.GetLinearOffsets(template_image.ImageSize);
            voxel_indices = repmat(int32(voxel_indices), 27, 1) + repmat(int32(linear_offsets27'), 1, length(voxel_indices));
            voxel_indices = unique(voxel_indices(:));
        end

        function global_coordinates = GetGlobalCoordinatesForPoints(point_list, template_image)
            xc = [point_list.CoordX];
            yc = [point_list.CoordY];
            zc = [point_list.CoordZ];
            ptk_coords = [xc', yc', zc'];
            coordinates_mm = MimImageCoordinateUtilities.PTKCoordinatesToCoordinatesMm(ptk_coords);
            global_coordinates = round(template_image.CoordinatesMmToGlobalCoordinates(coordinates_mm));
        end

        function global_indices = GetGlobalIndicesForPoints(point_list, template_image)
            global_coordinates = MimImageCoordinateUtilities.GetGlobalCoordinatesForPoints(point_list, template_image);
            global_indices = template_image.GlobalCoordinatesToGlobalIndices(global_coordinates);
        end

        function dist = DistanceBetweenPoints(point_1, point_2)
            dist = norm([point_1.CoordX - point_2.CoordX, point_1.CoordY - point_2.CoordY, point_1.CoordZ - point_2.CoordZ]);
        end

        % Select an appropriate image orientation for exporting an image
        function orientation = ChooseOrientation(voxel_size)
            orientation = GemImageOrientation.XY;
            [sorted_voxel_size, sorted_voxel_size_index] = sort(voxel_size, 'descend');
            if abs(sorted_voxel_size(1) - sorted_voxel_size(2)) > abs(sorted_voxel_size(2) - sorted_voxel_size(3))
                if sorted_voxel_size_index(1) == 1
                    orientation = GemImageOrientation.XZ;
                end
            end
        end

        function offset_voxels = GetOriginOffsetVoxels(from_image, to_image)
            if ~isempty(to_image.GlobalOrigin) && ~isempty(from_image.GlobalOrigin)
                offset_mm = to_image.GlobalOrigin - from_image.GlobalOrigin;
                offset_voxels = offset_mm./from_image.VoxelSize;
            else
                offset_voxels = [0, 0, 0];
            end
        end

        function [Y, X] = GetSliceCoordinates(coordinates_3d, dimension)
            % Returns the 2D [Y, X] coordinates for a 2D slice in the
            % specified orientation given a set of 3D [i,j,k] coordinates
           switch dimension
               case GemImageOrientation.XZ
                   Y = coordinates_3d(:, 3);
                   X = coordinates_3d(:, 2);
               case GemImageOrientation.YZ
                   Y = coordinates_3d(:, 3);
                   X = coordinates_3d(:, 1);
               case GemImageOrientation.XY
                   Y = coordinates_3d(:, 1);
                   X = coordinates_3d(:, 2);
               otherwise
                   error('Unsupported dimension');
           end
        end
    end
end


function gr=bvalue(catalogObject, mcType, manual_on)
    %BVALUE evaluate b-value, a-value and magnitude of completeness
    % of an earthquake catalog stored in a Catalog object.
    %
    % gr = BVALUE(catalogObject, MCTYPE) produces a Gutenberg-Richter type plot
    %    with the best fit line and display of b-,a-values and Mc
    %    for catalogObject. These values are also returned in a structure.
    %    MCTYPE is a number from 1-5
    %    to select the algorithm used for calculation of the
    %    magnitude of completeness. Options are:
    %
    %    1: Maximum curvature
    %    2: Fixed Mc = minimum magnitude (Mmin)
    %    3: Mc90 (90% probability)
    %    4: Mc95 (95% probability)
    %    5: Best combination (Mc95 - Mc90 - maximum curvature)
    %
    % * Note: it seems only 1 only really works, and 5 is same as 1 *'
    %
    % gr = BVALUE(catalogObject, MCTYPE, manual_on) where the value of manual_on
    %    computes as true will give the user the ability to manually pick a
    %    linear segment on the graph too (which is then plotted with a
    %    green line). The manual Mc and bvalue are returned in the gr
    %    structure as gr.Mc_manual and gr.bvalue_manual

    % Liberally adapted from original code in ZMAP.
    % Author: Silvio De Angelis, 27/07/2012 00:00:00
    % Modified and included in Catalog by Glenn Thompson,
    % 14/06/2014

    % This program is free software; you can redistribute it and/or modify
    % it under the terms of the GNU General Public License as published by
    % the Free Software Foundation; either version 2 of the License, or
    % (at your option) any later version.
    %
    % This program is distributed in the hope that it will be useful,
    % but WITHOUT ANY WARRANTY; without even the implied warranty of
    % MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
    % GNU General Public License for more details.
    %
    % You should have received a copy of the GNU General Public License
    % along with this program; if not, write to the
    % Free Software Foundation, Inc.,
    % 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.

    if nargin < 2
        disp('* Note: it seems only 1 only really works, and 5 is same as 1 *')
        mcType = menu('mcType can be:','Maximum curvature','Fixed Mc = minimum magnitude (Mmin)', ...
            'Mc90 (90% probability)', 'Mc95 (95% probability)', ...
            'Best combination (Mc95 - Mc90 - maximum curvature)')
    end
    if ~exist('manual_on','var')
        manual_on = false;
    end

    % form magnitude vector - removing any NaN values with find
    good_magnitude_indices = find(catalogObject.mag > -3.0);
    mag = catalogObject.mag(good_magnitude_indices);
    %MIN AND MAX MAGNITUDE IN catalogObject
    minimum_mag = min(mag);
    maximum_mag = max(mag);

    %COUNT EVENTS IN EACH MAGNITUDE BIN
    [bval, xt2] = hist(mag, (minimum_mag:0.1:maximum_mag));

    %CUMULATIVE NUMBER OF EVENTS IN EACH MAGNITUDE BIN
    bvalsum = cumsum(bval);

    %NUMBER OF EVENTS IN EACH BIN IN REVERSE ORDER
    bval2 = bval(length(bval):-1:1);

    %NUMBER OF EVENTS IN EACH MAGNITUDE BIN IN REVERSE ORDER
    bvalsum3 = cumsum(bval(length(bval):-1:1));

    %BINS IN REVERSE ORDER
    xt3 = (maximum_mag:-0.1:minimum_mag);
    backg_ab = log10(bvalsum3);

    %CREATE FIGURE WINDOW AND MAKE FREQUENCY-MAGNITUDE PLOT
    figure('Color','w','Position',[0 0 600 600])

    pl = semilogy(xt3,bvalsum3,'sb'); % semilogy is same as plot, except a log (base10) scale is used for Y-axis
    set(pl, 'LineWidth', [1.0],'MarkerSize', [10],'MarkerFaceColor','r','MarkerEdgeColor','k');
    axis square
    hold on

    pl1 = semilogy(xt3,bval2,'^b');
    set(pl1, 'LineWidth',[1.0],'MarkerSize',[10],'MarkerFaceColor','w','MarkerEdgeColor','k');
    xlabel('Magnitude','Fontsize', 12)
    ylabel('Cumulative Number','Fontsize',12)
    set(gca,'visible','on','FontSize',12,'FontWeight','normal',...
        'FontWeight','bold','LineWidth',[1.0],'TickDir','in','Ticklength',[0.01 0.01],...
        'Box','on','Tag','cufi','color','w')

    %ESTIMATE B-VALUE (MAX LIKELIHOOD ESTIMATE)
    Nmin = 10;
    fMccorr = 0;
    fBinning = 0.1;

    if length(mag) >= Nmin

        %GOODNESS-OF-FIT TO POWER LAW
        %%%%%%%%%%%%%%%%%% mcperc_ca3.m start %%%%%%%%%%%%%%%%%%%%
        % This is a completeness determination test

        [bval,xt2] = hist(mag,-2:0.1:6);
        l = max(find(bval == max(bval)));
        magco0 =  xt2(l);

        dat = [];

        %for i = magco0-0.6:0.1:magco0+0.2
        for i = magco0-0.5:0.1:magco0+0.7
            l = mag >= i - 0.0499;
            nu = length(mag(l));
            if length(mag(l)) >= 25;
                %[bv magco stan av] =  bvalca3(catZmap(l,:),2,2);
                [mw bv2 stan2 av] =  Catalog.bvalue_lib.bmemag(mag(l));
                Catalog.bvalue_lib.synthb_aut;
                dat = [ dat ; i res2];
            else
                dat = [ dat ; i nan];
            end

        end

        j =  min(find(dat(:,2) < 10 ));
        if isempty(j) == 1; Mc90 = nan ;
        else;
            Mc90 = dat(j,1);
        end

        j =  min(find(dat(:,2) < 5 ));
        if isempty(j) == 1; Mc95 = nan ;
        else;
            Mc95 = dat(j,1);
        end

        j =  min(find(dat(:,2) < 10 ));
        if isempty(j) == 1; j =  min(find(dat(:,2) < 15 )); end
        if isempty(j) == 1; j =  min(find(dat(:,2) < 20 )); end
        if isempty(j) == 1; j =  min(find(dat(:,2) < 25 )); end
        j2 =  min(find(dat(:,2) == min(dat(:,2)) ));
        %j = min([j j2]);

        Mc = dat(j,1);
        magco = Mc;
        prf = 100 - dat(j2,2);
        if isempty(magco) == 1; magco = nan; prf = 100 -min(dat(:,2)); end
        %display(['Completeness Mc: ' num2str(Mc) ]);
        %%%%%%%%%%%%%%%%%% mcperc_ca3.m end %%%%%%%%%%%%%%%%%%%%%%

        %CALCULATE MC
        [fMc] = Catalog.bvalue_lib.calc_Mc(mag, mcType, fBinning, fMccorr);
        l = mag >= fMc-(fBinning/2);
        if length(mag(l)) >= Nmin
            [fMeanMag, fBValue, fStd_B, fAValue] =  Catalog.bvalue_lib.calc_bmemag(mag(l), fBinning);
        else
            [fMc, fBValue, fStd_B, fAValue] = deal(NaN);
        end

        %STANDARD DEV OF a-value SET TO NAN;
        [fStd_A, fStd_Mc] = deal(NaN);

    else
        [fMc, fStd_Mc, fBValue, fStd_B, fAValue, fStd_A, ...
            fStdDevB, fStdDevMc] = deal(NaN);
    end

    magco = fMc;
    index_low=find(xt3 < magco+.05 & xt3 > magco-.05);
try
    mag_hi = xt3(1);
    index_hi = 1;
    mz = xt3 <= mag_hi & xt3 >= magco-.0001;
    mag_zone=xt3(mz);
    y = backg_ab(mz);

    %PLOT MC IN FIGURE
    Mc = semilogy(xt3(index_low),bvalsum3(index_low)*1.5,'vk');
    set(Mc,'LineWidth',[1.0],'MarkerSize',7)
    Mc = text(xt3(index_low)+0.2,bvalsum3(index_low)*1.5,'Mc');
    set(Mc,'FontWeight','normal','FontSize',12,'Color','k')

    %CREATE AND PLOT FIT LINE
    sol_type = 'Maximum Likelihood Solution';
    bw=fBValue;
    aw=fAValue;
    ew=fStd_B;
    p = [ -1*bw aw];
    f = polyval(p,mag_zone);
    f = 10.^f;
    hold on
    ttm= semilogy(mag_zone,f,'k');
    set(ttm,'LineWidth',[2.0])
    std_backg = ew;

    %ERROR CALCULATIONS
    %b = mag;
    bv = [];
    si = [];

    set(gca,'XLim',[min(mag)-0.5  max(mag+0.5)])
    %set(gca,'YLim',[0.9 length(mag+30)*2.5]);

    p=-p(1,1);
    p=fix(100*p)/100;
    tt1=num2str(bw,3);
    tt2=num2str(std_backg,1);
    tt4=num2str(bv,3);
    tt5=num2str(si,2);
    tmc=num2str(magco,2);
    rect=[0 0 1 1];
    h2=axes('position',rect);
    set(h2,'visible','off');
    t=catalogObject.gettimerange();
    a0 = aw-log10((t(2)-t(1))/365);

    text(.53,.88, ['b-value = ',tt1,' +/- ',tt2,',  a value = ',num2str(aw,3)],'FontSize',12);
    text(.53,.85,sol_type,'FontSize',12 );
    text(.53,.82,['Magnitude of Completeness = ',tmc],'FontSize',12);

    %% Added by Glenn 2018-05-01 to return a structure
    gr.bvalue = str2num(tt1);
    gr.bvalue_error = str2num(tt2);
    gr.avalue = aw;
    gr.Mc = str2num(tmc);

    %% Manually fit a line (added by Glenn 2018-05-01)
    if manual_on
        [xmag, yN] = ginput(2);
        slope = (log10(yN(1)) - log10(yN(2) )) / (xmag(2) - xmag(1) )
        plot(xmag, yN, 'g');
        gr.Mc_manual = xmag(1);
        gr.bvalue_manual = slope;
        text(xmag(1) + (xmag(2)-xmag(1))*0.5, yN(1) + (yN(2)-yN(1))*0.5, sprintf('manual b=%.2f',slope),'Color','g');
    end
catch
    gr.bvalue = NaN;
    gr.Mc = NaN;
    gr.avalue = NaN;
    gr.bvalue_error = NaN;
end

end


function [f, grad] = DL1c_regularization(Knots, kspc, D, csqrt)
    gvol = prod(kspc);
    k = 1;
    ksz = size(Knots(:,:,:, 1));
    Nd = size(Knots, 4);
    f = 0;
    grad = zeros(size(Knots));
    p = 1;
%     p = 0.85;

    for nn = 1 : size(Knots, 5)
        for i = 1 : Nd
            tmp = D * fl(Knots(:,:,:, i, nn));

            t2 = sqrt(tmp(:).^2 + csqrt);
            f = f + sum(t2.^p);

%             grad = D' * ((abs(tmp)+deps).^(p-1) .* sign(tmp)) * p;

%             gr = D' * fl(tmp ./ t2);
            gr = D' * (tmp .* (t2.^(p-2)) * p);

            grad(:,:,:, i, nn) = grad(:,:,:, i, nn) + reshape(gr, ksz);
        end
    end
    f = f * gvol;
    grad = grad * gvol;
end


%RANDOMFORESTC Breiman's random forest
%
%   W = RANDOMFORESTC(A,L,N)
%   W = A*RANDOMFORESTC([],L,N)
%
% INPUT
%   A       Dateset used for training
%   L       Number of decision trees to be generated (default 50)
%   N       Size of feature subsets to be used (default 1)
%
% OUTPUT
%   W       Resulting, trained feature space classifier
%
% DESCRIPTION
% Train a decision forest on A, using L decision trees, each trained on
% a bootstrapped version of dataset A. Each decison tree is using random
% feature subsets of size N in each node.  When N=0, no feature subsets
% are used.
%
% REFERENCES
% [1] L. Breiman, Random Forests, Machine learning, vol. 45 (1), 5-32, 2001
%
% SEE ALSO (PRTools Guide)
% DATASETS, MAPPINGS, DTC

% Copyright: D.M.J. Tax, D.M.J.Tax@37steps.com
% Faculty EWI, Delft University of Technology
% P.O. Box 5031, 2600 GA Delft, The Netherlands

function out = randomforestc(varargin)

argin = setdefaults(varargin,[],50,1);
if mapping_task(argin,'definition')

  out = define_mapping(argin,'untrained',['RandForest' int2str(argin{2})]);

elseif mapping_task(argin,'training')

  [a,L,featsubset] = deal(argin{:});
	isvaldfile(a,2,2); % at least 2 obj/class, 2 classes
	opt = [];
	[n,dim,opt.K] = getsize(a);
	opt.featsubset = featsubset;
	v = cell(L,1);
	for i=1:L
		[x,z] = gendat(a);
    if exist('decisiontree','file')==3
      v{i} = decisiontree(+x,getnlab(x),opt.K,opt.featsubset);
    else
		 prwarning(2,'No compiled decisiontree found, using the slower Matlab implementation.');
    	v{i} = tree_train(+x,getnlab(x),opt);
    end
  end
  out = trained_classifier(a,v);

elseif mapping_task(argin,'execution')

  [a,w] = deal(argin{1:2});
	v = getdata(w);
	n = size(a,1);  % nr objects
	K = size(w,2);  % nr of classes
	nrv = length(v); % nr of trees
    out = zeros(n,K);
    if exist('decisiontree')==3
      for j=1:nrv
        I = decisiontree(v{j},+a);
        out = out + accumarray([(1:n)' I],ones(n,1),[n K]);
      end
    else
      % the old fashioned slow Matlab code
      for i=1:n
        x = +a(i,:);
        for j=1:nrv
          I = tree_eval(v{j},x);
          out(i,I) = out(i,I)+1;
        end
      end
      out = out./repmat(sum(out,2),1,K);
    end
    out = setdat(a,out,w);

else
  error('Illegal call')
end

return

%    out = tree_eval(w,x)
%
function out = tree_eval(w,x)

n = size(x,1);
out = zeros(n,1);

for i=1:n

	v=w;
	% if the first split is already solving everything (1 obj. per class)
	if isa(v,'double')
		out(i,1) = v;
	end
	while (out(i,1)==0)
		if (x(i,v.bestf)<v.bestt)
			v = v.l;
		else
			v = v.r;
		end
		if isa(v,'double')
			out(i,1) = v;
		end
	end
end

%
%    w = tree_train(x,y,opt)
%
function w = tree_train(x,y,opt)

% how good are we in this node?
err = tree_gini(y,opt.K);
if (err==0)

	w = y(1); % just predict this label

else
	% we split further
	n = size(x,1);

	% optionally, choose only from a subset
	if (opt.featsubset>0)
		fss = randperm(size(x,2));
		fss = fss(1:opt.featsubset);
	else
		fss = 1:size(x,2);
	end

	% check each feature separately:
	besterr = inf; bestf = []; bestt = []; bestj = []; bestI = [];
	for i=fss
		% sort the data along feature i:
		[xi,I] = sort(x(:,i)); yi = y(I);
		% run over all possible splits:
		for j=1:n-1
			% compute the gini
			err = j*tree_gini(yi(1:j),opt.K) + (n-j)*tree_gini(yi(j+1:n),opt.K);
			% and see if it is better than before.
			if (err<besterr)
				besterr = err;
				bestf = i;
				bestj = j;
				bestt = mean(xi(j:j+1));
				bestI = I;
			end
		end
	end

	% store
	w.bestf = bestf;
	w.bestt = bestt;
	%  now find the children:
	w.l = tree_train(x(bestI(1:bestj),:),y(bestI(1:bestj)),opt);
	w.r = tree_train(x(bestI(bestj+1:end),:),y(bestI(bestj+1:end)),opt);
end

function g = tree_gini(y,K)

out = zeros(1,K);
for k=1:K
	out(k) = mean(y==k);
end

g = out*(1-out)';


function [meshStruct]=hexMeshCylinder(varargin)

% function [meshStruct]=hexMeshCylinder(cylRadius,cylLength,pointSpacing)
% ------------------------------------------------------------------------
%
%
% Kevin Mattheus Moerman
% gibbon.toolbox@gmail.com
%
% 2021/02/26 Created
% 2021/05/08 @Fireedman (Luis Antonio Aguilar) added "end" to function
%------------------------------------------------------------------------

%% Parse input

switch nargin
    case 0
        cylRadius=[];
        cylLength=[];
        pointSpacing=[];
    case 1
        cylRadius=varargin{1};
        cylLength=[];
        pointSpacing=[];
    case 2
        cylRadius=varargin{1};
        cylLength=varargin{2};
        pointSpacing=[];
    case 3
        cylRadius=varargin{1};
        cylLength=varargin{2};
        pointSpacing=varargin{3};
end

%Check for empty variables
if isempty(cylRadius)
    cylRadius=1; %Unit radius
end

if isempty(cylLength)
    cylLength=cylRadius; %Height the same as radius
end

if isempty(pointSpacing)
    pointSpacing=(cylRadius*2*pi)/10; %One tenth of circumference
end

if numel(pointSpacing)==1
    pointSpacing=pointSpacing.*ones(1,2);
end

%%
%Set number of elements for core
numElementsCore=ceil(((cylRadius*2*pi)./pointSpacing(1))/4);

if numElementsCore<1
    numElementsCore=1;
end

%Set number of nodes allong circumference
numElementsHeight=ceil(cylLength./pointSpacing(2));
if numElementsHeight<1
    numElementsHeight=1;
end

%% Create quad mesh for disc

%Raw quad mesh
[Fs,Vs]=discQuadMesh(numElementsCore,cylRadius,0.6);

%Smoothen
Eb=patchBoundary(Fs);
controlParSmooth.n=25;
controlParSmooth.Method='LAP';
controlParSmooth.RigidConstraints=unique(Eb(:));
[Vs]=patchSmooth(Fs,Vs,[],controlParSmooth);

%% Thicken to elements

%Thicken
[E,V,Fp1,Fp2]=patchThick(Fs,Vs,1,cylLength,numElementsHeight);
V(:,3)=V(:,3)-cylLength/2;

%Get element faces
[F,~]=element2patch(E,[],'hex8');

%Find boundary faces
[indFree]=freeBoundaryPatch(F);
Fb=F(indFree,:);

%Assign boundary labels (or colors)
faceBoundaryMarker=zeros(size(Fb,1),1); %Side of cylinder
faceBoundaryMarker(all(ismember(Fb,Fp1),2))=1; %Original (e.g. top)
faceBoundaryMarker(all(ismember(Fb,Fp2),2))=2; %Thickened (e.g. bottom)

%% Collect output

meshStruct.nodes=V;
meshStruct.facesBoundary=Fb;
meshStruct.boundaryMarker=faceBoundaryMarker;
meshStruct.faces=F;
meshStruct.elements=E;
meshStruct.elementMaterialID=ones(size(E,1),1);
meshStruct.faceMaterialID=ones(size(F,1),1);

end

%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2021 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.
%%
% _*GIBBON footer text*_
%
% License: <https://github.com/gibbonCode/GIBBON/blob/master/LICENSE>
%
% GIBBON: The Geometry and Image-based Bioengineering add-On. A toolbox for
% image segmentation, image-based modeling, meshing, and finite element
% analysis.
%
% Copyright (C) 2006-2022 Kevin Mattheus Moerman and the GIBBON contributors
%
% This program is free software: you can redistribute it and/or modify
% it under the terms of the GNU General Public License as published by
% the Free Software Foundation, either version 3 of the License, or
% (at your option) any later version.
%
% This program is distributed in the hope that it will be useful,
% but WITHOUT ANY WARRANTY; without even the implied warranty of
% MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
% GNU General Public License for more details.
%
% You should have received a copy of the GNU General Public License
% along with this program.  If not, see <http://www.gnu.org/licenses/>.


clc;
clear;
close all;
warning off;
addpath(genpath(cd));

I=double(imread('E:\lichang\1.Image fusion total variation\img\tank\tank_IR.png'))/255;
%V=double(imread('E:\lichang\1.Image fusion total variation\img\tank\tank_VIS.png'))/255;
% I=histeq(I);
% V=histeq(V);
% figure; imshow(I);
% figure; imshow(V);
% imwrite(I,'new_4917_IR.png','png');
% imwrite(V,'new_4917_VIS.png','png');
% I=rgb2gray(I);
% V=rgb2gray(V);
%proposed
nmpdef;
pars_irn = irntvInputPars('l2tv');

pars_irn.adapt_epsR   = 1;
pars_irn.epsR_cutoff  = 0.01;   % This is the percentage cutoff
pars_irn.adapt_epsF   = 1;
pars_irn.epsF_cutoff  = 0.05;   % This is the percentage cutoff

pars_irn.pcgtol_ini = 1e-4;

pars_irn.loops      = 5;
pars_irn.U0         = I;

pars_irn.variant       = NMP_TV_SUBSTITUTION;
pars_irn.weight_scheme = NMP_WEIGHTS_THRESHOLD;
pars_irn.pcgtol_ini    = 1e-2;
pars_irn.adaptPCGtol   = 1;
Final_Metric=zeros(6,1);
tic;
for i=[0.1:0.1:0.9]%[0.01:0.01:0.09 0.1:0.1:0.9 1:10 20:10:100]

    X = irntv(I, {}, i, pars_irn);
    X=im2gray(X);
    imwrite(X,strcat('Proposed_tank_',strcat(num2str(i),'.png')),'png');
    %figure;
    %imshow(X);
%     Result = Metric(uint8(abs(I)*255),uint8(abs(V)*255),uint8(abs(X*255)));
%     temp=Result.Total;
%     Final_Metric=max(Final_Metric,temp);
end


  function atten = xray_filters(mtype, thickness, energy, varargin)
%|function atten = xray_filters(mtype, thickness, energy, [options])
%|
%| Compute X-ray photon survival probability as a function of energy
%| for various materials.
%| in
%|	mtype			'aluminum', 'copper', ...
%|				can be a cell array {L} for multiple filters
%|	thickness		in cm (can be an array [L] if mtype is cell)
%|	energy	[N,1]		in keV (vector)
%| option
%|	'units'	cm | mm		default: cm
%| out
%|	atten	[N,L]		unitless survival probabilities
%|
%| Copyright 2001-04-27, Jeff Fessler, University of Michigan

if nargin == 1 && streq(mtype, 'test'), xray_filters_test, return, end
if nargin < 3, ir_usage, end

arg.units = 'cm';
arg = vararg_pair(arg, varargin);

if iscell(mtype)
	LL = length(mtype);
	if length(thickness) ~= LL, error 'thickness / material mismatch', end
	atten = zeros(length(energy), LL);
	for ll=1:LL
		atten(:,ll) = xray_filters(mtype{ll}, thickness(ll), ...
			energy(:), 'units', arg.units);
	end
return
end

mass_atten = xray_read_atten(mtype, energy, 'units', arg.units); % [N,L]
density = xray_read_dens(mtype, 'units', arg.units); % [L,1]
atten = exp(-mass_atten .* thickness .* density);

function xray_filters_test
kev = [20:200]';
mtype = {'lead', 'copper', 'aluminum'};
t = xray_filters(mtype, [0.01 0.2 0.1], kev);
if im
	clf, semilogy(kev, t, '-o'), axis([20 200 10^-2 1]),
	ir_legend(mtype)
end


% VOCLABELCOLORMAP Creates a label color map such that adjacent indices have different
% colors.  Useful for reading and writing index images which contain large indices,
% by encoding them as RGB images.
%
% CMAP = VOCLABELCOLORMAP(N) creates a label color map with N entries.
function cmap = VOClabelcolormap(N)

if nargin==0
    N=256;
end
cmap = zeros(N,3);
for i=1:N
    id = i-1; r=0;g=0;b=0;
    for j=0:7
        r = bitor(r, bitshift(bitget(id,1),7 - j));
        g = bitor(g, bitshift(bitget(id,2),7 - j));
        b = bitor(b, bitshift(bitget(id,3),7 - j));
        id = bitshift(id,-3);
    end
    cmap(i,1)=r; cmap(i,2)=g; cmap(i,3)=b;
end
cmap = cmap / 255;


function [ lo, hi ] = p06_box ( m )

%*****************************************************************************80
%
%% P06_BOX returns a bounding box for problem 06.
%
%  Licensing:
%
%    This code is distributed under the GNU LGPL license.
%
%  Modified:
%
%    12 April 2009
%
%  Author:
%
%    John Burkardt
%
%  Reference:
%
%    Per-Olof Persson and Gilbert Strang,
%    A Simple Mesh Generator in MATLAB,
%    SIAM Review,
%    Volume 46, Number 2, June 2004, pages 329-345.
%
%  Parameters:
%
%    Input, integer M, the spatial dimension.
%
%    Output, real LO(M), HI(M), the low and high corners of the box.
%
  r1 = 1.0;
  r2 = 0.5;

  lo(1:m) = [ -r1, -r1 ];
  hi(1:m) = [ +r1, +r1 ];

  return
end


% This function recursively cuts a sentence into shorter segments no longer
% than a predefined maximum length, based purely on the information about
% short pause durations and locations.
% Inputs:
%   sent_len: length of the sentence in terms of frames
%   sp_len: length of the short pauses in the sentence
%   middle_frame: middle of the short pauses
%   max_seg_len: maximum length of every resulting segments.
%   weight_location: the weight of short pause location. This is relative to the
%       short pause duration
% Outputs:
%   cutting_point: an array of suggested cutting points
%
% Authors: Xiong Xiao
% Date Created: 2009
% Last Modified: 16 April 2014
%
function cutting_point = choose_cutting_points_by_sp(sent_len, sp_len, middle_frame, max_seg_len, loc_weight)
if nargin<5
    loc_weight = 1;
end
if sent_len < max_seg_len
    cutting_point = [];
elseif length(sp_len)<2
    cutting_point = [];
else
    % Choose the sp for splitting
    % Two rules to select a sp: 1) longer sp segments should be
    % given higher priority; 2) sp near to center of the sentence
    % should be given higher priority. The weight of these two
    % criteria will be adjsuted by a weighting loc_weight
    sent_center = round(sent_len/2);
    score = [];
    for k = 1:length(sp_len)
        if middle_frame(k) < max_seg_len/5 || sent_len-middle_frame(k)<max_seg_len/5    % we don't cut by short pause that is too close to the both ends
            score(k) = 0;
        else
            dist_to_center = abs(middle_frame(k)-sent_center)/sent_center;      % how far is current short pause to the sentence center relatively, which is in [0 0.5] interval.
            % we change the distance to log scale, multiple it by -3 to convert it to positive number. As log(0) is infinity, we need to set a upper limit to the log distance.
            location_score = min(20, -3*log(dist_to_center) );
            score(k) = sp_len(k) + loc_weight * location_score;     % we still have loc_weight to tune the relative weight of the two factors
        end
    end
    [best_sp, idx] = max(score);    % everytime we only cut the current sentence once.
    cutting_point = middle_frame(idx);

    sub_points = choose_cutting_points_by_sp(cutting_point, sp_len(1:idx-1), middle_frame(1:idx-1), max_seg_len, loc_weight);     % See whether left segment needs to be cut further
    cutting_point = ([sub_points cutting_point]);
    sub_points = choose_cutting_points_by_sp(sent_len - cutting_point(end), sp_len(idx+1:end), middle_frame(idx+1:end)-cutting_point(end), max_seg_len, loc_weight);     % See whether left segment needs to be cut further
    cutting_point = ([cutting_point sub_points+cutting_point(end)]);
end


%function f = s6990029.m
%This function was completed on Tuesday, 16 November 2002
%as a part of a course, in order to form a good-interfaced program
%for producing random variables from the negative binomial distribution.
%
%Made by P.B.(6990029)
function s6990029

fprintf('In a few seconds a pop-up screen will prompt you to choose from one\nof 4 methods, in order to generate random variables from the Negative Binomial Distribution.');
fprintf('\n\nLOADING('),
for j=1:30
fprintf('---')
pause(0.06990029)
end
fprintf(')')
fprintf('\n')

K=menu('Choose a method for generating n random variables from the Neg.Binomial :','1) Inverse transform Method','2) Convolution Method (using Bernoulli D.)','3) Convolution Method (using Geometrical D.)','4) Acceptance Rejection Method','**************************Which is faster=better***********************','Exit');

%Method 1

if (K==1)

disp('You have selected the Inverse Transform method. Please wait...');
pause(2);
clc;clear;
N = input('Please give me the size of the sample : ');
R = input('Type the value of the parameter of successes R : ');
P = input('Now give the probability of success P : ');
disp('Please standby...');

%set up the storage space and the clock
tic
X = zeros(1,N);
x =1:N;

for x =1:N
pr(x)  = NBINCDF(x,R,P);
end

pr(N)=1;    %epeidh en vgainei panta 1 to teleutaio stoixeio tou pinaka ths a8roistikhs ...kammia fora... dhmiourgei provlhmata!!!

for i=1:N
 s=1;
u= rand;
while u > pr(s)
    s=s+1;
end
X(i) = s;
end

%stop the clock
t=toc;
fp=fopen('c:\data1.txt','w');
fprintf(fp,' %3.0f \n',X);
fclose(fp);
disp('Your sample has been saved in data1.txt');
fprintf('The time needed, depending on your machine'' speed \n and the complexity of the algorithm, was: ');disp(t)
pause(2);

load handel;
sound(y,Fs);

%the empirical histogram

[n,h]= hist(X,10);
n=n/(h(2)-h(1))/N;
bar(h,n,1,'w')
hold on

%theoritical curve

for x =1:N
pr(x)  = NBINPDF(x,R,P);
end
x =1:N;
plot(x,pr,'k');
hold off
title('Empirical & Theoritical pdf of the Neg. Binomial Distribution');
xlabel('X');
ylabel('P(X)');

%Method 2

elseif (K==2)

fprintf('You have selected the Convolution method \n(using as a prime several Bernoulli variables). \n\nPlease wait...');
pause(4);
clc;clear;
N = input('Please give me the size of the sample : ');
R = input('Type the value of the parameter of successes R : ');
P = input('Now give the probability of the bernoulli trials P : ');
disp('Please standby...');

%set up the storage space and the clock
tic

X = zeros(1,N);
for j=1:N
h=0;
i=0;
while h < R
u=rand;
i=i+1;
if  u <= P
h = h+1;
end
end
X(j)=i-R;               % duskolo shmeio...orismos:...o arithmos twn dokimwn mexri R epituxies!
end

t=toc;
fp=fopen('c:\data2.txt','w');
fprintf(fp,' %3.0f \n',X);
fclose(fp);
disp('Your sample has been saved in data2.txt');
fprintf('The time needed, depending on your machine'' speed \n and the complexity of the algorithm, was: ');disp(t)
pause(2);

load handel;
sound(y,Fs);

%the empirical histogram

[n,h]= hist(X,10);
n=n/(h(2)-h(1))/N;
bar(h,n,1,'w')
hold on

%theoritical curve

for x =1:N
pr(x)  = NBINPDF(x,R,P);
end
x =1:N;
plot(x,pr,'k');
hold off
title('Empirical & Theoritical pdf of the Neg. Binomial Distribution');
xlabel('X');
ylabel('P(X)');

%METHOD 3

elseif (K==3)

fprintf('You have selected the Convolution method \n(using as a prime several Geometrical variables). \n\nPlease wait...');
pause(4);
clc;clear;
N = input('Please give me the size of the sample : ');
R = input('Type the value of the parameter of successes R : ');
P = input('Now give the probability of the bernoulli trials P : ');
disp('Please standby...');

%set up the storage space and the clock
tic

X = zeros(1,N);

G=geornd(P,N,R);

X=G*ones(R,1);

%stop the clock
t=toc;
fp=fopen('c:\data3.txt','w');
fprintf(fp,' %3.0f \n',X);
fclose(fp);
disp('Your sample has been saved in data3.txt');
fprintf('The time needed, depending on your machine'' speed \n and the complexity of the algorithm, was: ');disp(t)
pause(2);

load handel;
sound(y,Fs);

%the empirical histogram

[n,h]= hist(X,10);
n=n/(h(2)-h(1))/N;
bar(h,n,1,'w')
hold on

%theoritical curve

for x =1:N
pr(x)  = NBINPDF(x,R,P);
end
x =1:N;
plot(x,pr,'k');
hold off
title('Empirical & Theoritical pdf of the Neg. Binomial Distribution');
xlabel('X');
ylabel('P(X)');

%METHOD 4

elseif (K==4)

fprintf('You have selected the Acceptance-Rejection method). \n\nPlease wait...');
pause(4);
clc;clear;
N = input('Please give me the size of the sample : ');
R = input('Type the value of the parameter of successes R : ');
P = input('Now give the probability of the bernoulli trials P : ');
disp('Please standby...');

%set up the storage space and the clock
tic

for x =1:N
pr(x)  = NBINPDF(x,R,P);
end

c=max(pr)*N;

irv=1;
while irv<=N
    y = unidrnd(N);
    u = rand(1);
    if u <= (pr(y))/c ;
        X(irv) =  y;
        irv = irv +1;
    end
end

%stop the clock
t=toc;
%save to disk
fp=fopen('c:\data4.txt','w');
fprintf(fp,' %3.0f \n',X);
fclose(fp);
disp('Your sample has been saved in data4.txt');
fprintf('The time needed, depending on your machine'' speed \n and the complexity of the algorithm, was: ');disp(t)
pause(2);

load handel;
sound(y,Fs);

%the empirical histogram

[n,h]= hist(X,10);
n=n/(h(2)-h(1))/N;
bar(h,n,1,'w')
hold on

%theoritical curve

for x =1:N
pr(x)  = NBINPDF(x,R,P);
end
x =1:N;
plot(x,pr,'k');
hold off
title('Empirical & Theoritical pdf of the Neg. Binomial Distribution');
xlabel('X');
ylabel('P(X)');

%Test for overall performance within the range of the two parameters (R,P)

%#########################################################################################

elseif (K==5)

    clc;
    fprintf('You have selected to test between the three first  methods.\nFor the 4th one the envelope function selected was rather unsuitable since it was\nthe discrete uniform.\nWith an other function as an envelope it would be very hard to test\nthrough a wide range of (R,P)\nsince the Neg. Binomial''s shape would change.\n\nPlease wait. It will take some time ...\n');
pause(5);

clear;
N = input('Please give me the size of the sample. It would be most preferable to choose sample bigger than 10000! : ');

fprintf('Please go drink a coffee...\n')

    q=1;

    for R=10:N
    for P=0.3:0.2:0.7
        %1st
tic
X = zeros(1,N);
x =1:N;

for x =1:N
pr(x)  = NBINCDF(x,R,P);
end

pr(N)=1;    %epeidh en vgainei panta 1 to teleutaio stoixeio tou pinaka ths a8roistikhs ...kammia fora... dhmiourgei provlhmata!!!

for i=1:N
 s=1;
u= rand;
while u> pr(s)
    s=s+1;
end
    X(i) = s;
end
%stop the clock
t1=toc;

%2nd

tic

X = zeros(1,N);
for j=1:N
h=0;
i=0;
while h < R
u=rand;
i=i+1;
if  u <= P
h = h+1;
end
end
X(j)=i-R;               % duskolo shmeio...orismos:...o arithmos twn dokimwn mexri R epituxies!
end

t2=toc;

%3rd

tic

X = zeros(1,N);

G=geornd(P,N,R);

X=G*ones(R,1);

%stop the clock
t3=toc;

q=q+1;

T(q,:)=[t1 t2 t3];

end
end

boxplot(T);
anova1(T);

fprintf('\n\n\n\n\nOne would choose the method which uses the sum of the geometrical variables\nsince the Anova table also recommends this method!\nHave a nice day.')

else
 disp('Have a nice Day!!!');

%break

end