Loading...
Searching...
No Matches
knot.h
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"
15#include "pxr/base/ts/typeHelpers.h"
17#include "pxr/base/vt/value.h"
19#include "pxr/base/gf/half.h"
22#include "pxr/base/tf/preprocessorUtilsLite.h"
23#include "pxr/base/tf/type.h"
24
25#include <iosfwd>
26#include <memory>
27#include <optional>
28#include <string>
29#include <type_traits>
30
31PXR_NAMESPACE_OPEN_SCOPE
32
33
42class TsKnot
43{
44public:
55
57 TS_API
59
61 TS_API
63 TfType valueType);
64
70 TS_API
72 TfType valueType,
73 TsCurveType curveType);
74
75 TS_API
76 TsKnot(const TsKnot &other);
77
78 TS_API
79 TsKnot(TsKnot &&other);
80
81 TS_API
82 ~TsKnot();
83
84 TS_API
85 TsKnot& operator=(const TsKnot &other);
86
87 TS_API
88 TsKnot& operator=(TsKnot &&other);
89
90 TS_API
91 bool operator==(const TsKnot &other) const;
92
93 TS_API
94 bool operator!=(const TsKnot &other) const;
95
99
100 TS_API
101 bool SetTime(
102 TsTime time);
103
104 TS_API
105 TsTime GetTime() const;
106
110
112 TS_API
113 bool SetNextInterpolation(TsInterpMode mode);
114
115 TS_API
116 TsInterpMode GetNextInterpolation() const;
117
121
122 TS_API
123 TfType GetValueType() const;
124
125 template <typename T>
126 bool IsHolding() const;
127
128 TS_API
129 bool SetValue(
130 VtValue value);
131
132 template <typename T>
133 bool SetValue(
134 const T value);
135
136 TS_API
137 bool GetValue(
138 VtValue *valueOut) const;
139
140 template <typename T>
141 bool GetValue(
142 T *valueOut) const;
143
147
148 TS_API
149 bool IsDualValued() const;
150
151 TS_API
152 bool SetPreValue(
153 VtValue value);
154
155 template <typename T>
156 bool SetPreValue(
157 const T value);
158
159 TS_API
160 bool GetPreValue(
161 VtValue *valueOut) const;
162
163 template <typename T>
164 bool GetPreValue(
165 T *valueOut) const;
166
167 TS_API
168 bool ClearPreValue();
169
179
180 TS_API
181 bool SetCurveType(TsCurveType curveType);
182
183 TS_API
184 TsCurveType GetCurveType() const;
185
198
199 TS_API
200 bool SetPreTanWidth(TsTime width);
201
202 TS_API
203 TsTime GetPreTanWidth() const;
204
205 TS_API
206 bool SetPreTanSlope(VtValue slope);
207
208 template <typename T>
209 bool SetPreTanSlope(T slope);
210
211 TS_API
212 bool GetPreTanSlope(VtValue *slopeOut) const;
213
214 template <typename T>
215 bool GetPreTanSlope(T *slopeOut) const;
216
225 TS_API
226 bool SetPreTanAlgorithm(TsTangentAlgorithm algorithm);
227
229 TS_API
230 TsTangentAlgorithm GetPreTanAlgorithm() const;
231
235
236 TS_API
237 bool SetPostTanWidth(TsTime width);
238
239 TS_API
240 TsTime GetPostTanWidth() const;
241
242 TS_API
243 bool SetPostTanSlope(VtValue slope);
244
245 template <typename T>
246 bool SetPostTanSlope(T slope);
247
248 TS_API
249 bool GetPostTanSlope(VtValue *slopeOut) const;
250
251 template <typename T>
252 bool GetPostTanSlope(T *slopeOut) const;
253
262 TS_API
263 bool SetPostTanAlgorithm(TsTangentAlgorithm algorithm);
264
266 TS_API
267 TsTangentAlgorithm GetPostTanAlgorithm() const;
268
272
295 TS_API
296 bool UpdateTangents(const std::optional<TsKnot> prevKnot,
297 const std::optional<TsKnot> nextKnot,
298 TsCurveType curveType = TsCurveTypeBezier);
299
314
315 TS_API
316 bool SetCustomData(
317 VtDictionary customData);
318
319 TS_API
320 VtDictionary GetCustomData() const;
321
322 TS_API
323 bool SetCustomDataByKey(
324 const std::string &keyPath,
325 VtValue value);
326
327 TS_API
328 VtValue GetCustomDataByKey(
329 const std::string &keyPath) const;
330
334
336 TS_API
337 bool IsC0Continuous() const;
338
340 TS_API
341 bool IsG1Continuous() const;
342
344 TS_API
345 bool IsC1Continuous() const;
346
348
349protected:
350 friend class TsSpline;
351 friend class TsKnotMap;
352 friend class TsRegressionPreventer;
353
354 // Constructor for copying knot data from SplineData. The data has been
355 // copied for us, and we take ownership of it.
356 TsKnot(
357 Ts_KnotData *data,
358 TfType valueType,
359 VtDictionary &&customData);
360
361 // Accessors for low-level knot data.
362 Ts_KnotData* _GetData() { return _data; }
363 const Ts_KnotData* _GetData() const { return _data; }
364
365private:
366 template <typename T>
367 bool _CheckInParam(T value) const;
368
369 template <typename T>
370 bool _CheckOutParam(T *valueOut) const;
371
372 bool _CheckSetWidth(TsTime width) const;
373 bool _CheckInParamVt(VtValue value) const;
374 bool _CheckOutParamVt(VtValue* value) const;
375
376 // Helpers to transform external VtValues holding time codes to and from
377 // internally stored VtValues holding doubles. If TsKnot::GetValueType
378 // isn't a time code, these functions return the stored value as-is.
379 VtValue _ToStorage(const VtValue& value) const;
380 VtValue _FromStorage(const VtValue& value) const;
381
382 template <typename T>
383 Ts_TypedKnotData<Ts_StorageType<T>>* _TypedData() const;
384
385 template <typename T>
386 const Ts_TypedKnotData<Ts_StorageType<T>>* _ConstTypedData() const;
387
388private:
389 // Main knot fields. Never null. The data is on the heap, and we own it
390 // exclusively, but we don't use unique_ptr because we need to deallocate in
391 // a type-aware way; see the destructor.
392 Ts_KnotData* _data;
393
394 // Proxy object, for typed data access. Never null.
395 //
396 // XXX: it would be possible to eliminate this member by encoding value type
397 // in a bitfield in Ts_KnotData; there are only three possible value types,
398 // and there are plenty of unused bits in the Ts_KnotData padding. Then we
399 // could create proxy objects on the fly, or make them singletons.
400 //
401 std::unique_ptr<Ts_KnotDataProxy> _proxy;
402
403 // Custom data. Optional; may be empty.
404 VtDictionary _customData;
405};
406
408TS_API
409std::ostream& operator<<(std::ostream& out, const TsKnot &knot);
410
411
434template <typename T,
435 typename = std::enable_if_t<Ts_IsSupportedValueType<T>::value>>
436class TsTypedKnot : public TsKnot
437{
438public:
439 TsTypedKnot() : TsKnot(Ts_GetType<T>()) {}
440};
441
445
449
453
457
461
462// Make sure we have coverage for all allowed types.
463#define _MAKE_CLAUSE(unused, tuple) \
464 static_assert(std::is_same_v<TF_PP_CAT(TF_PP_CAT(Ts, \
465 TS_SPLINE_VALUE_TYPE_NAME(tuple)), Knot), \
466 TsTypedKnot<TS_SPLINE_VALUE_CPP_TYPE(tuple)>>, \
467 "Incorrect type alias for TsKnot type: " #tuple);
468TF_PP_SEQ_FOR_EACH(_MAKE_CLAUSE, ~, TS_SPLINE_SUPPORTED_VALUE_TYPES)
469#undef _MAKE_CLAUSE
470
471
472
474// TEMPLATE HELPERS
475
476template <typename T>
477bool TsKnot::_CheckInParam(const T value) const
478{
479 if constexpr (!Ts_IsSupportedValueType<T>::value)
480 {
481 static_assert(Ts_IsSupportedValueType<T>::value,
482 "Cannot pass unsupported type as T-typed knot parameter");
483 return false;
484 }
485 else
486 {
487 if (GetValueType() != Ts_GetType<T>())
488 {
490 "Cannot set '%s' value into knot of type '%s'",
491 Ts_GetType<T>().GetTypeName().c_str(),
492 GetValueType().GetTypeName().c_str());
493 return false;
494 }
495
496 if (!Ts_IsFinite(value))
497 {
498 TF_CODING_ERROR("Set values must be finite.");
499 return false;
500 }
501
502 return true;
503 }
504}
505
506template <typename T>
507bool TsKnot::_CheckOutParam(T *valueOut) const
508{
509 if constexpr (!Ts_IsSupportedValueType<T>::value)
510 {
511 static_assert(Ts_IsSupportedValueType<T>::value,
512 "Cannot pass non-floating-point type as T-typed knot parameter");
513 return false;
514 }
515 else
516 {
517 if (!valueOut)
518 {
519 TF_CODING_ERROR("Null pointer");
520 return false;
521 }
522
523 if (GetValueType() != Ts_GetType<T>())
524 {
526 "Cannot read from knot of type '%s' into '%s'",
527 GetValueType().GetTypeName().c_str(),
528 Ts_GetType<T>().GetTypeName().c_str());
529 return false;
530 }
531
532 return true;
533 }
534}
535
536template <typename T>
537Ts_TypedKnotData<Ts_StorageType<T>>*
538TsKnot::_TypedData() const
539{
540 return static_cast<Ts_TypedKnotData<Ts_StorageType<T>>*>(_data);
541}
542
543template <typename T>
544const Ts_TypedKnotData<Ts_StorageType<T>>*
545TsKnot::_ConstTypedData() const
546{
547 return static_cast<const Ts_TypedKnotData<Ts_StorageType<T>>*>(_data);
548}
549
551// TEMPLATE IMPLEMENTATIONS
552
553template <typename T>
554bool TsKnot::IsHolding() const
555{
556 return GetValueType() == Ts_GetType<T>();
557}
558
559template <typename T>
560bool TsKnot::SetValue(const T value)
561{
562 if (!_CheckInParam(value))
563 {
564 return false;
565 }
566
567 _TypedData<T>()->value = Ts_StorageType<T>(value);
568 return true;
569}
570
571template <typename T>
572bool TsKnot::GetValue(T *valueOut) const
573{
574 if (!_CheckOutParam(valueOut))
575 {
576 return false;
577 }
578
579 *valueOut = _ConstTypedData<T>()->value;
580 return true;
581}
582
583template <typename T>
584bool TsKnot::SetPreValue(const T value)
585{
586 if (!_CheckInParam(value))
587 {
588 return false;
589 }
590
591 _data->dualValued = true;
592 _TypedData<T>()->preValue = Ts_StorageType<T>(value);
593 return true;
594}
595
596template <typename T>
597bool TsKnot::GetPreValue(T* const valueOut) const
598{
599 if (!_CheckOutParam(valueOut))
600 {
601 return false;
602 }
603
604 if (_data->dualValued)
605 {
606 *valueOut = _ConstTypedData<T>()->preValue;
607 }
608 else
609 {
610 *valueOut = _ConstTypedData<T>()->value;
611 }
612
613 return true;
614}
615
617// Pre-Tangent
618
619template <typename T>
620bool TsKnot::SetPreTanSlope(const T slope)
621{
622 if (!_CheckInParam(slope))
623 {
624 return false;
625 }
626
627 _TypedData<T>()->preTanSlope = Ts_StorageType<T>(slope);
628 return true;
629}
630
631template <typename T>
632bool TsKnot::GetPreTanSlope(T* const slopeOut) const
633{
634 if (!_CheckOutParam(slopeOut))
635 {
636 return false;
637 }
638
639 *slopeOut = _ConstTypedData<T>()->GetPreTanSlope();
640 return true;
641}
642
644// Post-Tangent
645
646template <typename T>
647bool TsKnot::SetPostTanSlope(const T slope)
648{
649 if (!_CheckInParam(slope))
650 {
651 return false;
652 }
653
654 _TypedData<T>()->postTanSlope = Ts_StorageType<T>(slope);
655 return true;
656}
657
658template <typename T>
659bool TsKnot::GetPostTanSlope(T* const slopeOut) const
660{
661 if (!_CheckOutParam(slopeOut))
662 {
663 return false;
664 }
665
666 *slopeOut = _ConstTypedData<T>()->GetPostTanSlope();
667 return true;
668}
669
670
671PXR_NAMESPACE_CLOSE_SCOPE
672
673#endif
Low-level utilities for informing users of various internal and external diagnostic conditions.
TfType represents a dynamic runtime type.
Definition type.h:48
A knot-construction convenience.
A knot-construction convenience.
A knot-construction convenience.
A knot-construction convenience.
A knot belonging to a TsSpline.
Definition knot.h:43
TS_API TsKnot()
Default constructor creates a double-typed knot.
TS_API TsTangentAlgorithm GetPreTanAlgorithm() const
Get the pre-tangent algorithm.
TS_API TsKnot(TfType valueType)
Creates a knot with a specified value type.
TS_API bool IsG1Continuous() const
Not yet implemented.
TS_API TsTangentAlgorithm GetPostTanAlgorithm() const
Get the post-tangent algorithm.
TS_API bool SetPostTanAlgorithm(TsTangentAlgorithm algorithm)
Set the post-tangent algorithm.
TS_API bool UpdateTangents(const std::optional< TsKnot > prevKnot, const std::optional< TsKnot > nextKnot, TsCurveType curveType=TsCurveTypeBezier)
Update tangent values algorithmically.
TS_API bool IsC1Continuous() const
Not yet implemented.
TS_API bool SetPreTanAlgorithm(TsTangentAlgorithm algorithm)
Set the pre-tangent algorithm.
TS_API TsKnot(TfType valueType, TsCurveType curveType)
Creates a knot with a specified value type and curve type.
TS_API bool SetNextInterpolation(TsInterpMode mode)
Sets the interpolation mode of the spline segment following this knot.
TS_API bool IsC0Continuous() const
Not yet implemented.
The knots in a spline.
Definition knotMap.h:37
An authoring helper class that enforces non-regression in splines.
A mathematical description of a curved function from time to value.
Definition spline.h:60
A knot-construction convenience.
A convenience for constructing knots with specified types.
Definition knot.h:437
A map with string keys and VtValue values.
Definition dictionary.h:52
Provides a container which may hold any type, and provides introspection and iteration over array typ...
Definition value.h:90
GF_API std::ostream & operator<<(std::ostream &, const GfBBox3d &)
Output a GfBBox3d using the format [(range) matrix zeroArea].
#define TF_CODING_ERROR(fmt, args)
Issue an internal programming error, but continue execution.
Definition diagnostic.h:69
This header serves to simply bring in the half float datatype and provide a hash_value function.