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;
162 void ApplyOffsetAndScale(
164 double scale)
override;
166 bool HasValueBlocks()
const override;
167 bool HasValueBlockAtTime(TsTime time)
const override;
171 std::vector<Ts_TypedKnotData<T>> knots;
182Ts_GetSplineData(
const TsSpline &spline);
185Ts_TypedSplineData<T>*
186Ts_GetTypedSplineData(
TsSpline &spline);
189const Ts_TypedSplineData<T>*
190Ts_GetTypedSplineData(
const TsSpline &spline);
197TfType Ts_TypedSplineData<T>::GetValueType()
const
204 return Ts_GetType<T>();
208size_t Ts_TypedSplineData<T>::GetKnotStructSize()
const
210 return sizeof(Ts_TypedKnotData<T>);
215Ts_TypedSplineData<T>::Clone()
const
217 return new Ts_TypedSplineData<T>(*
this);
221bool Ts_TypedSplineData<T>::operator==(
222 const Ts_SplineData &other)
const
225 if (isTyped != other.isTyped
226 || timeValued != other.timeValued
227 || curveType != other.curveType
228 || preExtrapolation != other.preExtrapolation
229 || postExtrapolation != other.postExtrapolation
230 || loopParams != other.loopParams
231 || customData != other.customData)
238 const Ts_TypedSplineData<T>*
const typedOther =
239 dynamic_cast<const Ts_TypedSplineData<T>*
>(&other);
246 return knots == typedOther->knots;
250void Ts_TypedSplineData<T>::ReserveForKnotCount(
253 times.reserve(count);
254 knots.reserve(count);
258void Ts_TypedSplineData<T>::PushKnot(
259 const Ts_KnotData*
const knotData,
262 const Ts_TypedKnotData<T>*
const typedKnotData =
263 static_cast<const Ts_TypedKnotData<T>*
>(knotData);
265 times.push_back(knotData->time);
266 knots.push_back(*typedKnotData);
268 if (!customDataIn.
empty())
270 customData[knotData->time] = customDataIn;
275size_t Ts_TypedSplineData<T>::SetKnot(
276 const Ts_KnotData*
const knotData,
279 const Ts_TypedKnotData<T>*
const typedKnotData =
280 static_cast<const Ts_TypedKnotData<T>*
>(knotData);
284 std::lower_bound(times.begin(), times.end(), knotData->time);
287 const bool overwrite =
288 (it != times.end() && *it == knotData->time);
293 times[idx] = knotData->time;
294 knots[idx] = *typedKnotData;
298 times.insert(it, knotData->time);
299 knots.insert(knots.begin() + idx, *typedKnotData);
303 if (!customDataIn.
empty())
305 customData[knotData->time] = customDataIn;
313Ts_TypedSplineData<T>::CloneKnotAtIndex(
314 const size_t index)
const
316 return new Ts_TypedKnotData<T>(knots[index]);
321Ts_TypedSplineData<T>::CloneKnotAtTime(
322 const TsTime time)
const
324 const auto it = std::lower_bound(times.begin(), times.end(), time);
325 if (it == times.end() || *it != time)
330 const auto knotIt = knots.begin() + (it - times.begin());
331 return new Ts_TypedKnotData<T>(*knotIt);
336Ts_TypedSplineData<T>::GetKnotPtrAtIndex(
339 return &(knots[index]);
344Ts_TypedKnotData<double>
345Ts_TypedSplineData<T>::GetKnotDataAsDouble(
346 const size_t index)
const
348 const Ts_TypedKnotData<T> &in = knots[index];
349 Ts_TypedKnotData<double> out;
353 static_cast<Ts_KnotData&
>(out) =
static_cast<const Ts_KnotData&
>(in);
356 out.value = in.value;
357 out.preValue = in.preValue;
358 out.preTanSlope = in.preTanSlope;
359 out.postTanSlope = in.postTanSlope;
365void Ts_TypedSplineData<T>::ClearKnots()
373void Ts_TypedSplineData<T>::RemoveKnotAtTime(
376 const auto it = std::lower_bound(times.begin(), times.end(), time);
377 if (it == times.end() || *it != time)
383 const size_t idx = it - times.begin();
385 customData.erase(time);
386 knots.erase(knots.begin() + idx);
390static void _ApplyOffsetAndScaleToKnot(
391 Ts_TypedKnotData<T>*
const knotData,
395 const bool reversing = (scale < 0);
396 const double absScale = std::abs(scale);
399 knotData->time = knotData->time * scale + offset;
402 knotData->preTanWidth *= absScale;
403 knotData->postTanWidth *= absScale;
406 knotData->preTanSlope /= scale;
407 knotData->postTanSlope /= scale;
412 std::swap(knotData->preTanWidth, knotData->postTanWidth);
413 std::swap(knotData->preValue, knotData->value);
414 std::swap(knotData->preTanSlope, knotData->postTanSlope);
419void Ts_TypedSplineData<T>::ApplyOffsetAndScale(
458 const bool reversing = (scale < 0);
461 TF_WARN(
"Applying negative scale to spline");
471 if (preExtrapolation.mode == TsExtrapSloped)
473 preExtrapolation.slope /= scale;
475 if (postExtrapolation.mode == TsExtrapSloped)
477 postExtrapolation.slope /= scale;
483 std::swap(preExtrapolation, postExtrapolation);
487 if (loopParams.protoEnd > loopParams.protoStart)
490 loopParams.protoStart = loopParams.protoStart * scale + offset;
491 loopParams.protoEnd = loopParams.protoEnd * scale + offset;
496 std::swap(loopParams.protoStart, loopParams.protoEnd);
497 std::swap(loopParams.numPreLoops, loopParams.numPostLoops);
502 for (TsTime &time : times)
503 time = time * scale + offset;
508 std::reverse(times.begin(), times.end());
516 for (Ts_TypedKnotData<T> &knotData : knots)
518 _ApplyOffsetAndScaleToKnot(&knotData, offset, scale);
522 static_cast<T
>(knotData.value * scale + offset);
524 static_cast<T
>(knotData.preValue * scale + offset);
529 for (Ts_TypedKnotData<T> &knotData : knots)
530 _ApplyOffsetAndScaleToKnot(&knotData, offset, scale);
536 for (
size_t i = 1; i < knots.size(); i++)
537 knots[i - 1].nextInterp = knots[i].nextInterp;
540 std::reverse(knots.begin(), knots.end());
544 if (!customData.empty())
546 std::unordered_map<TsTime, VtDictionary> newCustomData;
547 for (
const auto &mapPair : customData)
548 newCustomData[mapPair.first * scale + offset] = mapPair.second;
549 customData.swap(newCustomData);
554bool Ts_TypedSplineData<T>::HasValueBlocks()
const
561 if (preExtrapolation.mode == TsExtrapValueBlock
562 || postExtrapolation.mode == TsExtrapValueBlock)
567 for (
const Ts_TypedKnotData<T> &knotData : knots)
569 if (knotData.nextInterp == TsInterpValueBlock)
579bool Ts_TypedSplineData<T>::HasValueBlockAtTime(
580 const TsTime time)
const
590 std::lower_bound(times.begin(), times.end(), time);
594 if (lbIt == times.end())
596 return postExtrapolation.mode == TsExtrapValueBlock;
603 const auto knotIt = knots.begin() + (lbIt - times.begin());
604 return knotIt->nextInterp == TsInterpValueBlock;
609 if (lbIt == times.begin())
611 return preExtrapolation.mode == TsExtrapValueBlock;
616 const auto knotIt = knots.begin() + (lbIt - times.begin());
617 return (knotIt - 1)->nextInterp == TsInterpValueBlock;
621Ts_TypedSplineData<T>*
622Ts_GetTypedSplineData(
TsSpline &spline)
624 return static_cast<Ts_TypedSplineData<T>*
>(
625 Ts_GetSplineData(spline));
629const Ts_TypedSplineData<T>*
630Ts_GetTypedSplineData(
const TsSpline &spline)
632 return static_cast<Ts_TypedSplineData<T>*
>(
633 Ts_GetSplineData(spline));
637PXR_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_WARN(...)
Issue a warning, but continue execution.