HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
knot.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_H
9 #define PXR_BASE_TS_KNOT_H
10 
11 #include "pxr/pxr.h"
12 #include "pxr/base/ts/api.h"
13 #include "pxr/base/ts/knotData.h"
14 #include "pxr/base/ts/types.h"
16 #include "pxr/base/vt/dictionary.h"
17 #include "pxr/base/vt/value.h"
18 #include "pxr/base/gf/half.h"
19 #include "pxr/base/tf/diagnostic.h"
21 #include "pxr/base/tf/type.h"
22 
23 #include <string>
24 #include <memory>
25 #include <iosfwd>
26 #include <type_traits>
27 
29 
30 
31 /// A knot belonging to a TsSpline.
32 ///
33 /// This class is non-templated, but can hold data for varying value types
34 /// (double, float, and half). All knots in a spline must have the same value
35 /// type.
36 ///
37 /// \sa TsTypedKnot
38 ///
39 class TsKnot
40 {
41 public:
42  /// \name Construction and value semantics
43  ///
44  /// Unlike splines, knots have a fixed value type from the time they are
45  /// constructed.
46  ///
47  /// Knots are fairly small, so copying them is not particularly expensive.
48  /// Move construction and assignment are supported, but this is only
49  /// beneficial when there is custom data.
50  ///
51  /// @{
52 
53  /// Default constructor creates a double-typed knot.
54  TS_API
55  TsKnot();
56 
57  /// Creates a knot with a specified value type.
58  TS_API
59  TsKnot(
60  TfType valueType,
61  TsCurveType curveType = TsCurveTypeBezier);
62 
63  TS_API
64  TsKnot(const TsKnot &other);
65 
66  TS_API
67  TsKnot(TsKnot &&other);
68 
69  TS_API
70  ~TsKnot();
71 
72  TS_API
73  TsKnot& operator=(const TsKnot &other);
74 
75  TS_API
76  TsKnot& operator=(TsKnot &&other);
77 
78  TS_API
79  bool operator==(const TsKnot &other) const;
80 
81  TS_API
82  bool operator!=(const TsKnot &other) const;
83 
84  /// @}
85  /// \name Knot time
86  /// @{
87 
88  TS_API
89  bool SetTime(
90  TsTime time);
91 
92  TS_API
93  TsTime GetTime() const;
94 
95  /// @}
96  /// \name Interpolation mode
97  /// @{
98 
99  /// Sets the interpolation mode of the spline segment following this knot.
100  TS_API
102 
103  TS_API
105 
106  /// @}
107  /// \name Knot value
108  /// @{
109 
110  TS_API
111  TfType GetValueType() const;
112 
113  template <typename T>
114  bool IsHolding() const;
115 
116  TS_API
117  bool SetValue(
118  VtValue value);
119 
120  template <typename T>
121  bool SetValue(
122  const T value);
123 
124  TS_API
125  bool GetValue(
126  VtValue *valueOut) const;
127 
128  template <typename T>
129  bool GetValue(
130  T *valueOut) const;
131 
132  /// @}
133  /// \name Dual values
134  /// @{
135 
136  TS_API
137  bool IsDualValued() const;
138 
139  TS_API
140  bool SetPreValue(
141  VtValue value);
142 
143  template <typename T>
144  bool SetPreValue(
145  const T value);
146 
147  TS_API
148  bool GetPreValue(
149  VtValue *valueOut) const;
150 
151  template <typename T>
152  bool GetPreValue(
153  T *valueOut) const;
154 
155  TS_API
156  bool ClearPreValue();
157 
158  /// @}
159  /// \name Curve type
160  ///
161  /// Each knot's curve type must match the curve type of the spline to which
162  /// it belongs. Knot objects are Bezier by default.
163  ///
164  /// In a Hermite spline, tangent widths are determined automatically. They
165  /// are always one-third of the width of the segment to which they belong.
166  ///
167  /// @{
168 
169  TS_API
170  bool SetCurveType(TsCurveType curveType);
171 
172  TS_API
173  TsCurveType GetCurveType() const;
174 
175  /// @}
176  /// \name Pre-tangent
177  ///
178  /// Tangents are expressed as width and slope.
179  ///
180  /// It is an error to read or write widths for Hermite knots.
181  ///
182  /// \note Note that Maya uses tangents in a different format.
183  /// \ref TsConvertFromStandardTangent is a utility function that can
184  /// convert a standard width and slope to values expected by Maya.
185  ///
186  /// @{
187 
188  TS_API
189  bool SetPreTanWidth(TsTime width);
190 
191  TS_API
192  TsTime GetPreTanWidth() const;
193 
194  TS_API
195  bool SetPreTanSlope(VtValue slope);
196 
197  template <typename T>
198  bool SetPreTanSlope(T slope);
199 
200  TS_API
201  bool GetPreTanSlope(VtValue *slopeOut) const;
202 
203  template <typename T>
204  bool GetPreTanSlope(T *slopeOut) const;
205 
206  /// @}
207  /// \name Post-tangent
208  /// @{
209 
210  TS_API
211  bool SetPostTanWidth(TsTime width);
212 
213  TS_API
214  TsTime GetPostTanWidth() const;
215 
216  TS_API
217  bool SetPostTanSlope(VtValue slope);
218 
219  template <typename T>
220  bool SetPostTanSlope(T slope);
221 
222  TS_API
223  bool GetPostTanSlope(VtValue *slopeOut) const;
224 
225  template <typename T>
226  bool GetPostTanSlope(T *slopeOut) const;
227 
228  /// @}
229  /// \name Custom data
230  ///
231  /// Knots may have custom data: an arbitrary VtDictionary of key/value
232  /// pairs.
233  ///
234  /// Custom data does not affect evaluation. It is only for clients' use.
235  ///
236  /// When knots are edited, Ts does not automatically alter any custom data.
237  /// This means that, if splines are written out, edited by other clients
238  /// that do not recognize a particular kind of custom data, and read back
239  /// in, then that custom data may become outdated.
240  ///
241  /// @{
242 
243  TS_API
244  bool SetCustomData(
245  VtDictionary customData);
246 
247  TS_API
248  VtDictionary GetCustomData() const;
249 
250  TS_API
251  bool SetCustomDataByKey(
252  const std::string &keyPath,
253  VtValue value);
254 
255  TS_API
257  const std::string &keyPath) const;
258 
259  /// @}
260  /// \name Continuity queries
261  /// @{
262 
263  /// <b>Not yet implemented.</b>
264  TS_API
265  bool IsC0Continuous() const;
266 
267  /// <b>Not yet implemented.</b>
268  TS_API
269  bool IsG1Continuous() const;
270 
271  /// <b>Not yet implemented.</b>
272  TS_API
273  bool IsC1Continuous() const;
274 
275  /// @}
276 
277 protected:
278  friend class TsSpline;
279  friend class TsKnotMap;
280  friend class TsRegressionPreventer;
281 
282  // Constructor for copying knot data from SplineData. The data has been
283  // copied for us, and we take ownership of it.
284  TsKnot(
285  Ts_KnotData *data,
286  TfType valueType,
287  VtDictionary &&customData);
288 
289  // Accessors for low-level knot data.
290  Ts_KnotData* _GetData() { return _data; }
291  const Ts_KnotData* _GetData() const { return _data; }
292 
293 private:
294  template <typename T>
295  bool _CheckInParam(T value) const;
296 
297  template <typename T>
298  bool _CheckOutParam(T *valueOut) const;
299 
300  bool _CheckGetWidth() const;
301  bool _CheckSetWidth(TsTime width) const;
302  bool _CheckInParamVt(VtValue value) const;
303  bool _CheckOutParamVt(VtValue* value) const;
304 
305  template <typename T>
306  Ts_TypedKnotData<T>* _TypedData() const;
307 
308  template <typename T>
309  const Ts_TypedKnotData<T>* _ConstTypedData() const;
310 
311 private:
312  // Main knot fields. Never null. The data is on the heap, and we own it
313  // exclusively, but we don't use unique_ptr because we need to deallocate in
314  // a type-aware way; see the destructor.
315  Ts_KnotData* _data;
316 
317  // Proxy object, for typed data access. Never null.
318  //
319  // XXX: it would be possible to eliminate this member by encoding value type
320  // in a bitfield in Ts_KnotData; there are only three possible value types,
321  // and there are plenty of unused bits in the Ts_KnotData padding. Then we
322  // could create proxy objects on the fly, or make them singletons.
323  //
324  std::unique_ptr<Ts_KnotDataProxy> _proxy;
325 
326  // Custom data. Optional; may be empty.
327  VtDictionary _customData;
328 };
329 
330 /// Output a text representation of a spline to a stream.
331 TS_API
332 std::ostream& operator<<(std::ostream& out, const TsKnot &knot);
333 
334 
335 /// A convenience for constructing knots with specified types.
336 ///
337 /// Instead of writing:
338 ///
339 /// <pre>
340 /// TsKnot knot1(TfType::Find<double>());
341 /// TsKnot knot2(TfType::Find<float>());
342 /// TsKnot knot3(TfType::Find<GfHalf>());
343 /// </pre>
344 ///
345 /// One may write:
346 ///
347 /// <pre>
348 /// TsDoubleKnot knot1;
349 /// TsFloatKnot knot2;
350 /// TsHalfKnot knot3;
351 /// </pre>
352 ///
353 template <typename T,
355 class TsTypedKnot : public TsKnot
356 {
357 public:
359 };
360 
361 /// \class TsDoubleKnot
362 /// A knot-construction convenience. See TsTypedKnot.
364 
365 /// \class TsFloatKnot
366 /// A knot-construction convenience. See TsTypedKnot.
368 
369 /// \class TsHalfKnot
370 /// A knot-construction convenience. See TsTypedKnot.
372 
373 // Make sure we have coverage for all allowed types.
374 #define _MAKE_CLAUSE(unused, tuple) \
375  static_assert(std::is_same_v<TF_PP_CAT(TF_PP_CAT(Ts, \
376  TS_SPLINE_VALUE_TYPE_NAME(tuple)), Knot), \
377  TsTypedKnot<TS_SPLINE_VALUE_CPP_TYPE(tuple)>>, \
378  "Incorrect type alias for TsKnot type: " #tuple);
380 #undef _MAKE_CLAUSE
381 
382 
383 
384 ////////////////////////////////////////////////////////////////////////////////
385 // TEMPLATE HELPERS
386 
387 template <typename T>
388 bool TsKnot::_CheckInParam(const T value) const
389 {
390  if constexpr (!Ts_IsSupportedValueType<T>::value)
391  {
392  static_assert(Ts_IsSupportedValueType<T>::value,
393  "Cannot pass non-floating-point type as T-typed knot parameter");
394  return false;
395  }
396  else
397  {
398  if (GetValueType() != Ts_GetType<T>())
399  {
401  "Cannot set '%s' value into knot of type '%s'",
402  Ts_GetType<T>().GetTypeName().c_str(),
403  GetValueType().GetTypeName().c_str());
404  return false;
405  }
406 
407  if (!Ts_IsFinite(value))
408  {
409  TF_CODING_ERROR("Set values must be finite.");
410  return false;
411  }
412 
413  return true;
414  }
415 }
416 
417 template <typename T>
418 bool TsKnot::_CheckOutParam(T *valueOut) const
419 {
420  if constexpr (!Ts_IsSupportedValueType<T>::value)
421  {
422  static_assert(Ts_IsSupportedValueType<T>::value,
423  "Cannot pass non-floating-point type as T-typed knot parameter");
424  return false;
425  }
426  else
427  {
428  if (!valueOut)
429  {
430  TF_CODING_ERROR("Null pointer");
431  return false;
432  }
433 
434  if (GetValueType() != Ts_GetType<T>())
435  {
437  "Cannot read from knot of type '%s' into '%s'",
438  GetValueType().GetTypeName().c_str(),
439  Ts_GetType<T>().GetTypeName().c_str());
440  return false;
441  }
442 
443  return true;
444  }
445 }
446 
447 template <typename T>
449 TsKnot::_TypedData() const
450 {
451  return static_cast<Ts_TypedKnotData<T>*>(_data);
452 }
453 
454 template <typename T>
455 const Ts_TypedKnotData<T>*
456 TsKnot::_ConstTypedData() const
457 {
458  return static_cast<const Ts_TypedKnotData<T>*>(_data);
459 }
460 
461 ////////////////////////////////////////////////////////////////////////////////
462 // TEMPLATE IMPLEMENTATIONS
463 
464 template <typename T>
465 bool TsKnot::IsHolding() const
466 {
467  return GetValueType() == Ts_GetType<T>();
468 }
469 
470 template <typename T>
471 bool TsKnot::SetValue(const T value)
472 {
473  if (!_CheckInParam(value))
474  {
475  return false;
476  }
477 
478  _TypedData<T>()->value = value;
479  return true;
480 }
481 
482 template <typename T>
483 bool TsKnot::GetValue(T *valueOut) const
484 {
485  if (!_CheckOutParam(valueOut))
486  {
487  return false;
488  }
489 
490  *valueOut = _ConstTypedData<T>()->value;
491  return true;
492 }
493 
494 template <typename T>
496 {
497  if (!_CheckInParam(value))
498  {
499  return false;
500  }
501 
502  _data->dualValued = true;
503  _TypedData<T>()->preValue = value;
504  return true;
505 }
506 
507 template <typename T>
508 bool TsKnot::GetPreValue(T* const valueOut) const
509 {
510  if (!_CheckOutParam(valueOut))
511  {
512  return false;
513  }
514 
515  if (_data->dualValued)
516  {
517  *valueOut = _ConstTypedData<T>()->preValue;
518  }
519  else
520  {
521  *valueOut = _ConstTypedData<T>()->value;
522  }
523 
524  return true;
525 }
526 
527 ////////////////////////////////////////////////////////////////////////////////
528 // Pre-Tangent
529 
530 template <typename T>
531 bool TsKnot::SetPreTanSlope(const T slope)
532 {
533  if (!_CheckInParam(slope))
534  {
535  return false;
536  }
537 
538  _TypedData<T>()->preTanSlope = slope;
539  return true;
540 }
541 
542 template <typename T>
543 bool TsKnot::GetPreTanSlope(T* const slopeOut) const
544 {
545  if (!_CheckOutParam(slopeOut))
546  {
547  return false;
548  }
549 
550  *slopeOut = _ConstTypedData<T>()->GetPreTanSlope();
551  return true;
552 }
553 
554 ////////////////////////////////////////////////////////////////////////////////
555 // Post-Tangent
556 
557 template <typename T>
558 bool TsKnot::SetPostTanSlope(const T slope)
559 {
560  if (!_CheckInParam(slope))
561  {
562  return false;
563  }
564 
565  _TypedData<T>()->postTanSlope = slope;
566  return true;
567 }
568 
569 template <typename T>
570 bool TsKnot::GetPostTanSlope(T* const slopeOut) const
571 {
572  if (!_CheckOutParam(slopeOut))
573  {
574  return false;
575  }
576 
577  *slopeOut = _ConstTypedData<T>()->GetPostTanSlope();
578  return true;
579 }
580 
581 
583 
584 #endif
TS_API bool IsC0Continuous() const
Not yet implemented.
TS_API bool SetCustomDataByKey(const std::string &keyPath, VtValue value)
TS_API bool SetTime(TsTime time)
TS_API bool GetValue(VtValue *valueOut) const
TS_API bool operator==(const TsKnot &other) const
Default constructor creates a double-typed knot.
GT_API const UT_StringHolder time
GLsizei const GLfloat * value
Definition: glcorearb.h:824
const Ts_KnotData * _GetData() const
Definition: knot.h:291
#define TF_CODING_ERROR
TS_API TsCurveType GetCurveType() const
TS_API bool GetPreTanSlope(VtValue *slopeOut) const
TS_API bool SetPreValue(VtValue value)
TS_API bool SetValue(VtValue value)
#define _MAKE_CLAUSE(unused, tuple)
Definition: knot.h:374
TS_API bool SetPreTanSlope(VtValue slope)
TS_API TfType GetValueType() const
TS_API TsInterpMode GetNextInterpolation() const
Sets the interpolation mode of the spline segment following this knot.
TS_API TsTime GetPostTanWidth() const
TS_API bool SetPreTanWidth(TsTime width)
TsCurveType
Definition: types.h:92
TS_API std::ostream & operator<<(std::ostream &out, const TsKnot &knot)
Output a text representation of a spline to a stream.
TS_API bool SetCustomData(VtDictionary customData)
Ts_KnotData * _GetData()
Definition: knot.h:290
TS_API TsTime GetTime() const
TS_API bool SetNextInterpolation(TsInterpMode mode)
Sets the interpolation mode of the spline segment following this knot.
TS_API bool operator!=(const TsKnot &other) const
Default constructor creates a double-typed knot.
TS_API TsTime GetPreTanWidth() const
#define TS_API
Definition: api.h:24
GLenum mode
Definition: glcorearb.h:99
Definition: knot.h:39
TS_API VtValue GetCustomDataByKey(const std::string &keyPath) const
bool dualValued
Definition: knotData.h:129
TS_API bool SetPostTanWidth(TsTime width)
bool Ts_IsFinite(T value)
Definition: typeHelpers.h:70
PXR_NAMESPACE_CLOSE_SCOPE PXR_NAMESPACE_OPEN_SCOPE
Definition: path.h:1425
bool IsHolding() const
Definition: knot.h:465
TS_API bool IsC1Continuous() const
Not yet implemented.
#define TF_PP_SEQ_FOR_EACH(_macro, data, seq)
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
PXR_NAMESPACE_OPEN_SCOPE TfType Ts_GetType()
TS_API bool GetPostTanSlope(VtValue *slopeOut) const
Definition: type.h:47
TS_API bool SetPostTanSlope(VtValue slope)
GLint GLsizei width
Definition: glcorearb.h:103
#define TS_SPLINE_SUPPORTED_VALUE_TYPES
Definition: types.h:29
TS_API bool IsG1Continuous() const
Not yet implemented.
OIIO_UTIL_API const char * c_str(string_view str)
TS_API bool ClearPreValue()
TS_API ~TsKnot()
Default constructor creates a double-typed knot.
TS_API TsKnot & operator=(const TsKnot &other)
Default constructor creates a double-typed knot.
TS_API bool SetCurveType(TsCurveType curveType)
TS_API VtDictionary GetCustomData() const
TS_API TsKnot()
Default constructor creates a double-typed knot.
TS_API bool GetPreValue(VtValue *valueOut) const
Definition: value.h:146
TsInterpMode
Definition: types.h:82
Definition: format.h:1821
TS_API bool IsDualValued() const
TsTypedKnot()
Definition: knot.h:358