classdef referenceSphere < map.geodesy.Sphere
%

% Copyright 2011-2023 The MathWorks, Inc.

%#codegen

%   Seven read-only properties are provided to ensure that reference sphere
%   objects can be used interchangeably with reference ellipsoid objects in
%   most contexts. These include: SemimajorAxis, SemiminorAxis,
%   InverseFlattening, Eccentricity, Flattening, ThirdFlattening,
%   MeanRadius. These properties are omitted when an object is displayed on
%   the command line. An additional two read-only properties, SurfaceArea
%   and Volume, are also omitted, because their values are only needed in
%   certain cases.
    
    properties
        Name = 'Unit Sphere';
    end
    
    properties (Dependent = true)
        LengthUnit
    end
    
    properties (Access = private, Hidden = true)
        pLengthUnit = '';  % Stores value of LengthUnit
    end
    
    %--------------------------- Constructor ------------------------------

    methods
        function obj = referenceSphere(name, lengthUnit)
            if nargin > 0
                
                % Ensure that NAME is a string or character vector.
                validateattributes(name,{'char','string'}, ...
                    {'nonempty','scalartext'},'referenceSphere','NAME',1)
                
                % Make 'unitsphere' equivalent to 'Unit Sphere'.
                if strncmpi(name,'unitsphere',length(name))
                    name = 'Unit Sphere';
                end
                
                % Names and radii in meters
                spheres = { ...
                    'Unit Sphere',    1; ...
                    'Earth',   6371000; ...
                    'Sun',     6.9446e+08; ...
                    'Moon',    1738000; ...
                    'Mercury', 2439000; ...
                    'Venus',   6051000; ...
                    'Mars',    3.39e+06; ...
                    'Jupiter', 6.9882e+07; ...
                    'Saturn',  5.8235e+07; ...
                    'Uranus',  2.5362e+07; ...
                    'Neptune', 2.4622e+07; ...
                    'Pluto',   1151000 ...
                    };
                
                validNames = spheres(:,1)';
                
                name = validatestring(name, validNames, ...
                    'referenceSphere', 'NAME', 1);
 
                obj.Name = name;
                obj.Radius = spheres{strcmp(name, validNames), 2};
                
                % Set LengthUnit to 'meter', except for the unit sphere.
                if ~strcmp(obj.Name, 'Unit Sphere')
                    obj.pLengthUnit = 'meter';
                end
                
                if nargin > 1
                    obj.LengthUnit = validateLengthUnit(lengthUnit);
                end
            end
        end
    end
    
    %--------------------------- Get method ------------------------------
    
    methods
        
        function lengthUnit = get.LengthUnit(obj)
            lengthUnit = obj.pLengthUnit;
        end
    end
    
    %---------------------------- Set methods -----------------------------
    
    methods
        function obj = set.Name(obj, name)
            % Accept any valid name, including empty.
            if ~isempty(name)
                validateattributes(name, {'char','string'}, {'scalartext'}, '', 'Name')
            else
                validateattributes(name, {'char','string'}, {}, '', 'Name')
            end
            obj.Name = name;
        end
        
        
        function obj = set.LengthUnit(obj, unit)
            % If the length unit is not yet designated, validate the input
            % and assign it. Otherwise rescale the radius, then make
            % the assignment.
            if isempty(unit)
                % It would be unusual to change LengthUnit to empty, but
                % there's no reason to disallow it. Ensure an empty char,
                % vs. empty of some class other than char.
                obj.pLengthUnit = '';
            else
                unit = validateLengthUnit(unit);
                if ~isempty(obj.pLengthUnit)
                    ratio = unitsratio(unit, obj.pLengthUnit);
                    obj.a = ratio * obj.a;
                end
                obj.pLengthUnit = unit;
            end
        end
    end
end
