HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
knotData.h
Go to the documentation of this file.
1 //
2 // Copyright 2024 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 
8 #ifndef PXR_BASE_TS_KNOT_DATA_H
9 #define PXR_BASE_TS_KNOT_DATA_H
10 
11 #include "pxr/pxr.h"
12 #include "pxr/base/ts/api.h"
13 #include "pxr/base/ts/types.h"
15 #include "pxr/base/vt/value.h"
16 #include "pxr/base/tf/type.h"
17 
18 #include <memory>
19 #include <cstring>
20 
22 
23 
24 // Ts API objects (Spline, Knot) are non-templated, but they can represent
25 // different value types (double, float, half), and internally we handle those
26 // different value types with templates. Some knot members (like time) are
27 // type-independent, while others (like value) are type-dependent. All knots in
28 // a spline have the same value type.
29 //
30 // Splines can have many knots, and we try to take up as little memory as
31 // possible in storing them. We also try to be as fast as possible in accessing
32 // them, but the combination of non-templated API classes and templated data is
33 // a form of type erasure that requires a compromise: we use virtual methods to
34 // retrieve data.
35 //
36 // We manage knot data with two class hierarchies:
37 //
38 // - The data itself is stored as a plain struct. There are two halves: a
39 // non-templated base struct that contains the type-independent members, and a
40 // templated derived struct that contains the type-dependent members. By
41 // making the data a plain struct, we avoid storing a vtable pointer for every
42 // instance, but in return we have no convenient way to get at the templated
43 // data directly.
44 //
45 // - We access the type-dependent members using a proxy class. There is an
46 // abstract base class that declares a virtual interface, and a templated
47 // derived class that implements it. Proxy objects have a vtable pointer, and
48 // contain a pointer to a templated derived data struct.
49 
50 
51 // XXX TODO
52 // review access patterns - do we need all?:
53 // SplineData -> AsDouble -> direct access
54 // SplineData virtuals
55 // Ts_Get[Typed]SplineData
56 // Knot -> proxy
57 // Knot -> _TypedData -> direct access
58 // TsDispatchToValueTypeTemplate
59 
60 
61 // Non-template base class for knot data.
62 //
64 {
65 public:
66  // Typically used by Create(), but can be invoked directly for clients that
67  // don't care about the value dimension, and instantiate this struct without
68  // subclassing.
69  Ts_KnotData();
70 
71  // Creates an appropriately subtyped instance on the heap.
72  static Ts_KnotData* Create(TfType valueType);
73 
74  // Compares two KnotData structs. Ignores subclasses.
75  bool operator==(const Ts_KnotData &other) const;
76 
77 public:
78  // Helpers that switch on flags.
79 
80  TsTime GetPreTanWidth() const
81  {
82  return preTanWidth;
83  }
84 
85  TsTime GetPostTanWidth() const
86  {
87  return postTanWidth;
88  }
89 
90  void SetPreTanWidth(const TsTime width)
91  {
93  }
94 
95  void SetPostTanWidth(const TsTime width)
96  {
98  }
99 
100 public:
101  // Knot time.
102  TsTime time;
103 
104  // Time width of the pre-tangent. Always non-negative. Ignored for Hermite
105  // knots.
106  TsTime preTanWidth;
107 
108  // Time width of the post-tangent. Always non-negative. Ignored for
109  // Hermite knots.
110  TsTime postTanWidth;
111 
112  // BITFIELDS - note: for enum-typed bitfields, we declare one bit more than
113  // is minimally needed to represent all declared enum values. For example,
114  // TsCurveType has only two values, so it should be representable in one
115  // bit. However, compilers are free to choose the underlying representation
116  // of enums, and some platforms choose signed values, meaning that we
117  // actually need one bit more, so that we can hold the sign bit. We could
118  // declare the enums with unsigned underlying types, but that runs into a
119  // gcc 9.2 bug. We can spare the extra bit; alignment means there is no
120  // difference in struct size.
121 
122  // Interpolation mode for the segment following this knot.
124 
125  // The spline type this knot belongs to, or is intended for.
126  TsCurveType curveType : 2; // deprecated
127 
128  // Whether this knot is dual-valued (value discontinuity at the knot).
129  bool dualValued : 1;
130 
131  // The pre- and post-tangent algorithms.
134 };
135 
136 
137 // Data for one knot in a spline.
138 //
139 // Tangents are expressed as width and slope.
140 //
141 template <typename T>
143  public Ts_KnotData
144 {
145 public:
147 
148  bool operator==(const Ts_TypedKnotData<T> &other) const;
149 
150 public:
151  // Helpers that switch on flags.
152  T GetPreValue() const;
153  T GetPreTanSlope() const;
154  T GetPreTanHeight() const;
155  T GetPostTanSlope() const;
156  T GetPostTanHeight() const;
157 
158 
159  // Compute algorithmic tangents for this Ts_KnotData based on the provided
160  // prev and next Ts_KnotData. See TsKnot::UpdateTangents for documentation.
161  TS_API
162  bool UpdateTangents(const Ts_TypedKnotData<T>* prevData,
163  const Ts_TypedKnotData<T>* nextData,
164  const TsCurveType curveType);
165 
166 protected:
167  TS_API
168  bool _UpdateTangent(const Ts_TypedKnotData<T>* prevData,
169  const Ts_TypedKnotData<T>* nextData,
170  TsCurveType curveType,
171  bool updatePre);
172 
173  TS_API
174  bool _UpdateTangentAutoEase(const Ts_TypedKnotData<T>* prevData,
175  const Ts_TypedKnotData<T>* nextData,
176  bool updatePre);
177 
178 public:
179  // Value at this knot.
181 
182  // If dual-valued, the pre-value at this knot.
184 
185  // preTanSlope stores the slope of the pre-tangent, rise over run, value
186  // height divided by time width.
188 
189  // postTanSlope stores the slope of the post-tangent, rise over run, value
190  // height divided by time width.
192 };
193 
194 // Virtual interface to TypedKnotData.
195 //
196 // VtValue parameters are not type-checked. They are blindly cast. Callers
197 // must verify types.
198 //
200 {
201 public:
202  // Creates an appropriately subtyped instance.
203  static std::unique_ptr<Ts_KnotDataProxy>
204  Create(Ts_KnotData *data, TfType valueType);
205 
206  virtual ~Ts_KnotDataProxy();
207 
208  virtual Ts_KnotData* CloneData() const = 0;
209  virtual void DeleteData() = 0;
210 
211  virtual TfType GetValueType() const = 0;
212  virtual bool IsDataEqualTo(const Ts_KnotData &other) const = 0;
213 
214  virtual void SetValue(VtValue value) = 0;
215  virtual void GetValue(VtValue *valueOut) const = 0;
216  virtual void SetPreValue(VtValue value) = 0;
217  virtual void GetPreValue(VtValue *valueOut) const = 0;
218 
219  virtual void SetPreTanSlope(VtValue slope) = 0;
220  virtual void GetPreTanSlope(VtValue *slopeOut) const = 0;
221  virtual void SetPostTanSlope(VtValue slope) = 0;
222  virtual void GetPostTanSlope(VtValue *slopeOut) const = 0;
223 
224  virtual bool UpdateTangents(const Ts_KnotDataProxy* prevProxy,
225  const Ts_KnotDataProxy* nextProxy,
226  const TsCurveType curveType) = 0;
227 };
228 
229 
230 // A means of accessing TypedKnotData.
231 //
232 template <typename T>
234  public Ts_KnotDataProxy
235 {
236 public:
238 
239  Ts_KnotData* CloneData() const override;
240  void DeleteData() override;
241 
242  TfType GetValueType() const override;
243  bool IsDataEqualTo(const Ts_KnotData &other) const override;
244 
245  void SetValue(VtValue value) override;
246  void GetValue(VtValue *valueOut) const override;
247  void SetPreValue(VtValue value) override;
248  void GetPreValue(VtValue *valueOut) const override;
249 
250  void SetPreTanSlope(VtValue slope) override;
251  void GetPreTanSlope(VtValue *slopeOut) const override;
252  void SetPostTanSlope(VtValue slope) override;
253  void GetPostTanSlope(VtValue *slopeOut) const override;
254 
255  bool UpdateTangents(const Ts_KnotDataProxy* prevProxy,
256  const Ts_KnotDataProxy* nextProxy,
257  const TsCurveType curveType) override;
258 
259 private:
260  Ts_TypedKnotData<T> *_data;
261 };
262 
263 
264 ////////////////////////////////////////////////////////////////////////////////
265 // TEMPLATE IMPLEMENTATIONS
266 
267 template <typename T>
269  : Ts_KnotData(),
270  value(T()),
271  preValue(T()),
272  preTanSlope(T()),
273  postTanSlope(T())
274 {
275 }
276 
277 #define COMP(member) \
278  if (member != other.member) \
279  { \
280  return false; \
281  }
282 
283 template <typename T>
285  const Ts_TypedKnotData<T> &other) const
286 {
287  COMP(time);
288  COMP(preTanWidth);
289  COMP(postTanWidth);
290  COMP(dualValued);
291  COMP(nextInterp);
292  // CurveType for knots has been deprecated and we no longer consider its
293  // value when testing for equality.
294  // COMP(curveType);
295 
296  COMP(value);
297  COMP(preValue);
298  COMP(preTanSlope);
299  COMP(postTanSlope);
300 
301  COMP(preTanAlgorithm);
302  COMP(postTanAlgorithm);
303 
304  return true;
305 }
306 
307 #undef COMP
308 
309 template <typename T>
311 {
312  return (dualValued ? preValue : value);
313 }
314 
315 template <typename T>
317 {
318  return preTanSlope;
319 }
320 
321 template <typename T>
323 {
324  return -preTanWidth * preTanSlope;
325 }
326 
327 template <typename T>
329 {
330  return postTanSlope;
331 }
332 
333 template <typename T>
335 {
336  return postTanWidth * postTanSlope;
337 }
338 
339 ////////////////////////////////////////////////////////////////////////////////
340 // TypedKnotDataProxy
341 
342 template <typename T>
345  : _data(data)
346 {
347 }
348 
349 template <typename T>
351 {
352  return new Ts_TypedKnotData<T>(*_data);
353 }
354 
355 template <typename T>
357 {
358  delete _data;
359 }
360 
361 template <typename T>
363 {
364  return Ts_GetType<T>();
365 }
366 
367 template <typename T>
369 {
370  // Force-downcast to our value type. Callers must verify types match.
371  const Ts_TypedKnotData<T> *typedOther =
372  static_cast<const Ts_TypedKnotData<T>*>(&other);
373 
374  return *_data == *typedOther;
375 }
376 
377 template <typename T>
379  const VtValue value)
380 {
381  _data->value = value.UncheckedGet<T>();
382 }
383 
384 template <typename T>
386  VtValue* const valueOut) const
387 {
388  *valueOut = VtValue(_data->value);
389 }
390 
391 template <typename T>
393  const VtValue value)
394 {
395  _data->preValue = value.UncheckedGet<T>();
396 }
397 
398 template <typename T>
400  VtValue* const valueOut) const
401 {
402  *valueOut = VtValue(_data->preValue);
403 }
404 
405 template <typename T>
407  const VtValue slope)
408 {
409  _data->preTanSlope = slope.UncheckedGet<T>();
410 }
411 
412 template <typename T>
414  VtValue* const slopeOut) const
415 {
416  *slopeOut = VtValue(_data->GetPreTanSlope());
417 }
418 
419 template <typename T>
421  const VtValue slope)
422 {
423  _data->postTanSlope = slope.UncheckedGet<T>();
424 }
425 
426 template <typename T>
428  VtValue* const slopeOut) const
429 {
430  *slopeOut = VtValue(_data->GetPostTanSlope());
431 }
432 
433 template <typename T>
435  const Ts_KnotDataProxy* prevProxy,
436  const Ts_KnotDataProxy* nextProxy,
437  const TsCurveType curveType)
438 {
439  const Ts_TypedKnotDataProxy<T>* prevTypedProxy =
440  dynamic_cast<const Ts_TypedKnotDataProxy<T>*>(prevProxy);
441  const Ts_TypedKnotData<T>* prevData = (prevTypedProxy
442  ? prevTypedProxy->_data
443  : nullptr);
444  const Ts_TypedKnotDataProxy<T>* nextTypedProxy =
445  dynamic_cast<const Ts_TypedKnotDataProxy<T>*>(nextProxy);
446  const Ts_TypedKnotData<T>* nextData = (nextTypedProxy
447  ? nextTypedProxy->_data
448  : nullptr);
449 
450  return _data->UpdateTangents(prevData, nextData, curveType);
451 }
452 
453 
455 
456 #endif
TsCurveType curveType
Definition: knotData.h:126
void SetValue(VtValue value) override
Definition: knotData.h:378
T const & UncheckedGet() const &
Definition: value.h:1046
TsInterpMode nextInterp
Definition: knotData.h:123
static Ts_KnotData * Create(TfType valueType)
#define COMP(member)
Definition: knotData.h:277
GT_API const UT_StringHolder time
T GetPreValue() const
Definition: knotData.h:310
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
virtual void SetPreTanSlope(VtValue slope)=0
GLsizei const GLfloat * value
Definition: glcorearb.h:824
bool UpdateTangents(const Ts_KnotDataProxy *prevProxy, const Ts_KnotDataProxy *nextProxy, const TsCurveType curveType) override
Definition: knotData.h:434
bool operator==(const Ts_TypedKnotData< T > &other) const
Definition: knotData.h:284
TS_API bool _UpdateTangentAutoEase(const Ts_TypedKnotData< T > *prevData, const Ts_TypedKnotData< T > *nextData, bool updatePre)
TsTime preTanWidth
Definition: knotData.h:106
virtual void SetValue(VtValue value)=0
void GetPreTanSlope(VtValue *slopeOut) const override
Definition: knotData.h:413
void GetPostTanSlope(VtValue *slopeOut) const override
Definition: knotData.h:427
TS_API bool _UpdateTangent(const Ts_TypedKnotData< T > *prevData, const Ts_TypedKnotData< T > *nextData, TsCurveType curveType, bool updatePre)
void SetPreTanSlope(VtValue slope) override
Definition: knotData.h:406
virtual bool UpdateTangents(const Ts_KnotDataProxy *prevProxy, const Ts_KnotDataProxy *nextProxy, const TsCurveType curveType)=0
void SetPostTanWidth(const TsTime width)
Definition: knotData.h:95
void SetPreValue(VtValue value) override
Definition: knotData.h:392
TsTime GetPostTanWidth() const
Definition: knotData.h:85
TsCurveType
Definition: types.h:92
Ts_TypedKnotDataProxy(Ts_TypedKnotData< T > *data)
Definition: knotData.h:343
bool operator==(const Ts_KnotData &other) const
void SetPreTanWidth(const TsTime width)
Definition: knotData.h:90
T GetPostTanSlope() const
Definition: knotData.h:328
virtual bool IsDataEqualTo(const Ts_KnotData &other) const =0
Ts_KnotData * CloneData() const override
Definition: knotData.h:350
virtual TfType GetValueType() const =0
virtual ~Ts_KnotDataProxy()
T GetPostTanHeight() const
Definition: knotData.h:334
TfType GetValueType() const override
Definition: knotData.h:362
#define TS_API
Definition: api.h:24
virtual void GetValue(VtValue *valueOut) const =0
virtual Ts_KnotData * CloneData() const =0
TsTangentAlgorithm postTanAlgorithm
Definition: knotData.h:133
bool dualValued
Definition: knotData.h:129
static std::unique_ptr< Ts_KnotDataProxy > Create(Ts_KnotData *data, TfType valueType)
virtual void SetPostTanSlope(VtValue slope)=0
virtual void GetPreTanSlope(VtValue *slopeOut) const =0
TsTime GetPreTanWidth() const
Definition: knotData.h:80
bool IsDataEqualTo(const Ts_KnotData &other) const override
Definition: knotData.h:368
TsTime time
Definition: knotData.h:102
virtual void GetPreValue(VtValue *valueOut) const =0
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
Definition: type.h:47
GLint GLsizei width
Definition: glcorearb.h:103
void SetPostTanSlope(VtValue slope) override
Definition: knotData.h:420
virtual void SetPreValue(VtValue value)=0
virtual void DeleteData()=0
T GetPreTanHeight() const
Definition: knotData.h:322
TsTangentAlgorithm preTanAlgorithm
Definition: knotData.h:132
void DeleteData() override
Definition: knotData.h:356
TS_API bool UpdateTangents(const Ts_TypedKnotData< T > *prevData, const Ts_TypedKnotData< T > *nextData, const TsCurveType curveType)
T GetPreTanSlope() const
Definition: knotData.h:316
TsTime postTanWidth
Definition: knotData.h:110
virtual void GetPostTanSlope(VtValue *slopeOut) const =0
Definition: value.h:89
TsTangentAlgorithm
Definition: types.h:153
TsInterpMode
Definition: types.h:82
Definition: format.h:1821
void GetPreValue(VtValue *valueOut) const override
Definition: knotData.h:399
void GetValue(VtValue *valueOut) const override
Definition: knotData.h:385