BodyBuilder
This is the top-level class.
Contents
classdef BodyBuilder < handle
% This defines the BodyBuilder class. % URL : $URL: $ % Log : $Id: BodyBuilder.html,v 1.1 2008/07/23 12:51:18 jberg Exp $ % Copyright (c) 2008 The MathWorks, Inc. % Additions to classpath.txt: % $matlabroot/Java3D/1.5.0/lib/ext/j3dcore.jar % $matlabroot/Java3D/1.5.0/lib/ext/j3dutils.jar % % Addition to librarypath.txt: % $matlabroot/Java3D/1.5.0/bin % Notes: % Java3D items are not serializable, so they must be reconstructed upon % load. We use loadobj to do this.
Class Properties
properties ( SetAccess = 'public', GetAccess = 'public' ) active_shape_name; % (char) Name of a shape class end properties ( SetAccess = 'public', GetAccess = 'public', Dependent = true ) tree; % (JTree) tree_model; % (TreeModel) selected_path; % (TreePath) selected_node; % (TreeNode) selected_shape; % (Shape) selected_shape_parent; % (Shape) end properties ( SetAccess = 'private', GetAccess = 'public' ) body; % (ComplexShape) controls_pane; % (ControlsPane) details_pane; % (DetailsPane) materials; % ({ShapeMaterial}) navigator_pane; % (NavigatorPane) viewing_pane; % (ViewingPane) world_origin; % (CoordSystem) log_filename; % (char) end properties ( SetAccess = 'private', GetAccess = 'public', Constant = true ) mass_units = 'kg'; length_units = 'm'; rotation_type = 'Euler X-Y-Z'; rotation_units = 'rad'; time_units = 'sec'; end properties ( SetAccess = 'private', GetAccess = 'private' ) body_dir; % (char) body_name; % (char) frame; % (javax.swing.JFrame) is_dirty; % (logical) title; % (char) end methods
Constructor
function obj = BodyBuilder(varargin) % TBD. The plan is to substitute the current approach to logging % diagnostics to a known filename (using Log.msg) to one that uses a % tempname generated when an instance of BodyBuilder is created. % if (nargin == 0) && isa(varargin{1},'logical') && varargin{1} % obj.log_filename = fullfile(tempname,'.log'); % end % if ~isempty(obj.log_filename) % fid = fopen(obj.log_filename,'a'); % fprintf(fid,sprintf('%s::%s',mfilename,mfilename)); % fclose(fid); % end % Attempt to delete Log file for fresh start try delete(Log.filename); catch %#ok<CTCH> end Log.msg(sprintf('\n%s::%s',mfilename,mfilename)); % Load in the callback function handles fh = svSupport(); % Construct Library of Materials % material name, density (kg/m^3), youngsmodulus (MPa), poissons ratio, ambient, emissive, diffuse, specular, (1-128) dull -to- shiny materials = cell(0); materials{end+1} = ShapeMaterial('material_name','Aluminum',... 'density',2700,... 'youngs_modulus',68,... 'poissons_ratio',0.33,... 'ambientColor',[0.6602 0.6719 0.7109],... 'emissiveColor',[0.6602 0.6719 0.7109],... 'diffuseColor',[0 0 0],... 'specularColor',[1 1 1],... 'shininess',100); materials{end+1} = ShapeMaterial('material_name','Steel',... 'density',7800,... 'youngs_modulus',200,... 'poissons_ratio',0.3,... 'ambientColor',[0.4805 0.4063 0.9297],... 'emissiveColor',[0.4805 0.4063 0.9297],... 'diffuseColor',[0 0 0],... 'specularColor',[1 1 1],... 'shininess',100); materials{end+1} = ShapeMaterial('material_name','Platinum',... 'ambientColor',[0.984 0.8008 0.9641],... 'emissiveColor',[0.984 0.8008 0.9641],... 'diffuseColor',[0 0 0],... 'specularColor',[1 1 1],... 'shininess',100); materials{end+1} = ShapeMaterial('material_name','Plastic',... 'ambientColor',[0.1984 0.8008 0.4641],... 'emissiveColor',[0.1984 0.8008 0.4641],... 'diffuseColor',[0 0 0],... 'specularColor',[1 1 1],... 'shininess',100); materials{end+1} = ShapeMaterial('material_name','Rubber',... 'ambientColor',[0.1984 0.1008 0.1641],... 'emissiveColor',[0.1984 0.1008 0.1641],... 'diffuseColor',[0 0 0],... 'specularColor',[1 1 1],... 'shininess',100); materials{end+1} = ShapeMaterial('material_name','Titanium',... 'density',4500,... 'youngs_modulus',116,... 'poissons_ratio',0.34,... 'ambientColor',[0.3984 0.8008 0.6641],... 'emissiveColor',[0.3984 0.8008 0.6641],... 'diffuseColor',[0 0 0],... 'specularColor',[1 1 1],... 'shininess',100); materials{end+1} = ShapeMaterial('material_name','Wood',... 'ambientColor',[0.7984 0.8008 0.2641],... 'emissiveColor',[0.7984 0.8008 0.2641],... 'diffuseColor',[0 0 0],... 'specularColor',[1 1 1],... 'shininess',100); obj.materials = materials; % Initialize default directory for body obj.body_dir = pwd; % Define the world origin. world_origin = CoordSystem('name','World.Origin',... 'origin',[0 0 0],'orientation',[0 0 0],'is_deletable',false); world_origin.change_origin_visible(true); % This is used to place a small sphere at the origin to symbolize World Origin. obj.world_origin = world_origin; % Introduce the top-level ComplexShape body = ComplexShape('name','body'); % When a shape is created, an Origin CoordSystem is created. % Normally, the reference_CS for an Origin CoordSystem is set when % the Shape is attached to a ComplexShape. Here, we are dealing % with the top-level Shape, so the reference_CS is set to the world % origin. body.coord_system{1}.reference_CS = world_origin; obj.body = body; % Setting the reference_CS for a CoordSystem also links the two % CoordSystems in terms of behavior (the BranchGroup of % coord_system{1}'s Triad becomes a child of the TransformGroup of % world_origin's Triad). In order to get the whole system in the % SceneGraph, we need to attach the BranchGroup of the % world_origin's Triad to body_TransformGroup, which is a property % of ViewingPane. This is done in the CreateSceneGraph method of % ViewingPane. % Build the Gui [frame paneObjects] = obj.build_gui(fh); obj.frame = frame; obj.controls_pane = paneObjects{1}; obj.viewing_pane = paneObjects{2}; obj.details_pane = paneObjects{3}; obj.navigator_pane = paneObjects{4}; % Add the body to the tree obj.navigator_pane.add_shape_to_navigatorPane(body,[]); % Add the block name to the title of the Gui obj.title = ['Body Builder: ' body.name]; % Don't return anything if there is no LHS argument. % if (nargout > 0) % varargout = obj; % end end
SET Methods
function set.active_shape_name(obj, in) prop_name = 'active_shape_name'; prop_type = 'char'; [valid_flag in] = Validate.ARRAY(in,'type',prop_type); if valid_flag obj.(prop_name) = in; end end function set.body(obj,a_body) if ~isempty(a_body) && ~isa(a_body,'ComplexShape') error('%s: set.body. Expected a ComplexShape object',mfilename); else % Clear the body. obj.body = a_body; obj.is_dirty = false; obj.body_name = ''; % Make all necessary updates to Panes. if ~isempty(obj.viewing_pane) obj.viewing_pane.detach_body; end if ~isempty(obj.navigator_pane) obj.navigator_pane.clear_tree; end end if isa(a_body,'ComplexShape') obj.body_name = [a_body.name '.body']; % Are we in the initialization stage? Check to see if ViewingPane % and NavigatorPane have been created. if ~isempty(obj.viewing_pane) && ~isempty(obj.navigator_pane) obj.add_shape(a_body, true); % true ==> add to top level end end end function set.body_dir(obj, in) prop_name = 'body_dir'; prop_type = 'char'; [valid_flag in] = Validate.ARRAY(in,'type',prop_type); if valid_flag obj.(prop_name) = in; end end function set.body_name(obj, in) prop_name = 'body_name'; prop_type = 'char'; [valid_flag in] = Validate.ARRAY(in,'type',prop_type); if valid_flag % Substitute underscores for spaces obj.(prop_name) = strrep(in,' ','_'); end end function set.controls_pane(obj, in) prop_name = 'controls_pane'; prop_type = 'ControlsPane'; [valid_flag in] = Validate.SCALAR(in,'type',prop_type); if valid_flag obj.(prop_name) = in; end end function set.details_pane(obj, in) prop_name = 'details_pane'; prop_type = 'DetailsPane'; [valid_flag in] = Validate.SCALAR(in,'type',prop_type); if valid_flag obj.(prop_name) = in; end end function set.frame(obj, in) prop_name = 'frame'; prop_type = 'javax.swing.JFrame'; [valid_flag in] = Validate.SCALAR(in,'type',prop_type); if valid_flag obj.(prop_name) = in; end end function set.is_dirty(obj, in) prop_name = 'is_dirty'; prop_type = 'logical'; [valid_flag in] = Validate.SCALAR(in,'type',prop_type); if valid_flag obj.(prop_name) = in; end end function set.materials(obj, in) prop_name = 'materials'; prop_type = 'ShapeMaterial'; [valid_flag in] = Validate.ARRAY(in,'type',prop_type,'Cell',true); if valid_flag obj.(prop_name) = in; end end function set.navigator_pane(obj, in) prop_name = 'navigator_pane'; prop_type = 'NavigatorPane'; [valid_flag in] = Validate.SCALAR(in,'type',prop_type); if valid_flag obj.(prop_name) = in; end end function set.title(obj, in) prop_name = 'title'; prop_type = 'char'; [valid_flag in] = Validate.ARRAY(in,'type',prop_type); if valid_flag obj.(prop_name) = in; obj.frame.setTitle(in); end end function set.viewing_pane(obj, in) prop_name = 'viewing_pane'; prop_type = 'ViewingPane'; [valid_flag in] = Validate.SCALAR(in,'type',prop_type); if valid_flag obj.(prop_name) = in; end end function set.world_origin(obj, in) prop_name = 'world_origin'; prop_type = 'CoordSystem'; [valid_flag in] = Validate.SCALAR(in,'type',prop_type); if valid_flag obj.(prop_name) = in; end end
GET Methods
function tree = get.tree(obj) % tree = obj.navigator_pane.pane.getComponent(0); % When JPanel is used tree = obj.navigator_pane.pane.getComponent(0).getComponent(0); % When JScrollPane is used end function tree_model = get.tree_model(obj) tree_model = obj.tree.getModel; end function selected_path = get.selected_path(obj) selected_path = obj.tree.getSelectionPath; end function selected_node = get.selected_node(obj) selected_node = obj.selected_path.getLastPathComponent; end function selected_shape = get.selected_shape(obj) selected_path = obj.selected_path; hierarchy = selected_path.toString.toCharArray; hierarchy = hierarchy(2:end-1)'; % The hierarchy, which is a comma delimited char array provides the % linkage top down from the Body to the selected shape. % Create a cell array (shape_hierarchy) from the char array % (hierarchy). The format of shape_hierarchy is a cell array such % as {'Car','Frame','Front_Axle'}. pattern = '([^\s,][^,]+)'; shape_hierarchy = regexp(hierarchy,pattern,'tokens'); % March down to the selected shape. current_shape = obj.body; for ii = 1:length(shape_hierarchy)-1 % Find matching Shape name within the current parent's array of % Shapes parent_shape = current_shape; current_shape = parent_shape.retrieve_child_from_name(shape_hierarchy{ii+1}); end selected_shape = current_shape; end function selected_shape_parent = get.selected_shape_parent(obj) selected_path = obj.selected_path; hierarchy = selected_path.toString.toCharArray; hierarchy = hierarchy(2:end-1)'; % The hierarchy, which is a comma delimited char array provides the % linkage top down from the Body to the selected shape. % Create a cell array (shape_hierarchy) from the char array % (hierarchy). The format of shape_hierarchy is a cell array such % as {'Car','Frame','Front_Axle'}. pattern = '([^\s,][^,]+)'; shape_hierarchy = regexp(hierarchy,pattern,'tokens'); % March down to the selected shape. current_shape = obj.body; parent_shape = current_shape; for ii = 1:length(shape_hierarchy)-2 % Find matching Shape name within the current parent's array of % Shapes current_shape = parent_shape.retrieve_child_from_name(shape_hierarchy{ii+1}); parent_shape = current_shape; end selected_shape_parent = parent_shape; end
Public HELPER Methods
function add_shape(obj, the_shape, topLevel_flag) if isempty(the_shape) % No shape for some reason. Should never reach this point. error('%s: add_shape. Expected to add shape to %s, but none provided',mfilename, obj.active_shape_name); else if nargin > 2 && topLevel_flag % Need to add to top level the_shape.coord_system{1}.reference_CS = obj.world_origin; for ii = 1:the_shape.n_coord_system the_shape.coord_system{ii}.triad.length = obj.world_origin.triad.length; end else parent_shape = obj.selected_shape; if isa(parent_shape,'PrimitiveShape') % Warn that parent is a primitive shape if that is the case warning('Can only add Shapes to Shape Assemblies'); %#ok<WNTAG> return else % This fully defines the Shape's first CoordSystem the_shape.coord_system{1}.reference_CS = parent_shape.coord_system{1}; for ii = 1:the_shape.n_coord_system the_shape.coord_system{ii}.triad.length = obj.world_origin.triad.length; end % Update the Body parent_shape.add_child(the_shape); end end end % Update dirty status obj.is_dirty = true; % Update the Navigator pane obj.navigator_pane.add_shape_to_navigatorPane(the_shape,[]); end function remove_shape(obj, the_shape) % Remove the_shape from its parent shape. the_parent_shape = obj.selected_shape_parent; the_parent_shape.remove_child(the_shape); % Remove the_shape from NavigatorPane the_parent_path = obj.selected_path.getParentPath; node_to_remove = obj.selected_node; obj.tree.getModel.removeNodeFromParent(node_to_remove); % Select the parent obj.tree.setSelectionPath(the_parent_path); % Remove the_shape from ViewingPane by detaching the_shape's % BranchGroup from its parent's TransformGroup. the_BranchGroup = the_shape.BranchGroup; the_TransformGroup = the_BranchGroup.getParent; for ii = 0:the_TransformGroup.numChildren-1 if the_TransformGroup.getChild(ii).equals(the_BranchGroup) the_TransformGroup.removeChild(ii); break end end % Delete the_shape and everything underneath. delete(the_shape); end function change_shape_name(obj, tree) selected_path = tree.getSelectionPath; selected_node = selected_path.getLastPathComponent; the_parent = selected_node.getParent; if(isempty(the_parent)) % This is the body the_child = obj.body; else for ii = 1:the_parent.getChildCount if the_parent.getChildAt(ii-1) == selected_node idx = ii; break; end end the_parent_shape = obj.selected_shape_parent; the_child = the_parent_shape.children{idx}; end child_name = selected_node.toString.toCharArray; the_child.name = child_name(:)'; end function add_materials(obj,a_material) the_materials = obj.materials; the_materials{end+1} = a_material; obj.materials = the_materials; end function append_body_materials(obj,the_body) % Check for new materials and add to Material library if necessary % TBD end function body = open_body(obj) body = []; [pathstr, name, ext] = fileparts(obj.body_name); file_filter = [obj.body_dir '\*' ext]; [filename, pathname] = uigetfile(file_filter, 'Select the Body File'); if ~isequal(filename,0) try obj.body_dir = pathname; tmp = load(fullfile(pathname,filename),'-mat'); % Returns body % Get the name of the body and store its contents in body if isstruct(tmp) fn = fieldnames(tmp); if ~isempty(fn) body_candidate = tmp.(fn{1}); if isa(body_candidate,'ComplexShape') body = body_candidate; end end end catch ME % Get last segment of the error message identifier. idSegLast = regexp(ME.identifier, '(?<=:)\w+$', 'match'); error(idSegLast{:}); end end end function status = check_to_save(the_bodyBuilder) % See if session is dirty if the_bodyBuilder.is_dirty question = sprintf('Do you want to save the changes made to %s?',the_bodyBuilder.body_name); dlg = javaObjectEDT('javax.swing.JOptionPane'); status = dlg.showConfirmDialog(javaObjectEDT('javax.swing.JFrame'), ... question,'Exit',dlg.YES_NO_CANCEL_OPTION); else status = []; end end function export_to_xml(obj, the_body, xmlFilePath) % Create a DOM node for the .xml document that will be imported % using import_physmod. name = ['"' the_body.name '"']; the_coord_systems = the_body.coord_system; % <?xml version="1.0"?> doc_Node = com.mathworks.xml.XMLUtils.createDocument('PhysicalModelingXMLFile'); % doc_Node (Document interface) represents the entire XML % document. Conceptually, it is the root of the document tree, % and provides the primary access to the document's data. root_Node = doc_Node.getDocumentElement; % <formatVersion> thisElement = doc_Node.createElement('formatVersion'); thisElement.appendChild(doc_Node.createTextNode('"1.0.2"')); root_Node.appendChild(thisElement); % <creationDate> thisElement = doc_Node.createElement('creationDate'); thisElement.appendChild(doc_Node.createTextNode(datestr(now))); root_Node.appendChild(thisElement); % <createdBy> thisElement = doc_Node.createElement('createdBy'); thisElement.appendChild(doc_Node.createTextNode(getenv('user'))); root_Node.appendChild(thisElement); % <modelName> thisElement = doc_Node.createElement('modelName'); thisElement.appendChild(doc_Node.createTextNode(name)); root_Node.appendChild(thisElement); % <subsystem> subsystemElement = doc_Node.createElement('subsystem'); root_Node.appendChild(subsystemElement); % <Subsystem> SubsystemElement = doc_Node.createElement('Subsystem'); subsystemElement.appendChild(SubsystemElement); % <name> thisElement = doc_Node.createElement('name'); thisElement.appendChild(doc_Node.createTextNode(name)); SubsystemElement.appendChild(thisElement); % <status> thisElement = doc_Node.createElement('status'); thisElement.appendChild(doc_Node.createTextNode('')); SubsystemElement.appendChild(thisElement); % <bodies> bodiesElement = doc_Node.createElement('bodies'); SubsystemElement.appendChild(bodiesElement); % <Body> BodyElement = doc_Node.createElement('Body'); bodiesElement.appendChild(BodyElement); % <name> thisElement = doc_Node.createElement('name'); thisElement.appendChild(doc_Node.createTextNode(name)); BodyElement.appendChild(thisElement); % <status> thisElement = doc_Node.createElement('status'); thisElement.appendChild(doc_Node.createTextNode('""')); BodyElement.appendChild(thisElement); % <mass> thisElement = doc_Node.createElement('mass'); thisElement.appendChild(doc_Node.createTextNode(num2str(the_body.mass))); % E.g. num2str(the_body.mass) BodyElement.appendChild(thisElement); % <massUnits> thisElement = doc_Node.createElement('massUnits'); thisElement.appendChild(doc_Node.createTextNode(sprintf('"%s"',BodyBuilder.mass_units))); % E.g. "kg" BodyElement.appendChild(thisElement); % <inertia> thisElement = doc_Node.createElement('inertia'); inertia_matrix = the_body.moment_of_inertia_about_CG; thisElement.appendChild(doc_Node.createTextNode(sprintf('%f,%f,%f,%f,%f,%f,%f,%f,%f',inertia_matrix'))); BodyElement.appendChild(thisElement); % <inertiaUnits> thisElement = doc_Node.createElement('inertiaUnits'); thisElement.appendChild(doc_Node.createTextNode(sprintf('"%s*%s^2"',BodyBuilder.mass_units,BodyBuilder.length_units))); BodyElement.appendChild(thisElement); % <volume> thisElement = doc_Node.createElement('volume'); thisElement.appendChild(doc_Node.createTextNode(num2str(the_body.volume))); BodyElement.appendChild(thisElement); % <volumeUnits> thisElement = doc_Node.createElement('volumeUnits'); thisElement.appendChild(doc_Node.createTextNode(sprintf('"%s^3"',BodyBuilder.length_units))); BodyElement.appendChild(thisElement); % <surfaceArea> thisElement = doc_Node.createElement('surfaceArea'); thisElement.appendChild(doc_Node.createTextNode(num2str(1))); % E.g. 0 BodyElement.appendChild(thisElement); % <surfaceAreaUnits> thisElement = doc_Node.createElement('surfaceAreaUnits'); thisElement.appendChild(doc_Node.createTextNode(sprintf('"%s^2"',BodyBuilder.length_units))); BodyElement.appendChild(thisElement); % <frames> framesElement = doc_Node.createElement('frames'); BodyElement.appendChild(framesElement); % If the selected body is a complex shape, also add CG to the % list. if(isa(the_body,'ComplexShape')) cs = the_body.center_of_mass; % <Frame> FrameElement = doc_Node.createElement('Frame'); framesElement.appendChild(FrameElement); % <name> thisElement = doc_Node.createElement('name'); thisElement.appendChild(doc_Node.createTextNode(sprintf('"%s"','CG'))); % E.g. "CSO", "CG" FrameElement.appendChild(thisElement); % <position> thisElement = doc_Node.createElement('position'); thisElement.appendChild(doc_Node.createTextNode(sprintf('%f,%f,%f',cs.origin))); % E.g. 0,0,0 FrameElement.appendChild(thisElement); % <positionOrigin> thisElement = doc_Node.createElement('positionOrigin'); thisElement.appendChild(doc_Node.createTextNode(sprintf('"%s"',obj.convert_name(cs.reference_CS.name)))); % E.g. "WORLD" FrameElement.appendChild(thisElement); % <positionReferenceFrame> thisElement = doc_Node.createElement('positionReferenceFrame'); thisElement.appendChild(doc_Node.createTextNode(sprintf('"%s"',obj.convert_name(cs.reference_CS.name)))); % E.g. "WORLD" FrameElement.appendChild(thisElement); % <positionUnits> thisElement = doc_Node.createElement('positionUnits'); thisElement.appendChild(doc_Node.createTextNode(sprintf('"%s"',BodyBuilder.length_units))); % E.g. "m" FrameElement.appendChild(thisElement); % <orientation> thisElement = doc_Node.createElement('orientation'); rotation_matrix = CoordSystem.EulerXYZ_to_DirCosineMatrix(cs.orientation); thisElement.appendChild(doc_Node.createTextNode(sprintf('%f,%f,%f,%f,%f,%f,%f,%f,%f',rotation_matrix))); % E.g. 1,0,0,0,1,0,0,0,1 FrameElement.appendChild(thisElement); % <orientationType> thisElement = doc_Node.createElement('orientationType'); thisElement.appendChild(doc_Node.createTextNode(sprintf('"3x3 Transform"'))); % E.g. "Euler X-Y-Z" FrameElement.appendChild(thisElement); % <orientationUnits> thisElement = doc_Node.createElement('orientationUnits'); thisElement.appendChild(doc_Node.createTextNode(sprintf('"%s"',BodyBuilder.rotation_units))); % E.g. "rad" FrameElement.appendChild(thisElement); % <orientationReferenceFrame> thisElement = doc_Node.createElement('orientationReferenceFrame'); thisElement.appendChild(doc_Node.createTextNode(sprintf('"%s"',obj.convert_name(cs.reference_CS.name)))); % E.g. "WORLD" FrameElement.appendChild(thisElement); end for ii = 1:length(the_coord_systems) cs = the_coord_systems{ii}; cs_name = cs.name; % Note: Here we are only calculating coordinate values as if % the reference CS is changed. We do not actually change % the reference CS. This is because after exporting, we % still want to maintain the reference CSs as given by the % user and continue with his bodybuilding:) if(strcmp(cs.name,'Origin')) % origin CS is always w.r.to its parent's origin. So % calculate the CS coordinates so that its new reference CS is % World Origin. [cs_origin cs_orientation] = cs.convert_local_coordinates_to_world; ref_CS_name = 'World.Origin'; elseif(~isequal(cs.parent_shape,cs.reference_CS.parent_shape)) [cs_origin cs_orientation] = cs.convert_coordinates_wrt_new_refCS(the_coord_systems{1}); ref_CS_name = 'Origin'; else cs_origin = cs.origin; cs_orientation = cs.orientation; ref_CS_name = cs.reference_CS.name; end % <Frame> FrameElement = doc_Node.createElement('Frame'); framesElement.appendChild(FrameElement); % <name> thisElement = doc_Node.createElement('name'); thisElement.appendChild(doc_Node.createTextNode(sprintf('"%s"',obj.convert_name(cs_name)))); % E.g. "CSO", "CG" FrameElement.appendChild(thisElement); % <position> thisElement = doc_Node.createElement('position'); thisElement.appendChild(doc_Node.createTextNode(sprintf('%f,%f,%f',cs_origin))); % E.g. 0,0,0 FrameElement.appendChild(thisElement); % <positionOrigin> thisElement = doc_Node.createElement('positionOrigin'); thisElement.appendChild(doc_Node.createTextNode(sprintf('"%s"',obj.convert_name(ref_CS_name)))); % E.g. "WORLD" FrameElement.appendChild(thisElement); % <positionReferenceFrame> thisElement = doc_Node.createElement('positionReferenceFrame'); thisElement.appendChild(doc_Node.createTextNode(sprintf('"%s"',obj.convert_name(ref_CS_name)))); % E.g. "WORLD" FrameElement.appendChild(thisElement); % <positionUnits> thisElement = doc_Node.createElement('positionUnits'); thisElement.appendChild(doc_Node.createTextNode(sprintf('"%s"',BodyBuilder.length_units))); % E.g. "m" FrameElement.appendChild(thisElement); % <orientation> thisElement = doc_Node.createElement('orientation'); rotation_matrix = CoordSystem.EulerXYZ_to_DirCosineMatrix(cs_orientation); thisElement.appendChild(doc_Node.createTextNode(sprintf('%f,%f,%f,%f,%f,%f,%f,%f,%f',rotation_matrix))); % E.g. 1,0,0,0,1,0,0,0,1 FrameElement.appendChild(thisElement); % <orientationType> thisElement = doc_Node.createElement('orientationType'); thisElement.appendChild(doc_Node.createTextNode(sprintf('"3x3 Transform"'))); % E.g. "Euler X-Y-Z" FrameElement.appendChild(thisElement); % <orientationUnits> thisElement = doc_Node.createElement('orientationUnits'); thisElement.appendChild(doc_Node.createTextNode(sprintf('"%s"',BodyBuilder.rotation_units))); % E.g. "rad" FrameElement.appendChild(thisElement); % <orientationReferenceFrame> thisElement = doc_Node.createElement('orientationReferenceFrame'); thisElement.appendChild(doc_Node.createTextNode(sprintf('"%s"',obj.convert_name(ref_CS_name)))); % E.g. "WORLD" FrameElement.appendChild(thisElement); end % <connectionPorts> thisElement = doc_Node.createElement('connectionPorts'); SubsystemElement.appendChild(thisElement); % <id> thisElement = doc_Node.createElement('id'); thisElement.appendChild(doc_Node.createTextNode(num2str(0))); % E.g. 0 SubsystemElement.appendChild(thisElement); xmlwrite(xmlFilePath,doc_Node); end function export_to_stl(obj, the_body, stlFilePath) % Export to .stl document that will be available for use within % SimMechanics. % solid robot - forearm-1 % facet normal -8.742778e-001 0.000000e+000 4.854259e-001 % outer loop % vertex 1.687836e-001 1.489590e-001 8.808903e-004 % vertex 1.686560e-001 1.489590e-001 6.350000e-004 % vertex 1.687836e-001 1.483240e-001 8.808903e-004 % endloop % endfacet % endsolid [vertexInfo normalInfo] = the_body.get_vertex_info; fid = fopen(stlFilePath, 'wt'); fprintf(fid, 'solid %s\n', the_body.name); for ii = 1:n_facets fprintf(fid, '\tfacet normal %13.5e\n', normalInfo(ii,:)); fprintf(fid, '\t\touter loop\n'); for jj = 1:3 fprintf(fid, '\t\t\tvertex %13.5e\n', vertexInfo(jj,:)); end fprintf(fid, '\t\tendloop\n'); fprintf(fid, '\tendfacet\n'); end fprintf(fid, 'endsolid\n'); fclose(fid) end
end methods ( Access = 'private' )
Private HELPER Methods
function [frame paneObjects] = build_gui(obj,fh) % Create Frame frame = javaObjectEDT('javax.swing.JFrame'); % Position the Frame set(0,'Units','pixels'); screenSize = get(0,'ScreenSize'); topMargin = 10; bottomMargin = 10; leftMargin = 10; rightMargin = 10; width = screenSize(3) - leftMargin - rightMargin; height = screenSize(4) - topMargin - bottomMargin; frame.setBounds(leftMargin, topMargin, width, height); % Add the Icon icon_file = fullfile(matlabroot,'toolbox','matlab','icons','matlabicon.gif'); icon = javaObjectEDT('javax.swing.ImageIcon',icon_file); frame.setIconImage(icon.getImage()); % Create Menu bar obj.create_menu_bar(frame,fh); % Create panes cp = frame.getContentPane; cp.setLayout(java.awt.GridBagLayout); paneObjects{1} = ControlsPane(obj); paneObjects{2} = ViewingPane(obj); paneObjects{3} = DetailsPane(obj); paneObjects{4} = NavigatorPane(obj); pane_size_pref_width = [50 150 150 50]; pane_size_pref_height = [100 300 200 400]; panes = cell(length(paneObjects),1); for ii = 1:length(paneObjects) panes{ii} = paneObjects{ii}.pane(); panes{ii}.setPreferredSize(... java.awt.Dimension(pane_size_pref_width(ii),pane_size_pref_height(ii))) end % Add panes to frame % Preferred layout dimensions pref.gridx = [0 1 1 0]; pref.gridy = [0 0 3 1]; pref.gridwidth = [1 3 3 1]; pref.gridheight = [1 3 2 4]; pref.weightx = [1 5 5 1]; pref.weighty = [0 3 0 4]; gb = javaObjectEDT('java.awt.GridBagConstraints'); gb.fill = gb.BOTH; % components grow in both dimensions gb.insets = java.awt.Insets(5, 5, 5, 5); % 5-pixel margins on all sides for ii = 1:length(panes) gb.gridx = pref.gridx(ii); gb.gridy = pref.gridy(ii); gb.gridheight = pref.gridheight(ii); gb.gridwidth = pref.gridwidth(ii); gb.weightx = pref.weightx(ii); gb.weighty = pref.weighty(ii); cp.add(panes{ii}, gb); end % Update the frame and show it javax.swing.UIManager.setLookAndFeel( ... javax.swing.UIManager.getSystemLookAndFeelClassName()); javax.swing.SwingUtilities.updateComponentTreeUI(frame); % frame.pack frame.setVisible(true) end function menu_bar = create_menu_bar(obj, frame, fh) import java.awt.event.*; menu_bar = javaObjectEDT('javax.swing.JMenuBar'); frame.setJMenuBar(menu_bar); % ===================================================== % Create a File menu file_menu = javaObjectEDT('javax.swing.JMenu','File'); file_menu.setMnemonic('F'); menu_bar.add(file_menu); % New Body BodyBuilder.add_menu_item(file_menu,'New Body',... {fh.new_body_ActionPerformedCallback,obj,frame},... KeyEvent.VK_N,KeyEvent.VK_N); % Open Body BodyBuilder.add_menu_item(file_menu,'Open Body',... {fh.open_body_ActionPerformedCallback,obj,frame},... KeyEvent.VK_O,KeyEvent.VK_O); % % Import Body From VRML % BodyBuilder.add_menu_item(file_menu,'(TBD)Import Body from VRML',... % {fh.importVRML_ActionPerformedCallback,obj,frame},... % KeyEvent.VK_I,KeyEvent.VK_I); % Separator file_menu.addSeparator(); % Save Body BodyBuilder.add_menu_item(file_menu,'Save Body',... {fh.save_body_ActionPerformedCallback,obj,frame},... KeyEvent.VK_S,KeyEvent.VK_S); % Save Body As... BodyBuilder.add_menu_item(file_menu,'Save Body As..',... {fh.save_body_as_ActionPerformedCallback,obj,frame}); % Save Selected Body As... BodyBuilder.add_menu_item(file_menu,'Save Selected Body As..',... {fh.save_selected_body_as_ActionPerformedCallback,obj,frame}); % Separator file_menu.addSeparator(); % Close BodyBuilder.add_menu_item(file_menu,'Close Body Builder',... {fh.close_ActionPerformedCallback,obj,frame},... KeyEvent.VK_C,KeyEvent.VK_C); % ===================================================== % Create a Edit menu edit_menu = javaObjectEDT('javax.swing.JMenu','Edit'); edit_menu.setMnemonic('E'); menu_bar.add(edit_menu); % Attach a Body BodyBuilder.add_menu_item(edit_menu,'Attach a Body',... {fh.attach_body_ActionPerformedCallback,obj,frame},... KeyEvent.VK_A,KeyEvent.VK_A); % ===================================================== % Create a View menu view_menu = javaObjectEDT('javax.swing.JMenu','View'); view_menu.setMnemonic('V'); menu_bar.add(view_menu); % World Axes Display Setting BodyBuilder.add_menu_item(view_menu,'Toggle World Axes Display',... {fh.worldAxesDisplay_ActionPerformedCallback,obj,frame},... KeyEvent.VK_W,KeyEvent.VK_W); % Body Axes Display Setting BodyBuilder.add_menu_item(view_menu,'Toggle Body Axes Display',... {fh.bodyAxesDisplay_ActionPerformedCallback,obj,frame},... KeyEvent.VK_B,KeyEvent.VK_B); % Separator view_menu.addSeparator(); % Axes Length Setting BodyBuilder.add_menu_item(view_menu,'Set Axes Length',... {fh.axesLength_ActionPerformedCallback,obj,frame},... KeyEvent.VK_L,KeyEvent.VK_L); % ===================================================== % Create a Tools menu tools_menu = javaObjectEDT('javax.swing.JMenu','Tools'); tools_menu.setMnemonic('T'); menu_bar.add(tools_menu); % Export to SimMechanics BodyBuilder.add_menu_item(tools_menu,'Export to SimMechanics',... {fh.export2SM_ActionPerformedCallback,obj,frame},... KeyEvent.VK_E,KeyEvent.VK_E); % Export Selected Body to SimMechanics BodyBuilder.add_menu_item(tools_menu,'Export Selected Body to SimMechanics',... {fh.exportSelBody2SM_ActionPerformedCallback,obj,frame}); % Separator tools_menu.addSeparator(); % Export to XML BodyBuilder.add_menu_item(tools_menu,'Export to XML',... {fh.export2XML_ActionPerformedCallback,obj,frame}); % Export Selected Body to XML BodyBuilder.add_menu_item(tools_menu,'Export Selected Body to XML',... {fh.exportSelBody2XML_ActionPerformedCallback,obj,frame}); % Separator % tools_menu.addSeparator(); % Export to STL File % BodyBuilder.add_menu_item(tools_menu,'Export to STL',... % {fh.export2STL_ActionPerformedCallback,obj,frame}); % Export Selected Body to STL % BodyBuilder.add_menu_item(tools_menu,'Export Selected Body to STL',... % {fh.exportSelBody2STL_ActionPerformedCallback,obj,frame}); % Separator % tools_menu.addSeparator(); % Export to VRML % BodyBuilder.add_menu_item(tools_menu,'Export to VRML',... % {fh.export2VRML_ActionPerformedCallback,obj,frame},... % KeyEvent.VK_V,KeyEvent.VK_V); % % Export Selected Body to VRML % BodyBuilder.add_menu_item(tools_menu,'Export to VRML',... % {fh.exportSelBody2VRML_ActionPerformedCallback,obj,frame}); % Separator tools_menu.addSeparator(); % Display CoordSystem Ancestry BodyBuilder.add_menu_item(tools_menu,'Display CoordSystem Ancestry',... {fh.display_cs_ancestry,obj,frame}); % % DEBUG % BodyBuilder.add_menu_item(tools_menu,'DEBUG',... % {fh.debug_ActionPerformedCallback,obj,frame},... % KeyEvent.VK_D,KeyEvent.VK_D); % ===================================================== % Create a Help menu help_menu = javaObjectEDT('javax.swing.JMenu','Help'); help_menu.setMnemonic('H'); menu_bar.add(help_menu); % Help (F1) % BodyBuilder.add_menu_item(help_menu,'Help with Body Builder',... % {fh.help_ActionPerformedCallback,obj,frame},... % KeyEvent.VK_H,KeyEvent.VK_H); menu_item = javaObjectEDT('javax.swing.JMenuItem','Help with Body Builder'); menu_item.setAccelerator(javax.swing.KeyStroke.getKeyStroke('F1')); set(handle(menu_item, 'CallbackProperties'),'ActionPerformedCallback',{fh.help_ActionPerformedCallback,obj,frame}); help_menu.add(menu_item); end function new_name = convert_name(obj,cur_name) % To stay within the convention of SimMechanics, we need to % rename the_body's origin to CS0 and World.Origin to % WORLD. switch cur_name case obj.world_origin.name new_name = 'World'; case 'Origin' % case [obj.body.name '.Origin'] new_name = 'CS0'; otherwise % [tmp dot_name] = strtok(cur_name,'.'); % new_name = dot_name(2:end); new_name = cur_name; end end
end methods ( Access = 'private', Static = true )
Static Private HELPER Methods
function add_menu_item(menu,label,callback,mnemonic,accelerator) if nargin > 3 % Then set a mnemonic for the menu item menu_item = javaObjectEDT('javax.swing.JMenuItem',label,mnemonic); if nargin > 4 % Then set an accelerator for the menu item keystroke = javax.swing.KeyStroke.getKeyStroke( ... accelerator,java.awt.event.ActionEvent.CTRL_MASK); menu_item.setAccelerator(keystroke) end else menu_item = javaObjectEDT('javax.swing.JMenuItem',label); end set(handle(menu_item, 'CallbackProperties'),'ActionPerformedCallback',callback); menu.add(menu_item); end
end
end