Shape

This class is Abstract.

Contents

classdef Shape < handle
    %This Class defines the Shape object. The Shape object has two subclasses:
    % 1. Primitive Shape (eg: brick, cone etc)
    % 2. Complex Shape (eg: car, wheel etc made of multiple primitive shapes)
    %This is an abstract class in the sense that you cannot instantiate an object
    %of type Shape.
    %
    % All Primitive Shapes have:
    %	BranchGroup --> TransformGroup --> shape3D
    % All Complex Shapes have:
    %	BranchGroup --> TransformGroup

    % Assumptions:
    %	The first element of coord_system is the location of the shape's cg
    %	wrt the shape's parent cg.

    %   URL : $URL: $
    %   Log : $Id: Shape.html,v 1.1 2008/07/23 12:51:20 jberg Exp $
    %   Copyright (c) 2008 The MathWorks, Inc.

Class Properties

    properties ( SetAccess = 'public', GetAccess = 'public' )
%         name = 'New Shape'; % (char)
        name; % (char)
        coord_system;       % ({CoordSystem})
    end
    properties ( GetAccess = 'public', Dependent = true )
        % The first CoordSystem stores the Shape's relative origin and
        % orientation with respect to the Shape's parent's CG. For the upper
        % most Shape, (i.e., body), the parent is the global origin.
        BranchGroup;		% (javax.media.j3d.BranchGroup)
        TransformGroup;     % (javax.media.j3d.TransformGroup)
        n_coord_system;     % (int)
    end
    properties ( GetAccess = 'protected', Dependent = true )
        orientation;        % (3-element double array)
        origin;             % (3-element double array)
    end

    methods

Constructor

        function obj = Shape()
        end

Destructor

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

SET Methods

        function set.coord_system(obj, in)
            prop_name = 'coord_system';
            prop_type = 'CoordSystem';
            [valid_flag in] = Validate.ARRAY(in,'type',prop_type,'Cell',true);
            if valid_flag
                obj.(prop_name) = in;
            end
        end
        function set.name(obj, in)
            prop_name = 'name';
            prop_type = 'char';
            [valid_flag in] = Validate.ARRAY(in,'type',prop_type);
            if valid_flag
                obj.(prop_name) = in;
            end
        end

GET Methods

        function coord_system = get.coord_system(varargin)
            % returns all the coord_systems if index is not provided
            % If index or name is provided as the argument, it searches all
            % the CSs of this shape and returns that particular CS.
            obj = varargin{1};
            coord_system = obj.coord_system;
            if (nargin==2)
                if(isnumeric(varargin{2}))
                    % Find CS using index
                    index = varargin{2};
                    if(index > length(coord_system))
                        error('index (%d) entered exceeds coord_system length (%d)', index, length(coord_system));
                    else
                        coord_system = coord_system{index};
                    end
                else
                    % Find CS using name
                    cs_name = varargin{2};
                    ii = 1;
                    while(ii <= length(coord_system))
                        if(strcmp(cs_name,coord_system{ii}.name))
                            coord_system = coord_system{ii};
                            break;
                        end
                        ii = ii+1;
                    end
                    if(ii > obj.n_coord_system)
                        error('CS Name: (%s) entered could not be found',cs_name);
                    end
                end
            end
        end
        function n = get.n_coord_system(obj)
            n = length(obj.coord_system);
        end
        function pos = get.origin(obj)
            pos = obj.coord_system{1}.origin;
        end
        function dir = get.orientation(obj)
            dir = obj.coord_system{1}.orientation;
        end
        function BranchGroup = get.BranchGroup(obj)
            % The Shape's BranchGroup is identical to that of the main
            % CoordSystem.
            BranchGroup     = obj.coord_system{1}.triad.BranchGroup;
        end
        function TransformGroup = get.TransformGroup(obj)
            % The Shape's TransformGroup is identical to that of the main
            % CoordSystem.
            TransformGroup  = obj.coord_system{1}.triad.TransformGroup;
        end

Public HELPER Methods

        function change_axes_length(obj, a_length)
            % This method sets the axes length for the triad of this
            % shape and of all of the children of this shape.

            the_coord_systems = obj.coord_system;
            for ii = 1:length(the_coord_systems)
                the_coord_systems{ii}.triad.length = a_length;
            end

            if isa(obj,'ComplexShape')
                the_children = obj.children;
                for ii = 1:length(the_children)
                    the_children{ii}.change_axes_length(a_length);
                end
            end
        end
        function update_coord_system(obj,the_cs_name,dimension_id,a_value)
            % This is responsible for changing a Shape's Coordinate System
            % and the Shape's location in the Viewing Pane.

            idx = strfind('xyz',dimension_id(1));

            coord_system = CoordSystem.get_by_name(obj.coord_system,the_cs_name);
            switch lower(dimension_id)
                case {'x_pos','y_pos','z_pos'}
                    the_values = coord_system.origin;
                    the_values(idx) =  a_value;
                    coord_system.origin = the_values;
                case {'x_rot','y_rot','z_rot'}
                    the_values = coord_system.orientation;
                    the_values(idx) = a_value;
                    coord_system.orientation = the_values;
                otherwise
                    error([mfilename ':update_coord_system only accepts x_pos, y_pos, z_pos, x_rot, etc. for dimension ID']);
            end

            % Is this the CG that is changing?
            if (~isempty(strfind(the_cs_name,'Origin')))
                % Need to reflect the change in Shape location in the Viewing
                % Pane.
                obj.update_shape_location;
            end
        end

        function add_coord_system(obj,a_coord_system)
            if (nargin==1)
                % Add the Shape's first CoordSystem to property coord_system.
                % The first CS is named 'Origin' and it provides the
                % shape'representation of origin and orientation relative to its
                % parent.  The first CS of a new Shape is initially placed to
                % coincide with the first CS of its parent.  In the case of a
                % PrimitiveShape, the first CS is also its CG.
                % the_length = 0.25;
                Main_CS = CoordSystem('name','Origin',...
                    'is_deletable',false,...
                    'parent_shape',obj);

                % To fully define a CoordSystem, you need the reference
                % CoordSystem.  This is done when the Shape is attached to
                % another Shape.
                obj.coord_system = {Main_CS};
                obj.update_shape_location;
            else
                obj.coord_system{end+1} = a_coord_system;
            end
        end
        function remove_coord_system_by_index(obj,idx)
            if obj.n_coord_system >= idx
                obj.coord_system(idx) = [];
            end
        end
        function remove_coord_system(obj,a_CS)
            coord_systems = obj.coord_system;
            for ii = 1:length(coord_systems)
                if(strcmp(coord_systems{ii}.name,a_CS.name))
                    obj.remove_coord_system_by_index(ii);
                    break;
                end
            end
        end
        function toggle_axes_display(obj)
            % This method toggles the visibility for the triad of this
            % shape and of all of the children of this shape.

            the_coord_systems = obj.coord_system;
            for ii = 1:length(the_coord_systems)
                is_visible = the_coord_systems{ii}.triad.is_visible;
                the_coord_systems{ii}.triad.is_visible = ~is_visible;
            end

            if isa(obj,'ComplexShape')
                the_children = obj.children;
                for ii = 1:length(the_children)
                    the_children{ii}.toggle_axes_display;
                end
            end
        end
        function cs_to_orig_refCS = prepare_CS_to_save(obj)
            % To avoid saving anything above the intended objects, one thing that needs
            % to be done is to remove references to all coordinate systems above the
            % selected body.  We do this by changing such references to the
            % World.Origin.  We address how to avoid saving World.Origin later.

            % For each coord_system, check to see if the parent_shape of the
            % reference_CS is identical to the current shape.  If it is, fine.  If the
            % parent_shape of the reference_CS is empty (i.e., reference_CS =
            % World.Origin), fine.  Otherwise, convert reference_CS to World.Origin.  We
            % need to keep track of all conversions so that we can convert them back
            % after saving.
            cs_to_orig_refCS =cell(0);
            for ii = 1:obj.n_coord_system
                if ~isempty(obj.coord_system{ii}.reference_CS) && ...
                        ~isequal(obj.coord_system{ii}.reference_CS.parent_shape,obj)
                    cs_to_orig_refCS{end+1,1} = obj.coord_system{ii};
                    cs_to_orig_refCS{end,2} = obj.coord_system{ii}.reference_CS;
                    obj.coord_system{ii}.convert_local_coordinates_to_world;
                end
            end
        end
        function return_CS_to_orig_state(obj,cs_to_orig_refCS)
            for ii=1:size(cs_to_orig_refCS,1)
                cs_to_orig_refCS{ii,1}.reference_CS = cs_to_orig_refCS{ii,2};
            end
        end
    end

    methods ( Access = 'protected' )

Protected HELPER Methods

        function update_shape_location(the_shape)
            % This is called whenever a Shape's CG coordinate system changes
            import javax.vecmath.*;
            import javax.media.j3d.*;

            % Get the location of the Shape wrt it's parent's CG.
            the_origin      = the_shape.origin;
            the_orientation = the_shape.orientation*pi/180;
            the_TG			= the_shape.TransformGroup;

            tmpTrans    = javax.media.j3d.Transform3D();
            tmpTrans2   = javax.media.j3d.Transform3D();

            tmpTrans.rotX(the_orientation(1));
            tmpTrans2.rotY(the_orientation(2));

            tmpTrans.mul(tmpTrans2);

            tmpTrans2.rotZ(the_orientation(3));
            tmpTrans.mul(tmpTrans2);

            the_translation	= javax.vecmath.Vector3d();	% Vector3d
            the_translation.set(the_origin(1), the_origin(2), the_origin(3));

            tmpTrans.setTranslation(the_translation);
            the_TG.setTransform(tmpTrans);
        end
    end
end