% navego_example_canada_data: post-processing integration of
% IMU, GNSS and visual data for the Canada dataset.
%
% The main goal is to integrate IMU and GNSS measurements from Ekinox-D
% sensor which includes both IMU and GNSS sensors.
%
% Sensors dataset was generated driving a car through the streets of
% Turin city (Italy).
%
%   Copyright (C) 2014, Rodrigo Gonzalez, all rights reserved.
%
%   This file is part of NaveGo, an open-source MATLAB toolbox for
%   simulation of integrated navigation systems.
%
%   NaveGo is free software: you can redistribute it and/or modify
%   it under the terms of the GNU Lesser General Public License (LGPL)
%   version 3 as published by the Free Software Foundation.
%
%   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 Lesser General Public License for more details.
%
%   You should have received a copy of the GNU Lesser General Public
%   License along with this program. If not, see
%   <http://www.gnu.org/licenses/>.
%
% References:
%
%  The Canadian Planetary Emulation Terrain Energy-Aware Rover Navigation
% Dataset, Run 3. https://starslab.ca/enav-planetary-dataset/
%
%  Johann Diep et al. (2022). Investigating the Performance of LCNS with
% Visual-Inertial Odometry for Lunar Rover Navigation. NAVITEC 2022, April
% 2022.
%
%  Johann Diep (2022). Investigating the Performance of LCNS with
% Visual-Inertial Odometry for Lunar Rover Navigation. Youtube video.
% https://youtu.be/sPnPMBs1gSU
%
% Version: 002
% Date:    2022/07/19
% Author:  Johann Diep <johanndiep@gmail.com>
% URL:     https://github.com/rodralez/navego
%
% NOTE: NaveGo assumes that IMU is aligned with respect to body-frame as
% X-forward, Y-right and Z-down.
%
% NOTE: NaveGo assumes that yaw angle (heading) is positive clockwise.

clc
close all
clear
matlabrc

addpath ../../ins/
addpath ../../ins-gnss/
addpath ../../ins-visual/
addpath ../../conversions/
addpath ../../performance-analysis/
addpath ../../plot/
addpath ../../misc/
addpath ../../simulation/
addpath ./canada-planetary-data/data/
addpath ./canada-planetary-data/scripts/

navego_print_version;

fprintf('\nNaveGo: starting Canada planetary data integration... \n')

%% PARAMETERS

% Comment any of the following parameters in order to NOT execute a
% particular portion of code

GEN_DATA     = 'ON';

if (~exist('GEN_DATA','var')), GEN_DATA = 'OFF'; end

% FusionCase = "inertial_gnss";
% FusionCase = "inertial_visual";
FusionCase = "inertial_visual_gnss";

% Method to remove GNSS measurements for a certain time window. This is
% done to showcase that visual measurements provide a failsafe option in
% case satellite data is not available.
Sparse = "true";
% Sparse = "false";

fprintf('NaveGo: parameter FusionCase = %s \n', FusionCase)
fprintf('NaveGo: parameter Sparse = %s \n', Sparse)

%% Generating Data

if strcmp(GEN_DATA, 'ON')

    if FusionCase == "inertial_gnss"
        fprintf('NaveGo: generating IMU data... \n')
        imu_structure;

        fprintf('NaveGo: generating GNSS data... \n')
        if Sparse == "true"
            gnss_sparse_structure;
        else
            gnss_structure;
        end
    else
        imu_structure;
        fprintf('NaveGo: generating IMU data... \n')
        visual_structure;
        fprintf('NaveGo: generating VISUAL data... \n')
        if Sparse == "true"
            fprintf('NaveGo: generating GNSS data... \n')
            gnss_sparse_structure;
        else
            gnss_structure;
        end
    end
else
    fprintf('NaveGo: loading data... \n')

    if FusionCase == "inertial_gnss"
        load imu_planetary
        if Sparse == "true"
            load gnss_planetary_r
            load gnss_planetary_sparse_r
            load gnss_planetary
        else
            load gnss_planetary_r
            load gnss_planetary
        end
    else
        load imu_planetary
        load visual_planetary
        if Sparse == "true"
            load gnss_planetary_r
            load gnss_planetary_sparse_r
            load gnss_planetary
        else
            load gnss_planetary_r
            load gnss_planetary
        end
    end
end
%% Estimation

switch FusionCase
    case "inertial_gnss"
        fprintf('NaveGo: processing INS/GNSS integration... \n')
        nav_e = ins_gnss(imu_planetary,gnss_planetary,'dcm');
    case "inertial_visual"
        fprintf('NaveGo: processing INS/VISUAL integration... \n')
        nav_e = ins_visual(imu_planetary,gnss_planetary_r,visual_planetary,'dcm'); % note: figure out why we input gnss_planetary_r
    case "inertial_visual_gnss"
        fprintf('NaveGo: processing INS/GNSS/VISUAL integration... \n')
        nav_e = ins_visual_gnss(imu_planetary,gnss_planetary,visual_planetary,'dcm');
end

[nav_i, nav_ref] = navego_interpolation (nav_e, gnss_planetary_r);

if Sparse == "true"
    [gnss_i,gnss_ref] = navego_interpolation(gnss_planetary,gnss_planetary_sparse_r);
else
    [gnss_i,gnss_ref] = navego_interpolation(gnss_planetary,gnss_planetary_r);
end

%% Plotting

fprintf('NaveGo: plotting... \n')

switch FusionCase
    %% Plotting: IMU + GNSS
    case "inertial_gnss"

        % Position
        figure();
        hold on;
        plot(rad2deg(gnss_planetary.lon),rad2deg(gnss_planetary.lat),'.', 'Color', ones(1,3) * 0.75, 'LineWidth', 1.5);
        scatter(rad2deg(gnss_planetary_r.lon),rad2deg(gnss_planetary_r.lat),'y.','MarkerEdgeAlpha',.6);
        plot(rad2deg(nav_e.lon),rad2deg(nav_e.lat),'Color', [0, 0, 0], 'LineWidth', 1.5);
        grid on;
        xlabel('Longitude [deg]');
        ylabel('Latitude [deg]');
        legend('degraded GNSS','RTK','IMU + degraded GNSS','Location','Southeast');
        axis equal;

        % Position Errors
        [RN,RE]  = radius(nav_i.lat);
        LAT2M = RN + nav_i.h;
        LON2M = (RE + nav_i.h).*cos(nav_i.lat);
        [RN,RE]  = radius(gnss_i.lat);
        LAT2M_GR = RN + gnss_i.h;
        LON2M_GR = (RE + gnss_i.h).*cos(gnss_i.lat);

        figure();
        subplot(2,1,1);
        hold on;
        plot(gnss_i.t,LAT2M_GR.*(gnss_i.lat - gnss_ref.lat), '.', 'Color', ones(1,3) * 0.75, 'LineWidth', 1.5)
        plot(nav_i.t, LAT2M.*(nav_i.lat - nav_ref.lat),'Color', [0, 0, 0], 'LineWidth', 1.5)
        grid on;
        xlabel('Time [s]')
        ylabel('[m]')
        legend('GNSS', 'IMU + degraded GNSS', 'Location', 'northoutside');
        title('Latitude Error');
        xlim([0,max(gnss_planetary.t)]);
        subplot(2,1,2);
        hold on;
        plot(gnss_i.t, LON2M_GR.*(gnss_i.lon - gnss_ref.lon), '.', 'Color', ones(1,3) * 0.75, 'LineWidth', 1.5)
        plot(nav_i.t, LON2M.*(nav_i.lon - nav_ref.lon),'Color', [0, 0, 0], 'LineWidth', 1.5)
        grid on;
        xlabel('Time [s]')
        ylabel('[m]')
        legend('GNSS', 'IMU + degraded GNSS', 'Location', 'northoutside');
        title('Longitude Error');
        xlim([0,max(gnss_planetary.t)]);

        %% Plotting: Vision + IMU
    case "inertial_visual"

        % Position
        figure();
        hold on;
        plot(rad2deg(visual_planetary.lon),rad2deg(visual_planetary.lat),'.', 'Color', ones(1,3) * 0.75, 'LineWidth', 1.5);
        scatter(rad2deg(gnss_planetary_r.lon),rad2deg(gnss_planetary_r.lat),'y.','MarkerEdgeAlpha',.6);
        plot(rad2deg(nav_e.lon),rad2deg(nav_e.lat),'Color', [0, 0, 0], 'LineWidth', 1.5);
        grid on;
        xlabel('Longitude');
        ylabel('Latitude');
        legend('OpenVINS','RTK','IMU + OpenVINS','Location','Southeast');
        axis equal;
        % Position Errors
        [RN,RE]  = radius(nav_i.lat);
        LAT2M = RN + nav_i.h;
        LON2M = (RE + nav_i.h).*cos(nav_i.lat);

        [RN,RE]  = radius(gnss_i.lat);
        LAT2M_GR = RN + gnss_i.h;
        LON2M_GR = (RE + gnss_i.h).*cos(gnss_i.lat);

        figure();
        subplot(2,1,1);
        hold on;
        plot(gnss_i.t,  LAT2M_GR.*(gnss_i.lat - gnss_ref.lat), '.', 'Color', ones(1,3) * 0.75, 'LineWidth', 1.5)
        plot(nav_i.t, LAT2M.*(nav_i.lat - nav_ref.lat),'Color', [0, 0, 0], 'LineWidth', 1.5)
        grid on;
        xlabel('Time [s]')
        ylabel('[m]')
        legend('GNSS', 'IMU + OpenVINS', 'Location', 'northoutside');
        title('Latitude Error');
        xlim([0,max(gnss_planetary.t)]);
        subplot(2,1,2);
        hold on;
        plot(gnss_i.t, LON2M_GR.*(gnss_i.lon - gnss_ref.lon), '.', 'Color', ones(1,3) * 0.75, 'LineWidth', 1.5)
        plot(nav_i.t, LON2M.*(nav_i.lon - nav_ref.lon),'Color', [0, 0, 0], 'LineWidth', 1.5)
        grid on;
        xlabel('Time [s]')
        ylabel('[m]')
        legend('GNSS', 'IMU + OpenVINS', 'Location', 'northoutside');
        title('Longitude Error');
        xlim([0,max(gnss_planetary.t)]);

        %% Plotting: Vision + GNSS + INS
    case "inertial_visual_gnss"

        % Position
        figure();
        hold on;
        plot(rad2deg(gnss_planetary.lon),rad2deg(gnss_planetary.lat),'.', 'Color', ones(1,3) * 0.75, 'LineWidth', 1.5);
        scatter(rad2deg(gnss_planetary_r.lon),rad2deg(gnss_planetary_r.lat),'y.','MarkerEdgeAlpha',.6);
        plot(rad2deg(nav_e.lon),rad2deg(nav_e.lat),'Color', [0, 0, 0], 'LineWidth', 1.5);
        grid on;
        xlabel('Longitude [deg]');
        ylabel('Latitude [deg]');
        legend('degraded GNSS','RTK','IMU + degraded GNSS + OpenVINS','Location','Southeast');
        axis equal;

        % Position Errors
        [RN,RE]  = radius(nav_i.lat);
        LAT2M = RN + nav_i.h;
        LON2M = (RE + nav_i.h).*cos(nav_i.lat);

        [RN,RE]  = radius(gnss_i.lat);
        LAT2M_GR = RN + gnss_i.h;
        LON2M_GR = (RE + gnss_i.h).*cos(gnss_i.lat);

        figure();
        subplot(2,1,1);
        hold on;
        plot(gnss_i.t,  LAT2M_GR.*(gnss_i.lat - gnss_ref.lat), '.', 'Color', ones(1,3) * 0.75, 'LineWidth', 1.5)
        plot(nav_i.t, LAT2M.*(nav_i.lat - nav_ref.lat),'Color', [0, 0, 0], 'LineWidth', 1.5)
        grid on;
        xlabel('Time [s]')
        ylabel('[m]')
        legend('GNSS', 'IMU + degraded GNSS + OpenVINS', 'Location', 'northoutside');
        title('Latitude Error');
        xlim([0,max(gnss_planetary.t)]);
        subplot(2,1,2);
        hold on;
        plot(gnss_i.t, LON2M_GR.*(gnss_i.lon - gnss_ref.lon), '.', 'Color', ones(1,3) * 0.75, 'LineWidth', 1.5)
        plot(nav_i.t, LON2M.*(nav_i.lon - nav_ref.lon),'Color', [0, 0, 0], 'LineWidth', 1.5)
        grid on;
        xlabel('Time [s]')
        ylabel('[m]')
        legend('GNSS', 'IMU + degraded GNSS + OpenVINS', 'Location', 'northoutside');
        title('Longitude Error');
        xlim([0,max(gnss_planetary.t)]);
end


if ~exist('calib_name')|~exist('format_image'),
   data_calib_no_read;
   return;
end;

check_directory;

if ~exist('n_ima'),
   data_calib_no_read;
   return;
end;

check_active_images;

images_read = active_images;

if exist('image_numbers'),
   first_num = image_numbers(1);
end;

% Just to fix a minor bug:
if ~exist('first_num'),
   first_num = image_numbers(1);
end;

image_numbers = first_num:n_ima-1+first_num;

no_image_file = 0;

%% Step used to clean the memory if a previous atttempt has been made to read the entire set of images into memory:
for kk = 1:n_ima,
    if (exist(['I_' num2str(kk)])==1),
        clear(['I_' num2str(kk)]);
    end;
end;

fprintf(1,'\nChecking directory content for the calibration images (no global image loading in memory efficient mode)\n');

one_image_read = 0;

i = 1;

while (i <= n_ima), % & (~no_image_file),

    if active_images(i),

        %fprintf(1,'Loading image %d...\n',i);

        if ~type_numbering,
            number_ext =  num2str(image_numbers(i));
        else
            number_ext = sprintf(['%.' num2str(N_slots) 'd'],image_numbers(i));
        end;

        ima_name = [calib_name  number_ext '.' format_image];

        if i == ind_active(1),
            fprintf(1,'Found images: ');
        end;

        if exist(ima_name),

            fprintf(1,'%d...',i);

            if ~one_image_read

                if format_image(1) == 'p',
                    if format_image(2) == 'p',
                        I = double(loadppm(ima_name));
                    else
                        I = double(loadpgm(ima_name));
                    end;
                else
                    if format_image(1) == 'r',
                        I = readras(ima_name);
                    else
                        I = double(imread(ima_name));
                    end;
                end;

                if size(I,3)>1,
                    I = 0.299 * I(:,:,1) + 0.5870 * I(:,:,2) + 0.114 * I(:,:,3);
                end;

                if size(I,1)~=480,
                    small_calib_image = 1;
                else
                    small_calib_image = 0;
                end;

                [Hcal,Wcal] = size(I); 	% size of the calibration image

                [ny,nx] = size(I);

                one_image_read = 1;

            end;

        else

            images_read(i) = 0;

        end;

    end;

    i = i+1;

end;

ind_read = find(images_read);

if ~(exist('map')==1), map = gray(256); end;

active_images = images_read;

fprintf(1,'\ndone\n');


function f = allenAtlasBrowser_original(templateVolume, annotationVolume, structureTree)
% Browser for the allen atlas ccf data in matlab.
%
% Inputs templateVolume, annotationVolume, and structureTree are the data describing the atlas.
% The annotation volume should be the "by_index" version
%
% Features:
% - Use scroll wheel to go between slices
% - Apply 1mm-spacing grid lines ('g' to enable/disable)
% - View overlay of the region hovered over ('o' to enable/disable)
% - Switch to viewing the atlas annotations ('v' to toggle)
% - Click to register points in 3D ('p' to toggle)
%   - use:
%     >> ud = get(f, 'UserData'); myPoints = ud.pointList;
%     to retrieve these points

% todo/future features:
% - switch to sagittal/horizontal slice types

fprintf(1, 'Controls: \n');
fprintf(1, '--------- \n');
fprintf(1, 'scroll: move between slices \n');
fprintf(1, 'g: add/remove Gridlines \n');
fprintf(1, 'o: add/remove Overlay of current region extent \n');
fprintf(1, 'v: switch to Viewing annotations (or switch back) \n');
fprintf(1, 'p: enable/disable mode where clicks are logged as Points \n');

f = figure;

ud.bregma = allenCCFbregma;

ud.currentSlice = min(ud.bregma(1), size(templateVolume, 1));
ud.oldContour = [];
ud.showContour = false;
ud.showOverlay = false; ud.overlayAx = [];
ud.getPoint = false; ud.pointList = zeros(0,3); ud.pointHands = [];
ud.showAtlas = false;

ud.atlasAx = axes('Position', [0.05 0.05 0.9 0.9]);

ud.im = plotTVslice(squeeze(templateVolume(ud.currentSlice,:,:)));

set(ud.im, 'ButtonDownFcn', @(f,k)atlasClickCallback(f, k));

ud.bregmaText = annotation('textbox', [0 0.95 0.4 0.05], ...
    'String', '[coords]', 'EdgeColor', 'none', 'Color', 'k');

allData.tv = templateVolume;
allData.av = annotationVolume;
allData.st = structureTree;

hold(ud.atlasAx, 'on');
set(ud.atlasAx, 'HitTest', 'off');

set(f, 'UserData', ud);

set(f, 'KeyPressFcn', @(f,k)hotkeyFcn(f, k, allData));
set(f, 'WindowScrollWheelFcn', @(src,evt)updateSlice(f, evt, allData))
set(f, 'WindowButtonMotionFcn',@(f,k)fh_wbmfcn(f, allData)); % Set the motion detector.

function hotkeyFcn(f, keydata, allData)

ud = get(f, 'UserData');
switch lower(keydata.Key)
    case 'g' % toggle showing Gridlines
        if ~isfield(ud, 'gridlines') || isempty(ud.gridlines)
            axes(ud.atlasAx); hold on;
            gridY = 100:100:700; % assuming the size of the atlas for this for now
            gridX = 70:100:1140;
            xl = xlim(); yl = ylim();
            gx = arrayfun(@(x)plot(x*[1 1], yl, 'w'), gridX, 'uni', false);
            gy = arrayfun(@(y)plot(xl, y*[1 1], 'w'), gridY, 'uni', false);
            ud.gridlines = [gx gy];
        elseif strcmp(get(ud.gridlines{1}, 'Visible'), 'on');
            cellfun(@(x)set(x, 'Visible', 'off'), ud.gridlines);
        elseif strcmp(get(ud.gridlines{1}, 'Visible'), 'off');
            cellfun(@(x)set(x, 'Visible', 'on'), ud.gridlines);
        end
    case 'c' % toggle Contour
        % contours are disabled for now - they are slow and buggy...
%         if ud.showContour
%             delete(ud.oldContour); ud.oldContour = [];
%         end
%         ud.showContour = ~ud.showContour;
    case 'o' % toggle Overlay
        ud.showOverlay = ~ud.showOverlay;
        if ~ud.showOverlay
            % weird bug means that point clicking stops working when the
            % overlayAx exists, even though I turned all the hittests off??
            % hack solution is to just delete it every time... :/
%             ovIm = get(ud.overlayAx, 'Children');
%             set(ovIm, 'AlphaData', zeros(size(get(ovIm, 'CData'))));
            delete(ud.overlayAx); ud.overlayAx = [];
        end
    case 'p' % toggle mode to register clicks as Points
        ud.getPoint = ~ud.getPoint;
    case 'v' % toggle View between template/annotation
        ud.showAtlas = ~ud.showAtlas;
        if ud.showAtlas
            set(ud.im, 'CData', squeeze(allData.av(ud.currentSlice,:,:)));
            cmap = allen_ccf_colormap('2017');
            colormap(ud.atlasAx, cmap); caxis(ud.atlasAx, [1 size(cmap,1)]);
        else
            set(ud.im, 'CData', squeeze(allData.tv(ud.currentSlice,:,:)));
            colormap(ud.atlasAx, 'gray'); caxis(ud.atlasAx, [0 400]);
        end
        set(f, 'UserData', ud);

end
set(f, 'UserData', ud);

function updateSlice(f, evt, allData)

ud = get(f, 'UserData');
ud.currentSlice = ud.currentSlice+evt.VerticalScrollCount*3;
if ud.currentSlice>size(allData.tv,1); ud.currentSlice = 1; end %wrap around
if ud.currentSlice<1; ud.currentSlice = size(allData.tv,1); end %wrap around
set(f, 'UserData', ud);

if ud.showAtlas
    set(ud.im, 'CData', squeeze(allData.av(ud.currentSlice,:,:)));
else
    set(ud.im, 'CData', squeeze(allData.tv(ud.currentSlice,:,:)));
end

if ~isempty(ud.pointHands)
    % any points that are at this AP position, make them visible
    arrayfun(@(x)pointVis(ud.pointHands(x), ud.currentSlice, ud.pointList(x,:)), 1:numel(ud.pointHands));
end

pixel = getPixel(ud.atlasAx);
updateStereotaxCoords(ud.currentSlice, pixel, ud.bregma, ud.bregmaText);

[name, acr, ann] = getPixelAnnotation(allData, pixel, ud.currentSlice);

updateTitle(ud.atlasAx, name, acr)

if ud.showOverlay
    updateOverlay(f, allData, ann);
end

function pointVis(h, sliceInd, coord)
    if sliceInd==coord(3)
        set(h, 'Visible', 'on');
    else
        set(h, 'Visible', 'off');
    end

function atlasClickCallback(im, keydata)
f = get(get(im, 'Parent'), 'Parent');
ud = get(f, 'UserData');

if ud.getPoint
    clickX = round(keydata.IntersectionPoint(1));
    clickY = round(keydata.IntersectionPoint(2));
    clickZ = ud.currentSlice;

    ud.pointList(end+1, :) = [clickX, clickY, clickZ];
    ud.pointHands(end+1) = plot(ud.atlasAx, clickX, clickY, 'ro');
end
set(f, 'UserData', ud);

function fh_wbmfcn(f, allData)
% WindowButtonMotionFcn for the figure.

ud = get(f, 'UserData');

ax = ud.atlasAx;

pixel = getPixel(ax);

% show bregma coords
updateStereotaxCoords(ud.currentSlice, pixel, ud.bregma, ud.bregmaText);

% get annotation for this pixel
[name, acr, ann] = getPixelAnnotation(allData, pixel, ud.currentSlice);

updateTitle(ax, name, acr);

if ~isempty(name)
    if ud.showContour
        if ~isempty(ud.oldContour)
            delete(ud.oldContour);
        end
        [~,ch] = contour(squeeze(allData.av(ud.currentSlice,:,:)==ann), 1, 'r');
        ud.oldContour = ch;
        set(f, 'UserData', ud);
    end

    if ud.showOverlay
        updateOverlay(f, allData, ann)
    end
end

function updateStereotaxCoords(currentSlice, pixel, bregma, bregmaText)
atlasRes = 0.010; % mm
ap = -(currentSlice-bregma(1))*atlasRes;
dv = (pixel(1)-bregma(2))*atlasRes;
ml = (pixel(2)-bregma(3))*atlasRes;
set(bregmaText, 'String', sprintf('%.2f AP, %.2f DV, %.2f ML', ap, dv, ml));

function pixel = getPixel(ax)

currPoint = get(ax,'currentpoint');  % The current point w.r.t the axis.

Cx = currPoint(1,1); Cy = currPoint(1,2);
pixel = round([Cy Cx]);

function updateOverlay(f, allData, ann)
ud = get(f, 'UserData');
if isempty(ud.overlayAx) % first time
    avo = plotAVoverlay(fliplr(squeeze(allData.av(ud.currentSlice,:,:))'), ann, ud.atlasAx);
    ud.overlayAx = avo;
    set(ud.overlayAx, 'HitTest', 'off');
    set(f, 'UserData', ud);
else
    ovIm = get(ud.overlayAx, 'Children');
    set(ovIm, 'HitTest', 'off');
    thisSlice = squeeze(allData.av(ud.currentSlice,:,:));
    if ud.showAtlas
        % if showing the atlas annotations, make the cdata 1302 so you get
        % a black overlay (it's the number for the parafloccular sulcus, which
        % is unused) in current annotations so I stole its entry in the
        % colormap to be black.
        adat = ones(size(get(ovIm, 'CData')));
        set(ovIm, 'CData', 1302*adat);
        adat(thisSlice~=ann) = 0;
        set(ovIm, 'AlphaData', flipud(100*adat));
    else
        % otherwise show in the color of the atlas
        set(ovIm, 'CData', flipud(thisSlice));
        plotAVoverlay(fliplr(thisSlice'), ann, ud.atlasAx, ud.overlayAx);
    end

end

function [name, acr, ann] = getPixelAnnotation(allData, pixel, currentSlice)
if pixel(1)>0&&pixel(1)<size(allData.av,2) && pixel(2)>0&&pixel(2)<=size(allData.av,3)
    ann = allData.av(currentSlice,pixel(1),pixel(2));
    name = allData.st.safe_name(ann);
    acr = allData.st.acronym(ann);
else
    ann = []; name = []; acr = [];
end

function updateTitle(ax, name, acr)
if ~isempty(name)
    title(ax, [name{1} ' (' acr{1} ')']);
else
    title(ax, 'not found');
end


function openInplaneWindowforAlign3
%
% Opens a new inplane window and initializes the corresponding data structure.
%
% djh 8/29/01, modified from openInplaneWindow

% Make sure the global variables exist
global mrSESSION INPLANE

disp('Initializing Inplane view')

% Set name, viewType, & subdir
INPLANE.name='INPLANE';
INPLANE.viewType='Inplane';
INPLANE.subdir='Inplane';

% Refresh function, gets called by refreshScreen
INPLANE.refreshFn = 'refreshView';

% Initialize slot for anat
INPLANE.anat = [];

% Initialize slots for co, amp, and ph
INPLANE.co = [];
INPLANE.amp = [];
INPLANE.ph = [];
INPLANE.map = [];
INPLANE.mapName = '';
INPLANE.spatialGrad = [];

% Initialize slots for tSeries
INPLANE.tSeries = [];
INPLANE.tSeriesScan = NaN;
INPLANE.tSeriesSlice = NaN;

% Initialize ROIs
INPLANE.ROIs = [];
INPLANE.selectedROI = 0;

% Initialize curDataType
INPLANE.curDataType = 1;

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Make displayModes and color maps %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Initialize displayModes
INPLANE=resetDisplayModes(INPLANE);
INPLANE.ui.displayMode='anat';

%%%%%%%%%%%%%%%%%%%
% Open the window %
%%%%%%%%%%%%%%%%%%%

% Figure number for inplane view window
INPLANE.ui.figNum=figure('MenuBar','none');

% Handle for inplane view window
INPLANE.ui.windowHandle = gcf;

% Handle for main axis of inplane view
INPLANE.ui.mainAxisHandle = gca;

% Adjust position and size of main axes so there's room for
% buttons, colorbar, and sliders
set(INPLANE.ui.mainAxisHandle,'position',[0.1 0.1 0.725 0.7]);

% Set minColormap property so there's potentially room for 128
% colors
set(INPLANE.ui.windowHandle,'minColormap',128)

% Sharing of colors seems like it might be OK, but I'm turning it
% off just to be sure (djh, 1/26/98).
set(gcf,'sharecolors','off');

%%%%%%%%%%%%%%%%%%%%%%%%%
% Add Annotation String %
%%%%%%%%%%%%%%%%%%%%%%%%%

INPLANE = makeAnnotationString(INPLANE);

%%%%%%%%%%%%%%%%%
% Add Color Bar %
%%%%%%%%%%%%%%%%%

% Make color bar and initialize it to 'off'
INPLANE.ui.colorbarHandle=makeColorBar(INPLANE);
setColorBar(INPLANE,'off');
INPLANE.ui.cbarRange = [];

%%%%%%%%%%%%%%%%%%%
% Add popup menus %
%%%%%%%%%%%%%%%%%%%

disp('Attaching popup menus')

INPLANE = makeROIPopup(INPLANE);
INPLANE = makeDataTypePopup(INPLANE);

%%%%%%%%%%%%%%%
% Add sliders %
%%%%%%%%%%%%%%%

disp('Attaching sliders')

% scan slider
w = 0.12; h = 0.04; l = 0; b = 0.95;
INPLANE = makeSlider(INPLANE,'scan',[],[l b w h]);
INPLANE = initScanSlider(INPLANE,1);
INPLANE = selectDataType(INPLANE,INPLANE.curDataType);

% slice slider
w = 0.12; h = 0.04; l = 0; b = 0.85;
INPLANE = makeSlider(INPLANE,'slice',[],[l b w h]);
INPLANE = initSliceSlider(INPLANE);

% correlation threshold:
INPLANE = makeSlider(INPLANE,'cothresh',[0,1],[.85,.85,.15,.05]);
setCothresh(INPLANE,0);

% phase window:
INPLANE = makeSlider(INPLANE,'phWinMin',[0,2*pi],[.85,.75,.15,.05]);
INPLANE = makeSlider(INPLANE,'phWinMax',[0,2*pi],[.85,.65,.15,.05]);
setPhWindow(INPLANE,[0 2*pi]);

% parameter map window:
INPLANE = makeSlider(INPLANE,'mapWinMin',[0,1],[.85,.55,.15,.05]);
INPLANE = makeSlider(INPLANE,'mapWinMax',[0,1],[.85,.45,.15,.05]);
setMapWindow(INPLANE,[0 1]);

% anatClip: determines clipping of the anatomy base-image
%           values to fill the range of available grayscales.
INPLANE = makeSlider(INPLANE,'anatMin',[0,1],[.85,.2,.15,.05]);
INPLANE = makeSlider(INPLANE,'anatMax',[0,1],[.85,.1,.15,.05]);
setAnatClip(INPLANE,[0 .5]);

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Initialize display parameters %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% Initialize image field
INPLANE.ui.image = [];

% Show all ROIs
INPLANE.ui.showROIs = 2;

%%%%%%%%%%%%%%%%%%%%%%%%%
% Load user preferences %
%%%%%%%%%%%%%%%%%%%%%%%%%

INPLANE = loadPrefs(INPLANE);

%%%%%%%%%%%%%%%%%%
% Refresh screen %
%%%%%%%%%%%%%%%%%%

INPLANE=refreshScreen(INPLANE);

disp('Done initializing Inplane view')


function v = times(varargin)
% ensure that result is not S2Grid anymore

v = vector3d(times@vector3d(varargin{:}));


function StepThru(mfile,ws)
%STEPTHRU automatically steps through specified m-file
%
%   STEPTHRU(MFILE) sets breakpoints at all but first line comment and
%   executes MFILE in order to step through it using debugger.
%
%       Line comments begin with % character.
%
%       No breakpoint is generated if the text 'nobkpt' is
%       anywhere in the line comment.
%
%   STEPTHRU(MFILE,WS) executes MFILE in specified
%   workspace (ie, 'caller' or 'base' valid).

%This utility intended to simplify MATLAB script demos
%v2 Apr2004 rbemis@mathworks.com (added npbkpt option)
%v1 Oct2002 rbemis@mathworks.com

% Copyright 2004-2010 The MathWorks, Inc.

% find pure comment lines to set breakpoints
fid=fopen([mfile '.m']);
line_num=0;
while ~feof(fid) %read 1 line at-a-time
  dummy=NoLeadingBlanks(fgetl(fid));
  line_num=line_num+1;
  if length(dummy)>0 %nonempty line
    if dummy(1)=='%' & line_num>1 %comment line but not line1
      if strfind(lower(dummy),'nobkpt') %no breakpoint this line
        eval(['dbclear in ' mfile ' at ' num2str(line_num)])
      else
        eval(['dbstop in ' mfile ' at ' num2str(line_num)])
      end
    end
  end
end %file empty
fclose(fid);

%open file in Editor
edit(mfile)

% execute m-file (in specified workspace)
if nargin>1 %workspace specified
  evalin(ws,mfile)
else %default=local workspace (ie, this function)
  eval(mfile)
end
dbclear all

% helper function to remove any leading blanks
%--------------------------------------------------
function str1 = NoLeadingBlanks(str1)
Done=false;
while ~Done %keep looking
  if length(str1)==0 %empty string
    Done=true; %get out
  else %check first character
    if str1(1)==' ' %leading blank detected
      str1=str1(2:end); %remove it
    else %any other character
      Done=true; %leave it, done
    end
  end
end %stripped!


classdef LibrationPointEnum < matlab.mixin.SetGet
    %LibrationPointEnum Summary of this class goes here
    %   Detailed explanation goes here

    enumeration
        L1('L1')
        L2('L2');
    end

    properties
        name char = '';
    end

    methods
        function obj = LibrationPointEnum(name)
            obj.name = name;
        end
    end

    methods(Static)
        function [listBoxStr, enums] = getListBoxStr()
            m = enumeration('LibrationPointEnum');
            [~,I] = sort({m.name});
            listBoxStr = {m(I).name};
            enums = m;
        end

        function [ind, enum] = getIndForName(name)
            m = enumeration('LibrationPointEnum');
            [~,I] = sort({m.name});
            m = m(I);
            ind = find(ismember({m.name},name),1,'first');
            enum = m(ind);
        end

        function [enum, ind] = getEnumForListboxStr(nameStr)
            m = enumeration('LibrationPointEnum');
            ind = find(ismember({m.name},nameStr),1,'first');
            enum = m(ind);
        end
    end
end


function view_aValue(lab1, re3) % autogenerated function wrapper
    % This routine is the equivalent to the view_bva.m but for calc_avalgrid.m
    % view_maxz plots the maxz LTA values calculated
    % with maxzlta.m or other similar values as a color map
    % needs re3, gx, gy, stri
    %
    % define size of the plot etc.
    %
    % turned into function by Celso G Reyes 2017

    ZG=ZmapGlobal.Data; % used by get_zmap_globals

    if ~exist('Prmap','var') || isempty(Prmap)
        Prmap = nan(size(re3));
    end

    if isempty(name)
        name = '  ';
    end
    think
    report_this_filefun(mfilename('fullpath'));
    co = 'w';

    % Find out if figure already exists
    %
    bmap=findobj('Type','Figure','-and','Name','a-value-map');

    % Set up the Seismicity Map window Enviroment
    %
    if isempty(bmap)
        bmap = figure_w_normalized_uicontrolunits( ...
            'Name','a-value-map',...
            'NumberTitle','off', ...
            'NextPlot','new', ...
            'backingstore','on',...
            'Visible','off', ...
            'Position',[ (fipo(3:4) - [600 400]) ZmapGlobal.Data.map_len]);

        lab1 = 'a-value:';
        create_my_menu();

        re4 = re3;

        colormap(jet)
        tresh = nan;
        minpe = nan;
        Mmin = nan;

    end   % This is the end of the figure setup

    % Now lets plot the color-map of the z-value
    %
    figure(bmap);
    delete(findobj(bfig,'Type','axes'));
    % delete(sizmap);
    reset(gca)
    cla
    hold off
    watchon;
    set(gca,'visible','off','FontSize',ZmapGlobal.Data.fontsz.s,'FontWeight','normal',...
        'FontWeight','normal','LineWidth',1.,...
        'Box','on','SortMethod','childorder')

    rect = [0.18,  0.10, 0.7, 0.75];
    rect1 = rect;

    % find max and min of data for automatic scaling
    %
    ZG.maxc = max(max(re3));
    ZG.maxc = fix(ZG.maxc)+1;
    ZG.minc = min(min(re3));
    ZG.minc = fix(ZG.minc)-1;

    % set values gretaer tresh = nan
    %
    % re4 = re3;
    % l = r > tresh;
    % re4(l) = nan(1,length(find(l)));
    % l = Prmap < minpe;
    % re4(l) = nan(1,length(find(l)));
    % l = MaxCMap <  Mmin;
    % re4(l) = nan(1,length(find(l)));

    % plot image
    %
    orient landscape
    %set(gcf,'PaperPosition', [0.5 1 9.0 4.0])

    axes('position',rect)
    hold on
    pco1 = pcolor(gx,gy,re3);

    axis([ min(gx) max(gx) min(gy) max(gy)])
    set(gca,'dataaspect',[1 cosd(mean(ZG.primeCatalog.Latitude,'omitnan')) 1]);
    hold on
    if sha == 'fl'
        shading flat
    else
        shading interp
    end
    % make the scaling for the recurrence time map reasonable
    if lab1(1) =='T'
        l = isnan(re3);
        re = re3;
        re(l) = [];
        caxis([min(re) 5*min(re)]);
    end
    if fre == 1
        caxis([fix1 fix2])
    end

    title([name ';  '   num2str(t0b) ' to ' num2str(teb) ],'FontSize',ZmapGlobal.Data.fontsz.s,...
        'Color','r','FontWeight','normal')

    xlabel('Longitude [deg]','FontWeight','normal','FontSize',ZmapGlobal.Data.fontsz.s)
    ylabel('Latitude [deg]','FontWeight','normal','FontSize',ZmapGlobal.Data.fontsz.s)

    % plot overlay
    %
    hold on
    update(mainmap())
    ploeq = plot(ZG.primeCatalog.Longitude,ZG.primeCatalog.Latitude,'k.');
    set(ploeq,'Tag','eq_plot','MarkerSize',ZG.ms6,'Marker',ty,'Color',co,'Visible',vi)

    set(gca,'visible','on','FontSize',ZmapGlobal.Data.fontsz.s,'FontWeight','normal',...
        'FontWeight','normal','LineWidth',1.,...
        'Box','on','TickDir','out')

    h1 = gca;
    hzma = gca;

    % Create a colorbar
    %
    h5 = colorbar('horiz');
    set(h5,'Pos',[0.35 0.07 0.4 0.02],...
        'FontWeight','normal','FontSize',ZmapGlobal.Data.fontsz.s,'TickDir','out')

    rect = [0.00,  0.0, 1 1];
    axes('position',rect)
    axis('off')
    %  Text Object Creation
    txt1 = text(...
        'Color',[ 0 0 0 ],...
        'EraseMode','normal',...
        'Units','normalized',...
        'Position',[ 0.2 0.06 0 ],...
        'HorizontalAlignment','right',...
        'Rotation',[ 0 ],...
        'FontSize',ZmapGlobal.Data.fontsz.s,....
        'FontWeight','normal',...
        'String',lab1);

    % Make the figure visible
    %
    set(gca,'FontSize',ZmapGlobal.Data.fontsz.s,'FontWeight','normal',...
        'FontWeight','normal','LineWidth',1.,...
        'Box','on','TickDir','out')
    figure(bmap);
    %sizmap = signatur('ZMAP','',[0.01 0.04]);
    %set(sizmap,'Color','k')
    axes(h1)
    set(gcf,'color','w');
    watchoff(bmap)
    %whitebg(gcf,[ 0 0 0 ])
    done

    %% ui functions
    function create_my_menu()
        add_menu_divider();

        add_symbol_menu('eq_plot');

        options = uimenu('Label',' Select ');
        uimenu(options,'Label','Refresh ', 'callback',@callbackfun_001)
        uimenu(options,'Label','Select EQ in Circle',...
            'callback',@callbackfun_002)
        uimenu(options,'Label','Select EQ in Circle - Constant R',...
            'callback',@callbackfun_003)
        uimenu(options,'Label','Select EQ in Circle - Overlay existing plot',...
            'callback',@callbackfun_004)

        uimenu(options,'Label','Select EQ in Polygon -new ',...
            'callback',@callbackfun_005)
        uimenu(options,'Label','Select EQ in Polygon - hold ',...
            'callback',@callbackfun_006)

        % Menu 'Maps'
        op1 = uimenu('Label',' Maps ');
        % A-Value map calculated by the MaxLikelihoodA...
        uimenu(op1,'Label','a-value map ',...
            'callback',@callbackfun_007)
        % B-Value map (fixed b-value by input from calc_avalgrid.m (NEVER CALLED)
        uimenu(op1,'Label','b-value map ',...
            'callback',@callbackfun_008)
        % Magnitude of completeness calculated by MaxCurvature
        uimenu(op1,'Label','Magnitude of completness map ',...
            'callback',@callbackfun_009)
        % Resolution estimation by mapping the needed radius to cover ni
        % earthquakes
        uimenu(op1,'Label','Resolution map',...
            'callback',@callbackfun_010)
        % Earthquake density map
        uimenu(op1,'Label','Earthquake density map',...
            'callback',@callbackfun_011)
        % Mu-value of the normal CDF
        uimenu(op1,'Label','Mu-value of the normal CDF',...
            'callback',@callbackfun_012)
        %  Sigma-value of the normal CDF
        uimenu(op1,'Label','Sigma-value of the normal CDF',...
            'callback',@callbackfun_013)

        % Menu 'Display'
        add_display_menu(4);
    end

    %% callback functions

    function callbackfun_001(mysrc,myevt)
        % automatically created callback function from text
        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        view_aValue(lab1, re3);
    end

    function callbackfun_002(mysrc,myevt)
        % automatically created callback function from text
        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        h1 = gca;
        met = 'ni';
        ZG=ZmapGlobal.Data;
        ZG.hold_state=false;
        cirbva;
        watchoff(bmap);
    end

    function callbackfun_003(mysrc,myevt)
        % automatically created callback function from text
        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        h1 = gca;
        met = 'ra';
        ZG=ZmapGlobal.Data;
        ZG.hold_state=false;
        cirbva;
        watchoff(bmap);
    end

    function callbackfun_004(mysrc,myevt)
        % automatically created callback function from text
        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        h1 = gca;
        ZG.hold_state=true;
        cirbva;
        watchoff(bmap);
    end

    function callbackfun_005(mysrc,myevt)
        % automatically created callback function from text
        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        cufi = gcf;
        ZG.hold_state=false;
        selectp;
    end

    function callbackfun_006(mysrc,myevt)
        % automatically created callback function from text
        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        cufi = gcf;
        ZG.hold_state=true;
        view_aValue(lab1, re3);
    end

    function callbackfun_007(mysrc,myevt)
        % automatically created callback function from text
        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        lab1 ='a-value';
        re3 = aValueMap;
        view_aValue(lab1, re3);
    end

    function callbackfun_008(mysrc,myevt)
        % automatically created callback function from text
        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        lab1='b-value';
        re3 = bValueMap;
        view_aValue(lab1, re3);
    end

    function callbackfun_009(mysrc,myevt)
        % automatically created callback function from text
        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        lab1 = 'Mcomp';
        re3 = MaxCMap;
        view_aValue(lab1, re3);
    end

    function callbackfun_010(mysrc,myevt)
        % automatically created callback function from text
        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        lab1='Radius in [km]';
        re3 = reso;
        view_aValue(lab1, re3);
    end

    function callbackfun_011(mysrc,myevt)
        % automatically created callback function from text
        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        lab1='log(EQ per km^2)';
        re3 = log10(ni./(reso.^2*pi));
        view_aValue(lab1, re3);
    end

    function callbackfun_012(mysrc,myevt)
        % automatically created callback function from text
        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        lab1='Mu-Value';
        re3 = MuMap;
        view_aValue(lab1, re3);
    end

    function callbackfun_013(mysrc,myevt)
        % automatically created callback function from text
        callback_tracker(mysrc,myevt,mfilename('fullpath'));
        lab1='Sigma-Value';
        re3 = SigmaMap;
        view_aValue(lab1, re3);
    end
end


function val = mrViewGet(varargin);
%
% mrViewGet: Get the value of the specified property for
% a mrViewer UI.
%
% Can be used a number of ways:
%
% mrViewGet without any arguments returns the ui struct
% corresponding to the most current mrViewer UI. The most
% current UI is the one the selected figure belongs to;
% if the selected figure doesn't belong to a mrViewer UI,
% then it looks for the most recently-created UI. If no
% UIs are found, displays a warning and returns an empty
% matrix.
%
% mrViewGet(ui) lists the properties and set values for
% the specified ui, similar to GET.
%
% mrViewGet('PropertyName') returns the value of the
% specified property for the most current UI.
%
% mrViewGet(ui,'PropertyName') returns the value of the
% specified property for the specified UI.
%
% Properties include (non-case-sensitive):
%   'ImageCoords': Coordinates of the images being displayed
%   by the UI (in the ui.display struct, see mrViewUnderlay), in terms
%   of the UI's currently-selected space. Specifying
%       mrViewGet(ui,'imagecoords',N)
%   will return only the coordinates pertaining to the Nth image being
%   displayed. Otherwise, a cell array of image coordinates will be
%   returned. In all cases, the coords for each image are a 3xnPixels
%   matrix, with the rows being the row, column, and slice indices into
%   the base MR data.
%
%   'DataCoords': Coordinates of the images being displayed
%   by the UI (in the ui.display struct, see mrViewUnderlay), in terms
%   of the base MR data. Specifying  mrViewGet(ui,'datacoords',N) will
%   return only the coordinates pertaining to the Nth image being
%   displayed. Otherwise, a cell array of image coordinates will be
%   returned. In all cases, the coords for each image are a 3xnPixels
%   matrix, with the rows being the row, column, and slice indices into
%   the base MR data.
%
%   'ROI', [r]: Returns ROI struct for the selected ROI. If the index r is
%   omitted, returns the selected ROI.
%
%   'MapVals', [m], [roi]: Get values of the data map m in the selected
%   ROI. m is an index into the loaded data maps. ROI can be the name
%   of a loaded ROI, index into the ui.rois field, or 3xN list of
%   coordinates in the base mr space. If omitted, returns the map value
%   at the cursor position. The returned values are of size 1 x nCoords,
%   where nCoords is the number of columns in roi.coords. For coordinates
%   in the ROI for which data are not defined, returns a NaN.
%
%   'OverlayVals', [roi]: Get values of the data map currently being
%   displayed as an overlay. If more than one overlays are displayed, the
%   returned value is a matrix of size nOverlays x nCoords. If omitted,
%   uses the cursor position as the ROI.
%
%	'OverlayMask', [whichOverlays]: Returns a 3-D logical matrix, the size of
%	ui.mr.data, with a 1 where a given voxel passes the overlay thresholds
%	and a 0 otherwise. If the optional 'whichOverlays' argument is passed,
%	will only threshold according to the selected overlays; otherwise,
%	thresholds according to all overlays.
%
%	'CursorPosition': position of the mrViewer cursor, in the "base" space
%	(units of (rows, cols, slices) in mr.ui.data).
%
% ras, 07/05.
val = [];

if nargin==0
    % find most current UI:
    % first check current figure to see if it has a UI
    tag = get(gcf,'Tag');
    if strncmp(tag,'mrViewer',8)==1
        val = get(gcf,'UserData');
    else
        ud = get(gcf,'UserData');
        if isstr(ud) & strncmp(ud,'mrViewer',8)==1
            % The user data is pointing to the main UI figure
            fig = findobj('Tag',ud);
            val= get(fig,'UserData');
        else
            % last thing to try: search for figures w/
            % tag 'mrViewer[#]', and get highest #
            tag = 'mrViewer1';
            if isempty(findobj('Tag',tag))
                warning('No mrViewer UIs found!')
                val = [];
            else
                i = 1;
                while ~isempty(findobj('Tag',sprintf('mrViewer%i',i+1)))
                    i = i + 1;
                end
                fig = findobj('Tag',sprintf('mrViewer%i',i));
                val = get(fig,'UserData');
            end
        end
    end

    return
end

if length(varargin)==1
    if isstruct(varargin{1})
        % request to print out UI info
        disp('mrViewer UI Info: ')
        ui = varargin{1};
        fprintf('Base MR file: %s\n', ui.mr.name);
        fprintf('Base MR path: %s\n\n', ui.mr.path);
        for i = 1:length(ui.maps)
            fprintf('Map %i file: %s\n', i, ui.maps(i).name);
            fprintf('Map %i path: %s\n\n', i, ui.maps(i).path);
        end
        disp('UI Settings:')
        disp(ui.settings)
        val = ui.settings;
    else
        ui = mrViewGet;
        val = mrViewGet(ui,varargin{1});
    end
    return
end

% if we've gotten here, we have both a UI struct and an argument to get
ui = varargin{1};
prop = varargin{2};
if length(varargin)>2
    args = varargin(3:end);
else
    args = {};
end

% allow an empty UI struct to be passed, meaning get the current one
if isempty(ui), ui = mrViewGet; end
if ishandle(ui), ui = get(ui, 'UserData'); end

switch lower(prop)
case {'imgcoords','imagecoords','imagecoordinates'},
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % coordinates of displayed images in selected data space %
    % (args can specify an image #, otherwise return cell of %
    % coords for all displayed images)                       %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if ~isempty(args)       % get coords for specified image
        selectedImages = args{1};
    else                    % get coords for all images
        selectedImages = 1:length(ui.display.images);
    end

    b = ui.settings.bounds;
    val = {};
    for i = selectedImages
        % get the coords corresponding to this slice
        rng = {[b(1,1):b(1,2)] [b(2,1):b(2,2)] [b(3,1):b(3,2)]};
        rng{ui.display.oris(i)} = ui.display.slices(i);
        [X Y Z] = meshgrid(rng{2},rng{1},rng{3});
        val{end+1} = [Y(:) X(:) Z(:)]'; clear X Y Z
    end

    % if an image was specified, return the coords directly
    if ~isempty(args),  val = val{1};  end

case {'datacoords'},
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    % coordinates of displayed images in base data space     %
    % (args can specify an image #, otherwise return cell of %
    % coords for all displayed images)                       %
    %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
    if ~isempty(args)       % get coords for specified image
        selectedImages = args{1};
    else                    % get coords for all images
        selectedImages = 1:length(ui.display.images);
    end

    val = {};

    for i = selectedImages
        coords = mrViewGet(ui,'ImageCoords',i);
        if ui.settings.space ~= 1
            %%%%%%%%%%%%%%%%%%%%%
            % Transformed Space %
            %%%%%%%%%%%%%%%%%%%%%
            % xform from image space -> data space
            % (this is the inverse of the xform we
            % store in spaces)
            s = ui.settings.space;
            if ~isempty(ui.spaces(s).coords)
                % do the direct-coord method, or
                % use an external function
            else
                xform = inv(ui.spaces(s).xform);
                coords = xform * [coords; ones(1,size(coords,2))];
                coords = coords(1:3,:);
            end
        end

        % return coords
        val{end+1} = coords;
    end

    % if an image was specified, return the coords directly
    if ~isempty(args),  val = val{1};  end

case {'cursorcoords' 'cursorpos' 'cursorposition' 'cursordatacoords'}
    % position of cursor in base space
    val = ui.settings.cursorLoc;

    if ui.settings.space ~= 1
        %%%%%%%%%%%%%%%%%%%%%
        % Transformed Space %
        %%%%%%%%%%%%%%%%%%%%%
        % xform from image space -> data space
        % (this is the inverse of the xform we
        % store in spaces)
        s = ui.settings.space;
        if ~isempty(ui.spaces(s).coords)
            % do the direct-coord method, or
            % use an external function
        else
            xform = inv(ui.spaces(s).xform);
            val = xform * [val(:); 1];
            val = val(1:3,:)';
        end
	end

case {'displayformat'},		val = ui.settings.displayFormat;
case {'curslice', 'slice', 'selectedslice', 'firstslice'}
    val = ui.settings.slice;

case {'numslices' 'nslices'}
    val = ui.mr.dims(3);

case {'base' 'mr' 'anat' 'underlay'},   val = ui. mr;
case {'maps'}, val = ui.maps;
case {'overlay' 'curmap' 'selectedmap'},
	if ~isempty(args), o = args{1}; else, o = 1; end
    val = ui.maps(ui.overlays(o).mapNum);

case {'overlaysettings' 'overlaystruct'}
	if ~isempty(args), o = args{1}; else, o = 1:length(ui.overlays); end
	val = ui.overlays(o);

case {'roiviewmode' 'roidrawmode'}, val = ui.settings.roiViewMode;

case {'curroinum' 'roinum' 'selroinum' 'selectedroinum'},
	val = ui.settings.roi;
case {'roi' 'selroi' 'curroi' 'selectedroi'}
    if isempty(args), r = ui.settings.roi; else, r = args{1}; end
    val = ui.rois(r);

case {'mesh' 'curmesh'}
    s = ui.settings.segmentation;
    if s==0 | isempty(ui.segmentation), val = []; return; end

    if isempty(ui.segmentation(s).mesh)     % load a mesh
        ui = mrViewLoad(ui, '', 'mesh');
    end

    val = segGet(ui.segmentation(s), 'mesh');

case {'zoom'}, val = ui.settings.zoom;
case {'imagezoom'}, % zoom in format [xmin xmax ymin ymax] for displayed iamges
    val = ui.settings.zoom;
    if ui.settings.displayFormat==2 % 3-axis view: zoom different for each
        warning('Zoom is 3-D in 3-axis view -- returning 3 x 2 matrix');
        return
    end
    otherDims = setdiff(1:3, ui.settings.ori);
    val = [val(otherDims(2),:) val(otherDims(1),:)];

case {'displayimages' 'images'}, val = ui.display.images;
case {'croppedimages', 'zoomedimages'},  % images that are zoomed in on
     images = ui.display.images;
     zoom = round( mrViewGet(ui, 'imagezoom') );
     if ui.settings.displayFormat==2        % different zoom for each image
         for i = 1:3
             otherDims = setdiff(1:3, i); % orientation
             rows = zoom(otherDims(2),:);
             cols = zoom(otherDims(1),:);
             val{i} = images{i}(rows,cols,:);
         end
     else                                   % same zoom for each image
         for i = 1:length(images)
             val{i} = images{i}(zoom(3):zoom(4),zoom(1):zoom(2),:);
         end
     end

case {'colorbar' 'cbar'}
    if ~isempty(args), o = args{1}; else, o = 1; end
    val = ui.overlays(o).cbar;

case {'segmentationnum' 'segnum' 'cursegnum' 'cursegmentationnum'}
    val = ui.settings.segmentation;

case {'segmentation' 'seg' 'segstruct' 'cursegmentation' 'selectedsegmentation'}
    val = ui.segmentation( ui.settings.segmentation );

case {'curmeshnum' 'curmeshn' 'meshnum' 'selectedmeshnum'}
    s = ui.settings.segmentation;
    val = ui.segmentation(s).settings.mesh;

case {'curmesh' 'currentmesh' 'selectedmesh' 'mesh'}
    s = ui.settings.segmentation;
    m = ui.segmentation(s).settings.mesh;
    val = ui.segmentation(s).mesh{m};

case {'allmeshnames' 'meshlist'}
	val = {};
	for s = 1:length(ui.segmentation)
		for m = 1:length(ui.segmentation(s).mesh)
			val{end+1} = sprintf('%i %s', ...
								ui.segmentation(s).mesh{m}.id, ...
								ui.segmentation(s).mesh{m}.name);
		end
	end

case {'curmeshdir' 'selectedmeshdir' 'meshdir'}
    s = ui.settings.segmentation;
    val = ui.segmentation(s).params.meshDir;

case {'mapvals' 'mapdata'}
    if length(args) < 1, error('Need to specify a map index.'); end
    m = args{1};
    if length(args) >= 2,       roi = roiParse(args{2}, ui);
    else,                       roi = roiParse(ui.settings.cursorLoc');
	end
	% get xform from viewer coordinates -> map coordinates
	viewer2MapXform = inv(ui.maps(m).baseXform);

	% xform ROI coords to map coords
	roi = roiXformCoords(roi, viewer2MapXform, ui.maps(m).voxelSize(1:3));

	% sample the data at the map coordinates
	val = mrGet(ui.maps(m), 'data', roi.coords);

case {'overlayvals' 'overlaydata'}
    if isempty(args), roi = roiParse(ui.settings.cursorLoc');
    else,             roi = roiParse(args{1}, ui);
    end

    for o = 1:length(ui.overlays)
        val(o,:) = mrViewGet(ui, 'mapvals', ui.overlays(o).mapNum, roi);
	end

case {'overlaymask' 'datamask'}
    %% 3-D binary matrix with 1 where voxels pass the overlay thresholds,
    %% and 0 otherwise.
    if isempty(args), whichOverlays = find( ~([ui.overlays.hide]) );
    else,             whichOverlays = args{1};
	end

	% initialize empty matrix
	val = logical( zeros(ui.mr.dims(1:3)) );

	% input check
	if isempty(whichOverlays)
		warning('[mrViewGet(''overlaymask'')]: No overlays. Returning emtpy matrix.')
		return
	end

	% get the coords for all slices in the base data space
	[X Y Z] = meshgrid( 1:size(val,2), 1:size(val,1), 1:size(val,3) );
	coords = [Y(:) X(:) Z(:)]';

	% restrict coords to those which pass the threshold
	% of this overlay
	[coords, imageMask] = mrViewRestrict(ui, coords, whichOverlays);

	% set those coords which pass the threshold to 1 (true)
	I = sub2ind( size(val), coords(1,:), coords(2,:), coords(3,:) );
	val(I) = true;

otherwise, warning('Unknown mrViewer property.')

end

return


% eeg_checkchanlocs() - Check the consistency of the channel locations structure
%                  of an EEGLAB dataset.
%
% Usage:
%  >> EEG = eeg_checkchanlocs( EEG, 'key1', value1, 'key2', value2, ... );
%  >> [chanlocs chaninfo] = eeg_checkchanlocs( chanlocs, chaninfo, 'key1', value1, 'key2', value2, ... );
%
% Inputs:
%   EEG      - EEG dataset
%   chanlocs - EEG.chanlocs structure
%   chaninfo - EEG.chaninfo structure
%
% Outputs:
%   EEG        - new EEGLAB dataset with updated channel location structures
%                EEG.chanlocs, EEG.urchanlocs, EEG.chaninfo
%   chanlocs   - updated channel location structure
%   chaninfo   - updated chaninfo structure
%
% Author: Arnaud Delorme, SCCN/INC/UCSD, March 2, 2011

% Copyright (C) SCCN/INC/UCSD, March 2, 2011, 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

% Hey Arno -- this is a quick fix to make an analysis work for Makoto
% I think the old version had a bug...

function [chans, chaninfo, chanedit]= eeg_checkchanlocs(chans, chaninfo);

if nargin < 1
    help eeg_checkchanlocs;
    return;
end;

if nargin < 2
    chaninfo = [];
end;

processingEEGstruct = 0;
if isfield(chans, 'data')
    processingEEGstruct = 1;
    tmpEEG = chans;
    chans = tmpEEG.chanlocs;
    chaninfo = tmpEEG.chaninfo;
end;

if ~isfield(chans, 'datachan')
    [chanedit,dummy,complicated] = insertchans(chans, chaninfo);
else
    chanedit = chans;
    complicated = true;
end;

nosevals       = { '+X' '-X' '+Y' '-Y' };
if ~isfield(chaninfo, 'plotrad'), chaninfo.plotrad = []; end;
if ~isfield(chaninfo, 'shrink'),  chaninfo.shrink = [];  end;
if ~isfield(chaninfo, 'nosedir'), chaninfo.nosedir = nosevals{1}; end;

% handles deprecated fields
% -------------------------
plotrad  = [];
if isfield(chanedit, 'plotrad'),
    plotrad = chanedit(1).plotrad;
    chanedit = rmfield(chanedit, 'plotrad');
    if isstr(plotrad) & ~isempty(str2num(plotrad)), plotrad = str2num(plotrad); end;
    chaninfo.plotrad = plotrad;
end;
if isfield(chanedit, 'shrink') && ~isempty(chanedit(1).shrink)
    shrinkorskirt = 1;
    if ~isstr(chanedit(1).shrink)
        plotrad = 0.5/(1-chanedit(1).shrink); % convert old values
    end;
    chanedit = rmfield(chanedit, 'shrink');
    chaninfo.plotrad = plotrad;
end;

% set non-existent fields to []
% -----------------------------
fields    = { 'labels' 'theta' 'radius' 'X'   'Y'   'Z'   'sph_theta' 'sph_phi' 'sph_radius' 'type' 'ref' 'urchan' };
fieldtype = { 'str'    'num'   'num'    'num' 'num' 'num' 'num'       'num'     'num'        'str'  'str' 'num'    };
check_newfields = true; %length(fieldnames(chanedit)) < length(fields);
if ~isempty(chanedit)
    for index = 1:length(fields)
        if check_newfields && ~isfield(chanedit, fields{index})
            % new field
            % ---------
            if strcmpi(fieldtype{index}, 'num')
                chanedit = setfield(chanedit, {1}, fields{index}, []);
            else
                for indchan = 1:length(chanedit)
                    chanedit = setfield(chanedit, {indchan}, fields{index}, '');
                end;
            end;
        else
            % existing fields
            % ---------------
            allvals = {chanedit.(fields{index})};
            if strcmpi(fieldtype{index}, 'num')
                if ~all(cellfun('isclass',allvals,'double'))
                    numok = cellfun(@isnumeric, allvals);
                    if any(numok == 0)
                        for indConvert = find(numok == 0)
                            chanedit = setfield(chanedit, {indConvert}, fields{index}, []);
                        end;
                    end;
                end
            else
                strok = cellfun('isclass', allvals,'char');
                if strcmpi(fields{index}, 'labels'), prefix = 'E'; else prefix = ''; end;
                if any(strok == 0)
                    for indConvert = find(strok == 0)
                        try
                              strval   = [ prefix num2str(getfield(chanedit, {indConvert}, fields{index})) ];
                              chanedit = setfield(chanedit, {indConvert}, fields{index}, strval);
                        catch
                            chanedit = setfield(chanedit, {indConvert}, fields{index}, '');
                        end;
                    end;
                end;
            end;
        end;
    end;
end;
if ~isequal(fieldnames(chanedit)',fields)
    try
        chanedit = orderfields(chanedit, fields);
    catch, end;
end

% check if duplicate channel label
% --------------------------------
if isfield(chanedit, 'labels')
    tmp = sort({chanedit.labels});
    if any(strcmp(tmp(1:end-1),tmp(2:end)))
        disp('Warning: some channels have the same label');
    end
end;

% check for empty channel label
% -----------------------------
if isfield(chanedit, 'labels')
    indEmpty = find(cellfun(@isempty, {chanedit.labels}));
    if ~isempty(indEmpty)
        tmpWarning = warning('backtrace');
        warning backtrace off;
        warning('channel labels should not be empty, creating unique labels');
        warning(tmpWarning);
        for index = indEmpty
            chanedit(index).labels = sprintf('E%d', index);
        end;
    end;
end;

% remove fields
% -------------
if isfield(chanedit, 'sph_phi_besa'  ), chanedit = rmfield(chanedit, 'sph_phi_besa'); end;
if isfield(chanedit, 'sph_theta_besa'), chanedit = rmfield(chanedit, 'sph_theta_besa'); end;

% reconstruct the chans structure
% -------------------------------
if complicated
    [chans chaninfo.nodatchans] = getnodatchan( chanedit );
    if ~isfield(chaninfo, 'nodatchans'), chaninfo.nodatchans = []; end;
    if isempty(chanedit)
        for iField = 1:length(fields)
            chanedit = setfield(chanedit, fields{iField}, []);
        end;
    end;
else
    chans = rmfield(chanedit,'datachan');
    chaninfo.nodatchans = [];
end

if processingEEGstruct
    tmpEEG.chanlocs = chans;
    tmpEEG.chaninfo = chaninfo;
    chans = tmpEEG;
end;

% ---------------------------------------------
% separate data channels from non-data channels
% ---------------------------------------------
function [chans, fidsval] = getnodatchan(chans)
if isfield(chans,'datachan')
    [chans(cellfun('isempty',{chans.datachan})).datachan] = deal(0);
    fids = [chans.datachan] == 0;
    fidsval = chans(fids);
    chans = rmfield(chans(~fids),'datachan');
else
    fids = [];
end;

% ----------------------------------------
% fuse data channels and non-data channels
% ----------------------------------------
function [chans, chaninfo,complicated] = insertchans(chans, chaninfo, nchans)
if nargin < 3, nchans = length(chans); end;
[chans.datachan] = deal(1);
complicated = false;        % whether we need complicated treatment of datachans & co further down the road.....

if isfield(chans,'type')
    mask = strcmpi({chans.type},'FID') | strcmpi({chans.type},'IGNORE');
    if any(mask)
        [chans(mask).datachan] = deal(0);
        complicated = true;
    end
end
if length(chans) > nchans & nchans ~= 0 % reference at the end of the structure
    chans(end).datachan = 0;
    complicated = true;
end;
if isfield(chaninfo, 'nodatchans')
    if ~isempty(chaninfo.nodatchans) && isstruct(chaninfo.nodatchans)
        chanlen = length(chans);
        for index = 1:length(chaninfo.nodatchans)
            fields = fieldnames( chaninfo.nodatchans );
            ind = chanlen+index;
            for f = 1:length( fields )
                chans = setfield(chans, { ind }, fields{f}, getfield( chaninfo.nodatchans, { index },  fields{f}));
            end;
            chans(ind).datachan = 0;
            complicated = true;
        end;
        chaninfo = rmfield(chaninfo, 'nodatchans');

        % put these channels first
        % ------------------------
        % tmp = chans(chanlen+1:end);
        % chans(length(tmp)+1:end) = chans(1:end-length(tmp));
        % chans(1:length(tmp)) = tmp;
    end;
end;


function varargout = ImageGUI(varargin)
% IMAGEGUI MATLAB code for ImageGUI.fig
%      IMAGEGUI, by itself, creates a new IMAGEGUI or raises the existing
%      singleton*.
%
%      H = IMAGEGUI returns the handle to a new IMAGEGUI or the handle to
%      the existing singleton*.
%
%      IMAGEGUI('CALLBACK',hObject,eventData,handles,...) calls the local
%      function named CALLBACK in IMAGEGUI.M with the given input arguments.
%
%      IMAGEGUI('Property','Value',...) creates a new IMAGEGUI or raises the
%      existing singleton*.  Starting from the left, property value pairs are
%      applied to the GUI before ImageGUI_OpeningFcn gets called.  An
%      unrecognized property name or invalid value makes property application
%      stop.  All inputs are passed to ImageGUI_OpeningFcn via varargin.
%
%      *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 ImageGUI

% Copyright 2011-2013 The MathWorks, Inc.

% Last Modified by GUIDE v2.5 31-Mar-2011 16:55:25

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @ImageGUI_OpeningFcn, ...
                   'gui_OutputFcn',  @ImageGUI_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 ImageGUI is made visible.
function ImageGUI_OpeningFcn(hObject, eventdata, 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   command line arguments to ImageGUI (see VARARGIN)

% Choose default command line output for ImageGUI
handles.output = hObject;

% Update handles structure
guidata(hObject, handles);

% UIWAIT makes ImageGUI wait for user response (see UIRESUME)
% uiwait(handles.figure1);

movegui(handles.figure1, 'center');

% --- Outputs from this function are returned to the command line.
function varargout = ImageGUI_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 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)

findBallFcn(handles.im);

% --------------------------------------------------------------------
function uipushtool1_ClickedCallback(hObject, eventdata, handles)
% hObject    handle to uipushtool1 (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

[filename, pathname] = uigetfile('*.jpg', 'Select image file');

im = imread(fullfile(pathname, filename));

imshow(im);

handles.im = im;

guidata(hObject, handles);


classdef Stress3DVoigtTensor < SecondOrder3DVoigtTensor ...
                               & StressDescriptor ...

    methods (Access = public)

        function obj = Stress3DVoigtTensor()
        end
    end

end


classdef mtexFigure < handle
%
% a class to handles figures equaly sized axes with the following features
%
% * nicely resize axes
% * global or individual colorbars
% *
%
% Syntax
%   newMTEXFigure
%
%
% Class Properties
%  parent            - handle of the parent figure
%  children          - handles to all axes
%  cBarAxis          - handles to all colorbar axes
%  innerPlotSpacing  -
%  keepAspectRatio   -
%  nrows = 1         - number of rows
%  ncols = 1         - number of columns
%  axisWidth         - width of an individual axis
%  axisHeight        - height of an individual axis
%  cbx = 0           - colorbar width
%  cby = 0           - colorbar height
%  tightInset        - is added to axisSize
%  figTightInset     - is added to figSize
%  layoutMode        - 'auto' or 'user'
%
% Dependent Class Properties
%   currentAxes      - handle of the current axis
%   currentId        - id of te current axis
%   axesWidth        -
%   axesHeight       -
%   outerPlotSpacing -
%   dataCursorMenu   - handle of the data cursor context menu
%
% Description
%
% The calculation of the layout is initiated by the command
% <mtexFigure.drawNow.html drawNow>. This involves calls to the following
% functions:
%
%  drawNow
%    |  |
%    V  |
%  calcTightInset -> compute width of boundary around each axis
%       |
%       V
%  updateLayout
%       |
%       V
%  calcPartition -> compute partition (nrows, ncols)
%       |
%       V
%  calcAxesSize  -> compute axes size
%
% A mtexFigure may have the following children
%
% * <mapPlot.html mapPlot> -> micronbar
% * <sphericalPlot.html sphericalPlot> (stored in appdata of axes handle)
% * pfPlot [CS,SS,h]
% * ipdfPlot [CS]
% * MillerPlot [r,SS]
%
% See also
%

  properties
    parent            % the parent figure
    children          % the axes
    cBarAxis          % the colorbar axes
    innerPlotSpacing  %
    keepAspectRatio   %
    nrows = 1         % number of rows
    ncols = 1         % number of columns
    axisWidth         % width of an individual axis
    axisHeight        % height of an individual axis
    cbx = 0           % colorbar width
    cby = 0           % colorbar height
    tightInset = [0,0,0,0] % is added to axisSize
    figTightInset = [10,10,10,10] % is added to figSize
    layoutMode = 'auto' % set to user to fix it
    figSizeFactor = 0 % relative to the full screen
  end

  properties (Dependent = true)
    currentAxes       % current axis
    currentId         % current axis id
    axesWidth         %
    axesHeight        %
    outerPlotSpacing  %
    dataCursorMenu    % handle of the data cursor context menu
  end

  properties (Access = protected)
    cBarShift
  end

  methods

    function mtexFig = mtexFigure(varargin)

      % clear figure and set it up

      clf('reset');
      rmallappdata(gcf);
      set(gcf,'Visible','on');

      % set figure name
      if ~isempty(get_option(varargin,'FigureTitle'))
        set(gcf,'Name',get_option(varargin,'FigureTitle'));
      end

      % set custom resize function
      set(gcf,'ResizeFcn',@(src,evt) updateLayout(mtexFig));

      mtexFig.parent = gcf;

      mtexFig.outerPlotSpacing = get_option(varargin,'outerPlotSpacing',...
        getMTEXpref('outerPlotSpacing'));
      mtexFig.innerPlotSpacing = get_option(varargin,'innerPlotSpacing',...
        getMTEXpref('innerPlotSpacing'));
      mtexFig.keepAspectRatio = get_option(varargin,'keepAspectRatio',true);

      colrow = get_option(varargin,'layout',[1 1]);
      mtexFig.nrows = get_option(varargin,'nrows',colrow(1));
      mtexFig.ncols = get_option(varargin,'ncols',colrow(2));

      if check_option(varargin,{'nrows','ncols','layout'})
        mtexFig.layoutMode = 'user';
      end

      switch get_option(varargin,'figSize','','char')
        case 'huge'
          mtexFig.figSizeFactor = 1;
        case 'large'
          mtexFig.figSizeFactor = 0.8;
        case {'normal','medium'}
          mtexFig.figSizeFactor = 0.5;
        case 'small'
          mtexFig.figSizeFactor = 0.35;
        case 'tiny'
          mtexFig.figSizeFactor =  0.25;
        otherwise
          mtexFig.figSizeFactor = get_option(varargin,'figSize',0,'double');
      end

      set(mtexFig.parent,'color',[1 1 1],'nextPlot','replaceChildren');
      setappdata(mtexFig.parent,'mtexFig',mtexFig);

      varargin = delete_option(varargin,'color',1);
      varargin = delete_option(varargin,'position',1);
      optiondraw(mtexFig.parent,varargin{:});

      % set data cursor
      if check_option(varargin,'datacursormode')
        dcm_obj = datacursormode(mtexFig.parent);
        set(dcm_obj,'SnapToDataVertex','off')
        set(dcm_obj,'UpdateFcn',ensurecell(get_option(varargin,'datacursormode')));
        if ~check_option(varargin,'3d')
          datacursormode on;
        end
      end

      set(mtexFig.parent,'DefaultAxesCreateFcn', @updateChildren);
      set(mtexFig.parent,'DefaultAxesDeleteFcn', @deleteChildren);

      MTEXFigureMenu(mtexFig,varargin{:});

      h = findall(mtexFig.parent,'ToolTipString','Insert Colorbar');
      set(h,'ClickedCallback',@(a,b) mtexColorbar(mtexFig,a,b));

      function updateChildren(a,b)

        % prevent that this is called by colorbar
        x = dbstack;
        if any(strcmpi(x(2).name,{'colorbar','legend'})), return;end

        mtexFig.children = ...
        flipud(findobj(mtexFig.parent,'type','axes',...
        '-not','tag','Colorbar','-and','-not','tag','legend'));
      end

      function deleteChildren(a,b)
        mtexFig.children(mtexFig.children==a) = [];
      end

    end

    function ax = gca(mtexFig)
      % return current axis if exist otherwise create a new one

      if mtexFig.currentId == 0, mtexFig.currentId = 1;end

      ax = mtexFig.currentAxes;

    end

    % ---------------------------------------------------------

    function ax = get.currentAxes(mtexFig)
      ax = get(mtexFig.parent,'CurrentAxes');
    end

    function set.currentAxes(mtexFig,ax)
      try
        set(mtexFig.parent,'CurrentAxes',ax);
      end
    end

    function id = get.currentId(mtexFig)
      if isempty(mtexFig.currentAxes)
        id = 0;
      else
        id = find(mtexFig.currentAxes == mtexFig.children);
      end
    end

    function set.currentId(mtexFig,id)

      if id > numel(mtexFig.children) % create a nex axes
        for k = numel(mtexFig.children)+1:id
          axes('visible','off','parent',mtexFig.parent);
        end
        set(mtexFig.parent,'nextplot','add');

        if numel(mtexFig.children) > mtexFig.ncols * mtexFig.nrows
          mtexFig.ncols = ceil(numel(mtexFig.children) / mtexFig.nrows);
        end

      else
        set(mtexFig.parent,'CurrentAxes',mtexFig.children(id));
      end
    end

    function w = get.outerPlotSpacing(mtexFig)
      w = min(mtexFig.figTightInset);
    end

    function set.outerPlotSpacing(mtexFig,w)
      mtexFig.figTightInset = w * [1,1,1,1];
    end

    function aw = get.axesWidth(mtexFig)
      % the width of all axes is the number of columns times the width of
      % each single axis + inner and outer spacing

      aw = mtexFig.ncols * (mtexFig.axisWidth + sum(mtexFig.tightInset([1,3])))...
        + sum(mtexFig.figTightInset([1,3])) + ...
        (mtexFig.ncols-1) * mtexFig.innerPlotSpacing;
    end

    function ah = get.axesHeight(mtexFig)
      % the height of all axes is the number of rows times the height of
      % each single axis + inner and outer spacing

      ah = mtexFig.nrows * (mtexFig.axisHeight + sum(mtexFig.tightInset([2,4])))...
        + sum(mtexFig.figTightInset([2,4])) + ...
        (mtexFig.nrows-1) * mtexFig.innerPlotSpacing;
    end

    function setCamera(mtexFig,varargin)

      for a = 1:numel(mtexFig.children)
        setCamera(mtexFig.children(a),varargin{:});
      end
      mtexFig.drawNow;
    end

    function dcm = get.dataCursorMenu(mtexFig)

     dcm_obj = datacursormode(mtexFig.parent);
     dcm = dcm_obj.UIContextMenu;

    end

  end
end


function spm_opt_bfun

d       = round(get(gca,'CurrentPoint'));
i       = d(1);
pE      = get(gcf,'UserData');
P       = spm_fieldindices(pE,i);
j       = spm_fieldindices(pE,P);
j       = find(j == i);
[i j k] = ind2sub(size(spm_cat(getfield(pE,P))),j);

fprintf('\n%s(%i,%i,%i)\n',P,i,j,k);

return


% std_erpplot() - Command line function to plot STUDY cluster component ERPs. Either
%                 displays grand mean ERPs for all requested clusters in the same figure,
%                 with ERPs for different conditions (if any) plotted in different colors.
%                 Else, displays ERP for each specified cluster in separate figures
%                 (per condition), each containing the cluster component ERPs plus
%                 the grand mean cluster ERP (in bold). ERPs can be plotted only if
%                 component ERPs were computed and saved in the STUDY EEG
%                 datasets.
%                 These can be computed during pre-clustering using the gui-based
%                 function pop_preclust() or the equivalent command line functions
%                 eeg_createdata() and eeg_preclust(). Called by pop_clustedit().
%                 and std_propplot().
% Usage:
%   >> [STUDY] = std_erpplot(STUDY, ALLEEG, key1, val1, key2, val2);
%   >> [STUDY erpdata erptimes pgroup pcond pinter] = std_erpplot(STUDY, ALLEEG, ...);
%
% Inputs:
%   STUDY      - EEGLAB STUDY set comprising some or all of the EEG datasets in ALLEEG.
%   ALLEEG     - global EEGLAB vector of EEG structures for the datasets included
%                in the STUDY. A STUDY set ALLEEG is typically created by load_ALLEEG().
%
% Optional inputs for component plotting:
%   'clusters' - [numeric vector|'all'] indices of clusters to plot.
%                If no component indices ('comps' below) are given, the average
%                ERPs of the requested clusters are plotted in the same figure,
%                with ERPs for different conditions (and groups if any) plotted
%                in different colors. In 'comps' (below) mode, ERPS for each
%                specified cluster are plotted in separate figures (one per
%                condition), each overplotting cluster component ERPs plus the
%                average cluster ERP in bold. Note this parameter has no effect
%                if the 'comps' option (below) is used. {default: 'all'}
%   'comps'    - [numeric vector|'all'] indices of the cluster components to plot.
%                Note that 'comps', 'all' is equivalent to 'plotsubjects', 'on'.
%
% Optional inputs for channel plotting:
%   'channels' - [numeric vector]  specific channel group to plot. By
%                default, the grand mean channel ERP is plotted (using the
%                same format as for the cluster component means described above)
%   'subject'  - [numeric vector]  In 'changrp' mode (above), index of
%                the subject(s) to plot. Else by default, plot all components
%                in the cluster.
%   'plotsubjects' - ['on'|'off'] When 'on', plot ERP of all subjects.
%
% Other optional inputs:
%   'key','val' - All optional inputs to pop_erpparams() are also accepted here
%                 to plot subset of time, statistics etc. The values used by default
%                 are the ones set using pop_erpparams() and stored in the
%                 STUDY structure.
%
% Outputs:
%   STUDY      - the input STUDY set structure with plotted cluster mean
%                ERPs data to allow quick replotting
%   erpdata    - [cell] ERP data for each condition, group and subjects.
%                size of cell array is [nconds x ngroups]. Size of each element
%                is [times x subjects] for data channels or [times x components]
%                for component clusters. This array may be gicen as input
%                directly to the statcond() function or std_stats function
%                to compute statistics.
%   erptimes   - [array] ERP time point latencies.
%   pgroup     - [array or cell] p-values group statistics. Output of the
%                statcond() function.
%   pcond      - [array or cell] condition statistics. Output of the statcond()
%                function.
%   pinter     - [array or cell] groups x conditions statistics. Output of
%                statcond() function.
%
%   Example:
%            >> [STUDY] = std_erpplot(STUDY,ALLEEG, 'clusters', 2, 'comps', 'all');
%               % Plot cluster-2 component ERPs plus the mean ERP in bold.
%
%  See also  pop_clustedit(), pop_preclust(), eeg_createdata(), eeg_preclust(). std_propplot()
%
% Authors: Arnaud Delorme, CERCO, August, 2006-

% Copyright (C) Arnaud Delorme, 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

function [STUDY, erpdata, alltimes, pgroup, pcond, pinter] = std_erpplot(STUDY, ALLEEG, varargin)

if nargin < 2
    help std_erpplot;
    return;
end;
erpdata = []; alltimes = [];
pgroup = []; pcond = []; pinter = [];

% find datatype and default options
% ---------------------------------
dtype = 'erp';
for ind = 1:2:length(varargin)
    if strcmpi(varargin{ind}, 'datatype')
        dtype = varargin{ind+1};
    end;
end;
eval( [ 'STUDY = pop_' dtype 'params(STUDY, ''default'');' ...
        'params = STUDY.etc.' dtype 'params;' ] );
fields     = { 'filter' 'subtractsubjectmean' 'timerange' 'freqrange' 'topotime' 'topofreq' };
defaultval = { [] 'off' [] [] [] [] };
for ind=1:length(fields)
    if ~isfield(params, fields{ind}),
        params = setfield(params, fields{ind}, defaultval{ind});
    end;
end;

opt = finputcheck( varargin, { 'topotime'    'real'    [] params.topotime;
                               'topofreq'    'real'    [] params.topofreq;
                               'filter'      'real'    [] params.filter;
                               'timerange'   'real'    [] params.timerange;
                               'freqrange'   'real'    [] params.freqrange;
                               'ylim'        'real'    [] params.ylim;
                               'caxis'       'real'    [] params.ylim;
                               'statistics'  'string'  [] params.statistics;
                               'groupstats'  'string'  [] params.groupstats;
                               'condstats'   'string'  [] params.condstats;
                               'mcorrect'    'string'  [] params.mcorrect;
                               'plotgroups'  'string'  [] params.plotgroups;
                               'plotconditions' 'string'  [] params.plotconditions;
                               'subtractsubjectmean' 'string' [] params.subtractsubjectmean;
                               'threshold'   'real'    [] params.threshold;
                               'naccu'       'integer' [] params.naccu;
                               'singletrials' 'string' { 'on' 'off' }  params.singletrials;
                               'design'      'integer' []              STUDY.currentdesign;
                               'plotstderr'  'string'  []              'off';
                               'channels'    'cell'    []              {};
                               'clusters'    'integer' []              [];
                               'datatype'    'string'  { 'erp' 'spec' } 'erp';
                               'mode'        'string'  []              ''; % for backward compatibility
                               'comps'       { 'string' 'integer' } [] []; % for backward compatibility
                               'plotmode'    'string' { 'normal' 'condensed' }  'normal';
                               'unitx'       'string' { 'ms' 'Hz' }    'ms';
                               'plotsubjects' 'string' { 'on' 'off' }  'off';
                               'subject'     'string'  []              '';
                               'statmode'    'string'  { 'subjects' 'common' 'trials' } 'subjects'}, 'std_erpplot');
if isstr(opt), error(opt); end;
if isstr(opt.comps), opt.comps = []; opt.plotsubjects = 'on'; end;
if ~isempty(opt.topofreq),  opt.topotime  = opt.topofreq; end;
if ~isempty(opt.freqrange), opt.timerange = opt.freqrange; end;
datatypestr = upper(opt.datatype);
if strcmpi(datatypestr, 'spec'), datatypestr = 'Spectrum'; end;

% =======================================================================
% below this line, all the code should be non-specific to ERP or spectrum
% =======================================================================

allconditions = STUDY.design(opt.design).variable(1).value;
allgroups     = STUDY.design(opt.design).variable(2).value;
paired = { STUDY.design(opt.design).variable(1).pairing ...
           STUDY.design(opt.design).variable(2).pairing };

% for backward compatibility
% --------------------------
if strcmpi(opt.mode, 'comps'), opt.plotsubjects = 'on'; end;
if strcmpi(opt.singletrials, 'off') && ((~isempty(opt.subject) || ~isempty(opt.comps)))
    if strcmpi(opt.condstats, 'on') || strcmpi(opt.groupstats, 'on')
        opt.groupstats = 'off';
        opt.condstats   = 'off';
        disp('No statistics for single subject/component');
    end;
end;

if ~isnan(opt.topotime) & length(opt.channels) < 5
    warndlg2(strvcat('ERP parameters indicate that you wish to plot scalp maps', 'Select at least 5 channels to plot topography'));
    return;
end;

plotcurveopt = {};
if length(opt.clusters) > 1
    plotcurveopt = { 'figure' 'off' };
    opt.plotconditions = 'together';
    opt.plotgroups     = 'together';
    opt.condstats  = 'off';
    opt.groupstats = 'off';
end;
% if length(opt.channels) > 1 && strcmpi(opt.plotconditions, 'together') && strcmpi(opt.plotgroups, 'together')
%     plotcurveopt = { 'figure' 'off' };
%     opt.plotconditions = 'together';
%     opt.plotgroups     = 'together';
%     opt.condstats  = 'off';
%     opt.groupstats = 'off';
% end;
plotcurveopt = { plotcurveopt{:} ...
   'ylim',           opt.ylim, ...
   'threshold',      opt.threshold, ...
   'unitx'           opt.unitx, ...
   'filter',         opt.filter, ...
   'plotgroups',     opt.plotgroups, ...
   'plotconditions', opt.plotconditions };

% channel plotting
% ----------------
if ~isempty(opt.channels)

    chaninds = 1:length(opt.channels);

    if strcmpi(opt.datatype, 'erp')
        [STUDY erpdata alltimes] = std_readerp(STUDY, ALLEEG, 'channels', opt.channels(chaninds), 'timerange', opt.timerange, ...
                'subject', opt.subject, 'singletrials', opt.singletrials, 'design', opt.design);
    else
        [STUDY erpdata alltimes] = std_readspec(STUDY, ALLEEG, 'channels', opt.channels(chaninds), 'freqrange', opt.freqrange, ...
            'rmsubjmean', opt.subtractsubjectmean, 'subject', opt.subject, 'singletrials', opt.singletrials, 'design', opt.design);
    end;
    if isempty(erpdata), return; end;

    % select specific time
    % --------------------
    if ~isempty(opt.topotime) & ~isnan(opt.topotime)
        [tmp ti1] = min(abs(alltimes-opt.topotime(1)));
        [tmp ti2] = min(abs(alltimes-opt.topotime(end)));
        for condind = 1:length(erpdata(:))
            if ~isempty(erpdata{condind})
                erpdata{condind} = mean(erpdata{condind}(ti1:ti2,:,:),1);
            end;
        end;
    end;

    % compute statistics
    % ------------------
    [pcond pgroup pinter] = std_stat(erpdata, 'groupstats', opt.groupstats, 'condstats', opt.condstats, 'paired', paired, ...
                                         'statistics', opt.statistics, 'naccu', opt.naccu, 'threshold', opt.threshold, 'mcorrect', opt.mcorrect);
    if (~isempty(pcond) && length(pcond{1}) == 1) || (~isempty(pgroup) && length(pgroup{1}) == 1), pcond = {}; pgroup = {}; pinter = {}; end; % single subject STUDY
    if length(opt.channels) > 5 && ndims(erpdata{1}) < 3, pcond = {}; pgroup = {}; pinter = {}; end; % topo plotting for single subject

    % plot
    % ----
    locs = eeg_mergelocs(ALLEEG.chanlocs);
    locs = locs(std_chaninds(STUDY, opt.channels(chaninds)));
    [alltitles alllegends ] = std_figtitle('threshold', opt.threshold, 'mcorrect', opt.mcorrect, 'condstat', opt.condstats, 'cond2stat', opt.groupstats, ...
                             'statistics', opt.statistics, 'condnames', allconditions, 'plotsubjects', opt.plotsubjects, 'cond2names', allgroups, 'chanlabels', { locs.labels }, ...
                             'subject', opt.subject, 'valsunit', opt.unitx, 'vals', opt.topotime, 'datatype', datatypestr, 'cond2group', opt.plotgroups, 'condgroup', opt.plotconditions);

    if ~isempty(opt.topotime) && all(~isnan(opt.topotime))
        std_chantopo(erpdata, 'groupstats', pgroup, 'condstats', pcond, 'interstats', pinter, 'caxis', opt.caxis, ...
                                      'chanlocs', locs, 'threshold', opt.threshold, 'titles', alltitles);
    else
        std_plotcurve(alltimes, erpdata, 'groupstats', pgroup, 'legend', alllegends, 'condstats', pcond, 'interstats', pinter, ...
            'chanlocs', locs, 'titles', alltitles, 'plotsubjects', opt.plotsubjects, 'plotstderr', opt.plotstderr, ...
            'condnames', allconditions, 'groupnames', allgroups, 'plottopo', fastif(length(opt.channels) > 1, 'on', 'off'), plotcurveopt{:});
    end;

    set(gcf,'name',['Channel ' datatypestr ]);
    axcopy(gca);
else
    % plot component
    % --------------
    if length(opt.clusters) > 1, figure('color', 'w'); end;
    nc = ceil(sqrt(length(opt.clusters)));
    nr = ceil(length(opt.clusters)/nc);
    comp_names = {};

    for index = 1:length(opt.clusters)

        if length(opt.clusters) > 1, subplot(nr,nc,index); end;
        if strcmpi(opt.datatype, 'erp')
            [STUDY erpdata alltimes] = std_readerp(STUDY, ALLEEG, 'clusters', opt.clusters(index), 'timerange', opt.timerange, ...
                        'component', opt.comps, 'singletrials', opt.singletrials, 'design', opt.design);
        else
            [STUDY erpdata alltimes] = std_readspec(STUDY, ALLEEG, 'clusters', opt.clusters(index), 'freqrange', opt.freqrange, ...
                        'rmsubjmean', opt.subtractsubjectmean, 'component', opt.comps, 'singletrials', opt.singletrials, 'design', opt.design);
        end;
        if isempty(erpdata), return; end;

        % plot specific component
        % -----------------------
        if ~isempty(opt.comps)
            comp_names = { STUDY.cluster(opt.clusters(index)).comps(opt.comps) };
            opt.subject = STUDY.datasetinfo(STUDY.cluster(opt.clusters(index)).sets(1,opt.comps)).subject;
        end;
        [pcond pgroup pinter] = std_stat(erpdata, 'groupstats', opt.groupstats, 'condstats', opt.condstats, 'paired', paired, ...
                                         'statistics', opt.statistics, 'naccu', opt.naccu, 'threshold', opt.threshold, 'mcorrect', opt.mcorrect);

        [alltitles alllegends ] = std_figtitle('threshold', opt.threshold, 'plotsubjects', opt.plotsubjects, 'mcorrect', opt.mcorrect, 'condstat', opt.condstats, 'cond2stat', opt.groupstats, ...
                                 'statistics', opt.statistics, 'condnames', allconditions, 'cond2names', allgroups, 'clustname', STUDY.cluster(opt.clusters(index)).name, 'compnames', comp_names, ...
                                 'subject', opt.subject, 'valsunit', opt.unitx, 'vals', opt.topotime, 'datatype', datatypestr, 'cond2group', opt.plotgroups, 'condgroup', opt.plotconditions);

        if length(opt.clusters) > 1 && index < length(opt.clusters), alllegends = {}; end;
        std_plotcurve(alltimes, erpdata, 'condnames', allconditions, 'legend', alllegends, 'groupnames', allgroups, 'plotstderr', opt.plotstderr, ...
                                          'titles', alltitles, 'groupstats', pgroup, 'condstats', pcond, 'interstats', pinter, ...
                                          'chanlocs', ALLEEG(1).chanlocs, 'plotsubjects', opt.plotsubjects, plotcurveopt{:});
    end;

    set(gcf,'name', ['Component ' datatypestr ] );
    axcopy(gca);
end;


classdef Compliance3DVoigtTensor < SymmetricFourthOrder3DVoigtTensor ...
                                 & ComplianceDescriptor

end


function out=fieldnames(a)
% FIELDNAMES Get POLYNOMIAL object property names.
%
% NAMES=FIELDNAMES(P) returns a cell array of strings containing the
% names of the properties associated with uncertain polynomial object, P.
%
% See also GET, SET, POLYNOMIAL

% 11/12/2002: PJS  Initial Coding
%    This function allows tab completion of a public data fields.

aprop = PVget(a,'PropNames');
out = aprop.GPropNames;