Cone

This class is a child of PrimitiveShape.

Contents

classdef Cone < PrimitiveShape
    %This Class defines the Cone object. This is a subclass of Primitive
    %Shape and defines the geometric properties for a cone.
    %
    %   URL : $URL: $
    %   Log : $Id: Cone.html,v 1.1 2008/07/23 12:51:19 jberg Exp $
    %   Copyright (c) 2008 The MathWorks, Inc.

Class Properties

    properties ( SetAccess = 'public', GetAccess = 'public' )
        base_radius = 0.5;                    % (pos def double)
        top_radius = 0;                     % (pos semidef double) x and y-axes
        height = 1;                         % (pos def double) z-axis
    end
    properties ( Dependent = true )
        moment_of_inertia_about_CG;     % (3x3 double)
        volume;                         % (pos def double)
    end
    properties ( SetAccess = 'private', GetAccess = 'public', Constant = true )
        % The order of dimension_order needs to be the same as that
        % expected by org.j3d.geom.ConeGenerator.setDimensions()
        %	setDimensions(float height, float radius, boolean hasBottom)
        dimension_order = {'height','base_radius'};
    end
    properties ( SetAccess = 'private', GetAccess = 'private', Constant = true )
        PROPERTY_LIST = {
            'base_radius'   %
            'coord_system'  % From parent class Shape
            'height'        %
            'tempProp'
            'material'      % From parent class PrimitiveShape
            'name'          % From parent class Shape
            'orientation'   % From parent class Shape
            'origin'        % From parent class Shape
            'top_radius'    %
            };
    end
    methods

Constructor

        function obj = Cone(varargin)
            if(mod(nargin,2)~=0)
                error('Expecting inputs as property name-value pairs.')
            end

            prop_list = eval([mfilename '.PROPERTY_LIST']);
            n_props = length(prop_list);
            error(nargchk(0, 2*n_props, nargin,'string'));

            % Check to see if any input arguments are CoordSystem objects.  If
            % so, then this object is being created from another similar object
            % and there is no need to create the Origin and/or CG CoordSystems.
            if ~nargin || ~strmatch('coord_system',varargin(1:2:end),'exact')
                obj.add_coord_system; % Add Origin CS
            end

			% Child-specific default
			obj.name = 'New Cone';

			% Property Name-Value pair matching
			for ii=1:2:nargin
				prop    = varargin{ii};
				val     = varargin{ii+1};
				idx     = strmatch(lower(prop),lower(prop_list),'exact');
				if isempty(idx)
					error('%s: This property is unknown',...
						'or cannot be set during the construction',...
						'of the object: %s ',prop,mfilename);
				else
					obj.(prop_list{idx}) = val;
				end
			end
			% Create default CoordSystems specific to this Primitive. These are
			% not editable and are wrt the Origin of this Shape.
			% CG
            if obj.n_coord_system < 2
                csTmp = CoordSystem('name','CG',...
                    'is_deletable',false,...
                    'is_fixed',true,...
                    'origin',[0 -obj.height/6 0],...
                    'parent_shape',obj);
                csTmp.reference_CS = obj.coord_system{1};
                obj.add_coord_system(csTmp);
            end

			obj.attach_generator();
			obj.attach_primitive();

			%             % Move the CG to where it belongs (Java3D places it at the midpoint
			%             % between the base and the tip).
			%             cur_origin      = obj.coord_system{1}.origin;
			%             cur_origin(2)   = cur_origin(2) - 1/6*obj.height;
			%             obj.coord_system{1}.origin= cur_origin;
        end

SET Methods

        function set.base_radius(obj, in)
            prop_name = 'base_radius';
            prop_type = 'double';
            [valid_flag in] = Validate.SCALAR(in,'type',prop_type,'minVal',eps);
            if valid_flag
                obj.(prop_name) = in;
            end
        end
        function set.height(obj, in)
			prop_name = 'height';
			prop_type = 'double';
			[valid_flag in] = Validate.SCALAR(in,'type',prop_type,'minVal',eps);
			if valid_flag
				obj.(prop_name) = in;
                if obj.n_coord_system > 1
                    obj.update_CG();
                end
			end
		end
        function set.top_radius(obj, in)
            prop_name = 'top_radius';
            prop_type = 'double';
            [valid_flag in] = Validate.SCALAR(in,'type',prop_type,'minVal',0);
            if valid_flag
                obj.(prop_name) = in;
            end
        end

GET Methods

        function vol = get.volume(obj)
            %volume = pi*h/3(R^2+Rr+r^2)
            vol = (pi*obj.height/3)*(obj.base_radius^2 + obj.base_radius*obj.top_radius + obj.top_radius^2);
        end

        function inertia_tensor = get.moment_of_inertia_about_CG(obj)
            density = obj.material.density;
            base_rad = obj.base_radius;
            top_rad = obj.top_radius;
            h = obj.height;
            % if it is a full cone and not a frustum
            if(base_rad == 0 || top_rad == 0)
                if (base_rad == 0)
                    R = top_rad;
                else
                    R = base_rad;
                end
                if (R == 0)
                    warndlg('Both the top radius and base radius of the cone are zero.');
                end
                mi = Cone.MI_CG_FullCone(density,R,h);
                inertia_tensor = [mi.xx 0 0;0 mi.yy 0;0 0 mi.zz];
                return;
            end

            x = top_rad/base_rad;
            y = x^2 + x + 1;
            z = (x^2 + 2*x + 3)/(4*y);

            if (top_rad > base_rad)
                R1 = top_rad;
                R2 = base_rad;
                CG_from_base_center = z*h;
            elseif (top_rad < base_rad)
                R1 = base_rad;
                R2 = top_rad;
                CG_from_base_center = (1-z)*h;
            else
                warndlg('You have given both the radii to be same. Please use cylindrical primitive instead');
                R1 = base_rad;
                R2 = R1- R1*eps;
                CG_from_base_center = (1-z)*h;
            end

            a = h*R2/(R1-R2); % top cone height
            mi_topcone = Cone.MI_CG_FullCone(density,R2,a);
            mi_basecone = Cone.MI_CG_FullCone(density,R1,h+a);

            Ixx = (mi_basecone.xx + mi_basecone.mass*((h+a)/4 - CG_from_base_center)^2) - (mi_topcone.xx + mi_topcone.mass*(h+(a/4)-CG_from_base_center)^2);
            Izz = Ixx;
            Iyy = mi_basecone.yy - mi_topcone.yy;

            inertia_tensor = [Ixx 0 0;0 Iyy 0;0 0 Izz];
        end
    end
	methods ( Access = 'public')

Public HELPER Methods

        function attach_primitive(obj)
            r = obj.base_radius;
            h = obj.height;

            the_appearance = obj.material.appearance;
            p = org.j3d.renderer.java3d.geom.Cone(h, r, the_appearance);

            p.setName(mfilename);

            % Store primitive for future modifications as necessary.
            obj.primitive = p;

            obj.attach_primitive_common(p);
            % 			obj.attach_primitive_common(com.sun.j3d.utils.geometry.Cone(r, h, the_appearance));
            % Used to be obj.attach_primitive@PrimitiveShape(...), but resulted
            % in top down calling sequence, which we don't want.
        end
        function attach_generator(obj)
            % This needs to be a protected method to match the Access level of
            % the parent's method of the same name.
            obj.generator = org.j3d.geom.ConeGenerator();
        end
	end
    methods ( Static = true )

LOADOBJ Method

        function B = loadobj(A)
            % We use loadobj so that when a stored object is loaded, we can
            % perform necessary steps that are contained in the constructor. We
            % have to do this because the constructor is not executed when an
            % object is loaded.
            Log.msg(sprintf('\n%s::%s',mfilename,'loadobj (Entering)'));
            prop_list = eval([mfilename '.PROPERTY_LIST']);

            % Construct object using the stored properties
            storedFields = fieldnames(A);
            args = cell(0);
            for ii=1:length(storedFields)
                prop = storedFields{ii};
                idx     = strmatch(lower(prop),lower(prop_list),'exact');
                if ~isempty(idx)
                    args{end+1} = prop; %#ok<AGROW>
                    args{end+1} = A.(storedFields{ii}); %#ok<AGROW>
                end
            end
            B = Cone(args{:});
            Log.msg(sprintf('%s::%s',mfilename,'loadobj (Exiting)'));
        end
    end
	methods ( Access = 'private')

Private HELPER Methods

		function update_CG(obj)
			% Whenever the Cone height changes, you need to update the CG.
			obj.coord_system{2}.origin = [0 -obj.height/6 0];
		end
	end

    methods ( Access = 'private', Static = true )

Static Private HELPER Methods

        function mi = MI_CG_FullCone(rho, r, h) %% assuming cone height is along y-dir
            % This MI calculation assumes full cone (not a frustum)
            M = rho*pi*r^2*h/3;
            mi.xx = 3/80*(M*h^2) + 3/20*(M*r^2);
            mi.yy = 3/10*(M*r^2);
            mi.zz = mi.xx;
            mi.mass = M;
        end
    end
end