8#ifndef PXR_BASE_TS_DATA_H
9#define PXR_BASE_TS_DATA_H
12#include "pxr/base/ts/api.h"
16#include "pxr/base/ts/evalCache.h"
17#include "pxr/base/ts/mathUtils.h"
18#include "pxr/base/ts/types.h"
19#include "pxr/base/vt/value.h"
24PXR_NAMESPACE_OPEN_SCOPE
26class Ts_PolymorphicDataHolder;
36 virtual void CloneInto(Ts_PolymorphicDataHolder *holder)
const = 0;
40 virtual std::shared_ptr<Ts_UntypedEvalCache> CreateEvalCache(
47 EvalUncached(
Ts_Data const *kf2, TsTime time)
const = 0;
53 EvalDerivativeUncached(
Ts_Data const *kf2, TsTime time)
const = 0;
55 virtual bool operator==(
const Ts_Data &)
const = 0;
58 inline TsTime GetTime()
const {
61 inline void SetTime(TsTime newTime) {
66 virtual TsKnotType GetKnotType()
const = 0;
67 virtual void SetKnotType( TsKnotType knotType ) = 0;
68 virtual bool CanSetKnotType( TsKnotType knotType,
69 std::string *reason )
const = 0;
72 virtual VtValue GetValue()
const = 0;
73 virtual void SetValue(
VtValue val ) = 0;
74 virtual VtValue GetValueDerivative()
const = 0;
75 virtual bool GetIsDualValued()
const = 0;
76 virtual void SetIsDualValued(
bool isDual ) = 0;
77 virtual VtValue GetLeftValue()
const = 0;
78 virtual VtValue GetLeftValueDerivative()
const = 0;
79 virtual void SetLeftValue(
VtValue ) = 0;
80 virtual VtValue GetZero()
const = 0;
81 virtual bool ValueCanBeInterpolated()
const = 0;
82 virtual bool ValueCanBeExtrapolated()
const = 0;
90 const VtValue& slope)
const = 0;
105 virtual VtValue GetLeftTangentSlope()
const = 0;
106 virtual VtValue GetRightTangentSlope()
const = 0;
107 virtual TsTime GetLeftTangentLength()
const = 0;
108 virtual TsTime GetRightTangentLength()
const = 0;
109 virtual void SetLeftTangentSlope(
VtValue ) = 0;
110 virtual void SetRightTangentSlope(
VtValue ) = 0;
111 virtual void SetLeftTangentLength( TsTime ) = 0;
112 virtual void SetRightTangentLength( TsTime ) = 0;
113 virtual bool GetTangentSymmetryBroken()
const = 0;
114 virtual void SetTangentSymmetryBroken(
bool broken ) = 0;
115 virtual void ResetTangentSymmetryBroken() = 0;
124class Ts_TypedData :
public Ts_Data {
127 typedef Ts_TypedData<T> This;
129 Ts_TypedData(
const T&);
135 const T& leftTangentSlope,
136 const T& rightTangentSlope);
138 ~Ts_TypedData()
override =
default;
140 void CloneInto(Ts_PolymorphicDataHolder *holder)
const override;
144 std::shared_ptr<Ts_UntypedEvalCache> CreateEvalCache(
145 Ts_Data const* kf2)
const override;
151 Ts_Data const *kf2, TsTime time)
const override;
156 VtValue EvalDerivativeUncached(
157 Ts_Data const *kf2, TsTime time)
const override;
161 std::shared_ptr<Ts_EvalCache<T,
162 TsTraits<T>::interpolatable> > CreateTypedEvalCache(
165 bool operator==(
const Ts_Data &)
const override;
168 TsKnotType GetKnotType()
const override;
169 void SetKnotType( TsKnotType knotType )
override;
171 TsKnotType knotType, std::string *reason )
const override;
174 VtValue GetValue()
const override;
175 void SetValue(
VtValue )
override;
176 VtValue GetValueDerivative()
const override;
177 bool GetIsDualValued()
const override;
178 void SetIsDualValued(
bool isDual )
override;
179 VtValue GetLeftValue()
const override;
180 VtValue GetLeftValueDerivative()
const override;
181 void SetLeftValue(
VtValue )
override;
182 VtValue GetZero()
const override;
183 bool ValueCanBeInterpolated()
const override;
184 bool ValueCanBeExtrapolated()
const override;
189 VtValue GetLeftTangentSlope()
const override;
190 VtValue GetRightTangentSlope()
const override;
191 TsTime GetLeftTangentLength()
const override;
192 TsTime GetRightTangentLength()
const override;
193 void SetLeftTangentSlope(
VtValue )
override;
194 void SetRightTangentSlope(
VtValue )
override;
195 void SetLeftTangentLength( TsTime )
override;
196 void SetRightTangentLength( TsTime )
override;
197 bool GetTangentSymmetryBroken()
const override;
198 void SetTangentSymmetryBroken(
bool broken )
override;
199 void ResetTangentSymmetryBroken()
override;
207 if constexpr (TsTraits<T>::extrapolatable)
209 const TsTime dx = right.GetTime() - GetTime();
210 const TsTime dxInv = 1.0 / dx;
212 const T y1 = GetValue().template Get<T>();
213 const T y2 = right.GetLeftValue().template Get<T>();
214 const T dy = y2 - y1;
218 const T slope = dy * dxInv;
223 return VtValue(TsTraits<T>::zero);
228 const VtValue &value, TsTime dt,
const VtValue &slope)
const override
230 if constexpr (TsTraits<T>::extrapolatable)
232 const T v = value.template Get<T>();
233 const T s = slope.template Get<T>();
234 const T result = v + dt * s;
247 T
const& _GetRightValue()
const {
248 return _values.
Get()._rhv;
250 T
const& _GetLeftValue()
const {
251 return _values.Get()._lhv;
253 T
const& _GetRightTangentSlope()
const {
254 return _values.Get()._rightTangentSlope;
256 T
const& _GetLeftTangentSlope()
const {
257 return _values.Get()._leftTangentSlope;
260 void _SetRightValue(T
const& rhv) {
261 _values.GetMutable()._rhv = rhv;
263 void _SetLeftValue(T
const& lhv) {
264 _values.GetMutable()._lhv = lhv;
266 void _SetRightTangentSlope(T
const& rightTangentSlope) {
267 _values.GetMutable()._rightTangentSlope = rightTangentSlope;
269 void _SetLeftTangentSlope(T
const& leftTangentSlope) {
270 _values.GetMutable()._leftTangentSlope = leftTangentSlope;
275 friend class Ts_UntypedEvalCache;
276 friend class Ts_EvalQuaternionCache<T>;
277 friend class Ts_EvalCache<T, TsTraits<T>::interpolatable>;
284 V
const& lhv=TsTraits<T>::zero,
285 V
const& rhv=TsTraits<T>::zero,
286 V
const& leftTangentSlope=TsTraits<T>::zero,
287 V
const& rightTangentSlope=TsTraits<T>::zero) :
290 _leftTangentSlope(leftTangentSlope),
291 _rightTangentSlope(rightTangentSlope)
300 V _leftTangentSlope, _rightTangentSlope;
310 static constexpr size_t _size =
sizeof(_Values<double>);
311 static constexpr bool _isSmall = (
sizeof(_Values<T>) <= _size);
316 _LocalStorage(_Values<T> &&values)
317 : _data(
std::move(values)) {}
319 const _Values<T>& Get()
const {
return _data; }
320 _Values<T>& GetMutable() {
return _data; }
328 _HeapStorage(_Values<T> &&values)
329 : _data(new _Values<T>(
std::move(values))) {}
332 _HeapStorage(
const _HeapStorage &other)
333 : _data(new _Values<T>(other.Get())) {}
335 const _Values<T>& Get()
const {
return *_data; }
336 _Values<T>& GetMutable() {
return *_data; }
338 std::unique_ptr<_Values<T>> _data;
343 typename std::conditional<
344 _isSmall, _LocalStorage, _HeapStorage>::type;
348 explicit _ValuesHolder(_Values<T> &&values)
349 : _storage(
std::move(values)) {}
352 _ValuesHolder(
const _ValuesHolder &other)
353 : _storage(other._storage) {}
356 ~_ValuesHolder() { _storage.~_Storage(); }
359 const _Values<T>& Get()
const {
return _storage.Get(); }
360 _Values<T>& GetMutable() {
return _storage.GetMutable(); }
366 char _padding[_size];
372 sizeof(_ValuesHolder) ==
sizeof(_Values<double>),
373 "_ValuesHolder does not have expected type-independent size");
376 _ValuesHolder _values;
379 TsTime _leftTangentLength, _rightTangentLength;
381 TsKnotType _knotType;
383 bool _tangentSymmetryBroken;
389class Ts_PolymorphicDataHolder
393 template <
typename T>
394 void New(
const T &val)
396 new (&_storage) Ts_TypedData<T>(val);
400 template <
typename T>
406 const T &leftTangentSlope,
407 const T &rightTangentSlope)
409 new (&_storage) Ts_TypedData<T>(
410 t, isDual, leftValue, rightValue,
411 leftTangentSlope, rightTangentSlope);
415 template <
typename T>
416 void New(
const Ts_TypedData<T> &other)
418 new (&_storage) Ts_TypedData<T>(other);
431 return reinterpret_cast<const Ts_Data*
>(&_storage);
437 return reinterpret_cast<Ts_Data*
>(&_storage);
444 typename std::aligned_storage<
445 sizeof(Ts_TypedData<double>),
sizeof(
void*)>::type;
455Ts_TypedData<T>::Ts_TypedData(
const T& value) :
456 _values(_Values<T>(value,value)),
457 _leftTangentLength(0.0),
458 _rightTangentLength(0.0),
459 _knotType(TsKnotHeld),
461 _tangentSymmetryBroken(false)
466Ts_TypedData<T>::Ts_TypedData(
471 const T& leftTangentSlope,
472 const T& rightTangentSlope) :
473 _values(_Values<T>(leftValue,rightValue,
474 leftTangentSlope,rightTangentSlope)),
475 _leftTangentLength(0.0),
476 _rightTangentLength(0.0),
477 _knotType(TsKnotHeld),
479 _tangentSymmetryBroken(false)
486Ts_TypedData<T>::CloneInto(Ts_PolymorphicDataHolder *holder)
const
492std::shared_ptr<Ts_UntypedEvalCache>
493Ts_TypedData<T>::CreateEvalCache(
Ts_Data const* kf2)
const
497 Ts_TypedData<T>
const* typedKf2 =
498 static_cast<Ts_TypedData<T> const*
>(kf2);
501 return std::make_shared<
502 Ts_EvalCache<T, TsTraits<T>::interpolatable>>(
this, typedKf2);
506std::shared_ptr<Ts_EvalCache<T, TsTraits<T>::interpolatable> >
507Ts_TypedData<T>::CreateTypedEvalCache(
Ts_Data const* kf2)
const
509 Ts_TypedData<T>
const* typedKf2 =
510 static_cast<Ts_TypedData<T> const*
>(kf2);
512 return std::shared_ptr<Ts_EvalCache<T, TsTraits<T>::interpolatable> >(
513 new Ts_EvalCache<T, TsTraits<T>::interpolatable>(
this, typedKf2));
519::EvalUncached(
Ts_Data const *kf2, TsTime time)
const
523 Ts_TypedData<T>
const* typedKf2 =
524 static_cast<Ts_TypedData<T> const*
>(kf2);
526 return Ts_EvalCache<T, TsTraits<T>::interpolatable>(
this, typedKf2)
533::EvalDerivativeUncached(
Ts_Data const *kf2, TsTime time)
const
537 Ts_TypedData<T>
const* typedKf2 =
538 static_cast<Ts_TypedData<T> const*
>(kf2);
540 return Ts_EvalCache<T, TsTraits<T>::interpolatable>(
this, typedKf2)
541 .EvalDerivative(time);
546Ts_TypedData<T>::operator==(
const Ts_Data &rhs)
const
548 if (!TsTraits<T>::supportsTangents) {
550 GetKnotType() == rhs.GetKnotType() &&
551 GetTime() == rhs.GetTime() &&
552 GetValue() == rhs.GetValue() &&
553 GetIsDualValued() == rhs.GetIsDualValued() &&
554 (!GetIsDualValued() || (GetLeftValue() == rhs.GetLeftValue()));
558 GetTime() == rhs.GetTime() &&
559 GetValue() == rhs.GetValue() &&
560 GetKnotType() == rhs.GetKnotType() &&
561 GetIsDualValued() == rhs.GetIsDualValued() &&
562 (!GetIsDualValued() || (GetLeftValue() == rhs.GetLeftValue())) &&
563 GetLeftTangentLength() == rhs.GetLeftTangentLength() &&
564 GetRightTangentLength() == rhs.GetRightTangentLength() &&
565 GetLeftTangentSlope() == rhs.GetLeftTangentSlope() &&
566 GetRightTangentSlope() == rhs.GetRightTangentSlope() &&
567 GetTangentSymmetryBroken() == rhs.GetTangentSymmetryBroken();
572Ts_TypedData<T>::GetKnotType()
const
579Ts_TypedData<T>::SetKnotType( TsKnotType knotType )
583 if (!CanSetKnotType(knotType, &reason)) {
588 _knotType = knotType;
593Ts_TypedData<T>::CanSetKnotType( TsKnotType knotType,
594 std::string *reason )
const
597 if (!ValueCanBeInterpolated() && knotType != TsKnotHeld) {
599 *reason =
"Value cannot be interpolated; only 'held' " \
600 "key frames are allowed.";
606 if (!TsTraits<T>::supportsTangents && knotType == TsKnotBezier) {
609 "Cannot set keyframe type %s; values of type '%s' "
610 "do not support tangents.",
622Ts_TypedData<T>::GetValue()
const
624 return VtValue(_GetRightValue());
629Ts_TypedData<T>::GetValueDerivative()
const
631 if (TsTraits<T>::supportsTangents) {
632 return GetRightTangentSlope();
634 return VtValue(TsTraits<T>::zero);
640Ts_TypedData<T>::SetValue(
VtValue val )
644 _SetRightValue(v.
Get<T>());
645 if (!ValueCanBeInterpolated())
646 SetKnotType(TsKnotHeld);
656Ts_TypedData<T>::GetIsDualValued()
const
663Ts_TypedData<T>::SetIsDualValued(
bool isDual )
665 if (isDual && !TsTraits<T>::interpolatable) {
676 SetLeftValue(GetValue());
682Ts_TypedData<T>::GetLeftValue()
const
684 return VtValue(_isDual ? _GetLeftValue() : _GetRightValue());
689Ts_TypedData<T>::GetLeftValueDerivative()
const
691 if (TsTraits<T>::supportsTangents) {
692 return GetLeftTangentSlope();
694 return VtValue(TsTraits<T>::zero);
700Ts_TypedData<T>::SetLeftValue(
VtValue val )
702 if (!TsTraits<T>::interpolatable) {
707 if (!GetIsDualValued()) {
714 _SetLeftValue(v.
Get<T>());
715 if (!ValueCanBeInterpolated())
716 SetKnotType(TsKnotHeld);
726Ts_TypedData<T>::GetZero()
const
728 return VtValue(TsTraits<T>::zero);
733Ts_TypedData<T>::ValueCanBeInterpolated()
const
735 return TsTraits<T>::interpolatable;
740Ts_TypedData<T>::ValueCanBeExtrapolated()
const
742 return TsTraits<T>::extrapolatable;
747Ts_TypedData<T>::HasTangents()
const
749 return TsTraits<T>::supportsTangents && _knotType == TsKnotBezier;
754Ts_TypedData<T>::ValueTypeSupportsTangents()
const
758 return TsTraits<T>::supportsTangents;
763Ts_TypedData<T>::GetLeftTangentSlope()
const
765 if (!TsTraits<T>::supportsTangents) {
771 return VtValue(_GetLeftTangentSlope());
776Ts_TypedData<T>::GetRightTangentSlope()
const
778 if (!TsTraits<T>::supportsTangents) {
784 return VtValue(_GetRightTangentSlope());
789Ts_TypedData<T>::GetLeftTangentLength()
const
791 if (!TsTraits<T>::supportsTangents) {
797 return _leftTangentLength;
802Ts_TypedData<T>::GetRightTangentLength()
const
804 if (!TsTraits<T>::supportsTangents) {
810 return _rightTangentLength;
815Ts_TypedData<T>::SetLeftTangentSlope(
VtValue val )
817 if (!TsTraits<T>::supportsTangents) {
825 _SetLeftTangentSlope(val.
Get<T>());
835Ts_TypedData<T>::SetRightTangentSlope(
VtValue val )
837 if (!TsTraits<T>::supportsTangents) {
845 _SetRightTangentSlope(val.
Get<T>());
847 TF_CODING_ERROR(
"cannot convert type '%s' to '%s' to assign to keyframe"
853#define TS_LENGTH_EPSILON 1e-6
857Ts_TypedData<T>::SetLeftTangentLength( TsTime newLen )
859 if (!TsTraits<T>::supportsTangents) {
864 if (std::isnan(newLen)) {
868 if (std::isinf(newLen)) {
873 if (-newLen < TS_LENGTH_EPSILON) {
877 "Cannot set tangent length to negative value; ignoring");
882 _leftTangentLength = newLen;
887Ts_TypedData<T>::SetRightTangentLength( TsTime newLen )
889 if (!TsTraits<T>::supportsTangents) {
894 if (std::isnan(newLen)) {
898 if (std::isinf(newLen)) {
903 if (-newLen < TS_LENGTH_EPSILON) {
907 "Cannot set tangent length to negative value; ignoring");
912 _rightTangentLength = newLen;
917Ts_TypedData<T>::GetTangentSymmetryBroken()
const
919 if (!TsTraits<T>::supportsTangents) {
925 return _tangentSymmetryBroken;
930Ts_TypedData<T>::SetTangentSymmetryBroken(
bool broken )
932 if (!TsTraits<T>::supportsTangents) {
938 if (_tangentSymmetryBroken != broken) {
939 _tangentSymmetryBroken = broken;
940 if (!_tangentSymmetryBroken) {
941 _SetLeftTangentSlope(_GetRightTangentSlope());
948Ts_TypedData<T>::ResetTangentSymmetryBroken()
957Ts_TypedData<float>::ResetTangentSymmetryBroken();
961Ts_TypedData<double>::ResetTangentSymmetryBroken();
965Ts_TypedData<float>::ValueCanBeInterpolated()
const;
969Ts_TypedData<double>::ValueCanBeInterpolated()
const;
971PXR_NAMESPACE_CLOSE_SCOPE
Low-level utilities for informing users of various internal and external diagnostic conditions.
static TF_API std::string GetDisplayName(TfEnum val)
Returns the display name for an enumerated value.
Holds the data for an TsKeyFrame.
virtual bool ValueTypeSupportsTangents() const =0
If true, implies the tangents can be written.
virtual bool HasTangents() const =0
True if the data type supports tangents, and the knot type is one that shows tangents in the UI.
Specifies the value of an TsSpline object at a particular point in time.
Provides a container which may hold any type, and provides introspection and iteration over array typ...
VT_API std::string GetTypeName() const
Return the type name of the held typeid.
bool IsEmpty() const
Returns true iff this value is empty.
static VtValue Cast(VtValue const &val)
Return a VtValue holding val cast to hold T.
T const & Get() const &
Returns a const reference to the held object if the held object is of type T.
Demangle C++ typenames generated by the typeid() facility.
Assorted mathematical utility functions.
std::string ArchGetDemangled()
Return demangled RTTI generated-type name.
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
TF_API std::string TfStringPrintf(const char *fmt,...)
Returns a string formed by a printf()-like specification.