function [p,str] = cluster_surf(varargin)
% Surface plot of clusters on a standard brain
%
%    WARNING: SURFACE_CUTAWAY, TOR_3D, AND CLUSTER_SURF ARE DEPRECATED.
%    THEY USE AN OLDER STYLE OF SURFACE RENDERING THAT IS VERY SLOW. THEY
%    STILL WORK, BUT OBJECT-ORIENTED CANLAB TOOLS HAVE SHIFTED TO USING
%    ADDBRAIN.M COMBINED WITH RENDER_ON_SURFACE() METHOD, WHICH USES
%    MATLAB'S ISOCOLORS FOR DRAMATICALLY FASTER COLOR RENDERING.
%
% :Usage:
% ::
%
%    [suface_handle,colorchangestring] = cluster_surf(varargin)
%
% :Inputs:
%
%   **CLUSTERS:**
%        clusters structures, as created in tor_extract_rois.m
%
%   **COLORS:**
%        cell array of colors for each cluster: {[1 0 0] [0 1 0] [0 0 1]}
%       if number of colors specified is greater than number of clusters
%       structures entered, n+1 and n+2 colors are overlap of 2 and overlap
%       of all clusters, respectively.
%
%   **SURFACE MAT FILE:**
%        file name of mat file containing brain surface vertices and faces
%       as created with isosurface.
%
%   **SPECIAL SURFACE KEYWORDS:**
%        special string: 'bg' 'hipp' (hcmp,thal,amy)
%        number of mm to plot from surface (mmdeep)
%
%          - Special keywords for sets of surfaces are:
%            left, right, bg, limbic, cerebellum, brainstem
%
%          - Other keywords: 'left' 'right' 'amygdala' 'thalamus' 'hippocampus' '
%            'midbrain'  'caudate'   'globus pallidus'  'putamen'  'nucleus accumbens'
%             'hypothalamus' 'cerebellum'
%
%   **EXISTING SURFACE HANDLE(S):**
%        Pass in handles for surface patches, created,
%        e.g., with addbrain.m.  This lets you be very flexible in the
%        surfaces you image onto.
%
%   **'colorscale':**
%        This scales colors by Z-scores of voxels if used
%          - Uses input color, unless also used with 'heatmap'
%          - Z scores should be in ROW vector
%          - use with 'normalize' to scale Z-scores between -1 and 1
%          - will also create transparent effects, mixing
%            blob color with existing surface color in linear
%            proportion to Z-scores
%
%   **'heatmap':**
%        Map Z-scores to surface colors
%          - Used WITH or instead of 'colorscale'
%          - Blobs can have a range of colors
%          - Use with REFERENCE RANGE option below to control scale
%          - solid colors entered as input will be ignored
%          - use with 'colormaps' option below to be flexible
%            in which color maps you apply.
%          - if 'colorscale' is also used, will produce transparent blobs.
%
%   **REFERENCE RANGE:**
%        reference Z-scores range, [zmin_act zmax_act
%        zmax_negact zmin_negact], e.g., [0 5 -5 0], use only
%        with 'heatmap' option
%        to get refZ from clusters, try:
%        ::
%
%            clZ = cat(2,clusters.Z);
%            refZ = [min(clZ(clZ > 0)) max(clZ) min(clZ(clZ < 0)) min(clZ)];
%
%   **'colormaps':**
%        - followed by custom [colors x 3] matrices for positive colors
%          and negative colors.
%        - matlab can create some: e.g., colormap summer, jet, etc.
%          others can be created with colormap_tor.m
%
%        color [0 1 1] (cyan) is reserved for the overlap color btwn cluster sets.
%
% :Examples:
% ::
% % ------------------------------------------------------------
% % ------------------------------------------------------------
%
%    P = 'C:\tor_scripts\3DheadUtility\canonical_brains\surf_single_subj_T1_gray.mat';
%    cluster_surf(tcl,acl,P,10,{[0 1 0] [1 0 0]},'colorscale','heatmap')
%
%    or P = h (surface handle) to use current surface in figure, and refZ
%    cluster_surf(tcl,acl,h,[3 5 -5 -3],10,{[0 1 0] [1 0 0]},'colorscale','heatmap')
%
% % A complete example visualizing a network on several surfaces
% % ------------------------------------------------------------
% % Load atlas
% atl = load_atlas('yeo17networks');
%
% % Select a network
% r = atlas2region(select_atlas_subset(atl, 1));
%
% % Check what it looks like on slices
% figure; montage(r);
%
% % Check what it looks like using surface() method
% % and render_on_surface()
%
% figure; surface(r);
%
% %% Run cluster_surf on several standard left-hemisphere surfaces
% % ------------------------------------------------------------
% create_figure('Left lateral surface', 2, 2);
% cluster_surf(r, 2, 'colors', {[1 1 0]}, 'hires left');
% view(275, 10); lightRestoreSingle;
% title('MNI Colin single-subj, addbrain(...''hires left'')');
%
% subplot(2, 2, 2);
% % Inflated surfaces: These use the pre-calculated mappers from MNI to an
% % inflated freesurfer cortical surface for each hemisphere:
% % which('lh.avgMapping_allSub_RF_ANTs_MNI152_orig_to_fsaverage.mat')
% % which('rh.avgMapping_allSub_RF_ANTs_MNI152_orig_to_fsaverage.mat')
% try
%     cluster_surf(r, 2, 'colors', {[1 1 0]}, 'fsavg_left');
%     view(275, 10); lightRestoreSingle;
%     title('Freesurfer average with Wu 2017 MNI->surf mapping');
% catch
%     disp('cannot find required surface file');
% end
%
% subplot(2, 2, 3);
% % Pial surface from Glasser_et_al_2016 Nature, HCP data
% % 'L.pial_MSMAll_2_d41_WRN_DeDrift.32k.mat';
% try
%     surf_han = addbrain('surface left');
%     cluster_surf(r, 2, 'colors', {[1 1 0]}, surf_han);
%     view(275, 10); lightRestoreSingle;
%     set(surf_han, 'FaceAlpha', 1);
%     title('HCP pial surface, addbrain(...''surface left'')');
% catch
%     title('cannot find required surface file');
% end
%
% subplot(2, 2, 4);
% % BigBrain surface, Amunts et al.
% % 'BigBrainSurfaceLeft.mat' in addbrain
% try
%     surf_han = addbrain('hires surface left');
%     cluster_surf(r, 2, 'colors', {[1 1 0]}, surf_han);
%     view(275, 10); lightRestoreSingle;
%     set(surf_han, 'FaceAlpha', 1);
%     title('Julich BigBrain, addbrain(...''hires surface left'')');
% catch
%     title('cannot find required surface file');
% end
%
% % ------------------------------------------------------------
%
% Example 2:
% Show all 32 L/R Hem Schafer/Yeo networks on the Julich BigBrain
%
% % ------------------------------------------------------------
%
% atl = load_atlas('yeo17networks');
%
% % Parse the atlas into a cell array with one cell per region
% % Each cell will be rendered in a different color
% clear region_cell
%
% for i = 1:num_regions(atl)
%
%     % Select a network
%     region_cell{i} = atlas2region(select_atlas_subset(atl, i));
%
% end
%
% create_figure('surface');
%
% % Seaborn colors....
% colors = seaborn_colors(num_regions(atl) ./ 2)';
% colors = [colors colors];
%
% % Or standard CANlab colors...
% colors = scn_standard_colors(num_regions(atl));
%
% surf_han = addbrain('bigbrain');
%
% cluster_surf(region_cell{:}, 3, 'colors', colors, surf_han);
% view(135, 12);
% lightRestoreSingle;
% set(surf_han, 'FaceAlpha', 1);
% title('HCP pial surface, addbrain(...''surface left'')');
%
% % ------------------------------------------------------------
% % ------------------------------------------------------------
% :More examples:
% ::
% % ------------------------------------------------------------
%
%    cluster_surf(cl,2,'heatmap');     % brain surface.  vertices colored @2 mm
%    cluster_surf(cl,2,'bg','heatmap');    % heatmap on basal ganglia
%    cluster_surf(cl,5,'left','heatmap');  % heatmap on left surface @5 mm
%    cluster_surf(cl,2,'right','heatmap');
%
%    % A multi-color, multi-threshold display on the cerebellum
%    colors = {[1 1 0] [1 .5 0] [1 .3 .3]};
%    tor_fig;
%    sh = cluster_surf(cl{3},colors(3),5,'cerebellum');
%    cluster_surf(cl{2},colors(2),5,sh);
%    cluster_surf(cl{1},colors(1),5,sh);
%
%    % Custom colormaps:
%    create_figure('Brain Surface'); cluster_surf(cl, 2, 'heatmap','left');
%
%    poscm = colormap_tor([.2 .2 .4], [1 1 0], [.9 .6 .1]);  %slate to orange to yellow
%    negcm = colormap_tor([0 0 1], [0 .3 1]);  % light blue to dark blue
%    create_figure('Brain Surface'); cluster_surf(cl, 2, 'heatmap', 'colormaps', poscm, negcm, 'left');
%
%    % Single-color transparent map (green):
%    cluster_surf(cl, 2, {[0 1 0]}, 'colorscale', p3(2), 'normalize');
%
% :See Also: addbrain, img2surf.m, surface() methods for objects,
% cluster_cutaways, render_on_surface()
%
%    WARNING: SURFACE_CUTAWAY, TOR_3D, AND CLUSTER_SURF
%    USE AN OLDER STYLE OF SURFACE RENDERING THAT IS VERY SLOW. THEY
%    STILL WORK, BUT OBJECT-ORIENTED CANLAB TOOLS HAVE SHIFTED TO USING
%    ADDBRAIN.M COMBINED WITH RENDER_ON_SURFACE() METHOD, WHICH USES
%    MATLAB'S ISOCOLORS FOR DRAMATICALLY FASTER COLOR RENDERING.
%    CLUSTER_SURF IS STILL USEFUL FOR INFLATED SURFACES, AND FOR RENDERING
%    MULTIPLE SETS OF REGIONS ON THE SAME BRAIN IN DIFFERENT COLORS, AND
%    WITH FLEXIBLE CONTROL OVER THE DISTANCE TO SURFACE.

% ..
%    Programmers' Notes
%    Created by Tor, a long time ago
%    updated Sept 2015 to keep up with matlab graphics and handle some weird
%    stuff with processing inputs.
%      - Figures are now scalars and we need to check for those first.
%      - Also changed default surface and colormap
%
%    Jan 2020: Updated to add 'noverbose' option, minor cosmetic code
%    cleanup
% ..

disp('Cluster_surf uses a type of surface rendering with cluster_surf that is deprecated')
disp('It still functions, but the new method based on isocolors is dramatically faster')

% -----------------------------------------------------------------------
%    set up input arguments and defaults
% -----------------------------------------------------------------------
mmdeep = 10;
cscale = 0;
heatm = 0;
viewdeg = [135 30];
cl = [];

P = which('surf_spm2_brain.mat');
P = which('surf_spm2_brain_1mm.mat');

% default color maps
% These match fmridisplay:
poscm = colormap_tor([1 .5 0], [1 1 0]);
negcm = colormap_tor([0 0 1], [0 1 1]);

actcolors = [];  % used with heatmap
donormalize = 0; % used with colorscale
adjust_var = [];

doverbose = true;
if any(strcmp(varargin,'noverbose')), doverbose = false; end % do first

% -----------------------------------------------------------------------
%    optional inputs
% -----------------------------------------------------------------------
clind = 1;
for i = 1:length(varargin)

    if isempty(varargin{i})
        % ignore it

    elseif isstruct(varargin{i}) || isa(varargin{i}, 'region')
        cl{clind} = varargin{i}; clind = clind+1;

    elseif iscell(varargin{i}), mycolors = varargin{i};

    elseif isstr(varargin{i})

        if strcmp(varargin{i},'noverbose'), doverbose = false;

        elseif strcmp(varargin{i},'colorscale'), cscale = 1;

        elseif strcmp(varargin{i},'normalize'), donormalize = 1;

        elseif strcmp(varargin{i},'heatmap'), heatm = 1;

        elseif strcmp(varargin{i},'colormaps')
            if doverbose, disp('Using custom color maps.'); end
            poscm = varargin{i + 1}; varargin{i + 1} = [];
            negcm = varargin{i + 2};  varargin{i + 2} = [];

        elseif  strcmp(varargin{i},'left')
            P = which('surf_spm2_left.mat'); %which('surf_single_subj_grayL.mat');
            viewdeg = [90 0];

        elseif  strcmp(varargin{i},'right')
            P = which('surf_spm2_right.mat'); %which('surf_single_subj_grayR.mat');
            viewdeg = [270 0];

        elseif  strcmp(varargin{i},'hires left')
            P = which('surf_spm2_brain_left.mat'); %which('surf_single_subj_grayL.mat');
            viewdeg = [90 0];

        elseif  strcmp(varargin{i},'hires right')
            P = which('surf_spm2_brain_right.mat'); %which('surf_single_subj_grayR.mat');
            viewdeg = [270 0];
        elseif strcmp(varargin{i},'fsavg_right') % uses freesurfer inflated brain
            % with Thomas Yeo group's RF_ANTs mapping
            % from MNI to Freesurfer. (https://doi.org/10.1002/hbm.24213)
            P = which('surf_freesurf_inflated_Right.mat');
            viewdeg = [270 0];
            adjust_var = 'fsavg_right'; % varargin for getVertexColors
        elseif strcmp(varargin{i},'fsavg_left') % uses freesurfer inflated brain
            P = which('surf_freesurf_inflated_Left.mat');
            viewdeg = [90 0];
            adjust_var = 'fsavg_left'; % varargin for getVertexColors
        else P = varargin{i};
        end

    elseif isnumeric(varargin{i}) && isscalar(varargin{i})
        % it's a number, mm deep to render (any face within mmdeep mm of a significant voxel will
        % be colored)
        mmdeep = varargin{i};

    elseif any(ishandle(varargin{i})) && ~all(ishandle(varargin{i}))
        % Note: some weird things are happening as fig handles are class
        % double, and not recognized as figs, but are figure handles.
        % hopefully this will work with strcmp()
        % do nothing, but fig handles may be passed in inadvertently?
        % sometimes passing in integers is interpreted as fig handles...
        % For example, passing in 0 as a double is interpreted as a root
        % graphics object. Not a good design feature of new graphics in
        % Matlab...

        % Do nothing here. Could be all numeric input.

    elseif any(ishandle(varargin{i})) && any(strcmp(get(varargin{i}, 'Type'), 'figure'))
        % all are handles, one is a figure

        disp('You passed in a figure handle.')

    elseif  all(ishandle(varargin{i})) && all(isa(varargin{i}, 'matlab.graphics.primitive.Patch'))  %% all(~isa(varargin{i}, 'matlab.ui.Figure'))
        % all are handles, and patches
        % OLD: Pre-2014:  all(ishandle(varargin{i})) && all(varargin{i} ~= round(varargin{i}))
        if doverbose, disp('Found surface patch handles - plotting on existing surfaces.'); end
        P = varargin{i}; % handle(s) for existing surface

        % get rid of later calls to other surfaces
        wh = find(strcmp(varargin,'left') | strcmp(varargin,'right') | strcmp(varargin,'hires left') | strcmp(varargin,'hires right'));
        for jj = 1:length(wh), varargin{wh(jj)} = []; end

    elseif any(ishandle(varargin{i})) && ~all(isa(varargin{i}, 'matlab.graphics.primitive.Patch'))
        % OLD:  Pre-2014: any(ishandle(varargin{i})) && all(varargin{i} ~= round(varargin{i}))
        % Note: some weird things are happening as fig handles are class
        % double, and not recognized as figs, but are figure handles.
        % hopefully this will work with strcmp()
        if doverbose
            disp('Found existing surface patch handles, but some are invalid.  Check handles.');
            error('Exiting')
        end

    elseif length(varargin{i}) > 1   % it's a vector
        refZ = varargin{i};

    else    % no idea
        warning('cluster_surf: Unknown input');

    end

end

if ~exist('cl', 'var') || isempty(cl)
    if doverbose, disp('cluster_surf.m: No clusters to plot.  Try addbrain for brain surfaces with no activation.'); end
    p = []; str = [];
    return
end

if ~exist('mycolors', 'var')
    mycolors = scn_standard_colors(length(cl));
end

if isempty(P)
    disp(['Cannot find: ' P]);
    P = spm_get(1,'*mat','Choose brain surface file');
end

if doverbose

    disp('cluster_surf')
    disp('___________________________________________')
    fprintf('\t%3.0f cluster structures entered\n',length(cl))
    disp('  Colors are:')

    for i = 1:length(mycolors)
        disp([' ' num2str(mycolors{i})])
    end

end

if length(mycolors) > length(cl)
    if doverbose, disp([' overlap color is ' num2str(mycolors{length(cl)+1})]), end
    ovlc = ['[' num2str(mycolors{length(cl)+1}) ']'];
else
    ovlc = '[0 1 1]';
end

if length(mycolors) > length(cl)+1 && length(cl) > 2
    if doverbose, disp([' all overlap color is ' num2str(mycolors{length(cl)+2})]), end
    aovlc = ['[' num2str(mycolors{length(cl)+2}) ']'];
else
    aovlc = '[1 1 1]';
end

%disp([' Surface stored in: ' P])
if doverbose
    fprintf(' Building XYZ coord list\n');
end

% -------------------------------------------------------------------------
% * build xyz list
%
% also get cscale values for each coordinate, and alphascale values if both
% heatmap and colorscale options are entered
% -------------------------------------------------------------------------
for i = 1:length(cl) % each cell is a whole vector of cl, not a single region

    xyz{i} = cat(2,cl{i}.XYZmm)';

    if cscale || heatm
        for j = 1:length(cl{i})
            if size(cl{i}(j).Z,1) > size(cl{i}(j).Z,2)
                cl{i}(j).Z = cl{i}(j).Z';
            end
        end
        Z{i} = cat(2,cl{i}.Z)';

        % order voxels from lowest to highest, so that peak colors
        % appear because they are plotted last
        tmp = [xyz{i} Z{i}];
        tmp = sortrows(tmp,4);
        xyz{i} = tmp(:,1:3);
        Z{i} = tmp(:,4);1 ./ mad(abs(Z{i}));

        if cscale
            if donormalize
                Z{i} = Z{i} ./ max(Z{i});
            end

            if heatm
                % treat colorscale as alpha scaling to add transparent blobs
                % (preserve existing surface; good for isosurface objects)

                Za = abs(Z{i});
                a = prctile(Za, 85);  % midpoint of Z{i} defines transparency 0.5
                b = 1./mad(Za); % multiplier for Z for sigmoid

                sZ = 1 ./ (1 + exp(-b*(Za-a)));

                % fix, if all constant
                sZ(isnan(sZ)) = 1;

                alphascale{i} = sZ;

                % this is further adusted based on radius
                alphascale{i} = 5 * alphascale{i} ./ mmdeep^3; % should be 3?
                %alphascale

            end

        else
            % if heat map only, set mycolor{1} = [1 1 1]
            mycolors{1} = [1 1 1];
        end
    end
end

% ------------------------------------------------------------
% for heatmap option: get actcolors
% -------------------------------------------------------------
if heatm
    if doverbose, fprintf(' Getting heat-mapped colors\n'); end
    if exist('refZ') == 1
        actcolors = get_actcolors(Z, refZ, poscm, negcm);
    else
        actcolors = get_actcolors(Z, [], poscm, negcm);
    end
end

% rearrange Z to map the negative peak later
if exist('Z', 'var')
    for i = 1:numel(Z)
        neg_idx = Z{i}<0;
        xyz{i}(neg_idx,:)=flipud(xyz{i}(neg_idx,:));
        Z{i}(neg_idx)=flipud(Z{i}(neg_idx));
        actcolors{i}(neg_idx,:)=flipud(actcolors{i}(neg_idx,:));
    end
end

% -------------------------------------------------------------------------
% * build function call
% -------------------------------------------------------------------------
if doverbose, fprintf(' Building color change function call\n'); end

if length(cl) > 2 && exist('aovlc') == 1
    str = ['[c,alld] = getVertexColors(xyz{1},p,mycolors{1},[.5 .5 .5],' num2str(mmdeep) ',''ovlcolor'',' ovlc ',''allcolor'',' aovlc];
else
    str = ['[c,alld] = getVertexColors(xyz{1},p,mycolors{1},[.5 .5 .5],' num2str(mmdeep) ',''ovlcolor'',' ovlc];
end

if heatm
    str = [str ',''colorscale'',actcolors{1}'];
    if cscale
        % treat colorscale as alpha scaling to add transparent blobs
        str = [str ',''alphascale'',alphascale{1}'];
    end
elseif cscale
    % cscale alone - treat cscale as color-mapping index for single
    % colors in actcolors
    str = [str ',''colorscale'',Z{1}'];
end

for i = 2:length(cl)
    str = [str ',''vert'',xyz{' num2str(i) '},mycolors{' num2str(i) '}'];
    if heatm
        str = [str ',''colorscale'',actcolors{' num2str(i) '}'];
        if cscale
            % treat colorscale as alpha scaling to add transparent blobs
            str = [str ',''alphascale'',alphascale{' num2str(i) '}'];
        end
    elseif cscale
        % cscale alone - treat cscale as color-mapping index for single
        % colors in actcolors
        str = [str ',''colorscale'',Z{' num2str(i) '}'];
    end
end

if ~isempty(adjust_var)
    str = [str ',''' adjust_var ''''];
end

if ~doverbose
    str = [str ', ''noverbose'''];
end

str = [str ');'];

%p = P(end);
%co = get(p, 'FaceVertexCData');
if exist('alphascale','var')
    alphascale{1} = alphascale{1} * 12;
end
%eval(str)
%set(p, 'FaceVertexCData', co);

% -------------------------------------------------------------------------
% * run brain surface
% -------------------------------------------------------------------------
if ishandle(P)      % no input file, use existing handle
    if doverbose
        fprintf(' Using existing surface image\n');
        fprintf(' Running color change.\n');
    end
    for i = 1:length(P)
        p = P(i);
        if doverbose, disp([' eval: ' str]), end
        eval(str)
    end
else
    % we have either an input file or a special string ('bg')
    if doverbose, fprintf(' Loading surface image\n'); end
    [dtmp,ftmp,etmp]=fileparts(P);

    if strcmp(etmp,'.mat')

        load(P);

        %%figure
        p = patch('Faces',faces,'Vertices',vertices,'FaceColor',[.5 .5 .5], ...
            'EdgeColor','none','SpecularStrength',.2,'FaceAlpha',1,'SpecularExponent',200);
        lighting gouraud;camlight right
        axis image;
        lightRestoreSingle(gca);
        %myLight = camlight(0,0);set(myLight,'Tag','myLight');
        %set(gcf, 'WindowButtonUpFcn', 'lightFollowView');lightFollowView

        view(viewdeg(1),viewdeg(2));
        drawnow

        % -------------------------------------------------------------------------
        % * run color change
        % -------------------------------------------------------------------------
        if doverbose
            fprintf(' Running color change.\n');
            disp([' eval: ' str])
        end
        eval(str);

        % this for subcortex stuff
    elseif strcmp(P,'bg')
        p = [];
        myp = addbrain('caudate');p = [p myp];
        run_colorchange(myp,str,xyz,mycolors);

        myp = addbrain('globus pallidus');p = [p myp];
        run_colorchange(myp,str,xyz,mycolors);

        myp = addbrain('putamen');p = [p myp];
        run_colorchange(myp,str,xyz,mycolors);

        set(myp,'FaceAlpha',1);

        axis image; axis vis3d; lighting gouraud; lightRestoreSingle(gca)

    elseif strcmp(P,'limbic')
        p = [];

        myp = addbrain('amygdala');p = [p myp];
        run_colorchange(myp,str,xyz, mycolors, actcolors);
        myp = addbrain('hypothalamus');p = [p myp];
        run_colorchange(myp,str,xyz, mycolors, actcolors);
        myp = addbrain('hippocampus');p = [p myp];
        run_colorchange(myp,str,xyz, mycolors, actcolors);
        myp = addbrain('thalamus');p = [p myp];
        run_colorchange(myp,str,xyz, mycolors, actcolors);
        myp = addbrain('nucleus accumbens');p = [p myp];
        run_colorchange(myp,str,xyz, mycolors, actcolors);

        myp = addbrain('left');p = [p myp];
        run_colorchange(myp,str,xyz, mycolors, actcolors);
        set(myp,'FaceAlpha',1);

        axis image; axis vis3d; lighting gouraud; lightRestoreSingle(gca)

    elseif strcmp(P,'brainstem')
        p = [];

        myp = addbrain('thalamus');p = [p myp];
        run_colorchange(myp,str,xyz, mycolors, actcolors);
        myp = addbrain('hypothalamus');p = [p myp];
        run_colorchange(myp,str,xyz, mycolors, actcolors);
        myp = addbrain('brainstem');p = [p myp];
        run_colorchange(myp,str,xyz, mycolors, actcolors);
        %myp = addbrain('caudate');p = [p myp];
        %run_colorchange(myp,str,xyz, mycolors, actcolors);

        view(90,10); axis image; axis vis3d; lighting gouraud; lightRestoreSingle(gca)

    elseif strcmp(P,'subcortex')
        p = [];

        myp = addbrain('thalamus');p = [p myp];
        run_colorchange(myp,str,xyz, mycolors, actcolors);
        myp = addbrain('hypothalamus');p = [p myp];
        run_colorchange(myp,str,xyz, mycolors, actcolors);
        myp = addbrain('brainstem');p = [p myp];
        run_colorchange(myp,str,xyz, mycolors, actcolors);
        myp = addbrain('amygdala');p = [p myp];
        run_colorchange(myp,str,xyz, mycolors, actcolors);
        run_colorchange(myp,str,xyz, mycolors, actcolors);
        myp = addbrain('hippocampus');p = [p myp];
        run_colorchange(myp,str,xyz, mycolors, actcolors);
        myp = addbrain('thalamus');p = [p myp];
        run_colorchange(myp,str,xyz, mycolors, actcolors);
        myp = addbrain('nucleus accumbens');p = [p myp];
        run_colorchange(myp,str,xyz, mycolors, actcolors);
        myp = addbrain('caudate');p = [p myp];
        run_colorchange(myp,str,xyz, mycolors, actcolors);
        myp = addbrain('putamen');p = [p myp];
        run_colorchange(myp,str,xyz, mycolors, actcolors);
        %         myp = addbrain('globus pallidus');p = [p myp];  %Seems to be missing from canonical folder
        %         run_colorchange(myp,str,xyz, mycolors, actcolors);

        view(90,10); axis image; axis vis3d; lighting gouraud; lightRestoreSingle(gca)

    elseif strcmp(P,'cerebellum') || strcmp(P,'amygdala') || strcmp(P,'hypothalamus') ...
            || strcmp(P,'thalamus') || strcmp(P,'midbrain') || strcmp(P,'caudate') ...
            || strcmp(P,'globus pallidus') || strcmp(P,'putamen') || strcmp(P,'nucleus accumbens') ...
            || strcmp(P,'hippocampus')
        % this uses addbrain and works with any of its keywords
        p = [];

        myp = addbrain(P);p = [p myp];
        run_colorchange(myp,str,xyz, mycolors, actcolors);

        view(90,10); axis image; axis vis3d; lighting gouraud; lightRestoreSingle(gca)

    else
        error('Must input mat surf file or img file to convert to surf')
    end

end % if ishandle

lighting gouraud
lightRestoreSingle(gca);
material dull
axis off
set(gcf,'Color','w')
%scn_export_papersetup(400);  % this will mess up movies!!

if doverbose
    disp('Finished!')
    disp('___________________________________________')
end

end % main function

function actcolor = get_actcolors(datavaluesets, refZ, poscm, negcm)

actcolor = map_data_to_colormap(datavaluesets, poscm, negcm, refZ);

end

function run_colorchange(myp, str, xyz, mycolors, actcolors)

set(myp,'FaceAlpha',1);

for i = 1:length(myp)
    p = myp(i);

    % get original color
    origcolor = get(p,'FaceColor');

    % color change
    eval(str);

    % change non-active back to original color
    vdat = get(p,'FaceVertexCData');
    wh = find(all(vdat == .5, 2));
    vdat(wh,:) = repmat(origcolor,length(wh),1);
    set(p,'FaceVertexCData',vdat);

end
p = myp;
lighting gouraud; lightRestoreSingle(gca);

end


function [estimate] = ft_inverse_dics(sourcemodel, sens, headmodel, dat, C, varargin)

% FT_INVERSE_DICS scans on pre-defined dipole locations with a single dipole
% and returns the beamformer spatial filter output for a dipole on every
% location.
%
% Use as
%   [estimate] = ft_inverse_dics(sourcemodel, sens, headmodel, dat, cov, ...)
% where
%   sourcemodel is the input source model, see FT_PREPARE_SOURCEMODEL
%   sens        is the gradiometer or electrode definition, see FT_DATATYPE_SENS
%   headmodel   is the volume conductor definition, see FT_PREPARE_HEADMODEL
%   dat         is the data matrix with the ERP or ERF
%   cov         is the data covariance or cross-spectral density matrix
% and
%   estimate    contains the estimated source parameters
%
% Additional input arguments should be specified as key-value pairs and can include
%   'Pr'               = power of the external reference channel
%   'Cr'               = cross spectral density between all data channels and the external reference channel
%   'refdip'           = location of dipole with which coherence is computed
%   'powmethod'        = can be 'trace' or 'lambda1'
%   'feedback'         = can be 'none', 'gui', 'dial', 'textbar', 'text', 'textcr', 'textnl' (default = 'text')
%   'fixedori'         = use fixed or free orientation,                 can be 'yes' or 'no'
%   'projectnoise'     = project noise estimate through filter,         can be 'yes' or 'no'
%   'realfilter'       = construct a real-valued filter,                can be 'yes' or 'no'
%   'keepfilter'       = remember the beamformer filter,                can be 'yes' or 'no'
%   'keepleadfield'    = remember the forward computation,              can be 'yes' or 'no'
%   'keepcsd'          = remember the estimated cross-spectral density, can be 'yes' or 'no'
%   'weightnorm'       = normalize the beamformer weights,              can be 'no', 'unitnoisegain' or 'nai'
%
% These options influence the forward computation of the leadfield
%   'reducerank'      = 'no' or number (default = 3 for EEG, 2 for MEG)
%   'backproject'     = 'yes' or 'no', in the case of a rank reduction this parameter determines whether the result will be backprojected onto the original subspace (default = 'yes')
%   'normalize'       = 'no', 'yes' or 'column' (default = 'no')
%   'normalizeparam'  = parameter for depth normalization (default = 0.5)
%   'weight'          = number or Nx1 vector, weight for each dipole position to compensate for the size of the corresponding patch (default = 1)
%
% These options influence the mathematical inversion of the cross-spectral density matrix
%  'lambda'           = regularisation parameter
%  'kappa'            = parameter for covariance matrix inversion
%  'tol'              = parameter for covariance matrix inversion
%
% If the dipole definition only specifies the dipole location, a rotating
% dipole (regional source) is assumed on each location. If a dipole moment
% is specified, its orientation will be used and only the strength will
% be fitted to the data.
%
% See also FT_SOURCEANALYSIS, FT_PREPARE_HEADMODEL, FT_PREPARE_SOURCEMODEL

% Copyright (C) 2003-2020, Robert Oostenveld and Jan-Mathijs Schoffelen
%
% 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$

if mod(nargin-5,2)
  % the first 5 arguments are fixed, the other arguments should come in pairs
  ft_error('invalid number of optional arguments');
end

% get the optional input arguments, or use defaults
Pr             = ft_getopt(varargin, 'Pr');
Cr             = ft_getopt(varargin, 'Cr');
refdip         = ft_getopt(varargin, 'refdip');
powmethod      = ft_getopt(varargin, 'powmethod');  % the default for this is set below
realfilter     = ft_getopt(varargin, 'realfilter'); % the default for this is set below
subspace       = ft_getopt(varargin, 'subspace');
feedback       = ft_getopt(varargin, 'feedback',      'text');
keepcsd        = ft_getopt(varargin, 'keepcsd',       'no');
keepfilter     = ft_getopt(varargin, 'keepfilter',    'no');
keepleadfield  = ft_getopt(varargin, 'keepleadfield', 'no');
projectnoise   = ft_getopt(varargin, 'projectnoise',  'yes');
fixedori       = ft_getopt(varargin, 'fixedori',      'no');
weightnorm     = ft_getopt(varargin, 'weightnorm',    'no');

% construct the low-level options for the covariance matrix inversion as key-value pairs, these are passed to FT_INV
invopt = {};
invopt = ft_setopt(invopt, 'lambda',    ft_getopt(varargin, 'lambda', 0));
invopt = ft_setopt(invopt, 'kappa',     ft_getopt(varargin, 'kappa'));
invopt = ft_setopt(invopt, 'tolerance', ft_getopt(varargin, 'tol'));
invopt = ft_setopt(invopt, 'method',    ft_getopt(varargin, 'invmethod'));

% construct the low-level options for the leadfield computation as key-value pairs, these are passed to FT_COMPUTE_LEADFIELD
leadfieldopt = {};
leadfieldopt = ft_setopt(leadfieldopt, 'reducerank',     ft_getopt(varargin, 'reducerank'));
leadfieldopt = ft_setopt(leadfieldopt, 'backproject',    ft_getopt(varargin, 'backproject'));
leadfieldopt = ft_setopt(leadfieldopt, 'normalize',      ft_getopt(varargin, 'normalize'));
leadfieldopt = ft_setopt(leadfieldopt, 'normalizeparam', ft_getopt(varargin, 'normalizeparam'));
leadfieldopt = ft_setopt(leadfieldopt, 'weight',         ft_getopt(varargin, 'weight'));

% convert the yes/no arguments to the corresponding logical values
keepfilter     = istrue(keepfilter);
keepleadfield  = istrue(keepleadfield);
keepcsd        = istrue(keepcsd);
projectnoise   = istrue(projectnoise);
fixedori       = istrue(fixedori);

% FIXME besides regular/complex lambda1, also implement a real version

% default is to use the largest singular value of the csd matrix, see Gross 2001
if isempty(powmethod)
  powmethod = 'lambda1';
end

% default is to be consistent with the original description of DICS in Gross 2001
if isempty(realfilter)
  realfilter = 'no';
end

% use these two logical flags instead of doing the string comparisons each time again
powtrace   = strcmp(powmethod, 'trace');
powlambda1 = strcmp(powmethod, 'lambda1');

if ~isempty(Cr)
  % ensure that the cross-spectral density with the reference signal is a column matrix
  Cr = Cr(:);
end

if isfield(sourcemodel, 'mom') && fixedori
  ft_error('you cannot specify a dipole orientation and fixedori simultaneously');
end

% flags to avoid calling isfield repeatedly in the loop over grid positions (saves a lot of time)
hasmom        = isfield(sourcemodel, 'mom');
hasleadfield  = isfield(sourcemodel, 'leadfield');
hasfilter     = isfield(sourcemodel, 'filter');
hassubspace   = isfield(sourcemodel, 'subspace');

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% find the dipole positions that are inside/outside the brain
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
if ~isfield(sourcemodel, 'inside')
  if hasfilter
    sourcemodel.inside = ~cellfun(@isempty, sourcemodel.filter);
  elseif hasleadfield
    sourcemodel.inside = ~cellfun(@isempty, sourcemodel.leadfield);
  else
    sourcemodel.inside = ft_inside_headmodel(sourcemodel.pos, headmodel);
  end
end

% convert to logical representation
sourcemodel = fixinside(sourcemodel);

if hasfilter && (fixedori || ~isequal(weightnorm, 'no'))
  ft_warning('with precomputed spatial filters a fixed orientation constraint or weight normalisation options are not applied');
end

% keep the original details on inside and outside positions
originside = sourcemodel.inside;
origpos    = sourcemodel.pos;

% select only the dipole positions inside the brain for scanning
sourcemodel.pos    = sourcemodel.pos(originside,:);
sourcemodel.inside = true(size(sourcemodel.pos,1),1);

if hasmom
  sourcemodel.mom = sourcemodel.mom(:,originside);
end

if hasfilter
  ft_info('using precomputed filters\n');
  sourcemodel.filter = sourcemodel.filter(originside);
elseif hasleadfield
  ft_info('using precomputed leadfields\n');
  sourcemodel.leadfield = sourcemodel.leadfield(originside);
else
  ft_info('computing forward model on the fly\n');
end

if hassubspace
  ft_info('using subspace projection\n');
  sourcemodel.subspace = sourcemodel.subspace(originside);
end

% dics has the following sub-methods, which depend on the function input arguments
% power only, cortico-muscular coherence and cortico-cortical coherence
if ~isempty(Cr) && ~isempty(Pr) && isempty(refdip)
  % compute cortico-muscular coherence, using reference cross spectral density
  submethod = 'dics_refchan';
elseif isempty(Cr) && isempty(Pr) && ~isempty(refdip)
  % compute cortico-cortical coherence with a dipole at the reference position
  submethod = 'dics_refdip';
  % check for forbidden options in combination with this submethod
  if hassubspace || ~isempty(subspace)
    ft_error('subspace projections are not supported for beaming cortico-cortical coherence');
  end
  if fixedori
    ft_error('fixed orientations are not supported for beaming cortico-cortical coherence');
  end
elseif isempty(Cr) && isempty(Pr) && isempty(refdip)
  % only compute power of a dipole at the grid positions
  submethod = 'dics_power';
else
  ft_error('invalid combination of input arguments for dics');
end

% it is difficult to give a quantitative estimate of lambda, therefore also
% support relative (percentage) measure that can be specified as string (e.g. '10%')
% the converted value needs to be passed on to ft_inv
lambda = ft_getopt(invopt, 'lambda');
if ~isempty(lambda) && ischar(lambda) && lambda(end)=='%'
  ratio  = sscanf(lambda, '%f%%');
  ratio  = ratio/100;
  lambda = ratio * trace(C)/size(C,1);
  if ~hassubspace
    invopt = ft_setopt(invopt, 'lambda', lambda);
  end
end

if projectnoise || strcmp(weightnorm, 'nai')
  % estimate the noise level in the covariance matrix by the smallest (non-zero) singular value
  % always needed for the NAI weight normalization case
  noise = svd(C);
  noise = noise(rank(C));
  % estimated noise floor is equal to or higher than lambda
  noise = max(noise, lambda);
end

% the inverse of the cross-spectral density matrix only has to be computed once for all dipoles
if hassubspace
  ft_notice('using source-specific subspace projection\n');
  % remember the original data prior to the voxel dependent subspace projection
  dat_pre_subspace = dat;
  C_pre_subspace = C;
  if strcmp(submethod, 'dics_refchan')
    Cr_pre_subspace = Cr;
    Pr_pre_subspace = Pr;
  end
elseif ~isempty(subspace)
  ft_notice('using data-specific subspace projection\n');
  % TODO implement an "eigenspace beamformer" as described in Sekihara et al. 2002 in HBM
  if numel(subspace)==1
    % interpret this as a truncation of the eigenvalue-spectrum
    % if <1 it is a fraction of the largest eigenvalue
    % if >=1 it is the number of largest eigenvalues
    dat_pre_subspace = dat;
    C_pre_subspace  = C;
    [u, s, v] = svd(real(C));
    if subspace<1
      subspace  = find(diag(s)./s(1,1) > subspace, 1, 'last');
    end

    C       = s(1:subspace,1:subspace);
    % this is equivalent to subspace*C*subspace' but behaves well numerically
    % by construction.
    invC     = diag(1./diag(C + lambda * eye(size(C))));
    subspace = u(:,1:subspace)';
    if ~isempty(dat), dat = subspace*dat; end

    if strcmp(submethod, 'dics_refchan')
      Cr = subspace*Cr;
    end

  else
    C_pre_subspace  = C;
    C               = subspace*C*subspace';
    % here the subspace can be different from the singular vectors of C, so we
    % have to do the sandwiching as opposed to line 256
    if strcmp(realfilter, 'yes')
      invC = ft_inv(real(C), invopt{:});
    else
      invC = ft_inv(C, invopt{:});
    end

    if strcmp(submethod, 'dics_refchan')
      Cr = subspace*Cr;
    end
  end
else
  if strcmp(realfilter, 'yes')
    % the filter is computed using only the leadfield and the inverse covariance or CSD matrix
    % therefore using the real-valued part of the CSD matrix here ensures a real-valued filter
    invC = ft_inv(real(C), invopt{:});
  else
    invC = ft_inv(C, invopt{:});
  end
end

if ~hassubspace
  % compute the square of invC, which might be needed for unitnoisegain or NAI constraint
  invC_squared = invC^2;
end

if strcmp(submethod, 'dics_refdip')
  % handle the reference dipole, this needs to be done only once, since in this implementation
  % no fancy pairwise dipole source model is assumed
  if isstruct(refdip) && isfield(refdip, 'filter') % check if precomputed filter is present
    assert(iscell(refdip.filter) && numel(refdip.filter)==1);
    filt1 = refdip.filter{1};
  else
    if ~isstruct(refdip)
      % this is very old behavior: refdip is assumed to be a 1x3 position vector
      refpos     = refdip; clear refdip;
      refdip.pos = refpos;
    end
    % now refdip is always a struct
    if isfield(refdip, 'leadfield') % check if precomputed leadfield is present
      assert(iscell(refdip.leadfield) && numel(refdip.leadfield)==1);
      lf1 = refdip.leadfield{1};
    elseif isfield(refdip, 'pos')
      assert(isnumeric(refdip.pos) && numel(refdip.pos)==3);
      lf1 = ft_compute_leadfield(refdip.pos, sens, headmodel, leadfieldopt{:});
    end
    if isfield(refdip, 'mom') % check for fixed orientation
      lf1 = lf1 * refdip.mom(:);
    end

    % construct the spatial filter
    switch weightnorm
      case 'nai'
        % Van Veen's Neural Activity Index
        ft_error('vector version of nai weight normalization is not implemented');
      case 'unitnoisegain'
        % filt*filt' = I
        % Unit-noise gain minimum variance (aka Borgiotti-Kaplan) beamformer
        denom = pinv(lf1' * invC * lf1);
        gamma = denom * (lf1' * invC_squared * lf1) * denom;

        % compute the spatial filter, as per eqn. 4.85
        filt1 = diag(1./sqrt(diag(gamma))) * denom * lf1' * invC;
      case 'arraygain'
        % filt*lf = ||lf||, applies to scalar leadfield, and to one of the possibilities of the vector version, eqn. 4.75
        lfn   = lf1./norm(lf1);
        filt1 = pinv(lfn' * invC * lfn) * lfn' * invC; % S&N eqn. 4.09 (scalar version), and eqn. 4.75 (vector version)
      case {'unitgain' 'no'}
        % this is the 'standard' unit gain constraint spatial filter: filt*lf=I, applies both to vector and scalar leadfields
        filt1 = pinv(lf1' * invC * lf1) * lf1' * invC; % Gross eqn. 3 & van Veen eqn. 23, use PINV/SVD to cover rank deficient leadfield
      otherwise
        ft_error('unsupported option for weightnorm');
    end
  end

  % compute the power of the reference dipole location
  if powlambda1
    Pr = lambda1(filt1 * C * ctranspose(filt1));      % compute the power at the first dipole location, Gross eqn. 8
  elseif powtrace
    Pr = real(trace(filt1 * C * ctranspose(filt1)));  % compute the power at the first dipole location
  end
end % if dics_refdip

% start the scanning with the proper metric
ft_progress('init', feedback, 'scanning grid');
for i=1:size(sourcemodel.pos,1)
  ft_progress(i/size(sourcemodel.pos,1), 'scanning grid %d/%d\n', i, size(sourcemodel.pos,1));

  if hasfilter
    % precomputed filter is provided, the leadfield is not needed
    filt = sourcemodel.filter{i};

  else
    if hasleadfield && hasmom && size(sourcemodel.mom, 1)==size(sourcemodel.leadfield{i}, 2)
      % reuse the leadfield that was previously computed and project
      lf = sourcemodel.leadfield{i} * sourcemodel.mom(:,i);
    elseif  hasleadfield &&  hasmom
      % reuse the leadfield that was previously computed but don't project
      lf = sourcemodel.leadfield{i};
    elseif  hasleadfield && ~hasmom
      % reuse the leadfield that was previously computed
      lf = sourcemodel.leadfield{i};
    elseif ~hasleadfield &&  hasmom
      % compute the leadfield for a fixed dipole orientation
      lf = ft_compute_leadfield(sourcemodel.pos(i,:), sens, headmodel, leadfieldopt{:}) * sourcemodel.mom(:,i);
    else
      % compute the leadfield
      lf = ft_compute_leadfield(sourcemodel.pos(i,:), sens, headmodel, leadfieldopt{:});
    end

    if hassubspace
      % do subspace projection of the forward model
      lforig = lf;
      lf = sourcemodel.subspace{i} * lf;
      % the cross-spectral density becomes voxel dependent due to the projection
      C    = sourcemodel.subspace{i} * C_pre_subspace * sourcemodel.subspace{i}';
      if strcmp(realfilter, 'yes')
        invC = ft_inv(sourcemodel.subspace{i} * real(C_pre_subspace) * sourcemodel.subspace{i}', invopt{:});
      else
        invC = ft_inv(sourcemodel.subspace{i} * C_pre_subspace * sourcemodel.subspace{i}', invopt{:});
      end
    elseif ~isempty(subspace)
      % do subspace projection of the forward model only
      lforig = lf;
      lf     = subspace * lf;

      % according to Kensuke's paper, the eigenspace bf boils down to projecting
      % the 'traditional' filter onto the subspace spanned by the first k eigenvectors
      % [u,s,v] = svd(C); filt = ESES*filt; ESES = u(:,1:k)*u(:,1:k)';
      % however, even though it seems that the shape of the filter is identical to
      % the shape it is obtained with the following code, the w*lf=I does not hold.
    end

    if fixedori
      switch(weightnorm)
        case {'unitnoisegain','nai'}
          % optimal orientation calculation for unit-noise gain beamformer,
          % (also applies nai weightnorm constraint), based on equation 4.47 from Sekihara & Nagarajan (2008)
          % the following is a reformulation of the generalized eigenproblem
          [v, d]        = eig(pinv(lf' * invC_squared *lf)*(lf' * invC *lf));
          [d, iv]       = sort(diag(d), 'descend');
          unitnoiseori  = v(:,iv(1));
          lf            = lf * unitnoiseori;
          estimate.ori{i} = unitnoiseori;
          estimate.eta(i) = d(1)./d(2); % ratio between largest and second largest eigenvalues
          if hassubspace, lforig = lforig * unitnoiseori; end

        case 'arraygain'
          % optimal orientation calculation for array-gain beamformer, Sekihara & Nagarajan eqn. 4.44
          [v, d]        = eig(pinv(lf' * invC *lf)*(lf' * lf));
          [d, iv]       = sort(diag(d), 'descend');
          arraygainori  = v(:,iv(1));
          lf            = lf * arraygainori;
          estimate.ori{i} = arraygainori;
          estimate.eta(i) = d(1)./d(2); % ratio between largest and second largest eigenvalues
          if hassubspace, lforig = lforig * arraygainori; end

        otherwise
          % compute the leadfield for the optimal dipole orientation that maximizes spatial filter output
          % subsequently the leadfield for only that dipole orientation will be used for the final filter computation
          % filt = pinv(lf' * invC * lf) * lf' * invC;
          % [u, s, v] = svd(real(filt * C * ctranspose(filt)));
          % in this step the filter computation is not necessary, use the quick way to compute the voxel level covariance (cf. van Veen 1997)
          [u, s, v]     = svd(real(pinv(lf' * invC *lf)));
          maxpowori     = u(:,1);
          lf            = lf * maxpowori;
          estimate.ori{i} = maxpowori;
          estimate.eta(i) = s(1,1)./s(2,2); % ratio between the first and second singular values
          if hassubspace, lforig = lforig * maxpowori; end
      end
    end

    % construct the spatial filter
    switch weightnorm
      case 'nai'
        % Van Veen's Neural Activity Index
        % below equation is equivalent to following:
        % filt = pinv(lf' * invC * lf) * lf' * invC;
        % filt = filt/sqrt(noise*filt*filt');
        % the scaling term in the denominator is sqrt of projected noise, as per eqn. 2.67 of Sekihara & Nagarajan 2008 (S&N)
        if fixedori
          filt = pinv(sqrt(noise * lf' * invC_squared * lf)) * lf' *invC; % based on S&N eqn. 4.08
        else
          ft_error('vector version of nai weight normalization is not implemented');
        end
      case 'unitnoisegain'
        % filt*filt' = I
        % Unit-noise gain minimum variance (aka Borgiotti-Kaplan) beamformer
        % below equation is equivalent to following:
        % filt = pinv(lf' * invC * lf) * lf' * invC;
        % filt = filt/sqrt(filt*filt');
        if fixedori
          filt = pinv(sqrt(lf' * invC_squared * lf)) * lf' *invC; % S&N eqn. 4.15
        else
          % compute the matrix that is used for scaling of the filter's rows, as per eqn. 4.83
          denom = pinv(lf' * invC * lf);
          gamma = denom * (lf' * invC_squared * lf) * denom;

          % compute the spatial filter, as per eqn. 4.85
          filt = diag(1./sqrt(diag(gamma))) * denom * lf' * invC;
        end
      case 'arraygain'
        % filt*lf = ||lf||, applies to scalar leadfield, and to one of the possibilities of the vector version, eqn. 4.75
        lfn  = lf./norm(lf);
        filt = pinv(lfn' * invC * lfn) * lfn' * invC; % S&N eqn. 4.09 (scalar version), and eqn. 4.75 (vector version)

      case {'unitgain' 'no'}
        % this is the 'standard' unit gain constraint spatial filter: filt*lf=I, applies both to vector and scalar leadfields
        filt = pinv(lf' * invC * lf) * lf' * invC; % Gross eqn. 3 & van Veen eqn. 23, use PINV/SVD to cover rank deficient leadfield

      otherwise
    end
  end

  cfilt = filt * C * ctranspose(filt); % Gross eqn. 4 and 5
  if powlambda1
    if size(cfilt,1) == 1
      % only 1 orientation, no need to do svd
      estimate.pow(i,1) = real(cfilt);
    else
      estimate.pow(i,1) = lambda1(cfilt);   % compute the power at the dipole location, Gross eqn. 8
    end
  elseif powtrace
    estimate.pow(i,1) = real(trace(cfilt)); % compute the power at the dipole location
  end

  if strcmp(submethod, 'dics_refchan')
    % compute the cross-spectrum between the dipole and the reference channel
    cfilt = filt*Cr; % Gross eqn. 6, replaces cfilt computed above
    if powlambda1
      coh = lambda1(cfilt)^2 / (estimate.pow(i,1) * Pr); % Gross eqn. 9
    elseif powtrace
      coh = norm(cfilt)^2 / (estimate.pow(i,1) * Pr);
    end
    estimate.coh(i,1) = coh;
  elseif strcmp(submethod, 'dics_refdip')
    % compute the cross-spectrum between the reference dipole and the dipole
    cfilt = filt1 * C * ctranspose(filt); % Gross eqn. 6, replaces cfilt computed above
    if powlambda1
      coh = lambda1(cfilt)^2 / (estimate.pow(i,1) * Pr); % Gross eqn. 9
    elseif powtrace
      coh = norm(cfilt)^2 / (estimate.pow(i,1) * Pr);
    end
    estimate.coh(i,1) = coh;
  end

  if keepcsd
    % keep the dipole's csd or the dipole-ref cross-spectrum in the output
    estimate.csd{i,1} = cfilt;
  end

  if projectnoise
    if powlambda1
      estimate.noise(i,1) = noise * lambda1(filt * ctranspose(filt));
    elseif powtrace
      estimate.noise(i,1) = noise * real(trace(filt * ctranspose(filt)));
    end
    if keepcsd
      estimate.noisecsd{i,1} = noise * filt * ctranspose(filt);
    end
  end

  if keepfilter
    if hassubspace
      estimate.filter{i,1} = filt*sourcemodel.subspace{i};
    elseif ~isempty(subspace)
      estimate.filter{i,1} = filt*subspace; % FIXME should this be subspace, or pinv(subspace)?
    else
      estimate.filter{i,1} = filt;
    end
  end

  if keepleadfield
    if ~isempty(subspace)
      estimate.leadfield{i,1} = lforig;
    else
      estimate.leadfield{i,1} = lf;
    end
  end

end % for each dipole position
ft_progress('close');

% reassign the estimated values over the inside and outside grid positions
estimate.inside  = originside;
estimate.pos     = origpos;

fnames_cell   = {'leadfield' 'filter' 'ori' 'csd' 'noisecsd' 'subspace'};
for k = 1:numel(fnames_cell)
  if isfield(estimate, fnames_cell{k})
    estimate.(fnames_cell{k})( originside) = estimate.(fnames_cell{k});
    estimate.(fnames_cell{k})(~originside) = {[]};
  end
end

fnames_scalar = {'pow' 'noise' 'eta' 'coh'};
for k = 1:numel(fnames_scalar)
  if isfield(estimate, fnames_scalar{k})
    estimate.(fnames_scalar{k})( originside) = estimate.(fnames_scalar{k});
    estimate.(fnames_scalar{k})(~originside) = nan;
  end
end

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% helper function to obtain the largest singular value
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function [s, ori] = lambda1(x)
% determine the largest singular value, which corresponds to the power along the dominant direction
[u, s, v] = svd(x);
s   = s(1);
ori = u(:,1);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% helper function to compute the pseudo inverse. This is the same as the
% standard MATLAB function, except that the default tolerance is twice as
% high.
%   Copyright 1984-2004 The MathWorks, Inc.
%   $Revision$  $Date: 2009/06/17 13:40:37 $
%   default tolerance increased by factor 2 (Robert Oostenveld, 7 Feb 2004)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
function X = pinv(A,varargin)
[m,n] = size(A);
if n > m
  X = pinv(A',varargin{:})';
else
  [U,S,V] = svd(A,0);
  if m > 1, s = diag(S);
  elseif m == 1, s = S(1);
  else s = 0;
  end
  if nargin == 2
    tol = varargin{1};
  else
    tol = 10 * max(m,n) * max(s) * eps;
  end
  r = sum(s > tol);
  if (r == 0)
    X = zeros(size(A'),class(A));
  else
    s = diag(ones(r,1)./s(1:r));
    X = V(:,1:r)*s*U(:,1:r)';
  end
end


function reconstructSelSearchHierarchyFromFz(varargin)
% reconstructSelSearchHierarchyFromFz(varargin)
%
% Reconstruct a Selective Search hierachy to find out which superpixels make up the image.
%
% Note that labelHistos require pixel-level ground-truth.
%
% Copyright by Holger Caesar, 2015

% Parse input
p = inputParser;
addParameter(p, 'dataset', SiftFlowDatasetMC);
addParameter(p, 'projectName', 'WeaklySupervisedLearning');
addParameter(p, 'segmentationNameSS', 'Uijlings2013-ks100-sigma0.8-colorTypesRgb'); %can also be used for Felzen regions (but then has to be equal to segmentationNameFz)
addParameter(p, 'segmentationNameFz', 'Felzenszwalb2004-k100-sigma0.8-colorTypesRgb');
addParameter(p, 'subset', 'all');
addParameter(p, 'overwrite', false); % replaces the fields added by this script, but keeps all other fields
addParameter(p, 'randomOrder', false);
parse(p, varargin{:});

dataset = p.Results.dataset;
projectName = p.Results.projectName;
segmentationNameSS = p.Results.segmentationNameSS;
segmentationNameFz = p.Results.segmentationNameFz;
subset = p.Results.subset;
overwrite = p.Results.overwrite;
randomOrder = p.Results.randomOrder;

% Make program reproducible
rng(42);

% Init
globalTimer = tic;
labelCount = dataset.labelCount; %#ok<NASGU>
imagesProcessed = 0;

% Get image list and image size
[imageList, imageCount] = dataset.getImageListSubset(subset);

% Randomize image order
if randomOrder,
    % Store old randomness
    seed = rng;

    % Create randomness and shuffle image list
    rng('shuffle');
    imageList = imageList(randperm(imageCount));

    % Reset
    rng(seed.Seed);
end;

% Create paths
global glFeaturesFolder;
segmentationFolderSS = fullfile(glFeaturesFolder, projectName, dataset.name, 'segmentations', segmentationNameSS);
segmentationFolderFz = fullfile(glFeaturesFolder, projectName, dataset.name, 'segmentations', segmentationNameFz);

for imageIdx = 1 : imageCount,
    imagesRemaining = imageCount - imageIdx;
    secsPerImage = toc(globalTimer) / imagesProcessed;
    minutesLeft = secsPerImage / 60 * imagesRemaining;
    fprintf('Reconstructing hierarchy for image %d of %d (%.1fmin left) ##\n', imageIdx, imageCount, minutesLeft);

    imageName = imageList{imageIdx};
    imageSize = dataset.getImageSize(imageName);

    % Get SS propBlobs
    segmentPathSS = fullfile(segmentationFolderSS, [imageName, '.mat']);
    segmentStructSS = load(segmentPathSS);
    propBlobsSS = segmentStructSS.propBlobs;
    if ~overwrite,
        if isfield(segmentStructSS, 'overlapList'),
            fprintf('Skipping file which has already been processed: %s\n', segmentPathSS);
            continue;
        end;
    end;

    % Get Fz propBlobs
    segmentPathFz = fullfile(segmentationFolderFz, [imageName, '.mat']);
    segmentStructFz = load(segmentPathFz, 'propBlobs');
    propBlobsFz = segmentStructFz.propBlobs;

    % Find superpixels in region proposals
    spCount = numel(propBlobsFz);
    blobSizesSS = [propBlobsSS.size]';
    for spIdx = 1 : spCount,
        candidates = find(blobSizesSS == propBlobsFz(spIdx).size);

        for candidateIdx = 1 : numel(candidates),
            regionIdx = candidates(candidateIdx);
            if isequal(propBlobsFz(spIdx), propBlobsSS(regionIdx)),
                break;
            end;
        end;
    end;

    % Find Fz segments among the SS regions
    overlapList = sparse(computeBlobOverlapAny(propBlobsFz, propBlobsSS, imageSize))';

    % Construct GT label histograms
    superPixelLabelHistos = [];

    % Store new information
    segmentStructSS.superPixelLabelHistos = superPixelLabelHistos;
    segmentStructSS.overlapList = overlapList;
    save(segmentPathSS, '-struct', 'segmentStructSS', '-v6');
    imagesProcessed = imagesProcessed + 1;
end;


function ok = validate(logger)
% Checks that an object of type Logger obeys certain rules that
% must always be true.
% Inputs:
%   logger: the object to be checked.
% Outputs:
%   ok: a boolean value indicating whether the object is valid.

assert(nargin==1)
assert(isa(logger,'Logger'))

ok = length(logger.fidlist)==length(logger.fidlevels);
ok = ok && length(logger.filenamelist)==length(logger.filenamefids);
ok = ok && length(logger.filenamelist)==length(logger.filenamelevels);
ok = ok && all(logger.fidlist > 0);
ok = ok && all(logger.filenamefids > 0);
ok = ok && all(logger.fidlevels >= 0);
ok = ok && all(logger.fidlevels < 256);
ok = ok && all(logger.filenamelevels >= 0);
ok = ok && all(logger.filenamelevels < 256);


function out = fatrix2_imask_array(st)
if isempty(st.imask)
	out = true([st.idim 1]);
else
	out = st.imask;
end


function [charge, chargeWithoutProtons] = getChargeFromInChI(InChI)
% Returns the charge from a given InChI string
%
% USAGE:
%
%    [charge, chargeWithoutProtons] = getChargeFromInChI(InChI)
%
% INPUT:
%    InChI:                   The Inchi Identifier - string
%
% OUTPUTS:
%    charge:                  The charge encoded in the `InChi` string (including protonation)
%    chargeWithoutProtons:    The charge encoded in the `InChi` ignoring the protonation state
%
% NOTE:
%
%    InChI Charge is defined in the charge layer and can be modified in the
%    proton layer. If nothing is defined, the compound is uncharged.
%    First: Discard any "Reconnected" parts, as those don't influence the
%    charge
%
% .. Author:
%       - Ronan Fleming, 23 Sept 09
%       - Thomas Pfau, May 2017, Updated

    InChI = regexprep(InChI,'/r.*','');

    %Charge Layer: (either at the end or at the start)
    q_layer = regexp(InChI,'/q(.*?)/|/q(.*?)$','tokens');
    %We need to store a potential change of charge in the fixed-H
    %layer, as we need to ignore that change later on.
    q_fixed_H_layer = regexp(InChI,'/f.*?/q(.*?)/|/f.*?/q(.*?)$','tokens');

    %proton layer
    p_layer = regexp(InChI,'/p(.*?)/|/p(.*?)$','tokens');

    chargeWithoutProtons = 0;

    if ~isempty(q_layer)
        %Get individual charges from splitted reactions.
        individualCharges = cellfun(@(x) {strsplit(x{1},';')},q_layer);
        %And calculate the charge by evaluating the individual components.
        chargeWithoutProtons = sum(cellfun(@(x) sum(cellfun(@(y) eval(y) , x)), individualCharges));
        if ~isempty(q_fixed_H_layer)
            individualCharges_fixed_H = cellfun(@(x) {strsplit(x{1},';')},q_fixed_H_layer);
            chargeWithoutProtons = chargeWithoutProtons - sum(cellfun(@(x) sum(cellfun(@(y) eval(y) , x)), individualCharges_fixed_H));
        end
    end

    proton_charges = 0;
    if ~isempty(p_layer)
        individualProtons = cellfun(@(x) {strsplit(x{1},';')},p_layer);
        proton_charges = cellfun(@(x) sum(cellfun(@(y) eval(y) , x)), individualProtons);
    end
    %The overall Charge is the combination of charge from protons and base
    %charge
    charge = proton_charges + chargeWithoutProtons;


classdef SuperEllipsePrinter < handle

    properties (Access = private)
        mesh
        outPutName
        iteration
    end

    methods (Access = public)

        function obj = SuperEllipsePrinter(cParams)
            obj.init(cParams)
        end

        function print(obj)
            dI.mesh            = obj.mesh;
            dI.outName         = obj.outPutName;
            dI.pdim            = '2D';
            dI.ptype           = 'MICRO';
            ps = PostProcessDataBaseCreator(dI);
            dB = ps.getValue();
            dB.printers = 'Density';
            postCase = 'Density';
            postProcess = Postprocess(postCase,dB);
            d.x = ones(size(obj.mesh.coord(:,1),1),1);
            postProcess.print(obj.iteration,d);
        end

        function captureImage(obj)
            f = obj.outPutName;
            it = obj.iteration;
            imagePath = '/home/alex/git-repos/MicroStructurePaper/';
            outPutNameImage = fullfile(imagePath,[f,num2str(it)]);
            inputFileName = fullfile('Output',f,[f,num2str(it),'.flavia.res']);
            sI.fileName = f;
            sI.outPutImageName = outPutNameImage;
            sI.inputFileName = inputFileName;
            imageCapturer = GiDImageCapturer(sI);
            imageCapturer.capture();
        end

    end

    methods (Access = private)

        function init(obj,cParams)
            obj.outPutName = cParams.outPutName;
            obj.mesh       = cParams.mesh;
            obj.iteration  = 0;
        end

    end

end


function inspect_bug1995

% DEPENDENCY ft_voumerealign ft_sourceplot

filename = dccnpath('/home/common/matlab/fieldtrip/data/test/latest/mri/dicom/19112010_JHORSCHIG.MR.FCDC_SEQUENCES_STANDARD_SEQUENCES.0002.0176.2010.11.19.12.08.01.265625.73007255.IMA');
mri = ft_read_mri(filename);

cfg =[];
cfg.method = 'interactive';
ft_volumerealign(cfg, mri);

cfg =[];
cfg.method = 'ortho';
% cfg.interactive = 'yes';
ft_sourceplot(cfg, mri);


% Script: call_llforecast.m
% -----------------------
% Script to input parameters for an Omori law fit
% Calculation is done in function plot_fitloglike_a2
% The function works on the catalog newt2!!!
% J.Woessner
% last update: 10.07.03

report_this_filefun(mfilename('fullpath'));
% Get input parameters
prompt  = {,'Enter length of learning period (days)','Enter forecast period (days):','Enter number of bootstraps:'};
title   = 'Parameters ';
lines= 1;
def     = {'50','50','100'};
answer  = inputdlg(prompt,title,lines,def);
time = str2double(answer{1});
timef = str2double(answer{2});
bootloops = str2double(answer{3});

% maepi is the mainshock of sequence
plot_fitloglike_a2(newt2,time,timef,bootloops,maepi);


function genBox( obb, filename )
%GENBOX
cornerpoints = OBBrep2cornerpoints(obb);

fid = fopen(filename,'w');
for i = 1:size(cornerpoints,1)
	fprintf(fid, 'v  %f  %f  %f \n', cornerpoints(i,3), cornerpoints(i,1), cornerpoints(i,2));
end
fprintf(fid, 'f  %d  %d  %d %d \n', 4, 8, 7, 3);
fprintf(fid, 'f  %d  %d  %d %d \n', 8, 6, 5, 7);
fprintf(fid, 'f  %d  %d  %d %d \n', 6, 2, 1, 5);
fprintf(fid, 'f  %d  %d  %d %d \n', 2, 4, 3, 1);
fprintf(fid, 'f  %d  %d  %d %d \n', 4, 2, 6, 8);
fprintf(fid, 'f  %d  %d  %d %d \n', 7, 5, 1, 3);
fclose(fid);

end


% Defines the class currentSourceViewer for visualization of EEG inverse solutions on a realistic head model.
% This class is part of MoBILAB software.
% For more details visit:  https://code.google.com/p/mobilab/
%
% Author: Alejandro Ojeda, SCCN/INC/UCSD, Jan-2012

classdef currentSourceViewer < handle
    properties
        hFigure
        hAxes
        streamObj
        hLabels
        hSensors
        hScalp
        hCortex
        hVector
        dcmHandle
        sourceMagnitud
        sourceOrientation
        scalpData
        pointer
        clim
    end
    methods
        function obj = currentSourceViewer(streamObj,J,V,figureTitle,channelLabels)
            if nargin < 3, V = [];end
            if nargin < 4, figureTitle = '';end
            if nargin < 5
                channelLabels = cell(size(V,1),1);
                for it=1:length(channelLabels), channelLabels{it} = num2str(it);end
            end
            if isempty(channelLabels)
                channelLabels = cell(size(V,1),1);
                for it=1:length(channelLabels), channelLabels{it} = num2str(it);end
            end
            obj.streamObj = streamObj;
            load(obj.streamObj.surfaces);
            color = [0.93 0.96 1];

            path = fileparts(which('currentSourceViewer'));
            loc = strfind(path,'mobilab');
            if ~isempty(loc)
                path = path(1:loc+length('mobilab')-1);
            end
            path = fullfile(path,'skin');

            try labelsOn  = imread([path filesep 'labelsOn.png']);
                labelsOff = imread([path filesep 'labelsOff.png']);
                sensorsOn = imread([path filesep 'sensorsOn.png']);
                sensorsOff = imread([path filesep 'sensorsOff.png']);
                scalpOn = imread([path filesep 'scalpOn.png']);
                scalpOff = imread([path filesep 'scalpOff.png']);
                vectorOn = imread([path filesep 'vectorOn.png']);
                vectorOff = imread([path filesep 'vectorOff.png']);
                prev = imread([path filesep '32px-Gnome-media-seek-backward.svg.png']);
                next = imread([path filesep '32px-Gnome-media-seek-forward.svg.png']);
            catch ME
                ME.rethrow;
            end
            if isa(streamObj,'struct'), visible = 'off';else visible = 'on';end
            obj.hFigure = figure('Menubar','figure','ToolBar','figure','renderer','opengl','Visible',visible,'Color',color,'Name',figureTitle);
            position = get(obj.hFigure,'Position');
            set(obj.hFigure,'Position',[position(1:2) 1.06*position(3:4)]);
            obj.hAxes = axes('Parent',obj.hFigure);
            toolbarHandle = findall(obj.hFigure,'Type','uitoolbar');

            hcb(1) = uitoggletool(toolbarHandle,'CData',labelsOff,'Separator','on','HandleVisibility','off','TooltipString','Labels On/Off','userData',{labelsOn,labelsOff},'State','off');
            set(hcb(1),'OnCallback',@(src,event)rePaint(obj,hcb(1),'labelsOn'),'OffCallback',@(src, event)rePaint(obj,hcb(1),'labelsOff'));

            hcb(2) = uitoggletool(toolbarHandle,'CData',sensorsOff,'Separator','off','HandleVisibility','off','TooltipString','Sensors On/Off','userData',{sensorsOn,sensorsOff},'State','off');
            set(hcb(2),'OnCallback',@(src,event)rePaint(obj,hcb(2),'sensorsOn'),'OffCallback',@(src, event)rePaint(obj,hcb(2),'sensorsOff'));

            hcb(3) = uitoggletool(toolbarHandle,'CData',scalpOff,'Separator','off','HandleVisibility','off','TooltipString','Scalp On/Off','userData',{scalpOn,scalpOff},'State','off');
            set(hcb(3),'OnCallback',@(src,event)rePaint(obj,hcb(3),'scalpOn'),'OffCallback',@(src, event)rePaint(obj,hcb(3),'scalpOff'));

            hcb(4) = uitoggletool(toolbarHandle,'CData',vectorOff,'Separator','off','HandleVisibility','off','TooltipString','Vectors On/Off','userData',{vectorOn,vectorOff},'State','off');
            set(hcb(4),'OnCallback',@(src,event)rePaint(obj,hcb(4),'vectorOn'),'OffCallback',@(src, event)rePaint(obj,hcb(4),'vectorOff'));

            uipushtool(toolbarHandle,'CData',prev,'Separator','off','HandleVisibility','off','TooltipString','Previous','ClickedCallback',@obj.prev);
            uipushtool(toolbarHandle,'CData',next,'Separator','off','HandleVisibility','off','TooltipString','Next','ClickedCallback',@obj.next);
            set(obj.hFigure,'WindowScrollWheelFcn',@(src, event)mouseMove(obj,[], event));

            obj.dcmHandle = datacursormode(obj.hFigure);
            obj.dcmHandle.SnapToDataVertex = 'off';
            set(obj.dcmHandle,'UpdateFcn',@(src,event)showLabel(obj,event));
            obj.dcmHandle.Enable = 'off';
            hold(obj.hAxes,'on');

            obj.hSensors = scatter3(obj.hAxes,obj.streamObj.channelSpace(:,1),obj.streamObj.channelSpace(:,2),...
                obj.streamObj.channelSpace(:,3),'filled','MarkerEdgeColor','k','MarkerFaceColor','y');
            set(obj.hSensors,'Visible','off');

            N = length(channelLabels);
            k = 1.1;
            obj.hLabels = zeros(N,1);
            for it=1:N, obj.hLabels(it) = text('Position',k*obj.streamObj.channelSpace(it,:),'String',channelLabels{it},'Parent',obj.hAxes);end
            set(obj.hLabels,'Visible','off');

            if size(J,1) == 3*size(surfData(end).vertices,1)
                J = reshape(J,[size(J,1)/3 3 size(J,2)]);
                Jm = squeeze(sqrt(sum(J.^2,2)));
                normals = J;
            else
                Jm = J;
                normals = geometricTools.getSurfaceNormals(surfData(end).vertices,surfData(end).faces,false);
            end
            obj.sourceMagnitud = Jm;
            obj.sourceOrientation = J;
            obj.pointer = 1;

            % vectors
            obj.hVector = quiver3(surfData(end).vertices(:,1),surfData(end).vertices(:,2),surfData(end).vertices(:,3),normals(:,1,1),normals(:,2,1),normals(:,3,1),2);
            set(obj.hVector,'Color','k','Visible','off');

            % cortex
            obj.hCortex = patch('vertices',surfData(end).vertices,'faces',surfData(end).faces,'FaceVertexCData',obj.sourceMagnitud(:,1),...
                'FaceColor','interp','FaceLighting','phong','LineStyle','none','FaceAlpha',1,'SpecularColorReflectance',0,...
                'SpecularExponent',50,'SpecularStrength',0.5,'Parent',obj.hAxes);
            camlight(0,180)
            camlight(0,0)

            % scalp
            if isempty(V)
                skinColor = [1,.75,.65];
                obj.hScalp = patch('vertices',surfData(1).vertices,'faces',surfData(1).faces,'facecolor',skinColor,...
                    'facelighting','phong','LineStyle','none','FaceAlpha',.85,'Parent',obj.hAxes,'Visible','off');
                obj.scalpData = [];
            else
                W = geometricTools.localGaussianInterpolator(obj.streamObj.channelSpace,surfData(1).vertices,32);
                obj.scalpData = W*V;
                obj.hScalp = patch('vertices',surfData(1).vertices,'faces',surfData(1).faces,'FaceVertexCData',obj.scalpData(:,1),...
                    'FaceColor','interp','FaceLighting','phong','LineStyle','none','FaceAlpha',0.85,'SpecularColorReflectance',0,...
                    'SpecularExponent',50,'SpecularStrength',0.5,'Parent',obj.hAxes,'Visible','off');
            end
            view(obj.hAxes,[90 0]);

            disp('Calibrating the color scale...')
            mxsrc = obj.getRobustLimits(obj.sourceMagnitud(:),10);
            mxscp = obj.getRobustLimits(obj.scalpData,1);
            obj.clim = struct('source',[-mxsrc mxsrc],'scalp',[-mxscp mxscp]);
            disp('Done.')

            colorbar
            % box on;
            hold(obj.hAxes,'off');
            axis(obj.hAxes,'equal','vis3d');
            axis(obj.hAxes,'off')
            set(obj.hAxes,'Clim',obj.clim.source);
            try
                colormap(bipolar(512, 0.99))
            catch
                warning('Bipolar colormap is missing, fallback with jet.')
            end
            if isprop(streamObj,'name'), objName = [streamObj.name ': '];else objName = '';end
            set(obj.hFigure,'Visible',visible,'userData',obj,'Name',[objName num2str(1) '/' num2str(size(obj.sourceMagnitud,2))]);
            rotate3d
            drawnow
        end
        function [mx,mn] = getRobustLimits(obj,vect,th)
            if isempty(vect)
                mx = 1;
                mn = -1;
                return
            end
            samples = unidrnd(numel(vect),round(0.75*numel(vect)),20);
            prc = prctile(vect(samples),[th 100-th]);
            mn = median(prc(1,:));
            mx = median(prc(2,:));
            if mx == mn && mx == 0
                mx = max(vect(:));
                mn = min(vect(:));
            end
        end
       %%
        function rePaint(obj,hObject,opt)
            CData = get(hObject,'userData');
            if isempty(strfind(opt,'Off'))
                set(hObject,'CData',CData{2});
            else
                set(hObject,'CData',CData{1});
            end
            switch opt
                case 'labelsOn'
                    set(obj.hLabels,'Visible','on');
                case 'labelsOff'
                    set(obj.hLabels,'Visible','off');
                case 'sensorsOn'
                    set(obj.hSensors,'Visible','on');
                case 'sensorsOff'
                    set(obj.hSensors,'Visible','off');
                case 'scalpOn'
                    set(obj.hCortex,'FaceAlpha',0.15);
                    if strcmp(get(obj.hVector,'Visible'),'on')
                        set(obj.hScalp,'Visible','on','FaceAlpha',0.65);
                    else
                        set(obj.hScalp,'Visible','on','FaceAlpha',0.85);
                    end
                    set(get(obj.hScalp,'Parent'),'Clim',obj.clim.scalp);
                case 'scalpOff'
                    set(obj.hScalp,'Visible','off');
                    set(obj.hCortex,'Visible','on','FaceAlpha',1);
                    set(get(obj.hCortex,'Parent'),'Clim',obj.clim.source);
                case 'vectorOn'
                    set(obj.hVector,'Visible','on');
                    set(obj.hCortex,'FaceAlpha',0.75);
                case 'vectorOff'
                    set(obj.hVector,'Visible','off');
                    set(obj.hCortex,'FaceAlpha',1);
            end
        end
        %%
        function output_txt = showLabel(obj,event_obj)
            persistent DT
            if strcmp(obj.dcmHandle.Enable,'off'),return;end
            if strcmp(get(obj.hVector,'Visible'),'on')
                set(obj.hVector,'Visible','off');
                set(obj.hCortex,'FaceAlpha',1);
            end
            if isempty(DT)
                load(obj.streamObj.surfaces);
                vertices = surfData(end).vertices;
                DT = DelaunayTri(vertices(:,1),vertices(:,2),vertices(:,3));
            end
            pos = get(event_obj,'Position');
            loc = nearestNeighbor(DT, pos);
            output_txt = obj.streamObj.atlas.label{obj.streamObj.atlas.colorTable(loc)};
            drawnow
            %updateCursor(obj.dcmHandle,pos);
        end
        %%
        function prev(obj,~,~)
            obj.pointer = obj.pointer-1;
            if obj.pointer < 1, obj.pointer = 1;end
            val = obj.sourceMagnitud(:,obj.pointer);
            set(obj.hCortex,'FaceVertexCData',val);
            if isprop(obj.streamObj,'name'), objName = [obj.streamObj.name ': '];else objName = '';end
            set(obj.hFigure,'Name',[objName num2str(obj.pointer) '/' num2str(size(obj.sourceMagnitud,2))]);
            if isempty(obj.scalpData), drawnow;return;end
            val = obj.scalpData(:,obj.pointer);
            set(obj.hScalp,'FaceVertexCData',val);
            try %#ok
                set(obj.hVector,'UData',obj.sourceOrientation(:,1,obj.pointer),'VData',obj.sourceOrientation(:,2,obj.pointer),'WData',obj.sourceOrientation(:,3,obj.pointer));
            end
        end
        function next(obj,~,~)
            obj.pointer = obj.pointer+1;
            n = size(obj.sourceMagnitud,2);
            if obj.pointer > n, obj.pointer = n;end
            val = obj.sourceMagnitud(:,obj.pointer);
            set(obj.hCortex,'FaceVertexCData',val);
            if isprop(obj.streamObj,'name'), objName = [obj.streamObj.name ': '];else objName = '';end
            set(obj.hFigure,'Name',[objName num2str(obj.pointer) '/' num2str(size(obj.sourceMagnitud,2))]);
            if isempty(obj.scalpData), drawnow;return;end
            val = obj.scalpData(:,obj.pointer);
            set(obj.hScalp,'FaceVertexCData',val);
            try %#ok
                set(obj.hVector,'UData',obj.sourceOrientation(:,1,obj.pointer),'VData',obj.sourceOrientation(:,2,obj.pointer),'WData',obj.sourceOrientation(:,3,obj.pointer));
            end
            drawnow
        end
        function mouseMove(obj,~,eventObj)
            obj.pointer = obj.pointer - eventObj.VerticalScrollCount;%*eventObj.VerticalScrollAmount;
            if obj.pointer < 1, obj.pointer = 1;end
            if obj.pointer > size(obj.sourceMagnitud,2), obj.pointer = size(obj.sourceMagnitud,2);end
            val = obj.sourceMagnitud(:,obj.pointer);
            if isprop(obj.streamObj,'name'), objName = [obj.streamObj.name ': '];else objName = '';end
            set(obj.hFigure,'Name',[objName num2str(obj.pointer) '/' num2str(size(obj.sourceMagnitud,2))]);
            set(obj.hCortex,'FaceVertexCData',val);
            if isempty(obj.scalpData), drawnow;return;end
            val = obj.scalpData(:,obj.pointer);
            set(obj.hScalp,'FaceVertexCData',val);
        end
    end
end


function varargout = encriptacionprograma(varargin)
%ENCRIPTACIONPROGRAMA M-file for encriptacionprograma.fig
%      ENCRIPTACIONPROGRAMA, by itself, creates a new ENCRIPTACIONPROGRAMA or raises the existing
%      singleton*.
%
%      H = ENCRIPTACIONPROGRAMA returns the handle to a new ENCRIPTACIONPROGRAMA or the handle to
%      the existing singleton*.
%
%      ENCRIPTACIONPROGRAMA('Property','Value',...) creates a new ENCRIPTACIONPROGRAMA using the
%      given property value pairs. Unrecognized properties are passed via
%      varargin to encriptacionprograma_OpeningFcn.  This calling syntax produces a
%      warning when there is an existing singleton*.
%
%      ENCRIPTACIONPROGRAMA('CALLBACK') and ENCRIPTACIONPROGRAMA('CALLBACK',hObject,...) call the
%      local function named CALLBACK in ENCRIPTACIONPROGRAMA.M with the given input
%      arguments.
%
%      *See GUI Options on GUIDE's Tools menu.  Choose "GUI allows only one
%      instance to run (singleton)".
%
% See also: GUIDE, GUIDATA, GUIHANDLES

% Edit the above text to modify the response to help encriptacionprograma

% Last Modified by GUIDE v2.5 11-Jun-2013 18:21:20

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @encriptacionprograma_OpeningFcn, ...
                   'gui_OutputFcn',  @encriptacionprograma_OutputFcn, ...
                   'gui_LayoutFcn',  [], ...
                   'gui_Callback',   []);
if nargin && ischar(varargin{1})
   gui_State.gui_Callback = str2func(varargin{1});
end

if nargout
    [varargout{1:nargout}] = gui_mainfcn(gui_State, varargin{:});
else
    gui_mainfcn(gui_State, varargin{:});
end
% End initialization code - DO NOT EDIT

% --- Executes just before encriptacionprograma is made visible.
function encriptacionprograma_OpeningFcn(hObject, ~, handles, varargin)
% This function has no output args, see OutputFcn.
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
% varargin   unrecognized PropertyName/PropertyValue pairs from the
%            command line (see VARARGIN)

% Choose default command line output for encriptacionprograma
handles.output = hObject;
axes(handles.axes5);
BackGr = imread('encrip.gif');
  imshow(BackGr);

% Update handles structure
guidata(hObject, handles);
clc;
global Img;
global EncImg;
global DecImg;
% UIWAIT makes encriptacionprograma wait for user response (see UIRESUME)
% uiwait(handles.figure1);
% --- Outputs from this function are returned to the command line.
function varargout = encriptacionprograma_OutputFcn(hObject, eventdata, handles)
% varargout  cell array for returning output args (see VARARGOUT);
% hObject    handle to figure
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Get default command line output from handles structure
varargout{1} = handles.output;
% --- Executes during object creation, after setting all properties.
function imagenin_CreateFcn(hObject, eventdata, handles)
% hObject    handle to imagenin (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: place code in OpeningFcn to populate imagenin

% --- Executes on button press in pushbutton1.
function pushbutton1_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global Img;
global key;
X = uigetfile('*.jpg;*.tiff;*.ppm;*.pgm;*.png','pick a jpge file');
Img = imread(X);
  axes(handles.imagenin);
  imshow(Img);

[n m k] = size(Img);
  key = keyGen(n*m);
guidata(hObject, handles);
function [proImageOut] = imageProcess(ImgInp,key)
[n m k] = size(ImgInp);
% key =cell2mat(struct2cell( load('key5.mat')));
% key = keyGen(n*m);
for ind = 1 : m
    Fkey(:,ind) = key((1+(ind-1)*n) : (((ind-1)*n)+n));
end
len = n;
bre = m;
for ind = 1 : k
    Img = ImgInp(:,:,ind);
for ind1 = 1 : len
    for ind2 = 1 : bre
        proImage(ind1,ind2) = bitxor(Img(ind1,ind2),Fkey(ind1,ind2));
    end
end
proImageOut(:,:,ind) = proImage(:,:,1);
end
figure,imshow(proImageOut);
return;

% --- Executes on button press in pushbutton2.
function pushbutton2_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton2 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global Img ;
global EncImg;
global key;
EncImg = imageProcess(Img,key);
axes(handles.axes2)
imshow(EncImg);
imwrite(EncImg,'nueva imagen encriptada.jpg','jpg');

guidata(hObject, handles);

% --- Executes on button press in pushbutton3.
function pushbutton3_Callback(hObject, eventdata, handles)
% hObject    handle to pushbutton3 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
global DecImg;
global EncImg;
global key;
DecImg = imageProcess(EncImg,key);
axes(handles.axes3);
imshow(DecImg);
imwrite(DecImg,'imagen decriptada.jpg','jpg');
guidata(hObject, handles);
function [key] = keyGen(n)
n = n*4;
% n = 2048*2048*16;
%n = 24 * 24 * 8;
bin_x = zeros(n,1,'uint8');
r = 3.9999998;
bin_x_N_Minus_1 =  0.300001;
x_N = 0;
tic
for ind = 2 : n
    x_N = 1 - 2* bin_x_N_Minus_1 * bin_x_N_Minus_1;
     if (x_N > 0.0)
        bin_x(ind-1) = 1;
    end
     bin_x_N_Minus_1 =  x_N;

end
toc
save bin_sec bin_x;
t = int8(0);
key = zeros(n/4,1,'uint8');
for ind1 = 1 : n/4

    for ind2 = 1 : 4
    key(ind1) = key(ind1) + bin_x(ind2*ind1)* 2 ^ (ind2-1);
    end

end