classdef Rectangle < shape.Shape2D
%SHAPE.RECTANGLE Creates a rectangle centered at the origin on the X-Y plane
% 
%   h = shape.Rectangle returns a rectangle shape on the X-Y plane
%   centered at the origin.
%
%   h = shape.Rectangle(Name1=Value1,...,NameN=ValueN) creates a rectangle shape 
%   with specified properties. Name is the property name and 
%   Value is the corresponding value. Properties that you do 
%   not specify retain their default values.
%
%   Rectangle properties:
%
%   Name         - Name of the rectangle shape. The default name is
%                  myrectangle
%   Center       - Cartesian coordinates of the center of the rectangle in
%                  units of meters specified as a 2-element vector. The
%                  default vale is [0 0].
%   Length       - Length of the rectangle shape in meters. The default
%                  value is 1.
%   Width        - Width of the rectangle shape in meters. The default value
%                  is 2.
%   NumPoints    - Number of discretization points per side. The default
%                  value is 2.
%   Metal       - Metal assigned for the shape. The default object is
%                 'PEC' with infinite conductivity and zero
%                 thickness.
%   Color        - Face Color of the shape. The default value is 'y'.
%   Transparency - Transparency of the shape. The default value is 1.
%   EdgeColor    - Edge Color of the shape. The default value is 'k'.
%
%  Rectangle methods:
%
%   add           - Boolean unite operation on two shapes
%   subtract      - Boolean subtraction operation on two shapes
%   intersect     - Boolean intersection operation on two shapes
%   plus          - r1 + r2, boolean unite, equivalent to add
%   minus         - r1 - r2, boolean subtraction, equivalent to subtract
%   and           - r1&r2, boolean intersection, equivalent to intersect
%   area          - Area of shape in units of sq.m
%   show          - Visualize the shape as a filled patch
%   plot          - Visualize the shape boundary
%   mesh          - Compute/visualize the mesh of the shape
%   rotate        - Rotate the shape about an axis and an angle
%   rotateX       - Rotate the shape about X-axis with an angle
%   rotateY       - Rotate the shape about Y-axis with an angle
%   rotateZ       - Rotate the shape about Z-axis with an angle
%   translate     - Move the shape to a new location
%   scale         - Scale the size of the shape
%   imprintShape  - Imprint a 2D shape onto a custom 2D or 3D shape
%   createHole    - Create a 2D hole on the custom 2D or 3D shape
%   extrude       - Extrude a 2D shape on custom shape
%   extrudeLinear - Extrude a 2D shape linearly
%   extrudeRotate - Extrude a 2D shape by rotation
%   removeFaces   - Remove the selected faces of shape interactively
%
%
%   % Examples
%
%   % Example 1: 
%   % Create a rectangle shape, rotate it by 45 degrees about
%   % the z-axis and mesh it at a wavelength of 1 m
%   
%   r = shape.Rectangle;
%   r = rotateZ(r,45);
%   mesh(r,1)
%
%   % Example 2: 
%   % Create a 2 cm x 2 cm rectangle shape,and mesh it with a maximum
%   % edge length of 5 mm
%
%   r = shape.Rectangle('Length',.02,'Width',.02);
%   mesh(r,'MaxEdgeLength',5e-3)
%
%   See also shape.Circle, shape.Polygon
    
%   Copyright 2022-2023 The MathWorks, Inc.
    
    properties
        % Name of the rectangle shape specified as a character array
        Name
        % Cartesian coordinates of the center of the rectangle specified
        % as a 2-element vector (meter).
        Center
        % Length of the rectangle (meter).
        Length
        % Width of the rectangle (meter).
        Width
        % Number of discretization points for each side of rectangle
        NumPoints
    end
    
    properties(Hidden)
        PointDistribution         
    end
    
    methods
        function obj = Rectangle(varargin)
            parserObj = inputParser;
            addParameter(parserObj,'Name','myrectangle');
            addParameter(parserObj,'Length',1);
            addParameter(parserObj,'Width',2);
            addParameter(parserObj,'Center',[0,0]);
            addParameter(parserObj,'NumPoints',2);
            addParameter(parserObj,'Metal','PEC');
            addParameter(parserObj,'Color','y');
            addParameter(parserObj,'Transparency',1);
            addParameter(parserObj,'EdgeColor','k');
            parse(parserObj,varargin{:});
            p = [-0.5 -1 0;0.5 -1 0;0.5 1 0;-0.5 1 0]';
            obj = obj@shape.Shape2D(p');
            obj.Name      = parserObj.Results.Name;
            obj.Length    = parserObj.Results.Length;
            obj.Width     = parserObj.Results.Width;
            obj.Center    = parserObj.Results.Center;
            obj.NumPoints = parserObj.Results.NumPoints;
            obj.Metal = parserObj.Results.Metal;
            obj.Color = parserObj.Results.Color;
            obj.Transparency = parserObj.Results.Transparency;
            obj.EdgeColor = parserObj.Results.EdgeColor;

        end
        
    end
    
    
    methods
        function set.Name(obj,propVal)
            validateattributes(propVal,{'char','string'},{'nonempty',     ...
                },class(obj),'Name') ;
            if isPropertyChanged(obj,obj.Name,propVal)
                obj.Name = propVal;
            end
        end
        
        function set.Length(obj,propVal)
            validateattributes(propVal,{'double'},{'nonempty','scalar', 'real',     ...
                'nonnan','finite','positive'},class(obj),'Length') ;
            if isPropertyChanged(obj,obj.Length,propVal)
                obj.Length = propVal;
            end
        end
        
        function set.Width(obj,propVal)
            validateattributes(propVal,{'double'},{'nonempty','scalar', 'real',     ...
                'nonnan','finite','positive'},class(obj),'Width') ;
            if isPropertyChanged(obj,obj.Width,propVal)
                obj.Width = propVal;
            end
        end
        
        function set.Center(obj,propVal)
            validateattributes(propVal,{'double'},{'nonempty', 'real',     ...
                'nonnan','finite','numel',2},class(obj),'Center');
            if isPropertyChanged(obj,obj.Center,propVal)
                if ~isrow(propVal)
                    propVal = propVal';
                end
                obj.Center = propVal;
            end
        end
        
        function set.NumPoints(obj,propVal)
           if isscalar(propVal)
                validateattributes(propVal,{'numeric'},{'nonempty','vector',...
                    'nonnan','finite','real','integer','positive','>',1},class(obj),'NumPoints');
            else
                validateattributes(propVal,{'numeric'},{'nonempty','vector',...
                    'nonnan','finite','real','integer','positive','numel',4,'>',1},class(obj),'NumPoints');
                if numel(propVal)==4
                    if~(propVal(1)==propVal(3))||~(propVal(2)==propVal(4))
                        error(message('antenna:antennaerrors:InvalidNumPoints'));
                    end
                end
            end
            
            if isPropertyChanged(obj,obj.NumPoints,propVal)
                obj.NumPoints = propVal;
            end
        end
        
    end
    
    methods(Hidden)
        function createGeometry(obj)
            % Generate Rectangle Points
            p = shape.generateRectanglePoints(obj.Center,obj.Length,...
                obj.Width,obj.NumPoints);
            % Get the rounding decimal for the shape
            [~]=em.internal.authoring.getMultiplier(obj,[obj.Length,obj.Width,obj.Center],1);
            p = orientGeom(obj,p);
            updateShape(obj,p');
            obj.MesherStruct.Geometry.BorderVertices = p';
           
            % If thickness is present,modify geometry
            if (obj.Thickness)>0
                tr = triangulation(obj.InternalPolyShape);
                tr = triangulation(tr.ConnectivityList,p');
                tr = em.internal.authoring.thicken(tr,obj.Thickness);
                obj.Points = tr.Points; obj.Triangles = tr.ConnectivityList;
                be = {featureEdges(tr,pi/2)};
                geom = getGeometry(obj);
                % Save geometry
                saveGeometry(obj,obj.Points,{obj.Triangles}, ...
                    geom.MaxFeatureSize,...
                    be);
            end
            resetHasStructureChanged(obj);
           
        end
        
        function rObj = superLoad(obj,s)
            if nargin>1
                obj.Name            = s.Name;
                obj.Length          = s.Length;
                obj.Width           = s.Width;
                obj.Center          = s.Center;
                obj.NumPoints       = s.NumPoints;
                rObj = superLoadShape(obj,s);
            end            
        end
    end
    
    methods(Access=protected)
        function group = getPropertyGroups(obj) %#ok<MANU>
            title = '';
            propertyList = {'Name'; 'Center'; 'Length';'Width';...
                'NumPoints';...
                  % 'Material';...
                  'Metal';...
               'Color';'Transparency';'EdgeColor'};
            group = matlab.mixin.util.PropertyGroup(propertyList,title);
        end        
        function updateShapeDimension(obj, scalingFactor)
           tmpValue = [obj.Length obj.Width].*scalingFactor;
           obj.Length = tmpValue(1);
           obj.Width = tmpValue(2);
        end
    end
    
    methods (Static = true,Hidden) % ----LOADOBJ only IMPLEMENTATION ---%
        function r = loadobj(obj)
            if isobject(obj)&& isObjectFromCurrentVersion(obj)
                r = obj;
            else
                % Create default microstrip patch
                newrectangle = shape.Rectangle;
                % Populate the properties
                r = superLoad(newrectangle,obj);
            end
            r = loadobj@shape.Shape2D(r);
        end        
    end    
end
