Overte C++ Documentation
SwingTwistConstraint.h
1 //
2 // SwingTwistConstraint.h
3 //
4 // Copyright 2015 High Fidelity, Inc.
5 //
6 // Distributed under the Apache License, Version 2.0.
7 // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
8 //
9 
10 #ifndef hifi_SwingTwistConstraint_h
11 #define hifi_SwingTwistConstraint_h
12 
13 #include <vector>
14 
15 #include "RotationConstraint.h"
16 
17 #include <math.h>
18 
19 class SwingTwistConstraint : public RotationConstraint {
20 public:
21  // The SwingTwistConstraint starts in the "referenceRotation" and then measures an initial twist
22  // about the yAxis followed by a swing about some axis that lies in the XZ plane, such that the twist
23  // and swing combine to produce the rotation. Each partial rotation is constrained within limits
24  // then used to construct the new final rotation.
25 
26  SwingTwistConstraint();
27 
36  void setSwingLimits(std::vector<float> minDots);
37 
42  void setSwingLimits(const std::vector<glm::vec3>& swungDirections);
43 
44 
47  void setTwistLimits(float minTwist, float maxTwist);
48 
51  virtual bool apply(glm::quat& rotation) const override;
52 
53  void setLowerSpine(bool lowerSpine) { _lowerSpine = lowerSpine; }
54  virtual bool isLowerSpine() const override { return _lowerSpine; }
55 
58  virtual void dynamicallyAdjustLimits(const glm::quat& rotation) override;
59 
60  // for testing purposes
61  const std::vector<float>& getMinDots() const { return _swingLimitFunction.getMinDots(); }
62 
63  // SwingLimitFunction is an implementation of the constraint check described in the paper:
64  // "The Parameterization of Joint Rotation with the Unit Quaternion" by Quang Liu and Edmond C. Prakash
65  //
66  // The "dynamic adjustment" feature allows us to change the limits on the fly for one particular theta angle.
67  //
68  class SwingLimitFunction {
69  public:
70  SwingLimitFunction();
71 
73  void setMinDots(const std::vector<float>& minDots);
74 
78  void dynamicallyAdjustMinDots(float theta, float minDot);
79 
81  float getMinDot(float theta) const;
82 
83  // for testing purposes
84  const std::vector<float>& getMinDots() const { return _minDots; }
85 
86  private:
87  // the limits are stored in a lookup table with cyclic boundary conditions
88  std::vector<float> _minDots;
89 
90  // these values used to restore dynamic adjustment
91  float _minDotA;
92  float _minDotB;
93  int8_t _minDotIndexA;
94  int8_t _minDotIndexB;
95  };
96 
98  const SwingLimitFunction& getSwingLimitFunction() const { return _swingLimitFunction; }
99 
100  void clearHistory() override;
101 
102  virtual glm::quat computeCenterRotation() const override;
103 
104  float getMinTwist() const { return _minTwist; }
105  float getMaxTwist() const { return _maxTwist; }
106 
107 private:
108  float handleTwistBoundaryConditions(float twistAngle) const;
109 
110 protected:
111  SwingLimitFunction _swingLimitFunction;
112  float _minTwist;
113  float _maxTwist;
114 
115  float _oldMinTwist;
116  float _oldMaxTwist;
117 
118  // We want to remember the LAST clamped boundary, so we an use it even when the far boundary is closer.
119  // This reduces "pops" when the input twist angle goes far beyond and wraps around toward the far boundary.
120  mutable int _lastTwistBoundary;
121  bool _lowerSpine { false };
122  bool _twistAdjusted { false };
123 };
124 
125 #endif // hifi_SwingTwistConstraint_h