IMP logo
IMP Reference Guide  develop.63b38c487d,2024/12/21
The Integrative Modeling Platform
revolute_joints.h
Go to the documentation of this file.
1 /**
2  * \file IMP/kinematics/revolute_joints.h
3  * \brief functionality for defining various revolute kinematic
4  * joints between rigid bodies as part of a kinematic tree,
5  * including RevoluteJoint, DihedralAngleRevoluteJoint, and
6  * BondAngleRevoluteJoint
7  * \authors Dina Schneidman, Barak Raveh
8  *
9 
10  * Copyright 2007-2022 IMP Inventors. All rights reserved.
11  */
12 
13 #ifndef IMPKINEMATICS_REVOLUTE_JOINTS_H
14 #define IMPKINEMATICS_REVOLUTE_JOINTS_H
15 
16 #include <IMP/kinematics/kinematics_config.h>
18 #include <IMP/kinematics/Joint.h>
19 #include <IMP/Object.h>
20 #include <IMP/exception.h>
21 #include <IMP/core/internal/dihedral_helpers.h>
22 #include <IMP/algebra/Vector3D.h>
23 #include <IMP/check_macros.h>
24 
25 // TODO: for debug only = remove later
26 #define IMP_RAD_2_DEG(a) 180 * a / IMP::algebra::PI
27 #define IMP_DEG_2_RAD(a) a* IMP::algebra::PI / 180
28 
29 IMPKINEMATICS_BEGIN_NAMESPACE
30 
31 class KinematicForest;
32 
33 // inline void nice_print_trans(const IMP::algebra::Transformation3D& T,
34 // std::string description)
35 // {
36 // std::pair< IMP::algebra::Vector3D, double > aa;
37 // aa = IMP::algebra::get_axis_and_angle( T.get_rotation() );
38 // IMP_LOG( VERBOSE, description << "axis = " << aa.first
39 // << "; angle = " << IMP_RAD_2_DEG(aa.second) << " deg"
40 // << "; translation = " << T.get_translation()
41 // << std::endl );
42 // }
43 
44 /********************** RevoluteJoint ***************/
45 
46 //! Abstract class for all revolute joints
47 class IMPKINEMATICSEXPORT RevoluteJoint : public Joint {
48  public:
49  //! Construct on the line connecting a and b, with an initial angle 'angle'
50  /**
51  @param parent,child kinematic nodes upstream and downstream (resp.) of this
52  joint
53  **/
55 
56  // pure virtual dtr to declare as abstract class for SWIG
57  virtual ~RevoluteJoint() = 0;
58 
59  /******* getter / setter methods *********/
60  public:
61  /**
62  sets the angle of the revolute joint and marks the internal
63  coordinates as changed in the kinematic forest object
64  */
65  void set_angle(double angle);
66 
67  /**
68  gets the angle of the revolute joint. This method is kinematically
69  safe (it triggers an update to internal coordinates if needed)
70  */
71  double get_angle() const;
72 
73  protected:
74  //#ifndef SWIG
75  // in global coordinates
76  const IMP::algebra::Vector3D& get_rot_axis_origin() const {
77  return rot_axis_origin_;
78  }
79 
80  // in global coordinates
81  const IMP::algebra::Vector3D& get_rot_axis_unit_vector() const {
82  return rot_axis_unit_vector_;
83  }
84  //#endif
85 
86  /****************** general protected methods ***************/
87 
88  protected:
89  /**
90  Updates the reference frame of the child node by this joint
91  angle, assuming the parent reference frame and the witnesses
92  that affect update_axis_of_rotation_from_cartesian_witnesses()
93  are all updated already
94  */
95  virtual void update_child_node_reference_frame() const override;
96 
97  /**
98  this protected method updates the rot_axis_unit_vector_
99  and rot_axis_origin_ variables based on the Cartesian witnesses
100  appropriate for a specific implementation of this abstract class,
101  using parent coordinates, assuming all Cartesian witnesses are updated
102  */
103  virtual void update_axis_of_rotation_from_cartesian_witnesses() = 0;
104 
105  /**
106  this protected method uses the Cartesian witnesses to compute
107  the actual current angle of this joint (assuming external coordinates
108  of required Cartesian witnesses are up to date).
109  @note this method does not update the angle stored in this joint,
110  which may be strictly different (if external or internal coords
111  are outdated)
112  */
113  virtual double get_current_angle_from_cartesian_witnesses() const = 0;
114 
115  /**
116  Update the joint internal parameters based on external reference frames
117  of witnesses and rigid bodies, assuming external parameters are updated
118  */
119  virtual void update_joint_from_cartesian_witnesses() override {
120  update_axis_of_rotation_from_cartesian_witnesses();
121  angle_ = get_current_angle_from_cartesian_witnesses();
122  last_updated_angle_ = angle_;
124  }
125 
126  /**
127  Returns the transformation matrix for rotating a vector in
128  parent coordinates about the axis of the joint, in a way that
129  would bring the Cartesian witnesses to the correct joint angle
130  (as measured by get_angle_from_cartesian_witnesses() ).
131  */
134  IMP_LOG(VERBOSE, "get_rotation " << IMP_RAD_2_DEG(angle_)
135  << ", last_updated_angle = "
136  << IMP_RAD_2_DEG(last_updated_angle_)
137  << std::endl);
138  // rotate by the difference from last_updated_angle_
141  rot_axis_unit_vector_, angle_ - last_updated_angle_);
143  IMP::algebra::get_rotation_about_point(rot_axis_origin_, R);
144 
145  // debug prints
146  // nice_print_trans(R_origin, "R_origin: ");
147 
148  return R_origin;
149  }
150 
151  protected:
152  // the angle in Radians about the joint axis ("unit vector")
153  double angle_;
154 
155  // the angle used when the child reference frame was last up-to-date
156  // mutable cause logically does not change the state of this object
157  // (or is that so?)
158  mutable double last_updated_angle_;
159 
160  // the unit vector around which the joint revolves in parent coords
161  IMP::algebra::Vector3D rot_axis_unit_vector_;
162 
163  // the joint origin of rotation in parent coords
164  IMP::algebra::Vector3D rot_axis_origin_;
165 };
166 
167 /********************** DihedralAngleRevoluteJoint ***************/
168 // @TODO handle derivatives
169 
170 //! Joint that is parameterized as a dihedral angle between two planes
171 class IMPKINEMATICSEXPORT DihedralAngleRevoluteJoint : public RevoluteJoint {
172  public:
173  /**
174  constructs a dihedral angle that revolves around the axis b-c,
175  using a,b,c,d as witnesses for the dihedral angle
176 
177  @param parent,child kinematic nodes upstream and downstream (resp.) of
178  this joint
179  @param a,b,c,d 'witnesses' whose coordinates define the dihedral
180  angle between the planes containing a-b-c and
181  b-c-d)
182 
183  @note It is assumed that neither a, b and c are downstream of child,
184  and also that d is not upstream of it
185  */
189  IMP::core::XYZ d);
190 
191  IMP::core::XYZ get_a() const { return a_; }
192  IMP::core::XYZ get_b() const { return b_; }
193  IMP::core::XYZ get_c() const { return c_; }
194  IMP::core::XYZ get_d() const { return d_; }
195 
196  protected:
197  /**
198  updates the rot_axis_unit_vector_ and rot_axis_origin_ variables
199  in parent coordinates based on the witnesses b_ and c_,
200  using b_-c_ as the axis of rotation
201  @note it is assumed b_ and c_ have update Cartesian coordinates
202  */
204  using namespace IMP::algebra;
206  get_distance(b_.get_coordinates(), c_.get_coordinates()) > 1e-12,
207  "witnesses b and c must be non identical beyond numerical error");
208  ReferenceFrame3D rf_parent = get_parent_node().get_reference_frame();
209  // nice_print_trans(rf_parent.get_transformation_to(), "Parent trans: ");
210  rot_axis_origin_ = rf_parent.get_local_coordinates(b_.get_coordinates());
211  IMP_LOG(VERBOSE, "global b_ " << b_.get_coordinates()
212  << " and local parent b_ " << rot_axis_origin_
213  << std::endl);
214  Vector3D v = rf_parent.get_local_coordinates(c_.get_coordinates()) -
215  rf_parent.get_local_coordinates(b_.get_coordinates());
216  rot_axis_unit_vector_ = v.get_unit_vector();
217  IMP_LOG(VERBOSE, "local axis of rot unnorm "
218  << v << " global axis "
219  << c_.get_coordinates() - b_.get_coordinates()
220  << std::endl);
221  };
222 
223  /**
224  this protected method uses the Cartesian witnesses to compute
225  the actual current dihedral angle of this joint (assuming
226  external coordinates of required Cartesian witnesses are up to
227  date)
228  */
230  const override;
231 
232  private:
233  IMP::core::XYZ a_;
234  IMP::core::XYZ b_;
235  IMP::core::XYZ c_;
236  IMP::core::XYZ d_;
237 };
238 
239 /********************** BondAngleRevoluteJoint ***************/
240 // TODO: do we want to handle derivatives?
241 
242 //! Joint that is parameterized as a bond angle between three particles
243 class IMPKINEMATICSEXPORT BondAngleRevoluteJoint : public RevoluteJoint {
244  public:
245  /**
246  constructs a joint that controls the angle a-b-c. The joint
247  revolves around the axis that passes through b, normal to the
248  plane containing a, b and c. a,b and c are the witnesses for the
249  bond angle.
250 
251  @param parent,child kinematic nodes upstream and downstream (resp.) of
252  this joint
253  @param a,b,c 'witnesses' whose coordinates define the joint angle a-b-c
254 
255  @note It is assumed that a and b are upstream of or inside
256  this joint's child rigid body, and that c is downstream of
257  it or inside it.
258  */
262 
263  protected:
264  /**
265  this protected method uses the Cartesian witnesses to compute the
266  actual current bond angle of this joint (assuming external
267  coordinates of required Cartesian witnesses are up to date)
268  */
270  const override;
271 
272  /**
273  updates the rot_axis_unit_vector_ and rot_axis_origin_ variables
274  using b_ as origin of rotation and a vector perpendicular to the
275  plane containing a_,b_,c_ as axis of rotation, in global
276  coordinates
277  */
279  using namespace IMP::algebra;
280 
282  get_distance(b_.get_coordinates(), c_.get_coordinates()) > 1e-12,
283  "witnesses b and c must be non identical beyond numerical error");
285  get_distance(b_.get_coordinates(), a_.get_coordinates()) > 1e-12,
286  "witnesses b and a must be non identical beyond numerical error");
287  ReferenceFrame3D rf_parent = get_parent_node().get_reference_frame();
288  Vector3D v =
289  rf_parent.get_local_coordinates(get_perpendicular_vector(a_, b_, c_));
290  rot_axis_unit_vector_ = v.get_unit_vector();
291  rot_axis_origin_ = rf_parent.get_local_coordinates(b_.get_coordinates());
292  };
293 
294  private:
295  static IMP::algebra::Vector3D get_perpendicular_vector(core::XYZ a,
296  core::XYZ b,
297  core::XYZ c) {
300  return IMP::algebra::get_vector_product(v1, v2);
301  }
302  IMP::core::XYZ a_;
303  IMP::core::XYZ b_;
304  IMP::core::XYZ c_;
305 };
306 
310 
311 IMPKINEMATICS_END_NAMESPACE
312 
313 #endif /* IMPKINEMATICS_REVOLUTE_JOINTS_H */
Rotation3D get_rotation_about_normalized_axis(const Vector3D &axis_norm, double angle)
Definition: Rotation3D.h:391
Simple 3D transformation class.
Abstract class for all revolute joints.
Joint that is parameterized as a bond angle between three particles.
virtual void update_axis_of_rotation_from_cartesian_witnesses() override
Exception definitions and assertions.
double get_angle(const Line3D &a, const Line3D &b)
Get angle in radians between two lines around their closest points.
A reference frame in 3D.
virtual void update_joint_from_cartesian_witnesses()
Transformation2D get_rotation_about_point(const Vector2D &point, const Rotation2D &rotation)
Generate a Transformation2D object from a rotation around a point.
Vector3D get_local_coordinates(const Vector3D &v) const
Vector3D get_vector_product(const Vector3D &p1, const Vector3D &p2)
Return the vector product (cross product) of two vectors.
Definition: Vector3D.h:31
functionality for defining a kinematic joint between rigid bodies as part of a kinematic tree ...
IMP::algebra::Transformation3D get_rotation_about_joint_in_parent_coordinates() const
virtual void update_axis_of_rotation_from_cartesian_witnesses() override
Produce copious output to allow someone to trace through the computation.
Definition: enums.h:33
functionality for defining nodes on a kinematic chain
A decorator for a particle with x,y,z coordinates.
Definition: XYZ.h:30
const algebra::Vector3D & get_coordinates() const
Convert it to a vector.
Definition: XYZ.h:109
virtual double get_current_angle_from_cartesian_witnesses() const =0
virtual void update_child_node_reference_frame() const
3D rotation class.
Definition: Rotation3D.h:52
virtual void update_joint_from_cartesian_witnesses() override
Joint that is parameterized as a dihedral angle between two planes.
#define IMP_OBJECTS(Name, PluralName)
Define the types for storing lists of object pointers.
Definition: object_macros.h:44
Helper macros for throwing and handling exceptions.
Base class for joints between rigid bodies in a kinematic tree.
Definition: Joint.h:29
A shared base class to help in debugging and things.
VectorD< 3 > Vector3D
Definition: VectorD.h:408
Simple 3D vector class.
#define IMP_USAGE_CHECK(expr, message)
A runtime test for incorrect usage of a class or method.
Definition: check_macros.h:168
A decorator for a rigid body.
Definition: rigid_bodies.h:82
double get_distance(const Line3D &s, const Vector3D &p)
Get closest distance between a line and a point.