opensim-gui icon indicating copy to clipboard operation
opensim-gui copied to clipboard

`PhysicalOffsetFrame`s are ignored when rendering `GeometryPath`s

Open adamkewley opened this issue 8 months ago • 1 comments

A student reported that there's a rendering difference between OpenSim Creator and OpenSim for the same model. For context, they added a PhysicalOffsetFrame to an existing model and then placed Stations for a Ligament w.r.t. that offset frame (because the frame was a relevant coordinate system from external data, or similar)

Steps to reproduce

The model source code below renders differently in OSC vs OpenSim GUI due to this issue. Model description

  • Added a PhysicalOffsetFrame connected to ground (ground_offsetframe) and offset at X=0.25
  • Added a Body connected with a WeldJoint where the WeldJoint's parent offset frame (weldjoint/ground_offset) was set to Z=0.25
  • Created a muscle (Millard2012EquilibriumMuscle) where both muscle points are defined at Y=0.25 in their respective frames. One muscle point was attached to ground_offsetframe (Millard2012EquilibriumMuscle-P2) and the second muscle point was attached to new_body (Millard2012EquilibriumMuscle-P1)

Expected result

  • Millard2012EquilibriumMuscle-P2 will appear at (0.25, 0.25, 0.0)
  • Millard2012EquilibriumMuscle-P1 will appear at (0.0, 0.25, 0.25)

Actual result

  • Millard2012EquilibriumMuscle-P2 appears at (0.0, 0.25, 0.0) (bad)
  • Millard2012EquilibriumMuscle-P1 appears at (0.0, 0.25, 0.25) (ok)

OSC:

image

OpenSim GUI 4.5:

image

Environment and GUI version

  • Windows /w a 4.5 released version of OpenSim

Comments

The source code for generating path point decorations (based on naming etc.) seems to imply that calling get_location on a PathPoint yields its location w.r.t. a body but it actually returns the location of a PathPoint w.r.t. its parent frame, which may be (e.g. here) a PhysicalOffsetFrame):

  • https://github.com/opensim-org/opensim-gui/blob/4.5/Gui/opensim/view/src/org/opensim/threejs/ModelVisualizationJson.java#L1258

But I didn't get a chance to fully investigate it

Example Model

<?xml version="1.0" encoding="UTF-8" ?>
<OpenSimDocument Version="40600">
	<Model name="model">
		<!--List of components that this component owns and serializes.-->
		<components />
		<!--The model's ground reference frame.-->
		<Ground name="ground">
			<!--List of components that this component owns and serializes.-->
			<components>
				<PhysicalOffsetFrame name="ground_offsetframe">
					<!--The geometry used to display the axes of this Frame.-->
					<FrameGeometry name="frame_geometry">
						<!--Path to a Component that satisfies the Socket 'frame' of type Frame.-->
						<socket_frame>..</socket_frame>
						<!--Scale factors in X, Y, Z directions respectively.-->
						<scale_factors>0.20000000000000001 0.20000000000000001 0.20000000000000001</scale_factors>
					</FrameGeometry>
					<!--List of geometry attached to this Frame. Note, the geometry are treated as fixed to the frame and they share the transform of the frame when visualized-->
					<attached_geometry>
						<Sphere name="ground_offsetframe_geom_1">
							<!--Path to a Component that satisfies the Socket 'frame' of type Frame.-->
							<socket_frame>..</socket_frame>
							<!--Radius of sphere, defaults to 1.0-->
							<radius>0.05000000074505806</radius>
						</Sphere>
					</attached_geometry>
					<!--Path to a Component that satisfies the Socket 'parent' of type C (description: The parent frame to this frame.).-->
					<socket_parent>..</socket_parent>
					<!--Translational offset (in meters) of this frame's origin from the parent frame's origin, expressed in the parent frame.-->
					<translation>0.25 0 0</translation>
				</PhysicalOffsetFrame>
			</components>
			<!--The geometry used to display the axes of this Frame.-->
			<FrameGeometry name="frame_geometry">
				<!--Path to a Component that satisfies the Socket 'frame' of type Frame.-->
				<socket_frame>..</socket_frame>
				<!--Scale factors in X, Y, Z directions respectively.-->
				<scale_factors>0.20000000000000001 0.20000000000000001 0.20000000000000001</scale_factors>
			</FrameGeometry>
		</Ground>
		<!--List of bodies that make up this model.-->
		<BodySet name="bodyset">
			<objects>
				<Body name="new_body">
					<!--The geometry used to display the axes of this Frame.-->
					<FrameGeometry name="frame_geometry">
						<!--Path to a Component that satisfies the Socket 'frame' of type Frame.-->
						<socket_frame>..</socket_frame>
						<!--Scale factors in X, Y, Z directions respectively.-->
						<scale_factors>0.20000000000000001 0.20000000000000001 0.20000000000000001</scale_factors>
					</FrameGeometry>
					<!--List of geometry attached to this Frame. Note, the geometry are treated as fixed to the frame and they share the transform of the frame when visualized-->
					<attached_geometry>
						<Sphere name="new_body_geom_1">
							<!--Path to a Component that satisfies the Socket 'frame' of type Frame.-->
							<socket_frame>..</socket_frame>
							<!--Radius of sphere, defaults to 1.0-->
							<radius>0.05000000074505806</radius>
						</Sphere>
					</attached_geometry>
					<!--The mass of the body (kg)-->
					<mass>1</mass>
					<!--The location (Vec3) of the mass center in the body frame.-->
					<mass_center>0 0 0</mass_center>
					<!--The elements of the inertia tensor (Vec6) as [Ixx Iyy Izz Ixy Ixz Iyz] measured about the mass_center and not the body origin.-->
					<inertia>1 1 1 0 0 0</inertia>
				</Body>
			</objects>
			<groups />
		</BodySet>
		<!--List of joints that connect the bodies.-->
		<JointSet name="jointset">
			<objects>
				<WeldJoint name="weldjoint">
					<!--Path to a Component that satisfies the Socket 'parent_frame' of type PhysicalFrame (description: The parent frame for the joint.).-->
					<socket_parent_frame>ground_offset</socket_parent_frame>
					<!--Path to a Component that satisfies the Socket 'child_frame' of type PhysicalFrame (description: The child frame for the joint.).-->
					<socket_child_frame>new_body_offset</socket_child_frame>
					<!--Physical offset frames owned by the Joint that are typically used to satisfy the owning Joint's parent and child frame connections (sockets). PhysicalOffsetFrames are often used to describe the fixed transformation from a Body's origin to another location of interest on the Body (e.g., the joint center). When the joint is deleted, so are the PhysicalOffsetFrame components in this list.-->
					<frames>
						<PhysicalOffsetFrame name="ground_offset">
							<!--The geometry used to display the axes of this Frame.-->
							<FrameGeometry name="frame_geometry">
								<!--Path to a Component that satisfies the Socket 'frame' of type Frame.-->
								<socket_frame>..</socket_frame>
								<!--Scale factors in X, Y, Z directions respectively.-->
								<scale_factors>0.20000000000000001 0.20000000000000001 0.20000000000000001</scale_factors>
							</FrameGeometry>
							<!--Path to a Component that satisfies the Socket 'parent' of type C (description: The parent frame to this frame.).-->
							<socket_parent>/ground</socket_parent>
							<!--Translational offset (in meters) of this frame's origin from the parent frame's origin, expressed in the parent frame.-->
							<translation>0 0 0.25</translation>
						</PhysicalOffsetFrame>
						<PhysicalOffsetFrame name="new_body_offset">
							<!--The geometry used to display the axes of this Frame.-->
							<FrameGeometry name="frame_geometry">
								<!--Path to a Component that satisfies the Socket 'frame' of type Frame.-->
								<socket_frame>..</socket_frame>
								<!--Scale factors in X, Y, Z directions respectively.-->
								<scale_factors>0.20000000000000001 0.20000000000000001 0.20000000000000001</scale_factors>
							</FrameGeometry>
							<!--Path to a Component that satisfies the Socket 'parent' of type C (description: The parent frame to this frame.).-->
							<socket_parent>/bodyset/new_body</socket_parent>
						</PhysicalOffsetFrame>
					</frames>
				</WeldJoint>
			</objects>
			<groups />
		</JointSet>
		<!--Controllers that provide the control inputs for Actuators.-->
		<ControllerSet name="controllerset">
			<objects />
			<groups />
		</ControllerSet>
		<!--Forces in the model (includes Actuators).-->
		<ForceSet name="forceset">
			<objects>
				<Millard2012EquilibriumMuscle name="Millard2012EquilibriumMuscle">
					<!--Minimum allowed value for control signal. Used primarily when solving for control values.-->
					<min_control>0.01</min_control>
					<!--Maximum allowed value for control signal. Used primarily when solving for control values.-->
					<max_control>1</max_control>
					<!--The path of the actuator which defines length and lengthening speed.-->
					<GeometryPath name="path">
						<!--Default appearance attributes for this AbstractGeometryPath.-->
						<Appearance>
							<!--The color, (red, green, blue), [0, 1], used to display the geometry. -->
							<color>0.80000000000000004 0.10000000000000001 0.10000000000000001</color>
						</Appearance>
						<!--The set of points defining the path-->
						<PathPointSet>
							<objects>
								<PathPoint name="Millard2012EquilibriumMuscle-P1">
									<!--Path to a Component that satisfies the Socket 'parent_frame' of type PhysicalFrame (description: The frame in which this path point is defined.).-->
									<socket_parent_frame>/bodyset/new_body</socket_parent_frame>
									<!--The fixed location of the path point expressed in its parent frame.-->
									<location>0 0.25 0</location>
								</PathPoint>
								<PathPoint name="Millard2012EquilibriumMuscle-P2">
									<!--Path to a Component that satisfies the Socket 'parent_frame' of type PhysicalFrame (description: The frame in which this path point is defined.).-->
									<socket_parent_frame>/ground/ground_offsetframe</socket_parent_frame>
									<!--The fixed location of the path point expressed in its parent frame.-->
									<location>0 0.25 0</location>
								</PathPoint>
							</objects>
							<groups />
						</PathPointSet>
					</GeometryPath>
					<!--Active-force-length curve.-->
					<ActiveForceLengthCurve name="Millard2012EquilibriumMuscle_ActiveForceLengthCurve">
						<!--Minimum value of the active-force-length curve-->
						<minimum_value>0</minimum_value>
					</ActiveForceLengthCurve>
					<!--Force-velocity curve.-->
					<ForceVelocityCurve name="Millard2012EquilibriumMuscle_ForceVelocityCurve">
						<!--Curve slope at the maximum normalized concentric (shortening) velocity (normalized velocity of -1)-->
						<concentric_slope_at_vmax>0</concentric_slope_at_vmax>
						<!--Curve slope just before reaching concentric_slope_at_vmax-->
						<concentric_slope_near_vmax>0.25</concentric_slope_near_vmax>
						<!--Curve slope at isometric (normalized velocity of 0)-->
						<isometric_slope>5</isometric_slope>
						<!--Curve slope at the maximum normalized eccentric (lengthening) velocity (normalized velocity of 1)-->
						<eccentric_slope_at_vmax>0</eccentric_slope_at_vmax>
						<!--Curve slope just before reaching eccentric_slope_at_vmax-->
						<eccentric_slope_near_vmax>0.14999999999999999</eccentric_slope_near_vmax>
						<!--Curve value at the maximum normalized eccentric contraction velocity-->
						<max_eccentric_velocity_force_multiplier>1.3999999999999999</max_eccentric_velocity_force_multiplier>
					</ForceVelocityCurve>
					<!--Passive-force-length curve.-->
					<FiberForceLengthCurve name="Millard2012EquilibriumMuscle_FiberForceLengthCurve">
						<!--All properties of this object have their default values.-->
					</FiberForceLengthCurve>
					<!--Tendon-force-length curve.-->
					<TendonForceLengthCurve name="Millard2012EquilibriumMuscle_TendonForceLengthCurve">
						<!--All properties of this object have their default values.-->
					</TendonForceLengthCurve>
				</Millard2012EquilibriumMuscle>
			</objects>
			<groups />
		</ForceSet>
		<!--Visual preferences for this model.-->
		<ModelVisualPreferences name="modelvisualpreferences">
			<!--Model display preferences-->
			<ModelDisplayHints>
				<!--Flag to indicate whether or not to show frames, default to false.-->
				<show_frames>true</show_frames>
			</ModelDisplayHints>
		</ModelVisualPreferences>
	</Model>
</OpenSimDocument>

adamkewley avatar Jun 17 '24 13:06 adamkewley