HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
keyFrame.h
Go to the documentation of this file.
1 //
2 // Copyright 2023 Pixar
3 //
4 // Licensed under the Apache License, Version 2.0 (the "Apache License")
5 // with the following modification; you may not use this file except in
6 // compliance with the Apache License and the following modification to it:
7 // Section 6. Trademarks. is deleted and replaced with:
8 //
9 // 6. Trademarks. This License does not grant permission to use the trade
10 // names, trademarks, service marks, or product names of the Licensor
11 // and its affiliates, except as required to comply with Section 4(c) of
12 // the License and to reproduce the content of the NOTICE file.
13 //
14 // You may obtain a copy of the Apache License at
15 //
16 // http://www.apache.org/licenses/LICENSE-2.0
17 //
18 // Unless required by applicable law or agreed to in writing, software
19 // distributed under the Apache License with the above modification is
20 // distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
21 // KIND, either express or implied. See the Apache License for the specific
22 // language governing permissions and limitations under the Apache License.
23 //
24 
25 #ifndef PXR_BASE_TS_KEY_FRAME_H
26 #define PXR_BASE_TS_KEY_FRAME_H
27 
28 #include "pxr/pxr.h"
29 #include "pxr/base/ts/api.h"
30 #include "pxr/base/arch/demangle.h"
31 #include "pxr/base/ts/types.h"
32 #include "pxr/base/ts/data.h"
33 #include "pxr/base/vt/value.h"
34 #include "pxr/base/vt/traits.h"
35 #include "pxr/base/tf/diagnostic.h"
37 
38 #include <iostream>
39 #include <typeinfo>
40 
42 
43 class TsSpline;
44 
45 /// \class TsKeyFrame
46 /// \brief Specifies the value of an TsSpline object at a particular
47 /// point in time.
48 ///
49 /// Keyframes also specify the shape of a spline as it passes through each
50 /// keyframe: the knot type specifies what interpolation technique to use
51 /// (TsKnotHeld, TsKnotLinear, or TsKnotBezier), and tangent handles
52 /// specify the shape of the spline as it passes through the keyframe.
53 ///
54 /// It is also possible for keyframes to be "dual-valued." This means
55 /// that a separate keyframe value -- the left-side value -- is used
56 /// when approaching the keyframe from lower time values. The regular
57 /// value is then used starting at the keyframe's time and when
58 /// approaching that time from higher times to the right. Dual-value
59 /// knots are necessary to compensate for instantaneous shifts
60 /// in coordinate frames, such as the shift that occurs when there is a
61 /// constraint switch. The spline can snap to the new value required to
62 /// maintain the same position in worldspace.
63 ///
64 /// <b>Note:</b> TsKeyFrame is a value, not a formal object.
65 ///
66 class TsKeyFrame final
67 {
68 public: // methods
69 
70  /// Constructs a default double keyframe.
71  TS_API
72  TsKeyFrame();
73 
74  /// \name Constructors
75  /// @{
76  ///
77  /// There are four variations on the constructor, to support
78  /// single-valued or dual-valued keyframes, with values supplied as
79  /// either VtValues or a template parameter.
80 
81  /// Constructs a single-valued keyframe.
82  template <typename T>
83  TsKeyFrame( const TsTime & time,
84  const T & val,
85  TsKnotType knotType = TsKnotLinear,
86  const T & leftTangentSlope = TsTraits<T>::zero,
87  const T & rightTangentSlope = TsTraits<T>::zero,
88  TsTime leftTangentLength = 0,
89  TsTime rightTangentLength = 0);
90 
91  /// Constructs a single-valued keyframe with VtValues.
92  TS_API
93  TsKeyFrame( const TsTime & time,
94  const VtValue & val,
95  TsKnotType knotType = TsKnotLinear,
96  const VtValue & leftTangentSlope = VtValue(),
97  const VtValue & rightTangentSlope = VtValue(),
98  TsTime leftTangentLength = 0,
99  TsTime rightTangentLength = 0);
100 
101  /// Constructs a dual-valued keyframe.
102  template <typename T>
103  TsKeyFrame( const TsTime & time,
104  const T & lhv,
105  const T & rhv,
106  TsKnotType knotType = TsKnotLinear,
107  const T & leftTangentSlope = TsTraits<T>::zero,
108  const T & rightTangentSlope = TsTraits<T>::zero,
109  TsTime leftTangentLength = 0,
110  TsTime rightTangentLength = 0);
111 
112  /// Constructs a dual-valued keyframe with VtValues.
113  TS_API
114  TsKeyFrame( const TsTime & time,
115  const VtValue & lhv,
116  const VtValue & rhv,
117  TsKnotType knotType = TsKnotLinear,
118  const VtValue & leftTangentSlope = VtValue(),
119  const VtValue & rightTangentSlope = VtValue(),
120  TsTime leftTangentLength = 0,
121  TsTime rightTangentLength = 0);
122 
123  /// Constructs a keyframe by duplicating an existing TsKeyFrame.
124  TS_API
125  TsKeyFrame( const TsKeyFrame & kf );
126 
127  /// @}
128 
129  /// Non-virtual destructor; this class should not be subclassed.
130  TS_API
131  ~TsKeyFrame();
132 
133  /// \name Primary API
134  /// @{
135 
136  /// Assignment operator.
137  TS_API
138  TsKeyFrame & operator=(const TsKeyFrame &rhs);
139 
140  /// Compare this keyframe with another.
141  TS_API
142  bool operator==(const TsKeyFrame &) const;
143 
144  TS_API
145  bool operator!=(const TsKeyFrame &) const;
146 
147  /// Gets whether this key frame is at the same time and is equivalent to
148  /// \p keyFrame on the given \p side. In other words, replacing this
149  /// key frame with \p keyFrame in a spline will have no effect on how the
150  /// spline evaluates for any time on the given \p side of this key frame.
151  TS_API
152  bool IsEquivalentAtSide(const TsKeyFrame &keyFrame, TsSide side) const;
153 
154  /// Gets the time of this keyframe.
155  TS_API
156  TsTime GetTime() const {
157  return _holder.Get()->GetTime();
158  }
159 
160  /// Sets the time of this keyframe.
161  TS_API
162  void SetTime( const TsTime & newTime ) {
163  _holder.GetMutable()->SetTime(newTime);
164  }
165 
166  /// Gets the value at this keyframe.
167  TS_API
168  VtValue GetValue() const;
169 
170  /// Sets the value at this keyframe.
171  TS_API
172  void SetValue( VtValue val );
173 
174  /// Gets the value at this keyframe on the given side.
175  TS_API
176  VtValue GetValue( TsSide side ) const;
177 
178  /// Sets the value at this keyframe on the given side.
179  TS_API
180  void SetValue( VtValue val, TsSide side );
181 
182  /// Gets the value of the derivative at this keyframe.
183  TS_API
184  VtValue GetValueDerivative() const;
185 
186  /// Gets a zero for this keyframe's value type.
187  TS_API
188  VtValue GetZero() const;
189 
190  /// Gets the knot type
191  TS_API
192  TsKnotType GetKnotType() const;
193 
194  /// Sets the knot type
195  TS_API
196  void SetKnotType( TsKnotType knotType );
197 
198  /// Checks whether the key frame's value type supports the given knot
199  /// type.
200  TS_API
201  bool CanSetKnotType( TsKnotType, std::string *reason=NULL ) const;
202 
203  /// @}
204 
205  /// \name Dual-value API
206  ///
207  /// Keyframes have a "left side" and a "right side". The right side is
208  /// conceptually later than the left, even though they occur at the same
209  /// time. The two sides most often have the same value, but it is also
210  /// possible for the two sides to have different values. The purpose of
211  /// having different values on the two sides is to allow instantaneous value
212  /// discontinuities. This is useful, for example, when a constraint
213  /// changes, and the meaning of another property (like an IkTx)
214  /// instantaneously changes because of the constraint switch.
215  ///
216  /// Most spline evaluation takes place on the right side. Calling GetValue
217  /// returns the sole value for a single-valued keyframe, and the right value
218  /// for a double-valued keyframe.
219  ///
220  /// Note the difference between, on the one hand, asking a keyframe for its
221  /// left value; and on the other hand, evaluating a spline at the left side
222  /// of that keyframe's time. Usually these two methods agree. But when a
223  /// keyframe is preceded by a held segment, spline evaluation at the
224  /// keyframe's left side will yield the held value from the prior segment,
225  /// but the keyframe itself knows nothing about the prior segment, so
226  /// GetLeftValue returns the left value stored in the keyframe (which is the
227  /// right value for a single-valued knot). Another way to look at this
228  /// situation is that, when a keyframe B is preceded by a held keyframe A,
229  /// the left value of B is never consulted in spline evaluation. This
230  /// arrangement ensures that the instantaneous value change at the end of a
231  /// held segment occurs exactly at the time of the keyframe that ends the
232  /// segment.
233  ///
234  /// Note also the difference between GetIsDualValued and
235  /// TsSpline::DoSidesDiffer. Usually these two methods agree. But in the
236  /// after-held-knot case described above, they do not. They also do not
237  /// agree when SetIsDualValued(true) has been called, but the keyframe has
238  /// the same value on both sides.
239  ///
240  /// @{
241 
242  /// Gets whether this knot is dual-valued. See the note above about
243  /// TsSpline::DoSidesDiffer.
244  TS_API
245  bool GetIsDualValued() const;
246 
247  /// Sets whether this knot is dual-valued. When a knot is first made
248  /// dual-valued, the left value is copied from the right value.
249  TS_API
250  void SetIsDualValued( bool isDual );
251 
252  /// Gets the left value of this dual-valued knot. Returns the right value
253  /// if this is not a dual-valued knot.
254  TS_API
255  VtValue GetLeftValue() const;
256 
257  /// Sets the left value of this dual-valued knot. It is an error to call
258  /// this method on single-valued knots.
259  TS_API
260  void SetLeftValue( VtValue val );
261 
262  /// Gets the value of the derivative on the left side. This is a synonym
263  /// for GetLeftTangentSlope for knot types that support tangents; for other
264  /// types, this method returns zero.
265  TS_API
267 
268  /// @}
269 
270  /// \name Tangents
271  /// @{
272 
273  /// Gets whether the value type of this keyframe is interpolatable.
274  TS_API
275  bool IsInterpolatable() const;
276 
277  /// Gets whether the value type of this keyframe is extrapolatable. This
278  /// means that a slope can be computed from the line between two knots of
279  /// this knot's value type.
280  TS_API
281  bool IsExtrapolatable() const;
282 
283  /// Gets whether the value type of this keyframe supports tangents. This
284  /// will return true not only for Bezier, but also for Linear and Held,
285  /// because when authors switch from Bezier to Linear/Held and back to
286  /// Bezier, we want to preserve the original tangents, and thus we track
287  /// tangent data for Linear and Held knots. If you really want to write
288  /// just to Beziers, call HasTangents().
289  TS_API
290  bool SupportsTangents() const;
291 
292  /// Gets whether the knot of this keyframe has tangents. This is true when
293  /// the value type supports tangents, and the knot is a Bezier.
294  TS_API
295  bool HasTangents() const;
296 
297  /// Gets the length of the projection of the knot's left tangent onto the
298  /// time axis.
299  TS_API
301 
302  /// Gets the left-side tangent slope (in units per frame) of this knot.
303  TS_API
305 
306  /// Gets the length of the projection of the knot's right tangent onto the
307  /// time axis.
308  TS_API
310 
311  /// Gets the right-side tangent slope (in units per frame) of this knot.
312  TS_API
314 
315  /// Sets the left-side tangent length (in time) of this knot. Issues a
316  /// coding error if this knot does not support tangents
317  TS_API
319 
320  /// Sets the left-side tangent slope (in units per frame) of this knot.
321  /// Issues a coding error if this knot does not support tangents
322  TS_API
324 
325  /// Sets the right-side tangent length (in time) of this knot.
326  /// Issues a coding error if this knot does not support tangents
327  TS_API
329 
330  /// Sets the right-side tangent slope (in units per frame) of this knot.
331  /// Issues a coding error if this knot does not support tangents
332  TS_API
333  void SetRightTangentSlope( VtValue newSlope);
334 
335  /// Gets whether tangent symmetry has been broken. In this context,
336  /// "symmetric" refers to the tangents having equal slope but not
337  /// necessarily equal length.
338  ///
339  /// If tangent symmetry is broken, tangent handles will not
340  /// automatically stay symmetric as they are changed.
341  TS_API
342  bool GetTangentSymmetryBroken() const;
343 
344  /// Sets whether tangent symmetry is broken. Setting this to false
345  /// will make the tangents symmetric if they are not already by
346  /// reflecting the right tangent to the left side. Issues a
347  /// coding error if this knot does not support tangents
348  TS_API
349  void SetTangentSymmetryBroken( bool broken );
350 
351  /// Sets the flag that enforces tangent symmetry based on whether
352  /// the tangets are already symmetric. If they are symmetric, the
353  /// 'broken' flag will be cleared so that future edits maintain
354  /// symmetry. If they are not symmetric, they will be marked as
355  /// 'broken'.
356  ///
357  /// The intent is to help provide policy for newly received
358  /// tangent data: if the tangents happen to be symmetric, keep them
359  /// so; but if they are asymmetric, don't bother. Issues a
360  /// coding error if this knot does not support tangents.
361  TS_API
363 
364 private:
365 
366  // Give the rest of the library access to the Ts_Data object held
367  // in this keyframe through the Ts_GetKeyFrameData function.
368  friend Ts_Data* Ts_GetKeyFrameData(TsKeyFrame &kf);
369  friend Ts_Data const* Ts_GetKeyFrameData(TsKeyFrame const& kf);
370 
371  // Shared initialization
372  void _Initialize(
373  const TsTime & time,
374  TsKnotType knotType,
375  const VtValue & leftTangentSlope,
376  const VtValue & rightTangentSlope,
377  TsTime leftTangentLength,
378  TsTime rightTangentLength);
379 
380  // XXX: exported because called from inlined templated constructors
381  TS_API
382  void _InitializeKnotType(TsKnotType knotType);
383  TS_API
384  void _InitializeTangentLength(TsTime leftTangentLength,
385  TsTime rightTangentLength);
386 
387  // Helper function which tests the setability of tangents for this knot,
388  // and reports an error if tangents not supported
389  bool _ValidateTangentSetting() const;
390 
391 private:
392 
393  Ts_PolymorphicDataHolder _holder;
394 };
395 
396 ////////////////////////////////////////////////////////////////////////
397 
398 TS_API
399 std::ostream& operator<<(std::ostream &out, const TsKeyFrame &val);
400 
401 template <typename T>
403  const T & val,
404  TsKnotType knotType,
405  const T & leftTangentSlope,
406  const T & rightTangentSlope,
407  TsTime leftTangentLength,
408  TsTime rightTangentLength)
409 {
411 
412  _holder.New(time, false /*isDual*/,
413  val, val, leftTangentSlope, rightTangentSlope);
414 
415  _InitializeKnotType(knotType);
416  _InitializeTangentLength(leftTangentLength,rightTangentLength);
417 }
418 
419 template <typename T>
421  const T & lhv,
422  const T & rhv,
423  TsKnotType knotType,
424  const T & leftTangentSlope,
425  const T & rightTangentSlope,
426  TsTime leftTangentLength,
427  TsTime rightTangentLength)
428 {
430 
431  _holder.New(time, true /*isDual*/, lhv, rhv,
432  leftTangentSlope, rightTangentSlope);
433 
434  _InitializeKnotType(knotType);
435  _InitializeTangentLength(leftTangentLength,rightTangentLength);
436 }
437 
439 
440 #endif
TS_API bool GetTangentSymmetryBroken() const
TS_API bool IsExtrapolatable() const
TS_API TsTime GetLeftTangentLength() const
A Linear knot; tangents will be ignored.
Definition: types.h:66
GT_API const UT_StringHolder time
TS_API TsKnotType GetKnotType() const
Gets the knot type.
TS_API bool IsInterpolatable() const
Gets whether the value type of this keyframe is interpolatable.
GLsizei const GLchar *const * string
Definition: glcorearb.h:814
void New(const T &val)
Definition: data.h:411
TS_API bool operator==(const TsKeyFrame &) const
Compare this keyframe with another.
TS_API std::ostream & operator<<(std::ostream &out, const TsKeyFrame &val)
void SetTime(TsTime newTime)
Definition: data.h:78
Ts_Data * GetMutable()
Definition: data.h:452
TS_API VtValue GetZero() const
Gets a zero for this keyframe's value type.
TS_API VtValue GetLeftValueDerivative() const
TS_API void SetTangentSymmetryBroken(bool broken)
TS_API void SetKnotType(TsKnotType knotType)
Sets the knot type.
const Ts_Data * Get() const
Definition: data.h:446
TS_API ~TsKeyFrame()
Non-virtual destructor; this class should not be subclassed.
TS_API VtValue GetLeftValue() const
TS_API void SetTime(const TsTime &newTime)
Sets the time of this keyframe.
Definition: keyFrame.h:162
TS_API void SetRightTangentSlope(VtValue newSlope)
friend Ts_Data * Ts_GetKeyFrameData(TsKeyFrame &kf)
Gets whether the value type of this keyframe is interpolatable.
TsKnotType
Keyframe knot types.
Definition: types.h:64
TS_API TsTime GetTime() const
Gets the time of this keyframe.
Definition: keyFrame.h:156
TS_API TsKeyFrame & operator=(const TsKeyFrame &rhs)
Assignment operator.
SIM_API const UT_StringHolder broken
TS_API bool HasTangents() const
Specifies the value of an TsSpline object at a particular point in time.
Definition: keyFrame.h:66
TS_API void SetValue(VtValue val)
Sets the value at this keyframe.
TS_API VtValue GetLeftTangentSlope() const
Gets the left-side tangent slope (in units per frame) of this knot.
PXR_NAMESPACE_OPEN_SCOPE typedef double TsTime
The time type used by Ts.
Definition: types.h:57
TS_API bool operator!=(const TsKeyFrame &) const
Assignment operator.
#define TS_API
Definition: api.h:41
TS_API TsKeyFrame()
Constructs a default double keyframe.
TS_API void SetRightTangentLength(TsTime)
TS_API TsTime GetRightTangentLength() const
TS_API void SetLeftTangentLength(TsTime)
TsSide
Dual-value keyframe side.
Definition: types.h:90
TS_API bool GetIsDualValued() const
TS_API bool IsEquivalentAtSide(const TsKeyFrame &keyFrame, TsSide side) const
TS_API void SetLeftTangentSlope(VtValue)
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1432
TsTime GetTime() const
Definition: data.h:75
Holds the data for an TsKeyFrame.
Definition: data.h:50
GLuint GLfloat * val
Definition: glcorearb.h:1608
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:91
TS_API bool CanSetKnotType(TsKnotType, std::string *reason=NULL) const
TS_API bool SupportsTangents() const
TS_API void ResetTangentSymmetryBroken()
TS_API void SetLeftValue(VtValue val)
TS_API VtValue GetValue() const
Gets the value at this keyframe.
TS_API VtValue GetValueDerivative() const
Gets the value of the derivative at this keyframe.
TS_API VtValue GetRightTangentSlope() const
Gets the right-side tangent slope (in units per frame) of this knot.
Definition: value.h:164
TS_API void SetIsDualValued(bool isDual)