ViewingPane

This class is task with controlling the 3D display of shapes.

Contents

classdef ViewingPane < handle
    % This defines the ViewingPane class.

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

Class Properties

    properties ( SetAccess = 'private', GetAccess = 'public' )
        pane;                   % (javax.swing.JPanel)
    end
    properties ( SetAccess = 'private', GetAccess = 'private' )
        bodyBuilder;            % (BodyBuilder)
        body_TransformGroup;    % (javax.media.j3d.TransformGroup)
        userdata;               % (various Java3D objects)
    end

    methods

Constructor

        function obj = ViewingPane(bodyBuilder)
            % Load function handles
            fh = svSupport;

            obj.bodyBuilder = bodyBuilder;

            % Build the Gui and set pane
            obj.pane = obj.build_gui(fh);
        end

SET Methods

        function set.bodyBuilder(obj, in)
            prop_name = 'bodyBuilder';
            prop_type = 'BodyBuilder';
            [valid_flag in] = Validate.SCALAR(in,'type',prop_type);
            if valid_flag
                obj.(prop_name) = in;
            end
        end
        function set.body_TransformGroup(obj, in)
            prop_name = 'body_TransformGroup';
            prop_type = 'javax.media.j3d.TransformGroup';
            [valid_flag in] = Validate.SCALAR(in,'type',prop_type);
            if valid_flag
                obj.(prop_name) = in;
            end
        end
        function set.pane(obj, in)
            prop_name = 'pane';
            prop_type = 'javax.swing.JPanel';
            [valid_flag in] = Validate.SCALAR(in,'type',prop_type);
            if valid_flag
                obj.(prop_name) = in;
            end
        end

Public HELPER Methods

        function add_shape_to_viewingPane(obj, parent_shape, the_shape)
            % This method adds a shape to the viewing pane.  If the
            % shape is a ComplexShape, then we need to check for children
            % to complete the additions to the pane.  This requires
            % recursion.
            import com.sun.j3d.utils.behaviors.keyboard.*;
            import com.sun.j3d.utils.behaviors.mouse.*;
            import com.sun.j3d.utils.geometry.*;

            import javax.media.j3d.*;
            import javax.vecmath.*;

            % Create child node
            if isempty(parent_shape)
                % Get where in the tree we are pointing
                parent_shape = obj.bodyBuilder.selected_shape;
                if isempty(parent_shape) % Nothing Selected.  I.e., there is nothing in the model
                    % The_shape is at the top level (i.e., body).
                    % Therefore, the_shape's parent will be
                    % body_TransformGroup.
                    the_TransformGroup = obj.body_TransformGroup;
                else
                    the_TransformGroup = parent_shape.TransformGroup;
                end
            else
                the_TransformGroup = parent_shape.TransformGroup;
            end
            % Attach the_shape's BranchGroup to parent_shape's TransformGroup.
            the_TransformGroup.addChild(the_shape.BranchGroup);

            % If the_shape is a ComplexShape, check its children
            if isa(the_shape,'ComplexShape')
                the_children = the_shape.children;
                n_children = length(the_children);

                for ii = 1:n_children
                    obj.add_shape_to_viewingPane(...
                        the_shape, the_children{ii});
                end
            end
        end

        function detach_body(obj)
            % Remove old scene graph by detaching all BranchGroups that are
            % attached to World Origin.
            the_TransformGroup	= ...
                obj.bodyBuilder.world_origin.triad.TransformGroup;
            for ii = the_TransformGroup.numChildren:-1:1
                if isa(the_TransformGroup.getChild(ii-1),'javax.media.j3d.BranchGroup')
                    the_TransformGroup.removeChild(ii-1);
                end
            end
        end

        function attach_world_orgin(obj)
            % This function attaches the World Origin to yRotation_TransformGroup.
            % Get the World Oriogin's BranchGroup
            the_BranchGroup	= obj.bodyBuilder.world_origin.triad.BranchGroup;

            % Clear current body and add the new body
            obj.body_TransformGroup.addChild(the_BranchGroup);
        end
    end

    methods ( Access = 'private' )

Private HELPER Methods

        function pane = build_gui(obj,fh)
            import java.awt.*;
            import java.awt.event.*;
            import java.text.DecimalFormat;
            import java.util.*;

            import javax.swing.table.*;
            import javax.swing.border.*;
            import javax.swing.event.*;
            import javax.vecmath.*;
            import javax.swing.BorderFactory;

            preferredButtonSize = java.awt.Dimension(75,20);
            stdColor = java.awt.Color(uint8(round(.8314*255)),uint8(round(.8157*255)),uint8(round(.7843*255)));
            loweredetched = BorderFactory.createEtchedBorder();
            raisedbevel = BorderFactory.createRaisedBevelBorder();
            gbc = GridBagConstraints(); % Used for default settings

            % ==============================================================
            % VIEWING_PANE CONSISTS OF:

            % ==============================================================
            % VIEWING_PANE
            pane = javaObjectEDT('javax.swing.JPanel',BorderLayout);
            pane.setBorder(BorderFactory.createTitledBorder('Viewer'));
            pane.setBackground(stdColor);

            % Partition viewing area into regions
            northviewing_pane = javaObjectEDT('javax.swing.JPanel');
            northviewing_pane.setBackground(stdColor);
            pane.add(northviewing_pane,BorderLayout.NORTH);

            eastviewing_pane = javaObjectEDT('javax.swing.JPanel');
            eastviewing_pane.setBackground(stdColor);
            pane.add(eastviewing_pane,BorderLayout.EAST);

            southviewing_pane = javaObjectEDT('javax.swing.JPanel');
            southviewing_pane.setBorder(BorderFactory.createTitledBorder(...
                loweredetched,'View'));
            southviewing_pane.setBackground(stdColor);
            pane.add(southviewing_pane,BorderLayout.SOUTH);

            % view front
            viewFrontButton = javaObjectEDT('javax.swing.JButton','Front');
            viewFrontButton.setPreferredSize(preferredButtonSize);
            viewFrontButton.setBackground(stdColor);
            viewFrontButton.setBorder(raisedbevel);

            c = gbc;
            c.anchor = GridBagConstraints.CENTER;	c.insets =  Insets(2,2,2,2);
            c.gridwidth = 1;		c.gridheight = 1;
            c.gridx = 0;			c.gridy = 0;
            southviewing_pane.add(viewFrontButton,c);

            % view back
            viewBackButton = javaObjectEDT('javax.swing.JButton','Back');
            viewBackButton.setPreferredSize(preferredButtonSize);
            viewBackButton.setBackground(stdColor);
            viewBackButton.setBorder(raisedbevel);

            c = gbc;
            c.anchor = GridBagConstraints.CENTER;	c.insets =  Insets(2,2,2,2);
            c.gridwidth = 1;		c.gridheight = 1;
            c.gridx = 0;			c.gridy = 1;
            southviewing_pane.add(viewBackButton,c);

            % view top
            viewTopButton = javaObjectEDT('javax.swing.JButton','Top');
            viewTopButton.setPreferredSize(preferredButtonSize);
            viewTopButton.setBackground(stdColor);
            viewTopButton.setBorder(raisedbevel);

            c = gbc;
            c.anchor = GridBagConstraints.CENTER;	c.insets =  Insets(2,2,2,2);
            c.gridwidth = 1;		c.gridheight = 1;
            c.gridx = 1;			c.gridy = 0;
            southviewing_pane.add(viewTopButton,c);

            % view bottom
            viewBottomButton = javaObjectEDT('javax.swing.JButton','Bottom');
            viewBottomButton.setPreferredSize(preferredButtonSize);
            viewBottomButton.setBackground(stdColor);
            viewBottomButton.setBorder(raisedbevel);

            c = gbc;
            c.anchor = GridBagConstraints.CENTER;	c.insets =  Insets(2,2,2,2);
            c.gridwidth = 1;		c.gridheight = 1;
            c.gridx = 1;			c.gridy = 1;
            southviewing_pane.add(viewBottomButton,c);

            % view right
            viewRightButton = javaObjectEDT('javax.swing.JButton','Right');
            viewRightButton.setPreferredSize(preferredButtonSize);
            viewRightButton.setBackground(stdColor);
            viewRightButton.setBorder(raisedbevel);

            c = gbc;
            c.anchor = GridBagConstraints.CENTER;	c.insets =  Insets(2,2,2,2);
            c.gridwidth = 1;		c.gridheight = 1;
            c.gridx = 2;			c.gridy = 0;
            southviewing_pane.add(viewRightButton,c);

            % view left
            viewLeftButton = javaObjectEDT('javax.swing.JButton','Left');
            viewLeftButton.setPreferredSize(preferredButtonSize);
            viewLeftButton.setBackground(stdColor);
            viewLeftButton.setBorder(raisedbevel);

            c = gbc;
            c.anchor = GridBagConstraints.CENTER;	c.insets =  Insets(2,2,2,2);
            c.gridwidth = 1;		c.gridheight = 1;
            c.gridx = 2;			c.gridy = 1;
            southviewing_pane.add(viewLeftButton,c);

            % spin horizontally
            spinUpOrDownPanel = javaObjectEDT('javax.swing.JPanel',GridLayout(3,1));
            spinUpOrDownGroup 				= CheckboxGroup();
            spinUpCheckbox 					= Checkbox('Up',false,spinUpOrDownGroup);
            spinUpOrDownPanel.add(spinUpCheckbox);

            stopSpinningUpOrDownCheckbox 	= Checkbox('Stop',true,spinUpOrDownGroup);
            spinUpOrDownPanel.add(stopSpinningUpOrDownCheckbox);

            spinDownCheckbox 				= Checkbox('Down',false,spinUpOrDownGroup);
            spinUpOrDownPanel.add(spinDownCheckbox);
            eastviewing_pane.add(spinUpOrDownPanel);

            % spin about y-axis
            spinLeftOrRightPanel			= Panel(GridLayout(1,3));
            spinRightOrLeftGroup 			= CheckboxGroup();
            spinLeftCheckbox 				= Checkbox('Neg-Y',false,spinRightOrLeftGroup);
            spinLeftOrRightPanel.add(spinLeftCheckbox);

            stopSpinningRightOrLeftCheckbox = Checkbox('Stop',true,spinRightOrLeftGroup);
            spinLeftOrRightPanel.add(stopSpinningRightOrLeftCheckbox);

            spinRightCheckbox 				= Checkbox('Pos-Y',false,spinRightOrLeftGroup);
            spinLeftOrRightPanel.add(spinRightCheckbox);
            northviewing_pane.add(spinLeftOrRightPanel);

            % Construct the Scene Graph
            [Canvas3D ud] = obj.createSceneGraph();
            pane.add(Canvas3D);

            % With ud, we are ready to assign callbacks
            set(handle(viewFrontButton, 'CallbackProperties'),...
                'ActionPerformedCallback', ...
                {fh.viewFrontButton_ActionPerformedCallback,ud});
            set(handle(viewBackButton, 'CallbackProperties'),...
                'ActionPerformedCallback', ...
                {fh.viewBackButton_ActionPerformedCallback,ud});
            set(handle(viewTopButton, 'CallbackProperties'),...
                'ActionPerformedCallback', ...
                {fh.viewTopButton_ActionPerformedCallback,ud});
            set(handle(viewBottomButton, 'CallbackProperties'),...
                'ActionPerformedCallback', ...
                {fh.viewBottomButton_ActionPerformedCallback,ud});
            set(handle(viewRightButton, 'CallbackProperties'),...
                'ActionPerformedCallback', ...
                {fh.viewRightButton_ActionPerformedCallback,ud});
            set(handle(viewLeftButton, 'CallbackProperties'),...
                'ActionPerformedCallback', ...
                {fh.viewLeftButton_ActionPerformedCallback,ud});
            set(handle(spinUpCheckbox, 'CallbackProperties'),...
                'ItemStateChangedCallback', ...
                {fh.spinUpCheckbox_ItemStateChangedCallback,ud});
            set(handle(stopSpinningUpOrDownCheckbox, 'CallbackProperties'),...
                'ItemStateChangedCallback', ...
                {fh.stopSpinningUpOrDownCheckbox_ItemStateChangedCallback,ud});
            set(handle(spinDownCheckbox, 'CallbackProperties'),...
                'ItemStateChangedCallback', ...
                {fh.spinDownCheckbox_ItemStateChangedCallback,ud});
            set(handle(spinLeftCheckbox, 'CallbackProperties'),...
                'ItemStateChangedCallback', ...
                {fh.spinLeftCheckbox_ItemStateChangedCallback,ud});
            set(handle(stopSpinningRightOrLeftCheckbox, 'CallbackProperties'),...
                'ItemStateChangedCallback', ...
                {fh.stopSpinningRightOrLeftCheckbox_ItemStateChangedCallback,ud});
            set(handle(spinRightCheckbox, 'CallbackProperties'),...
                'ItemStateChangedCallback', ...
                {fh.spinRightCheckbox_ItemStateChangedCallback,ud});

            % Store ud as user data
            obj.userdata = ud;
        end

        function [Canvas3D ud] = createSceneGraph(obj)
            import com.sun.j3d.utils.behaviors.keyboard.*;
            import com.sun.j3d.utils.behaviors.mouse.*;
            import com.sun.j3d.utils.geometry.*;

            import javax.media.j3d.*;
            import javax.vecmath.*;
            import javax.media.j3d.GraphicsConfigTemplate3D;
            import java.awt.GraphicsEnvironment;

            import com.sun.j3d.utils.universe.SimpleUniverse;	% Contained in j3dutils.jar

            import org.j3d.renderer.java3d.geom.*;

            use_simple_universe = true;

            % ===================================================================================
            % Construct the content branch
            % Create BranchGroups and TransformGroups
            root_BranchGroup				= BranchGroup();
            root_BranchGroup.setName('root');
            translation_TransformGroup	= TransformGroup();
            translation_TransformGroup.setName('translation');
            xRotation_TransformGroup 	= TransformGroup();
            xRotation_TransformGroup.setName('xRotation');
            yRotation_TransformGroup 	= TransformGroup();
            yRotation_TransformGroup.setName('yRotation');

            % ===================================================================================
            % Set capabilities
            translation_TransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

            xRotation_TransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);

            yRotation_TransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
            yRotation_TransformGroup.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
            yRotation_TransformGroup.setCapability(TransformGroup.ALLOW_CHILDREN_READ);
            yRotation_TransformGroup.setCapability(TransformGroup.ALLOW_CHILDREN_WRITE);
            yRotation_TransformGroup.setCapability(TransformGroup.ALLOW_CHILDREN_EXTEND);

            % ===================================================================================
            % Attach BranchGroups and TransformGroups
            root_BranchGroup.addChild(translation_TransformGroup);
            translation_TransformGroup.addChild(xRotation_TransformGroup);
            xRotation_TransformGroup.addChild(yRotation_TransformGroup);

            % ===================================================================================
            % Create behaviors for TransformGroups
            rotationAlpha = Alpha(-1, 4000);

            % Create radiobutton-driven rotation behavior
            xRotation_RotationInterpolator = RotationInterpolator(...
                rotationAlpha, xRotation_TransformGroup, sv_Axes.get_posX, 0.0, 2*pi);
            yRotation_RotationInterpolator = RotationInterpolator(...
                rotationAlpha, yRotation_TransformGroup, sv_Axes.get_posY, 0.0, 2*pi);

            % Define bounds and schedule them
            bounds = BoundingSphere();

            xRotation_RotationInterpolator.setSchedulingBounds(bounds);
            yRotation_RotationInterpolator.setSchedulingBounds(bounds);

            xRotation_TransformGroup.addChild(xRotation_RotationInterpolator);
            yRotation_TransformGroup.addChild(yRotation_RotationInterpolator);

            xRotation_RotationInterpolator.setEnable(false);
            yRotation_RotationInterpolator.setEnable(false);

            obj.body_TransformGroup = yRotation_TransformGroup;			% TransformGroup();  An alias for convenience

            % ===================================================================================
            % Add the world origin to the scene
            obj.attach_world_orgin();

            % ===================================================================================
            % Add the Humanoid body to the scene
            if false
                the_BranchGroup = ViewingPane.make_human; %#ok<UNRCH>
                obj.body_TransformGroup.addChild(the_BranchGroup);
            end

            % ===================================================================================
            % Creeate Mouse-driven rotation behavior
            myMouseRotate = MouseRotate();
            myMouseRotate.setTransformGroup(translation_TransformGroup);
            myMouseRotate.setSchedulingBounds(BoundingSphere());
            translation_TransformGroup.addChild(myMouseRotate);

            % ===================================================================================
            % Creeate Mouse-driven translation behavior
            myMouseTranslate = MouseTranslate();
            myMouseTranslate.setTransformGroup(translation_TransformGroup);
            myMouseTranslate.setSchedulingBounds(BoundingSphere());
            translation_TransformGroup.addChild(myMouseTranslate);

            % ===================================================================================
            % Creeate Mouse-driven zoom behavior
            myMouseZoom = MouseZoom();
            myMouseZoom.setTransformGroup(translation_TransformGroup);
            myMouseZoom.setSchedulingBounds(BoundingSphere());
            translation_TransformGroup.addChild(myMouseZoom);

            % ===================================================================================
            % Create keyboard-driven rotation behavior
            %myBodyBehavior = BodyBehavior(translation_TransformGroup, xRotation_TransformGroup, yRotation_TransformGroup);
            %myBodyBehavior.setSchedulingBounds(bounds);
            %translation_TransformGroup.addChild(myBodyBehavior.behavior);

            % ===================================================================================
            % Creeate Key Navigation behavior
            %keyNavBeh = KeyNavigatorBehavior(translation_TransformGroup);
            %keyNavBeh.setSchedulingBounds(BoundingSphere(Point3d(),1000.0));
            %translation_TransformGroup.addChild(keyNavBeh);

            % Compile content branch graph
            root_BranchGroup.compile();

            if use_simple_universe
                % Create a Canvas3D Object
                Canvas3D	= javax.media.j3d.Canvas3D(SimpleUniverse.getPreferredConfiguration);

                % Create a SimpleUniverse object
                universe = SimpleUniverse(Canvas3D);
                universe.getViewingPlatform.setNominalViewingTransform();

                % Insert content branch graph into the Locale of the SimpleUniverse
                universe.addBranchGraph(root_BranchGroup);
            else
                % Create a Canvas3D object
                template = GraphicsConfigTemplate3D();        % template.setStereo(template.PREFERRED);

                local_env	= GraphicsEnvironment.getLocalGraphicsEnvironment();
                def_screen	= local_env.getDefaultScreenDevice();
                config		= def_screen.getBestConfiguration(template);
                Canvas3D	= javax.media.j3d.Canvas3D(config);

                % Create a VirtualUniverse object
                universe = VirtualUniverse();

                % Create a Locale object and attach it to VirtualUniverse object
                locale = Locale(universe);  % A default Locale is generally used in 3D applications were we don't have to worry about really large coordinate values.

                locale.addBranchGraph(root_BranchGroup);

                % Construct a view branch graph
                view_BranchGroup = BranchGroup();
                view_BranchGroup.setName('view');

                camera_1 = ViewPlatform();	% Create a ViewPlatform object
                camera_1.setActivationRadius(1000.0);
                camera_1.setViewAttachPolicy(View.NOMINAL_HEAD);

                view = View();			% Create a View object
                view.addCanvas3D(Canvas3D);		% View connects a given view
                view.attachViewPlatform(camera_1);	% platform to the canvas.
                view.setBackClipDistance(200.0);
                view.setFrontClipDistance(1.0);
                % 				view.setPhysicalBody(PhysicalBody());
                % 				view.setPhysicalEnvironment(PhysicalEnvironment());

                view_TransformGroup = TransformGroup();
                view_TransformGroup.setName('view');
                tempTrans = Transform3D();
                tempTrans.setTranslation(Vector3f(0.0,0.0,7.5));
                view_TransformGroup.setTransform(tempTrans);
                view_TransformGroup.addChild(camera_1);

                view_BranchGroup.addChild(view_TransformGroup);

                % Compile and insert into the locale.
                view_BranchGroup.compile();
                locale.addBranchGraph(view_BranchGroup);
            end

            % ===================================================================================
            % Assemble structure of Viewing Pane objects that are needed for GUI calbacks
            ud.xRotation_RotationInterpolator	= xRotation_RotationInterpolator;% RotationInterpolator
            ud.yRotation_RotationInterpolator	= yRotation_RotationInterpolator;% RotationInterpolator
            ud.translation_TransformGroup		= translation_TransformGroup;	% TranslationTransformGroup
            ud.xRotation_TransformGroup			= xRotation_TransformGroup;		% XRotationTransformGroup
            ud.yRotation_TransformGroup			= yRotation_TransformGroup;		% YRotationTransformGroup
            ud.root_BranchGroup					= root_BranchGroup;				% BranchGroup();
        end

        function body_TransformGroup = assemble_body(obj, the_body)
            import javax.media.j3d.*;
            import javax.vecmath.*;

            body_TransformGroup = TransformGroup();
            body_TransformGroup.setName('Root Body');
            % center the body
            tmpTrans = Transform3D();
            tmpVector = Vector3f();
            tmpVector.set(0.0, -1.5, 0.0);
            tmpTrans.set(tmpVector);
            body_TransformGroup.setTransform(tmpTrans);

            % Append any children of body to the root TransformGroup
            obj.extend_assy(the_body,body_TransformGroup);
        end

        function extend_assy(obj, the_parent, the_parent_TG)
            import javax.vecmath.*;
            import javax.media.j3d.*;

            % We know that the_parent is a ComplexShape object.  Get its
            % children and extend the branch starting from the_parent.
            the_children = the_parent.children;
            n_children = length(the_children);
            if ~n_children
                return;
            end

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

            tmpVector = Vector3f();

            % Idenify those children that are ComplexShapes
            is_complex_shape = cellfun(@(x) isa(x,'ComplexShape'),the_children);

            % Create the_body TransformGroup
            the_body = TransformGroup();
            the_body.setName('the_body');
            the_body.setTransform(tmpTrans);

            % For all children , we add a TransformGroup and a Shape Object.
            % For children that are ComplexShape objects, we recurse further.
            for ii = 1:n_children
                % Get the next child
                the_child  = the_children{ii};

                % Add a TransformGroup
                child_TG = TransformGroup();

                % Move the TransformGroup according to the location of the child
                % wrt the parent.  Get shape's cg coordinate system
                % 				child_cg_loc	= the_child.coord_system{1}.origin;
                % 				child_cg_dir	= the_child.coord_system{1}.orientation;
                % 				tmpVector.set(child_cg_loc(1), child_cg_loc(2), child_cg_loc(3));
                the_t3d.set(tmpVector);					% Transform3D
                % 				the_t3d.rotX(child_cg_dir(1));
                % 				the_t3d.rotY(child_cg_dir(2));
                % 				the_t3d.rotZ(child_cg_dir(3));

                child_TG.setTransform(the_t3d);

                % add the shape to the body
                child_TG.addChild(the_child.shape3D);

                % add the child's transform group and shape to its parent
                the_parent_TG.addChild(child_TG);

                if is_complex_shape(ii)
                    % Recursion Step to continue the branch as necessary
                    obj.extend_assy(the_child, child_TG);
                end
            end
        end
    end

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

Static Private HELPER Methods

        function the_human = make_human()
            import javax.media.j3d.*;
            % Set up an appearance to make the body with red ambient,
            % black emmissive, red diffuse and white specular coloring
            the_appearance	= sv_Appearance.create_appearance(...
                [1 0 0],[0 0 0],[1 0 0],[1 1 1],64);

            %box = com.sun.j3d.utils.geometry.Box(0.5/2, 1.5/2, 0.3/2, the_appearance);

            tmpTrans = Transform3D();
            tmpVector = Vector3f();

            the_human					= BranchGroup();
            the_human_TransformGroup	= TransformGroup();
            the_human.addChild(the_human_TransformGroup);

            % center the body
            tmpVector.set(0.0, -1.5, 0.0);
            tmpTrans.set(tmpVector);
            the_human_TransformGroup.setTransform(tmpTrans);

            % offset and place the cylinder for the body
            tmpTG = TransformGroup();
            % offset the shape
            tmpVector.set(0.0, 1.5, 0.0);
            tmpTrans.set(tmpVector);
            tmpTG.setTransform(tmpTrans);
            tmpCyl = com.sun.j3d.utils.geometry.Cylinder(0.75, 3.0, the_appearance);
            tmpTG.addChild(tmpCyl);

            % add the shape to the body
            the_human_TransformGroup.addChild(tmpTG);

            % create the r_shoulder TransformGroup
            Human_r_shoulder = TransformGroup();
            Human_r_shoulder.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
            Human_r_shoulder.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
            % translate from the waist
            tmpVector.set(-0.95, 2.9, -0.2);
            tmpTrans.set(tmpVector);
            Human_r_shoulder.setTransform(tmpTrans);

            % place the sphere for the r_shoulder
            tmpSphere = com.sun.j3d.utils.geometry.Sphere(0.22, the_appearance);
            Human_r_shoulder.addChild(tmpSphere);

            % offset and place the cylinder for the r_shoulder
            tmpTG = TransformGroup();
            % offset the shape
            tmpVector.set(0.0, -0.5, 0.0);
            tmpTrans.set(tmpVector);
            tmpTG.setTransform(tmpTrans);
            tmpCyl = com.sun.j3d.utils.geometry.Cylinder(0.2, 1.0, the_appearance);
            tmpTG.addChild(tmpCyl);

            % add the shape to the r_shoulder
            Human_r_shoulder.addChild(tmpTG);

            % add the shoulder to the body group
            the_human_TransformGroup.addChild(Human_r_shoulder);

            % create the r_elbow TransformGroup
            Human_r_elbow = TransformGroup();
            Human_r_elbow.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
            Human_r_elbow.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
            tmpVector.set(0.0, -1.054, 0.0);
            tmpTrans.set(tmpVector);
            Human_r_elbow.setTransform(tmpTrans);

            % place the sphere for the r_elbow
            tmpSphere = com.sun.j3d.utils.geometry.Sphere(0.22, the_appearance);
            Human_r_elbow.addChild(tmpSphere);

            % offset and place the cylinder for the r_shoulder
            tmpTG = TransformGroup();
            % offset the shape
            tmpVector.set(0.0, -0.5, 0.0);
            tmpTrans.set(tmpVector);
            tmpTG.setTransform(tmpTrans);
            tmpCyl = com.sun.j3d.utils.geometry.Cylinder(0.2, 1.0, the_appearance);
            tmpTG.addChild(tmpCyl);

            % add the shape to the r_shoulder
            Human_r_elbow.addChild(tmpTG);

            % add the elbow to the shoulder group
            Human_r_shoulder.addChild(Human_r_elbow);

            % create the l_shoulder TransformGroup
            Human_l_shoulder = TransformGroup();
            Human_l_shoulder.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
            Human_l_shoulder.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
            tmpVector.set(0.95, 2.9, -0.2);
            tmpTrans.set(tmpVector);
            Human_l_shoulder.setTransform(tmpTrans);

            % place the sphere for the l_shoulder
            tmpSphere = com.sun.j3d.utils.geometry.Sphere(0.22, the_appearance);
            Human_l_shoulder.addChild(tmpSphere);

            % offset and place the cylinder for the l_shoulder
            tmpTG = TransformGroup();
            % offset the shape
            tmpVector.set(0.0, -0.5, 0.0);
            tmpTrans.set(tmpVector);
            tmpTG.setTransform(tmpTrans);
            tmpCyl = com.sun.j3d.utils.geometry.Cylinder(0.2, 1.0, the_appearance);
            tmpTG.addChild(tmpCyl);

            % add the shape to the l_shoulder
            Human_l_shoulder.addChild(tmpTG);

            % add the shoulder to the body group
            the_human_TransformGroup.addChild(Human_l_shoulder);

            % create the r_elbow TransformGroup
            Human_l_elbow = TransformGroup();
            Human_l_elbow.setCapability(TransformGroup.ALLOW_TRANSFORM_READ);
            Human_l_elbow.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
            tmpVector.set(0.0, -1.054, 0.0);
            tmpTrans.set(tmpVector);
            Human_l_elbow.setTransform(tmpTrans);

            % place the sphere for the l_elbow
            tmpSphere = com.sun.j3d.utils.geometry.Sphere(0.22, the_appearance);
            Human_l_elbow.addChild(tmpSphere);

            % offset and place the cylinder for the l_elbow
            tmpTG = TransformGroup();
            % offset the shape
            tmpVector.set(0.0, -0.5, 0.0);
            tmpTrans.set(tmpVector);
            tmpTG.setTransform(tmpTrans);
            tmpCyl = com.sun.j3d.utils.geometry.Cylinder(0.2, 1.0, the_appearance);
            tmpTG.addChild(tmpCyl);

            % add the shape to the l_elbow
            Human_l_elbow.addChild(tmpTG);

            % add the shoulder to the body group
            Human_l_shoulder.addChild(Human_l_elbow);

            % create the skullbase TransformGroup
            Human_skullbase = TransformGroup();
            tmpVector.set(0.0, 3.632, 0.0);
            tmpTrans.set(tmpVector);
            Human_skullbase.setTransform(tmpTrans);

            % offset and place the sphere for the skull
            tmpSphere = com.sun.j3d.utils.geometry.Sphere(0.5, the_appearance);

            % add the shape to the l_shoulder
            Human_skullbase.addChild(tmpSphere);

            % add the shoulder to the body group
            the_human_TransformGroup.addChild(Human_skullbase);
        end
    end
end