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

% Last Modified by GUIDE v2.5 13-May-2021 10:35:04

% Begin initialization code - DO NOT EDIT
gui_Singleton = 1;
gui_State = struct('gui_Name',       mfilename, ...
                   'gui_Singleton',  gui_Singleton, ...
                   'gui_OpeningFcn', @lvd_EditGeometricVectorConstraintGUI_OpeningFcn, ...
                   'gui_OutputFcn',  @lvd_EditGeometricVectorConstraintGUI_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 lvd_EditGeometricVectorConstraintGUI is made visible.
function lvd_EditGeometricVectorConstraintGUI_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 lvd_EditGeometricVectorConstraintGUI (see VARARGIN)

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

    centerUIFigure(hObject);

    constraint = varargin{1};
    setappdata(hObject, 'constraint', constraint);

    lvdData = varargin{2};
    setappdata(hObject,'lvdData',lvdData);

	populateGUI(handles, constraint, lvdData);

    % Update handles structure
    guidata(hObject, handles);

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

function populateGUI(handles, constraint, lvdData)
    handles.constraintTypeLabel.String = constraint.getConstraintType();
    handles.constraintTypeLabel.TooltipString = constraint.getConstraintType();
    [unit, ~, ~, usesLbUb, ~, ~] = constraint.getConstraintStaticDetails();

    if(usesLbUb)
        [lb, ub] = constraint.getBounds();
        handles.ubText.String = fullAccNum2Str(ub);
        handles.lbText.String = fullAccNum2Str(lb);
    else
        handles.ubText.String = fullAccNum2Str(0);
        handles.lbText.String = fullAccNum2Str(0);
        handles.lbText.Enable = 'off';
        handles.ubText.Enable = 'off';
    end

    handles.scaleFactorText.String = fullAccNum2Str(constraint.getScaleFactor());

    handles.ubUnitLabel.String = unit;
    handles.lbUnitLabel.String = unit;

    evtNum = lvdData.script.getNumOfEvent(constraint.event);
    handles.eventCombo.String = lvdData.script.getListboxStr();
    if(not(isempty(evtNum)))
        handles.eventCombo.Value = evtNum;
    else
        handles.eventCombo.Value = 1;
    end

    handles.vectorCombo.String = lvdData.geometry.vectors.getListboxStr();

    if(isempty(constraint.vector))
        vectorInd = 1;
    else
        vectorInd = lvdData.geometry.vectors.getIndsForVectors(constraint.vector);
    end
    handles.vectorCombo.Value = vectorInd;

    frame = constraint.frame;
    if(isempty(frame))
        frame = LvdData.getDefaultInitialBodyInfo(lvdData.celBodyData).getBodyCenteredInertialFrame();
        constraint.frame = frame;
    end
    setappdata(handles.lvd_EditGeometricVectorConstraintGUI,'frame',frame);

    handles.refFrameTypeCombo.String = ReferenceFrameEnum.getListBoxStr();
    [ind, ~] = ReferenceFrameEnum.getIndForName(frame.typeEnum.name);
    handles.refFrameTypeCombo.Value = ind;
    handles.setFrameOptionsButton.TooltipString = sprintf('Current Frame: %s', frame.getNameStr());
    handles.refFrameNameLabel.String = sprintf('%s', frame.getNameStr());
    handles.refFrameNameLabel.TooltipString = sprintf('%s', frame.getNameStr());

    handles.constraintEvalTypeCombo.String = ConstraintEvalTypeEnum.getListBoxStr();
    handles.constraintEvalTypeCombo.Value = ConstraintEvalTypeEnum.getIndForName(constraint.evalType.name);
    constraintEvalTypeCombo_Callback(handles.constraintEvalTypeCombo, [], handles);

    evtNum = lvdData.script.getNumOfEvent(constraint.stateCompEvent);
    handles.compEventCombo.String = lvdData.script.getListboxStr();
    if(not(isempty(evtNum)))
        handles.compEventCombo.Value = evtNum;
    else
        handles.compEventCombo.Value = 1;
    end

    handles.eventNodeCombo.String = ConstraintStateComparisonNodeEnum.getListBoxStr();
    handles.eventNodeCombo.Value = ConstraintStateComparisonNodeEnum.getIndForName(constraint.eventNode.name);

    handles.stateComparisonNodeCombo.String = ConstraintStateComparisonNodeEnum.getListBoxStr();
    handles.stateComparisonNodeCombo.Value = ConstraintStateComparisonNodeEnum.getIndForName(constraint.stateCompNode.name);

    handles.comparisonTypeCombo.String = ConstraintStateComparisonTypeEnum.getListBoxStr();
    handles.comparisonTypeCombo.Value = ConstraintStateComparisonTypeEnum.getIndForName(constraint.stateCompType.name);

    handles.constActiveCheckbox.Value = constraint.active;

% --- Outputs from this function are returned to the command line.
function varargout = lvd_EditGeometricVectorConstraintGUI_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
    if(isempty(handles))
        varargout{1} = false;
    else
        constraint = getappdata(hObject, 'constraint');
        lvdData = getappdata(hObject,'lvdData');

        constraint.lb = str2double(handles.lbText.String);
        constraint.ub = str2double(handles.ubText.String);

        constraint.setScaleFactor(str2double(handles.scaleFactorText.String));

        constraint.vector = lvdData.geometry.vectors.getVectorAtInd(handles.vectorCombo.Value);

        frame = getappdata(hObject,'frame');
        constraint.frame = frame;

        [~, enums] = ConstraintEvalTypeEnum.getListBoxStr();
        constraint.evalType = enums(handles.constraintEvalTypeCombo.Value);

        [~, enums] = ConstraintStateComparisonTypeEnum.getListBoxStr();
        constraint.stateCompType = enums(handles.comparisonTypeCombo.Value);

        [~, enums] = ConstraintStateComparisonNodeEnum.getListBoxStr();
        constraint.eventNode = enums(handles.eventNodeCombo.Value);

        [~, enums] = ConstraintStateComparisonNodeEnum.getListBoxStr();
        constraint.stateCompNode = enums(handles.stateComparisonNodeCombo.Value);

        numEvents = lvdData.script.getTotalNumOfEvents();
        if(numEvents > 0)
            eventNum = handles.eventCombo.Value;
            constraint.event = lvdData.script.getEventForInd(eventNum);

            if(constraint.evalType == ConstraintEvalTypeEnum.StateComparison)
                eventNum = handles.compEventCombo.Value;
                constraint.stateCompEvent = lvdData.script.getEventForInd(eventNum);
            else
                constraint.stateCompEvent = LaunchVehicleEvent.empty(1,0);
            end
        else
            constraint.event = LaunchVehicleEvent.empty(1,0);
            constraint.stateCompEvent = LaunchVehicleEvent.empty(1,0);
        end

        constraint.active = logical(handles.constActiveCheckbox.Value);

        varargout{1} = true;
        close(handles.lvd_EditGeometricVectorConstraintGUI);
    end

% --- Executes on button press in saveAndCloseButton.
function saveAndCloseButton_Callback(hObject, eventdata, handles)
% hObject    handle to saveAndCloseButton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
    errMsg = validateInputs(handles);

    if(isempty(errMsg))
        uiresume(handles.lvd_EditGeometricVectorConstraintGUI);
    else
        msgbox(errMsg,'Invalid Constraint Inputs','error');
    end

function errMsg = validateInputs(handles)
    errMsg = {};

    constraint = getappdata(handles.lvd_EditGeometricVectorConstraintGUI, 'constraint');
    [~, lbLim, ubLim, usesLbUb, ~, ~] = constraint.getConstraintStaticDetails();

    if(usesLbUb)
        lwrBnd = str2double(get(handles.lbText,'String'));
        enteredStr = get(handles.lbText,'String');
        numberName = 'Lower Bound';
        lb = lbLim;
        ub = Inf;
        isInt = false;
        errMsg = validateNumber(lwrBnd, numberName, lb, ub, isInt, errMsg, enteredStr);

        uprBnd = str2double(get(handles.ubText,'String'));
        enteredStr = get(handles.ubText,'String');
        numberName = 'Upper Bound';
        lb = -Inf;
        ub = ubLim;
        isInt = false;
        errMsg = validateNumber(uprBnd, numberName, lb, ub, isInt, errMsg, enteredStr);

        if(isempty(errMsg))
            uprBnd = str2double(get(handles.ubText,'String'));
            enteredStr = get(handles.ubText,'String');
            numberName = 'Upper Bound';
            lb = lwrBnd;
            ub = ubLim;
            isInt = false;
            errMsg = validateNumber(uprBnd, numberName, lb, ub, isInt, errMsg, enteredStr);
        end
    end

    sf = str2double(get(handles.scaleFactorText,'String'));
    enteredStr = get(handles.scaleFactorText,'String');
    numberName = 'Scale Factor';
    lb = 1E-12;
    ub = Inf;
    isInt = false;
    errMsg = validateNumber(sf, numberName, lb, ub, isInt, errMsg, enteredStr);

    [~, enums] = ConstraintEvalTypeEnum.getListBoxStr();
    evalTypeEnum = enums(handles.constraintEvalTypeCombo.Value);
    if(evalTypeEnum == ConstraintEvalTypeEnum.StateComparison && ...
       handles.eventCombo.Value == handles.compEventCombo.Value && ...
       handles.eventNodeCombo.Value == handles.stateComparisonNodeCombo.Value)
        errMsg{end+1} = 'When using the state comparison evaluation type, the Applicable Event and Node and Comparison Event and Node must be different.';
    end

% --- Executes on button press in cancelButton.
function cancelButton_Callback(hObject, eventdata, handles)
% hObject    handle to cancelButton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
    close(handles.lvd_EditGeometricVectorConstraintGUI);

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

% Hints: get(hObject,'String') returns contents of lbText as text
%        str2double(get(hObject,'String')) returns contents of lbText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function lbText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to lbText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes during object creation, after setting all properties.
function constraintTypeLabel_CreateFcn(hObject, eventdata, handles)
% hObject    handle to constraintTypeLabel (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

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

% Hints: get(hObject,'String') returns contents of ubText as text
%        str2double(get(hObject,'String')) returns contents of ubText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function ubText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to ubText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on selection change in vectorCombo.
function vectorCombo_Callback(hObject, eventdata, handles)
% hObject    handle to vectorCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns vectorCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from vectorCombo

% --- Executes during object creation, after setting all properties.
function vectorCombo_CreateFcn(hObject, eventdata, handles)
% hObject    handle to vectorCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on selection change in eventCombo.
function eventCombo_Callback(hObject, eventdata, handles)
% hObject    handle to eventCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns eventCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from eventCombo

% --- Executes during object creation, after setting all properties.
function eventCombo_CreateFcn(hObject, eventdata, handles)
% hObject    handle to eventCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

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

% Hints: get(hObject,'String') returns contents of scaleFactorText as text
%        str2double(get(hObject,'String')) returns contents of scaleFactorText as a double
    newInput = get(hObject,'String');
    newInput = attemptStrEval(newInput);
    set(hObject,'String', newInput);

% --- Executes during object creation, after setting all properties.
function scaleFactorText_CreateFcn(hObject, eventdata, handles)
% hObject    handle to scaleFactorText (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: edit controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on key press with focus on lvd_EditGeometricVectorConstraintGUI or any of its controls.
function lvd_EditGeometricVectorConstraintGUI_WindowKeyPressFcn(hObject, eventdata, handles)
% hObject    handle to lvd_EditGeometricVectorConstraintGUI (see GCBO)
% eventdata  structure with the following fields (see MATLAB.UI.FIGURE)
%	Key: name of the key that was pressed, in lower case
%	Character: character interpretation of the key(s) that was pressed
%	Modifier: name(s) of the modifier key(s) (i.e., control, shift) pressed
% handles    structure with handles and user data (see GUIDATA)
    switch(eventdata.Key)
        case 'return'
            saveAndCloseButton_Callback(handles.saveAndCloseButton, [], handles);
        case 'enter'
            saveAndCloseButton_Callback(handles.saveAndCloseButton, [], handles);
        case 'escape'
            close(handles.lvd_EditGeometricVectorConstraintGUI);
    end

% --- Executes on button press in constActiveCheckbox.
function constActiveCheckbox_Callback(hObject, eventdata, handles)
% hObject    handle to constActiveCheckbox (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hint: get(hObject,'Value') returns toggle state of constActiveCheckbox

% --- Executes on selection change in constraintEvalTypeCombo.
function constraintEvalTypeCombo_Callback(hObject, eventdata, handles)
% hObject    handle to constraintEvalTypeCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns constraintEvalTypeCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from constraintEvalTypeCombo
    contents = cellstr(get(hObject,'String'));
    name = contents{get(hObject,'Value')};

    enum = ConstraintEvalTypeEnum.getEnumForListboxStr(name);
    switch enum
        case ConstraintEvalTypeEnum.FixedBounds
            handles.ubText.Enable = 'on';
            handles.lbText.Enable = 'on';
            handles.compEventCombo.Enable = 'off';
            handles.comparisonTypeCombo.Enable = 'off';
            handles.stateComparisonNodeCombo.Enable = 'off';

        case ConstraintEvalTypeEnum.StateComparison
            handles.ubText.Enable = 'off';
            handles.lbText.Enable = 'off';
            handles.compEventCombo.Enable = 'on';
            handles.comparisonTypeCombo.Enable = 'on';
            handles.stateComparisonNodeCombo.Enable = 'on';

        otherwise
            error('Unknown constraint evaluation type.');
    end

% --- Executes during object creation, after setting all properties.
function constraintEvalTypeCombo_CreateFcn(hObject, eventdata, handles)
% hObject    handle to constraintEvalTypeCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on selection change in compEventCombo.
function compEventCombo_Callback(hObject, eventdata, handles)
% hObject    handle to compEventCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns compEventCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from compEventCombo

% --- Executes during object creation, after setting all properties.
function compEventCombo_CreateFcn(hObject, eventdata, handles)
% hObject    handle to compEventCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on selection change in comparisonTypeCombo.
function comparisonTypeCombo_Callback(hObject, eventdata, handles)
% hObject    handle to comparisonTypeCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns comparisonTypeCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from comparisonTypeCombo

% --- Executes during object creation, after setting all properties.
function comparisonTypeCombo_CreateFcn(hObject, eventdata, handles)
% hObject    handle to comparisonTypeCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on selection change in refFrameTypeCombo.
function refFrameTypeCombo_Callback(hObject, eventdata, handles)
% hObject    handle to refFrameTypeCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns refFrameTypeCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from refFrameTypeCombo
    updateFrameChange(handles);

% --- Executes during object creation, after setting all properties.
function refFrameTypeCombo_CreateFcn(hObject, eventdata, handles)
% hObject    handle to refFrameTypeCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on button press in setFrameOptionsButton.
function setFrameOptionsButton_Callback(hObject, eventdata, handles)
% hObject    handle to setFrameOptionsButton (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)
    curFrame = getappdata(handles.lvd_EditGeometricVectorConstraintGUI,'frame');
    curFrame = curFrame.editFrameDialogUI(EditReferenceFrameContextEnum.ForState);

    setappdata(handles.lvd_EditGeometricVectorConstraintGUI,'frame',curFrame);

    handles.setFrameOptionsButton.Tooltip = sprintf('Current Frame: %s', curFrame.getNameStr());
    handles.refFrameNameLabel.String = sprintf('%s', curFrame.getNameStr());
    handles.refFrameNameLabel.TooltipString = sprintf('%s', curFrame.getNameStr());

function updateFrameChange(handles)
    lvdData = getappdata(handles.lvd_EditGeometricVectorConstraintGUI,'lvdData');
    celBodyData = lvdData.celBodyData;

    refEnumListBoxStr = ReferenceFrameEnum.getListBoxStr();
    selFrameTypeInd = handles.refFrameTypeCombo.Value;
    refFrameEnum = ReferenceFrameEnum.getEnumForListboxStr(refEnumListBoxStr{selFrameTypeInd});

%             if(not(isempty(newFrame)) && newFrame.typeEnum ~= refFrameEnum)
%                 refFrameEnum = newFrame.typeEnum;
%                 app.refFrameTypeCombo.Value = ReferenceFrameEnum.getIndForName(refFrameEnum.name);
%             end

    switch refFrameEnum
        case ReferenceFrameEnum.BodyCenteredInertial
            bodyInfo = getSelectedBodyInfo(handles);

            newFrame = bodyInfo.getBodyCenteredInertialFrame();

        case ReferenceFrameEnum.BodyFixedRotating
            bodyInfo = getSelectedBodyInfo(handles);

            newFrame = bodyInfo.getBodyFixedFrame();

        case ReferenceFrameEnum.TwoBodyRotating
            bodyInfo = getSelectedBodyInfo(handles);
            if(not(isempty(bodyInfo.childrenBodyInfo)))
                primaryBody = bodyInfo;
                secondaryBody = bodyInfo.childrenBodyInfo(1);
            else
                primaryBody = bodyInfo.getParBodyInfo();
                secondaryBody = bodyInfo;
            end

            originPt = TwoBodyRotatingFrameOriginEnum.Primary;

            newFrame = TwoBodyRotatingFrame(primaryBody, secondaryBody, originPt, celBodyData);

        case ReferenceFrameEnum.UserDefined
            numFrames = lvdData.geometry.refFrames.getNumRefFrames();
            if(numFrames >= 1)
                geometricFrame = AbstractGeometricRefFrame.empty(1,0);
                for(i=1:numFrames)
                    frame = lvdData.geometry.refFrames.getRefFrameAtInd(i);
                    if(frame.isVehDependent() == false)
                        geometricFrame = frame;
                        break;
                    end
                end

                if(not(isempty(geometricFrame)))
                    newFrame = UserDefinedGeometricFrame(geometricFrame, lvdData);
                else
                    bodyInfo = getSelectedBodyInfo(handles);
                    newFrame = bodyInfo.getBodyCenteredInertialFrame();

                    warndlg('There are no geometric frames available which are not dependent on vehicle properties.  A body-centered inertial frame will be selected instead.');
                end
            else
                bodyInfo = getSelectedBodyInfo(handles);
                newFrame = bodyInfo.getBodyCenteredInertialFrame();

                warndlg('There are no geometric frames available which are not dependent on vehicle properties.  A body-centered inertial frame will be selected instead.');
            end

        otherwise
            error('Unknown reference frame type: %s', string(refFrameEnum));
    end

    if(not(isempty(newFrame)) && newFrame.typeEnum ~= refFrameEnum)
        refFrameEnum = newFrame.typeEnum;
        handles.refFrameTypeCombo.Value = ReferenceFrameEnum.getIndForName(refFrameEnum.name);
    end

    setappdata(handles.lvd_EditGeometricVectorConstraintGUI,'frame', newFrame);
    handles.setFrameOptionsButton.TooltipString = sprintf('Current Frame: %s', newFrame.getNameStr());
    handles.refFrameNameLabel.String = sprintf('%s', newFrame.getNameStr());
    handles.refFrameNameLabel.TooltipString = sprintf('%s', newFrame.getNameStr());

function bodyInfo = getSelectedBodyInfo(handles)
    curFrame = getappdata(handles.lvd_EditGeometricVectorConstraintGUI,'frame');
    bodyInfo = curFrame.getOriginBody();

% --- Executes on selection change in eventNodeCombo.
function eventNodeCombo_Callback(hObject, eventdata, handles)
% hObject    handle to eventNodeCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns eventNodeCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from eventNodeCombo

% --- Executes during object creation, after setting all properties.
function eventNodeCombo_CreateFcn(hObject, eventdata, handles)
% hObject    handle to eventNodeCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end

% --- Executes on selection change in stateComparisonNodeCombo.
function stateComparisonNodeCombo_Callback(hObject, eventdata, handles)
% hObject    handle to stateComparisonNodeCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    structure with handles and user data (see GUIDATA)

% Hints: contents = cellstr(get(hObject,'String')) returns stateComparisonNodeCombo contents as cell array
%        contents{get(hObject,'Value')} returns selected item from stateComparisonNodeCombo

% --- Executes during object creation, after setting all properties.
function stateComparisonNodeCombo_CreateFcn(hObject, eventdata, handles)
% hObject    handle to stateComparisonNodeCombo (see GCBO)
% eventdata  reserved - to be defined in a future version of MATLAB
% handles    empty - handles not created until after all CreateFcns called

% Hint: popupmenu controls usually have a white background on Windows.
%       See ISPC and COMPUTER.
if ispc && isequal(get(hObject,'BackgroundColor'), get(0,'defaultUicontrolBackgroundColor'))
    set(hObject,'BackgroundColor','white');
end


function assertTrue(a, message)
% assert that the input is equal to true
%
% assertTrue(a[,msg])
%
% Inputs:
%   a               vector scalar logical that must be true
%   msg             optional custom message
%
% Throws:
%   'MOxUnit:notLogicalScalar'      a is not a logical scalar
%   'MOxUnit:notTrue'               a is not true
%
% Examples:
%   assertTrue(true);
%   %||  % ok
%
%   assertTrue(false);
%
%   %|| error('input does not evaluate to true');
%
%   assertFalse([true,true]);
%   %|| error('input is not a logical scalar');
%
% Notes:
%   - If a custom message is provided, then any error message is prefixed
%     by this custom message
%   - This function attempts to show similar behaviour as in
%     Steve Eddins' MATLAB xUnit Test Framework (2009-2012)
%     URL: http://www.mathworks.com/matlabcentral/fileexchange/
%                           22846-matlab-xunit-test-framework
%
% NNO Jan 2014

    if ~isscalar(a) || ~islogical(a)
        whatswrong='input is not a logical scalar';
        error_id='assertTrue:invalidCondition';
    elseif ~a
        whatswrong='input does not evaluate to true';
        error_id='assertTrue:falseCondition';
    else
        return
    end

    if isempty(error_id)
        return;
    end

    if nargin<2
        message='';
    end

    full_message=moxunit_util_input2str(message,whatswrong,a);

    if moxunit_util_platform_is_octave()
        error(error_id,'%s',full_message);
    else
        throwAsCaller(MException(error_id,'%s',full_message));
    end


function p = parse_filename(filename,fields)
% Split a filename into its building constituents
% FORMAT p = parse_filename(filename,fields)
%
% Example:
%
% >> filename = '../sub-16/anat/sub-16_ses-mri_run-1_echo-2_FLASH.nii.gz';
% >> parse_filename(filename)
%
% ans =
%
%   struct with fields:
%
%     filename: 'sub-16_ses-mri_run-1_echo-2_FLASH.nii.gz'
%         type: 'FLASH'
%          ext: '.nii.gz'
%          sub: '16'
%          ses: 'mri'
%          run: '1'
%         echo: '2'
%__________________________________________________________________________

% Copyright (C) 2016-2018, Guillaume Flandin, Wellcome Centre for Human Neuroimaging
% Copyright (C) 2018--, BIDS-MATLAB developers

filename = file_utils(filename,'filename');
[parts, dummy] = regexp(filename,'(?:_)+','split','match');
p.filename = filename;
[p.type, p.ext] = strtok(parts{end},'.');
for i=1:numel(parts)-1
    [d, dummy] = regexp(parts{i},'(?:\-)+','split','match');
    if length(d)<2
%        warning([filename ' cannot be parsed. ''' d{1} ''' is not associated with a label (' d{1} '-)']);
        continue
    end
    p.(d{1}) = d{2};
end
if nargin == 2
    for i=1:numel(fields)
        if ~isfield(p,fields{i})
            p.(fields{i}) = '';
        end
    end
    try
        p = orderfields(p,['filename','ext','type',fields]);
    catch
        warning('Ignoring file "%s" not matching template.',filename);
        p = struct([]);
    end
end


classdef SetPowerSinkActiveStateAction < AbstractEventAction
    %SetPowerSinkActiveStateAction Summary of this class goes here
    %   Detailed explanation goes here

    properties
        sink AbstractLaunchVehicleElectricalPowerSrcSnk
        activeStateToSet(1,1) logical = false;
    end

    properties(Constant)
        emptyVarArr = AbstractOptimizationVariable.empty(0,1);
    end

    methods
        function obj = SetPowerSinkActiveStateAction(sink, activeStateToSet)
            if(nargin > 0)
                obj.sink = sink;
                obj.activeStateToSet = activeStateToSet;
            end

            obj.id = rand();
        end

        function newStateLogEntry = executeAction(obj, stateLogEntry)
            newStateLogEntry = stateLogEntry;
            stageStates = newStateLogEntry.stageStates;

            pwrSinkStates = AbstractLaunchVehicleElectricalPowerSnkState.empty(1,0);
            for(i=1:length(stageStates)) %#ok<*NO4LP>
                pwrSinkStates = horzcat(pwrSinkStates, stageStates(i).powerSinkStates); %#ok<AGROW>
            end

            pwrSinks = AbstractLaunchVehicleElectricalPowerSrcSnk.empty(1,0);
            for(i=1:length(pwrSinkStates))
                pwrSinks = horzcat(pwrSinks, pwrSinkStates(i).getEpsSinkComponent()); %#ok<AGROW>
            end

            pwrSinkInd = find(pwrSinks == obj.sink,1,'first');
            pwrSinkState = pwrSinkStates(pwrSinkInd);

            pwrSinkState.setActiveState(obj.activeStateToSet);
        end

        function initAction(obj, initialStateLogEntry)
            %nothing
        end

        function name = getName(obj)
            if(obj.activeStateToSet)
                tf = 'Active';
            else
                tf = 'Inactive';
            end

            name = sprintf('Set Power Sink State (%s = %s)',obj.sink.getName(),tf);
        end

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

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

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

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

        function tf = usesStopwatch(obj, stopwatch)
            tf = false;
        end

        function tf = usesExtremum(obj, extremum)
            tf = false;
        end

        function tf = usesTankToTankConn(obj, tankToTank)
            tf = false;
        end

        function tf = usesPwrSink(obj, powerSink)
            tf = [obj.sink] == powerSink;
        end

        function tf = usesPwrSrc(obj, powerSrc)
            tf = false;
        end

        function tf = usesPwrStorage(obj, powerStorage)
            tf = false;
        end

        function [tf, vars] = hasActiveOptimVar(obj)
            tf = false;
            vars = obj.emptyVarArr;
        end
    end

    methods(Static)
        function addActionTf = openEditActionUI(action, lv)
            [~, powerSinks] = lv.getPowerSinksListBoxStr();

            if(not(isempty(powerSinks)))
%                 addActionTf = lvd_EditActionSetPwrSinkStateGUI(action, lv);

                output = AppDesignerGUIOutput({false});
                lvd_EditActionSetPwrSinkStateGUI_App(action, lv, output);
                addActionTf = output.output{1};
            else
                addActionTf = false;
                warndlg('There are no power sinks on the vehicle.  Create one first.','Cannot Create Action','modal');
            end
        end
    end
end


classdef PTKCoords < handle
    % PTKCoords. Class for storing a set of coordinates.
    %
    %     Licence
    %     -------
    %     Part of the TD Pulmonary Toolkit. https://github.com/tomdoel/pulmonarytoolkit
    %     Author: Tom Doel, 2013.  www.tomdoel.com
    %     Distributed under the GNU GPL v3 licence. Please see website for details.
    %

    properties
        Coords
    end

    methods
        function obj = PTKCoords(coords)
            if nargin > 0
                obj.Coords = coords;
            end
        end
    end
end


function planC = storeStructuresMatrices(planC, indicesM, structBitsM, scanNum)
%"storeStructuresMatrices"
%   Either 1) modifies planC by adding another cell just before the index cell, or
%          2) uses the preallocated structureArray cell in planC.
%
%this new cell includes the index matrix and the bit matrix for the structures.
%
% 16 Aug 02, V H Clark
% 18 Feb 05, JRA, Added support for multiple scanSets.
% 14 Feb 08, APA, Added UID association
%
%Usage:
%   function planC = storeStructuresMatrices(planC, indicesM, structBitsM)

fieldExists = isfield(planC{end}, 'structureArray'); %this will be true for newer versions, false for old versions
indexS = planC{end};
assScanUID = planC{indexS.scan}(scanNum).scanUID;
structSetUID = createUID('STRUCTURESET');
if fieldExists %most common
    if isempty(planC{planC{end}.structureArray})
        planC{planC{end}.structureArray} = struct('indicesArray', indicesM, 'bitsArray', structBitsM, 'assocScanUID', assScanUID, 'structureSetUID', structSetUID);
    else
        planC{planC{end}.structureArray}(scanNum) = struct('indicesArray', indicesM, 'bitsArray', structBitsM, 'assocScanUID', assScanUID, 'structureSetUID', structSetUID);
    end
else
    structIndex = length(planC);
    planC{end+1} = planC{end}; %moves the index to the end

    planC{structIndex}(scanNum) = struct('indicesArray', indicesM, 'bitsArray', structBitsM, 'assocScanUID', assScanUID, 'structureSetUID', structSetUID);
    %change index
    planC{end}.structureArray = structIndex;
end


function opti_package
% OPTI_PACKAGE  Generates GitHub releases .zip files

% Get Solver Names (ones we want to upload)
s = lower(optiSolver('all'));
removeIdx = strcmp(s,'baron') | strcmp(s,'cplex') | strcmp(s,'gmatlab') | strcmp(s, 'matlab') | strcmp(s,'mosek') | strcmp(s,'scip') | strcmp(s,'sedumi');
solvers = s(~removeIdx);

% Utility Names
utilities = {'asl', 'coinR', 'coinW', 'mklJac', 'rmathlib'};

% Build zip file list
files = [solvers utilities];
for i = 1:length(files)
    files{i} = which([files{i} '.' mexext]);
end

% Zip the files
fprintf('Compressing MEX Files...');
name = ['optiMEXFiles_' mexext '_' sprintf('%.0f_%.0f',optiver,mod(optiver*100,100))];
zip(name,files);
rehash;
rehash;
fprintf('Done!\n');

% Update the contents file
UpdateContentsFile('OPTI',optiver,'Utilities/opti');

% Copy latest SCIP to download folder
copyfile(which(['scip.' mexext]), '../../../Inverse Problem/OPTI Academic Solvers');

function UpdateContentsFile(name,tbxver,contentsFile)
%Update contents file description line

if(~isempty(strfind(contentsFile,'Contents.m')))
    p = contentsFile;
elseif(contentsFile(end) == filesep)
    p = [contentsFile 'Contents.m'];
else
    p = [contentsFile filesep 'Contents.m'];
end
s = fileread(p);
%Find initial date
idx = strfind(s,'(C)');
idxe = strfind(s(idx:end),'-');
stDate = strtrim(s(idx+3:idx+idxe-2));
mver = ver('matlab');
%Regenerate Contents File
fid = fopen(p,'w');
if(fid)
    try
        fprintf(fid,'%% %s Toolbox\n',upper(name));
        fprintf(fid,'%% Version %.2f %s %s\n',tbxver,mver.Release,datestr(now,1));
        fprintf(fid,'%% Copyright (C) %s-%s Jonathan Currie (Inverse Problem Ltd)\n',stDate,datestr(now,10));
        fprintf(fid,'%% License: https://inverseproblem.co.nz/OPTI/index.php/DL/License\n');
    catch ME
        fclose(fid);
        rethrow(ME);
    end
end
fclose(fid);


function ker = get_kernel(ker_name, cu_filename)

global data;

switch data.gpu.float_t
case 'double',
    ker_name = [ker_name '_d'];
case 'single',
    ker_name = [ker_name '_f'];
end

if ~isfield(data.gpu.kernels, ker_name)
    cu_filename = fullfile('cuda', cu_filename);
    ptx_filename = regexprep(cu_filename, '\.cu$', '.ptx');
    ker = struct();
    ker.name = ker_name;
    ker.ker = parallel.gpu.CUDAKernel(ptx_filename, cu_filename, ker_name);
    ker.block_size = ker.ker.ThreadBlockSize;
    ker.grid_size = ker.ker.GridSize;
    data.gpu.kernels.(ker_name) = ker;
end

ker = data.gpu.kernels.(ker_name);


% A test script on image sequences, making sure grayscale and 16 bit
% sequences work

clear

% The location executable will depend on the OS
if(isunix)
    executable = '"../../build/bin/FeatureExtraction"';
else
    executable = '"../../x64/Release/FeatureExtraction.exe"';
end

% Input file
in_dirs = {'../../samples/image_sequence',...
    '../../samples/image_sequence_gray', ...
    '../../samples/image_sequence_16bit'};

% Where to store the output
output_dir = './processed_features/';

for i=1:numel(in_dirs)
    command = sprintf('%s -fdir "%s" -out_dir "%s" -verbose', executable, in_dirs{i}, output_dir);

    if(isunix)
        unix(command);
    else
        dos(command);
    end
end


function h = cmpndNoisePointPlot(noise, X, y, fontName, fontSize, markerSize, lineWidth)

% CMPNDNOISEPOINTPLOT Plot the data-points for the CMPND noise model.
% FORMAT
% DESC plots the data point locations for the compound
%  noise structure.
% ARG noise : the noise structure which is to be plotted.
% ARG X : input locations to be plotted.
% ARG y : target locations to be plotted.
% ARG fontName : name of any fonts to be used.
% ARG fontSize : size of any fonts to be used.
% ARG markerSize : size of the makers to be used.
% ARG lineWidth : size of any lines to be plotted.
%
% SEEALSO : cmpndNoiseParamInit, noisePointPlot
%
% COPYRIGHT : Neil D. Lawrence, 2004, 2005

% NOISE


classdef PTKTreeSegment < PTKTree
    % PTKTreeSegment. A data structure representing a segmented airway tree
    %
    %     A root PTKTreeSegment is returned by
    %     PTKAirwayRegionGrowingWithExplosionControl. From this you
    %     can extract and analyse the resulting airway tree.
    %
    %     PTKTreeSegment is used in the construction and storage of
    %     the airway trees. A PTKTreeSegment stores an individual
    %     segment of the centreline tree, with references to the parent and child
    %     PTKTreeSegments, so that it is possible to reconstruct the entire
    %     tree from a single segment.
    %
    %     The way the airway voxels are stored in each segment is as follows:
    %         The wavefront only exists during the region growing. It is a thick
    %         layer of voxels which exists at the end of each segment
    %         which is currently growing. If the wavefront forms more than one
    %         connected component, the segment is ended and new child segments
    %         formed from the wavefront components. When new voxels are added to
    %         the front of the wavefront, old voxels from the back of the
    %         wavefront are pushed out into the Pending voxels of the segment.
    %         Pending voxels are 'accepted' or 'rejected' according to whether
    %         the heuristics have determined an explosion has occurred.
    %
    %     Licence
    %     -------
    %     Part of the TD Pulmonary Toolkit. https://github.com/tomdoel/pulmonarytoolkit
    %     Author: Tom Doel, 2012.  www.tomdoel.com
    %     Distributed under the GNU GPL v3 licence. Please see website for details.
    %

    properties
        Colour         % A colourmap index allocated to this branch
    end

    properties (SetAccess = private)
        % Generation of this segment, starting at 1
        GenerationNumber

        % Indicates if this branch was terminated due to the generation number
        % being too high, which may indicate leakage
        ExceededMaximumNumberOfGenerations = false

        MarkedExplosion = false

    end

    properties (Access = private)

        % List of accepted (i.e. non-exploded) voxels
        AcceptedVoxelIndices

        % List of rejected (exploded) voxels
        RejectedVoxelIndices

        % Indices are allocated to the segment from the back of the wavefront
        % They are pending until the explosion control heuristic has determined
        % they are 'Accepted' or 'Exploded'.
        PendingVoxelIndices

        % Additional voxels that were not originally part of the segment but
        % were added later after a morphological closing operation
        ClosedPoints

        PreviousMinimumVoxels
        NumberOfVoxelsSkipped = 0
        LastNumberOfVoxels = 0

        PermittedVoxelSkips = 0
        IsFirstSegment

        % We never use less than this value at each step when computing the minimum wavefront
        % size over the image
        MinimumNumberOfPointsThreshold

        ExplosionMultiplier

    end

    methods
        function obj = PTKTreeSegment(parent, min_number_of_points_threshold, explosion_multiplier)
            if nargin > 0
                obj.Parent = parent;
                obj.MarkedExplosion = false;
                obj.PendingVoxelIndices = int32([]);
                obj.AcceptedVoxelIndices = int32([]);
                obj.RejectedVoxelIndices = int32([]);

                obj.ExplosionMultiplier = explosion_multiplier;
                obj.MinimumNumberOfPointsThreshold = min_number_of_points_threshold;

                if ~isempty(parent)
                    parent.AddChild(obj);
                    obj.PreviousMinimumVoxels = parent.PreviousMinimumVoxels;
                    obj.LastNumberOfVoxels = obj.PreviousMinimumVoxels;
                    obj.IsFirstSegment = false;
                    obj.GenerationNumber = parent.GenerationNumber + 1;
                else
                    obj.PreviousMinimumVoxels = 1000;
                    obj.LastNumberOfVoxels = obj.PreviousMinimumVoxels;
                    obj.IsFirstSegment = true;
                    obj.GenerationNumber = 1;
                end
            end
        end

        % Returns a list of voxels which have been accepted as not explosions.
        function accepted_voxels = GetAcceptedVoxels(obj)
            accepted_voxels = obj.ConcatenateVoxels(obj.AcceptedVoxelIndices);
        end

        % Returns the wavefront for this segment, which includes voxels that may
        % be separated into child segments
        function rejected_voxels = GetRejectedVoxels(obj)
            rejected_voxels = obj.ConcatenateVoxels(obj.RejectedVoxelIndices);
        end

        function endpoints = GetEndpoints(obj)
            endpoints = obj.AcceptedVoxelIndices{end};
        end

        % Returns all accepted region-growing points, plus those added from the airway closing operation
        function all_points = GetAllAirwayPoints(obj)
            all_points = [obj.GetAcceptedVoxels; obj.ClosedPoints];
        end

        % Points which are added later to close gaps in the airway tree
        function AddClosedPoints(obj, new_points)
            obj.ClosedPoints = [obj.ClosedPoints, new_points];
        end

        function RecomputeGenerations(obj, new_generation_number)
            obj.GenerationNumber = new_generation_number;
            children = obj.Children;
            for child = children
                child.RecomputeGenerations(new_generation_number + 1);
            end
        end

        % Returns the number of branches in this tree, from this branch
        % and excluding generations above the max_generation_number
        function number_of_branches = CountBranchesUpToGeneration(obj, max_generation_number)
            number_of_branches = 0;
            if obj.GenerationNumber > max_generation_number
                return;
            else
                branches_to_do = obj;
                while ~isempty(branches_to_do)
                    branch = branches_to_do(end);
                    branches_to_do(end) = [];
                    if branch.GenerationNumber <= max_generation_number
                        branches_to_do = [branches_to_do, branch.Children];
                        number_of_branches = number_of_branches + 1;
                    end
                end
            end
        end

        function AddColourValues(obj, new_colour_value)
            obj.Colour = new_colour_value;
            children = obj.Children;
            for child = children
                new_colour_value = new_colour_value + 1;
                if mod(new_colour_value, 7) == 0
                    new_colour_value = new_colour_value + 1;
                end
                child.AddColourValues(new_colour_value);
            end
        end

        function AddPendingVoxels(obj, indices_of_new_points)

            if isempty(obj.PendingVoxelIndices)
                obj.LastNumberOfVoxels = max(1, round(numel(indices_of_new_points)/2));
            end
            obj.PendingVoxelIndices{end + 1} = indices_of_new_points;

            if obj.MarkedExplosion
                obj.RejectAllPendingVoxelIndices;
                return;
            end

            number_of_points = numel(indices_of_new_points);

            if (number_of_points < obj.PreviousMinimumVoxels) && (~obj.IsFirstSegment)
                obj.PreviousMinimumVoxels = max(number_of_points, obj.MinimumNumberOfPointsThreshold);
            end

            if (number_of_points < obj.ExplosionMultiplier*obj.PreviousMinimumVoxels)
                obj.NumberOfVoxelsSkipped = 0;
            else
                obj.NumberOfVoxelsSkipped = obj.NumberOfVoxelsSkipped + 1;
            end

            % Keep track of the point at which an explosion starts to occur
            if (number_of_points <= obj.LastNumberOfVoxels)
                obj.LastNumberOfVoxels = number_of_points;
                obj.AcceptAllPendingVoxelIndices;
            end

            % Explosion control: we allow a certain number of consecutive
            % points to exceed the expansion limit.
            % Once exceeded, this segment is not permitted to expand further, and it is also marked so that it can be
            % deleted later.
            if (obj.NumberOfVoxelsSkipped > obj.PermittedVoxelSkips)
                obj.MarkedExplosion = true;
                obj.RejectAllPendingVoxelIndices;
            end
        end

        function EarlyTerminateBranch(obj)
            obj.CompleteThisSegment;
            if ~obj.MarkedExplosion
                obj.ExceededMaximumNumberOfGenerations = true;
            end
        end

        function CompleteThisSegment(obj)
            if obj.MarkedExplosion
                obj.RejectAllPendingVoxelIndices;
            else
                obj.AcceptAllPendingVoxelIndices;
            end
        end

        function MergeWithChild(obj)
            if (length(obj.Children) ~= 1)
                error('MergeWithChild should only be called if there is one child segment');
            end
            child = obj.Children(1);
            if ~isempty(child.PendingVoxelIndices)
                error('Programming error: MergeWithParent should not be called while a segment is in progress');
            end
            grandchildren = child.Children;
            obj.Children = [setdiff(obj.Children, child), grandchildren];
            for grandchild = obj.Children
                grandchild.Parent = obj;
                grandchild.RecomputeGenerations(obj.GenerationNumber + 1);
            end
            while ~isempty(child.AcceptedVoxelIndices)
                obj.AcceptedVoxelIndices{end + 1} = child.AcceptedVoxelIndices{1};
                child.AcceptedVoxelIndices(1) = [];
            end
            while ~isempty(child.RejectedVoxelIndices)
                obj.RejectedVoxelIndices{end + 1} = child.RejectedVoxelIndices{1};
                child.RejectedVoxelIndices(1) = [];
            end

        end

        function PruneAcceptedVoxels(obj)
            pruned_voxels = [];
            for index = 1 : length(obj.AcceptedVoxelIndices)
                next_voxel_set = obj.AcceptedVoxelIndices{index};
                size_voxel_set = numel(next_voxel_set);
                if (index == 1) || (size_voxel_set <= last_size)
                    pruned_voxels{index} = next_voxel_set;
                    last_size = size_voxel_set;
                else
                    obj.AcceptedVoxelIndices = pruned_voxels;
                    return;
                end
            end

        end

    end

    methods (Access = private)
        function AcceptAllPendingVoxelIndices(obj)
            while ~isempty(obj.PendingVoxelIndices)
                obj.AcceptedVoxelIndices{end + 1} = obj.PendingVoxelIndices{1};
                obj.PendingVoxelIndices(1) = [];
            end
        end

        function RejectAllPendingVoxelIndices(obj)
            while ~isempty(obj.PendingVoxelIndices)
                obj.RejectedVoxelIndices{end + 1} = obj.PendingVoxelIndices{1};
                obj.PendingVoxelIndices(1) = [];
            end
        end
    end

    methods (Static, Access = private)
        function concatenated_voxels = ConcatenateVoxels(voxels)
            concatenated_voxels = [];
            number_layers = length(voxels);
            for index = 1 : number_layers
                next_voxels = voxels{index};
                if ~isempty(next_voxels)
                    concatenated_voxels = cat(1, concatenated_voxels, next_voxels);
                end
            end
        end
    end

end


% sgwt_setpath : Set paths for SGWT toolbox
%
% user should set SGWT_ROOT to be directory where sgwt_toolbox is installed

% This file is part of the SGWT toolbox (Spectral Graph Wavelet Transform toolbox)
% Copyright (C) 2010, David K. Hammond.
%
% The SGWT toolbox 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.
%
% The SGWT toolbox 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 the SGWT toolbox.  If not, see <http://www.gnu.org/licenses/>.

SGWT_ROOT=[fileparts(mfilename('fullpath')),filesep];

sgwt_relpathlist={'',...
                  'utils',...
                  'demo',...
                  'mex',...
                 };
fprintf('Welcome to sgwt_toolbox. SGWT root directory is %s\n',SGWT_ROOT);
for k=1:numel(sgwt_relpathlist)
  sgwt_tmp_pathname=[SGWT_ROOT,sgwt_relpathlist{k}];
  fprintf('adding path %s\n',sgwt_tmp_pathname);
  addpath(sgwt_tmp_pathname);

end
clear sgwt_relpathlist sgwt_tmp_pathname


function restorefig(h,old)
    %RESTOREFIG  Restore a figure's properties
    %   RESTOREFIG(H,OLD) restores the properties of H specified in
    %   OLD. The state-difference structure OLD is the output of the
    %   function APPLYTOFIG. Deleting object handles after the call to
    %   APPLYFIG might cause undesired behavior.
    %
    %   See also EXPORTFIG, PREVIEWFIG, APPLYTOFIG.

    %  Copyright 2000 Ben Hinkle
    %  Email bug reports and comments to bhinkle@mathworks.com

    for n=1:length(old.objs)
        try
            if ~iscell(old.values{n})  &&  iscell(old.prop{n})
                old.values{n} = {old.values{n}};
            end
            set(old.objs{n}, old.prop{n}, old.values{n});
        end
    end


classdef  VideoMaker_TopOpt_levelSet3D < VideoMaker
  properties

  end

  methods (Access = public)

        function obj = VideoMaker_TopOpt_levelSet3D(cParams)
            obj.init(cParams);
        end

        function Make_video_design_variable(obj,output_video_name)
            post = Postprocess_TopOpt_levelSet();
            field2print = post.levelSet_name;
            componentfield = post.levelSet_name_component;
            obj.Make_video_characteristic_function(field2print,componentfield,output_video_name)
        end

  end

  methods (Access = private)
         function Make_video_characteristic_function(obj,field2print,componentfield,output_video_name_in)
            file_tcl_name = 'tcl_gid.tcl';
            file_list = obj.create_file_list(obj.iterations_to_print,obj.file_name,obj.files_folder);

            [output_video_name] = obj.replace_special_character(output_video_name_in);
            [output_photo]=obj.replace_special_character(strcat(obj.files_folder,'\',obj.file_name,'.png'));
            [file_list] = obj.replace_special_character(file_list);

            min_value = -1e-32;

            file_tcl_name_with_path = fullfile(obj.files_folder,file_tcl_name);
            file_path_in = fullfile(pwd,'FEM','PostProcess','Make_Video_characteristic3D.tcl');
            filepath = obj.replace_special_character(file_path_in);

            fid = fopen(file_tcl_name_with_path,'w+');

            fprintf(fid,'GiD_Process PostProcess \n');
            fprintf(fid,'%s\n',['set arg1 "',file_list,'"']);
            fprintf(fid,'%s\n',['set arg2 "',output_video_name,'"']);
            fprintf(fid,'%s\n',['set arg3 "',field2print,'"']);
            fprintf(fid,'%s\n',['set arg4 "',componentfield,'"']);
            fprintf(fid,'%s\n',['set arg5 "',num2str(min_value),'"']);
            fprintf(fid,'%s\n',['set arg6 "',output_photo,'"']);

            fprintf(fid,'%s\n',['source "',filepath,'"']);
            fprintf(fid,'%s\n',['Make_Video_characteristic $arg1 $arg2 $arg3 $arg4 $arg5 $arg6']);
            fprintf(fid,'%s\n',['GiD_Process Mescape Quit']);
            fclose(fid);
            obj.execute_tcl_files(obj.gidPath,file_tcl_name_with_path)
        end

  end
end


function IM = updateVMCInfluence(IM, structROIV, sampleRateV, updateM)
%"updateVMCInfluence"
%   Uses the VMC++ MC engine to populate the beamlet fields of an IM structure.
%   StructROIV is the list of structures, sampleRateV is a vector of sample
%   rates, one for each structROIV.
%   The doses are stored in sparse format.
%   The stored index is with respect to the structure mask registered to the
%   uniformized CT scan.
%
%
%      Rewrite June 06, JOD, to be a 'drop-in' alternative to the pencil
%      beam calculations.
%
%      Based on code by P. Lindsay, J. Alaly, and J. Deasy
%
%      Last modified: JJW, 21 June 2006
%                     JJW, 26 June 2006
%                     JC,  12 July 2006
%                           Implement to use 'IM.params.cutoffDistance'.
%                           Remove the assumption of SID = 100 cm.
%           JC, 26 Feb 2007
%               Fix bug, "the dose was shifted by one voxel". to.
%               offset(1:2)=offset(1:2)+yres/2;
%
% Copyright 2010, Joseph O. Deasy, on behalf of the CERR development team.
%
% This file is part of The Computational Environment for Radiotherapy Research (CERR).
%
% CERR development has been led by:  Aditya Apte, Divya Khullar, James Alaly, and Joseph O. Deasy.
%
% CERR has been financially supported by the US National Institutes of Health under multiple grants.
%
% CERR is distributed under the terms of the Lesser GNU Public License.
%
%     This version of CERR 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.
%
% CERR 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 CERR.  If not, see <http://www.gnu.org/licenses/>.

%  Flow:
%
%  Loop over beams
%    Loop over beamlets
%      Get MC2CT beamlet matrix.
%      Loop over structures
%            Get infl contribution from that beamlet to that structure
%                at that sample rate.
%            Store
%      end structure loop
%    End beamlet loop
%  End beam loop

%This is a different organizational structure compared to the PB generate influence
%flow.  In particular, we loop over beams first, not structures, because the MC
%calculation is always done to the entire CT matrix, and it is by far the slowest
%computation.

%==========Set up MC params=======================%

global planC
global stateS
indexS=planC{end};

%obtain associated scanNum for structures. It is assumed that all the
%structures are associated to same scan (which is checked in IMRTP.m)
scanNum = getStructureAssociatedScan(structROIV(1));

numBeams = length(IM.beams);

IMRTPGui('statusbar', 'Preparing VMC++ calculation');
percentDone = 0;
IMRTPGui('waitbar', percentDone);

%Create all path parameters.
IMRTPdir = fileparts(which('IMRTP'));
VMCPath         = fullfile(IMRTPdir , 'vmc++', '');
runsPath        = fullfile(VMCPath, 'runs', '')
phantomPath     = fullfile('.', 'phantoms', '');
energyPath      = fullfile('.', 'spectra', '');

%Create phantom default filename.
phantomFilename = fullfile(phantomPath, 'CERR_IMRT.ct');

%Set environment variables for PC.  Unix set at runtime.
if ispc
    dos(['"' fullfile(VMCPath, 'setx" ') 'vmc_home "' VMCPath '" -m']);
    dos(['"' fullfile(VMCPath, 'setx" ') 'vmc_dir "' runsPath '" -m']);
    dos(['"' fullfile(VMCPath, 'setx" ') 'xvmc_dir "' VMCPath '" -m']);

    [jnk, out1] = dos('set vmc_home');
    [jnk, out2] = dos('set vmc_dir');
    [jnk, out3] = dos('set xvmc_dir');

    %(1:end-1) to avoid CR at end of output1-3.
    if ~strcmpi(out1(1:end-1), ['vmc_home=' VMCPath]) | ~strcmpi(out2(1:end-1), ['vmc_dir=' runsPath ]) | ~strcmpi(out3(1:end-1), ['xvmc_dir=' VMCPath])
        error('Environment Variables were not properly set for VMC++.  CERR has set them--please restart Matlab and begin the calculation again.');
    end
end

%Calculation will be based on the resolution of uniformized CT dataset.
currDir = cd;
cd(VMCPath);
fillWater = 0;
[offset, bbox] = generateCT_uniform(getUniformizedCTScan(0,scanNum), phantomFilename, scanNum, fillWater);
cd(currDir);

scandr = bbox(2) - bbox(1) + 1;
scandc = bbox(4) - bbox(3) + 1;
scands = bbox(6) - bbox(5) + 1;

%Get x,y,z resolution.
[xV, yV, zV] = getUniformScanXYZVals(planC{indexS.scan}(scanNum));
xres = abs(xV(2) - xV(1));
yres = abs(yV(2) - yV(1));
zres = abs(zV(2) - zV(1));

%Left hand side versus centre of each voxel
%offset(1:2)=offset(1:2)-yres/2;
% This is the fix, as in <generateCT_uniform.m> %THIS IS THE FIX::: Y=Y(end:-1:1);
offset(1:2)=offset(1:2)+yres/2;
offset(3:4)=offset(3:4)-xres/2;
offset(5:6)=offset(5:6)-zres/2;

%Setup the options for the VMC++ input.
VMCOpt = VMCOptInit;
phantomFilename(strfind(phantomFilename, '\')) = '/'; %VMC requires '/'.
VMCOpt.startGeometry.startXYZGeometry.phantomFile=phantomFilename;

%Set options from IM.params.VMC
VMCOpt.startMCControl.NCase                     = IM.params.VMC.NumParticles;
VMCOpt.startMCControl.NBatch                    = IM.params.VMC.NumBatches;
VMCOpt.startScoring.startDoseOptions.scoreDoseToWater = IM.params.VMC.scoreDoseToWater;
VMCOpt.startBeamletSource.monoEnergy            = IM.params.VMC.monoEnergy;
VMCOpt.startVarianceReduction.repeatHistory     = IM.params.VMC.repeatHistory;
VMCOpt.startVarianceReduction.splitPhotons      = IM.params.VMC.splitPhotons;
VMCOpt.startVarianceReduction.photonSplitFactor = IM.params.VMC.photonSplitFactor;
VMCOpt.startQuasi.base                          = IM.params.VMC.base;
VMCOpt.startQuasi.dimension                     = IM.params.VMC.dimension;
VMCOpt.startQuasi.skip                          = IM.params.VMC.skip;
switch lower(IM.params.VMC.includeError)
    case 'yes'
        VMCOpt.startScoring.startOutputOptions.dumpDose = 1;
    case 'no'
        VMCOpt.startScoring.startOutputOptions.dumpDose = 2;
    otherwise
        error('Invalid value for includeError property.');
end

% Precalc voxel indices for all structures
scanIndV=cell(max(structROIV),1);
for i = 1 : length(structROIV)
    if sampleRateV(i) ~= 1
        %Ensures that interpolative downsampling won't miss edge points:
        maskSingle3D = getSurfaceExpand(structROIV(i),0.5,1);
        if rem(log2(sampleRateV(i)),1) ~= 0
            error('Sample factor must (currently) be a power of 2.')
        end
        maskSample3D = getDown3Mask(maskSingle3D, sampleRateV(i), 1);
        %Get a mask of where to sample points
        tmpM = logical(maskSample3D) & maskSingle3D;
        clear maskSample3D maskSingle3D;
    else
        tmpM = getUniformStr(structROIV(i));
    end
    scanIndV{i} = find(tmpM);  %Indices with respect to the uniformized scan.
    clear tmpM
end

%===========Loop over beams=============%

% To generate independent datasets, need to set
% VMCOpt.startQuasi.skip to skip the numbers of histories
% used in previous calculations

beamletCounter = 1;  %Keep up with how many beamlets have been computed.
errorBeamlets = [];

indV = 1:(scandr*scandc*scands);
[r,c,s] = ind2sub([scandr,scandc,scands], indV);
r = r + bbox(1) - 1;
c = c + bbox(3) - 1;
s = s + bbox(5) - 1;
%indV = sub2ind(getUniformizedSize(planC), r, c, s);
indV = sub2ind(getUniformScanSize(planC{indexS.scan}(scanNum)), r, c, s);
clear r c s

% Added by JC July 11, 2006
% Used later in chop doseV/doseM off by 'IM.params.cutoffDistance'
[xM yM zM] = meshgrid(xV, yV, zV);
pM = [xM(indV)', yM(indV)', zM(indV)'];
clear xM yM zM

for beamIndex=1:numBeams

    if ~any(updateM(:,beamIndex)) % no goal changed for this beam
        continue
    elseif ~all(updateM(:,beamIndex))
        indstructV = find(updateM(:,beamIndex));
        if ~ismember('skin',lower({IM.goals(indstructV).structName})) && ...
                ismember('skin',lower({IM.goals.structName}))
            skinInd = find(strcmpi('skin',{IM.goals.structName}));
            recomputeDose = 0;
        else
            recomputeDose = 1;
        end
    else
        recomputeDose = 1;
    end

    if recomputeDose

        pb(:,1)=IM.beams(beamIndex).RTOGPBVectorsM_MC(:,1)+IM.beams(beamIndex).x;
        pb(:,2)=IM.beams(beamIndex).RTOGPBVectorsM_MC(:,2)+IM.beams(beamIndex).y;
        pb(:,3)=IM.beams(beamIndex).RTOGPBVectorsM_MC(:,3)+IM.beams(beamIndex).z;

        dx=IM.beams(beamIndex).beamletDelta_x;
        dy=IM.beams(beamIndex).beamletDelta_y;

        IC=[IM.beams(beamIndex).isocenter.x IM.beams(beamIndex).isocenter.y  IM.beams(beamIndex).isocenter.z];
        th=IM.beams(beamIndex).gantryAngle*pi/180;

        M=[cos(th) sin(th) 0; -sin(th) cos(th) 0; 0 0 1];
        Minv=[cos(th) -sin(th) 0; sin(th) cos(th) 0; 0 0 1];

        % translate to IC frame of reference
        pb=pb-repmat(IC, [length(pb), 1]);

        % anti rotate (i.e., to gantry angle of 0)
        pb=(Minv*pb')';

        % assuming SID=100
        % back project beams up by -50 cm
        %     s1=0.5;
        %     s2=50;
        %     s3=s1*0.5;
        % take SID from the IM struct. back project beams up by -50 cm
        s2 = 50;
        s1 = s2/IM.beams(beamIndex).isodistance;
        s3 = s1 * s1;

        pb(:,[1 3])=pb(:, [1 3])*s1;
        pb(:,2)=pb(:,2)+s2;

        for i=1:length(pb),
            pb_new{i}=[pb(i, 1)+dx*s3, pb(i, 2),  pb(i, 3)+dy*s3
                pb(i, 1)-dx*s3,  pb(i, 2),  pb(i, 3)+dy*s3
                pb(i, 1)-dx*s3,  pb(i, 2),  pb(i, 3)-dy*s3];
        end

        % rotate by the gantry angle
        for i=1:length(pb),
            pb_rot{i}=(M*pb_new{i}')' + repmat(IC, [3 1]);
        end

        % include the offset from the CT image
        virtualSource=[IM.beams(beamIndex).x-offset(3), offset(2)-IM.beams(beamIndex).y, IM.beams(beamIndex).z-offset(5)];

        IC=[IC(1)-offset(3) offset(2)-IC(2) IC(3)-offset(5)];

        for i=1:length(pb),
            pb_rot{i}=pb_rot{i}-repmat([offset(3) 0 offset(5)], [3 1]);
            pb_rot{i}(:,2)=offset(2)-pb_rot{i}(:,2);
        end

        % rounding because VMC++ requires the edges of the beamlet form
        % a square, by testing the dot product      %PUT error function here??
        for i=1:length(pb),
            temp=pb_rot{i};
            pb_rot{i}(:,1)=temp(:,2);
            pb_rot{i}(:,2)=temp(:,1);
            pb_rot{i}=round(pb_rot{i}*100000)/100000;
        end

        VMCOpt.startBeamletSource.virtualPointSourcePosition = [virtualSource(2) virtualSource(1) virtualSource(3)];

        %Write .vmc files for each pencil beam.
        for i=1:length(pb_rot),

            %Set beam spectrum file.
            switch IM.beams(beamIndex).beamEnergy
                case 6
                    energyFile = fullfile(energyPath, 'var_6MV.spectrum');
                case 15
                    energyFile = fullfile(energyPath, 'mohan_15MV.spectrum');
                case 18
                    energyFile = fullfile(energyPath, 'var_18MV.spectrum');
                otherwise
                    error('Invalid beam energy.'); %Eventually add custom beamEnergy files here.
            end

            %if a spectrum was entered in the GUI, use this one instead
            if ~strcmp(IM.params.VMC.spectrum,'') && ~isempty(IM.params.VMC.spectrum)
                if exist(fullfile(VMCPath,'spectra',IM.params.VMC.spectrum), 'file') == 2
                    energyFile = fullfile(energyPath,IM.params.VMC.spectrum);
                else
                    fprintf('\nERROR: Spectrum %s does not exist!\n\n',fullfile(VMCPath,'spectra',IM.params.VMC.spectrum));
                    return
                end
            end

            energyFile(strfind(energyFile, '\')) = '/'; %Must use '/' instead of '\' for VMC.

            VMCOpt.startBeamletSource.spectrum = energyFile;

            switch lower(IM.beams(beamIndex).beamModality)
                case 'photons'
                    VMCOpt.startBeamletSource.charge = 0;
                case 'electrons'
                    VMCOpt.startBeamletSource.charge = -1;
                otherwise
                    error('Invalid beamModality.');
            end

            %Create different rands 1:30000 for each PB.
            VMCOpt.startMCControl.RNGSeeds = [round(rand*30000)+1 round(rand*30000)+1];

            %Set pencil beam edges.
            VMCOpt.startBeamletSource.beamletEdges= [pb_rot{i}(1, :), pb_rot{i}(2,:),pb_rot{i}(3, :)];

            %Write .vmc file.
            outfile=['MCpencilbeam_', int2str(beamIndex), '_', int2str(i), '.vmc'];
            VMCInputC = makeVMCInput(VMCOpt, fullfile(runsPath, outfile));
        end

        npb = length(pb_rot);

        clear pb pb_new pb_rot

        switch VMCOpt.startScoring.startOutputOptions.dumpDose
            case 1
                precision = 4;
            case 2
                precision = 2;
            otherwise
                error('Incorrect value for dumpDose in VMCOpt. Try 1 or 2.')
        end

        sourceM = repmat([IM.beams(beamIndex).x, IM.beams(beamIndex).y, IM.beams(beamIndex).z], length(pM), 1);
        pRelM = pM - sourceM;

        %=========Loop over beamlets=============%
        for pbNum = 1:npb

            if pbNum > 1
                disp(['Computed ' int2str(pbNum-1) ' out of ' num2str(npb)]); pause(0.003);
                try
                    IMRTPGui('status', beamIndex, numBeams, ' CT scan ', pbNum - 1, npb);
                end
            end

            outfile=['MCpencilbeam_', int2str(beamIndex), '_', int2str(pbNum)];
            if ispc
                currPath = cd;
                cd(VMCPath);
                dos(['start /low /B /wait ' fullfile('.', 'bin', 'vmc_Windows.exe') ' ' outfile '']);

                %if exist('VMCOpt.denoising')
                %  if strcmpi(VMCOpt.denoising,'yes')
                %    niter=2;
                %    cerror=0.05;
                %    str=fullfile(VMCPath, 'runs', [outfile '_' VMCOpt.startScoring.startDoseOptions.scoreInGeometries '.dos'])
                %    dose = readDoseFile(fullfile(VMCPath, 'runs', [outfile '_' VMCOpt.startScoring.startDoseOptions.scoreInGeometries '.dos']), precision, scandr, scandc, scands);
                %    dose = reshape(dose, [scandr, scandc, scands]);
                %    maxValue = max(dose(:));
                %    mask = dose < (IM.params.Scatter.Threshold * maxValue);
                %%    lowDoses = zeros(size(dose));
                %    lowDoses(mask) = dose(mask);
                %    dose(mask) = 0;
                %    smoothLowDoses=anisodiff3d_miao(lowDoses, cerror, niter);  %denoising via anisotropic diffusion.
                %      clear mask
                %      clear lowDoses
                %    dose  = dose + smoothLowDoses;
                %    doseV = dose(:);
                %  end
                %end
                doseV = readDoseFile(fullfile('.', 'runs', [outfile '_' VMCOpt.startScoring.startDoseOptions.scoreInGeometries '.dos']), precision, scandr, scandc, scands);

            elseif isunix
                currPath = cd;
                cd(VMCPath);
                dos(['chmod u+x ' fullfile(VMCPath, 'vmc_wrapper')]);
                dos(['chmod u+x ' fullfile(VMCPath, 'bin', 'vmc_Linux.exe')]);
                dos(['dos2unix ' fullfile(VMCPath, 'vmc_wrapper')]); % to make sure endOfLine characters are correct
                dos([fullfile(VMCPath,'vmc_wrapper') ' ' VMCPath ' ' runsPath ' ' VMCPath ' ' fullfile(VMCPath, 'bin', 'vmc_Linux.exe') ' ' outfile]);
                doseV = readDoseFile(fullfile(VMCPath, 'runs', [outfile '_' VMCOpt.startScoring.startDoseOptions.scoreInGeometries '.dos']), precision, scandr, scandc, scands);

            end
            cd(currPath);

            % Added by JC July 11, 2006
            % Used later in chop doseV/doseM off by 'IM.params.cutoffDistance'
            RTOGPBVectorsM = IM.beams(beamIndex).RTOGPBVectorsM;
            PBV = RTOGPBVectorsM(pbNum,:);
            distV = pRelM * PBV';    %Each row is the dot product of (the un-normalized) source-to-calc point
            %direction and the PB unit vector.
            %Hence, this is the distance along the PB ray line for each dose calc point.

            qM = sourceM + distV * PBV;  %The last term gives the vector i, j, and k components of
            clear distV
            %distance to the depth of closest approach.
            %Each row of sourceM is the i,j,k position of the source.
            %So vector sum locates the positions of closest approach
            %to the dose calc points.

            rM  = pM - qM;    %Each row of pM is the x, y, z location of a dose calc point.
            clear qM
            %rM is then the vector pointing from the dose calc point to the point
            %at which the PB vector makes closest approach.

            %Trap points which are too far away to need dose calcs
            %Uses sepsq if possible, much faster.
            try
                rDistVSquared = sepsq([0 0 0]', rM');  %mex file speedup
                goV = rDistVSquared < (IM.params.cutoffDistance^2);
                %clear rDistVSquared
            catch
                rDistV = (rM(:,1).^2 + rM(:,2).^2 + rM(:,3).^2);    %if mex not there
                goV = rDistV < IM.params.cutoffDistance^2;         %Mod by JOD to speedup, Dec 05.
                %clear rDistV
            end

            % Cut off the dose by IM.params.cutoffDistance.
            doseV(~goV) = 0;
            clear goV rM

            % apply compression
            doseV = applyIMRTCompression(IM.params, doseV);

            % build 3D dose matrix
            doseM = zeros(getUniformScanSize(planC{indexS.scan}(scanNum)));
            if length(indV)==length(doseV)
                doseM(indV) = doseV;
            else
                errorBeamlets = [errorBeamlets beamletCounter];
            end

            %-----------Insert dose data into correct beamlet indices---------------------%
            for i = 1 : length(structROIV)
                beamlet = createIMBeamlet(doseM(scanIndV{i}), scanIndV{i}, beamIndex, 0);
                if isempty(IM.beams(beamIndex).beamlets)
                    IM.beams(beamIndex).beamlets = beamlet;
                else
                    IM.beams(beamIndex).beamlets(i,pbNum) = beamlet;
                end
                IM.beams(beamIndex).beamlets(i,pbNum).structureName = planC{planC{end}.structures}(structROIV(i)).structureName;
                IM.beams(beamIndex).beamlets(i,pbNum).sampleRate    = sampleRateV(i);
                IM.beams(beamIndex).beamlets(i,pbNum).strUID = planC{planC{end}.structures}(structROIV(i)).strUID;
            end
            beamletCounter = beamletCounter + 1;

        end

    else % obtain doseV from skin

        beamletsSkin = IM.beams(beamIndex).beamlets;
        npb = size(beamletsSkin,2);
        for PBNum = 1:npb
            dosebmtV  = double(beamletsSkin(skinInd,PBNum).influence);
            indV      = beamletsSkin(skinInd,PBNum).indexV;
            maxVal    = beamletsSkin(skinInd,PBNum).maxInfluenceVal;
            sizeParam = beamletsSkin(skinInd,PBNum).fullLength;
            if isfield(beamletsSkin, 'lowDosePoints')
                lowDosePoints = unpackLogicals(beamletsSkin(skinInd,PBNum).lowDosePoints, size(indV));
                doseScaledV(~lowDosePoints) = dosebmtV(~lowDosePoints) * (maxVal / (2^8 -1));
                doseScaledV(lowDosePoints) = dosebmtV(lowDosePoints) * (maxVal / (2^8 -1) / (2^8 -1));
            else
                doseScaledV = dosebmtV * (maxVal / (2^8 -1));
            end
            % build 3D dose matrix
            doseM = zeros(getUniformScanSize(planC{indexS.scan}(scanNum)));
            doseM(indV) = doseScaledV;
            doseScaledV = [];

            %-----------Insert dose data into correct beamlet indices---------------------%
            for i = 1 : length(structROIV)
                beamlet = createIMBeamlet(doseM(scanIndV{i}), scanIndV{i}, beamIndex, 0);
                if isempty(IM.beams(beamIndex).beamlets)
                    IM.beams(beamIndex).beamlets = beamlet;
                else
                    IM.beams(beamIndex).beamlets(i,PBNum) = beamlet;
                end
                IM.beams(beamIndex).beamlets(i,PBNum).structureName = planC{planC{end}.structures}(structROIV(i)).structureName;
                IM.beams(beamIndex).beamlets(i,PBNum).sampleRate    = sampleRateV(i);
                IM.beams(beamIndex).beamlets(i,PBNum).strUID = planC{planC{end}.structures}(structROIV(i)).strUID;
            end

        end

    end

    IMRTPGui('status', beamIndex, numBeams, ' CT scan ', npb, npb);

end

if length(errorBeamlets)>0
    disp(' ');
    disp('Error in generateVMCInfluence.m!');
    disp('The following beamlets were set to 0:');
    disp(errorBeamlets);
end


%  name for the perturbation parameter entering the structural model
%  explicitly
%  if parameterize is true, return also the default (MAIH's perturbation)
%  values
%


function [x_struct, z_struct, u_struct, p_struct, ...
          x_bounds, z_bounds, u_bounds, p_bounds, ...
          x_order] = vars(varsfh, userdata)

vh = ocl.VarHandler(userdata);
varsfh(vh);

x_struct = vh.x_struct;
z_struct = vh.z_struct;
u_struct = vh.u_struct;
p_struct = vh.p_struct;

x_bounds = vh.x_bounds;
z_bounds = vh.z_bounds;
u_bounds = vh.u_bounds;
p_bounds = vh.p_bounds;

x_order = vh.x_order;


function varargout = setInputName(obj,varargin)
    nVarargs = length(varargin);
    name = varargin{1};
    if nVarargs == 2
        index = varargin{2};
    else
        index = 1:obj.dim.u;
    end
    varargout = cell(size(index));
    j = 1;
    for i=index
        obj.u(i) = sym(name{j});
        varargout{j} = sym(name{j});
        j = j+1;
    end
end


function LoadFishDataWithoutTS(hfig,i_fish,hdf5_dir,mat_dir)
disp(['loading fish #' num2str(i_fish) '...']);

M_fish_set = getappdata(hfig,'M_fish_set');
fishset = M_fish_set(i_fish);
setappdata(hfig,'fishset',fishset);

%% load data from file

disp(['load fish ' num2str(i_fish) '...']);

if ~exist('hdf5_dir','var') || ~exist('mat_dir','var'),
    data_masterdir = getappdata(hfig,'data_masterdir');
    data_dir = fullfile(data_masterdir,['subject_' num2str(i_fish)]);
    hdf5_dir = fullfile(data_dir,'TimeSeries.h5');
    mat_dir = fullfile(data_dir,'data_full.mat');
end

tic

% load 'data'
load(mat_dir,'data'); % struct with many fields
names = fieldnames(data); % cell of strings
for i = 1:length(names),
    setappdata(hfig,names{i},eval(['data.',names{i}]));
end

% load time series (hdf5 file)
absIX = h5read(hdf5_dir,'/absIX');

setappdata(hfig,'absIX',absIX);

toc

% setappdata(hfig,'isfullfish',1);
end


function ppTrigger(value,raiseTime, delayTime)
% function - ppTrigger
%
% Send a value to the parallel port
%
% Synopsis:
%   ppTrigger(value)
%   ppTrigger(value, raiseTime)
%   ppTrigger(value, raiseTime, delayTime)
%
% Description:
%   The function uses ppWrite to write a value on the parallel port if
%   the global variable IO_ADDR is set. If the global variable
%   NOUZZ_UDP_SOCKET is set the values are also send via udp.
%
%   Currently the delay is not implemented for nouzz.
%
% Input:
%       value: The value you want write on the parallel port
%   raiseTime:[Optional] The time in ms how long the value should stay on
%             the parallel port. (Default: 10ms)
%   delayTime:[Optional] The time in ms how long the value should be
%              delayed. (Default: 0ms)

% Author ??? (Max Sagebaum)
%   2011/11/16 - Max Sagebaum
%                - Added documentation
%                - Added delayTime argument

global IO_ADDR
global NOUZZ_UDP_SOCKET
%global ETH_MARKERS

if ~isempty(IO_ADDR)
    if exist('delayTime','var')
      ppWrite(IO_ADDR, value, raiseTime, delayTime);
    elseif exist('raiseTime','var')
      ppWrite(IO_ADDR, value, raiseTime);
    else
      ppWrite(IO_ADDR, value);
    end
end

if ~isempty(NOUZZ_UDP_SOCKET)
    if exist('delayTime','var')
        if 0 ~= delayTime
            warning('ppTrigger: delay is not implemented for nouzz');
        end
    end
    pnet(NOUZZ_UDP_SOCKET, 'write', [uint8('M') typecast(uint16(value),'uint8')]);
    pnet(NOUZZ_UDP_SOCKET, 'writepacket');
end

%if (~isempty(ETH_MARKERS))
%    fprintf('redirecting trigger eth: %d\n', value);
 %   rawethmex('sendto', 1, sprintf('S%3d',value), 3);
%end


function []=ps_load_initial_isce(data_inc)
%PS_LOAD_INITIAL Initial load of PS files into matlab workspace
%   PS_LOAD_INITIAL() loads various files and stores them
%   in various workspaces. The version number, PSVER, is set to 1.
%
%   Andy Hooper, June 2006
%
%   ======================================================================
%   06/2006 AH: Initialize day variable
%   07/2006 AH: Fix error in la and bperp matrix calculation
%   07/2006 AH: Add patch compatibility
%   09/2006 AH: Store wrapped phase in separate workspace
%   11/2007 AH: Change bperp to be the bperp at 0 m
%   01/2008 AH: Selection of bperp files made more rigourous
%   03/2009 AH: Change bperp back to be the bperp at local height
%   10/2009 AH: Add n_image to mat file
%   04/2010 KS: Fixed small issue with new logit function
%   10/2009 MA: Oversampling factor file introduced
%   12/2012 DB: Add compatiblility with Matlab2012B, keep backward compatible
%   01/2016 DB: Replace save with stamps_save which checks for var size when saving
%   04/2017 DB: Include fix for isce2stamps calamp.out slc filenaming
%   04/2018 DB: Add support for baseline grids
%   03/2022 DHTM: change master to reference and ingesting TomoSAR_interflist
%   ======================================================================

%NB IFGS assumed in ascending date order
fprintf('Loading data into matlab...\n')

phname=['pscands.1.ph'];            % for each PS candidate, a float complex value for each ifg
ijname=['pscands.1.ij'];            % ID# Azimuth# Range# 1 line per PS candidate
bperpname=['bperp.1.in'];           % in meters 1 line per ifg
dayname=['day.1.in'];               % YYYYMMDD, 1 line per ifg
masterdayname=['reference_day.1.in'];  % YYYYMMDD
llname=['pscands.1.ll'];            % 2 float values (lon and lat) per PS candidate
daname=['pscands.1.da'];            % 1 float value per PS candidate
hgtname=['pscands.1.hgt'];          % 1 float value per PS candidate
laname=['look_angle.1.in'];         % grid of look angle values
headingname=['heading.1.in'];       % satellite heading
lambdaname=['lambda.1.in'];         % wavelength
calname=['calamp.out'];             % amplitide calibrations
widthname=['width.txt'];            % width of interferograms
lenname=['len.txt'];                % length of interferograms

psver=1;
incsavename=['inc',num2str(psver)];
lasavename=['la',num2str(psver)];

% Get matlab version as function arguments change with the matlab version
matlab_version = version('-release');           % [DB] getting the matlab version
matlab_version = str2num(matlab_version(1:4));  % [DB] the year

if ~exist(dayname,'file')
    dayname= ['../',dayname];
end
day = load(dayname);

% ingesting the TomoSAR ComSAR name
TomoSAR_interflist = 'TomoSAR_interflist.mat';
if ~exist(TomoSAR_interflist,'file')
    TomoSAR_interflist= ['../',TomoSAR_interflist];
    if ~exist(TomoSAR_interflist,'file')
        % assume PSDS output is the same as PSI, no need to index-ing
        TomoSAR_ind = 1:size(day,1);
    else
        load(TomoSAR_interflist)
        [~,TomoSAR_ind]=ismember(TomoSAR_interflist,day);
    end
else
    load(TomoSAR_interflist)
    [~,TomoSAR_ind]=ismember(TomoSAR_interflist,day);
end

day = day(TomoSAR_ind);

year=floor(day/10000);
month=floor((day-year*10000)/100);
monthday=day-year*10000-month*100;
slave_day=datenum(year,month,monthday);
[slave_day,day_ix]=sort(slave_day);

if ~exist(masterdayname,'file')
    masterdayname= ['../',masterdayname];
end
master_day=load(masterdayname);
master_day_yyyymmdd=master_day;
year=floor(master_day/10000);
month=floor((master_day-year*10000)/100);
monthday=master_day-year*10000-month*100;
master_day=datenum(year,month,monthday);

master_ix=sum(slave_day<master_day)+1;
day=[slave_day(1:master_ix-1);master_day;slave_day(master_ix:end)]; % insert master day

%% bperp one value per slave
if ~exist(bperpname,'file')
    bperpname= ['../',bperpname];
end
bperp=load(bperpname);
bperp = bperp(TomoSAR_ind);

bperp=bperp(day_ix);
bperp=[bperp(1:master_ix-1);0;bperp(master_ix:end)]; % insert master-master bperp (zero)
n_ifg=size(bperp,1);
n_image=n_ifg;

%% heading
if ~exist(headingname,'file')
    headingname= ['../',headingname];
end
heading=load(headingname);
if isempty(heading)
    error('heading.1.in is empty')
end
setparm('heading',heading,1);

%% wavelength
if ~exist(lambdaname,'file')
    lambdaname= ['../',lambdaname];
end
lambda=load(lambdaname);
setparm('lambda',lambda,1);

%% Radar coordinates
ij=load(ijname);
n_ps=size(ij,1);

if ~exist(calname,'file')
    calname= ['../',calname];
end
if exist(calname,'file')
    [calfile,calconst]=textread(calname,'%s%f');
    caldate=zeros(length(calfile),1);
    for i = 1 : length(calfile)
        aa=strread(calfile{i},'%s','delimiter','/');

        if strcmpi(aa{end-1},'reference');
                bb=str2num(aa{end-2}(end-7:end));
        else
            bb=str2num(aa{end}(1:8));
            if isempty(bb)
                bb=str2num(aa{end-1}(1:8));
            end
        end
        caldate(i)=bb;
    end
    not_master_ix=caldate~=master_day_yyyymmdd;
    caldate=caldate(not_master_ix);
    calconst=calconst(not_master_ix);
    [Y,I]=sort(caldate);
    calconst=calconst(I);
else
    calconst=ones(n_ifg-1,1);
end

fid=fopen(phname,'r');
ph=zeros(n_ps,n_ifg-1,'single');
byte_count=n_ps*2;
for i=1:n_ifg-1
    [ph_bit,byte_count]=fread(fid,[(n_ps)*2,1],'float');
    ph_bit=single(ph_bit);
    ph(:,i)=complex(ph_bit(1:2:end),ph_bit(2:2:end));
end

ph=ph(:,day_ix);
zero_ph=sum(ph==0,2);
nonzero_ix=zero_ph<=1;       % if more than 1 phase is zero, drop node
ph=ph./repmat(calconst',n_ps,1);  % scale amplitudes
ph=[ph(:,1:master_ix-1),ones(n_ps,1),ph(:,master_ix:end)]; % insert zero phase master-master ifg

%% LON LAT
fid=fopen(llname,'r');
lonlat=fread(fid,[2,inf],'float');
lonlat=lonlat';
fclose(fid);

ll0=(max(lonlat)+min(lonlat))/2;
xy=llh2local(lonlat',ll0)*1000;
xy=xy';
sort_x=sortrows(xy,1);
sort_y=sortrows(xy,2);
n_pc=round(n_ps*0.001);
bl=mean(sort_x(1:n_pc,:)); % bottom left corner
tr=mean(sort_x(end-n_pc:end,:)); % top right corner
br=mean(sort_y(1:n_pc,:)); % bottom right  corner
tl=mean(sort_y(end-n_pc:end,:)); % top left corner

theta=(180-heading)*pi/180;
if theta>pi
    theta=theta-2*pi;
end

rotm=[cos(theta),sin(theta); -sin(theta),cos(theta)];
xy=xy';
xynew=rotm*xy; % rotate so that scene axes approx align with x=0 and y=0
if max(xynew(1,:))-min(xynew(1,:))<max(xy(1,:))-min(xy(1,:)) &...
   max(xynew(2,:))-min(xynew(2,:))<max(xy(2,:))-min(xy(2,:))
    xy=xynew; % check that rotation is an improvement
    disp(['Rotating by ',num2str(theta*180/pi),' degrees']);
end

xy=single(xy');
[dummy,sort_ix]=sortrows(xy,[2,1]); % sort in ascending y order
xy=xy(sort_ix,:);
xy=[[1:n_ps]',xy];
xy(:,2:3)=round(xy(:,2:3)*1000)/1000; % round to mm

ph=ph(sort_ix,:);
ij=ij(sort_ix,:);
ij(:,1)=1:n_ps;
lonlat=lonlat(sort_ix,:);

savename=['ps',num2str(psver)];
stamps_save(savename,ij,lonlat,xy,bperp,day,master_day,master_ix,n_ifg,n_image,n_ps,sort_ix,ll0,calconst,master_ix,day_ix);
save psver psver

phsavename=['ph',num2str(psver)];
% save(phsavename,'ph');
stamps_save(phsavename,ph);

if exist(daname,'file')
  D_A=load(daname);
  D_A=D_A(sort_ix);
  dasavename=['da',num2str(psver)];
  stamps_save(dasavename,D_A);
end

if exist(hgtname,'file')
    fid=fopen(hgtname,'r');
    hgt=fread(fid,[1,inf],'float');
    hgt=hgt';
    hgt=hgt(sort_ix);
    fclose(fid);
    hgtsavename=['hgt',num2str(psver)];
    stamps_save(hgtsavename,hgt);
end

if ~exist(widthname,'file')
    widthname= ['../',widthname];
end
width=load(widthname);

if ~exist(lenname,'file')
    lenname= ['../',lenname];
end
len=load(lenname);

% try to see if inc angle exist, fall back to la if needed
if nargin<1 | isempty(data_inc)
    clear data_inc
    % might be in dirs above when called from patch dir
    % inc angle
    if ~exist(incname,'file')
        incname= ['..',filesep,incname];
        if ~exist(incname,'file')
            incname= ['..',filesep,incname];
        end
    end

    if exist(incname,'file')
         data_inc = single(load_isce(incname));
    end
end
% checking if the inc angle exist if not try look angle
if exist('data_inc','var')
    % inc angle exist
    % getting the position of the PS
    IND = sub2ind(size(data_inc),ij(:,3)+1,ij(:,2)+1);
    % storing the data
    inc=data_inc(IND);
    inc = inc*pi./180;
    stamps_save(incsavename,inc)
else
    % trying look angle instead
     if ~exist(laname,'file')
        laname= ['..',filesep,laname];
        if ~exist(incname,'file')
            laname= ['..',filesep,laname];
            clear laname
        end
     end
     % laod the data if it exists
     if exist(laname,'file')
         data_la = single(load_isce(laname));

        % getting the position of the PS
        IND = sub2ind(size(data_la),ij(:,3)+1,ij(:,2)+1);

        % storing the data
        la=data_la(IND);
        la = la*pi./180;
        stamps_save(lasavename,la)
        clear data_la
     end
end

updir=0;
bperpdir=dir(['..' filesep 'baselineGRID_*']);
if isempty(bperpdir)
    bperpdir=dir(['..' filesep '..' filesep 'baselineGRID_*']);
    updir=1;
end
if length(bperpdir)>0
    % make a set of baseline excluding the master
    bperp_mat=zeros(n_ps,n_image-1,'single');
    counter =1;
    for i=setdiff([1:n_image],master_ix);
        bperp_fname=['..' filesep 'baselineGRID_' datestr(day(i),'yyyymmdd')];
        if updir==1
            bperp_fname=['..' filesep bperp_fname];
        end
        bperp_grid = load_isce(bperp_fname);

        % check if the baseline grid is a full IFG grid or smaller grid
        if size(bperp_grid)==[width, len]
            % getting the position of the PS
            IND = sub2ind(size(bperp_grid),ij(:,3)+1,ij(:,2)+1);
            % storing the data
            bp0_ps=bperp_grid(IND);
            if i==1
                fprintf('yes \n')
            end
        else
            if i==1
                fprintf('no \n')
                [gridX,gridY]=meshgrid(linspace(0,width,size(bperp_grid,1)),linspace(0,len,size(bperp_grid,2)));
            end
            bp0_ps=griddata_version_control(gridX,gridY,bperp_grid',ij(:,3),ij(:,2),'linear',matlab_version);               % [DB] fix matlab2012 version and older

        end
        bperp_mat(:,counter)=bp0_ps;
        counter = counter+1;
    end
else
    bperp_mat=repmat(single(bperp([1:master_ix-1,master_ix+1:end]))',n_ps,1);
end
bpsavename=['bp',num2str(psver)];
stamps_save(bpsavename,bperp_mat);