8#ifndef PXR_BASE_TS_SPLINE_DATA_H
9#define PXR_BASE_TS_SPLINE_DATA_H
12#include "pxr/base/ts/api.h"
13#include "pxr/base/ts/knotData.h"
14#include "pxr/base/ts/types.h"
15#include "pxr/base/ts/typeHelpers.h"
18#include "pxr/base/tf/type.h"
22#include <unordered_map>
28PXR_NAMESPACE_OPEN_SCOPE
47 static Ts_SplineData* Create(
49 const Ts_SplineData *overallParamSource =
nullptr);
51 virtual ~Ts_SplineData();
56 virtual TfType GetValueType()
const = 0;
57 virtual size_t GetKnotStructSize()
const = 0;
58 virtual Ts_SplineData* Clone()
const = 0;
60 virtual bool operator==(
const Ts_SplineData &other)
const = 0;
62 virtual void ReserveForKnotCount(
size_t count) = 0;
63 virtual void PushKnot(
64 const Ts_KnotData *knotData,
66 virtual size_t SetKnot(
67 const Ts_KnotData *knotData,
70 virtual Ts_KnotData* CloneKnotAtIndex(
size_t index)
const = 0;
71 virtual Ts_KnotData* CloneKnotAtTime(TsTime time)
const = 0;
72 virtual Ts_KnotData* GetKnotPtrAtIndex(
size_t index) = 0;
73 virtual Ts_TypedKnotData<double>
74 GetKnotDataAsDouble(
size_t index)
const = 0;
76 virtual void ClearKnots() = 0;
77 virtual void RemoveKnotAtTime(TsTime time) = 0;
79 virtual void ApplyOffsetAndScale(
83 virtual bool HasValueBlocks()
const = 0;
84 virtual bool HasValueBlockAtTime(TsTime time)
const = 0;
91 size_t *firstProtoIndexOut =
nullptr)
const;
114 TsCurveType curveType : 2;
125 std::vector<TsTime> times;
128 std::unordered_map<TsTime, VtDictionary> customData;
135struct Ts_TypedSplineData final :
139 TfType GetValueType()
const override;
140 size_t GetKnotStructSize()
const override;
141 Ts_SplineData* Clone()
const override;
143 bool operator==(
const Ts_SplineData &other)
const override;
145 void ReserveForKnotCount(
size_t count)
override;
147 const Ts_KnotData *knotData,
150 const Ts_KnotData *knotData,
153 Ts_KnotData* CloneKnotAtIndex(
size_t index)
const override;
154 Ts_KnotData* CloneKnotAtTime(TsTime time)
const override;
155 Ts_KnotData* GetKnotPtrAtIndex(
size_t index)
override;
156 Ts_TypedKnotData<double>
157 GetKnotDataAsDouble(
size_t index)
const override;
159 void ClearKnots()
override;
160 void RemoveKnotAtTime(TsTime time)
override;
169 void ApplyOffsetAndScale(
171 double scale)
override;
173 bool HasValueBlocks()
const override;
174 bool HasValueBlockAtTime(TsTime time)
const override;
178 std::vector<Ts_TypedKnotData<T>> knots;
189Ts_GetSplineData(
const TsSpline &spline);
192Ts_TypedSplineData<T>*
193Ts_GetTypedSplineData(
TsSpline &spline);
196const Ts_TypedSplineData<T>*
197Ts_GetTypedSplineData(
const TsSpline &spline);
204TfType Ts_TypedSplineData<T>::GetValueType()
const
211 return Ts_GetType<T>();
215size_t Ts_TypedSplineData<T>::GetKnotStructSize()
const
217 return sizeof(Ts_TypedKnotData<T>);
222Ts_TypedSplineData<T>::Clone()
const
224 return new Ts_TypedSplineData<T>(*
this);
228bool Ts_TypedSplineData<T>::operator==(
229 const Ts_SplineData &other)
const
232 if (isTyped != other.isTyped
233 || timeValued != other.timeValued
234 || curveType != other.curveType
235 || preExtrapolation != other.preExtrapolation
236 || postExtrapolation != other.postExtrapolation
237 || loopParams != other.loopParams
238 || customData != other.customData)
245 const Ts_TypedSplineData<T>*
const typedOther =
246 dynamic_cast<const Ts_TypedSplineData<T>*
>(&other);
253 return knots == typedOther->knots;
257void Ts_TypedSplineData<T>::ReserveForKnotCount(
260 times.reserve(count);
261 knots.reserve(count);
265void Ts_TypedSplineData<T>::PushKnot(
266 const Ts_KnotData*
const knotData,
269 const Ts_TypedKnotData<T>*
const typedKnotData =
270 static_cast<const Ts_TypedKnotData<T>*
>(knotData);
272 times.push_back(knotData->time);
273 knots.push_back(*typedKnotData);
275 if (!customDataIn.
empty())
277 customData[knotData->time] = customDataIn;
282size_t Ts_TypedSplineData<T>::SetKnot(
283 const Ts_KnotData*
const knotData,
286 const Ts_TypedKnotData<T>*
const typedKnotData =
287 static_cast<const Ts_TypedKnotData<T>*
>(knotData);
291 std::lower_bound(times.begin(), times.end(), knotData->time);
294 const bool overwrite =
295 (it != times.end() && *it == knotData->time);
300 times[idx] = knotData->time;
301 knots[idx] = *typedKnotData;
305 times.insert(it, knotData->time);
306 knots.insert(knots.begin() + idx, *typedKnotData);
310 if (!customDataIn.
empty())
312 customData[knotData->time] = customDataIn;
320Ts_TypedSplineData<T>::CloneKnotAtIndex(
321 const size_t index)
const
323 return new Ts_TypedKnotData<T>(knots[index]);
328Ts_TypedSplineData<T>::CloneKnotAtTime(
329 const TsTime time)
const
331 const auto it = std::lower_bound(times.begin(), times.end(), time);
332 if (it == times.end() || *it != time)
337 const auto knotIt = knots.begin() + (it - times.begin());
338 return new Ts_TypedKnotData<T>(*knotIt);
343Ts_TypedSplineData<T>::GetKnotPtrAtIndex(
346 return &(knots[index]);
351Ts_TypedKnotData<double>
352Ts_TypedSplineData<T>::GetKnotDataAsDouble(
353 const size_t index)
const
355 const Ts_TypedKnotData<T> &in = knots[index];
356 Ts_TypedKnotData<double> out;
360 static_cast<Ts_KnotData&
>(out) =
static_cast<const Ts_KnotData&
>(in);
363 out.value = in.value;
364 out.preValue = in.preValue;
365 out.preTanSlope = in.preTanSlope;
366 out.postTanSlope = in.postTanSlope;
372void Ts_TypedSplineData<T>::ClearKnots()
380void Ts_TypedSplineData<T>::RemoveKnotAtTime(
383 const auto it = std::lower_bound(times.begin(), times.end(), time);
384 if (it == times.end() || *it != time)
390 const size_t idx = it - times.begin();
392 customData.erase(time);
393 knots.erase(knots.begin() + idx);
397static void _ApplyOffsetAndScaleToKnot(
398 Ts_TypedKnotData<T>*
const knotData,
406 knotData->time = knotData->time * scale + offset;
409 knotData->preTanWidth *= scale;
410 knotData->postTanWidth *= scale;
413 knotData->preTanSlope /= scale;
414 knotData->postTanSlope /= scale;
418void Ts_TypedSplineData<T>::ApplyOffsetAndScale(
425 "collapsing/reversing time and spline representation "
437 if (preExtrapolation.mode == TsExtrapSloped)
439 preExtrapolation.slope /= scale;
441 if (postExtrapolation.mode == TsExtrapSloped)
443 postExtrapolation.slope /= scale;
447 if (loopParams.protoEnd > loopParams.protoStart)
450 loopParams.protoStart = loopParams.protoStart * scale + offset;
451 loopParams.protoEnd = loopParams.protoEnd * scale + offset;
455 for (TsTime &time : times) {
456 time = time * scale + offset;
464 for (Ts_TypedKnotData<T> &knotData : knots)
466 _ApplyOffsetAndScaleToKnot(&knotData, offset, scale);
470 static_cast<T
>(knotData.value * scale + offset);
472 static_cast<T
>(knotData.preValue * scale + offset);
477 for (Ts_TypedKnotData<T> &knotData : knots) {
478 _ApplyOffsetAndScaleToKnot(&knotData, offset, scale);
483 if (!customData.empty())
485 std::unordered_map<TsTime, VtDictionary> newCustomData;
486 for (
const auto &mapPair : customData) {
487 newCustomData[mapPair.first * scale + offset] = mapPair.second;
489 customData.swap(newCustomData);
494bool Ts_TypedSplineData<T>::HasValueBlocks()
const
501 if (preExtrapolation.mode == TsExtrapValueBlock
502 || postExtrapolation.mode == TsExtrapValueBlock)
507 for (
const Ts_TypedKnotData<T> &knotData : knots)
509 if (knotData.nextInterp == TsInterpValueBlock)
519bool Ts_TypedSplineData<T>::HasValueBlockAtTime(
520 const TsTime time)
const
530 std::lower_bound(times.begin(), times.end(), time);
534 if (lbIt == times.end())
536 return postExtrapolation.mode == TsExtrapValueBlock;
543 const auto knotIt = knots.begin() + (lbIt - times.begin());
544 return knotIt->nextInterp == TsInterpValueBlock;
549 if (lbIt == times.begin())
551 return preExtrapolation.mode == TsExtrapValueBlock;
556 const auto knotIt = knots.begin() + (lbIt - times.begin());
557 return (knotIt - 1)->nextInterp == TsInterpValueBlock;
561Ts_TypedSplineData<T>*
562Ts_GetTypedSplineData(
TsSpline &spline)
564 return static_cast<Ts_TypedSplineData<T>*
>(
565 Ts_GetSplineData(spline));
569const Ts_TypedSplineData<T>*
570Ts_GetTypedSplineData(
const TsSpline &spline)
572 return static_cast<Ts_TypedSplineData<T>*
>(
573 Ts_GetSplineData(spline));
577PXR_NAMESPACE_CLOSE_SCOPE
Low-level utilities for informing users of various internal and external diagnostic conditions.
TfType represents a dynamic runtime type.
A mathematical description of a curved function from time to value.
A map with string keys and VtValue values.
VT_API bool empty() const
true if the VtDictionary's size is 0.
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
#define TF_VERIFY(cond, format,...)
Checks a condition and reports an error if it evaluates false.