classdef ClutterRegionPlotter < fusion.theaterPlot.TheaterPlotter
    %ClutterRegionPlotter Create a new clutter region plotter
    %
    %   See:  <a href="matlab:help theaterPlot/clutterRegionPlotter">theaterPlot/clutterRegionPlotter</a>

    %   Copyright 2022-2023 The MathWorks, Inc.

    properties (Dependent)
        %RegionFaceColor    Region fill color
        % The face color of the plotted regions, specified as a "color"
        % string or an [R, G, B] vector defining a color.
        %
        % Default: [0.1757, 0.8235, 0.1757]
        RegionFaceColor

        %RegionFaceAlpha    Region fill transparency
        % The face alpha value of the plotted regions, specified as a
        % scalar. The same alpha value is used for all regions.
        %
        % Default: 1
        RegionFaceAlpha

        %RegionEdgeColor    Region outline color
        % The edge color of the plotted regions, specified as a "color"
        % string or an [R, G, B] vector defining a color
        %
        % Default: 'black'
        RegionEdgeColor
        
        %RegionEdgeWidth    Region outline width
        % The edge width of the plotted regions, specified as a scalar.
        %
        % Default: 0.5
        RegionEdgeWidth

        %RegionEdgeAlpha    Region outline transparency
        % The edge alpha value of the plotted regions, specified as a
        % scalar. The same alpha value is used for all regions.
        %
        % Default: 1
        RegionEdgeAlpha

        %PatchMarker    Patch marker symbol
        % The marker symbol to use for patches.  It can be one of the
        % following values:
        %       o   circle   s  square       ^ triangle (up)
        %       x   x-mark   d  diamond      v triangle (down)
        %       +   plus     p  pentagram    < triangle (left)
        %       *   star     h  hexagram     > triangle (right)
        %       .   dot (default)
        PatchMarker

        %PatchMarkerFaceColor    Patch marker fill color
        % The patch marker fill color. This can be a
        % "color" string or an [R, G, B] vector defining
        % a color.
        %
        % Default: 'none'
        PatchMarkerFaceColor

        %PatchMarkerEdgeColor    Patch marker outline color
        % The patch marker edge color. This can be a "color" string or an
        % [R, G, B] vector defining a color.
        %
        % Default: 'blue'
        PatchMarkerEdgeColor

        %PatchMarkerSize    Patch marker size
        % A positive integer specifying the size of the patch marker.
        %
        % Default: 3
        PatchMarkerSize
    end

    properties(SetAccess=protected)
        %ShowPatchCenters    Show patch centers
        % A scalar logical that specifies if the clutter patch centers
        % should be plotted along with the clutter regions.
        %
        % Default: false
        ShowPatchCenters
    end

    properties
        %MaxPatches    Max patches to show
        % A scalar double that specifies the maximum number of clutter
        % patch centers to plot.
        %
        % Default: 1e2
        MaxPatches
    end

    properties(Access=private)
        Patch
        Line
    end

    methods
        function obj = ClutterRegionPlotter(tp, varargin)
            obj@fusion.theaterPlot.TheaterPlotter(tp, varargin{:});
        end

        function plotClutterRegion(obj, plotdata)
            validateattributes(plotdata,{'struct'},{},'ClutterRegionPlotter','plotdata');
            obj.validatePlotData(plotdata,obj.ShowPatchCenters)

            drawRegions(obj, plotdata);
            drawnow limitrate
        end

        function clearData(obj)
            %clearData remove all data from a plotter
            %   clearData(trajPlotter) removes all trajectories associated with the
            %   plotter, trajPlotter.
            drawRegions(obj, []);
            drawnow limitrate
        end

        function value = get.RegionFaceColor(obj)
            hPatch = obj.Patch;
            value = hPatch.FaceColor;
        end

        function value = get.RegionFaceAlpha(obj)
            hPatch = obj.Patch;
            value = hPatch.FaceAlpha;
        end

        function value = get.RegionEdgeColor(obj)
            hPatch = obj.Patch;
            value = hPatch.EdgeColor;
        end
        
        function value = get.RegionEdgeWidth(obj)
            hPatch = obj.Patch;
            value = hPatch.LineWidth;
        end

        function value = get.RegionEdgeAlpha(obj)
            hPatch = obj.Patch;
            value = hPatch.EdgeAlpha;
        end

        function value = get.PatchMarker(obj)
            hLine = obj.Line;
            value = hLine.Marker;
        end

        function value = get.PatchMarkerFaceColor(obj)
            hLine = obj.Line;
            value = hLine.MarkerFaceColor;
        end

        function value = get.PatchMarkerEdgeColor(obj)
            hLine = obj.Line;
            value = hLine.MarkerEdgeColor;
        end

        function value = get.PatchMarkerSize(obj)
            hLine = obj.Line;
            value = hLine.MarkerSize;
        end

        function set.RegionFaceColor(obj,value)
            hPatch = obj.Patch;
            if ishghandle(hPatch)
                hPatch.FaceColor = value;
            end
            drawnow limitrate
        end

        function set.RegionFaceAlpha(obj,value)
            hPatch = obj.Patch;
            if ishghandle(hPatch)
                hPatch.FaceAlpha = value;
            end
            drawnow limitrate
        end

        function set.RegionEdgeColor(obj,value)
            hPatch = obj.Patch;
            if ishghandle(hPatch)
                hPatch.EdgeColor = value;
            end
            drawnow limitrate
        end
        
        function set.RegionEdgeWidth(obj,value)
            hPatch = obj.Patch;
            if ishghandle(hPatch)
                hPatch.LineWidth = value;
            end
            drawnow limitrate
        end

        function set.RegionEdgeAlpha(obj,value)
            hPatch = obj.Patch;
            if ishghandle(hPatch)
                hPatch.EdgeAlpha = value;
            end
            drawnow limitrate
        end

        function set.PatchMarker(obj,value)
            hLine = obj.Line;
            if ishghandle(hLine)
                hLine.Marker = value;
            end
            drawnow limitrate
        end

        function set.PatchMarkerFaceColor(obj,value)
            hLine = obj.Line;
            if ishghandle(hLine)
                hLine.MarkerFaceColor = value;
            end
            drawnow limitrate
        end

        function set.PatchMarkerEdgeColor(obj,value)
            hLine = obj.Line;
            if ishghandle(hLine)
                hLine.MarkerEdgeColor = value;
            end
            drawnow limitrate
        end

        function set.PatchMarkerSize(obj,value)
            hLine = obj.Line;
            if ishghandle(hLine)
                hLine.MarkerSize = value;
            end
            drawnow limitrate
        end

    end

    methods (Access=protected)
        function initParser(obj, p)
            initParser@fusion.theaterPlot.TheaterPlotter(obj, p);
            addParameter(p,'RegionFaceColor',[0.1757, 0.8235, 0.1757])
            addParameter(p,'RegionFaceAlpha',1)
            addParameter(p,'RegionEdgeColor','black')
            addParameter(p,'RegionEdgeWidth',0.5)
            addParameter(p,'RegionEdgeAlpha',1)
            addParameter(p,'PatchMarker','.');
            addParameter(p,'PatchMarkerFaceColor','none')
            addParameter(p,'PatchMarkerEdgeColor','blue')
            addParameter(p,'PatchMarkerSize',3)
            addParameter(p,'ShowPatchCenters',false)
            addParameter(p,'MaxPatches',1e3)
        end

        function value = getPrimaryObject(obj)
            value = obj.Patch;
        end

        function createGraphics(obj, hAxes, p)

            pr = p.Results;
            
            % Configuration options
            obj.ShowPatchCenters = pr.ShowPatchCenters;
            obj.MaxPatches = pr.MaxPatches;

            hPatch = patch(hAxes,nan,nan,nan,...
                'FaceColor',pr.RegionFaceColor,...
                'FaceAlpha',pr.RegionFaceAlpha,...
                'EdgeColor',pr.RegionEdgeColor,...
                'LineWidth',pr.RegionEdgeWidth,...
                'EdgeAlpha',pr.RegionEdgeAlpha);
            
            if isempty(pr.DisplayName)
                hPatch.DisplayName = '';
                hPatch.Tag = 'tpClutterRegions_';
                hPatch.HandleVisibility = 'off';
            else
                hPatch.DisplayName = pr.DisplayName;
                hPatch.Tag = ['tpClutterRegions_' pr.DisplayName];
            end
            obj.Patch = hPatch;

            hLine = line(hAxes,nan,nan,nan,'linestyle','none',...
                'Marker',pr.PatchMarker,...
                'MarkerFaceColor',pr.PatchMarkerFaceColor,...
                'MarkerEdgeColor',pr.PatchMarkerEdgeColor,...
                'MarkerSize',pr.PatchMarkerSize);

            % apply theme defaults when using defaults
            pu = p.UsingDefaults;
            if ismember('RegionEdgeColor',pu)
                matlab.graphics.internal.themes.specifyThemePropertyMappings( ...
                    hPatch,'EdgeColor','--mw-graphics-borderColor-axes-primary');
            end

            if ismember('PatchMarkerEdgeColor',pu)
                matlab.graphics.internal.themes.specifyThemePropertyMappings( ...
                    hLine,'MarkerEdgeColor','--mw-graphics-colorSpace-rgb-blue');
            end

            if isempty(pr.DisplayName)
                hLine.Tag = 'tpClutterPatches_';
            else
                hLine.Tag = ['tpClutterPatches_' pr.DisplayName];
            end
            if obj.ShowPatchCenters
                hLine.DisplayName = '(patch centers)';
                hLine.HandleVisibility = 'on';
            else
                hLine.HandleVisibility = 'off';
            end
            obj.Line = hLine;

        end

        function deleteGraphics(obj)
            delete(obj.Patch)
            delete(obj.Line)
        end
    end

    methods (Access=private)
        function drawRegions(obj,pd)
            if isempty(pd)
                % Clear data
                hPatch = obj.Patch;
                if ishghandle(hPatch)
                    set(hPatch,'XData',[],'YData',[],'ZData',[])
                end
                hLine = obj.Line;
                if ishghandle(hLine)
                    set(hLine,'XData',[],'YData',[],'ZData',[])
                end
            else
                hPatch = obj.Patch;
                if ishghandle(hPatch)
                    set(hPatch,'XData',pd.X,'YData',pd.Y,'ZData',pd.RegionPlotHeight*ones(size(pd.X)))
                end
                if obj.ShowPatchCenters
                    n = size(pd.PatchCenters,2);
                    if n == 0
                        return
                    elseif n > obj.MaxPatches
                        I = interp1(1:n,1:n,linspace(1,n,obj.MaxPatches),'nearest');
                    else
                        I = 1:n;
                    end
                    hLine = obj.Line;
                    if ishghandle(hLine)
                        set(hLine,'XData',pd.PatchCenters(1,I),'YData',pd.PatchCenters(2,I),'ZData',pd.PatchCenters(3,I))
                    end
                end
            end
        end
    end

    methods(Access=private, Static)

        function validatePlotData(pd,showpatches)
            % Check for all required fields
            if ~isfield(pd,'X') || ~isfield(pd,'Y') || ~isfield(pd,'RegionPlotHeight') ...
                    || (showpatches && ~isfield(pd,'PatchCenters'))
                if showpatches
                    error(message('shared_radarfusion:theaterPlot:ClutterRegPlotterDataWrongFieldsHasPatches'))
                else
                    error(message('shared_radarfusion:theaterPlot:ClutterRegPlotterDataWrongFieldsNoPatches'))
                end
            end

            % Check size consistency with X/Y
            if ~ismatrix(pd.X) || ~ismatrix(pd.Y) || ~isequal(size(pd.X),size(pd.Y))
                error(message('shared_radarfusion:theaterPlot:ClutterRegPlotterDataWrongRegSizes'))
            end

            % Check size of RegionPlotHeight
            if ~isscalar(pd.RegionPlotHeight)
                error(message('shared_radarfusion:theaterPlot:ClutterRegPlotterDataWrongPlotHeightSize'))
            end

            % Check size of PatchCenters if applicable
            if showpatches && ~isempty(pd.PatchCenters)
                if ~ismatrix(pd.PatchCenters) || size(pd.PatchCenters,1) ~= 3
                    error(message('shared_radarfusion:theaterPlot:ClutterRegPlotterDataWrongPatchCentersSize'))
                end
            end
        end

    end

end

% LocalWords:  plotdata traj tp linestyle mw
