Contents

Triad

This class enables 3D axes display.

classdef Triad < handle
    % This defines the Triad class.

    %   URL : $URL: $
    %   Log : $Id: Triad.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' )
        is_origin_visible = false;  % (logical) Represents the visibility of a small sphere at the origin of the triad
        is_semi_length = true;     % (logical) true -> display axes from origin out; false -> display axes on both sides of origin.
        is_visible = true;         % (logical)
        length = 0.25;             % (pos semidef double)
        name = 'New Triad';               % (char)
        transparency = 0.25;       % (pos semidef double)
    end
    properties ( SetAccess = 'private', GetAccess = 'public' )
        BranchGroup;        % (javax.media.j3d.BranchGroup)
        TransformGroup;     % (javax.media.j3d.TransformGroup)
        BG_parent_str = ''; % (String)
        TG_id_str = '';		% (String)
    end
    properties ( SetAccess = 'private', GetAccess = 'private' )
        primitives;         % (com.sun.j3d.utils.geometry...)

        axis_x_TG           % (javax.media.j3d.TransformGroup)
        axis_y_TG           % (javax.media.j3d.TransformGroup)
        axis_z_TG           % (javax.media.j3d.TransformGroup)
        axis_T3D            % (javax.media.j3d.Transform3D)
        axis_x_T3D          % (javax.media.j3d.Transform3D)
        axis_y_T3D          % (javax.media.j3d.Transform3D)
        axis_z_T3D          % (javax.media.j3d.Transform3D)
        axis_offset_V3f     % (javax.vecmath.Vector3f)

        arrow_x_TG          % (javax.media.j3d.TransformGroup)
        arrow_y_TG          % (javax.media.j3d.TransformGroup)
        arrow_z_TG          % (javax.media.j3d.TransformGroup)
        arrow_T3D           % (javax.media.j3d.Transform3D)
        arrow_offset_V3f    % (javax.vecmath.Vector3f)
    end

    properties ( SetAccess = 'private', GetAccess = 'private', Dependent = true )
        arrow_radius;       % (double)
        arrow_length;       % (double)
        axes_radius;        % (double)
        n_primitives;       % (int)
        origin_sphere_radius;% (double)
    end
    properties ( SetAccess = 'private', GetAccess = 'private', Constant = true )
        PROPERTY_LIST = {
            'is_origin_visible'
            'is_semi_length'
            'is_visible'
            'length'
            'name'
            'transparency'
            };
    end

    methods

Constructor

        function obj = Triad(varargin)
            Log.msg(sprintf('%s::%s',mfilename,mfilename));
            prop_list = eval([mfilename '.PROPERTY_LIST']);
            n_props = length(prop_list); %#ok<CPROP>
			if(mod(nargin,2)~=0)
				error('Expecting inputs as property name-value pairs.')
			end
			error(nargchk(0, 2*n_props, nargin,'string'));

			% 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

			obj.add_BranchGroup;
			obj.add_TransformGroup;
			obj.add_primitives;
		end

SAVEOBJ Method

        function A = saveobj(obj)
            % Java3D items are not serializable, so they must be stored another
			% way.  For an explanation, refer to the notes at the top of
			% BodyBuilder.m
            Log.msg(sprintf('\n%s::%s',mfilename,'saveobj (Entering)'));
            Log.msg(sprintf('obj.name = %s',obj.name));
			if ~isempty(obj.BranchGroup)
				the_parent = obj.BranchGroup.getParent;
				if ~isempty(the_parent)
					A.BG_parent_str = the_parent.toString.toCharArray';
                    Log.msg(sprintf('A.BG_parent_str = %s',A.BG_parent_str));
				end
			end
            if ~isempty(obj.TransformGroup)
                A.TG_id_str = obj.TransformGroup.toString.toCharArray';
                Log.msg(sprintf('A.TG_id_str = %s',A.TG_id_str));
            end
			A.is_origin_visible = obj.is_origin_visible;
			A.is_semi_length = obj.is_semi_length;
			A.is_visible = obj.is_visible;
			A.length = obj.length;
			A.name = obj.name;
			A.transparency = obj.transparency;
			A.BranchGroup = [];
			A.TransformGroup = [];     % (javax.media.j3d.TransformGroup)
			A.primitives = [];

            A.axis_x_TG = [];           % (javax.media.j3d.TransformGroup)
            A.axis_y_TG = [];           % (javax.media.j3d.TransformGroup)
            A.axis_z_TG = [];           % (javax.media.j3d.TransformGroup)
            A.axis_T3D = [];            % (javax.media.j3d.Transform3D)
            A.axis_x_T3D = [];          % (javax.media.j3d.Transform3D)
            A.axis_y_T3D = [];          % (javax.media.j3d.Transform3D)
            A.axis_z_T3D = [];          % (javax.media.j3d.Transform3D)
            A.axis_offset_V3f = [];     % (javax.vecmath.Vector3f)

            A.arrow_x_TG = [];          % (javax.media.j3d.TransformGroup)
            A.arrow_y_TG = [];          % (javax.media.j3d.TransformGroup)
            A.arrow_z_TG = [];          % (javax.media.j3d.TransformGroup)
            A.arrow_T3D = [];           % (javax.media.j3d.Transform3D)
            A.arrow_offset_V3f = [];    % (javax.vecmath.Vector3f)

            Log.msg(sprintf('%s::%s',mfilename,'saveobj (Leaving)'));
		end

SET Methods

        function set.BranchGroup(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 = 'BranchGroup';
            prop_type = 'javax.media.j3d.BranchGroup';
			% Validate and assign
			[valid_flag in] = Validate.SCALAR(in,'type',prop_type);
			if valid_flag
				obj.(prop_name) = in;
			end
        end
        function set.is_origin_visible(obj, in)
            prop_name = 'is_origin_visible';
            prop_type = 'logical';
            [valid_flag in] = Validate.ARRAY(in,'type',prop_type);
            if valid_flag
                obj.(prop_name) = in;
                import javax.media.j3d.*;

                % Set visibility by setting transparency.
                if in			% If visible, use transparency.
                    the_transparency = obj.transparency;
                else					% Otherwise, use 1.
                    the_transparency = 1;
                end
                the_primitives = obj.primitives;  % The first item is origin

                if ~isempty(the_primitives)
                    a_transparencyAttribute = ...
                        TransparencyAttributes(TransparencyAttributes.NICEST,the_transparency);
                    the_appearance = the_primitives{1}.getAppearance;
                    the_appearance.setTransparencyAttributes(a_transparencyAttribute);
                end
            end
        end
        function set.is_semi_length(obj, in)
            prop_name = 'is_semi_length';
            prop_type = 'logical';
            [valid_flag in] = Validate.ARRAY(in,'type',prop_type);
            if valid_flag
                obj.(prop_name) = in;
                obj.is_semi_length = in;
            end
        end
        function set.is_visible(obj, in)
            prop_name = 'is_visible';
            prop_type = 'logical';
            [valid_flag in] = Validate.ARRAY(in,'type',prop_type);
            if valid_flag
                obj.(prop_name) = in;

                import javax.media.j3d.*;
                the_primitives = obj.primitives;
                if isempty(the_primitives)
                    return;  % Object still under construction
                end

                % Set visibility by setting transparency.
                if in			% If visible, use transparency.
                    the_transparency    = obj.transparency;
                    if obj.is_origin_visible
                        the_origin_transparency = obj.transparency;
                    else
                        the_origin_transparency = 1;
                    end
                else					% Otherwise, use 1.
                    the_transparency = 1;
                    the_origin_transparency = the_transparency;
                end
                the_transparencyAttribute = ...
                    TransparencyAttributes(TransparencyAttributes.NICEST,the_transparency);
                the_origin_transparencyAttribute = ...
                    TransparencyAttributes(TransparencyAttributes.NICEST,the_origin_transparency);

                % The first primitive is the origin, which has its own
                % visibility property
                the_appearance = the_primitives{1}.getAppearance;
                the_appearance.setTransparencyAttributes(the_origin_transparencyAttribute);

                for ii = 2:obj.n_primitives
                    the_appearance = the_primitives{ii}.getAppearance;
                    the_appearance.setTransparencyAttributes(the_transparencyAttribute);
                end
            end
        end
        function set.length(obj, in)
            prop_name = 'length';
            prop_type = 'double';
            [valid_flag in] = Validate.ARRAY(in,'type',prop_type,'minVal',0);
            if valid_flag
                obj.(prop_name) = in;
                if obj.n_primitives > 0
                    obj.set_primitive_geometries;
                end
            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
        function set.primitives(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 = 'primitives';
			obj.(prop_name) = in;
        end
        function set.TransformGroup(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 = 'TransformGroup';
            prop_type = 'javax.media.j3d.TransformGroup';
			% Validate and assign
            [valid_flag in] = Validate.SCALAR(in,'type',prop_type);
            if valid_flag
                obj.(prop_name) = in;
            end
        end
        function set.transparency(obj, in)
            prop_name = 'transparency';
            prop_type = 'double';
            [valid_flag in] = Validate.ARRAY(in,'type',prop_type,'minVal',0);
            if valid_flag
                obj.(prop_name) = in;
            end
        end

GET Methods

        function arrow_radius = get.arrow_radius(obj)
            arrow_radius = 4*obj.axes_radius;
        end
        function arrow_length = get.arrow_length(obj)
            arrow_length = 2*obj.arrow_radius;
        end
        function axes_radius = get.axes_radius(obj)
            axes_radius = obj.length/50;
        end
        function n = get.n_primitives(obj)
            n = length(obj.primitives);
        end
        function origin_sphere_radius = get.origin_sphere_radius(obj)
            origin_sphere_radius = obj.arrow_radius;
        end

Public HELPER Methods

        function attach_BranchGroup(obj,the_parent_TG)
			% This method is used to attach the Triad's BranchGroup to a parent TransformGroup.

            Log.msg(sprintf('\n%s::%s',mfilename,'attach_BranchGroup (Entering)'));
			obj.BranchGroup.detach;
			the_parent_TG.addChild(obj.BranchGroup);
            obj.BG_parent_str = the_parent_TG.toString.toCharArray';
        end
        function highlight(obj,highlighted)
            % This method highlights the given triad primitives.  Presumably
            % because the associated coordinate system has been selected.

            if highlighted
                red_appearance = sv_Appearance.create_appearance(...
                    [1 1 1],[1 1 1],[],[],150,0);
                green_appearance = sv_Appearance.create_appearance(...
                    [1 1 1],[1 1 1],[],[],150,0);
                blue_appearance = sv_Appearance.create_appearance(...
                    [1 1 1],[1 1 1],[],[],150,0);
            else
                red_appearance = sv_Appearance.create_appearance(...
                    [1 0 0],[1 0 0],[],[],75,0.25);
                green_appearance = sv_Appearance.create_appearance(...
                    [0 1 0],[0 1 0],[],[],75,0.25);
                blue_appearance = sv_Appearance.create_appearance(...
                    [0 0 1],[0 0 1],[],[],75,0.25);
            end

            % Change the color of the primitive Cones
            p_cones = obj.primitives(5:7);     % origin_sphere,x_cyl,y_cyl,z_cyl,x_cone,y_cone,z_cone

            % Cones
            p_cones{1}.setAppearance(red_appearance);
            p_cones{2}.setAppearance(green_appearance);
            p_cones{3}.setAppearance(blue_appearance);

        end
    end

    methods ( Static = true )

LOADOBJ Method

        function B = loadobj(A)
            % This appears to be what happens when an object is loaded from a
            % file:
            %   1. A default object for the corresponding class is created.
            %   This involves running the set method for all properties that
            %   have a default value.
            %   2. Run the set method for all stored properties.  This includes
            %   properties that do not have defaults and properties who defaults
            %   have been overwritten.
            %   3. Execute loadobj() by passing in the structure that was read
            %   from the file.
            %   4. If the class description matches the output structure from
            %   loadobj, instantiate it.

            % 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) %#ok<CPROP>
                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 = Triad(args{:});
            Log.msg(sprintf('%s::%s',mfilename,'loadobj (Leaving)'));
        end
    end

    methods ( Access = 'private' )

Private HELPER Methods

        function add_BranchGroup(obj)
            Log.msg(sprintf('\n%s::%s',mfilename,'add_BranchGroup (Entering)'));
            obj.BranchGroup = javax.media.j3d.BranchGroup;
            obj.BranchGroup.setName(obj.name);
            obj.BranchGroup.setCapability(javax.media.j3d.BranchGroup.ALLOW_DETACH);
            obj.BranchGroup.setCapability(javax.media.j3d.BranchGroup.ALLOW_CHILDREN_EXTEND);
        end
        function add_TransformGroup(obj)
            Log.msg(sprintf('\n%s::%s',mfilename,'add_TransformGroup (Entering)'));
            obj.TransformGroup = javax.media.j3d.TransformGroup();
            obj.TransformGroup.setName(obj.name);
            obj.TransformGroup.setCapability(javax.media.j3d.TransformGroup.ALLOW_TRANSFORM_READ);
            obj.TransformGroup.setCapability(javax.media.j3d.TransformGroup.ALLOW_TRANSFORM_WRITE);
            obj.TransformGroup.setCapability(javax.media.j3d.TransformGroup.ALLOW_CHILDREN_READ);
            obj.TransformGroup.setCapability(javax.media.j3d.TransformGroup.ALLOW_CHILDREN_WRITE);
            obj.TransformGroup.setCapability(javax.media.j3d.TransformGroup.ALLOW_CHILDREN_EXTEND);
            obj.BranchGroup.addChild(obj.TransformGroup);
            obj.TG_id_str = obj.TransformGroup.toString.toCharArray';
        end
        function add_primitives(obj)
            % Draw with three color-coded cylinders and cones
            red_appearance = sv_Appearance.create_appearance(...
                [1 0 0],[1 0 0],[],[],75,0.25);
            green_appearance = sv_Appearance.create_appearance(...
                [0 1 0],[0 1 0],[],[],75,0.25);
            blue_appearance = sv_Appearance.create_appearance(...
                [0 0 1],[0 0 1],[],[],75,0.25);
            if obj.is_origin_visible
                sphere_appearance = sv_Appearance.create_appearance(...
                    [0 1 1],[0 1 1],[],[],75,0.25);
            else
                sphere_appearance = sv_Appearance.create_appearance(...
                    [0 1 1],[0 1 1],[],[],75,1);
            end

            % Cylinders
            x_cyl = org.j3d.renderer.java3d.geom.Cylinder(...
                1, 1, red_appearance);
            y_cyl = org.j3d.renderer.java3d.geom.Cylinder(...
                1, 1, green_appearance);
            z_cyl = org.j3d.renderer.java3d.geom.Cylinder(...
                1, 1, blue_appearance);

            % Cones
            x_cone = org.j3d.renderer.java3d.geom.Cone(...
                1, 1, red_appearance);
            y_cone = org.j3d.renderer.java3d.geom.Cone(...
                1, 1, green_appearance);
            z_cone = org.j3d.renderer.java3d.geom.Cone(...
                1, 1, blue_appearance);

            x_cone.setCapability(x_cone.ALLOW_APPEARANCE_READ);
            x_cone.setCapability(x_cone.ALLOW_APPEARANCE_WRITE);
            y_cone.setCapability(y_cone.ALLOW_APPEARANCE_READ);
            y_cone.setCapability(y_cone.ALLOW_APPEARANCE_WRITE);
            z_cone.setCapability(z_cone.ALLOW_APPEARANCE_READ);
            z_cone.setCapability(z_cone.ALLOW_APPEARANCE_WRITE);

            % Sphere
            origin_sphere = org.j3d.renderer.java3d.geom.Sphere(...
                0.025, sphere_appearance);
            origin_sphere.setName('Triad origin_Sphere');

            % ===========================================
            % Assemble Triad

            % Create TransformGroups for each Axis
            obj.axis_x_TG = javax.media.j3d.TransformGroup();
            obj.axis_y_TG = javax.media.j3d.TransformGroup();
            obj.axis_z_TG = javax.media.j3d.TransformGroup();
            obj.axis_x_TG.setName('Triad axis_x_TG');
            obj.axis_y_TG.setName('Triad axis_y_TG');
            obj.axis_z_TG.setName('Triad axis_z_TG');
            obj.axis_x_TG.setCapability(obj.axis_x_TG.ALLOW_TRANSFORM_WRITE);
            obj.axis_y_TG.setCapability(obj.axis_y_TG.ALLOW_TRANSFORM_WRITE);
            obj.axis_z_TG.setCapability(obj.axis_z_TG.ALLOW_TRANSFORM_WRITE);

            % Align and Offset TransformGroups for each Axis
            obj.axis_x_T3D =  javax.media.j3d.Transform3D();
            obj.axis_y_T3D =  javax.media.j3d.Transform3D();
            obj.axis_z_T3D =  javax.media.j3d.Transform3D();

            % Offset each axis away from origin along its direction
            obj.axis_T3D =  javax.media.j3d.Transform3D();
            obj.axis_offset_V3f = javax.vecmath.Vector3f();

            % Create TransformGroups for each Arrow
            obj.arrow_x_TG = javax.media.j3d.TransformGroup();
            obj.arrow_y_TG = javax.media.j3d.TransformGroup();
            obj.arrow_z_TG = javax.media.j3d.TransformGroup();
            obj.arrow_x_TG.setCapability(obj.arrow_x_TG.ALLOW_TRANSFORM_WRITE);
            obj.arrow_y_TG.setCapability(obj.arrow_y_TG.ALLOW_TRANSFORM_WRITE);
            obj.arrow_z_TG.setCapability(obj.arrow_z_TG.ALLOW_TRANSFORM_WRITE);

            % Offset each arrow away from origin along its direction
            obj.arrow_T3D           = javax.media.j3d.Transform3D();
            obj.arrow_offset_V3f    = javax.vecmath.Vector3f();

            % Attach Everything
            obj.TransformGroup.addChild(obj.axis_x_TG);
            obj.TransformGroup.addChild(obj.axis_y_TG);
            obj.TransformGroup.addChild(obj.axis_z_TG);

            % Add a small sphere to origin, but set invisible by default
            obj.TransformGroup.addChild(origin_sphere);

            obj.axis_x_TG.addChild(obj.arrow_x_TG);
            obj.axis_y_TG.addChild(obj.arrow_y_TG);
            obj.axis_z_TG.addChild(obj.arrow_z_TG);

            % Attach Cylinders
            obj.axis_x_TG.addChild(x_cyl);
            obj.axis_y_TG.addChild(y_cyl);
            obj.axis_z_TG.addChild(z_cyl);

            % Attach Cones
            obj.arrow_x_TG.addChild(x_cone);
            obj.arrow_y_TG.addChild(y_cone);
            obj.arrow_z_TG.addChild(z_cone);

            obj.primitives = {origin_sphere,x_cyl,y_cyl,z_cyl,x_cone,y_cone,z_cone};

            obj.set_primitive_geometries;
        end
        function set_primitive_geometries(obj)
            % This method sets the geometry for the axes (cylinders), arrows
            % (cones) and origin marker (sphere)

            cyl_length      = obj.length;
            cyl_radius      = obj.axes_radius;
            cone_length     = obj.arrow_length;
            cone_radius     = obj.arrow_radius;
            sphere_radius   = obj.origin_sphere_radius;

            the_primitives = obj.primitives;
            % Place primitives where they belong

            if obj.is_semi_length
                cyl_offset = cyl_length/2;
            else
                cyl_length = 2*cyl_length;
                cyl_offset = 0;
            end
            cone_offset    = cyl_length/2 + cone_length/2;

            % Align each axis along its direction
            obj.axis_x_T3D.rotZ(-pi/2);
            obj.axis_y_T3D.rotX(0);
            obj.axis_z_T3D.rotX(pi/2);

            % Offset each axis away from origin along its direction
            obj.axis_offset_V3f.set(0, cyl_offset, 0);
            obj.axis_T3D.set(obj.axis_offset_V3f);

            obj.axis_x_T3D.mul(obj.axis_T3D);
            obj.axis_y_T3D.mul(obj.axis_T3D);
            obj.axis_z_T3D.mul(obj.axis_T3D);

            obj.axis_x_TG.setTransform(obj.axis_x_T3D);
            obj.axis_y_TG.setTransform(obj.axis_y_T3D);
            obj.axis_z_TG.setTransform(obj.axis_z_T3D);

            % Offset each arrow away from origin along its direction
            obj.arrow_offset_V3f.set(0, cone_offset, 0);
            obj.arrow_T3D.set(obj.arrow_offset_V3f);

            obj.arrow_x_TG.setTransform(obj.arrow_T3D);
            obj.arrow_y_TG.setTransform(obj.arrow_T3D);
            obj.arrow_z_TG.setTransform(obj.arrow_T3D);

            % Set primitives to their correct dimensions
            for ii = 1:obj.n_primitives
                prim = the_primitives{ii};

                if isa(prim, 'org.j3d.renderer.java3d.geom.Cylinder')
                    prim.setDimensions(cyl_length,cyl_radius);
                elseif isa(prim, 'org.j3d.renderer.java3d.geom.Cone')
                    prim.setDimensions(cone_length,cone_radius);
                elseif isa(prim, 'org.j3d.renderer.java3d.geom.Sphere')
                    % prim.setDimensions(sphere_radius);

                    % ??? Java exception occurred:
                    % java.lang.IllegalArgumentException:
                    % GeometryStripArray: initial vertex index + valid
                    % vertex count > vertex count

%                     data = prim.getGeometry;
%                     data.geometryType = GeometryData.INDEXED_TRIANGLE_STRIPS;
%
%                     data.geometryComponents = ...
%                         GeometryData.TEXTURE_2D_DATA + GeometryData.NORMAL_DATA;
%                     the_generator = obj.generator();
%                     if isa(prim,'org.j3d.renderer.java3d.geom.Cylinder')
%                         the_generator.setDimensions(cyl_length,cyl_radius,true,true);
%                     else
%                         the_generator.setDimensions(cone_length,cone_radius,true);
%                     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);
%                     prim.setGeometry(geom);
                end
            end
            drawnow
        end
    end
end