ComplexShape

This class is a child of Shape.

Contents

classdef ComplexShape < Shape
    %This Class defines the Complex Shape object. Complex Shape is a
    %subclass of superclass Shape. These are custom shapes built by the user
    %in BodyBuilder and may consist of multiple primitive shapes.
    %
    %   URL : $URL: $
    %   Log : $Id: ComplexShape.html,v 1.1 2008/07/23 12:51:18 jberg Exp $
    %   Copyright (c) 2008 The MathWorks, Inc.

Class Properties

    properties ( Dependent = true )
        n_children;     % (int)
    end
    properties ( SetAccess = 'private', GetAccess = 'public' )
        children;               % ({<Complex/Primitive Shapes>})
    end
    properties ( SetAccess = 'private', GetAccess = 'private', Constant = true )
        PROPERTY_LIST = {
            'name'          % From parent class Shape
            };
    end

    methods

Constructor

        function obj = ComplexShape(varargin)
            prop_list = eval([mfilename '.PROPERTY_LIST']);
            n_props = length(prop_list);
			Log.msg(sprintf('\n%s::%s',mfilename,mfilename));
			obj.add_coord_system; % Add Origin CS
			if(mod(nargin,2)~=0)
				error('Expecting inputs as property name-value pairs.')
			end
			error(nargchk(0, 2*n_props, nargin,'string'));

			% Child-specific default
            obj.name = 'New Assembly';
			% 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
		end

Destructor

        function delete(obj)
%             disp(sprintf('%s:delete() %s',mfilename,obj.name));
        end

SET Methods

        function set.children(obj, in)
            prop_name = 'children';
            prop_type = 'Shape';
            [valid_flag in] = Validate.ARRAY(in,'type',prop_type,'Cell',true);
            if valid_flag
                obj.(prop_name) = in;
            end
        end

Public HELPER Methods

        function mass = mass(obj)
            % mass = Summation(mass_of_each_child)
            mass = 0;
            the_children = obj.children;
            for ii = 1:obj.n_children
                mass = mass + the_children{ii}.mass;
            end
        end
        function vol = volume(obj)
            % volume = Summation(volume_of_each_child)
            vol = 0;
            the_children = obj.children;
            for ii = 1:obj.n_children
                vol = vol + the_children{ii}.volume;
            end
        end

        function center_of_mass = center_of_mass(obj)
            % The coordinate values are calculated wrt to the
            % ref_CS which is passed argument.
            the_children = obj.children;
            origin = obj.coord_system{1};

            % Initialize the CG of this complex shape to be a duplicate of
            % the complex shape's origin. If there are no children, pass
            % this directly else calculate the new origin values.

            position = zeros(1,3);
            if(obj.n_children ~= 0)
                for ii = 1:obj.n_children
                    child_CM    = the_children{ii}.center_of_mass;
                    child_mass  = the_children{ii}.mass;
                    % Convert the child's CG wrt parent's origin
                    pos = child_CM.convert_coordinates_wrt_new_refCS(origin);
                    position = position + pos*child_mass;
                end
                % CM wrt to the selected complex shape's origin
                if (obj.mass == 0)
                    position = position/eps;
                else
                    position = position/obj.mass;
                end
            end
            CS_name = [obj.name '.CM'];
            center_of_mass = CoordSystem('name',CS_name,...
                'origin',position,...
                'orientation',[0 0 0],...
                'parent_shape',obj);
            center_of_mass.reference_CS = origin;
        end

        function inertia_tensor = moment_of_inertia_about_CG(obj)
            % Memory Note: I believe child_CG and CG CoordSystem objects
            % get deleted at the end of the function call. However it is
            % important to verify this as otherwise there will be lots of
            % these CoordSystems dangling somewhere in the ether.

            the_children = obj.children;
            % Initialize the inertia_tensor. If there are no children, just
            % return this tensor.
            inertia_tensor = zeros(3);
            if(obj.n_children == 0)
                return;
            end
            % For each child,
            % Step 1: Calculate the child's CG coords wrt my CG (selected
            % parent complex shape's CG (center of mass))
            % Step 2: Calculate the MI of the child shape wrto an axis sharing
            % the origin as its CG but orientation coinciding with the
            % parent axis (basically invert the angles and rotation
            % sequence would be Z-Y-X). Let us call this CS_int
            % Step 3: Use Parallel Axis Theorem and calculate MI wrt to the
            % CG of the parent complex shape
            % Step 4: Add this tensor to the MI of the complex shape
            CG = obj.center_of_mass;
            for ii = 1:obj.n_children
                % Step 1:
                child_CG = the_children{ii}.center_of_mass;
                [the_pos the_dir] = child_CG.convert_coordinates_wrt_new_refCS(CG);
                % Step 2:
                % Calculate the unit vectors along each of the X, Y and Z
                % directions of the CS_int wrt to the child CG coordsystem.
                % For this, first calculate the Transformation matrices
                % which would be Euler Z-Y-X to get back to CS_int from
                % child_CG and then apply them on each of the unit vectors
                % [1; 0; 0], [0; 1; 0] and [0; 0; 1].
                theta_x = the_dir(1)*pi/180;
                theta_y = the_dir(2)*pi/180;
                theta_z = the_dir(3)*pi/180;

                Rx = [1		0				0;...
                    0	cos(theta_x)	sin(theta_x);...
                    0	-sin(theta_x)	cos(theta_x)];

                Ry = [cos(theta_y)	0	-sin(theta_y);...
                    0				1		0;...
                    sin(theta_y)	0	cos(theta_y)];

                Rz = [cos(theta_z)	sin(theta_z)	0;...
                    -sin(theta_z)	cos(theta_z)	0;...
                    0					0			1];

                % Dir_Cosine_Matrix contains unit_vectors as columns.
                dir_cosine_mat = Rx*Ry*Rz;
                child_MI = the_children{ii}.moment_of_inertia_about_CG;
                MI_temp = dir_cosine_mat'*child_MI*dir_cosine_mat;
                % Step 3: Using parallel axis theorem.
                child_mass = the_children{ii}.mass;
                X = the_pos(1);
                Y = the_pos(2);
                Z = the_pos(3);
                MI(1,1) = MI_temp(1,1) + child_mass*(Y^2+Z^2);
                MI(1,2) = MI_temp(1,2) + child_mass*(X*Y);
                MI(1,3) = MI_temp(1,3) + child_mass*(X*Z);
                MI(2,1) = MI_temp(2,1) + child_mass*(X*Y);
                MI(2,2) = MI_temp(2,2) + child_mass*(X^2+Z^2);
                MI(2,3) = MI_temp(2,3) + child_mass*(Y*Z);
                MI(3,1) = MI_temp(3,1) + child_mass*(X*Z);
                MI(3,2) = MI_temp(3,2) + child_mass*(Y*Z);
                MI(3,3) = MI_temp(3,3) + child_mass*(X^2+Y^2);
                % Step 4:
                inertia_tensor = inertia_tensor + MI;
            end
        end
        function n = get.n_children(obj)
            n = length(obj.children);
        end

        function idx = retrieve_child_idx_from_name(obj, a_name)
            % Iterate through child vector to find one whos name matches
            % a_name

            % Construct cell array of child names by retrieving the names of
            % each child contained in this shape.
            the_children = obj.children;

            ch_names = cell(obj.n_children,1);
            for ii = 1:obj.n_children
                ch_names{ii} = the_children{ii}.name;
            end

            idx = strmatch(a_name,ch_names,'exact');

            if isempty(idx)
                warning('%s:%s Could not find a match',...
                    mfilename,'retrieve_child_from_name');
            end
        end
        function child = retrieve_child_from_name(obj, a_name)
            idx = retrieve_child_idx_from_name(obj, a_name);

            if isempty(idx)
                child = [];
            else
                child = obj.children{idx};
            end
        end
        function add_child(obj, a_child)
            % Add a child shape to vector children.
            if ~obj.n_children
                obj.children = cell(0);
            end

            a_name = a_child.name();
            % Check to see if the shape's name is available, else rename.

            % Construct cell array of child names by retrieving the names of
            % each child contained in this ComplexShape.
            ch_names = cell(obj.n_children,1);
            for ii = 1:obj.n_children
                ch_names{ii} = obj.children{ii}.name;
            end

            % Make sure there isn't already a child of the same exact name
            % contained in this ComplexShape.
            idx_exact = strmatch(a_name,ch_names,'exact');
            if (idx_exact)
                ii = 0;
                while true
                    ii = ii + 1;
                    good_name = sprintf('%s_%d',a_name,ii);
                    if isempty(strmatch(good_name,ch_names,'exact'))
                        break;
                    end
                end
            else
                good_name = a_name;
            end

            a_child.name = good_name;
            obj.children{end+1} = a_child;
        end
        function remove_child(obj, a_child)
            % Remove the given child shape from body.
            idx = retrieve_child_idx_from_name(obj, a_child.name);
            if ~isempty(idx)
                the_children = obj.children;
                the_children(idx) = [];
                obj.children = the_children;
            end
        end

        function change_name(obj, idx, new_name)
            obj.retrieve_child_from_idx(idx).name = new_name;
        end

        function dimension_info = make_dimension_info(obj)
            dimension_info = cell(0,2);
        end
        function [vertexInfo normalInfo] = get_vertex_info(obj)
            % Vertex info is returned to enable exporting to .stl document.
            n = obj.n_children;
            vertexInfo = cell(n,1);
            normalInfo = cell(n,1);
            for ii = 1:n
                the_child = obj.children{ii};
                [vertexInfo{ii} normalInfo{ii}] = the_child.get_vertex_info;
            end
        end
    end

    methods ( Access = 'private' )

Private HELPER Methods

        function child = retrieve_child_from_idx(obj, idx)
            child = obj.children{idx};
        end
    end
end