25#ifndef PXR_BASE_TS_DATA_H
26#define PXR_BASE_TS_DATA_H
29#include "pxr/base/ts/api.h"
33#include "pxr/base/ts/evalCache.h"
34#include "pxr/base/ts/mathUtils.h"
35#include "pxr/base/ts/types.h"
36#include "pxr/base/vt/value.h"
41PXR_NAMESPACE_OPEN_SCOPE
43class Ts_PolymorphicDataHolder;
53 virtual void CloneInto(Ts_PolymorphicDataHolder *holder)
const = 0;
57 virtual std::shared_ptr<Ts_UntypedEvalCache> CreateEvalCache(
64 EvalUncached(
Ts_Data const *kf2, TsTime time)
const = 0;
70 EvalDerivativeUncached(
Ts_Data const *kf2, TsTime time)
const = 0;
72 virtual bool operator==(
const Ts_Data &)
const = 0;
75 inline TsTime GetTime()
const {
78 inline void SetTime(TsTime newTime) {
83 virtual TsKnotType GetKnotType()
const = 0;
84 virtual void SetKnotType( TsKnotType knotType ) = 0;
85 virtual bool CanSetKnotType( TsKnotType knotType,
86 std::string *reason )
const = 0;
89 virtual VtValue GetValue()
const = 0;
90 virtual void SetValue(
VtValue val ) = 0;
91 virtual VtValue GetValueDerivative()
const = 0;
92 virtual bool GetIsDualValued()
const = 0;
93 virtual void SetIsDualValued(
bool isDual ) = 0;
94 virtual VtValue GetLeftValue()
const = 0;
95 virtual VtValue GetLeftValueDerivative()
const = 0;
96 virtual void SetLeftValue(
VtValue ) = 0;
97 virtual VtValue GetZero()
const = 0;
98 virtual bool ValueCanBeInterpolated()
const = 0;
99 virtual bool ValueCanBeExtrapolated()
const = 0;
107 const VtValue& slope)
const = 0;
122 virtual VtValue GetLeftTangentSlope()
const = 0;
123 virtual VtValue GetRightTangentSlope()
const = 0;
124 virtual TsTime GetLeftTangentLength()
const = 0;
125 virtual TsTime GetRightTangentLength()
const = 0;
126 virtual void SetLeftTangentSlope(
VtValue ) = 0;
127 virtual void SetRightTangentSlope(
VtValue ) = 0;
128 virtual void SetLeftTangentLength( TsTime ) = 0;
129 virtual void SetRightTangentLength( TsTime ) = 0;
130 virtual bool GetTangentSymmetryBroken()
const = 0;
131 virtual void SetTangentSymmetryBroken(
bool broken ) = 0;
132 virtual void ResetTangentSymmetryBroken() = 0;
141class Ts_TypedData :
public Ts_Data {
144 typedef Ts_TypedData<T> This;
146 Ts_TypedData(
const T&);
152 const T& leftTangentSlope,
153 const T& rightTangentSlope);
155 ~Ts_TypedData()
override =
default;
157 void CloneInto(Ts_PolymorphicDataHolder *holder)
const override;
161 std::shared_ptr<Ts_UntypedEvalCache> CreateEvalCache(
162 Ts_Data const* kf2)
const override;
168 Ts_Data const *kf2, TsTime time)
const override;
173 VtValue EvalDerivativeUncached(
174 Ts_Data const *kf2, TsTime time)
const override;
178 std::shared_ptr<Ts_EvalCache<T,
179 TsTraits<T>::interpolatable> > CreateTypedEvalCache(
182 bool operator==(
const Ts_Data &)
const override;
185 TsKnotType GetKnotType()
const override;
186 void SetKnotType( TsKnotType knotType )
override;
188 TsKnotType knotType, std::string *reason )
const override;
191 VtValue GetValue()
const override;
192 void SetValue(
VtValue )
override;
193 VtValue GetValueDerivative()
const override;
194 bool GetIsDualValued()
const override;
195 void SetIsDualValued(
bool isDual )
override;
196 VtValue GetLeftValue()
const override;
197 VtValue GetLeftValueDerivative()
const override;
198 void SetLeftValue(
VtValue )
override;
199 VtValue GetZero()
const override;
200 bool ValueCanBeInterpolated()
const override;
201 bool ValueCanBeExtrapolated()
const override;
206 VtValue GetLeftTangentSlope()
const override;
207 VtValue GetRightTangentSlope()
const override;
208 TsTime GetLeftTangentLength()
const override;
209 TsTime GetRightTangentLength()
const override;
210 void SetLeftTangentSlope(
VtValue )
override;
211 void SetRightTangentSlope(
VtValue )
override;
212 void SetLeftTangentLength( TsTime )
override;
213 void SetRightTangentLength( TsTime )
override;
214 bool GetTangentSymmetryBroken()
const override;
215 void SetTangentSymmetryBroken(
bool broken )
override;
216 void ResetTangentSymmetryBroken()
override;
224 if constexpr (TsTraits<T>::extrapolatable)
226 const TsTime dx = right.GetTime() - GetTime();
227 const TsTime dxInv = 1.0 / dx;
229 const T y1 = GetValue().template Get<T>();
230 const T y2 = right.GetLeftValue().template Get<T>();
231 const T dy = y2 - y1;
235 const T slope = dy * dxInv;
240 return VtValue(TsTraits<T>::zero);
245 const VtValue &value, TsTime dt,
const VtValue &slope)
const override
247 if constexpr (TsTraits<T>::extrapolatable)
249 const T v = value.template Get<T>();
250 const T s = slope.template Get<T>();
251 const T result = v + dt * s;
264 T
const& _GetRightValue()
const {
265 return _values.
Get()._rhv;
267 T
const& _GetLeftValue()
const {
268 return _values.Get()._lhv;
270 T
const& _GetRightTangentSlope()
const {
271 return _values.Get()._rightTangentSlope;
273 T
const& _GetLeftTangentSlope()
const {
274 return _values.Get()._leftTangentSlope;
277 void _SetRightValue(T
const& rhv) {
278 _values.GetMutable()._rhv = rhv;
280 void _SetLeftValue(T
const& lhv) {
281 _values.GetMutable()._lhv = lhv;
283 void _SetRightTangentSlope(T
const& rightTangentSlope) {
284 _values.GetMutable()._rightTangentSlope = rightTangentSlope;
286 void _SetLeftTangentSlope(T
const& leftTangentSlope) {
287 _values.GetMutable()._leftTangentSlope = leftTangentSlope;
292 friend class Ts_UntypedEvalCache;
293 friend class Ts_EvalQuaternionCache<T>;
294 friend class Ts_EvalCache<T, TsTraits<T>::interpolatable>;
301 V
const& lhv=TsTraits<T>::zero,
302 V
const& rhv=TsTraits<T>::zero,
303 V
const& leftTangentSlope=TsTraits<T>::zero,
304 V
const& rightTangentSlope=TsTraits<T>::zero) :
307 _leftTangentSlope(leftTangentSlope),
308 _rightTangentSlope(rightTangentSlope)
317 V _leftTangentSlope, _rightTangentSlope;
327 static constexpr size_t _size =
sizeof(_Values<double>);
328 static constexpr bool _isSmall = (
sizeof(_Values<T>) <= _size);
333 _LocalStorage(_Values<T> &&values)
334 : _data(
std::move(values)) {}
336 const _Values<T>& Get()
const {
return _data; }
337 _Values<T>& GetMutable() {
return _data; }
345 _HeapStorage(_Values<T> &&values)
346 : _data(new _Values<T>(
std::move(values))) {}
349 _HeapStorage(
const _HeapStorage &other)
350 : _data(new _Values<T>(other.Get())) {}
352 const _Values<T>& Get()
const {
return *_data; }
353 _Values<T>& GetMutable() {
return *_data; }
355 std::unique_ptr<_Values<T>> _data;
360 typename std::conditional<
361 _isSmall, _LocalStorage, _HeapStorage>::type;
365 explicit _ValuesHolder(_Values<T> &&values)
366 : _storage(
std::move(values)) {}
369 _ValuesHolder(
const _ValuesHolder &other)
370 : _storage(other._storage) {}
373 ~_ValuesHolder() { _storage.~_Storage(); }
376 const _Values<T>& Get()
const {
return _storage.Get(); }
377 _Values<T>& GetMutable() {
return _storage.GetMutable(); }
383 char _padding[_size];
389 sizeof(_ValuesHolder) ==
sizeof(_Values<double>),
390 "_ValuesHolder does not have expected type-independent size");
393 _ValuesHolder _values;
396 TsTime _leftTangentLength, _rightTangentLength;
398 TsKnotType _knotType;
400 bool _tangentSymmetryBroken;
406class Ts_PolymorphicDataHolder
410 template <
typename T>
411 void New(
const T &val)
413 new (&_storage) Ts_TypedData<T>(val);
417 template <
typename T>
423 const T &leftTangentSlope,
424 const T &rightTangentSlope)
426 new (&_storage) Ts_TypedData<T>(
427 t, isDual, leftValue, rightValue,
428 leftTangentSlope, rightTangentSlope);
432 template <
typename T>
433 void New(
const Ts_TypedData<T> &other)
435 new (&_storage) Ts_TypedData<T>(other);
448 return reinterpret_cast<const Ts_Data*
>(&_storage);
454 return reinterpret_cast<Ts_Data*
>(&_storage);
461 typename std::aligned_storage<
462 sizeof(Ts_TypedData<double>),
sizeof(
void*)>::type;
472Ts_TypedData<T>::Ts_TypedData(
const T& value) :
473 _values(_Values<T>(value,value)),
474 _leftTangentLength(0.0),
475 _rightTangentLength(0.0),
476 _knotType(TsKnotHeld),
478 _tangentSymmetryBroken(false)
483Ts_TypedData<T>::Ts_TypedData(
488 const T& leftTangentSlope,
489 const T& rightTangentSlope) :
490 _values(_Values<T>(leftValue,rightValue,
491 leftTangentSlope,rightTangentSlope)),
492 _leftTangentLength(0.0),
493 _rightTangentLength(0.0),
494 _knotType(TsKnotHeld),
496 _tangentSymmetryBroken(false)
503Ts_TypedData<T>::CloneInto(Ts_PolymorphicDataHolder *holder)
const
509std::shared_ptr<Ts_UntypedEvalCache>
510Ts_TypedData<T>::CreateEvalCache(
Ts_Data const* kf2)
const
514 Ts_TypedData<T>
const* typedKf2 =
515 static_cast<Ts_TypedData<T> const*
>(kf2);
518 return std::make_shared<
519 Ts_EvalCache<T, TsTraits<T>::interpolatable>>(
this, typedKf2);
523std::shared_ptr<Ts_EvalCache<T, TsTraits<T>::interpolatable> >
524Ts_TypedData<T>::CreateTypedEvalCache(
Ts_Data const* kf2)
const
526 Ts_TypedData<T>
const* typedKf2 =
527 static_cast<Ts_TypedData<T> const*
>(kf2);
529 return std::shared_ptr<Ts_EvalCache<T, TsTraits<T>::interpolatable> >(
530 new Ts_EvalCache<T, TsTraits<T>::interpolatable>(
this, typedKf2));
536::EvalUncached(
Ts_Data const *kf2, TsTime time)
const
540 Ts_TypedData<T>
const* typedKf2 =
541 static_cast<Ts_TypedData<T> const*
>(kf2);
543 return Ts_EvalCache<T, TsTraits<T>::interpolatable>(
this, typedKf2)
550::EvalDerivativeUncached(
Ts_Data const *kf2, TsTime time)
const
554 Ts_TypedData<T>
const* typedKf2 =
555 static_cast<Ts_TypedData<T> const*
>(kf2);
557 return Ts_EvalCache<T, TsTraits<T>::interpolatable>(
this, typedKf2)
558 .EvalDerivative(time);
563Ts_TypedData<T>::operator==(
const Ts_Data &rhs)
const
565 if (!TsTraits<T>::supportsTangents) {
567 GetKnotType() == rhs.GetKnotType() &&
568 GetTime() == rhs.GetTime() &&
569 GetValue() == rhs.GetValue() &&
570 GetIsDualValued() == rhs.GetIsDualValued() &&
571 (!GetIsDualValued() || (GetLeftValue() == rhs.GetLeftValue()));
575 GetTime() == rhs.GetTime() &&
576 GetValue() == rhs.GetValue() &&
577 GetKnotType() == rhs.GetKnotType() &&
578 GetIsDualValued() == rhs.GetIsDualValued() &&
579 (!GetIsDualValued() || (GetLeftValue() == rhs.GetLeftValue())) &&
580 GetLeftTangentLength() == rhs.GetLeftTangentLength() &&
581 GetRightTangentLength() == rhs.GetRightTangentLength() &&
582 GetLeftTangentSlope() == rhs.GetLeftTangentSlope() &&
583 GetRightTangentSlope() == rhs.GetRightTangentSlope() &&
584 GetTangentSymmetryBroken() == rhs.GetTangentSymmetryBroken();
589Ts_TypedData<T>::GetKnotType()
const
596Ts_TypedData<T>::SetKnotType( TsKnotType knotType )
600 if (!CanSetKnotType(knotType, &reason)) {
605 _knotType = knotType;
610Ts_TypedData<T>::CanSetKnotType( TsKnotType knotType,
611 std::string *reason )
const
614 if (!ValueCanBeInterpolated() && knotType != TsKnotHeld) {
616 *reason =
"Value cannot be interpolated; only 'held' " \
617 "key frames are allowed.";
623 if (!TsTraits<T>::supportsTangents && knotType == TsKnotBezier) {
626 "Cannot set keyframe type %s; values of type '%s' "
627 "do not support tangents.",
639Ts_TypedData<T>::GetValue()
const
641 return VtValue(_GetRightValue());
646Ts_TypedData<T>::GetValueDerivative()
const
648 if (TsTraits<T>::supportsTangents) {
649 return GetRightTangentSlope();
651 return VtValue(TsTraits<T>::zero);
657Ts_TypedData<T>::SetValue(
VtValue val )
661 _SetRightValue(v.
Get<T>());
662 if (!ValueCanBeInterpolated())
663 SetKnotType(TsKnotHeld);
673Ts_TypedData<T>::GetIsDualValued()
const
680Ts_TypedData<T>::SetIsDualValued(
bool isDual )
682 if (isDual && !TsTraits<T>::interpolatable) {
693 SetLeftValue(GetValue());
699Ts_TypedData<T>::GetLeftValue()
const
701 return VtValue(_isDual ? _GetLeftValue() : _GetRightValue());
706Ts_TypedData<T>::GetLeftValueDerivative()
const
708 if (TsTraits<T>::supportsTangents) {
709 return GetLeftTangentSlope();
711 return VtValue(TsTraits<T>::zero);
717Ts_TypedData<T>::SetLeftValue(
VtValue val )
719 if (!TsTraits<T>::interpolatable) {
724 if (!GetIsDualValued()) {
731 _SetLeftValue(v.
Get<T>());
732 if (!ValueCanBeInterpolated())
733 SetKnotType(TsKnotHeld);
743Ts_TypedData<T>::GetZero()
const
745 return VtValue(TsTraits<T>::zero);
750Ts_TypedData<T>::ValueCanBeInterpolated()
const
752 return TsTraits<T>::interpolatable;
757Ts_TypedData<T>::ValueCanBeExtrapolated()
const
759 return TsTraits<T>::extrapolatable;
764Ts_TypedData<T>::HasTangents()
const
766 return TsTraits<T>::supportsTangents && _knotType == TsKnotBezier;
771Ts_TypedData<T>::ValueTypeSupportsTangents()
const
775 return TsTraits<T>::supportsTangents;
780Ts_TypedData<T>::GetLeftTangentSlope()
const
782 if (!TsTraits<T>::supportsTangents) {
788 return VtValue(_GetLeftTangentSlope());
793Ts_TypedData<T>::GetRightTangentSlope()
const
795 if (!TsTraits<T>::supportsTangents) {
801 return VtValue(_GetRightTangentSlope());
806Ts_TypedData<T>::GetLeftTangentLength()
const
808 if (!TsTraits<T>::supportsTangents) {
814 return _leftTangentLength;
819Ts_TypedData<T>::GetRightTangentLength()
const
821 if (!TsTraits<T>::supportsTangents) {
827 return _rightTangentLength;
832Ts_TypedData<T>::SetLeftTangentSlope(
VtValue val )
834 if (!TsTraits<T>::supportsTangents) {
842 _SetLeftTangentSlope(val.
Get<T>());
852Ts_TypedData<T>::SetRightTangentSlope(
VtValue val )
854 if (!TsTraits<T>::supportsTangents) {
862 _SetRightTangentSlope(val.
Get<T>());
864 TF_CODING_ERROR(
"cannot convert type '%s' to '%s' to assign to keyframe"
870#define TS_LENGTH_EPSILON 1e-6
874Ts_TypedData<T>::SetLeftTangentLength( TsTime newLen )
876 if (!TsTraits<T>::supportsTangents) {
881 if (std::isnan(newLen)) {
885 if (std::isinf(newLen)) {
890 if (-newLen < TS_LENGTH_EPSILON) {
894 "Cannot set tangent length to negative value; ignoring");
899 _leftTangentLength = newLen;
904Ts_TypedData<T>::SetRightTangentLength( TsTime newLen )
906 if (!TsTraits<T>::supportsTangents) {
911 if (std::isnan(newLen)) {
915 if (std::isinf(newLen)) {
920 if (-newLen < TS_LENGTH_EPSILON) {
924 "Cannot set tangent length to negative value; ignoring");
929 _rightTangentLength = newLen;
934Ts_TypedData<T>::GetTangentSymmetryBroken()
const
936 if (!TsTraits<T>::supportsTangents) {
942 return _tangentSymmetryBroken;
947Ts_TypedData<T>::SetTangentSymmetryBroken(
bool broken )
949 if (!TsTraits<T>::supportsTangents) {
955 if (_tangentSymmetryBroken != broken) {
956 _tangentSymmetryBroken = broken;
957 if (!_tangentSymmetryBroken) {
958 _SetLeftTangentSlope(_GetRightTangentSlope());
965Ts_TypedData<T>::ResetTangentSymmetryBroken()
974Ts_TypedData<float>::ResetTangentSymmetryBroken();
978Ts_TypedData<double>::ResetTangentSymmetryBroken();
982Ts_TypedData<float>::ValueCanBeInterpolated()
const;
986Ts_TypedData<double>::ValueCanBeInterpolated()
const;
988PXR_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.