classdef PDEVisualization < matlab.graphics.chartcontainer.ChartContainer & ...
                            matlab.graphics.chartcontainer.mixin.Colorbar
% A container that represents a PDE visualization object
% A PDEVisualization is a container that stores the nodal data, mesh, and 
% visualization options.
%
% Create a PDEVisualization object using pdeviz and providing the mesh data
% and, optionally, the nodal data.
%
% Full Property list:
%       MeshData
%       NodalData
%       DeformationData
%       DeformationScaleFactor
%       MeshVisible
%       Transparency
%
%       Position
%       InnerPosition
%       OuterPosition
%       PositionConstraint
%       Units
%       Layout
%       Parent
%       HandleVisibility
%       ColorbarVisible
%       Visible
%
%       XLimits
%       YLimits
%       ZLimits
%       ColorLimits
%       XLabel
%       YLabel
%       ZLabel
%       Title
%       Colormap
%       View
%       AxesVisible
%       AxesColor
%

%   Copyright 2020-2023 The MathWorks, Inc.
    
    properties(Dependent)
        % Main chart properties
        MeshData (:,1) pde.FEMesh = pde.FEMesh.empty
        NodalData (:,1) double = []
        DeformationData {pde.graphics.PDEVisualization.mustBeNumericOrFEStructLike(DeformationData)} = []
        MeshVisible (1,1) matlab.lang.OnOffSwitchState = matlab.lang.OnOffSwitchState.off
        Transparency (1,1) double {mustBeNonnegative,mustBeLessThanOrEqual(Transparency,1)} = 1
        DeformationScaleFactor (1,1) double {mustBeNonnegative} = 0
        % Axis manipulation - all set/get methods use axis properties
        XLimits matlab.internal.datatype.matlab.graphics.datatype.Limits = [0 1]
        YLimits matlab.internal.datatype.matlab.graphics.datatype.Limits = [0 1]
        ZLimits matlab.internal.datatype.matlab.graphics.datatype.Limits = [0 1]
        ColorLimits matlab.internal.datatype.matlab.graphics.datatype.Limits = [0 1]
        XLabel matlab.internal.datatype.matlab.graphics.datatype.NumericOrString
        YLabel matlab.internal.datatype.matlab.graphics.datatype.NumericOrString
        ZLabel matlab.internal.datatype.matlab.graphics.datatype.NumericOrString
        Title matlab.internal.datatype.matlab.graphics.datatype.NumericOrString
        Colormap % matlab.internal.datatype.matlab.graphics.datatype.ColorMap
        View matlab.internal.datatype.matlab.graphics.datatype.AxesView 
        AxesVisible (1,1) matlab.lang.OnOffSwitchState = matlab.lang.OnOffSwitchState.on;
        AxesColor matlab.internal.datatype.matlab.graphics.datatype.RGBAColor
    end

    properties(Access = protected,Hidden,Transient,NonCopyable)
        % These are the graphics objects captured 
        MeshObject (:,1) matlab.graphics.chart.primitive.Line
        SolidObject (:,1) matlab.graphics.primitive.Patch
        % Properties for building graphics objects
        SolidUndeformedVertices double
        MeshLinkage double
        NeedSurfaceAndMeshRecompute (1,1) logical = true
        IsTwoD (1,1) logical = false
    end
    
    properties(Access = protected,Hidden)
        % Internal Properties needed besides those captured in axis and
        % objects
        MeshData_I (:,1) pde.FEMesh = pde.FEMesh.empty
        NodalData_I (:,1) double = []
        Transparency_I (1,1) double {mustBeNonnegative,mustBeLessThanOrEqual(Transparency_I,1)} = 1
        DeformationData_I {pde.graphics.PDEVisualization.mustBeNumericOrFEStructLike(DeformationData_I)} = []
        MeshVisible_I (1,1) matlab.lang.OnOffSwitchState = matlab.lang.OnOffSwitchState.off
        DeformationMode matlab.internal.datatype.matlab.graphics.datatype.AutoManual = 'auto'
        DeformationScaleFactor_I (1,1) double {mustBeNonnegative} = 0
        ViewMode matlab.internal.datatype.matlab.graphics.datatype.AutoManual = 'auto'
        
        % Property that stores all data for save/load
        % will grab other Internal properties from axis and objects
        DataStorage

        Colormap_I = turbo;
    end
    
    methods
        function obj = PDEVisualization(varargin)
            
            % Call Colorbar mixin constructor first so the ColorbarVisible property
            % can be set as part of nv-pairs
            obj@matlab.graphics.chartcontainer.mixin.Colorbar();
            
            % Call ChartContainer superclass constructor
            obj@matlab.graphics.chartcontainer.ChartContainer(varargin{:});
        end
    end
    
    methods(Access = protected)
        function setup(obj)
            % create empty Solid and Mesh objects
            ax = getAxes(obj);
            hold(ax,'on');
            solid = patch(ax,'Faces',[], 'Vertices',[], 'FaceVertexCData',[], 'AmbientStrength', .75,  ...
                'EdgeColor', 'none', 'FaceColor', 'interp', 'Clipping','off');
            hf = ancestor(solid,'matlab.graphics.mixin.ThemeContainer'); 
            % enable dark theme
            if (~isempty(hf))
                matlab.graphics.internal.themes.figureUseDesktopTheme(hf);
            end
            mesh = plot(ax,NaN,NaN,'Clipping','off');
            
            % Set default axis look and colormap
            ax.DataAspectRatio = [1 1 1];
            axis(ax,'tight');
            colormap(ax,obj.Colormap_I);

            % Save objects and turn off hold
            obj.SolidObject = solid;
            obj.MeshObject = mesh;
            hold(ax,'off');
        end

        function update(obj)
            % simple names for common variables
            solid = obj.SolidObject;
            mesh = obj.MeshObject;
            
            % Nothing to update if mesh is empty
            if isempty(obj.MeshData_I)
                % Set Solid and Mesh object to empty
                solid.Vertices = [];
                solid.Faces = [];
                mesh.XData = [];
                mesh.YData = [];
                mesh.ZData = [];
                
                % Warn if NodalData is non-empty
                if ~isempty(obj.NodalData_I)
                    warning(message('pde:pdeviz:incompatibleNodalData'));
                end
                
                % Warn if DeformationData is non-empty
                if ~isempty(obj.DeformationData_I)
                    warning(message('pde:pdeviz:incompatibleDeformationData'));
                end
                
                % Quick return
                return;
            end
            
            obj.SolidObject.FaceAlpha = obj.Transparency_I;

            % First recompute surface and mesh triangulations if necessary
            % (on a MeshData change) and save mesh vertices
            if obj.NeedSurfaceAndMeshRecompute 
                % Compute triangulation for surface
                [p,~,t] = obj.MeshData_I.meshToPet();
                
                % Remove domain labels for t
                if size(p,1) == 2
                    if(size(t,1) == 4 || size(t,1) == 7)
                        t(end,:)=[];
                    end
                    obj.IsTwoD = true;
                else
                    if(size(t,1) == 5 || size(t,1) == 11)
                        t(end,:)=[];
                    end
                    obj.IsTwoD = false;
                end
            
                % If we are using quadratic elements split up each triangle
                % accordingly into 4 and also compute mesh linkage
                if obj.IsTwoD
                    % for solid
                    ltri = t';
                    if (size(t,1) == 6)
                        t4Nodes = [1 4 6; 4 5 6; 4 2 5; 6 5 3];
                        ltri = [ltri(:,t4Nodes(1,:)); ltri(:,t4Nodes(2,:)); ltri(:,t4Nodes(3,:)); ltri(:,t4Nodes(4,:))];
                    end
                    
                    % for mesh
                    if size(t,1) == 3
                        ltrim = t([1 2 3 1],:);
                    else
                        ltrim = t([1 4 2 5 3 6 1],:);
                    end

                    % Set to default 2D view if in auto mode
                    if (obj.ViewMode == "auto")
                        obj.View = [0 90];
                    end
                else
                    % for solid surface
                    ltri = tetBoundaryFacets(p,t);
                    
                    % for mesh 
                    if (size(t,1) == 4)
                        ltrim = ltri(:,[1 2 3 1])';
                    else
                        ltrim = ltri(:,[1 4 2 5 3 6 1])';
                    end
                    
                    if (size(t,1) == 10)
                        t4Nodes = [1 4 6; 4 5 6; 4 2 5; 6 5 3];
                        ltri = [ltri(:,t4Nodes(1,:)); ltri(:,t4Nodes(2,:)); ltri(:,t4Nodes(3,:)); ltri(:,t4Nodes(4,:))];
                    end

                    % Set to default 3D view if in auto mode
                    if (obj.ViewMode == "auto")
                        obj.View = [30 30];
                    end
                end
                
                % Once triangulation is computed can set the surface
                % property and userdata for vertices and mesh linkage
                solid.Faces = ltri;
                obj.SolidUndeformedVertices = p;
                obj.MeshLinkage = ltrim;

                % Set flag to avoid this expensive operation until next
                % MeshData change
                obj.NeedSurfaceAndMeshRecompute = false;
            end
            
            % Check nodal sizes between Mesh, NodalData and Deformation,
            % warn if they dont match, then fast return
            if ~isempty(obj.NodalData) && ~pde.graphics.PDEVisualization.verifyMeshAndNodalDataMatch(obj.MeshData,obj.NodalData)
                warning(message('pde:pdeviz:incompatibleNodalData'));
                return;
            end
            
            if ~pde.graphics.PDEVisualization.verifyMeshAndDeformationDataNodalMatch(obj.MeshData,obj.DeformationData)
                warning(message('pde:pdeviz:incompatibleDeformationData'));
                return;
            end
            
            if ~pde.graphics.PDEVisualization.verifyMeshAndDeformationDataDimensionMatch(obj.MeshData,obj.DeformationData)
                warning(message('pde:pdeviz:incompatibleDeformationDataDimensionality',size(obj.MeshData.Nodes,1)));
                return;
            end
            
            % if we have deformationData and automode Compute the
            % Deformation Factor
            if ~isempty(obj.DeformationData_I) && (obj.DeformationMode == "auto")
                obj.DeformationScaleFactor_I = ComputeDefFactor(obj);
            end
            
            % Modify surface and Mesh objects vertices by Deformation
            if ~isempty(obj.DeformationData)
                deformation = obj.DeformationData_I;
                scaleFactor = obj.DeformationScaleFactor_I;
                if ~isnumeric(deformation)
                    if obj.IsTwoD
                        d = real([deformation.ux deformation.uy]);
                    else
                        d = real([deformation.ux deformation.uy deformation.uz]);
                    end
                else
                    d = real(deformation);
                end
            else
                d = 0;
                scaleFactor = 0;
            end
            
            % Set solid vertex locations to deformed mesh vertices
            solid.Vertices = (obj.SolidUndeformedVertices)' + scaleFactor*d;
            
            % Set NodalData as CData unless it's empty
            if ~isempty(obj.NodalData_I)            
                solid.FaceVertexCData = real(obj.NodalData);
            else
                solid.FaceVertexCData = zeros(size(solid.Vertices,1),1);
            end            
                        
            % if mesh is visible update its information also
            if obj.MeshVisible_I
                ltrim = obj.MeshLinkage;
                
                x = solid.Vertices(:,1);
                y = solid.Vertices(:,2);
                xt = x(ltrim); yt = y(ltrim);
                xt(end+1,:)=NaN; yt(end+1,:)=NaN;
                mesh.XData = xt(:);
                mesh.YData = yt(:);
                    
                if obj.IsTwoD
                    mesh.ZData = [];
                else
                    z = solid.Vertices(:,3);
                    zt = z(ltrim);
                    zt(end+1,:)=NaN;
                    mesh.ZData = zt(:);
                end
                mesh.Visible = true;
            else
                mesh.Visible = false;
            end
        end
        
        function propgrp = getPropertyGroups(obj)
            if isempty(obj.DeformationData)
                proplist = {'MeshData','NodalData','MeshVisible','Transparency','Position','Units'};
            else
                proplist = {'MeshData','NodalData','DeformationData','DeformationScaleFactor','MeshVisible','Transparency','Position','Units'};
            end
            propgrp = matlab.mixin.util.PropertyGroup(proplist);
        end
    end
    
    methods
        % gets called on save
        function DS = get.DataStorage(obj)
            % Save axis properties in DataStorage property
            ax = obj.getAxes();
            DS.XLim = ax.XLim;
            DS.YLim = ax.YLim;
            DS.ZLim = ax.ZLim;
            DS.CLim = ax.CLim;
            DS.XLimMode = ax.XLimMode;
            DS.YLimMode = ax.YLimMode;
            DS.ZLimMode = ax.ZLimMode;
            DS.CLimMode = ax.CLimMode;
            DS.XLabel = ax.XLabel.String;
            DS.YLabel = ax.YLabel.String;
            DS.ZLabel = ax.ZLabel.String;
            DS.Title = ax.Title.String;
            DS.View = ax.View;
            DS.Colormap = ax.Colormap;
            DS.ColorbarVisible = obj.ColorbarVisible;
            DS.AxesColor = ax.Color;
            DS.AxesVisible = ax.Visible;
        end
        
        % gets called on load
        function set.DataStorage(obj,data)
            % Load axis properties in DataStorage property
            ax = obj.getAxes();
            ax.XLim = data.XLim;
            ax.YLim = data.YLim;
            ax.ZLim = data.ZLim;
            ax.CLim = data.CLim;
            ax.XLimMode = data.XLimMode;
            ax.YLimMode = data.YLimMode;
            ax.ZLimMode = data.ZLimMode;
            ax.CLimMode = data.CLimMode;
            ax.XLabel.String = data.XLabel;
            ax.YLabel.String = data.YLabel;
            ax.ZLabel.String = data.ZLabel;
            ax.Title.String = data.Title;
            ax.View = data.View;
            colormap(ax,data.Colormap);
            obj.ColorbarVisible = data.ColorbarVisible;
            if (isfield(data,'AxesVisible'))
                ax.Visible = data.AxesVisible;
            end
            if (isfield(data,'AxesColor'))
                ax.Color = data.AxesColor;
            else
                ax.Color = [1 1 1];
            end

            % By design, Labels and Title are set to on, even if visibility
            % of the Axes is set to off. See the method: set.AxesVisible
            ax.XLabel.Visible = 'on';
            ax.YLabel.Visible = 'on';
            ax.ZLabel.Visible = 'on';
            ax.Title.Visible = 'on';
        end
        
        % main setters
        function set.MeshData(obj,newmesh)
            obj.MeshData_I = newmesh;
            obj.NeedSurfaceAndMeshRecompute = true;
        end
        
        function set.NodalData(obj,newnodaldata)
            obj.NodalData_I = newnodaldata;
        end
                
        function set.DeformationData(obj,newdefdata)
            if ~pde.graphics.PDEVisualization.mustBeNumericOrFEStructLike(newdefdata)
                error(message('pde:pdeviz:invaliddefdata'));
            end
            obj.DeformationData_I = newdefdata;
        end
        
        function set.DeformationScaleFactor(obj,newval)
            if isfinite(newval)
                obj.DeformationMode = 'manual';
                obj.DeformationScaleFactor_I = newval;
            else
                obj.DeformationMode = 'auto';
            end
        end
        
        function set.Transparency(obj,newtrans)
            obj.Transparency_I = newtrans;
            obj.SolidObject.FaceAlpha = newtrans;
        end
        
        function set.MeshVisible(obj,newmv)
            obj.MeshVisible_I = newmv;
        end
        
        % main getters
        function msh = get.MeshData(obj)
            msh = obj.MeshData_I;
        end
        
        function nd = get.NodalData(obj)
            nd = obj.NodalData_I;
        end
        
        function def = get.DeformationData(obj)
            def = obj.DeformationData_I;
        end
        
        function dsf = get.DeformationScaleFactor(obj)
            if obj.DeformationMode == "manual"
                dsf = obj.DeformationScaleFactor_I;
            else
                dsf = ComputeDefFactor(obj);
            end
        end
        
        function mv = get.MeshVisible(obj)
            mv = obj.MeshVisible_I;
        end
        
        function tr = get.Transparency(obj)
            tr = obj.Transparency_I;
        end
        
        % graphics convenience functions
        function varargout = xlim(obj, varargin)
            % Call the standard xlim method on the axes,
            % This may toggle either XLim or XLimMode or both.
            ax = obj.getAxes();
            [varargout{1:nargout}] = xlim(ax, varargin{:});
        end
        
        function set.XLimits(obj,limits)
            xlim(obj,limits);
        end

        function varargout = ylim(obj, varargin)
            % Call the standard ylim method on the axes,
            % This may toggle either YLim or YLimMode or both.
            ax = obj.getAxes();
            [varargout{1:nargout}] = ylim(ax, varargin{:});
        end
        
        function set.YLimits(obj,limits)
            ylim(obj,limits);
        end
        
        function varargout = zlim(obj, varargin)
            % Call the standard zlim method on the axes,
            % This may toggle either YLim or YLimMode or both.
            ax = obj.getAxes();
            [varargout{1:nargout}] = zlim(ax, varargin{:});
        end
        
        function set.ZLimits(obj,limits)
            zlim(obj,limits);
        end
 
        function varargout = caxis(obj, varargin)
            % Call the standard caxis method on the axes,
            % This may toggle either CAxis or XLimMode or both.
            ax = obj.getAxes();
            [varargout{1:nargout}] = caxis(ax, varargin{:});
        end
        
        function set.ColorLimits(obj,limits)
            caxis(obj,limits);
        end
        
        function varargout = colormap(obj, varargin)
            % Call the standard caxis method on the axes,
            % This may toggle either CAxis or CLimMode or both.
            ax = obj.getAxes();
            [varargout{1:nargout}] = colormap(ax, varargin{:});
        end
        
        function set.Colormap(obj,val)
            ax = getAxes(obj);
            colormap(ax,val);
            obj.Colormap_I = val;
        end
        
        function varargout = view(obj, varargin)
            % Call the standard view method on the axes,
            ax = obj.getAxes();
            [varargout{1:nargout}] = view(ax, varargin{:});
        end
        
        function set.View(obj,val)
            obj.ViewMode = 'manual';
            view(obj,val);
        end 
        
        function set.Title(obj,newtitle)
            ax = getAxes(obj);
            ax.Title.String = newtitle;
            ax.Title.Visible = 'on';
        end 
        
        function set.XLabel(obj,newxlabel)
            ax = getAxes(obj);
            ax.XLabel.String = newxlabel;
            ax.XLabel.Visible = 'on';
        end
        
        function set.YLabel(obj,newylabel)
            ax = getAxes(obj);
            ax.YLabel.String = newylabel;
            ax.YLabel.Visible = 'on';
        end
        
        function set.ZLabel(obj,newzlabel)
            ax = getAxes(obj);
            ax.ZLabel.String = newzlabel;
            ax.ZLabel.Visible = 'on';
        end
        
        function set.AxesVisible(obj,val)
            ax = getAxes(obj);
            ax.Visible = val;
            % Make sure labels and title stay visible
            ax.XLabel.Visible = 'on';
            ax.YLabel.Visible = 'on';
            ax.ZLabel.Visible = 'on';
            ax.Title.Visible = 'on';
        end
        
        function set.AxesColor(obj,val)
            ax = getAxes(obj);
            ax.Color = val;
        end
        
        % get methods for axis dependent properties
        function lim = get.XLimits(obj)
            update(obj);
            ax = getAxes(obj);
            lim = ax.XAxis.Limits;
        end
        
        function lim = get.YLimits(obj)
            update(obj);
            ax = getAxes(obj);
            lim = ax.YAxis.Limits;
        end
        
        function lim = get.ZLimits(obj)
            update(obj);
            ax = getAxes(obj);
            lim = ax.ZAxis.Limits;
        end
        
        function lim = get.ColorLimits(obj)
            update(obj);
            ax = obj.getAxes();
            lim = caxis(ax);
        end
        
        function out = get.Colormap(obj)
            update(obj);
            ax = obj.getAxes();
            out = colormap(ax);
        end
        
        function out = get.View(obj)
            update(obj);
            ax = obj.getAxes();
            [Az, El] = view(ax);
            out = [Az El];
        end
        
        function out = get.Title(obj)
            update(obj);
            ax = getAxes(obj);
            out = ax.Title.String;
        end
        
        function out = get.XLabel(obj)
            update(obj);
            ax = getAxes(obj);
            out = ax.XLabel.String;
        end
        
        function out = get.YLabel(obj)
            update(obj);
            ax = getAxes(obj);
            out = ax.YLabel.String;
        end
        
        function out = get.ZLabel(obj)
            update(obj);
            ax = getAxes(obj);
            out = ax.ZLabel.String;
        end
        
        function out = get.AxesVisible(obj)
            update(obj);
            ax = getAxes(obj);
            out = ax.Visible;
        end
        
        function out = get.AxesColor(obj)
            update(obj);
            ax = getAxes(obj);
            out = ax.Color;
        end
    end
    
    methods(Access = private)
        % Helper for computing automode
        function sF = ComputeDefFactor(obj)
            [p,~,~] = obj.MeshData.meshToPet();
            
            if size(p,1) == 2 % obj.IsTwoD
                bbox = [min(p(1,:)) max(p(1,:));
                    min(p(2,:)) max(p(2,:))];
            else
                bbox = [min(p(1,:)) max(p(1,:));
                    min(p(2,:)) max(p(2,:));
                    min(p(3,:)) max(p(3,:))];
            end
            
                deformation = obj.DeformationData;
                
                if isnumeric(deformation)
                    MaxDeformationMag = max(sum(abs(real(deformation).^2),2));
                else
                    if size(p,1) == 2
                        MaxDeformationMag = max(abs(real(deformation.ux)).^2+abs(real(deformation.uy)).^2,[],'all');
                    else
                        MaxDeformationMag = max(abs(real(deformation.ux)).^2+abs(real(deformation.uy)).^2+abs(real(deformation.uz)).^2,[],'all');
                    end
                end
                
                if(sqrt(MaxDeformationMag) > eps())
                    sF = min(bbox(:,2) - bbox(:,1)) / (sqrt(MaxDeformationMag)); % Based on lowest bounding box dimension
                else
                    sF = 0;
                end
        end
    end
    
    methods(Static = true)
        % Helpers for verifying type and properties match
        function tf = verifyMeshAndNodalDataMatch(mesh,nodaldata)
            tf = ~isempty(nodaldata) && (size(mesh.Nodes,2) == size(nodaldata,1));
        end
        
        function tf = verifyMeshAndDeformationDataNodalMatch(mesh,defdata)
            if ~isempty(defdata)
                if isnumeric(defdata)
                    szdef = size(defdata,1);
                else
                    szdef = size(defdata.ux,1);
                end
                
                % does it match in number of nodes
                tf = (size(mesh.Nodes,2) == szdef);
            else
                % If deformation data is empty no need to match
                tf = true;
            end
        end
        
         function tf = verifyMeshAndDeformationDataDimensionMatch(mesh,defdata)
            if ~isempty(defdata)
                if isnumeric(defdata)
                    dsize = size(defdata,2);
                else
                    try 
                        if isempty(defdata.uz)
                            dsize = 2;
                        else
                            dsize = 3;
                        end
                    catch
                        dsize = 2;
                    end
                end
                
                % does it match 2D/3D
                tf = (size(mesh.Nodes,1) == dsize);                
            else
                % If deformation data is empty no need to match
                tf = true;
            end
        end
        
        function tf = mustBeNumericOrFEStructLike(newdefdata)
            tf = (isnumeric(newdefdata) && ismatrix(newdefdata)) || ...
                  isa(newdefdata,'FEStruct') || ...
                 (isstruct(newdefdata) && isfield(newdefdata,'ux') && isfield(newdefdata,'uy'));
        end
        
        % Helper for making sure NV pairs are all correct before creating
        % object
        function DS = verifyOptions(options)
            arguments
                % main properties
                options.MeshData (:,1) pde.FEMesh = pde.FEMesh.empty
                options.NodalData (:,1) double = []
                options.DeformationData {pde.graphics.PDEVisualization.mustBeNumericOrFEStructLike(options.DeformationData)} = []
                options.DeformationScaleFactor (1,1) double {mustBeNonnegative} = 0
                options.MeshVisible (1,1) matlab.lang.OnOffSwitchState = matlab.lang.OnOffSwitchState.off
                options.Transparency (1,1) double {mustBeNonnegative,mustBeLessThanOrEqual(options.Transparency,1)} = 1
                % other properties - only have partial checks for datatypes
                options.XLabel (1,1) string
                options.YLabel (1,1) string
                options.ZLabel (1,1) string
                options.Title (1,1) string
                options.XLimits (1,2) double
                options.YLimits (1,2) double
                options.ZLimits (1,2) double
                options.ColorLimits (1,2) double
                options.ColorbarVisible (1,1) matlab.lang.OnOffSwitchState = matlab.lang.OnOffSwitchState.on
                options.Colormap 
                options.View (1,2) double
                options.Parent matlab.graphics.Graphics
                options.HandleVisibility (1,1) matlab.lang.OnOffSwitchState = matlab.lang.OnOffSwitchState.on
                options.InnerPosition (1,4) double
                options.OuterPosition (1,4) double
                options.Position (1,4) double
                options.Units 
                options.Layout 
                options.Visible (1,1) matlab.lang.OnOffSwitchState = matlab.lang.OnOffSwitchState.on
                options.AxesVisible (1,1) matlab.lang.OnOffSwitchState = matlab.lang.OnOffSwitchState.on
                options.AxesColor (1,3) double
            end
            DS = options;
        end
    end 
end
