function mne_write_inverse_sol_w(stem,inv,sol)
%
% function mne_write_inverse_sol_w(stem,inv,sol)
%
% Save static inverse solution data into stc files
%
% stem      - Stem for the w files
% inv       - The inverse operator structure (can be the forward operator as well)
% sol       - The solution matrix (number of locations)
%

%
%
%   Author : Matti Hamalainen, MGH Martinos Center
%   License : BSD 3-clause
%
%   Revision 1.2  2009/03/04 22:04:31  msh
%   Fixed typos in comments
%
%   Revision 1.1  2009/03/04 03:50:15  msh
%   Added mne_write_inverse_sol_w
%
%   Revision 1.2  2006/09/14 22:12:48  msh
%   Added output of the files written.
%
%   Revision 1.1  2006/05/05 03:50:40  msh
%   Added routines to compute L2-norm inverse solutions.
%   Added mne_write_inverse_sol_stc to write them in stc files
%   Several bug fixes in other files
%
%

me='MNE:mne_write_inverse_sol_w';
global FIFF;
if isempty(FIFF)
   FIFF = fiff_define_constants();
end

if nargin ~= 3
    error(me,'Incorrect number of arguments');
end

if length(sol) ~= inv.nsource
    error(me,'The solution data cannot correspond to these source spaces');
end

off = 0;
for k = 1:length(inv.src)
    off = off + inv.src(k).nuse;
    if (inv.src(k).id ~= FIFF.FIFFV_MNE_SURF_LEFT_HEMI && ...
            inv.src(k).id ~= FIFF.FIFFV_MNE_SURF_RIGHT_HEMI)
        error(me,'Source space hemispheres not properly assigned.');
    end
end
if off ~= inv.nsource
    error(me,'The source spaces are inconsistent with other inverse/forward operator data');
end
%
%   Write a separate stc file for each source space
%
off = 0;
for k = 1:length(inv.src)
    if (inv.src(k).id == FIFF.FIFFV_MNE_SURF_LEFT_HEMI)
        outname = sprintf('%s-lh.w',stem);
    elseif (inv.src(k).id == FIFF.FIFFV_MNE_SURF_RIGHT_HEMI)
        outname = sprintf('%s-rh.w',stem);
    end
    w.vertices = double(inv.src(k).vertno - 1);
    w.data     = sol(off+1:off+inv.src(k).nuse);
    mne_write_w_file(outname,w);
    off = off + inv.src(k).nuse;
    fprintf(1,'Wrote %s\n',outname);
end

return;


function pos=readsnx(sta_name,fname)

k=0; pos=zeros(1,3);
fid=fopen(fname);
while ~feof(fid)
    line = fgetl(fid);
    [tmp,line]=strtok(line);%#ok
    if strcmp(tmp,'+SOLUTION/APRIORI')
        while 1
            line = fgetl(fid);
            [tmp1,line]=strtok(line);%#ok
            [tmp2,line]=strtok(line);%#ok
            [tmp3,line]=strtok(line);%#ok
            if strcmp(tmp3,sta_name)
                [tmp,line]=strtok(line);%#ok
                [tmp,line]=strtok(line);%#ok
                [tmp,line]=strtok(line);%#ok
                [tmp,line]=strtok(line);%#ok
                [tmp,line]=strtok(line);%#ok
                [tmp,line]=strtok(line);%#ok
                pos(k+1)=str2num(tmp);%#ok
                k=k+1;
            end
            if (strcmp(tmp2,'STAZ') && strcmp(tmp3,sta_name)) || strcmp(tmp1,'-SOLUTION/APRIORI')
                break;
            end
        end
        break;
    end
end
fclose(fid);

return


function bnd = prepare_mesh_manual(cfg, mri)

% PREPARE_MESH_MANUAL is called by PREPARE_MESH and opens a GUI to manually
% select points/polygons in an mri dataset.
%
% It allows:
%   Visualization of 3d data in 3 different projections
%   Adjustment of brightness for every slice
%   Storage of the data points in an external .mat file
%   Retrieval of previously saved data points
%   Slice fast scrolling with keyboard arrows
%   Polygons or points selection/deselection
%
% See also PREPARE_MESH_SEGMENTATION, PREPARE_MESH_HEADSHAPE

% Copyrights (C) 2009, Cristiano Micheli & 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/>.
%
% $Id$

% FIXME: control slice's cmap referred to abs values
% FIXME: clean structure slicedata
% FIXME: check function assign3dpoints

global obj

mri = ft_checkdata(mri, 'datatype', {'volume', 'segmentation'});

hasheadshape = isfield(cfg, 'headshape');
hasbnd       = isfield(cfg, 'bnd');  % FIXME why is this in cfg?
hasmri       = nargin>1;

% check the consistency of the input arguments
if hasheadshape && hasbnd
  ft_error('you should not specify cfg.headshape and cfg.bnd simultaneously');
end

% check the consistency of the input arguments
if ~hasmri
  % FIXME give a warning or so?
  mri.anatomy = [];
  mri.transform = eye(4);
else
  % ensure that it is double precision
  mri.anatomy = double(mri.anatomy);
end

% start with an empty boundary
bnd.pnt = [];
bnd.tri = [];

if hasheadshape
  if ~isempty(cfg.headshape)
    % start with the headshape
    [bnd.pos, bnd.tri] = headsurface([], [], 'headshape', cfg.headshape);
  end
elseif hasbnd
  if ~isempty(cfg.bnd)
    % start with the prespecified boundaries
    bnd = cfg.bnd;
  end
end

% creating the GUI
fig = figure;

% initialize some values
slicedata = []; points = bnd.pnt;
axs = floor(size(mri.anatomy,1)/2);

% initialize properties
set(fig, 'KeyPressFcn',@keypress);
set(fig, 'CloseRequestFcn', @cb_close);
setappdata(fig,'data',mri.anatomy);
setappdata(fig,'prop',{1,axs,0,[]});
setappdata(fig,'slicedata',slicedata);
setappdata(fig,'points',points);
setappdata(fig,'box',[]);

% add GUI elements
cb_creategui(gca);
cb_redraw(gca);
waitfor(fig);

% close sequence
global pnt
try
  tmp = pnt;
  clear global pnt
  pnt = tmp;
  clear tmp
  [tri] = projecttri(pnt);
  bnd.pnt = pnt;
  bnd.tri = tri;
catch
  bnd.pnt = [];
  bnd.tri = [];
end

function cb_redraw(hObject, eventdata, handles)
fig  = get(hObject, 'parent');
prop = getappdata(fig,'prop');
data = getappdata(fig,'data');
slicedata = getappdata(fig,'slicedata');
points = getappdata(fig,'points');

% draw image
try
  cla
  % i,j,k axes
  if (prop{1}==1) %jk
    imh=imagesc(squeeze(data(prop{2},:,:)));
    xlabel('k');
    ylabel('j');
    colormap bone
  elseif (prop{1}==2) %ik
    imh=imagesc(squeeze(data(:,prop{2},:)));
    xlabel('k');
    ylabel('i');
    colormap bone
  elseif (prop{1}==3) %ij
    imh=imagesc(squeeze(data(:,:,prop{2})));
    xlabel('j');
    ylabel('i');
    colormap bone
  end
  axis equal; axis tight
  brighten(prop{3});
  title([ 'slice ' num2str(prop{2}) ])
catch
end
if ~ishold,hold on,end
% draw points and lines
for zz = 1:length(slicedata)
  if(slicedata(zz).proj==prop{1})
    if(slicedata(zz).slice==prop{2})
      polygon = slicedata(zz).polygon;
      for kk=1:length(polygon)
        if ~isempty(polygon{kk})
          [xs,ys]=deal(polygon{kk}(:,1),polygon{kk}(:,2));
          plot(xs, ys, 'g.-');
        end
      end
    end
  end
end % end for

% draw other slices points
points = getappdata(fig,'points');
pnts   = round(points);
if ~isempty(pnts)
  % exclude polygons inside the same slice
  indx  = find(points(:,prop{1})==prop{2});
  tmp   = ones(1,size(points,1));
  tmp(indx)  = 0;
  pnts  = points(find(tmp),:);
  % calculate indexes of other proj falling in current slice
  indx2 = find(round(pnts(:,prop{1}))==prop{2});
  rest  = setdiff([1 2 3],prop{1});
  % plot the points
  for jj=1:length(indx2)
    [x,y] = deal(pnts(indx2(jj),rest(1)),pnts(indx2(jj),rest(2)));
    plot(y,x,'g*')
  end
end

% add blue cross markers in case of box selection
box        = getappdata(fig,'box');
point2mark = getappdata(fig,'point2mark');

if ~isempty(point2mark)
  plot(point2mark.x,point2mark.y,'marker','+')
end

if ~isempty(box)
  for kk=1:size(box,1)
    proj   = box(kk,1);
    slice  = box(kk,2);
    rowmin = box(kk,3);
    rowmax = box(kk,4);
    colmin = box(kk,5);
    colmax = box(kk,6);
    aaa = get(findobj(fig, 'color', 'g'));
    for ii=1:length(aaa)
      if ispolygon(aaa(ii))
        L = length(aaa(ii).YData);
        for jj=1:L
          cond = lt(aaa(ii).YData(jj),rowmax).*gt(aaa(ii).YData(jj),rowmin).* ...
            lt(aaa(ii).XData(jj),colmax).*gt(aaa(ii).XData(jj),colmin);
          if cond
            plot(aaa(ii).XData(jj),aaa(ii).YData(jj),'marker','+')
          end
        end
      elseif ispoint(aaa(ii))
        cond = lt(aaa(ii).YData,rowmax).*gt(aaa(ii).YData,rowmin).* ...
          lt(aaa(ii).XData,colmax).*gt(aaa(ii).XData,colmin);
        % the test after cond takes care the box doesnt propagate in 3D
        if (cond && (proj == prop{1}) && (slice == prop{2}))
          plot(aaa(ii).XData,aaa(ii).YData,'marker','+')
        end
      end
    end
  end
end

if get(findobj(fig, 'tag', 'toggle axes'), 'value')
  axis on
else
  axis off
end

function cb_creategui(hObject, eventdata, handles)

fig = get(hObject, 'parent');
% define the position of each GUI element
% constants
CONTROL_WIDTH  = 0.10;
CONTROL_HEIGHT = 0.075;
CONTROL_HOFFSET = 0.8;
CONTROL_VOFFSET = 0.6;

% control buttons
uicontrol('tag', 'view', 'parent', fig, 'units', 'normalized', 'style', 'radiobutton', 'string', 'View', 'value', 1, 'callback', @which_task1);
ft_uilayout(fig, 'tag', 'view',  'BackgroundColor', [0.8 0.8 0.8], 'width', 2*CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'vpos', CONTROL_VOFFSET+4*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);

uicontrol('tag', 'ins', 'parent', fig, 'units', 'normalized', 'style', 'radiobutton', 'string', 'Ins', 'value', 0, 'callback', @which_task2);
ft_uilayout(fig, 'tag', 'ins',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'vpos', CONTROL_VOFFSET+2.75*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);
uicontrol('tag', 'del', 'parent', fig, 'units', 'normalized', 'style', 'radiobutton', 'string', 'Del', 'value', 0, 'callback', @which_task3);
ft_uilayout(fig, 'tag', 'del',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'vpos', CONTROL_VOFFSET+2.75*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET+CONTROL_WIDTH);

uicontrol('tag', 'slice', 'parent', fig, 'units', 'normalized', 'style', 'text', 'string', 'slice', 'value', [], 'callback', []);
ft_uilayout(fig, 'tag', 'slice',  'BackgroundColor', [0.8 0.8 0.8], 'width', 2*CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'vpos', CONTROL_VOFFSET+1.25*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);
uicontrol('tag', 'min', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', '<', 'value', [], 'callback', @cb_btn);
ft_uilayout(fig, 'tag', 'min',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET+1*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);
uicontrol('tag', 'max', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', '>', 'value', [], 'callback', @cb_btn);
ft_uilayout(fig, 'tag', 'max',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET+1*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET+CONTROL_WIDTH);

uicontrol('tag', 'brightness', 'parent', fig, 'units', 'normalized', 'style', 'text', 'string', 'brightness', 'value', [], 'callback', []);
ft_uilayout(fig, 'tag', 'brightness',  'BackgroundColor', [0.8 0.8 0.8], 'width', 2*CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'vpos', CONTROL_VOFFSET-0.75*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);
uicontrol('tag', 'plus', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', '+', 'value', [], 'callback', @cb_btn);
ft_uilayout(fig, 'tag', 'plus',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-1*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);
uicontrol('tag', 'minus', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', '-', 'value', [], 'callback', @cb_btn);
ft_uilayout(fig, 'tag', 'minus',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-1*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET+CONTROL_WIDTH);

uicontrol('tag', 'toggle axes', 'parent', fig, 'units', 'normalized', 'style', 'checkbox', 'string', 'axes', 'value', 0, 'callback', @cb_redraw);
ft_uilayout(fig, 'tag', 'toggle axes',  'BackgroundColor', [0.8 0.8 0.8], 'width', 2*CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'vpos', CONTROL_VOFFSET-2.5*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);

uicontrol('tag', 'plane', 'parent', fig, 'units', 'normalized', 'style', 'text', 'string', 'plane', 'value', [], 'callback', []);
ft_uilayout(fig, 'tag', 'plane',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-3.5*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);
uicontrol('tag', 'one', 'parent', fig, 'units', 'normalized', 'style', 'radiobutton', 'string', 'jk', 'value', 0, 'callback', @cb_btnp1);
ft_uilayout(fig, 'tag', 'one',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-3.5*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET+CONTROL_WIDTH);
uicontrol('tag', 'two', 'parent', fig, 'units', 'normalized', 'style', 'radiobutton', 'string', 'ik', 'value', 0, 'callback', @cb_btnp2);
ft_uilayout(fig, 'tag', 'two',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-4*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);
uicontrol('tag', 'three', 'parent', fig, 'units', 'normalized', 'style', 'radiobutton', 'string', 'ij', 'value', 0, 'callback', @cb_btnp3);
ft_uilayout(fig, 'tag', 'three',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-4*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET+CONTROL_WIDTH);

uicontrol('tag', 'mesh', 'parent', fig, 'units', 'normalized', 'style', 'text', 'string', 'mesh', 'value', [], 'callback', []);
ft_uilayout(fig, 'tag', 'mesh',  'BackgroundColor', [0.8 0.8 0.8], 'width', 2*CONTROL_WIDTH, 'height', CONTROL_HEIGHT, 'vpos', CONTROL_VOFFSET-5.75*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);

uicontrol('tag', 'smoothm', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'smooth', 'value', [], 'callback', @smooth_mesh);
ft_uilayout(fig, 'tag', 'smoothm',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-6*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);
uicontrol('tag', 'viewm', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'view', 'value', [], 'callback', @view_mesh);
ft_uilayout(fig, 'tag', 'viewm',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-6*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET+CONTROL_WIDTH);

uicontrol('tag', 'cancel', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'cancel', 'value', [], 'callback', @cancel_mesh);
ft_uilayout(fig, 'tag', 'cancel',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-6.5*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET);
uicontrol('tag', 'ok', 'parent', fig, 'units', 'normalized', 'style', 'pushbutton', 'string', 'ok', 'value', [], 'callback', @cb_btn);
ft_uilayout(fig, 'tag', 'ok',  'BackgroundColor', [0.8 0.8 0.8], 'width', CONTROL_WIDTH, 'height', CONTROL_HEIGHT/2, 'vpos', CONTROL_VOFFSET-6.5*CONTROL_HEIGHT, 'hpos', CONTROL_HOFFSET+CONTROL_WIDTH);

function cb_btn(hObject, eventdata, handles)
fig  = get(gca, 'parent');
prop = getappdata(fig,'prop');
slice = prop{2};
br    = prop{3};
datdim = size(getappdata(fig,'data'));
% p1 = [];p2 = [];p3 = [];
p1  = get(findobj('string','jk'),'value');
p2  = get(findobj('string','ik'),'value');
p3  = get(findobj('string','ij'),'value');
set(findobj('string','-'),'Value',prop{3});
set(findobj('string','+'),'Value',prop{3});
beta = get(findobj('string','-'),'Value');

if (p1)     %jk
  setappdata(fig,'prop',{1,round(datdim(1)/2),br,prop{4}});
  cb_redraw(gca);
elseif (p2) %ik
  setappdata(fig,'prop',{2,round(datdim(2)/2),br,prop{4}});
  cb_redraw(gca);
elseif (p3) %ij
  setappdata(fig,'prop',{3,round(datdim(3)/2),br,prop{4}});
  cb_redraw(gca);
end
if strcmp(get(hObject,'string'),'-')
  beta=beta-0.05;
  set(findobj('string','-'),'Value',beta);
  set(findobj('string','+'),'Value',beta);
  setappdata(fig,'prop',{prop{1},prop{2},beta,prop{4}});
  cb_redraw(gca);
elseif strcmp(get(hObject,'string'),'+')
  beta=beta+0.05;
  set(findobj('string','+'),'Value',beta);
  setappdata(fig,'prop',{prop{1},prop{2},beta,prop{4}});
  cb_redraw(gca);
end

if strcmp(get(hObject,'string'),'<')
  setappdata(fig,'prop',{prop{1},slice-1,0,prop{4}});
  cb_redraw(gca);
end
if strcmp(get(hObject,'string'),'>')
  setappdata(fig,'prop',{prop{1},slice+1,0,prop{4}});
  cb_redraw(gca);
end
if strcmp(get(hObject,'string'),'OK')
  close(fig)
end

function keypress(h, eventdata, handles, varargin)
fig   = get(gca, 'parent');
prop  = getappdata(fig,'prop');
dat   = guidata(gcbf);
key   = get(gcbf, 'CurrentCharacter');
slice = prop{2};
if  key
  switch key
    case 28
      setappdata(fig,'prop',{prop{1},slice-1,0,prop{4}});
      cb_redraw(gca);
    case 29
      setappdata(fig,'prop',{prop{1},slice+1,0,prop{4}});
      cb_redraw(gca);
    otherwise
  end
end
uiresume(h)

function build_polygon
fig   = get(gca, 'parent');
prop  = getappdata(fig,'prop');
data  = getappdata(fig,'data');
ss = size(data);
proj  = prop{1};
slice = prop{2};
thispolygon =1;
polygon{thispolygon} = zeros(0,2);
maskhelp = [ ...
  '------------------------------------------------------------------------\n' ...
  'specify polygons for masking the topographic interpolation\n' ...
  'press the right mouse button to add another point to the current polygon\n' ...
  'press backspace on the keyboard to remove the last point\n' ...
  'press "c" on the keyboard to close this polygon and start with another\n' ...
  'press "q" or ESC on the keyboard to continue\n' ...
  ];
again = 1;
if ~ishold,hold,end
fprintf(maskhelp);
fprintf('\n');

while again
  for i=1:length(polygon)
    fprintf('polygon %d has %d points\n', i, size(polygon{i},1));
  end

  [x, y, k] = ginput(1);
  okflag = 0;

  % check points do not fall out of image boundaries
  if get(findobj('string','Ins'),'value')
    if (proj == 1 && y<ss(2) && x<ss(3) && x>1 && y>1)
      okflag = 1;
    elseif (proj == 2 && y<ss(1) && x<ss(3) && x>1 && y>1)
      okflag = 1;
    elseif (proj == 3 && y<ss(1) && x<ss(2) && x>1 && y>1)
      okflag = 1;
    else
      okflag = 0;
    end
  end

  if okflag
    switch lower(k)
      case 1
        polygon{thispolygon} = cat(1, polygon{thispolygon}, [x y]);
        % add the last line segment to the figure
        if size(polygon{thispolygon},1)>1
          x = polygon{i}([end-1 end],1);
          y = polygon{i}([end-1 end],2);
        end
        plot(x, y, 'g.-');

      case 8 % backspace
        if size(polygon{thispolygon},1)>0
          % redraw existing polygons
          cb_redraw(gca);
          % remove the last point of current polygon
          polygon{thispolygon} = polygon{thispolygon}(1:end-1,:);
          for i=1:length(polygon)
            x = polygon{i}(:,1);
            y = polygon{i}(:,2);
            if i~=thispolygon
              % close the polygon in the figure
              x(end) = x(1);
              y(end) = y(1);
            end
            set(gca,'nextplot','new')
            plot(x, y, 'g.-');
          end
        end

      case 'c'
        if size(polygon{thispolygon},1)>0
          % close the polygon
          polygon{thispolygon}(end+1,:) = polygon{thispolygon}(1,:);
          % close the polygon in the figure
          x = polygon{i}([end-1 end],1);
          y = polygon{i}([end-1 end],2);
          plot(x, y, 'g.-');
          % switch to the next polygon
          thispolygon = thispolygon + 1;
          polygon{thispolygon} = zeros(0,2);
          slicedata = getappdata(fig,'slicedata');
          m = length(slicedata);
          slicedata(m+1).proj    = prop{1};
          slicedata(m+1).slice   = prop{2};
          slicedata(m+1).polygon = polygon;
          setappdata(fig,'slicedata',slicedata);
        end

      case {'q', 27}
        if size(polygon{thispolygon},1)>0
          % close the polygon
          polygon{thispolygon}(end+1,:) = polygon{thispolygon}(1,:);
          % close the polygon in the figure
          x = polygon{i}([end-1 end],1);
          y = polygon{i}([end-1 end],2);
          plot(x, y, 'g.-');
        end
        again = 0;
        %set(gcf,'WindowButtonDownFcn','');
        slicedata = getappdata(fig,'slicedata');
        m = length(slicedata);
        if ~isempty(polygon{thispolygon})
          slicedata(m+1).proj    = prop{1};
          slicedata(m+1).slice   = prop{2};
          slicedata(m+1).polygon = polygon;
          setappdata(fig,'slicedata',slicedata);
        end
      otherwise
        ft_warning('invalid button (%d)', k);
    end

  end
  assign_points3d
end

function cb_btn_dwn(hObject, eventdata, handles)
build_polygon
uiresume

function cb_btn_dwn2(hObject, eventdata, handles)
global obj
erase_points2d(obj)
uiresume

function erase_points2d (obj)
fig       = get(gca, 'parent');
prop      = getappdata(fig,'prop');
slicedata = getappdata(fig,'slicedata');
pntsslice = [];

% 2d slice selected box boundaries
if strcmp(get(obj,'string'),'box')
  [x, y] = ft_select_box;
  rowmin = min(y);    rowmax = max(y);
  colmin = min(x);    colmax = max(x);
  box = getappdata(fig,'box');
  box = [box; prop{1} prop{2} rowmin rowmax colmin colmax];
  setappdata(fig,'box',box);
else
  % converts lines to points
  pos = slicedata2pnts(prop{1},prop{2});
  tmp = ft_select_point(pos);
  point2mark.x = tmp(1); point2mark.y = tmp(2);
  setappdata(fig,'point2mark',point2mark);
end

maskhelp = [ ...
  '------------------------------------------------------------------------\n' ...
  'Delete points:\n' ...
  'press "c" on the keyboard to undo all selections\n' ...
  'press "d" or DEL on the keyboard to delete all selections\n' ...
  ];
fprintf(maskhelp);
fprintf('\n');
again = 1;
if ~ishold,hold,end
cb_redraw(gca);

% waits for a key press
while again
  [junk1, junk2, k] = ginput(1);

  switch lower(k)
    case 'c'
      if strcmp(get(obj,'string'),'box')
        % undoes all the selections, but only in the current slice
        ind = [];
        for ii=1:size(box,1)
          if box(ii,1)==prop{1} && box(ii,2)==prop{2}
            ind = [ind,ii];
          end
        end
        box(ind,:) = [];
        setappdata(fig,'box',box);
        cb_redraw(gca);
        again = 0;
        set(gcf,'WindowButtonDownFcn','');
      else
        setappdata(fig,'point2mark',[]);
        cb_redraw(gca);
        again = 0;
        set(gcf,'WindowButtonDownFcn','');
      end
    case {'d', 127}
      if strcmp(get(obj,'string'),'box')
        update_slicedata
        % deletes only the points selected in the current slice
        ind = [];
        for ii=1:size(box,1)
          if box(ii,1)==prop{1} && box(ii,2)==prop{2}
            ind = [ind,ii];
          end
        end
        box(ind,:) = [];
        setappdata(fig,'box',box);
        cb_redraw(gca);
        again = 0;
        set(gcf,'WindowButtonDownFcn','');
      else
        update_slicedata
        setappdata(fig,'point2mark',[]);
        cb_redraw(gca);
        again = 0;
        set(gcf,'WindowButtonDownFcn','');
      end
    otherwise
  end
end
assign_points3d

function assign_points3d
fig       = get(gca, 'parent');
slicedata = getappdata(fig,'slicedata');

points = [];
for zz = 1:length(slicedata)
  slice   = slicedata(zz).slice;
  proj    = slicedata(zz).proj;
  polygon = slicedata(zz).polygon;
  for kk=1:length(polygon)
    if ~isempty(polygon{kk})
      [xs,ys]=deal(polygon{kk}(:,1),polygon{kk}(:,2));
      if (proj==1)     %jk
        tmp    = [ slice*ones(length(xs),1),ys(:),xs(:) ];
        points = [points; unique(tmp,'rows')];
      elseif (proj==2) %ik
        tmp    = [ ys(:),slice*ones(length(xs),1),xs(:) ];
        points = [points; unique(tmp,'rows')];
      elseif (proj==3) %ij
        tmp    = [ ys(:),xs(:),slice*ones(length(xs),1) ];
        points = [points; unique(tmp,'rows')];
      end
    end
  end
end
setappdata(fig,'points',points);

function update_slicedata
fig       = get(gca, 'parent');
prop      = getappdata(fig,'prop');
slicedata = getappdata(fig,'slicedata');
box       = getappdata(fig,'box');
point2mark = getappdata(fig,'point2mark');
% case of box selection
if ~isempty(box) && ~isempty(slicedata)
  for zz = 1:length(slicedata)
    slice   = slicedata(zz).slice;
    proj    = slicedata(zz).proj;
    polygon = slicedata(zz).polygon;
    for uu=1:size(box,1)
      if (box(uu,1)==proj) && (box(uu,2)==slice)
        for kk=1:length(polygon)
          if ~isempty(polygon{kk})
            [xs,ys] = deal(polygon{kk}(:,1),polygon{kk}(:,2));
            tmpind = lt(ys,ones(length(xs),1)*box(uu,4)).*gt(ys,ones(length(xs),1)*box(uu,3)).* ...
              lt(xs,ones(length(xs),1)*box(uu,6)).*gt(xs,ones(length(xs),1)*box(uu,5));
            slicedata(zz).polygon{kk} = [ xs(find(~tmpind)),ys(find(~tmpind)) ];
          end
        end
      end
    end
  end
  % case of point selection
else
  if ~isempty(slicedata)
    for zz = 1:length(slicedata)
      slice   = slicedata(zz).slice;
      proj    = slicedata(zz).proj;
      polygon = slicedata(zz).polygon;
      for kk=1:length(polygon)
        if ~isempty(polygon{kk})
          [xs,ys] = deal(polygon{kk}(:,1),polygon{kk}(:,2));
          tmpind = eq(xs,point2mark.x).*eq(ys,point2mark.y);
          slicedata(zz).polygon{kk} = [ xs(find(~tmpind)),ys(find(~tmpind)) ];
        end
      end
    end
  end
end
setappdata(fig,'slicedata',slicedata)

% FIXME: obsolete: replaced by headshape at the beginning
function smooth_mesh(hObject, eventdata, handles)
fig = get(gca,'parent');
disp('not yet implemented')

% FIXME: make it work for pre-loaded meshes
function view_mesh(hObject, eventdata, handles)
fig  = get(gca, 'parent');
assign_points3d
pnt  = getappdata(fig,'points');
pnt_ = pnt;
if ~isempty(pnt)
  tri = projecttri(pnt);
  bnd.pnt = pnt_;
  bnd.tri = tri;
  slicedata = getappdata(fig,'slicedata');
  figure
  ft_plot_mesh(bnd,'vertexcolor','k');
end

function cancel_mesh(hObject, eventdata, handles)
fig  = get(gca, 'parent');
close(fig)

function cb_close(hObject, eventdata, handles)
% get the points from the figure
fig    = hObject;
global pnt
pnt   = getappdata(fig, 'points');
set(fig, 'CloseRequestFcn', @delete);
delete(fig);

function cb_btnp1(hObject, eventdata, handles)
set(findobj('string','jk'),'value',1);
set(findobj('string','ik'),'value',0);
set(findobj('string','ij'),'value',0);
cb_btn(hObject);

function cb_btnp2(hObject, eventdata, handles)
set(findobj('string','jk'),'value',0);
set(findobj('string','ik'),'value',1);
set(findobj('string','ij'),'value',0);
cb_btn(hObject);

function cb_btnp3(hObject, eventdata, handles)
set(findobj('string','jk'),'value',0);
set(findobj('string','ik'),'value',0);
set(findobj('string','ij'),'value',1);
cb_btn(hObject);

function which_task1(hObject, eventdata, handles)
set(gcf,'WindowButtonDownFcn','');
set(findobj('string','View'),'value',1);
set(findobj('string','Ins'), 'value',0);
set(findobj('string','Del'), 'value',0);
set(gcf,'WindowButtonDownFcn','');
change_panel

function which_task2(hObject, eventdata, handles)
set(findobj('string','View'),'value',0);
set(findobj('string','Ins'), 'value',1);
set(findobj('string','Del'), 'value',0);
set(gcf,'WindowButtonDownFcn',@cb_btn_dwn);
change_panel

function which_task3(hObject, eventdata, handles)
set(gcf,'WindowButtonDownFcn','');
set(findobj('string','View'),'value',0);
set(findobj('string','Ins'), 'value',0);
set(findobj('string','Del'), 'value',1);
change_panel

function change_panel
% affect panel visualization
w1 = get(findobj('string','View'),'value');
w2 = get(findobj('string','Ins'), 'value');
w3 = get(findobj('string','Del'), 'value');

if w1
  set(findobj('tag','slice'),'string','slice');
  set(findobj('tag','min'),'string','<');
  set(findobj('tag','max'),'string','>');
  set(findobj('tag','min'),'style','pushbutton');
  set(findobj('tag','max'),'style','pushbutton');
  set(findobj('tag','min'),'callback',@cb_btn);
  set(findobj('tag','max'),'callback',@cb_btn);
  set(findobj('tag','mesh'),'visible','on');
  set(findobj('tag','openm'),'visible','on');
  set(findobj('tag','viewm'),'visible','on');
  set(findobj('tag','brightness'),'visible','on');
  set(findobj('tag','plus'),'visible','on');
  set(findobj('tag','minus'),'visible','on');
  set(findobj('tag','toggle axes'),'visible','on');
  set(findobj('tag','plane'),'visible','on');
  set(findobj('tag','one'),'visible','on');
  set(findobj('tag','two'),'visible','on');
  set(findobj('tag','three'),'visible','on');
elseif w2
  set(findobj('tag','slice'),'string','select points');
  set(findobj('tag','min'),'string','close');
  set(findobj('tag','max'),'string','next');
  set(findobj('tag','min'),'style','pushbutton');
  set(findobj('tag','max'),'style','pushbutton');
  set(findobj('tag','min'),'callback',@tins_close);
  set(findobj('tag','max'),'callback',@tins_next);
  set(findobj('tag','mesh'),'visible','off');
  set(findobj('tag','openm'),'visible','off');
  set(findobj('tag','viewm'),'visible','off');
  set(findobj('tag','brightness'),'visible','off');
  set(findobj('tag','plus'),'visible','off');
  set(findobj('tag','minus'),'visible','off');
  set(findobj('tag','toggle axes'),'visible','off');
  set(findobj('tag','plane'),'visible','off');
  set(findobj('tag','one'),'visible','off');
  set(findobj('tag','two'),'visible','off');
  set(findobj('tag','three'),'visible','off');
elseif w3
  set(findobj('tag','slice'),'string','select points');
  set(findobj('tag','min'),'string','box');
  set(findobj('tag','max'),'string','point');
  set(findobj('tag','min'),'style','pushbutton');
  set(findobj('tag','max'),'style','pushbutton');
  set(findobj('tag','min'),'callback',@tdel_box);
  set(findobj('tag','max'),'callback',@tdel_single);
  set(findobj('tag','mesh'),'visible','off');
  set(findobj('tag','openm'),'visible','off');
  set(findobj('tag','viewm'),'visible','off');
  set(findobj('tag','brightness'),'visible','off');
  set(findobj('tag','plus'),'visible','off');
  set(findobj('tag','minus'),'visible','off');
  set(findobj('tag','toggle axes'),'visible','off');
  set(findobj('tag','plane'),'visible','off');
  set(findobj('tag','one'),'visible','off');
  set(findobj('tag','two'),'visible','off');
  set(findobj('tag','three'),'visible','off');
end

function tins_close(hObject, eventdata, handles)
set(gcf,'WindowButtonDownFcn','');

function tins_next(hObject, eventdata, handles)
set(gcf,'WindowButtonDownFcn','');

function tdel_box(hObject, eventdata, handles)
global obj
obj = gco;
set(gcf,'WindowButtonDownFcn',@cb_btn_dwn2);

function tdel_single(hObject, eventdata, handles)
global obj
obj = gco;
set(gcf,'WindowButtonDownFcn',@cb_btn_dwn2);

% accessory functions:
function [pnts] = slicedata2pnts(proj,slice)
fig       = get(gca, 'parent');
slicedata = getappdata(fig,'slicedata');
pnts = [];
for i=1:length(slicedata)
  if slicedata(i).slice==slice && slicedata(i).proj == proj
    for j=1:length(slicedata(i).polygon)
      if ~isempty(slicedata(i).polygon{j})
        tmp = slicedata(i).polygon{j};
        xs = tmp(:,1); ys = tmp(:,2);
        pnts = [pnts;[unique([xs,ys],'rows')]];
      end
    end
  end
end

function h = ispolygon(x)
h = length(x.XData)>1;

function h = ispoint(x)
h = length(x.XData)==1;

function [T,P] = points2param(pnt)
x = pnt(:,1); y = pnt(:,2); z = pnt(:,3);
[phi,theta,R] = cart2sph(x,y,z);
theta = theta + pi/2;
phi   = phi + pi;
T     = theta(:);
P     = phi(:);

function [bnd2,a,Or] = spherical_harmonic_mesh(bnd, nl)

% SPHERICAL_HARMONIC_MESH realizes the smoothed version of a mesh contained in the first
% argument bnd. The boundary argument (bnd) contains typically 2 fields
% called .pnt and .tri referring to vertices and triangulation of a mesh.
% The degree of smoothing is given by the order in the second input: nl
%
% Use as
%   bnd2 = spherical_harmonic_mesh(bnd, nl);

% nl    = 12; % from van 't Ent paper

bnd2 = [];

% calculate midpoint
Or = mean(bnd.pnt);
% rescale all points
x = bnd.pnt(:,1) - Or(1);
y = bnd.pnt(:,2) - Or(2);
z = bnd.pnt(:,3) - Or(3);
X = [x(:), y(:), z(:)];

% convert points to parameters
[T,P] = points2param(X);

% basis function
B     = shlib_B(nl, T, P);
Y     = B'*X;

% solve the linear system
a     = pinv(B'*B)*Y;

% build the surface
Xs = zeros(size(X));
for l = 0:nl-1
  for m = -l:l
    if m<0
      Yml = shlib_Yml(l, abs(m), T, P);
      Yml = (-1)^m*conj(Yml);
    else
      Yml = shlib_Yml(l, m, T, P);
    end
    indx = l^2 + l + m+1;
    Xs = Xs + Yml*a(indx,:);
  end
  fprintf('%d of %d\n', l, nl);
end
% Just take the real part
Xs = real(Xs);
% reconstruct the matrices for plotting.
xs = reshape(Xs(:,1), size(x,1), size(x,2));
ys = reshape(Xs(:,2), size(x,1), size(x,2));
zs = reshape(Xs(:,3), size(x,1), size(x,2));

bnd2.pnt = [xs(:)+Or(1) ys(:)+Or(2) zs(:)+Or(3)];
[bnd2.tri] = projecttri(bnd.pnt);

function B = shlib_B(nl, theta, phi)
% function B = shlib_B(nl, theta, phi)
%
% Constructs the matrix of basis functions
% where b(i,l^2 + l + m) = Yml(theta, phi)
%
% See also: shlib_Yml.m, shlib_decomp.m, shlib_gen_shfnc.m
%
% Dr. A. I. Hanna (2006).
B = zeros(length(theta), nl^2+2*nl+1);
for l = 0:nl-1
  for m = -l:l
    if m<0
      Yml = shlib_Yml(l, abs(m), theta, phi);
      Yml = (-1)^m*conj(Yml);
    else
      Yml = shlib_Yml(l, m, theta, phi);
    end
    indx = l^2 + l + m+1;
    B(:, indx) = Yml;
  end
end
return;

function Yml = shlib_Yml(l, m, theta, phi)
% function Yml = shlib_Yml(l, m, theta, phi)
%
% MATLAB function that takes a given order and degree, and the matrix of
% theta and phi and constructs a spherical harmonic from these. The
% analogue in the 1D case would be to give a particular frequency.
%
% Inputs:
%  m - order of the spherical harmonic
%  l - degree of the spherical harmonic
%  theta - matrix of polar coordinates \theta \in [0, \pi]
%  phi - matrix of azimuthal cooridinates \phi \in [0, 2\pi)
%
% Example:
%
% [x, y] = meshgrid(-1:.1:1);
% z = x.^2 + y.^2;
% [phi,theta,R] = cart2sph(x,y,z);
% Yml = spharm_aih(2,2, theta(:), phi(:));
%
% See also: shlib_B.m, shlib_decomp.m, shlib_gen_shfnc.m
%
% Dr. A. I. Hanna (2006)
Pml=legendre(l,cos(theta));
if l~=0
  Pml=squeeze(Pml(m+1,:,:));
end
Pml = Pml(:);
% Yml = sqrt(((2*l+1)/4).*(factorial(l-m)/factorial(l+m))).*Pml.*exp(sqrt(-1).*m.*phi);
% new:
Yml = sqrt(((2*l+1)/(4*pi)).*(factorial(l-m)/factorial(l+m))).*Pml.*exp(sqrt(-1).*m.*phi);
return;


function [reducedModel, removedRxns, indexedDuplicateRxns]=contractModel(model,distReverse,mets)
% contractModel
%   Contracts a model by grouping all identical reactions. Similar to the
%   deleteDuplicates part in simplifyModel but more care is taken here
%   when it comes to gene associations. If the duplicated reactions have
%   '_EXP_*' suffixes (where * is a digit), then the model is assumed to
%   have been passed through expandModel, and these suffixes are removed
%   here.
%
%   model                  a model structure
%   distReverse            distinguish reactions with same metabolites
%                          but different reversibility as different
%                          reactions (opt, default true)
%   mets                   string or cell array of strings with metabolite
%                          identifiers, whose involved reactions should be
%                          checked for duplication (opt, by default all
%                          reactions are considered) (option is used by
%                          replaceMets)
%
%   reducedModel           a model structure without duplicate reactions
%   removedRxns            cell array for the removed duplicate reactions
%   indexedDuplicateRxns   indexed cell array for the removed duplicate
%                          reactions (multiple valuess separated by semicolon)
%
%   NOTE: This code might not work for advanced grRules strings
%         that involve nested expressions of 'and' and 'or'.
%
%   Usage: [reducedModel, removedRxns, indexedDuplicateRxns]=contractModel(model,distReverse)

if nargin<2
    distReverse=true;
end

%First sort the model so that reversible reactions are in the same
%direction
modelS=sortModel(model);

%Get a list of duplicate reactions
if distReverse
    x=[modelS.S; model.rev']';
else
    x=modelS.S';
end
if nargin>2
    toCheck = getIndexes(model,mets,'mets');
    [~, toCheck] = find(modelS.S(toCheck,:));
    x = [x, (1:size(x,1))']; % Make all other rxns unique by additional column
    x(toCheck,end) = 0;
end

[~,I,J] = unique(x,'rows','first');

%Initialize cell array of indexedDuplicateRxns
indexedDuplicateRxns=cell(numel(model.rxns),1);
indexedDuplicateRxns(:)={''};

duplicateRxns=setdiff(1:numel(model.rxns),I);
mergeTo=I(J(duplicateRxns));

mergedRxns=unique(mergeTo);

%Now add all the info from this one. Print a warning if they have different
%bounds or objective function coefficients. Uses the widest bounds and
%largest magnitude of objective coefficient
for i=1:numel(mergedRxns)
    duplRxn=transpose([mergedRxns(i),duplicateRxns(mergeTo==mergedRxns(i))]);
    if numel(unique(model.lb(duplRxn)))>1
        EM=['Duplicates of reaction ' model.rxns{mergedRxns(i)} ' have different lower bound. Uses the most negative/smallest lower bound'];
        dispEM(EM,false);
        model.lb(mergedRxns(i))=min(model.lb(duplRxn));
    end
    if numel(unique(model.ub(duplRxn)))>1
        EM=['Duplicates of reaction ' model.rxns{mergedRxns(i)} ' have different upper bound. Uses the most positive/largest upper bound'];
        dispEM(EM,false);
        model.ub(mergedRxns(i))=max(model.ub(duplRxn));
    end
    if numel(unique(model.c(duplRxn)))>1
        EM=['Duplicates of reaction ' model.rxns{mergedRxns(i)} ' has a different objective function coefficient. Uses the largest coefficient'];
        dispEM(EM,false);
        model.c(mergedRxns(i))=max(model.c(duplRxn));
    end
    if isfield(model,'grRules') && any(~isempty(model.grRules(duplRxn)))
        rules=model.grRules(duplRxn);
        allRules={};
        for j=1:numel(rules)
            rules{j}=ignoreORinComplex(rules{j});
            allRules=[allRules regexp(rules{j},' or ','split')];
        end
        allRules=unique(allRules);
        allRules=strrep(allRules,'__OR__',' or ');
        andRules=contains(allRules,' and ');
        allRules(andRules)=strcat('(',allRules(andRules),')');
        if numel(allRules)==1
            model.grRules{mergedRxns(i)}=allRules{1};
        else
            model.grRules{mergedRxns(i)}=strjoin(allRules,' or ');
        end
    end
    if isfield(model,'eccodes') && any(~isempty(model.eccodes(duplRxn)))
        codes=model.eccodes(duplRxn);
        allCodes={};
        for j=1:numel(codes)
            allCodes=[allCodes regexp(codes{j},';','split')];
        end
        allCodes=unique(allCodes);
        if numel(allCodes)==1
            model.eccodes{mergedRxns(i)}=allCodes{1};
        else
            model.eccodes{mergedRxns(i)}=strjoin(allCodes,';');
        end
    end
    %Generate indexedDuplicateRxns cell array
    if numel(duplRxn)==2
        indexedDuplicateRxns{duplRxn(1)}=model.rxns{duplRxn(2)};
    else
        indexedDuplicateRxns{duplRxn(1)}=strjoin(model.rxns(duplRxn(2:end)),';');
    end
    %If all reactions have _EXP_* (where * is digit) as suffix, then the
    %model had passed through expandModel(), and these suffixes are removed.
    if all(~cellfun(@isempty,regexp(model.rxns(duplRxn),'_EXP_\d+$')))
        model.rxns(duplRxn(1))=regexprep(model.rxns(duplRxn(1)),'_EXP_\d+$','');
    end
end

%Delete the duplicate reactions
reducedModel=removeReactions(model,duplicateRxns);
removedRxns=model.rxns(duplicateRxns);
[~, index]=ismember(reducedModel.rxns,model.rxns);
indexedDuplicateRxns=indexedDuplicateRxns(index);

if isfield(reducedModel,'rxnGeneMat')
    %Fix grRules and reconstruct rxnGeneMat
    [grRules,rxnGeneMat] = standardizeGrRules(reducedModel,true);
    reducedModel.grRules = grRules;
    reducedModel.rxnGeneMat = rxnGeneMat;
end
end

function grRule = ignoreORinComplex(grRule)
%In a grRule, if OR relationship is nested in an AND relationship, then
%obfuscate the OR before splitting isoenzymes
grRule=['(' grRule ')'];
brOpen=strfind(grRule,'(');
brClose=strfind(grRule,')');
andPos=strfind(grRule,' and ');
%Find opening bracket closest before AND
stillCapturing = 0;
for i=1:numel(andPos)
    searchPos = andPos(i);
    while stillCapturing == 0
        closestOpen = brOpen(max(find(brOpen<searchPos)));
        inbetweenClose = brClose(brClose<searchPos & brClose>closestOpen);
        if ~isempty(inbetweenClose)
            searchPos=max(inbetweenClose);
        else
            stillCapturing = 1;
            beginPos = closestOpen;
        end
    end
    stillCapturing = 0;
    searchPos = andPos(i);
    while stillCapturing == 0
        closestClose = brClose(min(find(brClose>searchPos)));
        inbetweenOpen = brOpen(brOpen>searchPos & brOpen<closestOpen);
        if ~isempty(inbetweenOpen)
            searchPos=min(closestClose);
        else
            stillCapturing = 1;
            endPos = closestClose;
        end
    end
    replacePart=regexprep(grRule(beginPos:endPos),' or ','__OR__');
    grRule=strrep(grRule,grRule(beginPos:endPos),replacePart);
end
grRule=grRule(2:end-1);
end


function dtiXformRoiToMrVistaVolume(handles, roiNum)
%
% mrVistaFibers = dtiXformRoiToMrVistaVolume(handles, [roiNum])
%
% Uses the xformVAnatToAcpc (see dtiXformVanatCompute) to convert the specified
% ROI to mrVista vAnatomy coords.
%
% HISTORY:
% 2004.05.19 RFD (bob@white.stanford.edu) wrote it.

if(~isfield(handles, 'xformVAnatToAcpc') | isempty(handles.xformVAnatToAcpc))
    error('xformVAnatToAcpc not computed yet- run "Compute mrVista Xform" from the "Xform" menu.');
end
if(~exist('roiNum','var') | isempty(roiNum))
    roiNum = handles.curRoi;
end

view = getSelectedVolume;

for(ii=1:length(roiNum))
    roi = handles.rois(roiNum(ii));
    coords = unique(round(mrAnatXformCoords(inv(handles.xformVAnatToAcpc),roi.coords)),'rows')';
    view = newROI(view, ['dti_' roi.name], 1);
    view.ROIs(view.selectedROI).coords = coords;
end

% Is there a better way to do this?
mrGlobals;
eval([view.name '=view;']);
return;


function [models,M] = esvm_subset_of_models(models,M,subset)
%Choose a subset of models and a subset of the calibration matrix
% Copyright (C) 2011-12 by Tomasz Malisiewicz
% All rights reserved.
%
% This file is part of the Exemplar-SVM library and is made
% available under the terms of the MIT license (see COPYING file).
% Project homepage: https://github.com/quantombone/exemplarsvm

if ~exist('subset','var')
  s1 = cellfun(@(x)size(x.model.w,1),models);
  s2 = cellfun(@(x)size(x.model.w,2),models);
  urows = unique([s1; s2]','rows');
  [c,d] = ismember([s1; s2]',urows,'rows');
  [aa,bb] = max(hist(d,1:size(urows,1)));
  target = urows(bb,:);
  subset = find(s1==target(1) & s2==target(2));
end
hits = repmat(1:length(models),2,1);

models = models(subset);

subset2 = find(ismember(hits(:),subset));
M.w = cellfun2(@(x)x(subset2),M.w);
M.w = M.w(subset2);
M.b = M.b(subset2);
M.C = M.C(subset2,subset2);


classdef KeplerianOrbitVariable < AbstractOrbitModelVariable
    %KeplerianOrbitVariable Summary of this class goes here
    %   Detailed explanation goes here

    properties
        varObj(1,1) KeplerianOrbitStateModel = KeplerianOrbitStateModel.getDefaultOrbitState();

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

        varSma(1,1) logical = false;
        varEcc(1,1) logical = false;
        varInc(1,1) logical = false;
        varRaan(1,1) logical = false;
        varArg(1,1) logical = false;
        varTru(1,1) logical = false;
    end

    methods
        function obj = KeplerianOrbitVariable(varObj)
            obj.varObj = varObj;
            obj.varObj.optVar = obj;

            obj.id = rand();
        end

        function x = getXsForVariable(obj)
            x = [];

            if(obj.varSma)
                x(end+1) = obj.varObj.sma;
            end

            if(obj.varEcc)
                x(end+1) = obj.varObj.ecc;
            end

            if(obj.varInc)
                x(end+1) = obj.varObj.inc;
            end

            if(obj.varRaan)
                x(end+1) = obj.varObj.raan;
            end

            if(obj.varArg)
                x(end+1) = obj.varObj.arg;
            end

            if(obj.varTru)
                x(end+1) = obj.varObj.tru;
            end
        end

        function [lb, ub] = getBndsForVariable(obj)
            useTf = obj.getUseTfForVariable();

            lb = obj.lb(useTf);
            ub = obj.ub(useTf);
        end

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

        function setBndsForVariable(obj, lb, ub)
            if(length(lb) == 6 && length(ub) == 6)
                obj.lb = lb;
                obj.ub = ub;
            else
                useTf = obj.getUseTfForVariable();

                obj.lb(useTf) = lb;
                obj.ub(useTf) = ub;
            end
        end

        function useTf = getUseTfForVariable(obj)
            useTf = [obj.varSma        obj.varEcc        obj.varInc        obj.varRaan        obj.varArg        obj.varTru];
        end

        function setUseTfForVariable(obj, useTf)
            obj.varSma  = useTf(1);
            obj.varEcc = useTf(2);
            obj.varInc  = useTf(3);
            obj.varRaan = useTf(4);
            obj.varArg  = useTf(5);
            obj.varTru = useTf(6);
        end

        function updateObjWithVarValue(obj, x)
            xInd = 1;

            if(obj.varSma)
                obj.varObj.sma = x(xInd);
                xInd = xInd + 1;
            end

            if(obj.varEcc)
                obj.varObj.ecc = x(xInd);
                xInd = xInd + 1;
            end

            if(obj.varInc)
                obj.varObj.inc = x(xInd);
                xInd = xInd + 1;
            end

            if(obj.varRaan)
                obj.varObj.raan = x(xInd);
                xInd = xInd + 1;
            end

            if(obj.varArg)
                obj.varObj.arg = x(xInd);
                xInd = xInd + 1;
            end

            if(obj.varTru)
                obj.varObj.tru = x(xInd);
                xInd = xInd + 1; %#ok<NASGU>
            end
        end

        function nameStrs = getStrNamesOfVars(obj, evtNum, varLocType)
            nameStrs = {sprintf('Event %i SMA', evtNum), ...
                        sprintf('Event %i Eccentricity', evtNum), ...
                        sprintf('Event %i Inclination', evtNum), ...
                        sprintf('Event %i RAAN', evtNum), ...
                        sprintf('Event %i Argument of Periapsis', evtNum), ...
                        sprintf('Event %i True Anomaly', evtNum)};

            nameStrs = nameStrs(obj.getUseTfForVariable());
        end
    end
end


function [hPatch,api] = imRectRot( varargin )
% Create a draggable, resizable, rotatable rectangle or ellipse.
%
% The 'ellipse' param determines if the displayed object is a rectangle or
% ellipse. The object is identical in both cases, only the display changes.
% The created object may be queried or controlled programatically by using
% the returned api.
%
% The 'rotate' param determines overall behavior of the created object. If
% rotate=0, the resulting object (rect or ellipse) is axis aligned. In
% terms of the graphical interface it is identical to Matlab's imrect (can
% drag by clicking in interior or resize by clicking on edges), although it
% is much less cpu intensive. If rotate>0, the resulting object is
% rotatable. In addition to the interface for a non-rotatable object, four
% control points are present, one at the center of each edge. Three of
% these have color given by the 'color' flag, the last has color 'colorc'.
% The odd colored control point is used to display orientation. Dragging
% this control point or the one opposite changes orientation, dragging the
% remaining two resizes the object symmetrically. Finally, when creating a
% rotatable object, the first drag determines the major axes (height) of
% the object, with the width set to height*rotate (hence the rotate param
% also determines aspect ratio of newly created objects). Using this
% control scheme, an object can be naturally specified with two drags: the
% first is used to draw the major axes, the second to adjust the width.
%
% Position is represented by [x y w h theta], where [x,y] give the top/left
% corner of the rect PRIOR to rotation, [w,h] are the width and height, and
% theta is the angle in degrees. The final rect is given by first placing
% the rect at [x,y], then rotating it by theta around it's center. The
% advantage of this is that if theta=0, the first four elements are
% identical to the standard rect representation. The disadvantage is that
% [x,y] need not lie in the interior of the rect after rotation.
%
% USAGE
%  [h,api] = imRectRot( varargin )
%
% INPUTS
%  varargin   - parameters (struct or name/value pairs)
%   .hParent    - [gca] object parent, typically an axes object
%   .ellipse    - [0] if true display ellipse otherwise display rectangle
%   .rotate     - [1] determines if object is axis aligned
%   .pos        - [] initial pos vector [x y w h theta] or [] or [x y]
%   .lims       - [] rectangle defining valid region for object placement
%   .showLims   - [0] draw rectangle representing lims
%   .color      - ['g'] color for the displayed object
%   .colorc     - ['b'] color for the control point displaying orientation
%   .lw         - [2] 'LineWidth' property for the displayed object
%   .ls         - ['-'] 'LineStyle' property for the displayed object
%   .cross      - [0] if 1 show diagonal, if 2 show cross
%
% OUTPUTS
%  h          - handle used to delete object
%  api        - interface allowing access to created object
%  .getPos()       - get position - returns 5 elt pos
%  .setPos(pos)    - set position (while respecting constraints)
%  .setPosLock(b)  - if lock set (b==true), object cannot change
%  .setSizLock(b)  - if lock set (b==true), object cannot change size
%  .setDrgLock(b)  - if lock set (b==true), object cannot be dragged
%  .setSidLock(lk) - [4x1] set locks for each side (tp/rt/bt/lf)
%  .setPosChnCb(f) - whenever pos changes (even slightly), calls f(pos)
%  .setPosSetCb(f) - whenever pos finished changing, calls f(pos)
%  .uistack(...)   - calls 'uistack( [objectHandles], ... )', see uistack
%  .setStyle(...)  - set line style (ls), width (lw), color and colorc
%
% EXAMPLE - interactively place simple axis aligned rectangle
%  figure(1), imshow peppers.png;
%  [h,api]=imRectRot('rotate',0);
%  api.setPosChnCb( @(pos) disp(num2str(pos)) );
%
% EXAMPLE - create rotatable ellpise that falls inside image
%  figure(1); I=imread('cameraman.tif'); imshow(I); siz=size(I);
%  [h,api]=imRectRot('pos',[60 60 40 40 45],'lims',[1 1 siz(1:2)-2 0],...
%    'showLims',1,'ellipse',1,'rotate',1,'color','w','colorc','y'  );
%  api.setPosSetCb( @(pos) disp(num2str(pos)) );
%
% See also IMRECT, RECTANGLE, PATCH
%
% Piotr's Computer Vision Matlab Toolbox      Version 2.51
% Copyright 2014 Piotr Dollar.  [pdollar-at-gmail.com]
% Licensed under the Simplified BSD License [see external/bsd.txt]

% global variables (shared by all functions below)
[hParent,pos,lims,rotate,crXs,crYs,posChnCb,posSetCb,posLock,sizLock,...
  dgrLock,sidLock,hAx,hFig,hPatch,hBnds,hCntr,hEll] = deal([]);

% intitialize
intitialize( varargin{:} );

% create api
api = struct('getPos',@getPos, 'setPos',@setPos, 'uistack',@uistack1, ...
  'setPosChnCb',@setPosChnCb, 'setPosSetCb',@setPosSetCb, ...
  'setPosLock',@setPosLock, 'setSizLock',@setSizLock, ...
  'setDrgLock',@setDrgLock, 'setSidLock',@setSidLock, ...
  'setStyle',@setStyle );

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

  function intitialize( varargin )
    % get default arguments
    dfs={'hParent',gca, 'ellipse',0, 'rotate',1, 'pos',[], 'lims',[], ...
      'showLims',0,'color','g','colorc','b','lw',2,'ls','-','cross',0};
    [hParent,ellipse,rotate,pos,lims,showLims,color,colorc,lw,ls,cross]=...
      getPrmDflt(varargin,dfs,1);
    if(numel(pos)==4), pos=[pos(:)' 0]; end
    if(numel(lims)==4), lims=[lims(:)' 0]; end

    % get figure and axes handles
    hAx = ancestor(hParent,'axes'); assert(~isempty(hAx));
    hFig = ancestor(hAx,'figure'); assert(~isempty(hFig));
    set( hFig, 'CurrentAxes', hAx );

    % optionally display limits
    if(showLims && ~isempty(lims)), [~,xs,ys]=rectToCorners(lims);
      for j=1:4, ids=mod([j-1 j],4)+1; line(xs(ids),ys(ids)); end
    end

    % create objects for rectangle display/interface
    if( ellipse ), linePrp={'color',[.7 .7 .7],'LineWidth',1};
    else linePrp={'color',color,'LineWidth',lw,'LineStyle',ls}; end
    if(isempty(pos)); vis='off'; else vis='on'; end;
    assert(cross==0 || cross==1 || cross==2);
    for i=1:4+cross, hBnds(i)=line(linePrp{:},'Visible',vis); end

    % create transparent patch to capture clicks in object interior
    hPatch=patch('FaceColor','none','EdgeColor','none');

    % create objects for ellipse display/interface
    if( ellipse )
      ellPrp={'color',color,'LineWidth',lw,'LineStyle',ls};
      ts=linspace(-180,180,50); crXs=cosd(ts); crYs=sind(ts);
      hold on; hEll=plot(crXs,crYs,ellPrp{:},'Visible',vis); hold off;
    end

    % create objects for rotation display/interface
    if( rotate )
      circPrp={'Curvature',[1 1],'FaceColor',color,'EdgeColor',color};
      for i=1:4, hCntr(i)=rectangle(circPrp{:},'Visible',vis); end
      set(hCntr(1),'LineWidth',lw,'FaceColor',colorc);
    end

    % set callbacks on all objects
    hs=[hPatch hBnds hCntr hEll];
    set(hs,'ButtonDownFcn',{@btnDwn,0},'DeleteFcn',@deleteFcn);

    % set or query initial position
    posLock=0; sizLock=0; dgrLock=0; sidLock=[0 0 0 0];
    if(length(pos)==5), setPos(pos,1); else
      btnDwn([],[],-1); waitfor(hFig,'WindowButtonUpFcn','');
    end
  end

  function [pc,rs,R] = rectInfo( pos0 )
    % return rectangle center, radii, and rotation matrix
    t=pos0(5); c=cosd(t); s=sind(t); R=[c -s; s c];
    rs=pos0(3:4)/2; pc=pos0(1:2)+rs;
  end

  function [pts,xs,ys,pc] = rectToCorners( pos0 )
    % return 4 rect corners in real world coords
    [pc,rs,R]=rectInfo( pos0 );
    x0=-rs(1); x1=rs(1); y0=-rs(2); y1=rs(2);
    pts=[x0 y0; x1 y0; x1 y1; x0 y1]*R'+pc(ones(4,1),:);
    xs=pts(:,1); ys=pts(:,2);
  end

  function pos1 = cornersToRect( pos0, x0, y0, x1, y1 )
    % compute pos from 4 corners given in rect coords
    [pc,~,R] = rectInfo( pos0 );
    p0=[x0 y0]*R'+pc; p1=[x1 y1]*R'+pc;
    pc=(p1+p0)/2; p0=(p0-pc)*R; p1=(p1-pc)*R;
    pos1 = [pc+p0 p1-p0 pos0(5)];
  end

  function setPos( posNew, ignoreLims )
    if(isempty(hBnds) || isempty(hPatch)); return; end; L=lims;
    % if corners fall outside lims don't use posNew
    if( ~isempty(L) && (nargin<2 || ~ignoreLims) )
      if( posNew(5)==lims(5) )
        % lims and posNew at same orient (do everything in rect coords)
        [pc,rs,R]=rectInfo(posNew); p0=-rs; p1=rs;
        pts=(rectToCorners(L)-pc(ones(4,1),:))*R;
        L0=[pts(1,1) pts(1,2)]; L1=[pts(2,1) pts(3,2)];
        p0=min(max(p0,L0),L1); p1=max(min(p1,L1),p0);
        posNew=cornersToRect(posNew,p0(1),p0(2),p1(1),p1(2));
      else
        % lims and posNew at diff orient (do everything in lims coords)
        [pc,rs,R]=rectInfo(L); p0=-rs; p1=rs;
        p=(rectToCorners(posNew)-pc(ones(4,1),:))*R; xs=p(:,1); ys=p(:,2);
        valid=[xs>=p0(1) xs<=p1(1) ys>=p0(2) ys<=p1(2)];
        if(~all(valid(:))), return; end
      end
    end
    % create invisible patch to captures key presses
    pos=posNew; [~,xs,ys]=rectToCorners(pos);
    vert=[xs ys ones(4,1)]; face=1:4;
    set(hPatch,'Faces',face,'Vertices',vert);
    % draw ellipse
    if(~isempty(hEll)), [pc,rs]=rectInfo(posNew); th=pos(5);
      xsEll = rs(1)*crXs*cosd(-th)+rs(2)*crYs*sind(-th)+pc(1);
      ysEll = rs(2)*crYs*cosd(-th)-rs(1)*crXs*sind(-th)+pc(2);
      set(hEll,'XData',xsEll,'YData',ysEll);
    end
    % draw rectangle boundaries and control circles
    r=axisUnitsPerCentimeter();
    r=max( r*.1, min(mean(pos(3:4))/10,r) );
    for i=1:length(hBnds), ids=mod([i-1 i],4)+1;
      if(i==5), ids=[1 3]; elseif(i==6), ids=[2 4]; end
      set(hBnds(i),'Xdata',xs(ids),'Ydata',ys(ids));
      if(rotate && i<=4), x=mean(xs(ids)); y=mean(ys(ids));
        set(hCntr(i),'Position',[x-r y-r 2*r 2*r]);
      end
    end
  end

  function pnt = getCurPnt()
    pnt=get(hAx,'CurrentPoint'); pnt=pnt([1 3]);
  end

  function d = axisUnitsPerCentimeter()
    % approximage absolute axes size
    units=get(hAx,'units'); set(hAx,'units','centimeters');
    cm=get(hAx,'Position'); cm=max(cm(3:4));
    set(hAx,'units',units);
    % axes size in axes units
    xLim=get(gca,'xLim'); yLim=get(gca,'yLim');
    sizInner = max([xLim(2)-xLim(1),yLim(2)-yLim(1)]);
    % units per centimeter
    d = sizInner/cm;
  end

  function [side,cursor,flag] = getSide( pnt0 )
    % get pnt in coordintates of center of rectangle
    [pc,rs,R]=rectInfo(pos); pnt=(pnt0-pc)*R; th=pos(5);
    % side(i) -1=lf/tp bnd; 0=interior; +1:rt/bt bnd; 2=center
    t = axisUnitsPerCentimeter(); side=[0 0]; flag=0;
    t = max( t*.1, min(mean(pos(3:4))/5,t) );
    for i=1:2
      ti = min(t,rs(i)/3);
      if( abs(pnt(i))<ti && rotate ), side(i)=2; % near center
      elseif( pnt(i)<-rs(i)+ti ), side(i)=-1; % near lf/tp boundary
      elseif( pnt(i)>rs(i)-ti), side(i)=1; % near rt/bt boundary
      end
    end
    % flag: -1: none, 0=resize; 1=drag; 2=rotate; 3=symmetric-resize
    if((sidLock(4)&&side(1)==-1)||(sidLock(2)&&side(1)==1)), side(1)=0; end
    if((sidLock(1)&&side(2)==-1)||(sidLock(3)&&side(2)==1)), side(2)=0; end
    if(any(side==0) || all(side==2)), side(side==2)=0; end
    if(side(1)==2), flag=2; cursor='crosshair'; return; end
    if(sizLock), side=[0 0]; end
    if(all(side==0) && dgrLock), cursor=''; flag=-1; return; end
    if(all(side==0)), flag=1; side=pnt0; cursor='fleur'; return; end
    if(side(2)==2), flag=3; side(2)=0; end
    % select cursor based on position
    cs={'bottom','botr','right','topr','top','topl','left','botl'};
    a=mod(round((atan2(side(1),side(2))/pi-th/180)*4),8)+1; cursor=cs{a};
  end

  function btnDwn( h, evnt, flag ) %#ok<INUSL>
    if(isempty(hBnds) || isempty(hPatch) || posLock), return; end
    if( flag==-1 ) % create new rectangle
      if(isempty(pos)), anchor=ginput(1); else anchor=pos(1:2); end
      pos=[anchor 1 1 0]; setPos(pos);
      set([hBnds hCntr hEll],'Visible','on');
      if(rotate), cursor='crosshair'; flag=4;
      else cursor='botr'; flag=0; end
    else % resize, rotate or drag rectangle
      pnt=getCurPnt(); [anchor,cursor,flag]=getSide( pnt );
      if(flag==-1), return; end
    end
    set( hFig, 'Pointer', cursor );
    set( hFig, 'WindowButtonMotionFcn',{@drag,flag,anchor,pos} );
    set( hFig, 'WindowButtonUpFcn', @stopDrag );
  end

  function drag( h, evnt, flag, anchor, pos0 ) %#ok<INUSL>
    if(isempty(hBnds) || isempty(hPatch)); return; end;
    pnt = getCurPnt();
    if( flag==1 ) % shift rectangle by del=pnt-anchor
      setPos( [pos0(1:2)+(pnt-anchor) pos0(3:5)] );
    elseif( flag==0 || flag==3 ) % resize in rectangle coordinate frame
      [pc,rs,R]=rectInfo(pos0); p0=-rs; p1=rs; pnt=(pnt-pc)*R;
      if( flag==3 ), p0(1)=-pnt(1); p1(1)=pnt(1); else
        for i=1:2, if(anchor(i)>0), p1(i)=pnt(i); end; end
        for i=1:2, if(anchor(i)<0), p0(i)=pnt(i); end; end
      end; p0a=min(p0,p1); p1=max(p0,p1); p0=p0a;
      setPos(cornersToRect(pos0,p0(1),p0(2),p1(1),p1(2)));
    elseif( flag==2 || flag==4 ) % rotate rectangle
      [~,xs,ys]=rectToCorners(pos0);
      if(anchor(2)==-1), ids=[3 4]; else ids=[1 2]; end
      p0=mean([xs(ids) ys(ids)]); pc=(p0+pnt)/2;
      if(anchor(2)==-1), d=pnt-p0; else d=p0-pnt; end
      h=sqrt(sum(d.^2)); th=atan2(d(1),-d(2))/pi*180;
      if(flag==2), w=pos(3); else w=h*rotate; end
      setPos([pc(1)-w/2 pc(2)-h/2 w h th]);
    end
    if(~isempty(posChnCb)); posChnCb(pos); end;
    drawnow; % update display
  end

  function stopDrag( h, evnt ) %#ok<INUSD>
    set( hFig, 'WindowButtonMotionFcn','');
    set( hFig, 'WindowButtonUpFcn','');
    set( hFig, 'Pointer', 'arrow' );
    if(~isempty(posSetCb)); posSetCb(pos); end;
  end

  function deleteFcn( h, evnt ) %#ok<INUSD>
    [posChnCb,posSetCb]=deal([]); hs=[hPatch hBnds hCntr hEll];
    for i=1:length(hs), if(ishandle(hs(i))); delete(hs(i)); end; end
    [hBnds,hPatch,hCntr,hEll]=deal([]);
  end

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

  function pos0 = getPos(), pos0=pos; end

  function setPosChnCb( f ), posChnCb=f; end

  function setPosSetCb( f ), posSetCb=f; end

  function setPosLock( b ), posLock=b; end

  function setSizLock( b ), sizLock=b; end

  function setDrgLock( b ), dgrLock=b; end

  function setSidLock( lk )
    sidLock=lk; vis={'off','on'};
    for i=1:4, set(hCntr(i),'Visible',vis{2-lk(i)}); end
  end

  function uistack1( varargin )
    if(isempty(hBnds) || isempty(hPatch)); return; end;
    uistack( [hBnds hPatch hCntr hEll], varargin{:} );
  end

  function setStyle( ls, lw, color, colorc )
    if(isempty(hEll)), h=hBnds; else h=hEll; end
    set(h,'LineStyle',ls,'LineWidth',lw,'color',color);
    if(~rotate), return; end; if(nargin<4), colorc='b'; end
    set(hCntr,'FaceColor',color,'EdgeColor',color);
    set(hCntr(1),'LineWidth',lw,'FaceColor',colorc);
  end
end


classdef TestMagnitude
    %TestMagnitude

    methods (Static)
        function test_1
            x = randn(5,6);
            y = randn(5,6);
            mag = cv.magnitude(x, y);
            validateattributes(mag, {class(x)}, {'size',size(x)});

            x = single(x);
            y = single(y);
            mag = cv.magnitude(x, y);
            validateattributes(mag, {class(x)}, {'size',size(x)});
        end

        function test_error_argnum
            try
                cv.magnitude();
                throw('UnitTest:Fail');
            catch e
                assert(strcmp(e.identifier,'mexopencv:error'));
            end
        end
    end

end


% Superclass for linear filters.
%
% This file is part of the Kernel Adaptive Filtering Toolbox for Matlab.
% https://github.com/steven2358/kafbox/

classdef linear_filter < base_estimator

end


function h = maxhorsign(signrestriction)

for ii = 1 : size(signrestriction,2)
    tmp    = (signrestriction{ii});
    index  = strfind(tmp,',');
    eval(['tmp1 = ' tmp( index(1)+1 : index(2)-1 ) ';']);
    hh(ii) = max(tmp1);
end

h = max(hh);


% FPMat: FlexPDE Matlab Interface
%
%   Subject:    FlexPDE Matlab Interface
%   Gategory:   Utility
%   Author:     Mohammad Rahmani
%   Created:    Dec. 3, 2004
%   Version:    1.0
%
% Files
%   fpreade  - reads the unformatted data produced by FlexPDE ELEVATION plot command.
%   fpreadh  - reads the unformatted data exported by FlexPDE HISTORY plot command.
%   fpreadsc - reads the unformatted data EXPORTED by FlexPDE on a rectangular grid.
%
% Notes: Tested under Matlab R13, R14 and FlexPDE 4.x.
%
%
% Jan. 13, 2005
% Mohammad Rahmani
% Chemical Eng. Dep.
% Amir-Kabir Uni. of Technology
% Tehran, IRAN
% Mohammad.Rahmani@Gmail.com
%
%


%WATERSHED  Performs a marker-based image segmentation using the watershed algorithm
%
%     marker = cv.watershed(image, marker)
%
% ## Input
% * __image__ Input 8-bit 3-channel image.
% * __marker__ Input 32-bit single-channel image (map) of markers. It should
%   have the same size as `image`.
%
% ## Output
% * __marker__ Output 32-bit single-channel image (map) of markers. It has the
%   same size as `image`.
%
% The function implements one of the variants of watershed, non-parametric
% marker-based segmentation algorithm, described in [Meyer92].
%
% Before passing the image to the function, you have to roughly outline the
% desired regions in the image markers with positive (>0) indices. So, every
% region is represented as one or more connected components with the pixel
% values 1, 2, 3, and so on. Such markers can be retrieved from a binary mask
% using cv.findContours and cv.drawContours. The markers are "seeds" of the
% future image regions. All the other pixels in markers, whose relation to the
% outlined regions is not known and should be defined by the algorithm, should
% be set to 0's. In the function output, each pixel in markers is set to a
% value of the "seed" components or to -1 at boundaries between the regions.
%
% ### Note
% Any two neighbor connected components are not necessarily separated by
% a watershed boundary (-1 pixels); for example, they can touch each other in
% the initial marker image passed to the function.
%
% ## References
% [Meyer92]:
% > Fernand Meyer. "Color image segmentation". In Image Processing and its
% > Applications, 1992, International Conference on, pages 303-306. IET, 1992.
%
% See also: cv.grabCut, cv.findContours, watershed, boundarymask
%


function [ f ] = getEEF_Moment( t )
%% This function is used to get the endeffector moment of the KUKA iiwa 7 R 800.

%% Syntax:
% [ M ] = getEEF_Moment( t )

%% About:
% This function is used to get the endeffector moment of the KUKA iiwa 7 R 800.
% The moment is measured at the media flange of the robot.

%% Arreguments:
% t: is the TCP/IP connection
% M: is 1x3 cell array. Represinting the  X,Y and Z components of the moment acting on the
% media flange of the robot. The components of the vector of moment are
% described in the robot base frame. The moment is measured in
% (Newton.meter)

% Copyright, Mohammad SAFEEA, 3rd of May 2017

theCommand='Eef_moment';
fprintf(t, theCommand);
message=fgets(t);
%disp(message)
[P1,N]=getDoubleFromString(message);

for i=1:3
    f{i}=P1{i};
end

end

function [jPos,j]=getDoubleFromString(message)
n=max(max(size(message)));
j=0;
numString=[];
for i=1:n
    if message(i)=='_'
        j=j+1;
        jPos{j}=str2num(numString);
        numString=[];
    else
        numString=[numString,message(i)];
    end
end
end


function initializeLengthFilterPanel( horizontalBar, leftBottom, panelSize, hdls )
%INITIALIZELENGTHFILTERPANEL Initialize length filter panel with 2 edit boxes for min and max length of eddy tracks

lengthFilterPanel = uipanel(horizontalBar, ...
    'Units', 'normalize', ...
    'Position', [leftBottom panelSize]);

uicontrol(lengthFilterPanel, ...
    'String', 'Min length', ...
    'Style', 'text',...
    'FontSize', 11, ...
    'Units', 'normalized', ...
    'Position', [0 .5 .5 .5]);

uicontrol(lengthFilterPanel, ...
    'String', 'Max length', ...
    'Style', 'text',...
    'FontSize', 11, ...
    'Units', 'normalized', ...
    'Position', [.5 .5 .5 .5]);

uicontrol(lengthFilterPanel, ...
    'Style', 'edit', ...
    'Units', 'normalized',...
    'Position', [0 0 .5 .5], ...
    'String', 'any', ...
    'Callback', {@minLengthCallback, hdls});

uicontrol(lengthFilterPanel, ...
    'Style', 'edit', ...
    'Units', 'normalized',...
    'Position', [0.5 0 .5 .5], ...
    'String', 'any', ...
    'Callback', {@maxLengthCallback, hdls});

hdls.add_attribute_filter('lifetimes');

end

function minLengthCallback(hObject, ~, hdls)
% Update track min length and generate data again

old_pointer = start_busy_pointer(hdls);

minLength = get(hObject, 'String');
if isempty(minLength) || strcmp(minLength, 'any')
    hdls.set_attribute_filter_min_value('lifetimes', -inf);
else
    minLength = str2double(minLength);
    if(isnan(minLength)) % Not valid string
        errordlg('Min length must be an integer, "any" or empty', 'Min length input error');
        return;
    end
    hdls.set_attribute_filter_min_value('lifetimes', minLength);
end
hdls.generate_data();

end_busy_pointer(hdls, old_pointer);

end

function maxLengthCallback(hObject, ~, hdls)
% Update track max length and generate data again

old_pointer = start_busy_pointer(hdls);

maxLength = get(hObject, 'String');
if(isempty(maxLength) || strcmp(maxLength, 'any'))
    hdls.set_attribute_filter_max_value('lifetimes', inf);
else
    maxLength = str2double(maxLength);
    if(isnan(maxLength)) % Not valid string
        errordlg('Max length must be an integer, "any" or empty', 'Max length input error');
        return;
    end
    hdls.set_attribute_filter_max_value('lifetimes', maxLength);
end
hdls.generate_data();

end_busy_pointer(hdls, old_pointer);

end


% --------- DeepMIMO: A Generic Dataset for mmWave and massive MIMO ------%
% Authors: Ahmed Alkhateeb, Umut Demirhan, Abdelrahman Taha
% Date: March 17, 2022
% Goal: Encouraging research on ML/DL for MIMO applications and
% providing a benchmarking tool for the developed algorithms
% ---------------------------------------------------------------------- %

function [DeepMIMO_dataset, params] = DeepMIMO_generator(params)

    % -------------------------- DeepMIMO Dataset Generation -----------------%
    fprintf(' DeepMIMO Dataset Generation started')

    [params, params_inner] = validate_parameters(params);

    if params_inner.dynamic_scenario
        for f = 1:length(params_inner.list_of_folders)
            fprintf('\nGenerating Scene %i/%i', f, length(params_inner.list_of_folders))
            params.scenario_files = fullfile(params_inner.list_of_folders{f}, params.scenario); % The initial of all the scenario files
            DeepMIMO_scene{f} = generate_data(params, params_inner);
            param{f} = params;
        end

        DeepMIMO_dataset = DeepMIMO_scene;
        params = param;
        saveDataset = params{1}.saveDataset;
    else
        DeepMIMO_dataset = generate_data(params, params_inner);
        saveDataset = params.saveDataset;
    end

    % Saving the data
    if saveDataset
        fprintf('\n Saving the DeepMIMO Dataset ...')

        fileidx = 1;
        while isfile(sprintf('DeepMIMO_dataset/dataset_%i.mat', fileidx))
            fileidx = fileidx + 1;
        end
        sfile_DeepMIMO = sprintf('DeepMIMO_dataset/dataset_%i.mat', fileidx);
        dataset_params = params;
        save(sfile_DeepMIMO,'DeepMIMO_dataset', 'dataset_params', '-v7.3');

        fprintf('\n The generated DeepMIMO dataset is saved into %s file.', sfile_DeepMIMO);

    end

    fprintf('\n DeepMIMO Dataset Generation completed \n')

end

function DeepMIMO_dataset = generate_data(params, params_inner)
    % Reading ray tracing data
    fprintf('\n Reading the channel parameters of the ray-tracing scenario %s', params.scenario)
    for t=1:params.num_active_BS
        bs_ID = params.active_BS(t);
        fprintf('\n Basestation %i', bs_ID);
        [TX{t}.channel_params, TX{t}.channel_params_BSBS, TX{t}.loc] = read_raytracing(bs_ID, params, params_inner.scenario_files);
    end

    % Constructing the channel matrices from ray-tracing
    for t = 1:params.num_active_BS
        fprintf('\n Constructing the DeepMIMO Dataset for BS %d', params.active_BS(t))
        c = progress_counter(params.num_user+params.enable_BS2BSchannels*params.num_active_BS);

        % BS transmitter location & rotation
        DeepMIMO_dataset{t}.loc = TX{t}.loc;
        DeepMIMO_dataset{t}.rotation = params_inner.array_rotation_BS(t,:);

        %----- BS-User Channels
        for user=1:params.num_user
            % Channel Construction

            if params.generate_OFDM_channels
                [DeepMIMO_dataset{t}.user{user}.channel]=construct_DeepMIMO_channel(params_inner.num_ant_BS(t, :), params_inner.array_rotation_BS(t,:), params_inner.ant_spacing_BS(t), params.num_ant_UE, params_inner.array_rotation_UE(user, :), params.ant_spacing_UE, TX{t}.channel_params(user), params);
            else
                [DeepMIMO_dataset{t}.user{user}.channel]=construct_DeepMIMO_channel_TD(params_inner.num_ant_BS(t, :), params_inner.array_rotation_BS(t,:), params_inner.ant_spacing_BS(t), params.num_ant_UE, params_inner.array_rotation_UE(user, :), params.ant_spacing_UE, TX{t}.channel_params(user), params);
                DeepMIMO_dataset{t}.user{user}.ToA = TX{t}.channel_params(user).ToA; %Time of Arrival/Flight of each channel path (seconds)
            end
            DeepMIMO_dataset{t}.user{user}.rotation = params_inner.array_rotation_UE(user, :);

            % Location, LOS status, distance, pathloss, and channel path parameters
            DeepMIMO_dataset{t}.user{user}.loc=TX{t}.channel_params(user).loc;
            DeepMIMO_dataset{t}.user{user}.LoS_status=TX{t}.channel_params(user).LoS_status;
            DeepMIMO_dataset{t}.user{user}.distance=TX{t}.channel_params(user).distance;
            DeepMIMO_dataset{t}.user{user}.pathloss=TX{t}.channel_params(user).pathloss;
            DeepMIMO_dataset{t}.user{user}.path_params=rmfield(TX{t}.channel_params(user),{'loc','distance','pathloss'});

            c.increment();
        end

        %----- BS-BS Channels
        if params.enable_BS2BSchannels
            for BSreceiver=1:params.num_active_BS
                % Channel Construction
                if params.generate_OFDM_channels
                    [DeepMIMO_dataset{t}.basestation{BSreceiver}.channel]=construct_DeepMIMO_channel(params_inner.num_ant_BS(t, :), params_inner.array_rotation_BS(t,:), params_inner.ant_spacing_BS(t), params_inner.num_ant_BS(BSreceiver, :), params_inner.array_rotation_BS(BSreceiver,:), params_inner.ant_spacing_BS(BSreceiver), TX{t}.channel_params_BSBS(BSreceiver), params);
                else
                    [DeepMIMO_dataset{t}.basestation{BSreceiver}.channel]=construct_DeepMIMO_channel_TD(params_inner.num_ant_BS(t, :), params_inner.array_rotation_BS(t,:), params_inner.ant_spacing_BS(t), params_inner.num_ant_BS(BSreceiver, :), params_inner.array_rotation_BS(BSreceiver,:), params_inner.ant_spacing_BS(BSreceiver), TX{t}.channel_params_BSBS(BSreceiver), params);
                    DeepMIMO_dataset{t}.basestation{BSreceiver}.ToA=TX{t}.channel_params_BSBS(BSreceiver).ToA; %Time of Arrival/Flight of each channel path (seconds)
                end
                DeepMIMO_dataset{t}.basestation{BSreceiver}.rotation = params_inner.array_rotation_BS(BSreceiver, :);

                % Location, LOS status, distance, pathloss, and channel path parameters
                DeepMIMO_dataset{t}.basestation{BSreceiver}.loc=TX{t}.channel_params_BSBS(BSreceiver).loc;
                DeepMIMO_dataset{t}.basestation{BSreceiver}.LoS_status=TX{t}.channel_params_BSBS(BSreceiver).LoS_status;
                DeepMIMO_dataset{t}.basestation{BSreceiver}.distance=TX{t}.channel_params_BSBS(BSreceiver).distance;
                DeepMIMO_dataset{t}.basestation{BSreceiver}.pathloss=TX{t}.channel_params_BSBS(BSreceiver).pathloss;
                DeepMIMO_dataset{t}.basestation{BSreceiver}.path_params=rmfield(TX{t}.channel_params_BSBS(BSreceiver),{'loc','distance','pathloss'});

                c.increment();
            end
        end
    end

end


% JN Kather, NCT Heidelberg / RWTH Aachen, 2017-2018
% see separate LICENSE
%
% This MATLAB script is associated with the following project
% "Deep learning can predict microsatellite instability directly
% from histology in gastrointestinal cancer". Please consider citing this
% publication if you re-use the code
%
% Step 05:
% this is an important step: we will split all image tiles into train and
% test set. This is done on a patient level, that means each patient will
% be assigned to the train or test group and then all tiles of this patient
% will be moved to the train or test folder

clear variables, close all, clc
addpath(genpath('./subroutines/'));
sq = @(varargin) varargin';
doCopy = true; % if false, the images will not be copied (simulation run)

% define the path to the normalized tiles
cnst.tileInputPath = 'D:\Colorectal_MSI_Project\DX_TILES_NORM\'; % source folder
cnst.tileOutputPath = 'E:\DX_TILES_NORM_SPLIT\'; % where to save the train and test set
mkdir(cnst.tileOutputPath);

% define the path to the clinical data table and to the hypermutation data table
% this requires Microsoft Excel to be installed on the machine
cnst.cliniDataTable = './cliniData/merged_TCGA_TUM_clini_table_v1.xlsx';

% read all tiles, might take a while
tic,
allTiles = dir([cnst.tileInputPath,'*.png']);
toc
tic, allTileNames = sq(allTiles.name); toc
disp('successfully read all tile names');

% read clinical data (merged data)
cliniDat = readtable(cnst.cliniDataTable);
cliniPatient = cliniDat.submitter_id;
cliniTumor = cliniDat.project_id;
cliniMSI = cliniDat.MSIStatus;
cliniHiMut = cliniDat.Tota_Mutation_cnt; % extract hypermutated samples.
% hypermutated tumors will have a number here, all other will have NaN

%% MATCH IMAGE PATCHES WITH PATIENT LEVEL DATA FOR TABLE 1
matches = zeros(size(cliniPatient));
tic
for i = 1:numel(cliniPatient)
    currPat = cliniPatient{i}; % current patient name
    TF = contains(allTileNames,currPat); % match all tiles
    matches(i) = sum(TF); % how many tiles were matched to this patient
    if isempty(cliniMSI{i}) % if no MSI info is present, look for mutation data
        % the reason for this is that we have few MSI patients and we do
        % not want to miss any because the MSI field is empty. This will
        % affect only very few patients (8 STAD and 6 COAD patients)
        if isnan(cliniHiMut(i)) % set status not hypermutated
            msistat{i} = 'NA'; % no MSI data, not hypermutated
        else % set status hypermutated
            msistat{i} = 'MUT'; % no MSI data, but hypermutated (highly probable MSI)
        end
    else % set status MSS or MSI
        msistat{i} = cliniMSI{i};
    end
    if mod(i,25)==1
    disp(['progress: ',num2str(round(i/numel(cliniPatient)*100,1))]);
    end
end
toc

% how many MSI and MSS patients could be matched
imgmatch = matches>0;
msimatch = strcmp(msistat,'MSI-H')'&imgmatch; % these are known MSI-H patients
mutmatch = strcmp(msistat,'MUT')'&imgmatch;   % these patients have no MSI status but are hypermutated
mssmatch = strcmp(msistat,'MSS')'&imgmatch;   % these patients are MSS

disp(['I matched ',num2str(sum(msimatch)),' MSI-H patients']);
disp(['I matched ',num2str(sum(mutmatch)),' non-MSI-H MUT patients']);
disp(['I matched ',num2str(sum(mssmatch)),' MSS patients']);

%% RANDOMIZE PATIENTS
rng(1); % reset the random number generator for reproducibility
figure(1),clf, hold on
traintest = 0.70; % split the data set in a 70/30 ratio (approximate)

msitrain = msimatch & rand(size(msimatch))<traintest;
muttrain = mutmatch & rand(size(mutmatch))<traintest;
msstrain = mssmatch & rand(size(mssmatch))<traintest;

plot(1:numel(imgmatch),msitrain,'r.'),plot(1:numel(imgmatch),muttrain,'b.'),plot(1:numel(imgmatch),msstrain,'g.')

disp(['Training cohort contains ',num2str(sum(msitrain)),' MSI-H patients']);
disp(['Training cohort contains ',num2str(sum(muttrain)),' non-MSI-H MUT patients']);
disp(['Training cohort contains ',num2str(sum(msstrain)),' MSS patients']);

% everybody not in training set goes to test set
msitest = msimatch & ~msitrain;
muttest = mutmatch & ~muttrain;
msstest = mssmatch & ~msstrain;

plot(1:numel(imgmatch),msitest,'rx'),plot(1:numel(imgmatch),muttest,'bx'),plot(1:numel(imgmatch),msstest,'gx')

disp(['Test cohort contains ',num2str(sum(msitest)),' MSI-H patients']);
disp(['Test cohort contains ',num2str(sum(muttest)),' non-MSI-H MUT patients']);
disp(['Test cohort contains ',num2str(sum(msstest)),' MSS patients']);

%% COPY IMAGE TILES TO TRAIN AND TEST FOLDERS

% now copy the files to the actual folder. This might take a while.
if doCopy
moveImagesToFolder(cliniPatient,msitrain,cnst.tileInputPath,cnst.tileOutputPath,'msitrain');
moveImagesToFolder(cliniPatient,muttrain,cnst.tileInputPath,cnst.tileOutputPath,'muttrain');
moveImagesToFolder(cliniPatient,msstrain,cnst.tileInputPath,cnst.tileOutputPath,'msstrain');

moveImagesToFolder(cliniPatient,msitest,cnst.tileInputPath,cnst.tileOutputPath,'msitest');
moveImagesToFolder(cliniPatient,muttest,cnst.tileInputPath,cnst.tileOutputPath,'muttest');
moveImagesToFolder(cliniPatient,msstest,cnst.tileInputPath,cnst.tileOutputPath,'msstest');
end


% pop_icathresh() - main menu for choosing threshold for component
%                      rejection in EEGLAB.
%
% Usage:
%   >> [OUTEEG rej] = pop_icathresh(INEEG, threshval, rejmethod,
%                                      rejvalue, interact);
%
% Inputs:
%   INEEG      - input dataset
%   threshval  - values of thresholds for each of the 3 statistical
%                measures. Default is [] and the program uses the value
%                in the dataset.
%   rejmethod  - either 'percent', 'dataset' or 'current'. 'percent'
%                will reject a given percentage of components with
%                the highest value in one or several statistical
%                measure. 'dataset' will use an other dataset for
%                calibration. 'current' will use the current dataset
%                for calibration. Default is 'current'.
%   rejvalue   - percentage if rejmethod is 'percent', dataset number
%                if rejmethod is 'dataset' (no input if 'current'). If it
%                is a percentage, '25' for instance means that the 25%
%                independent components with the highest values of one
%                statistical measure are  rejected. Note that, one can
%                also enter one percentage per statistical value (such as
%                25 20 30).
%   interact   - interactive windows or just rejection
%
% Inputs:
%   OUTEEG     - output dataset with updated thresholds
%   rej        - new rejection array
%
% Graphic interface:
%   The graphic interface is divided into 3 parts. On the top, the
% experimenter chooses the basis for the component rejection (see
% rejmethod input). On the middle panel, the user can tune thresholds
% manually and plot the distribution of statistical values. Each time
% that setting of one of these two top panels is modified, the curve
% on the third panel are redrawn.
%   The third panel is composed of 3 graphs, one for each statistical
% measure. The blue curve on each graph indicates the accuracy of the
% measure to detect artifactual components and non-artifactual
% components of a dataset. Note that 'artifactual components are
% defined with the rejection methods fields on the top (if you use
% the percentage methods, these artifactual components may not actually
% be artifactual). For accurate rejection, one should first reject
% artifactual component manually and then set up the threshold to
% approximate this manual rejection. The green curve indicate the
% rejection when all measure are considered. Points on the blue and
% on the green curves indicate the position of the current threshold on
% the parametric curve. Not that for the green cumulative curve, this
% point is at the same location for all graphs.
%   How to tune the threshold? To tune the threshold, one should try to
% maximize the detection of non-artifactual components (because it is
% preferable to miss some artifactual components than to classify as
% artifactual non-artifact components).
%
% Author: Arnaud Delorme, CNL / Salk Institute, 2001
%
% See also: eeglab()

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

%PROBLEM: when the % is set and we change manually yhe threshold,
% the software comes back to the percentage rejection

% 01-25-02 reformated help & license -ad

function [EEG, rej, com] = pop_icathresh( EEG, threshval, rejmethod, rejvalue, interact);

com = [];
rej = EEG.reject.gcompreject;
if nargin < 1
	help pop_icathresh;
	return;
end;

if nargin < 2
	threshval = [];
end;
if nargin < 3
	rejmethod = 'current';
end;
if nargin < 4
	rejvalue = 25;
end;
if nargin < 5
	interact = 1;
end;
if ~isempty(threshval)
	EEG.reject.threshentropy = threshval(1);
	EEG.reject.threshkurtact = threshval(2);
	EEG.reject.threshkurtdist = threshval(3);
end;

tagmenu = 'pop_icathresh';

if ~isempty( findobj('tag', tagmenu))
	error('cannot open two identical windows, close the first one first');
end;

% the current rejection will be stored in userdata of the figure
% --------------------------------------------------------------
gcf = figure('visible', 'off', 'numbertitle', 'off', 'name', 'Choose thresholds', 'tag', tagmenu, 'userdata', rej);
pos = get(gca, 'position');
q = [pos(1) pos(2) 0 0];
s = [pos(3) pos(4) pos(3) pos(4)]./100;
axis off;

% definition of callbacks
% -----------------------

cb_cancel  = [  'userdat = get(gcbo, ''userdata'');' ... % restore thresholds
				'EEG.reject.threshentropy  = userdat{1};' ...
				'EEG.reject.threshkurtact  = userdat{2};' ...
				'EEG.reject.threshkurtdist = userdat{3};' ...
				'clear userdat; close(gcbf);' ];

drawgraphs  = [ 'if isempty( gcbf ), fig = gcf; else fig = gcbf; end;' ... % determine the figure handler
                'if get( findobj(''parent'', fig, ''tag'', ''Ipercent''), ''value'') == 1, ' ... % test if percentage
				'   perc = str2num(get( findobj(''parent'', fig, ''tag'', ''Ipercenttext''), ''String''));' ...
				'   if length(perc < 2), perc = [perc perc perc]; end;' ...
				'   perc = round((100-perc) * length( EEG.stats.compenta) / 100);' ... % convert the percentage
				'   method = zeros( size( EEG.stats.compenta ) );' ...
				'   [tmprej tmpindex] = sort(EEG.stats.compenta(:));' ...
				'   method( tmpindex(perc(1)+1:end) ) = 1;' ...
				'   set( findobj(''parent'', fig, ''tag'', ''entstring''), ''string'', num2str(tmprej(perc(1)+1)));' ... % update threshold
				'   [tmprej tmpindex] = sort(EEG.stats.compkurta(:));' ...
				'   method( tmpindex(perc(2)+1:end) ) = 1;' ...
				'   set( findobj(''parent'', fig, ''tag'', ''kurtstring''), ''string'', num2str(tmprej(perc(1)+1)));' ... % update threshold
				'   [tmprej tmpindex] = sort(EEG.stats.compkurtdist(:));' ...
				'   method( tmpindex(perc(3)+1:end) ) = 1;' ...
				'   set( findobj(''parent'', fig, ''tag'', ''kurtdiststring''), ''string'', num2str(tmprej(perc(1)+1)));' ... % update threshold
				'   allvalues = [EEG.stats.compenta(:) EEG.stats.compkurta(:) EEG.stats.compkurtdist(:) ];' ...
				'   clear perc tmprej tmpindex;' ...
                'end;' ...
				'if get( findobj(''parent'', fig, ''tag'', ''Iother''), ''value'') == 1, ' ... % test if other dataset
				'   di = str2num(get( findobj(''parent'', fig, ''tag'', ''Iothertext''), ''String''));' ...
				'   if isempty( di ), clear fig; return; end;' ...
				'   method    = ALLEEG(di).reject.gcompreject'';' ...
				'   allvalues = [ALLEEG(di).stats.compenta(:) ALLEEG(di).stats.compkurta(:) ALLEEG(di).stats.compkurtdist(:) ];' ...
				'   clear di;' ...
                'end;' ...
				'if get( findobj(''parent'', fig, ''tag'', ''Icurrent''), ''value'') == 1, ' ... % test if current dataset
				'   method = EEG.reject.gcompreject'';' ...
				'   allvalues = [EEG.stats.compenta(:) EEG.stats.compkurta(:) EEG.stats.compkurtdist(:) ];' ...
                'end;' ...
				'axes( findobj( ''parent'', fig, ''tag'', ''graphent'')); cla;' ...
                '[tmp1 tmp2 tmp3] = drawproba( method, allvalues, [0 EEG.reject.threshkurtact EEG.reject.threshkurtdist ], ' ...
				'   { ''&'' ''|'' }, EEG.reject.threshentropy, ''Entropy of activity'',''Artifact detection (%)'', ''Non-artifact detection (%)'');' ...
				'set(gca, ''tag'', ''graphent'');' ...
				'axes( findobj( ''parent'', fig, ''tag'', ''graphkurt'')); cla;' ...
                '[tmp1 tmp2 tmp3] = drawproba( method, allvalues, [EEG.reject.threshentropy 0 EEG.reject.threshkurtdist ], ' ...
				'   { ''&'' ''|'' }, EEG.reject.threshkurtact, ''Kurtosis of activity'', ''Artifact detection (%)'', '''');' ...
				'set(gca, ''tag'', ''graphkurt'');' ...
				'axes( findobj( ''parent'', fig, ''tag'', ''graphkurtdist'')); cla;' ...
                '[tmp1 tmp2 tmp3] = drawproba( method, allvalues, [EEG.reject.threshentropy EEG.reject.threshkurtact 0 ], ' ...
				'   { ''&'' ''|'' }, EEG.reject.threshkurtdist, ''Kurtosis of topography'', ''Artifact detection (%)'', '''');' ...
				'set(gca, ''tag'', ''graphkurtdist'');' ...
				'clear method allvalues fig;' ...
				];

cb_percent = [  'if isempty( gcbf ), fig = gcf; else fig = gcbf; end;' ... % determine the figure handler
                'set( findobj(''parent'', fig, ''tag'', ''Ipercent''), ''value'', 1);'...
				'set( findobj(''parent'', fig, ''tag'', ''Iother''), ''value'', 0);' ...
				'set( findobj(''parent'', fig, ''tag'', ''Icurrent''), ''value'', 0);' ...
				'set( findobj(''parent'', fig, ''tag'', ''Ipercenttext''), ''enable'', ''on'');' ...
				'set( findobj(''parent'', fig, ''tag'', ''Iothertext''), ''enable'', ''off''); clear fig;' drawgraphs ];

cb_other   = [  'if isempty( gcbf ), fig = gcf; else fig = gcbf; end;' ... % determine the figure handler
                'set( findobj(''parent'', fig, ''tag'', ''Iother''), ''value'', 1);'...
				'set( findobj(''parent'', fig, ''tag'', ''Ipercent''), ''value'', 0);' ...
				'set( findobj(''parent'', fig, ''tag'', ''Icurrent''), ''value'', 0);' ...
				'set( findobj(''parent'', fig, ''tag'', ''Ipercenttext''), ''enable'', ''off'');' ...
				'set( findobj(''parent'', fig, ''tag'', ''Iothertext''), ''enable'', ''on''); clear fig;' drawgraphs ];

cb_current = [  'if isempty( gcbf ), fig = gcf; else fig = gcbf; end;' ... % determine the figure handler
                'set( findobj(''parent'', fig, ''tag'', ''Icurrent''), ''value'', 1);'...
				'set( findobj(''parent'', fig, ''tag'', ''Iother''), ''value'', 0);' ...
				'set( findobj(''parent'', fig, ''tag'', ''Ipercent''), ''value'', 0);' ...
				'set( findobj(''parent'', fig, ''tag'', ''Ipercenttext''), ''enable'', ''off'');' ...
				'set( findobj(''parent'', fig, ''tag'', ''Iothertext''), ''enable'', ''off''); clear fig;' drawgraphs ];

cb_entropy  = [ 'EEG.reject.threshentropy = str2num(get(gcbo, ''string''));' ...
				drawgraphs ];
cb_kurtact  = [ 'EEG.reject.threshkurtact = str2num(get(gcbo, ''string''));' ...
				drawgraphs ];
cb_kurtdist  = [ 'EEG.reject.threshkurtdist = str2num(get(gcbo, ''string''));' ...
				drawgraphs ];

if interact
	cb_calrej = [ 'ButtonName=questdlg2( ''This will erase previous projections'', ''Confirmation'', ''CANCEL'', ''OK'', ''OK'');' ]
else
	cb_calrej = [ 'ButtonName= ''OK''' ];
end;
cb_calrej = [ cb_calrej ...
    		  'switch ButtonName,' ...
       	 	  '   case ''OK'',' ...
			  '    rej1 = find(EEG.stats.compenta > EEG.reject.threshentropy);' ...
			  '    rej2 = find(EEG.stats.compkurta > EEG.reject.threshkurtact);' ...
			  '    rej3 = find(EEG.stats.compkurtdist > EEG.reject.threshkurtdist);' ...
			  '    EEG.reject.gcompreject = (rej1 & rej2) | rej3;' ...
			  '    clear rej1 rej2 rej3;' ...
			  'end; clear ButtonName;' ];

% default value for rejection methods
% -----------------------------------
rejvalother = '';
rejvalpercent = '25';
switch rejmethod
	case 'percent', rejvalpercent = num2str( rejvalue);
	case 'dataset', rejvalother = num2str( rejvalue);
end;

% -----------------------------------------------------
allh = supergui(gcf, { 	[1] ...
					[2 1] [2 1] [2 1] ...
					[1] ...
					[1] ...
					[1.5 0.5 1] [1.5 0.5 1] [1.5 0.5 1] ...
					[1] [1] [1] [1] [1] [1] [1] [1] [1] [1] ...
					[1 1 1 1 1] ...
					}, [], ...
	{ 'Style', 'text', 'string', 'Calibration method', 'FontSize', 13, 'fontweight', 'bold' }, ...
	...
	{ 'style', 'checkbox', 'String', '% of artifactual components (can also put one % per rejection)', 'tag', 'Ipercent', 'value', 1, 'callback', cb_percent}, ...
	{ 'style', 'edit', 'String', rejvalpercent, 'tag', 'Ipercenttext', 'callback', drawgraphs }, ...
	...
	{ 'style', 'checkbox', 'String', 'Specific dataset (enter dataset number)', 'tag', 'Iother', 'value', 0, 'callback', cb_other}, ...
	{ 'style', 'edit', 'String', rejvalother, 'tag', 'Iothertext', 'enable', 'off', 'callback', drawgraphs }, ...
	...
	{ 'style', 'checkbox', 'String', 'Current dataset', 'tag', 'Icurrent', 'value', 0, 'callback', cb_current}, ...
	{ }, ...
	...
	{ }, ...
	...
	{ 'Style', 'text', 'string', 'Threshold values', 'FontSize', 13, 'fontweight', 'bold' }, ...
	...
	{ 'style', 'text', 'String', 'Entropy of activity threshold' }, ...
	{ 'style', 'edit', 'String', num2str(EEG.reject.threshentropy), 'tag', 'entstring', 'callback',  cb_entropy }, ...
	{ 'style', 'pushbutton', 'String', 'Histogram', 'callback', 'figure; hist(EEG.stats.compenta,20); title(''Entropy of activity'');' }, ...
	...
	{ 'style', 'text', 'String', 'Kurtosis of activity threshold' }, ...
	{ 'style', 'edit', 'String', num2str(EEG.reject.threshkurtact), 'tag', 'kurtstring', 'callback', cb_kurtact }, ...
	{ 'style', 'pushbutton', 'String', 'Histogram', 'callback', 'figure; hist(EEG.stats.compkurta,200); title(''Kurtosis of activity'');' },  ...
	...
	{ 'style', 'text', 'String', 'Kurtosis of topography threshold' }, ...
	{ 'style', 'edit', 'String', num2str(EEG.reject.threshkurtdist), 'tag', 'kurtdiststring', 'callback', cb_kurtdist }, ...
	{ 'style', 'pushbutton', 'String', 'Histogram', 'callback', 'figure; hist(EEG.stats.compkurtdist,20); title(''Kurtosis of topography'');' }, ...
	...
	{ }, { }, { }, { }, { }, { }, { }, { }, { }, { }, ...
	...
	{ 'style', 'pushbutton', 'String', 'Cancel', 'callback', cb_cancel, 'userdata', { EEG.reject.threshentropy EEG.reject.threshkurtact EEG.reject.threshkurtdist }}, ...
	{ 'style', 'pushbutton', 'String', 'Auto thresh'  , 'callback', '', 'enable', 'off' }, ...
	{ 'style', 'pushbutton', 'String', 'Help'  , 'callback', 'pophelp(''pop_icathresh'');' }, ...
	{ 'style', 'pushbutton', 'String', 'Accept thresh.' , 'callback', 'close(gcbf);' }, ...
	{ 'style', 'pushbutton', 'String', 'Calc. rejection' , 'callback', 'close(gcbf);' } ...
	...
	);

h = axes('position', [0  15 30 30].*s+q, 'tag', 'graphent');
h = axes('position', [35 15 30 30].*s+q, 'tag', 'graphkurt');
h = axes('position', [70 15 30 30].*s+q, 'tag', 'graphkurtdist');

rejmethod
switch rejmethod
	case 'dataset', eval([ 'gcbf = [];' cb_other]);
	case 'current', eval([ 'gcbf = [];' cb_current]);
	otherwise, eval([ 'gcbf = [];' cb_percent]);
end;

return;


function cell2txtfile(varargin)

% function cell2txtfile(fileName,T,skipOpt,checkChar)
% ------------------------------------------------------------------------
%
% This function exports the content in the cell array T to
% the text file fileName. Each entry in the cell array will be a line in
% the txt file. Prior to text file creation the cell is converted to a
% column format. If the input skipOpt=1 cell entries which appear empty
% (after spaces are removed) will be skipped.
%
% Kevin Mattheus Moerman
% gibbon.toolbox@gmail.com
%
% Change log:
% 2016/09/09: Updated for GIBBON
% 2016/09/09: Added conversion to char and associated warning for non-character content.
% 2018/02/14: Added whole cell conversion when skipOp==0
% 2018/02/14: Added varargin and defaults
%
% To do:
% * Proper handling of conversion of non-character entries (e.g. have user
% specify conversion format to use for numerical data).
%------------------------------------------------------------------------

%% parse input

switch nargin
    case 2
        fileName=varargin{1};
        T=varargin{2};
        skipOpt=0;
        checkChar=1;
    case 3
        fileName=varargin{1};
        T=varargin{2};
        skipOpt=varargin{3};
        checkChar=1;
    case 4
        fileName=varargin{1};
        T=varargin{2};
        skipOpt=varargin{3};
        checkChar=varargin{4};
end

% Force column if it isn't
if ~isvector(T)
    T=T(:);%Make column
end

% Convert non-character content to text
if checkChar==1
    indNotChar=find(~cellfun(@(x) ischar(x),T,'UniformOutput',1));
    if ~isempty(indNotChar)
        %warning('Non character entries detected');
        for q=indNotChar
            T{q}=vec2strIntDouble(T{q},'%6.7e');
        end
    end
end

%%
% Write to file

fid=fopen(fileName,'w');
switch skipOpt
    case 0 %Process in one go
        fprintf(fid,'%s\r\n', T{:});
    case 1 %Looping to check if lines are empty
        for q=1:numel(T)
            l=T{q}; %Get current cell entry
            if ~ischar(l) %If this isn't a char then attempt conversion
                l=sprintf('%u',l);
            end

            %Write if not empty
            if ~isempty(deblank(l))
                fprintf(fid,'%s\r\n',l);
            end
        end
end
fclose(fid);

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