function varargout = isreal(varargin)
%ISREAL   Real-valued SPHEREFUN test.
%   ISREAL(F) returns logical true if F does not have an imaginary part and
%   false otherwise.
%
%   ~ISREAL(F) detects SPHEREFUN object that have an imaginary part even if it i
%   all zero.
%
%   Since only real-valued SPHEREFUNS are presently supported, this
%   function always returns a logical true.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

[varargout{1:nargout}] = isreal@separableApprox(varargin{:});

end


function symb_pvec = sdpvar2str(pvec)
%SDPVAR2STR Converts an SDPVAR object to MATLAB string representation
%
% S = SDPVAR2STR(P)
%
% S : String
% P : SDPVAR object

for pi = 1:size(pvec,1)
    for pj = 1:size(pvec,2)
        p = pvec(pi,pj);

        if isa(p,'double')
            symb_p = num2str(p);
        else
            LinearVariables = depends(p);
            x = recover(LinearVariables);
            exponent_p = full(exponents(p,x));
            names = cell(length(LinearVariables),1);
            for i = 1:length(LinearVariables)
                names{i}=['x(' num2str(LinearVariables(i)) ')'];
            end

            symb_p = '';
            if all(exponent_p(1,:)==0)
                symb_p = num2str(getbasematrix(p,0));
                exponent_p = exponent_p(2:end,:);
            end

            for i = 1:size(exponent_p,1)
                coeff = getbasematrixwithoutcheck(p,i);
                switch full(coeff)
                    case 1
                        coeff='+';
                    case -1
                        coeff = '-';
                    otherwise
                        if coeff >0
                            coeff = ['+' num2str2(coeff)];
                        else
                            coeff=[num2str2(coeff)];
                        end
                end
                if strcmp(symb_p,'') & (strcmp(coeff,'+') | strcmp(coeff,'-'))
                        symb_p = [symb_p coeff symbmonom(names,exponent_p(i,:))];
                    else
                symb_p = [symb_p coeff '*' symbmonom(names,exponent_p(i,:))];
            end
            end
            if symb_p(1)=='+'
                symb_p = symb_p(2:end);
            end
        end

        symb_p = strrep(symb_p,'*^0','');
        symb_p = strrep(symb_p,'^0','');
        symb_p = strrep(symb_p,'+*','+');
        symb_p = strrep(symb_p,'-*','-');
        symb_pvec{pi,pj} = symb_p;
    end
end

function s = symbmonom(names,monom)
s = '';
for j = 1:length(monom)
    if monom(j)~=0
        if strcmp(s,'')
            s = [s names{j}];
        else
            s = [s '*' names{j}];
        end
    end
    if monom(j)~=1
        s = [s '^' num2str(monom(j))];
    end
%      if monom(j)>1
%        s = [s '^' num2str(monom(j))];
%    end

end

function s = num2str2(x)
        s = num2str(x);
        if isequal(s,'1')
            s = '';
        end
        if isequal(s,'-1')
            s = '-';
        end


function[varargout]=gulf4plot(varargin)
%GULF4PLOT  A four-panel circulation plot for the Gulf of Mexico.
%
%   GULF4PLOT(LAT,LON,CV) makes a four-panel quiver plot in the Gulf of
%   Mexico with color shading being the speed of the mean flow.  CV is the
%   complex-valued velocity U+iV of size LENGTH(LAT) x LENGTH(LON) x 4.
%
%   The plot has 2 rows and 2 columns, with a single colorbar centered
%   beneath the four plots.
%
%   GULF4PLOT(LAT,LON,CV,X) instead uses X, of the same size as CV, for the
%   color shading.
%
%   GULF4PLOT(...,CAX) uses CAX, a length 2 array, for the color axis.
%
%   GULF4PLOT(...,CAX,CLABEL,LABELS), where LABELS is a cell array of four
%   strings, prints LABELS{i} after the letter label of the ith subplot.
%
%   LAT, LON, CV, and X can also be cell arrays of four elements.  This is
%   useful if the grid size is not the same in all four plots.
%
%   Usage: h=gulf4plot(lat,lon,cv);
%   __________________________________________________________________
%   This is part of JLAB --- type 'help jlab' for more information
%   (C) 2020 J.M. Lilly --- type 'help jlab_license' for details

% if strcmp(varargin{1}, '--t')
%     gulf4plot_test,return
% end

tweakmap_thin=['plot([-84.5+1i*21.5 -84.5+1i*22],''k--'',''linewidth'',0.5);hold on;'...
    'plot([-86.9+1i*21.5 -84.5+1i*21.5],''k--'',''linewidth'',0.5);' setstr(10) ...
    'jfig axis|[-98.35 -81.5 18 30.75] latratio|25 topoplot|gray '...
    'eval|topoplot([],[],-5:1:-1,''0.5E'') eval|topoplot([],[],-1/2,''0.5k'') eval|topoplot([],[],-0.005,''0.5E'') ' ...
    'ticksout portrait fontsize|[11 10 10 10] '];

cax=[];
clabel=[];
labels={'','','',''};
alpha=1/80;

if length(varargin{1})==1
    alpha=varargin{1};
    varargin=varargin(2:end);
end

lat=varargin{1};
lon=varargin{2};
cv=varargin{3};
x=varargin{4};
if length(varargin)>4
    cax=varargin{5};
end
if length(varargin)>5
    clabel=varargin{6};
end
if length(varargin)>6
    labels=varargin{7};
end

if isempty(x)
    if ~iscell(cv)
        x=abs(cv);
    else
        for i=1:length(cv)
            x{i}=abs(cv{i});
        end
    end
end

if ~iscell(x)
    xcell{1}=x(:,:,1);
    xcell{2}=x(:,:,2);
    xcell{3}=x(:,:,3);
    xcell{4}=x(:,:,4);
else
    xcell=x;
end

if ~iscell(cv)&&~isempty(cv)
    cvcell{1}=cv(:,:,1);
    cvcell{2}=cv(:,:,2);
    cvcell{3}=cv(:,:,3);
    cvcell{4}=cv(:,:,4);
else
    cvcell=cv;
end

if ~iscell(lat)
    latcell{1}=lat;
    latcell{2}=lat;
    latcell{3}=lat;
    latcell{4}=lat;
else
    latcell=lat;
end

if ~iscell(lon)
    loncell{1}=lon;
    loncell{2}=lon;
    loncell{3}=lon;
    loncell{4}=lon;
else
    loncell=lon;
end

figure
subplot(3,2,1)
jpcolor(loncell{1},latcell{1},xcell{1}),
hold on,eval(tweakmap_thin),
ar=get(gca,'dataaspectratio');
[long,latg]=meshgrid(loncell{1},latcell{1});
if ~isempty(cvcell)
    quiver([long(:);-90.2],[latg(:);20.5],alpha*[vcolon(real(cvcell{1}));30]*ar(1),alpha*[vcolon(imag(cvcell{1}));0],0,'k');hold on
end
text(-98,30.155,['(a) ' labels{1}])
text(-90.2,19.95,'30 cm/s')
%--------------------------------------------------------------------------
for i=2:4
    subplot(3,2,i)
    jpcolor(loncell{i},latcell{i},xcell{i}),
    hold on,eval(tweakmap_thin),
    ar=get(gca,'dataaspectratio');
    [long,latg]=meshgrid(loncell{i},latcell{i});
    if ~isempty(cvcell)
        h=quiver(long,latg,alpha*real(cvcell{i})*ar(1),alpha*imag(cvcell{i}),0,'k');hold on
    end
    text(-98,30.155,['(' setstr(97+i-1) ') ' labels{i}])
end
%--------------------------------------------------------------------------
if ~isempty(cax)
    for i=1:4,subplot(3,2,i),caxis(cax),end
end
h1=packfig(3,2,'both');
delete(h1(5:6))
orient tall
fontsize 8 8 8 8
set(gcf,'paperposition',[0.25 0.25 8 9.5])
axes(h1(3)),set(gca,'xticklabelmode','auto')
axes(h1(4)),set(gca,'xticklabelmode','auto')

axes(h1(3))
hc=colorbar('South');
if ~isempty(clabel)
    hc.Label.String=clabel;
end
pos=hc.Position;
hc.Position=[0.32 0.34 0.4 pos(4)/2];
set(hc,'AxisLocation','out')

varargout{1}=h1;

function[]=gulf4plot_test

%reporttest('GULF4PLOT',aresame())


function [ZI,f] = spm_eeg_plotScalpData(Z,pos,ChanLabel,in)
% Display M/EEG interpolated sensor data on a scalp image
% FORMAT [ZI,f] = spm_eeg_plotScalpData(Z,pos,ChanLabel,in)
%
% INPUT:
%   Z          - the data matrix at the sensors
%   pos        - the positions of the sensors
%   ChanLabel  - the names of the sensors
%   in         - a structure containing some informations related to the
%                main PRESELECTDATA window. This entry is not necessary
% OUTPUT:
%   ZI         - an image of interpolated data onto the scalp
%   f          - the handle of the figure which displays the interpolated
%                data
%__________________________________________________________________________
%
% This function creates a figure whose purpose is to display an
% interpolation of the sensor data on the scalp (as an image).
%__________________________________________________________________________
% Copyright (C) 2008-2014 Wellcome Trust Centre for Neuroimaging

% Jean Daunizeau
% $Id: spm_eeg_plotScalpData.m 7221 2017-11-16 14:25:37Z vladimir $

ChanLabel  = char(ChanLabel);
ParentAxes = [];
f          = [];
clim       = [min(Z(:))-( max(Z(:))-min(Z(:)) )/63 , max(Z(:))];
figName    = 'Image Scalp data';
noButtons  = 0;
if nargin < 4 || isempty(in)
    in     = [];
else
    if isfield(in,'min') && ...
            isfield(in,'max') && ...
            isfield(in,'type')
        clim    = [in.min, in.max];
        dc      = abs(diff(clim))./63;
        clim(1) = clim(1) - dc;
        figName = ['Image Scalp data: ',in.type,' sensors'];
        if isfield(in,'trN')
            figName = [figName ', trial #',num2str(in.trN),'.'];
        end
    end
    if isfield(in,'f')
        f = in.f;
    else
        f = figure;
    end
    if isfield(in,'ParentAxes')
        ParentAxes = in.ParentAxes;
    else
        ParentAxes = axes('parent',f);
    end
    if isfield(in,'noButtons')
        noButtons = ~~in.noButtons;
    end
end

if ~isfield(in,'cbar')
    in.cbar = 1;
end

if ~isfield(in,'plotpos')
    in.plotpos = 1;
end

if size(pos,2) ~= size(ChanLabel, 1)
    pos = pos';
end

nD = size(pos,1);
if nD ~= 2
    % get 2D positions from 3D positions
   xyz   = pos;
   [pos] = get2Dfrom3D(xyz);
   pos   = pos';
end

% exclude channels ?
goodChannels = find(~isnan(pos(1,:)));
pos          = pos(:,goodChannels);
Z            = Z(goodChannels,:);
ChanLabel    = ChanLabel(goodChannels, :);

if ~isempty(in) && isfield(in,'type') && strcmp(in.type, 'MEGPLANAR')
    [cZ, cpos, cChanLabel] = combineplanar(Z, pos, ChanLabel);
else
    cZ         = Z;
    cpos       = pos;
    cChanLabel = ChanLabel;
end

xmin    = min(cpos(1,:));
xmax    = max(cpos(1,:));
dx      = (xmax-xmin)./100;
ymin    = min(cpos(2,:));
ymax    = max(cpos(2,:));
dy      = (ymax-ymin)./100;
x       = xmin:dx:xmax;
y       = ymin:dy:ymax;
[XI,YI] = meshgrid(x,y);
ZI      = griddata(cpos(1,:)',cpos(2,:)',full(double(cZ')),XI,YI);

try
    figure(f)
catch
    f   = figure(...
        'name',      figName,...
        'color',     [1 1 1],...
        'deleteFcn', @dFcn);
    ParentAxes = axes('parent',f);
end

COLOR = get(f,'color');
d.hi = image(flipud(ZI),...
    'CDataMapping','scaled',...
    'Parent',ParentAxes);
set(ParentAxes,'nextPlot','add',...
    'tag','spm_eeg_plotScalpData')
try
    if length(unique(ZI)) ~= 1
        [C,d.hc] = contour(ParentAxes,flipud(ZI),...
            'linecolor',0.5.*ones(3,1));
    end
end
caxis(ParentAxes,clim);
col = jet;
col(1,:) = COLOR;
colormap(ParentAxes,col)

if in.cbar
    d.cbar = colorbar('peer',ParentAxes);
end

axis(ParentAxes,'off')
axis(ParentAxes,'equal')
axis(ParentAxes,'tight')

fpos = cpos;
fpos(1,:) = fpos(1,:) - xmin;
fpos(2,:) = fpos(2,:) - ymin;
fpos(1,:) = fpos(1,:)./(dx);
fpos(2,:) = fpos(2,:)./(dy);
fpos(2,:) = 100-fpos(2,:);  % for display purposes (flipud imagesc)

figure(f);
if in.plotpos
    d.hp = plot(ParentAxes,...
        fpos(1,:),fpos(2,:),...
        'ko');
end

d.ht = text(fpos(1,:),fpos(2,:),cChanLabel,...
    'Parent',ParentAxes,...
    'visible','off');
axis(ParentAxes,'image')

d.interp.XI = XI;
d.interp.YI = YI;
d.interp.pos = cpos;
d.f = f;
d.pos = fpos;
d.goodChannels = goodChannels;
d.ChanLabel = cChanLabel;
d.origChanLabel = ChanLabel;
d.origpos = pos;
d.ParentAxes = ParentAxes;
d.in = in;

if ~noButtons
    d.hsp = uicontrol(f,...
        'style','pushbutton',...
        'callback',{@dosp},...
        'BusyAction','cancel',...
        'Interruptible','off',...
        'position',[10    50    80    20],...
        'string','channel pos');
    d.hsn = uicontrol(f,...
        'style','pushbutton',...
        'callback',{@dosn},...
        'BusyAction','cancel',...
        'Interruptible','off',...
        'position',[10    80    80    20],...
        'string','channel names');
end
if ~isempty(in) && isfield(in,'handles')
    nT = length(in.gridTime);
    d.hti = uicontrol(f,...
        'style','text',...
        'BackgroundColor',COLOR,...
        'string',[num2str(in.gridTime(in.x)),' (',in.unit,')'],...
        'position',[10    10    120    20]);
    d.hts = uicontrol(f,...
        'style','slider',...
        'Position',[130 10 250 20],...
        'min',1,'max',nT,...
        'value',in.x,'sliderstep',[1./(nT-1) 1./(nT-1)],...
        'callback',{@doChangeTime},...
        'BusyAction','cancel',...
        'Interruptible','off');
    set(d.hti,'userdata',d);
    set(d.hts,'userdata',d);
end
if ~noButtons
    set(d.hsp,'userdata',d);
    set(d.hsn,'userdata',d);
end
set(d.ParentAxes,'userdata',d);

%==========================================================================
% dFcn
%==========================================================================
function dFcn(btn,evd)
hf = findobj('tag','Graphics');
D = get(hf,'userdata');
try delete(D.PSD.handles.hli); end

%==========================================================================
% dosp
%==========================================================================
function dosp(btn,evd)
d = get(btn,'userdata');
switch get(d.hp,'visible');
    case 'on'
        set(d.hp,'visible','off');
    case 'off'
        set(d.hp,'visible','on');
end

%==========================================================================
% dosn
%==========================================================================
function dosn(btn,evd)
d = get(btn,'userdata');
switch get(d.ht(1),'visible')
    case 'on'
        set(d.ht,'visible','off');
    case 'off'
        set(d.ht,'visible','on');
end

%==========================================================================
% doChangeTime
%==========================================================================
function doChangeTime(btn,evd)
d = get(btn,'userdata');
v = get(btn,'value');
% get data
if ishandle(d.in.handles.hfig)
    D = get(d.in.handles.hfig,'userdata');
    if ~isfield(d.in,'trN')
        trN = 1;
    else
        trN = d.in.trN;
    end
    try
        Z = D(d.in.ind,v,trN);
        Z = Z(d.goodChannels);

        if strcmp(d.in.type, 'MEGPLANAR')
            Z = combineplanar(Z, d.origpos, d.origChanLabel);
        end

        clear ud;
        % interpolate data
        ZI = griddata(d.interp.pos(1,:),d.interp.pos(2,:),full(double(Z)),d.interp.XI,d.interp.YI);
        % update data display
        set(d.hi,'Cdata',flipud(ZI));
        % update time index display
        v = round(v);
        set(d.hti,'string',[num2str(d.in.gridTime(v)), ' (', d.in.unit, ')']);
        % update display marker position
        try;set(d.in.hl,'xdata',[v;v]);end
        set(d.ParentAxes,'nextPlot','add')
        try
            % delete current contour plot
            delete(findobj(d.ParentAxes,'type','hggroup'));
            delete(findobj(d.ParentAxes,'type','contour')); % R2014b
            % create new one
            [C,hc] = contour(d.ParentAxes,flipud(ZI),...
                'linecolor',[0.5.*ones(3,1)]);
        end
        axis(d.ParentAxes,'image')
        drawnow
    catch
%     else
        error('Did not find the data!')
    end
else
    error('SPM Graphics Figure has been deleted!')
end

%==========================================================================
% get2Dfrom3D
%==========================================================================
function [xy] = get2Dfrom3D(xyz)
% function [xy] = get2Dfrom3D(xyz)
% This function is used to flatten 3D sensor positions onto the 2D plane
% using a modified spherical projection operation.
% It is used to visualize channel data.
% IN:
%   - xyz: the cartesian sensor position in 3D space
% OUT:
%   - xy: the (x,y) cartesian coordinates of the sensors after projection
%   onto the best-fitting sphere

if size(xyz,2) ~= 3
    xyz = xyz';
end
% exclude channels ?
badChannels  = find(isnan(xyz(:,1)));
goodChannels = find(isnan(xyz(:,1))~=1);
xyz          = xyz(goodChannels,:);
% Fit sphere to 3d sensors and center frame
C            = fitSphere(xyz(:,1),xyz(:,2),xyz(:,3));
xyz          = xyz - repmat(C,size(xyz,1),1);
% apply transformation using spherical coordinates
[TH,PHI,RAD] = cart2sph(xyz(:,1),xyz(:,2),xyz(:,3));
TH           = TH - mean(TH);
[X,Y,Z]      = sph2cart(TH,zeros(size(TH)),RAD.*(cos(PHI+pi./2)+1));
xy           = [X(:),Y(:)];

%==========================================================================
% combineplanar
%==========================================================================
function [Z, pos, ChanLabel] = combineplanar(Z, pos, ChanLabel)

if ~iscell(ChanLabel)
    ChanLabel = cellstr(ChanLabel);
end

chanind = zeros(1, numel(ChanLabel));
for i = 1:numel(ChanLabel)
    chanind(i) = sscanf(ChanLabel{i}, 'MEG%d');
end

pairs = [];
unpaired = [];
paired = zeros(length(chanind));
for i = 1:length(chanind)
    if ~paired(i)

        cpair = find(abs(chanind - chanind(i))<2);

        if length(cpair) == 1
            unpaired = [unpaired cpair];
        else
            pairs = [pairs; cpair(:)'];
        end
        paired(cpair) = 1;
    end
end

if ~isempty(unpaired)
    warning(['Could not pair all channels. Ignoring ' num2str(length(unpaired)) ' unpaired channels.']);
end

Z = sqrt(Z(pairs(:, 1)).^2 + Z(pairs(:, 2)).^2);
pos = (pos(:, pairs(:, 1)) + pos(:, pairs(:, 2)))./2;
ChanLabel = {};
for i = 1:size(pairs,1)
    ChanLabel{i} = ['MEG' num2str(min(pairs(i,:))) '+' num2str(max(pairs(i,:)))];
end

%==========================================================================
% fitSphere
%==========================================================================
function [C,R,out] = fitSphere(x,y,z)
% fitSphere  Fit sphere.
%       A = fitSphere(x,y,z) returns the parameters of the best-fit
%       [C,R,out] = fitSphere(x,y,z) returns the center and radius
%       sphere to data points in vectors (x,y,z) using Taubin's method.
% IN:
%   - x/y/z: 3D carthesian ccordinates
% OUT:
%   - C: the center of sphere coordinates
%   - R: the radius of the sphere
%   - out: an output structure devoted to graphical display of the best fit
%   sphere

% Make sugary one and zero vectors
l = ones(length(x),1);
O = zeros(length(x),1);

% Make design mx
D = [(x.*x + y.*y + z.*z) x y z l];

Dx = [2*x l O O O];
Dy = [2*y O l O O];
Dz = [2*z O O l O];

% Create scatter matrices
M = D'*D;
N = Dx'*Dx + Dy'*Dy + Dz'*Dz;

% Extract eigensystem
[v, evalues] = eig(M);
evalues = diag(evalues);
Mrank = sum(evalues > eps*5*norm(M));

if (Mrank == 5)
    % Full rank -- min ev corresponds to solution
    Minverse = v'*diag(1./evalues)*v;
    [v,evalues] = eig(inv(M)*N);
    [dmin,dminindex] = max(diag(evalues));
    pvec = v(:,dminindex(1))';
else
    % Rank deficient -- just extract nullspace of M
    pvec = null(M)';
    [m,n] = size(pvec);
    if m > 1
        pvec = pvec(1,:);
    end
end

% Convert to (R,C)
if nargout == 1
    if pvec(1) < 0
        pvec = -pvec;
    end
    C = pvec;
else
    C = -0.5*pvec(2:4) / pvec(1);
    R = sqrt(sum(C*C') - pvec(5)/pvec(1));
end

[X,Y,Z] = sphere;
[TH,PHI,R0] = cart2sph(X,Y,Z);
[X,Y,Z] = sph2cart(TH,PHI,R);
X = X + C(1);
Y = Y + C(2);
Z = Z + C(3);

out.X = X;
out.Y = Y;
out.Z = Z;


function test_ft_denoise_hfc(testfile)

% WALLTIME 00:10:00
% MEM 8gb
% DEPENDENCY test_ft_denoise_hfc

% switch nargin
%   case 0
%     locate_function = which('test_ft_denoise_hfc');
%     % load data
%     load(fullfile(locate_function,'..','..','..','project_zeus',...
%       'data_UCL_OPM.mat'));
%   case 1
%     % If user inputs a filename, use path specific for DCCN
%     % Find this data: https://doi.org/10.17605/OSF.IO/CJNXH
%     load(dccnpath('/home/common/matlab/fieldtrip/data/test/pull2123/data_UCL_OPM.mat'));
% end
if nargin == 0
  testfile = dccnpath('/home/common/matlab/fieldtrip/data/test/pull2123/data_UCL_OPM.mat');
else
  % testfile is required in the input, as a full path to a mat-file
end
load(testfile);

% Test of Harmonic Field Correction (HFC) where L = 1
cfg               = [];
cfg.order         = 1;
cfg.residualcheck = 'yes';
[data_out]        = ft_denoise_hfc(cfg,data);

% Check L = 2
cfg               = [];
cfg.order         = 2;
cfg.residualcheck = 'yes';
[data_out]        = ft_denoise_hfc(cfg,data);

% Check L = 3
cfg               = [];
cfg.order         = 3;
cfg.residualcheck = 'yes';
[data_out]        = ft_denoise_hfc(cfg,data);

% Check L = 1 without residual check
cfg               = [];
cfg.order         = 1;
cfg.residualcheck = 'no';
[data_out]        = ft_denoise_hfc(cfg,data);


function [cnt1, cnt2] = elec1020_follow(pnt, dhk, v1, v2, v3, feedback)

% ELEC1020_FOLLOW

% Copyright (C) 2003, Robert Oostenveld
%
% This file is part of FieldTrip, see http://www.fieldtriptoolbox.org
% for the documentation and details.
%
%    FieldTrip 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.
%
%    FieldTrip 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 FieldTrip. If not, see <http://www.gnu.org/licenses/>.

if nargin<6
  feedback = false;
end

% compute the distribution of edge lengths
edge = [
  pnt(dhk(:,1),:) - pnt(dhk(:,2),:)
  pnt(dhk(:,2),:) - pnt(dhk(:,3),:)
  pnt(dhk(:,3),:) - pnt(dhk(:,1),:)
  ];
edgelength = sqrt(sum(edge.^2,2));

% the tolerance depends on the edge length
tolerance       = min(edgelength)*1e-6;
tolerance_limit = min(edgelength)*1e-3;

npnt = size(pnt,1);
ndhk = size(dhk,1);

pside = nan(1,npnt);
for i=1:npnt
  % determine on which side of the plane each vertex lies
  pside(i) = ptriside(v1, v2, v3, pnt(i,:), tolerance);
end

% dcut = zeros(ndhk,1);
% for i=1:ndhk
%   % find the triangles that are intersected by the plane
%   if sum(pside(dhk(i,:))==0)==2
%     dcut(i) = 1;
%   elseif sum(pside(dhk(i,:))==0)==1 & sum(pside(dhk(i,:))==1)==1 & sum(pside(dhk(i,:))==-1)==1
%     dcut(i) = 1;
%   elseif sum(pside(dhk(i,:))==1)==2 & sum(pside(dhk(i,:))==-1)==1
%     dcut(i) = 1;
%   elseif sum(pside(dhk(i,:))==1)==1 & sum(pside(dhk(i,:))==-1)==2
%     dcut(i) = 1;
%   end
% end
tmp  = pside(dhk);
dcut = true(ndhk,1);
dcut(all(tmp== 1,2)) = false;
dcut(all(tmp==-1,2)) = false;

% continue working with only the intersecting triangles
dhk = dhk(dcut,:);
ndhk = size(dhk,1);

% for each triangle determine the neighbouring triangles
neighb = zeros(ndhk,ndhk);
for i=1:ndhk
  for j=(i+1):ndhk
    if dhk(i,1)==dhk(j,1)
      neighb(i,j) = 1;
    elseif dhk(i,1)==dhk(j,2)
      neighb(i,j) = 1;
    elseif dhk(i,1)==dhk(j,3)
      neighb(i,j) = 1;
    elseif dhk(i,2)==dhk(j,1)
      neighb(i,j) = 1;
    elseif dhk(i,2)==dhk(j,2)
      neighb(i,j) = 1;
    elseif dhk(i,2)==dhk(j,3)
      neighb(i,j) = 1;
    elseif dhk(i,3)==dhk(j,1)
      neighb(i,j) = 1;
    elseif dhk(i,3)==dhk(j,2)
      neighb(i,j) = 1;
    elseif dhk(i,3)==dhk(j,3)
      neighb(i,j) = 1;
    else
      neighb(i,j) = 0;
    end
    neighb(j,i) = neighb(i,j);
  end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% make a contour from v1 via v2 to v3

% find the nearest triangle on which point v1 projects
v1_dist = inf;
for i=1:ndhk
  % shift a fraction towards v2 to avoid starting in the vertex of a wrong triangle
  [proj, dist] = ptriproj(pnt(dhk(i,1),:), pnt(dhk(i,2),:), pnt(dhk(i,3),:), v1+tolerance*(v2-v1)/norm(v2-v1), 1);
  if dist<v1_dist
    v1_dist = dist;
    v1_indx = i;
    v1_proj = ptriproj(pnt(dhk(i,1),:), pnt(dhk(i,2),:), pnt(dhk(i,3),:), v1, 1);
  end
end

% find the nearest triangle on which point v3 projects
v3_dist = inf;
for i=1:ndhk
  [proj, dist] = ptriproj(pnt(dhk(i,1),:), pnt(dhk(i,2),:), pnt(dhk(i,3),:), v3, 1);
  if dist<v3_dist
    v3_dist = dist;
    v3_indx = i;
    v3_proj = proj;
  end
end

% intersect the triangle containing the projection of v1 with the plane
[l1, l2] = tritrisect(v1, v2, v3, pnt(dhk(v1_indx,1),:), pnt(dhk(v1_indx,2),:), pnt(dhk(v1_indx,3),:));
if pntdist(l1,v2) < pntdist(l2,v2)
  % remember the projection point and l1 as the first line segment
  cnt1 = [v1_proj];
  cnt2 = [l1];
  prev_proj = l1;
  prev_indx = v1_indx;
else
  % remember the projection point and l2 as the first line segment
  cnt1 = [v1_proj];
  cnt2 = [l2];
  prev_proj = l2;
  prev_indx = v1_indx;
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

while(1)

  for i=find(neighb(prev_indx,:))

    ncnt = size(cnt1,1);
    c1 = pnt(dhk(i,1),:);
    c2 = pnt(dhk(i,2),:);
    c3 = pnt(dhk(i,3),:);
%
%     if feedback
%       ft_plot_mesh(struct('pos', pnt, 'tri', dhk(i,:)), 'edgecolor', 'b', 'facecolor', 'none')
%       ft_plot_mesh(c1, 'vertexsize', 30, 'vertexcolor', 'r')
%       ft_plot_mesh(c2, 'vertexsize', 30, 'vertexcolor', 'r')
%       ft_plot_mesh(c3, 'vertexsize', 30, 'vertexcolor', 'r')
%       ft_plot_mesh(prev_proj, 'vertexsize', 30, 'vertexcolor', 'g')
%       drawnow
%     end

    [proj, dist] = ptriproj(c1, c2, c3, prev_proj, 1);

    if dist<tolerance
      [l1, l2] = tritrisect(v1, v2, v3, c1, c2, c3);

      if pntdist(l1, cnt1(ncnt,:))<tolerance && pntdist(l2, cnt2(ncnt,:))<tolerance
        continue
      elseif pntdist(l1, cnt2(ncnt,:))<tolerance && pntdist(l2, cnt1(ncnt,:))<tolerance
        continue
      end

      if pntdist(l1, prev_proj) < pntdist(l2, prev_proj)
        cnt1 = [cnt1; l1];
        cnt2 = [cnt2; l2];
        prev_proj = l2;
        prev_indx = i;
        break
      else
        cnt1 = [cnt1; l2];
        cnt2 = [cnt2; l1];
        prev_proj = l1;
        prev_indx = i;
        break
      end
    end

  end

  % stop if no new segment was added
  if ~(size(cnt1,1)>ncnt)
    tolerance = 2*tolerance;
    if tolerance>=tolerance_limit
      ft_warning('premature end of contour')
      break
    else
      ft_warning('increasing tolerance');
    end
  end

  % stop if we arrive on the triangle with the endpoint
  if pntdist(prev_proj, v3_proj)<tolerance
    % replace the current endpoint with the projection of v3
    cnt2(size(cnt2,1),:) = v3_proj;
    break
  end

  % stop if we arrive on the triangle with the endpoint
  if prev_indx==v3_indx
    % replace the current endpoint with the projection of v3
    cnt2(size(cnt2,1),:) = v3_proj;
    break
  end

end % while

if feedback
  X = [cnt1(:,1) cnt2(:,1)];
  Y = [cnt1(:,2) cnt2(:,2)];
  Z = [cnt1(:,3) cnt2(:,3)];
  line(X, Y, Z, 'color', 'k')
  drawnow
end

end % function


function regular_training_ms(video)

opts.dataDir = 'net/traffic_Simple' ;
opts.expDir = ['net/' video] ;

opts.train.batchSize = 5 ;
opts.train.numEpochs = 20;
opts.train.continue = false ;
opts.train.useGpu = true ;
opts.train.learningRate    = 1e-3;
opts.train.expDir = opts.expDir ;

scales = [1, 0.75, 0.5];

%opts = vl_argparse(opts, varargin) ;

% --------------------------------------------------------------------
%                                                         Prepare data
% --------------------------------------------------------------------

imgDir = ['../SBMIDataset/' video '/input'];
labelDir = ['../SBMIDataset/' video '/groundtruth'];
imdb = getImdb(video,imgDir,labelDir);

imdb.half_size = 15;

%%%%%%Yi%%%%%% redefined the net
load('net');

net.layers{end-1} = struct('type', 'conv', ...
    'filters', 0.1*randn(1,1,64,1, 'single'), ...
    'biases', zeros(1, 1, 'single'), ...
    'stride', 1, ...
    'pad', 0) ;
net.layers{end} = struct('type', 'sigmoidcrossentropyloss');

load('meanPixel.mat');
imdb.meanPixel = meanPixel;
imdb.scales = scales;

[net,info] = cnn_train_adagrad_ms(net, imdb, @getBatch,...
    opts.train,'errorType','euclideanloss',...
    'conserveMemory', true);

end

function [im, labels] = getBatch(imdb, batch)
% --------------------------------------------------------------------

half_size = imdb.half_size;
meanPixel = imdb.meanPixel;

for ii = 1:numel(batch)

    imagename = imdb.images.name{batch(ii)};
    im_ii = single(imread(imagename));
    labelname = imdb.images.labels{batch(ii)};
    roi = imread(labelname);
    labels_ii = zeros(size(roi, 1), size(roi, 2));
    labels_ii( roi == 50 )  = 0.25;       %shade
    labels_ii( roi == 170 ) = 0.75;       %object boundary
    labels_ii( roi == 255 ) = 1;          %foreground

    % resize the image to half size
    if size(im_ii,1) > 400 || size(im_ii,2) >400
        im_ii = imresize(im_ii, 0.5, 'nearest');
        labels_ii = imresize(labels_ii, 0.5, 'nearest');
    end

    im(:,:,:,ii) = im_ii;
    labels(:,:,1,ii) = labels_ii;
end
end

function imdb = getImdb(video, imgDir, labelDir)

files = [dir([imgDir '/*.png']); dir([imgDir '/*.jpg'])];
label_files = dir([labelDir '/*.png']);
names = {};labels = {};

load(['../split/' video '.mat']);

for ii = 1:numel(train_index)
    names{end+1} = [imgDir '/' files(train_index(ii)).name];
    labels{end+1} = [labelDir '/' label_files(train_index(ii)).name];
end

im = imread(labels{1});
mask = ones(size(im,1),size(im,2));
if size(mask,1) > 400 || size(mask,2) >400
    mask = imresize(mask, 0.5, 'nearest');
end

imdb.mask = single(mask);

imdb.images.set = ones(1,numel(names));
imdb.images.name = names ;
imdb.images.labels = labels;
end


function [c, ceq] = ma_truConstraint(stateLog, eventID, lbTru, ubTru, bodyIDApply, celBodyData, maData)
%ma_semiMajorAxisConstraint Summary of this function goes here
%   Detailed explanation goes here
    normFact = pi;

    if(ischar(eventID) && strcmpi(eventID,'final'))
        eventNum = max(stateLog(:,13));
    else
%         hMAMainGUI = findall(0,'tag','ma_MainGUI');
%         maData = getappdata(hMAMainGUI,'ma_data');
        [~, eventNum] = getEventByID(eventID, maData.script);
    end

    eventLog = stateLog(stateLog(:,13)==eventNum,:);

    bodyEventLog = eventLog(eventLog(:,8)==bodyIDApply,:);
    if(isempty(bodyEventLog))
        finalEntry = eventLog(end,:);
    else
        finalEntry = bodyEventLog(end,:);
    end

    bodyID = finalEntry(8);

    if(bodyID == bodyIDApply || bodyIDApply==-1)
        bodyInfo = getBodyInfoByNumber(bodyID, celBodyData);
        gmu = bodyInfo.gm;
        rVect = finalEntry(2:4)';
        vVect = finalEntry(5:7)';

        [~, ~, ~, ~, ~, tru] = getKeplerFromState(rVect,vVect,gmu);

        if(lbTru <= 0 && ubTru <= 0)
            lbTru = AngleZero2Pi(lbTru);
            ubTru = AngleZero2Pi(ubTru);
        elseif(lbTru<0 && ubTru >=0)
            if(tru >= AngleZero2Pi(lbTru) && tru <= 2*pi)
                lbTru = AngleZero2Pi(lbTru);
                ubTru = 2*pi;
            elseif(tru >= 0 && tru <= ubTru)
                lbTru = 0;
            end
        end

        if(lbTru == ubTru)
            c = [0 0];
            ceq(1) = tru - ubTru;
        else
            c(1) = lbTru - tru;
            c(2) = tru - ubTru;
            ceq = [0];
        end
        c = c/normFact;
        ceq = ceq/normFact;
    else
        c = [0 0];
        ceq = [0];
    end
end


function status = test_secondary_source_selection(modus)
%TEST_SECONDARY_SOURCE_SELECTION tests the correctness of
%secondary_source_selection()
%
%   Usage: status = test_secondary_source_selection(modus)
%
%   Input parameters:
%       modus   - 0: numerical (quiet)
%                 1: visual (not available)
%                 2: numerical verbose
%
%   Output parameters:
%       status - true or false

%*****************************************************************************
% 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 *
%*****************************************************************************

status = false;

%% ===== Checking of input  parameters ===================================
nargmin = 1;
nargmax = 1;
narginchk(nargmin,nargmax);

%% ===== Main ============================================================
conf = SFS_config;
conf.secondary_sources.number = 16;
% reference values
ref_selection_circular_pw = ...
    [0   1   1   1   1   1   1   1   0   0   0   0   0   0   0   0]';
ref_selection_circular_ps = ...
    [0   0   1   1   1   1   1   0   0   0   0   0   0   0   0   0]';
ref_selection_circular_fs = ...
    [1   1   1   1   1   0   0   0   0   0   0   0   0   0   0   0]';
ref_selection_linear_pw = ...
    [1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1]';
ref_selection_linear_ps = ...
    [1   1   1   1   1   1   1   1   1   1   1   1   1   1   1   1]';
ref_selection_linear_fs = ...
    [0   0   0   0   0   0   0   0   1   1   1   1   1   1   1   1]';
ref_selection_box_pw = ...
    [0   0   0   0   1   1   1   1   0   0   0   0   0   0   0   0]';
ref_selection_box_ps = ...
    [0   0   0   0   1   1   1   1   0   0   0   0   0   0   0   0]';
ref_selection_box_fs = ...
    [0   1   1   1   1   1   1   0   0   0   0   0   0   0   0   0]';
% Calculate current values
% circular array
conf.secondary_source.geometry = 'circular';
x0 = secondary_source_positions(conf);
[~,selection_circular_pw] = secondary_source_selection(x0,[0 -1 0],'pw');
[~,selection_circular_ps] = secondary_source_selection(x0,[0 2.5 0],'ps');
[~,selection_circular_fs] = secondary_source_selection(x0,[0.5 0.5 0 -1 -1 0],'fs');
% linear array
conf.secondary_sources.geometry = 'linear';
x0 = secondary_source_positions(conf);
[~,selection_linear_pw] = secondary_source_selection(x0,[0 -1 0],'pw');
[~,selection_linear_ps] = secondary_source_selection(x0,[0 1 0],'ps');
[~,selection_linear_fs] = secondary_source_selection(x0,[0.5 -0.5 0 -1 -1 0],'fs');
% box form array
conf.secondary_sources.geometry = 'box';
x0 = secondary_source_positions(conf);
[~,selection_box_pw] = secondary_source_selection(x0,[0 -1 0],'pw');
[~,selection_box_ps] = secondary_source_selection(x0,[0 3.5 0],'ps');
[~,selection_box_fs] = secondary_source_selection(x0,[0.5 0.5 0 -1 -1 0],'fs');

if modus==0
    % Numerical mode (quiet)
    if ~all(eq(ref_selection_circular_pw,selection_circular_pw)) || ...
       ~all(eq(ref_selection_circular_ps,selection_circular_ps)) || ...
       ~all(eq(ref_selection_circular_fs,selection_circular_fs)) || ...
       ~all(eq(ref_selection_linear_pw,selection_linear_pw)) || ...
       ~all(eq(ref_selection_linear_ps,selection_linear_ps)) || ...
       ~all(eq(ref_selection_linear_fs,selection_linear_fs)) || ...
       ~all(eq(ref_selection_box_pw,selection_box_pw)) || ...
       ~all(eq(ref_selection_box_ps,selection_box_ps)) || ...
       ~all(eq(ref_selection_box_fs,selection_box_fs))
        return;
    end
elseif modus==2
    message = 'wrong secondary source selection for a';
    if ~all(eq(ref_selection_circular_pw,selection_circular_pw))
        error('%s: %s circular array and a plane wave.', ...
            upper(mfilename),message);
    end
    if ~all(eq(ref_selection_circular_ps,selection_circular_ps))
        error('%s: %s circular array and a point source.', ...
            upper(mfilename),message);
    end
    if ~all(eq(ref_selection_circular_fs,selection_circular_fs))
        error('%s: %s circular array and a focused source.', ...
            upper(mfilename),message);
    end
    if ~all(eq(ref_selection_linear_pw,selection_linear_pw))
        error('%s: %s linear array and a plane wave.', ...
            upper(mfilename),message);
    end
    if ~all(eq(ref_selection_linear_ps,selection_linear_ps))
        error('%s: %s linear array and a point source.', ...
            upper(mfilename),message);
    end
    if ~all(eq(ref_selection_linear_fs,selection_linear_fs))
        error('%s: %s linear array anda focused source.', ...
            upper(mfilename),message);
    end
    if ~all(eq(ref_selection_box_pw,selection_box_pw))
        error('%s: %s box shaped array and a plane wave.', ...
            upper(mfilename),message);
    end
    if ~all(eq(ref_selection_box_ps,selection_box_ps))
        error('%s: %s box shaped array and a point source.', ...
            upper(mfilename),message);
    end
    if ~all(eq(ref_selection_box_fs,selection_box_fs))
        error('%s: %s box shaped array and a focused source.', ...
            upper(mfilename),message);
    end
end

status = true;


classdef test_Correlation < matlab.unittest.TestCase
   %UNTITLED Summary of this class goes here
   %   Detailed explanation goes here

   properties
   end

   methods(Test)

      % Cases for adjusttrig
      function TestAdjustTrigDefaults(testCase)
         c = correlation.demo();
         c = c.adjustrig();
      end
      function TestAdjustTrigTimeshift(testCase)
         c = correlation.demo();
         c = c.adjustrig('index', 10);
      end
      function TestAdjustTrigMin(testCase)
         c = correlation.demo();
         c = c.adjustrig('min');
      end
      function TestAdjustTrigMedian(testCase)
         c = correlation.demo();
         c = c.adjustrig('median');
      end
      function TestAdjustTrigMaxLag(testCase)
         c = correlation.demo();
         c = c.adjustrig('min', 1);
      end
      function TestAdjustTrigIndex(testCase)
         c = correlation.demo();
         c = c.adjustrig('index');
      end
      function TestAdjustTrigIndexRelativeToSpecificTrace(testCase)
         c = correlation.demo();
         c = c.adjustrig('index', 10);
      end
      function TestAdjustTrigLeastSquares(testCase)
         c = correlation.demo();
         c = c.adjustrig('lsq');

         % TEST RESULT
      end

      % tests for agc
      function TestAutoGainControl(testCase)
      end
      function TestAlign(testCase)
      end
      function testButter(testCase)
      end
      function testCat(testCase)
      end
      function testCheck(testCase)
      end
      function testCluster(testCase)
      end
      function testColormap(testCase)
      end
      function testConv(testCase)
      end
      function testCrop(testCase)
      end
      function testDeconv(testCase)
      end
      function testDemean(testCase)
      end
      function testDetrend(testCase)
      end
      function testDiff(testCase)
      end
      function testFind(testCae)
      end

   end
end


function [] = anim8_DIC_images_corr_faces_n_n(IMset,DIC_2Dpair_results,varargin)
%% function for plotting 2D-DIC results imported from Ncorr in step 2
% called inside plotNcorrPairResults
% plotting the images chosen for stereo DIC (2 views) with the
% triangular faces results plotted on top, colored as their correlation
% coefficient.
% on the left side the images from the reference camera (reference image and current images), and on the right side the
% images from the deformed camera
% requirements: GIBBON toolbox
%
% calling options:
% [] = anim8_DIC_images(IMset,DIC_2Dpair_results);
% [] = anim8_DIC_images(IMset,DIC_2Dpair_results,CorCoeffCutOff,CorCoeffDispMax);
%
% INPUT:
% * IMset - a 2nX1 cell array containing 2n grayscale images. The first n
% images are from camera A (the "reference" camera), and the last n images
% are from camera B (the "deformed" camera). The first image in the set is
% considered as the reference image, on which the reference grid of points
% is defined, and all the correlated points and consequent displacements
% and strains, are relative to this image.
% * DIC_2Dpair_results - containig the correlated points, correlation
% coefficients, faces..
% * optional: CorCoeffCutOff - - maximal correlation coefficient to plot
% points
% * optional: CorCoeffDispMax - maximal correlation coefficient in colorbar

%%
nCur=numel(IMset); % number of frames

nSteps=nCur/2; %Number of animation steps
if  rem(nSteps,1)~=0
    error('Number of images in the set should be even');
end

%%
Points=DIC_2Dpair_results.Points;
CorCoeffVec=DIC_2Dpair_results.CorCoeffVec;
nCamRef=DIC_2Dpair_results.nCamRef;
nCamDef=DIC_2Dpair_results.nCamDef;
nImages=DIC_2Dpair_results.nImages;
F=DIC_2Dpair_results.Faces;

nVars = length(varargin);
switch nVars
    case 2
        CorCoeffCutOff=varargin{1};
        if isnan(CorCoeffCutOff)
            CorCoeffCutOff=max(max([CorCoeffVec{:}]));
        end
        CorCoeffDispMax=varargin{2};
        if isnan(CorCoeffDispMax)
            CorCoeffDispMax=max(max([CorCoeffVec{:}]));
        end
    case 1
        CorCoeffCutOff=varargin{1};
        if isnan(CorCoeffCutOff)
            CorCoeffCutOff=max(max([CorCoeffVec{:}]));
        end
        CorCoeffDispMax=max(max([CorCoeffVec{:}]));
    case 0
        CorCoeffCutOff=max(max([CorCoeffVec{:}]));
        CorCoeffDispMax=max(max([CorCoeffVec{:}]));
    otherwise
        error('Wrong number of input arguments');
end

%%
hf=cFigure;
hf.Units='normalized'; hf.OuterPosition=[.05 .05 .9 .9]; hf.Units='pixels';

% Ref
ii=1;
subplot(1,2,1)
CFcorr=mean(CorCoeffVec{1}(F),2);
CFcorr(CFcorr>CorCoeffCutOff)=NaN;
hp1=imagesc(repmat(IMset{ii},1,1,3)); hold on;
hp2=gpatch(F,Points{1},CFcorr,'k',0.4);
set(hp2,'EdgeAlpha',0.4);
colormap jet
pbaspect([size(IMset{ii},2) size(IMset{ii},1) 1])
hs1=title(['Ref (Cam ' num2str(nCamRef) ' frame ' num2str(1) ')']);
hc1=colorbar;
caxis([0 CorCoeffDispMax])
title(hc1, 'Corr-Coeff')
axis off

% Cur
ii=nImages+1;
subplot(1,2,2)
CFcorr=mean(CorCoeffVec{1+nCur/2}(F),2);
CFcorr(CFcorr>CorCoeffCutOff)=NaN;
hp3=imagesc(repmat(IMset{ii},1,1,3)); hold on
hp4=gpatch(F,Points{ii},CFcorr,'k',0.4); %colormap jet
colormap jet
pbaspect([size(IMset{ii},2) size(IMset{ii},1) 1])
hs2=title(['Cur ' num2str(ii) ' (Cam ' num2str(nCamDef) ' frame ' num2str(1) ')']);
hc2=colorbar;
caxis([0 CorCoeffDispMax])
title(hc2, 'Corr-Coeff')
axis off

drawnow

%Create the time vector
animStruct.Time=linspace(0,1,nImages);

for ii=1:nImages
    Pnow1=Points{ii};
    Pnow2=Points{ii+nImages};

    cNow1=CorCoeffVec{ii};
    cNow1(cNow1>CorCoeffCutOff)=NaN;
    cNow2=CorCoeffVec{ii+nImages};
    cNow2(cNow2>CorCoeffCutOff)=NaN;

    TitleNow1=['Cur ' num2str(ii) ' (Cam ' num2str(nCamRef) ' frame ' num2str(ii) ')'];
    TitleNow2=['Cur ' num2str(ii) ' (Cam ' num2str(nCamDef) ' frame ' num2str(ii) ')'];

   %Set entries in animation structure
    animStruct.Handles{ii}=[hp1,hp3,hp2,hp2,hp4,hp4,hs1,hs2]; %Handles of objects to animate
    animStruct.Props{ii}={'CData','CData','Vertices','CData','Vertices','CData','String','String'}; %Properties of objects to animate
    animStruct.Set{ii}={repmat(IMset{ii},1,1,3),repmat(IMset{ii+nImages},1,1,3),Pnow1,cNow1,Pnow2,cNow2,TitleNow1,TitleNow2}; %Property values for to set in order to animate

end

anim8(hf,animStruct);

addColorbarLimitsButton(hf);
addColormapButton(hf);
addEdgeColorButton(hf);
addFaceAlphaButton(hf);
addLightButton(hf);
addAmbientStrengthButton(hf);

end

%%
% MultiDIC: a MATLAB Toolbox for Multi-View 3D Digital Image Correlation
%
% License: <https://github.com/MultiDIC/MultiDIC/blob/master/LICENSE.txt>
%
% Copyright (C) 2018  Dana Solav
%
% Modified by Rana Odabas 2018
%
% If you use the toolbox/function for your research, please cite our paper:
% <https://engrxiv.org/fv47e>


%ISPARALLEL Test on parallel mapping
%
%  N = ISPARALLEL(W)
%      ISPARALLEL(W)
%
% INPUT
%  W    input mapping
%
% OUTPUT
%  N    logical value
%
% DESCRIPTION
% Returns true for parallel mappings. If no output is required,
% false outputs are turned into errors. This may be used for
% assertion.
%
% SEE ALSO (PRTools Guide)
% ISMAPPING, ISSTACKED

% $Id: isparallel.m,v 1.2 2006/03/08 22:06:58 duin Exp $

function n = isparallel(w)

	if isa(w,'prmapping') & strcmp(w.mapping_file,'parallel')
		n = 1;
	else
		n = 0;
	end

	% generate error if input is not a parallel mapping
	% AND no output is requested (assertion)

	if nargout == 0 & n == 0
		error([newline '---- Parallel mapping expected -----'])
	end

return


function [obX,obY,obXM,obYM,lp] = mrTransInplanes(numofanats,obXM,obYM,lp,curInplane)
%NAME:    [obX,obY,obXM,obYM,lp] = mrTransInplanes(numofanats,obXM,obYM,lp,curInplane)
%AUTHOR:  Poirson
%DATE:	  08.04.96
%PURPOSE: One of a set of routines that allows user
%         to set and select a set of oblique planes in saggital slice.
%	  The routines are mrTransInplanes.m, mrRotInplanes.m,
%	  mrClipInplanes.m, mrSelInplane.m, mrSetupInplanes.m
%         mrSpreadInplanes.m
%HISTORY: Started with mrGetOblPlane from G. Boynton 4/6/96
%NOTES:

global sagwin
figure(sagwin)

% One more pair of points for the perpendicular line
nPtPairs = numofanats + 1;

% See if the user has already been working on some inPlanes
if size(obXM,1) == 0
	disp('You must first create a candidate set of Inplanes');
	disp('Choose Set_Up_Inplanes first');
	return
end

% Center point of the inplanes is the middle of perpendicular line
centerX = mean(obXM(nPtPairs,:));
centerY = mean(obYM(nPtPairs,:));

xlim=get(gca,'XLim');
ylim=get(gca,'YLim');
xt = diff(xlim)*(-1.0) * 0.8;
yt=ylim(1)+diff(xlim)*[0.05,0.125,0.20];
msg(1) = text(xt,yt(1),'Translate Buttons:');
msg(2) = text(xt,yt(2),'Left = Center point');
msg(3) = text(xt,yt(3),'Right= Quit');

button = 0;
while(button~=3)
 [tempx,tempy,button]=mrGinput(1,'cross');
 if (button~=3)
  if (button == 1) | (button == 2)
   obXM = obXM + (tempx-centerX);
   obYM = obYM + (tempy-centerY);
   % Recalculate the center
   centerX = tempx;
   centerY = tempy;
  end

  for i=1:length(lp)
    delete(lp(i));
  end

  for i=1:nPtPairs
   if i == curInplane
        lp(i)=line(obXM(i,:),obYM(i,:),'Color','r');
	% Set obX and obY to new values.
   else
        lp(i)=line(obXM(i,:),obYM(i,:),'Color','b');
   end
  end

 end
end

if (curInplane ~= 0)
	obX = obXM(curInplane,:);
	obY = obYM(curInplane,:);
else
	obX = [0,0];
	obY = [0,0];
end

delete(msg(1));delete(msg(2));delete(msg(3));

return;


function maximize( varargin )

%MAXIMIZE Specifiies a concave (or affine) objective to be maximized.

if nargin < 1,
    cvx_throw( 'Objective expression missing.' );
elseif iscellstr( varargin ),
    x = evalin( 'caller', sprintf( '%s ', varargin{:} ) );
elseif nargin > 1,
    cvx_throw( 'Too many input arguments.' );
else
    x = varargin{1};
end
evalin( 'caller', 'cvx_verify' );
cvx_pushobj( 'maximize', x );

% Copyright 2005-2014 CVX Research, Inc.
% See the file LICENSE.txt for full copyright information.
% The command 'cvx_where' will show where this file is located.


function out = isinf(f)
%ISINF   Test if a CLASSICFUN is unbounded.
%   ISINF(F) returns TRUE if F takes an infinite value and FALSE otherwise.
%
% See also ISFINITE, ISNAN.

% Copyright 2017 by The University of Oxford and The Chebfun Developers.
% See http://www.chebfun.org/ for Chebfun information.

% Check if the ONEFUN of f is infinite:
out = isinf(f.onefun);

end


%% inRange Thresholding Operations
%
% In this demo, we show how to:
%
% * Perform basic thresholding operations using OpenCV function |cv.inRange|
% * Detect an object based on the range of pixel values it has
%
% For improving detection by color, it is common to perform thresholding in
% other colorspaces like HSV or LAB, where luma and chroma are represented
% separately.
%
% Sources:
%
% * <https://docs.opencv.org/3.2.0/da/d97/tutorial_threshold_inRange.html>
% * <https://github.com/opencv/opencv/blob/3.2.0/samples/cpp/tutorial_code/ImgProc/Threshold_inRange.cpp>
%

function varargout = threshold_inrange_demo_gui(im)
    % load source image
    if nargin < 1
        src = cv.imread(fullfile(mexopencv.root(),'test','monster.jpg'));
    elseif ischar(im)
        src = cv.imread(im);
    else
        src = im;
    end
    validateattributes(src, {'uint8'}, {'size',[NaN NaN 3]});

    % create the UI
    h = buildGUI(src);
    if nargout > 0, varargout{1} = h; end
end

function onType(~,e,h)
    %ONTYPE  Event handler for key press on figure

    % handle keys
    switch e.Key
        case 'h'
            helpdlg({
                'Hot keys:'
                'h - this help dialog'
                'q - quit the program'
                's - save thresholded image'
            });

        case {'q', 'escape'}
            close(h.fig);

        case {'s', 'space'}
            % save image
            img = get(h.img(2), 'CData');
            fname = fullfile(tempdir(), ...
                sprintf('out_%s.png', datestr(now(),'yyyymmddTHHMMSS')));
            cv.imwrite(fname, img);
            disp(['Saved ' fname]);
    end
end

function onChange(~,~,h)
    %ONCHANGE  Event handler for UI controls

    % retrieve current values from UI controls
    rlo = round(get(h.slid(1), 'Value'));
    rhi = round(get(h.slid(2), 'Value'));
    glo = round(get(h.slid(3), 'Value'));
    ghi = round(get(h.slid(4), 'Value'));
    blo = round(get(h.slid(5), 'Value'));
    bhi = round(get(h.slid(6), 'Value'));

    % permform thresholding
    lowerb = min([rlo glo blo], [rhi ghi bhi]);
    upperb = max([rlo glo blo], [rhi ghi bhi]);
    mask = cv.inRange(h.src, lowerb, upperb);

    % apply mask
    out = cv.copyTo(h.src, 'Mask',mask);

    % update UI and show result
    set(h.txt(1), 'String',sprintf(' Low R: %3d',rlo));
    set(h.txt(2), 'String',sprintf('High R: %3d',rhi));
    set(h.txt(3), 'String',sprintf(' Low G: %3d',glo));
    set(h.txt(4), 'String',sprintf('High G: %3d',ghi));
    set(h.txt(5), 'String',sprintf(' Low B: %3d',blo));
    set(h.txt(6), 'String',sprintf('High B: %3d',bhi));
    set(h.img(2), 'CData',out);
    drawnow;
end

function h = buildGUI(img)
    %BUILDGUI  Creates the UI

    % parameters
    sz = size(img);
    rlo = 100; rhi = 255;
    glo = 0; ghi = 100;
    blo = 0; bhi = 100;

    % build the user interface (no resizing to keep it simple)
    h = struct();
    h.src = img;
    h.fig = figure('Name','Threshold Demo', ...
        'NumberTitle','off', 'Menubar','none', 'Resize','off', ...
        'Position',[200 200 sz(2)*2 sz(1)+155-1]);
    if ~mexopencv.isOctave()
        %HACK: not implemented in Octave
        movegui(h.fig, 'center');
    end
    imgs = {img, false(sz(1:2))};
    for i=1:numel(imgs)
        h.ax(i) = axes('Parent',h.fig, 'Units','pixels', ...
            'Position',[1+sz(2)*(i-1) 155 sz(2) sz(1)]);
        if ~mexopencv.isOctave()
            h.img(i) = imshow(imgs{i}, 'Parent',h.ax(i));
        else
            %HACK: https://savannah.gnu.org/bugs/index.php?45473
            axes(h.ax(i));
            h.img(i) = imshow(imgs{i});
        end
    end
    h.txt(1) = uicontrol('Parent',h.fig, 'Style','text', ...
        'Position',[5 5 130 20], 'FontSize',11, 'ForegroundColor','r', ...
        'String',sprintf(' Low R: %3d',rlo));
    h.txt(2) = uicontrol('Parent',h.fig, 'Style','text', ...
        'Position',[5 30 130 20], 'FontSize',11, 'ForegroundColor','r', ...
        'String',sprintf('High R: %3d',rhi));
    h.txt(3) = uicontrol('Parent',h.fig, 'Style','text', ...
        'Position',[5 55 130 20], 'FontSize',11, 'ForegroundColor','g', ...
        'String',sprintf(' Low G: %3d',glo));
    h.txt(4) = uicontrol('Parent',h.fig, 'Style','text', ...
        'Position',[5 80 130 20], 'FontSize',11, 'ForegroundColor','g', ...
        'String',sprintf('High G: %3d',ghi));
    h.txt(5) = uicontrol('Parent',h.fig, 'Style','text', ...
        'Position',[5 105 130 20], 'FontSize',11, 'ForegroundColor','b', ...
        'String',sprintf(' Low B: %3d',blo));
    h.txt(6) = uicontrol('Parent',h.fig, 'Style','text', ...
        'Position',[5 130 130 20], 'FontSize',11, 'ForegroundColor','b', ...
        'String',sprintf('High B: %3d',bhi));
    h.slid(1) = uicontrol('Parent',h.fig, 'Style','slider', ...
        'Position',[135 5 sz(2)-135-5 20], 'Value',rlo, ...
        'Min',0, 'Max',255, 'SliderStep',[1 20]./(255-0));
    h.slid(2) = uicontrol('Parent',h.fig, 'Style','slider', ...
        'Position',[135 30 sz(2)-135-5 20], 'Value',rhi, ...
        'Min',0, 'Max',255, 'SliderStep',[1 20]./(255-0));
    h.slid(3) = uicontrol('Parent',h.fig, 'Style','slider', ...
        'Position',[135 55 sz(2)-135-5 20], 'Value',glo, ...
        'Min',0, 'Max',255, 'SliderStep',[1 20]./(255-0));
    h.slid(4) = uicontrol('Parent',h.fig, 'Style','slider', ...
        'Position',[135 80 sz(2)-135-5 20], 'Value',ghi, ...
        'Min',0, 'Max',255, 'SliderStep',[1 20]./(255-0));
    h.slid(5) = uicontrol('Parent',h.fig, 'Style','slider', ...
        'Position',[135 105 sz(2)-135-5 20], 'Value',blo, ...
        'Min',0, 'Max',255, 'SliderStep',[1 20]./(255-0));
    h.slid(6) = uicontrol('Parent',h.fig, 'Style','slider', ...
        'Position',[135 130 sz(2)-135-5 20], 'Value',bhi, ...
        'Min',0, 'Max',255, 'SliderStep',[1 20]./(255-0));

    % hook event handlers, and trigger default start
    opts = {'Interruptible','off', 'BusyAction','cancel'};
    set(h.slid, 'Callback',{@onChange,h}, opts{:});
    set(h.fig, 'WindowKeyPressFcn',{@onType,h}, opts{:});
    onChange([],[],h);
end


classdef MaterialDesignExperiment < handle

   properties (Access = public)

    end

    properties (Access = private)

    end

    properties (Access = private)
        fileNames
        topOptSet
        topOptProblem
    end

    methods (Access = public)

        function obj = MaterialDesignExperiment()
            obj.init();
            for icases = 1:numel(obj.fileNames)
                obj.createSettings(icases);
                obj.solveProblem();
                close all
            end

        end

    end

    methods (Access = private)

        function init(obj)
            obj.fileNames = {...
                             'HorizontalMaterialDesign';
                          %   'CompositeMaterialDesignTriDensityP1';
                           %  'CompositeMaterialDesignTriDensityPDE';
                           %  'CompositeMaterialDesignQuadDensityP1';
                            %  'CompositeMaterialDesignQuadDensityPDE';
                            % 'CompositeMaterialDesignTriLevelSetP1';
                            % 'CompositeMaterialDesignTriLevelSetPDE';
                           % 'CompositeMaterialDesignQuadLevelSetP1';
                           %  'CompositeMaterialDesignQuadLevelSetPDE';
                             };
        end

        function createSettings(obj,icases)
            s = SettingsTopOptProblem(obj.fileNames{icases});
            obj.topOptSet = s;
        end

        function solveProblem(obj)
            obj.topOptProblem = TopOpt_Problem(obj.topOptSet);
            obj.topOptProblem.computeVariables();
            obj.topOptProblem.postProcess();
        end
    end

end


function [flow_out, time_shifted_points_out] = em1_flow(...
    events, ...
    feature_pos, ...
    flow_init, ...
    params, ...
    fig)
%EM1_FLOW Estimates optical flow for an event feature.
%
% EM1_FLOW estimates the optical flow of a set of events % combined to form
% a 'feature'. This EM step runs from the events alone, as in:
% Alex Zihao Zhu, Nikolay Atanasov and Kostas Daniilidis.
% "Event-based Feature Tracking with Probabilistic Data Associations", ICRA 2017.
%
% Syntax:  [flow_out, time_shifted_points_out] = EM1_FLOW(...
%            events, ...
%            feature_pos, ...
%            flow_init, ...
%            params, ...
%            fig)
%
% Inputs:
%    events               - 4xN, each column is (x,y,t,p).
%    feature_pos          - 2x1, pixel position of the feature.
%    flow_init            - 2x1, initialization for the flow.
%    params               - parameters, defined in get_params().
%    fig                  - figure handle for plotting.
%
% Outputs:
%    flow_out                - 2x1, estimated flow.
%    time_shifted_points_out - 2xN, input events in the feature window
%                              shifted by the flow [x;y] + dt * flow.
%
% See also GET_PARAMS
%
% Author: Alex Zihao Zhu, University of Pennsylvania
% Email: alexzhu(at)seas.upenn.edu
% Copyright 2018 University of Pennsylvania
% Alex Zihao Zhu, Nikolay Atanasov, Kostas Daniilidis
%
% THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS, CONTRIBUTORS, AND THE
% TRUSTEES OF THE UNIVERSITY OF PENNSYLVANIA "AS IS" AND ANY EXPRESS OR
% IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
% OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
% IN NO EVENT SHALL THE COPYRIGHT OWNER, CONTRIBUTORS OR THE TRUSTEES OF
% THE UNIVERSITY OF PENNSYLVANIA BE LIABLE FOR ANY DIRECT, INDIRECT,
% INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
% NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
% DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
% THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
% (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
% THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

%% Initialization
flow = flow_init;
% Estimated flow
flow_out = [nan; nan];
% Final time shifted events.
time_shifted_points_out = [];
% Store change in flow norm at each iteration for plotting.
delta_flows = zeros(params.em1_params.max_iters, 1);
num_iter = 0;
% Plot handle.
scatter_plot_handle = [];
% Boolean array of size equal to the number of events. Is true if an event
% is in the spatial window of the feature, and thus needs to be processed.
event_window = [];
n_in_window = 0;

target_time = events(3, 1);

% Translate the events so that they are centered at the last position of
% the feature.
centered_events = events;
centered_events(1:2, :) = bsxfun(@minus, events(1:2, :), feature_pos);
prev_flow = flow;

%% Main EM Loop
while true
    if num_iter > params.em1_params.max_iters
        return
    end
    % Shift the centered events in time by the current estimate of the
    % flow.
    time_shifted_points = centered_events(1:2,:) + ...
        bsxfun(@times, flow,(target_time - centered_events(3,:)));

    % Only compute the event window once.
    if isempty(event_window)
        event_window = time_shifted_points(1, :) >= -params.window_size/2 & ...
            time_shifted_points(2, :) >= -params.window_size/2 & ...
            time_shifted_points(1, :) <= params.window_size/2 & ...
            time_shifted_points(2, :) <= params.window_size/2;
        n_in_window = sum(event_window);

        % Don't bother optimizing if there aren't enough events.
        if n_in_window < params.min_events_for_em
            return
        end

        centered_events = centered_events(:, event_window);
        time_shifted_points = time_shifted_points(:, event_window);
        %         params.max_distance = n_in_window / 400;
    end

    % Scale the events so that the computed distances are equal to
    % (x1-x2)/(2*sigma^2). Saves us having to divide all the
    % correspondences later.
    normalized_events = time_shifted_points' / (sqrt(2) * params.em1_params.sigma);

    % The KD tree allows us to compute distances between neighboring
    % events, while also performing outlier rejection. Unfortunately, as
    % the time shifted events change every iteration, it must also be
    % reconstructed at every iteration.
    kdtree = KDTreeSearcher(...
        normalized_events, ...
        'Distance', ...
        'euclidean');

    % Threshold distances by the Malhalanobis distance.
    [neighbors_cell, distances_cell] = rangesearch(...
        kdtree, ...
        normalized_events, ...
        params.em1_params.max_distance);

    distancesstacked = cell2mat(cellfun(...
        @transpose, distances_cell, 'UniformOutput', false))';

    % Can't solve for flow without any correspondences :(
    if isempty(distancesstacked)
        return
    end

    % Number of neighbors for each event.
    % NOTE: 'length' is not the same as @length
    num_neighbors_per_event = cellfun('length', neighbors_cell);

    neighbor_inds = cell2mat(cellfun(...
        @transpose, neighbors_cell, 'UniformOutput', false))';

    event_inds = repelem(1:n_in_window, num_neighbors_per_event);

    % The event to neighbor graph is undirected, so no need to double count
    % the event-neighbor correspondences.
    valid_correspondences = neighbor_inds > event_inds;

    neighbor_inds = neighbor_inds(valid_correspondences);
    event_inds = event_inds(valid_correspondences);
    distancesstacked = distancesstacked(valid_correspondences);

    % Distances are already scaled by the variance. Note that the original
    % equation in the paper is the sum of the product of two weights. Here
    % we simplify it with a single weight for speed.
    weights = exp(-distancesstacked);

    %% Simultaneously minimize over flow and translation.
    neighbor_events = centered_events(:, neighbor_inds);
    original_events = centered_events(:, event_inds);

    % These are the X and D matrices specified in the original paper,
    % except the weighting is handled by multiplying the D with the full
    % weight.
    X = original_events(1:2, :) - neighbor_events(1:2, :);
    D = original_events(3, :)-neighbor_events(3, :);
    weighted_D = bsxfun(@times, D, weights);
    DDT = weighted_D*D';
    XDT = X*weighted_D';

    flow = XDT/DDT;

    %% Calculate change in flow, plot debug information.
    if (norm(flow - prev_flow) < params.em1_params.min_err)
        break;
    end

    delta_flows(num_iter+1) = norm(flow - prev_flow);
    prev_flow = flow;

    if params.debug
        set(0, 'CurrentFigure', fig)
        subplot(2,1,1)
        plot(delta_flows(delta_flows > 0),'b')
        title('EM1 change in flow (convergence criterion)')
        xlim([0 params.em1_params.max_iters])

        subplot(2,1,2)
        if (~isempty(scatter_plot_handle))
            delete(scatter_plot_handle)
        end
        scatter_plot_handle = scatter(...
            time_shifted_points(1, :), ...
            time_shifted_points(2, :), 'r.');

        axis equal
        axis([-params.window_size/2-5 params.window_size/2+5 -params.window_size/2-5 params.window_size/2+5])
        axis ij
        title('EM1 Time shifted events')
        pause(0.01)
    end

    num_iter = num_iter + 1;
end

if params.debug
    pause(0.5)
end

flow_out = flow;

% Calculate the final shifted events to be used in EM2 later.
dt = events(3, end) - events(3, 1);
centered_events = events;
centered_events(1:2, :) = bsxfun(@minus, events(1:2, :), feature_pos + flow * dt);
time_shifted_points = centered_events(1:2, :) + ...
    bsxfun(@times, flow,(events(3, end)-centered_events(3, :)));

% Make the window a little bigger.
window_size = round(params.window_size * 1.5);

event_window = time_shifted_points(1, :) >= -window_size/2 & ...
    time_shifted_points(2, :) >= -window_size/2 & ...
    time_shifted_points(1, :) <= window_size/2 & ...
    time_shifted_points(2, :) <= window_size/2;

time_shifted_points_out = time_shifted_points(:, event_window);
end


%ESTIMATEPOSEBOARD  Pose estimation for a board of markers
%
%     [rvec, tvec, num] = cv.estimatePoseBoard(corners, ids, board, cameraMatrix, distCoeffs)
%     [rvec, tvec, num] = cv.estimatePoseBoard(..., 'OptionName',optionValue, ...)
%
% ## Input
% * __corners__ cell array of already detected markers corners. For each
%   marker, its four corners are provided, (e.g `{{[x,y],..}, ..}`). The order
%   of the corners should be clockwise.
% * __ids__ list of identifiers for each marker in `corners` (0-based).
% * __board__ layout of markers in the board. The layout is composed by the
%   marker identifiers and the positions of each marker corner in the board
%   reference system. You can specify the board as a cell-array that starts
%   with the type name followed by option arguments `{Type, ...}`. There are
%   three types of boards available:
%   * __Board__ `{'Board', objPoints, dictionary, ids}`.
%     Creates a board of markers.
%   * __GridBoard__ `{'GridBoard', markersX, markersY, markerLength, markerSeparation, dictionary, 'FirstMarker',firstMarker}`.
%     Creates a a GridBoard object given the number of markers in each
%     direction and the marker size and marker separation.
%   * __CharucoBoard__ `{'GridBoard', squaresX, squaresY, squareLength, markerLength, dictionary}`.
%     Creates a CharucoBoard object given the number of squares in each
%     direction and the size of the markers and chessboard squares.
% * __cameraMatrix__ input 3x3 floating-point camera matrix
%   `A = [fx 0 cx; 0 fy cy; 0 0 1]`.
% * __distCoeffs__ vector of distortion coefficients
%   `[k1,k2,p1,p2,k3,k4,k5,k6,s1,s2,s3,s4]` of 4, 5, 8 or 12 elements.
%
% ## Output
% * __rvec__ Output vector `[x,y,z]` corresponding to the rotation vector of
%   the board.
% * __tvec__ Output vector `[x,y,z]` corresponding to the translation vector
%   of the board.
% * __num__ The number of markers from the input employed for the board pose
%   estimation. Note that returning a 0 means the pose has not been estimated.
%
% ## Options
% * __Rvec__, __Tvec__ Initial `rvec` and `tvec`. Used as initial guess if not
%   empty. The function uses the provided values as initial approximations of
%   the rotation and translation vectors, respectively, and further optimizes
%   them. Not set by default.
% * __UseExtrinsicGuess__ defines whether initial guess for `rvec` and `tvec`
%   will be used or not. default false.
%
% ## Inputs for Board
% * __objPoints__ array of object points of all the marker corners in the
%   board, i.e. their coordinates with respect to the board system. Each
%   marker include its 4 corners in CCW order
%   `{{[x1,y1,z1],[x2,y2,z2],[x3,y3,z3],[x4,y4,z4]}, ..}`. Usually object
%   points are planar with Z=0.
% * __dictionary__ the dictionary of markers employed for this board. This is
%   specified in the same format described in cv.detectMarkers.
% * __ids__ vector of the identifiers of the markers in the board (same size
%   as `objPoints`). The identifiers refers to the board dictionary (0-based).
%
% ## Inputs for GridBoard
% * __markersX__ number of markers in X direction.
% * __markersY__ number of markers in Y direction.
% * __markerLength__ marker side length (normally in meters).
% * __markerSeparation__ separation between two markers in the grid (same unit
%   as `markerLength`).
% * __dictionary__ dictionary of markers indicating the type of markers. This
%   is specified in the same format described in cv.detectMarkers.
% * __FirstMarker__ optional 0-based id of first marker in dictionary to use
%   on board. default 0
%
% ## Inputs for CharucoBoard
% * __squaresX__ number of chessboard squares in X direction.
% * __squaresY__ number of chessboard squares in Y direction.
% * __squareLength__ chessboard square side length (normally in meters).
% * __markerLength__ marker side length (same unit as `squareLength`)
% * __dictionary__ dictionary of markers indicating the type of markers. The
%   first markers in the dictionary are used to fill the white chessboard
%   squares. This is specified in the same format described in
%   cv.detectMarkers.
%
% The cv.estimatePoseBoard function receives the detected markers and returns
% the pose of a marker board composed by those markers. A board of marker has
% a single world coordinate system which is defined by the board layout. The
% returned transformation is the one that transforms points from the board
% coordinate system to the camera coordinate system. Input markers that are
% not included in the board layout are ignored.
%
% # Board of markers
%
% A board is a set of markers in the 3D space with a common cordinate system.
% The common form of a board of marker is a planar (2D) board, however any 3D
% layout can be used.
%
% # Grid Board
%
% A GridBoard is a special case of planar boards with grid arrangement of
% markers. It is the most common type of board. All markers are placed in the
% same plane in a grid arrangment.
%
% # ChArUco board
%
% Specific class for ChArUco boards. A ChArUco board is a planar board where
% the markers are placed inside the white squares of a chessboard. The
% benefits of ChArUco boards is that they provide both, ArUco markers
% versatility and chessboard corner precision, which is important for
% calibration and pose estimation.
%
% See also: cv.detectMarkers, cv.estimatePoseSingleMarkers, cv.Rodrigues,
%  cv.solvePnP
%


%TESTFEATDOM Test feature domains
%
%	   [N,I,J] = TESTFEATDOM(A,K,M)
%
% The feature domains of the dataset A are tested. When given,
% the vector K should contain the indices of the features to
% be tested. Optionally, a vector M can be given which indicates which
% of the objects should be taken for testing.
%
% N = 0 if the dataset values are within the domains to be tested.
% N = 1 if somewhere a value is outside a domain. I and J return
%       the indices to the erroneous objects and features.
%
%	TESTFEATDOM(A,K,M)
%
% Performs the test and prints an error message if a feature value
% outside a domain is encountered.


function [mvy2,mvx2,mvz2]=expand_motion_field(mvy,mvx,mvz,newdim,offsets)

if length(offsets) == 1
	offsets = [0 0 offsets];
end

mvy2=zeros(newdim,class(mvy));
mvx2 = mvy2;
mvz2 = mvy2;

dim = size(mvy);
ub = dim+offsets;

ys = 1:newdim(1); ys2 = ys-offsets(1); ys2(ys2<1) = 1; ys2(ys2>dim(1)) = dim(1);
xs = 1:newdim(2); xs2 = xs-offsets(2); xs2(xs2<1) = 1; xs2(xs2>dim(2)) = dim(2);
zs = 1:newdim(3); zs2 = zs-offsets(3); zs2(zs2<1) = 1; zs2(zs2>dim(3)) = dim(3);

mvy2(ys,xs,zs) = mvy(ys2,xs2,zs2);
mvx2(ys,xs,zs) = mvx(ys2,xs2,zs2);
mvz2(ys,xs,zs) = mvz(ys2,xs2,zs2);


clear Models MM GA

% User-Specified Parameters
% ===============================================================

% Conditions and stimuli
% ---------------------------------------------------------------
GA.conditions = [1 2 3 4 5];
	% a vector of integers 1:# of event-related conditions (e.g., [1 2 3 4])
	% to add "rest" intervals, add an extra condition and set its contrast weight
	% to zero in all contrasts.
	% e.g., condition 3 in this design could be passive rest.

GA.freqConditions = [.20 .20 .20 .20 .20];
	% vector of frequencies of each trial type; should sum to 1

GA.scanLength = 360;
	% how long your run is, in seconds.
    % This and the ISI determine how many stimuli are in each design vector

GA.ISI = 2;
	% how long between stimulus presentations? (you can also include "rest" presentations)
	% also the time resolution of stimulus condition function (list of stimuli)
	% designs will be constructed in time units of this resolution

GA.TR = 2;
    % the TR (sampling resolution) of your experiment; time for volume acquisition

GA.epochdur = 2;        % build epochs instead of events; enter dur in sec (default is events, 0 sec)

% Hox optimization parameters
% A hox gene is a master gene.  These numbers control the stimulus
% parameters, which can be optimized within the GA rather than
% pre-specified.
% Hox elements in this GA go in the stimlist as the first several elements.
% hox sequence currently codes, in number order:
% ISI TR cuelen cuerest stimlen stimrest resplen resprest (in s)
% the last 6 parameters are for use with doepochs.
% They code epoch lengths for 6 periods within each trial.
% TR does not work right now
% use zeros to use default rather than variable hox parameters
% ---------------------------------------------------------------
GA.numhox = 0;
GA.hoxrange = [];
    % rows are each hox gene's allowable range, cols index hox elements
	% use this if you want to determine the ISI, etc. using the GA
	% also may require significant user input/program modification at this stage.

% Genetic algorithm parameters
% ---------------------------------------------------------------
nmodels = 1;
	% how many runs do you want to optimize?
	% GA runs one separate optimization for each model.

GA.cbalColinPowerWeights = [0 1 0 .3];	% 1 = cbal, 2 = eff, 3 = hrf shape, 4 = freq
	% first element: counterbalancing of stimuli
	% second: contrast detection efficiency
	% third: hrf shape estimation efficiency
	% maintenance of input frequencies for each trial type
	% fitness scores for each measure are multiplied by these values
	% before collapsing to a single, final fitness measure for each design.
	% does not have to sum to 1.

GA.numGenerations = 10;
	% how many iterations of the GA to run.
GA.sizeGenerations = 40;
	% how many designs to test  for each generation?  Population size.
GA.maxTime = 30;
	% max time to run in s, or Inf for infinite time
	% The GA stops when either numGenerations or maxTime is reached.

GA.alph = 2.1;
	% "selection pressure": higher is more extreme selection; always pick the best 50% of designs
	%1 is no selection pressure at all, or random selection of designs for recombination
	% selection pressure is like in evolution; refers to whether the best designs are selected to
	% continue on to the next generation.
	% an intermediate value is best, to keep the population heterogeneity high.

GA.plotFlag = 1;
	% plot results after each run.
	% Recommended to leave this off if nmodels > 1, and then plot your final results later.

% Filtering, counterbalancing, and design tolerance
% ---------------------------------------------------------------
% Empty brackets indicate the option is not to be used.

GA.lowerLimit = [];
GA.HPlength = [120];
	% high-pass filter length, in s, for analysis; [] for no HP filter
	% Used to filter out noise at lower frequencies than design during data analysis
	% The cutoff you should use depends on how much power in your design is below the cutoff -
	% you want all the power in your design to be above the cutoff.

GA.LPsmooth = [];
	% low-pass filter type for analysis; [] for no LP filter
	% choices are 'hrf' or []

GA.maxOrder = 1;
    % order of counterbalancing to use
    % 1 = each trial type follows each other with equal probabilities, adjusted for base frequencies
    % 2 = one-back and two-back counterbalancing.  3 = 1+2+3 back, etc.

% Hard constraints
% ---------------------------------------------------------------
% Here you can specify tolerances for designs
% If designs do not meet these criteria, they will receive -infinity fitness scores
% Empty brackets indicate the option is not to be used.

GA.NumStimthresh = [];      % maximum number of repeats of any one event type in a row
GA.maxCbalDevthresh = []; 	% maximum acceptable counterbalancing deviation (actual freq - expected freq)
GA.maxFreqDevthresh = .2;   % maximum acceptable deviation from input frequencies (GA.freqConditions)

% Contrast setup
% ---------------------------------------------------------------
% Here you specify contrasts across conditions, for use with the contrast estimation fitness measure
% Each contrasts should be a row in the matrix GA.contrasts
%
GA.contrasts = [1 0 0 0 0; ...
                0 1 0 0 0; ...
                0 0 1 0 0; ...
                0 0 0 1 0];
    % there should be one column per condition in your design, not including the intercept.
    %if trans2switch or trans2block = 1, double the number of columns.
    % when using epoch design, three elements per condition for epochs (3 epochs)!
GA.contrastweights = [1 1 1 1];
    % Weighting function for contrasts (rows of GA.contrasts)
    % Contrast efficiencies will be multiplied by these weights before computing overall design fitness
    % If no contrasts are specified, this vector can specify weights for predictors (columns)

% Autocorrelation and special options
% ---------------------------------------------------------------
AutocorrelationFileName = 'myscannerxc';
    % This is the name of a mat file without the .mat extension
    % In the mat file, there should be a variable called myscannerxc
    % which is a row vector containing the autocorrelation fucntion you wish to use.
    % This function is used as the intrinsic noise autocorrelation estimate.
    % Included with the GA scripts are these functions:
    % myscannerxc   (U of M 3T, 7 subjects)
    % hiautocorr    (1/f)
    % hiautocorr3   (another 1/f)
    % noautocorr    (identity; no autocorrelation)

GA.restlength = [];
    % if inserting probe or instruction periods, modeled with periodic rests in the simulation,
    % this is the length of the rest/probe/instr periods to insert, in units of the ISI
GA.restevery = [];
    % This is how many regular events you want to have (in ISIs) between rests.
    % Leave restlength and restevery blank to avoid using these options.
GA.trans2switch = 0;
    % 1 or 0.  This option works if the conditions field is 2 elements long.
    % This option creates new conditions 3 and 4 that occur whenever 1 is followed by 2 or 2 by 1
    % So this option creates trial history-dependent predictors.  1 and 2 are repeats, 3 and 4 are switches
    % Useful when studying habituation, switching between items, etc.
GA.trans2block = 0;
    % 1 or 0.  This option doubles the input length of conditions - so [1 2] is transformed to [1 2 3 4]
    % This option creates alternating ABAB blocks of your input event types (e.g., 1 2) with the new
    % event types (e.g., 3 4).  This is useful when simulating mixed block/event related designs.
    % Trial types 1-2, for example, can be two events within block A, and 3-4 can be the same (or different)
    % events within block B.  The alternation frequency (in ISIs) is specified by GA.restevery.
    % If you use this option, the contrasts field must contain twice as many columns as you have input conditions.
    % for example, if conditions = [1 2 3 4], contrasts = [1 1 1 1 -1 -1 -1 -1] specifies block A vs block B.
    % contrasts = [1 1 1 1 -1 -1 -1 -1; 1 1 -1 -1 1 1 -1 -1] specifies A vs B and events [1 2 5 6] - [3 4 7 8].
GA.dofirst = 0;
    % 1 or 0.  This creates a separate trial type for the first trial following rests in GA.restlength.
    % It only works if you're using trans2switch and trans2block together; unreliable under other circumstances.
GA.nonlinthreshold = [2];
    % If the value here is x, predictor heights are clipped (thresholded) at x times the unit HRF height.
    % If empty, no thresholding is performed.
    % This is useful for modeling nonlinearities in the BOLD signal, which is important if your design uses
    % short ISIs (generally, 2 s or less).  The clipping acts as a 'saturation' factor.
    % I like to use 2, because data in our lab suggests the the nonlinearities in the HRF can be
    % roughly approximated by a clipping function with this parameter value.

% ---------------------------------------------------------------
%
% * E N D   U S E R   I N P U T
%
% ---------------------------------------------------------------
eval(['load ' AutocorrelationFileName]);
GA.xc = myscannerxc;

% =============================================
% * vary by parameter - set this in this script
% * if running multiple models, nmodels > 1
% ---------------------------------------------

varyparam = 0;
fieldname = 'alph';		% or 'freqConditions(end), etc.
incrementby = 0.3;
incrementevery = 5;		% every n models
contrastsofinterest = 1;% contrasts or predictors, if no cons specified

% =============================================

if varyparam
	eval(['paramvalue = GA.' fieldname ';'])
	disp(' ');disp('* *********************************************************************')
	disp('*  You have selected to vary a parameter across models in ga_gui_script')
	disp(['*  GA.' fieldname ' starting at ' num2str(paramvalue)])
	disp('* *********************************************************************')
end

for nm = 1:nmodels

   eval(['diary model' num2str(nm) '.log'])
   disp(['Starting Model ' num2str(nm)])
    % freqConditions

   M = optimizeGA(GA);

   Models(:,nm) = M.stimlist;
   MM{nm} = M;
   save GAworkspace

   if varyparam
   	if isfield(M,'consebeta'),
		Fit(1,nm) = mean(M.consebeta(contrastsofinterest));
	else
		Fit(1,nm) = mean(M.sebeta(contrastsofinterest));
	end
   	eval(['Fit(2,nm) = GA.' fieldname ';'])
   	FC(nm,:) = GA.freqConditions;
   	ALPH(nm,:) = GA.alph;
	str = ['if mod(nm,' num2str(incrementevery) ') == 0,GA.' fieldname ' = GA.' fieldname '+' num2str(incrementby) ';,end']
   	eval(str);
	eval(['paramvalue = GA.' fieldname ';'])
	disp('* *********************************************************************')
	disp('*  Varying parameter option on.')
	disp(['*  GA.' fieldname ' is now ' num2str(paramvalue)])
	disp('* *********************************************************************')
   end

   eval(['save model' num2str(nm) '_' M.date ' M'])
   save GAworkspace
   diary off
   fprintf('\n')
end


function [newnode,newelem,newelem0]=surfboolean(node,elem,varargin)
%
% [newnode,newelem,newelem0]=surfboolean(node1,elem1,op2,node2,elem2,op3,node3,elem3,...)
%
% merge two or more triangular meshes and resolve intersecting elements
%
% author: Qianqian Fang <fangq at nmr.mgh.harvard.edu>
%
% input:
%      node: node coordinates, dimension (nn,3)
%      elem: tetrahedral element or triangle surface (ne,3)
%      op:  a string of a boolean operator, possible op values include
%           'union' or 'or': the outter surface of the union of the enclosed space
%           'inter' or 'and': the surface of the domain contained by both meshes
%           'diff' or '-': the surface of the domain in mesh 1 excluding that of
%                   mesh 2
%           'all' or 'xor' or '+': the output contains 4 subsurfaces, identified by the 4th
%                  column of newelem:
%                    1: mesh 1 outside of mesh 2
%                    2: mesh 2 outside of mesh 1
%                    3: mesh 1 inside of mesh 2
%                    4: mesh 2 inside of mesh 1
%                  you can use newelem(find(mod(newelem(:,4),2)==1),:) to
%                  get mesh 1 cut by mesh 2, or newelem(find(mod(newelem(:,4),2)==0),:)
%                  to get mesh 2 cut by mesh 1;
%           'first': combine 1 and 3 from the output of 'all'
%           'second': combine 2 and 4 from the output of 'all'
%           'self': test for self-intersections; only the first mesh is
%                   tested; other inputs are ignored.
%           'decouple': separate two shells and make sure there is no intersection;
%                   the input surfaces must be closed and ordered from outer to inner
%
% output:
%      newnode: the node coordinates after boolean operations, dimension (nn,3)
%      newelem: tetrahedral element or surfaces after boolean operations (nn,4) or (nhn,5)
%      newelem0: when the operator is 'self', return the intersecting
%               element list in terms of the input node list (experimental)
%
% example:
%
%   [node1,face1,elem1]=meshabox([0 0 0],[10 10 10],1,1);
%   [node2,face2,elem2]=meshabox([0 0 0]+5,[10 10 10]+5,1,1);
%   [newnode,newface]=surfboolean(node1,face1,'union',node2,face2);
%   plotmesh(newnode,newface);
%   figure;
%   [newnode,newface]=surfboolean(node1,face1,'diff',node2,face2);
%   plotmesh(newnode,newface,'x>5');
%
% -- this function is part of iso2mesh toolbox (http://iso2mesh.sf.net)
%

allinputs=varargin;
opt=struct;
if(length(allinputs)>0 && isstruct(allinputs{end}))
    opt=allinputs{end};
    allinputs{end}=[];
end
len=length(varargin);
newnode=node;
newelem=elem;
if(len>0 && mod(len,3)~=0)
   error('you must give operator, node and element in trilet forms');
end

exesuff=fallbackexeext(getexeext,'gtsset');

for i=1:3:len
   op=varargin{i};
   no=varargin{i+1};
   el=varargin{i+2};
   opstr=op;
   if(strcmp(op,'or'))   opstr='union'; end
   if(strcmp(op,'xor'))  opstr='all';   end
   if(strcmp(op,'and'))  opstr='inter'; end
   if(strcmp(op,'-'))    opstr='diff';  end
   if(strcmp(op,'self')) opstr='inter -s';  end
   if(strcmp(op,'first') || strcmp(op,'second') || strcmp(op,'+'))
       opstr='all';
   end

   deletemeshfile(mwpath('pre_surfbool*.gts'));
   deletemeshfile(mwpath('post_surfbool.off'));
   if(strcmp(opstr,'all'))
      deletemeshfile(mwpath('s1out2.off'));
      deletemeshfile(mwpath('s1in2.off'));
      deletemeshfile(mwpath('s2out1.off'));
      deletemeshfile(mwpath('s2in1.off'));
   end
   if(strcmp(op,'decouple'))
       if(exist('node1','var')==0)
          node1=node;
          elem1=elem;
          newnode(:,4)=1;
          newelem(:,4)=1;
       end
       opstr=['-q --shells 2'];
       saveoff(node1(:,1:3),elem1(:,1:3),mwpath('pre_decouple1.off'));
       if(isstruct(el))
           if(isfield(el,'MoreOptions'))
               opstr=[opstr el.MoreOptions];
           end
       else
           opstr=[opstr ' --decouple-inin 1'];
       end
       if(size(no,2)~=3)
           opstr=['-q --shells ' num2str(no)];
           cmd=sprintf('cd "%s" && "%s%s" "%s" %s',mwpath,mcpath('meshfix'),exesuff,...
               mwpath('pre_decouple1.off'),opstr);
       else
           saveoff(no(:,1:3),el(:,1:3),mwpath('pre_decouple2.off'));
           cmd=sprintf('cd "%s" && "%s%s" "%s" "%s" %s',mwpath,mcpath('meshfix'),exesuff,...
               mwpath('pre_decouple1.off'),mwpath('pre_decouple2.off'),opstr);
       end
   else
       savegts(newnode(:,1:3),newelem(:,1:3),mwpath('pre_surfbool1.gts'));
       savegts(no(:,1:3),el(:,1:3),mwpath('pre_surfbool2.gts'));
       cmd=sprintf('cd "%s" && "%s%s" %s "%s" "%s" -v > "%s"',mwpath,mcpath('gtsset'),exesuff,...
           opstr,mwpath('pre_surfbool1.gts'),mwpath('pre_surfbool2.gts'),mwpath('post_surfbool.off'));
   end
   [status outstr]=system(cmd);
   if(status~=0 && strcmp(op,'self')==0)
       error(sprintf('surface boolean command failed:\n%s\nERROR: %s\n',cmd,outstr));
   end
   if(status~=0 && strcmp(op,'self') && ~isempty(strfind(outstr,'(new_ear): assertion failed')))
       fprintf(1,'no self-intersection was found! (ignore the above error)\n');
       newnode=[];
       newelem=[];
       newelem0=[];
       return;
   end
   if(strcmp(opstr,'all'))
      % tag the 4 piceses of meshes, this tag do not propagate to the next boolean operation
      [nnode nelem]=readoff(mwpath('s1out2.off'));
      newelem=[nelem ones(size(nelem,1),1)];
      newnode=[nnode ones(size(nnode,1),1)];

      [nnode nelem]=readoff(mwpath('s1in2.off'));
      newelem=[newelem; nelem+size(newnode,1) 3*ones(size(nelem,1),1)];
      newnode=[newnode; nnode 3*ones(size(nnode,1),1)];

      [nnode nelem]=readoff(mwpath('s2out1.off'));
      newelem=[newelem; nelem+size(newnode,1) 2*ones(size(nelem,1),1)];
      newnode=[newnode; nnode 2*ones(size(nnode,1),1)];

      [nnode nelem]=readoff(mwpath('s2in1.off'));
      newelem=[newelem; nelem+size(newnode,1) 4*ones(size(nelem,1),1)];
      newnode=[newnode; nnode 4*ones(size(nnode,1),1)];

      if(strcmp(op,'first'))
          newelem=newelem(find(mod(newelem(:,4),2)==1),:);
          [newnode,nelem]=removeisolatednode(newnode,newelem(:,1:3));
          newelem=[nelem newelem(:,4)];
      elseif(strcmp(op,'second'))
          newelem=newelem(find(mod(newelem(:,4),2)==0),:);
          [newnode,nelem]=removeisolatednode(newnode,newelem(:,1:3));
          newelem=[nelem,newelem(:,4)];
      end
   elseif(strcmp(op,'decouple'))
      [node1,elem1]=readoff(mwpath('pre_decouple1_fixed.off'));
      newelem=[newelem;elem1+size(newnode,1) (i+1)*ones(size(elem1,1),1)];
      newnode=[newnode;node1 (i+1)*ones(size(node1,1),1)];
   else
      [newnode,newelem]=readoff(mwpath('post_surfbool.off'));
      if(strcmp(op,'self'))
          fprintf(1,'a total of %d self-intersecting elements were found\n',size(newelem,1));
          if(nargout>=3)
              [found,newelem0]=ismember(newnode,node,'rows');
              if(~all(found))
                  error('self intersecting elements contain new nodes');
              end
              newelem0=newelem0(newelem);
          end
          return;
      end
   end
end


classdef(Abstract) AbstractGeometricVectorConstraint < AbstractConstraint
    %AbstractGeometricVectorConstraint Summary of this class goes here
    %   Detailed explanation goes here

    properties
        normFact = 1;
        vector AbstractGeometricVector
        event LaunchVehicleEvent
        eventNode(1,1) ConstraintStateComparisonNodeEnum = ConstraintStateComparisonNodeEnum.FinalState;

        lb(1,1) double = 0;
        ub(1,1) double = 0;

        type(1,:) char

        evalType(1,1) ConstraintEvalTypeEnum = ConstraintEvalTypeEnum.FixedBounds;
        stateCompType(1,1) ConstraintStateComparisonTypeEnum = ConstraintStateComparisonTypeEnum.Equals;
        stateCompEvent LaunchVehicleEvent
        stateCompNode(1,1) ConstraintStateComparisonNodeEnum = ConstraintStateComparisonNodeEnum.FinalState;
    end

    methods
        function [lb, ub] = getBounds(obj)
            lb = obj.lb;
            ub = obj.ub;
        end

        function [c, ceq, value, lwrBnd, uprBnd, type, eventNum, valueStateComp] = evalConstraint(obj, stateLog, celBodyData)
            type = obj.getConstraintType();

            switch obj.eventNode
                case ConstraintStateComparisonNodeEnum.FinalState
                    stateLogEntry = stateLog.getLastStateLogForEvent(obj.event);

                case ConstraintStateComparisonNodeEnum.InitialState
                    stateLogEntry = stateLog.getFirstStateLogForEvent(obj.event);

                otherwise
                    error('Unknown event node.');
            end

            if(not(isempty(obj.frame)))
                frame = obj.frame;
            else
                frame = stateLogEntry.centralBody.getBodyCenteredInertialFrame();
            end

            value = lvd_GeometricVectorTasks(stateLogEntry, obj.type, obj.vector, frame);

            if(obj.evalType == ConstraintEvalTypeEnum.StateComparison)
                switch obj.stateCompNode
                    case ConstraintStateComparisonNodeEnum.FinalState
                        stateLogEntryStateComp = stateLog.getLastStateLogForEvent(obj.stateCompEvent);

                    case ConstraintStateComparisonNodeEnum.InitialState
                        stateLogEntryStateComp = stateLog.getFirstStateLogForEvent(obj.stateCompEvent);

                    otherwise
                        error('Unknown event node.');
                end

                valueStateComp = lvd_GeometricVectorTasks(stateLogEntryStateComp, obj.type, obj.vector, frame);
            else
                valueStateComp = NaN;
            end

            [c, ceq] = obj.computeCAndCeqValues(value, valueStateComp);

            lwrBnd = obj.lb;
            uprBnd = obj.ub;

            eventNum = obj.event.getEventNum();
        end

        function sF = getScaleFactor(obj)
            sF = obj.normFact;
        end

        function setScaleFactor(obj, sF)
            obj.normFact = sF;
        end

        function tf = usesStage(obj, stage)
            tf = false;
        end

        function tf = usesEngine(obj, engine)
            tf = false;
        end

        function tf = usesTank(obj, tank)
            tf = false;
        end

        function tf = usesEngineToTankConn(obj, engineToTank)
            tf = false;
        end

        function tf = usesEvent(obj, event)
            tf = obj.event == event;
            if(obj.evalType == ConstraintEvalTypeEnum.StateComparison)
                tf = tf || obj.stateCompEvent == event;
            end
        end

        function tf = usesStopwatch(~, ~)
            tf = false;
        end

        function tf = usesExtremum(~, ~)
            tf = false;
        end

        function tf = usesGroundObj(~, ~)
            tf = false;
        end

        function tf = usesGeometricVector(obj, vector)
            tf = obj.vector == vector;
        end

        function tf = canUseSparseOutput(obj)
            tf = true;
        end

        function event = getConstraintEvent(obj)
            event = obj.event;
        end

        function [unit, lbLim, ubLim, usesLbUb, usesCelBody, usesRefSc] = getConstraintStaticDetails(obj)
            unit = '';
            lbLim = 0;
            ubLim = Inf;
            usesLbUb = true;
            usesCelBody = false;
            usesRefSc = false;
        end

        function addConstraintTf = openEditConstraintUI(obj, lvdData)
            if(lvdData.geometry.vectors.getNumVectors() >= 1)
%                 addConstraintTf = lvd_EditGeometricVectorConstraintGUI(obj, lvdData);

                output = AppDesignerGUIOutput({false});
                lvd_EditGeometricVectorConstraintGUI_App(obj, lvdData, output);
                addConstraintTf = output.output{1};
            else
                errordlg('There are currently no geometric vectors in this scenario.  Add at least one new vector first.');

                addConstraintTf = false;
            end
        end

        function vector = selectConstraintObj(obj, lvdData)
            [listBoxStr, vectors] = lvdData.geometry.vectors.getListboxStr();

            vector = [];
            if(isempty(vectors))
                warndlg('Cannot create vector value object: no vectors have been created.  Create a vector first.','Vector Value Constraint','modal');
            else
                [Selection,ok] = listdlg('PromptString',{'Select a vector:'},...
                                'SelectionMode','single',...
                                'Name','Vectors',...
                                'ListString',listBoxStr);

                if(ok == 0)
                    vector = [];
                else
                    vector = vectors(Selection);
                end
            end
        end

        function useObjFcn = setupForUseAsObjectiveFcn(obj,lvdData)
            vectorSel = obj.selectConstraintObj(lvdData);

            if(not(isempty(vectorSel)))
                obj.vector = vectorSel;
                useObjFcn = true;
            else
                useObjFcn = false;
            end
        end
    end
end


function [proj_lg, BHCalib] = BHCorrection(datafolder, geo, ScanXML, proj_lg,gpuids)
% Entry Function For BH Correction
%   Detailed explanation goes here

disp('BH correction is very memory intensive. The effect is to be justified. ');
typein = input('Continue BH correction? Y or N (recommended): ', 's');
if(contains(typein, 'n', 'IgnoreCase', true))
    BHCalib = NaN;
    disp('BH correction is skipped.');
    return;
end

disp('Beam Hardening Correction is on-going: be patient... ');

% Key calibration information
BHCalib = BHCalibFromXML(datafolder, ScanXML);

% Precompute filter attenuated spectrum: debug pass
BHCalib = BH_SpectrumFilter(BHCalib);

% Precompute bowtie attenuated spectra LUT
BHCalib = BH_SpectrumBowtieLUT(geo, BHCalib);

% Build reference object (water) attanuation LUT
BHCalib = BH_ObjectCalibLUT(BHCalib);

% BH correction via reference object (water)
BHCalib = BH_RemappingFunc(BHCalib);

proj_lg = BH_ObjectRemapping(BHCalib, proj_lg, gpuids);

disp('BH correction is done.')

end


function outsig=operator(Op,insig);
%OPERATOR  Apply operator
%   Usage: c=operator(Op,f);
%
%   `c=operator(Op,f)` applies the operator *Op* to the input signal *f*.
%   The operator object *Op* must have been created using |operatornew|.
%
%   If *f* is a matrix, the transform will be applied along the columns
%   of *f*. If *f* is an N-D array, the transform will be applied along
%   the first non-singleton dimension.
%
%   See also: operatornew, ioperator, operatoradj

if nargin<2
  error('%s: Too few input parameters.',upper(mfilename));
end;

if ~isstruct(Op)
  error('%s: First agument must be a operator definition structure.',upper(mfilename));
end;

switch(Op.type)
  case 'framemul'
    outsig=framemul(insig,Op.Fa,Op.Fs,Op.s);
  case 'spread'
    outsig=spreadop(insig,Op.s);
end;