30 OpenSim_DECLARE_PROPERTY(station_path, std::string,
"Absolute path (e.g. `/componentset/some_station`) to a `Station` component in the model");
31 OpenSim_DECLARE_PROPERTY(wrap_cylinder_path, std::string,
"Absolute path (e.g. `/bodyset/body/wrap_cylinder_2`) to a `WrapCylinder` component in the model");
34 ScalingStep{
"Recalculate WrapCylinder 'xyz_body_rotation' from Station Placed Along Its Midline"}
36 setDescription(
"Recalculates the 'xyz_body_rotation' of a `WrapCylinder` component, located at `wrap_cylinder_path` such that the cylinder's +Z direction (midline) points toward the Station component located at `station_path`");
37 constructProperty_station_path(
"");
38 constructProperty_wrap_cylinder_path(
"");
44 const OpenSim::Model&
model)
const final
46 std::vector<ScalingStepValidationMessage> messages;
49 const auto* station = FindComponent<OpenSim::Station>(
model, get_station_path());
51 messages.emplace_back(
53 std::format(
"{}: Cannot find `station_path` in the source model (or it isn't a Station).", get_station_path())
58 const auto* wrapCylinder = FindComponent<OpenSim::WrapCylinder>(
model, get_wrap_cylinder_path());
59 if (not wrapCylinder) {
60 messages.emplace_back(
62 std::format(
"{}: Cannot find 'wrap_cylinder_path' in the source model (or it isn't a `WrapCylinder`).", get_wrap_cylinder_path())
72 const OpenSim::Model&,
73 OpenSim::Model& resultModel)
const final
78 const auto* station = FindComponent<OpenSim::Station>(resultModel, get_station_path());
80 auto* wrapCylinder = FindComponentMut<OpenSim::WrapCylinder>(resultModel, get_wrap_cylinder_path());
84 const SimTK::Transform cylinder2cylinderFrame = wrapCylinder->getTransform();
85 const SimTK::Transform cylinderFrame2ground = wrapCylinder->getFrame().getTransformInGround(resultModel.getWorkingState());
86 const SimTK::Transform ground2cylinder = (cylinderFrame2ground * cylinder2cylinderFrame).invert();
87 const SimTK::Vec3 stationPosInCylinder = ground2cylinder * station->getLocationInGround(resultModel.getWorkingState());
90 const SimTK::UnitVec3 cylinderDirectionInCylinder{SimTK::CoordinateAxis::ZCoordinateAxis{}};
91 const SimTK::UnitVec3 stationDirectionInCylinder{stationPosInCylinder};
94 const auto cosRotationAngle = SimTK::dot(cylinderDirectionInCylinder, stationDirectionInCylinder);
95 if (abs(cosRotationAngle) >= 1.0 - SimTK::Eps) {
101 const auto rotationAngle = acos(cosRotationAngle);
102 const SimTK::UnitVec3 rotationAxis{SimTK::cross(cylinderDirectionInCylinder, stationDirectionInCylinder)};
103 const SimTK::Rotation rotation{rotationAngle, rotationAxis};
106 const SimTK::Rotation newRotation = cylinder2cylinderFrame.R() * rotation;
109 wrapCylinder->set_xyz_body_rotation(newRotation.convertRotationToBodyFixedXYZ());
Definition recalculate_wrap_cylinder_xyz_body_rotation_from_station_scaling_step.h:27
std::vector< ScalingStepValidationMessage > implValidate(ScalingCache &, const ScalingParameters &, const OpenSim::Model &model) const final
Definition recalculate_wrap_cylinder_xyz_body_rotation_from_station_scaling_step.h:41
void implApplyScalingStep(ScalingCache &, const ScalingParameters &, const OpenSim::Model &, OpenSim::Model &resultModel) const final
Definition recalculate_wrap_cylinder_xyz_body_rotation_from_station_scaling_step.h:69