PrimitiveShape

This class is a child of Shape.

Contents

classdef PrimitiveShape < Shape
    %This Class defines the Primitive Shape object. Primitive Shape is a
    %subclass of superclass Shape. These are native shapes available in
    %BodyBuilder and consist of a material and geometrical properties. A
    %complex shape usually consists of multiple primitive shapes.
    %This is an abstract class in the sense that each primitive shape for
    %instance brick, cone etc have separate class definitions. These can be
    %instantiated. However you cannot instantiate an object of type
    %Primitive Shape.
    %
    %   URL : $URL: $
    %   Log : $Id: PrimitiveShape.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' )
%         material = ShapeMaterial; % (ShapeMaterial)
        material; % (ShapeMaterial)
    end
    properties ( Dependent = true )
        center_of_mass;     % (CoordSystem)
        mass;               % (pos semidef double)
    end
    properties ( SetAccess = 'protected', GetAccess = 'public' )
        primitive;			% (com.sun.j3d.utils.geometry...)
        generator;          % (org.j3d.geom...)
    end

    methods

Constructor

        function obj = PrimitiveShape()
            Log.msg(sprintf('\n%s::%s',mfilename,mfilename));
            obj.material = ShapeMaterial;
        end

Destructor

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

SET Methods

        function set.generator(obj, in)
            % This property contains unserializable object(s), which creates a
            % problem for saving and loading.  As a workaround, this set will
            % first check for the keyword 'deflate', which indicates that the
            % user wishes to substitute the object currently stored in the
            % property with a description of how to recreate the object(s).  The
            % description will be in the form of a structure with fields cmd and
            % args.  If the property is  currently empty, it remains empty (no
            % harm, no foul).
            prop_name = 'generator';
			obj.(prop_name) = in;
        end
        function set.material(obj, in)
            prop_name = 'material';
            prop_type = 'ShapeMaterial';
            % This is responsible for changing a Shape's material property and
            % the Shape's appearance in the Viewing Pane.
            [valid_flag in] = Validate.SCALAR(in,'type',prop_type);
            if valid_flag
                obj.(prop_name) = in;
                if ~isempty(in)
                    obj.update_shape_appearance;
                end
            end
        end
        function set.primitive(obj, in)
            prop_name = 'primitive';
			obj.(prop_name) = in;
            Log.msg(sprintf('%s::set.primitive (%s)',...
                mfilename, in.toString.toCharArray));
        end

GET Methods

        function mass = get.mass(obj)
            if strcmp(class(obj),'PrimitiveShape')
                % Should only be the case during debug since we do not normally
                % instantiate a Primitive object
                mass = obj.material.density;
            else
                mass = obj.material.density * obj.volume;
            end
        end
        function center_of_mass = get.center_of_mass(obj)
            % Get the shape's CG
             center_of_mass = obj.coord_system{2};
            % Convert the CG wrt to the parent's origin
            % 	[the_pos the_dir]   = CG.convert_coordinates_wrt_new_refCS(ref_CS);
            % 	center_of_mass      = the_pos;
        end

Public HELPER Methods

        function change_geometry(the_shape,dimension_idx,the_value)
            % This is responsible for changing a Shape's geometry properties and
            % the Shape's dimensions in the Viewing Pane.

            the_dimension	= the_shape.dimension_order{dimension_idx};
            eval(['the_shape.' the_dimension ' = ' the_value(:)' ';']);

            the_shape.update_shape_geometry();
        end
        function dimension_info = make_dimension_info(obj)
            % Get all dimensions for the primitive shape
            the_shape_dimensions = obj.dimension_order;
            n_dimensions = length(the_shape_dimensions);

            dimension_info = cell(n_dimensions,2);
            dimension_info(:,1) = the_shape_dimensions;
            for ii = 1:n_dimensions
                dimension_info{ii,2} = eval(['obj.' the_shape_dimensions{ii} '()']);
            end
        end
        function attach_primitive_common(obj,a_primitive)
            % Set all Shape3D objects for the primitive to enable modifications
            % to the appearance (in case the material type is changed).
            % Attach this shape's primitive to this shape's TransformGroup.
            if isempty(obj.TransformGroup)
                % This happens when we are reloading a model because the
                % primitive property is loaded before the TransformGroup
                % property due to the fact that TransformGroup is part of the
                % superclass Shape whereas primitive is part of PrimitiveShape.
                % As we see below, attaching the primitive requires the
                % TransformGroup.
                return
            end

            if true
                % Using org.j3d.renderer.java3d.geom.* for primitives
                a_primitive.setCapability(javax.media.j3d.Shape3D.ALLOW_APPEARANCE_READ);
                a_primitive.setCapability(javax.media.j3d.Shape3D.ALLOW_APPEARANCE_WRITE);
                a_primitive.setCapability(javax.media.j3d.Shape3D.ALLOW_GEOMETRY_WRITE);
            else
                % Using com.sun.j3d.utils.geometry.* for primitives
                ii = 0;
                while true
                    a_shape3D = a_primitive.getShape(ii);
                    if isempty(a_shape3D)
                        break;
                    else
                        a_shape3D.setCapability(a_shape3D.ALLOW_APPEARANCE_READ);
                        a_shape3D.setCapability(a_shape3D.ALLOW_APPEARANCE_WRITE);
                        a_shape3D.setCapability(a_shape3D.ALLOW_GEOMETRY_WRITE);

                        ii = ii+1;
                    end
                end
            end
            % Attach this shape's primitive to this shape's TransformGroup.
            obj.TransformGroup.addChild(a_primitive);
        end
        function [vertexInfo normalInfo] = get_vertex_info(obj)
            % Vertex info is returned to enable exporting to .stl document.
            geom = obj.primitive.getGeometry;
            n_vertex = geom.getVertexCount;
            vertexInfo = zeros(n_vertex,3);
            normalInfo = zeros(n_vertex,3);
            P3f = javax.vecmath.Point3f;
            V3f = javax.vecmath.Vector3f;
            for ii = 1:n_vertex
                geom.getCoordinate(ii-1,P3f);
                vertexInfo(ii,:) = [P3f.x P3f.y P3f.z];
                geom.getNormal(ii-1,V3f);
                normalInfo(ii,:) = [V3f.x V3f.y V3f.z];
            end
        end
    end

    methods ( Access = 'private' )

Private HELPER Methods

        function update_shape_appearance(obj)
            % This is called whenever a Shape's material type has changed
            a_primitive = obj.primitive;
            if ~isempty(a_primitive)
                if true % Using org.j3d.renderer.java3d.geom.* for primitives
                    a_primitive.setAppearance(obj.material.appearance);
                else    % Using com.sun.j3d.utils.geometry.* for primitives
                    ii = 0;
                    while true
                        a_shape3D = a_primitive.getShape(ii);
                        if isempty(a_shape3D)
                            break;
                        else
                            a_shape3D.setAppearance(obj.material.appearance);
                            % a_shape3D.getAppearance.setMaterial(obj.material)
                            ii = ii+1;
                        end
                    end
                end
            end
        end

        function update_shape_geometry(obj)
            % This is called whenever a Shape's dimensions change
            import org.j3d.geom.*;
            import javax.media.j3d.*;

            a_primitive = obj.primitive;

            % Get the latest dimensions and create evaluation string

            the_dimension_info = obj.make_dimension_info();

            if ~isempty(a_primitive)
                try
                    if true
                        % Using org.j3d.renderer.java3d.geom.* for primitives

                        % For some reason, setDimensions does not work for
                        % Spheres.  For them, we use SphereGenerator.
                        if isa(a_primitive,'org.j3d.renderer.java3d.geom.Sphere')
                            obj.update_shape_geometry_using_shape_generator;
                        else
                            obj.primitive.setDimensions(the_dimension_info{:,2});
                        end
                    else
                        % Using com.sun.j3d.utils.geometry.* for primitives
                    end
                catch ME
                    msg = sprintf(...
                        '--> In %s:update_shape_geometry: Trouble Setting Geometry',...
                        mfilename);
                    % Get last segment of the error message identifier.
                    idSegLast = regexp(ME.identifier, '(?<=:)\w+$', 'match');
                    error([msg idSegLast{:}]);
                end
            end
        end

        function update_shape_geometry_using_shape_generator(obj)
            % This is called whenever a Shape's dimensions change
            disp(sprintf('%s:%s (%s)',mfilename,...
                'update_shape_geometry_using_shape_generator',class(obj)));
            import org.j3d.geom.*;
            import javax.media.j3d.*;

            data = GeometryData();
            data.geometryType = GeometryData.INDEXED_TRIANGLE_STRIPS;

            data.geometryComponents = ...
                GeometryData.TEXTURE_2D_DATA + GeometryData.NORMAL_DATA;

            the_generator = obj.generator();

            % Get the latest dimensions
            the_dimension_info = obj.make_dimension_info();

            switch lower(class(obj))
                case 'sphere'
                    the_generator.setDimensions(the_dimension_info{:,2},false);
                    % False for full sphere (vs hemi-sphere)
                case 'cylinder'
                    the_generator.setDimensions(the_dimension_info{:,2},true,true);
                    % True to generate faces for the ends
                case 'cone'
                    the_generator.setDimensions(the_dimension_info{:,2},true);
                    % True if to generate faces for the bottom
                case 'torus'
                    the_generator.setDimensions(the_dimension_info{:,2});
                    % True if to generate faces for the bottom
                otherwise
                    the_generator.setDimensions(the_dimension_info{:,2});
            end
            the_generator.generate(data);

            format = GeometryArray.COORDINATES + GeometryArray.NORMALS;

            i_geom = IndexedTriangleStripArray(...
                data.vertexCount,...
                format,...
                data.indexesCount,...
                data.stripCounts);
            i_geom.setCoordinateIndices(0, data.indexes);
            i_geom.setNormalIndices(0, data.indexes);

            geom = i_geom;

            geom.setCoordinates(0, data.coordinates);
            geom.setNormals(0, data.normals);
            a_primitive = obj.primitive;
            if ~isempty(a_primitive)
                try
                    if true
                        % Using org.j3d.renderer.java3d.geom.* for primitives
                        a_primitive.setGeometry(geom);
                    else
                        % Using com.sun.j3d.utils.geometry.* for primitives
                        ii = 0;
                        while true
                            a_shape3D = a_primitive.getShape(ii);
                            if isempty(a_shape3D)
                                break;
                            else
                                a_shape3D.setGeometry(geom);
                                ii = ii+1;
                            end
                        end
                        % a_shape3D.setAppearance(obj.material.appearance);
                        % a_shape3D.getAppearance.setMaterial(obj.material)
                    end
                catch ME
                    msg = sprintf(...
                        '--> In %s:update_shape_geometry: Trouble Setting Geometry',...
                        mfilename);
                    % Get last segment of the error message identifier.
                    idSegLast = regexp(ME.identifier, '(?<=:)\w+$', 'match');
                    error([msg idSegLast{:}]);
                end
            end
        end
    end
end