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"
18#include "pxr/base/gf/half.h"
21#include "pxr/base/tf/preprocessorUtilsLite.h"
22#include "pxr/base/tf/type.h"
23
24#include <iosfwd>
25#include <memory>
26#include <optional>
27#include <string>
28#include <type_traits>
29
30PXR_NAMESPACE_OPEN_SCOPE
31
32
41class TsKnot
42{
43public:
54
56 TS_API
58
60 TS_API
62 TfType valueType);
63
69 TS_API
71 TfType valueType,
72 TsCurveType curveType);
73
74 TS_API
75 TsKnot(const TsKnot &other);
76
77 TS_API
78 TsKnot(TsKnot &&other);
79
80 TS_API
81 ~TsKnot();
82
83 TS_API
84 TsKnot& operator=(const TsKnot &other);
85
86 TS_API
87 TsKnot& operator=(TsKnot &&other);
88
89 TS_API
90 bool operator==(const TsKnot &other) const;
91
92 TS_API
93 bool operator!=(const TsKnot &other) const;
94
98
99 TS_API
100 bool SetTime(
101 TsTime time);
102
103 TS_API
104 TsTime GetTime() const;
105
109
111 TS_API
112 bool SetNextInterpolation(TsInterpMode mode);
113
114 TS_API
115 TsInterpMode GetNextInterpolation() const;
116
120
121 TS_API
122 TfType GetValueType() const;
123
124 template <typename T>
125 bool IsHolding() const;
126
127 TS_API
128 bool SetValue(
129 VtValue value);
130
131 template <typename T>
132 bool SetValue(
133 const T value);
134
135 TS_API
136 bool GetValue(
137 VtValue *valueOut) const;
138
139 template <typename T>
140 bool GetValue(
141 T *valueOut) const;
142
146
147 TS_API
148 bool IsDualValued() const;
149
150 TS_API
151 bool SetPreValue(
152 VtValue value);
153
154 template <typename T>
155 bool SetPreValue(
156 const T value);
157
158 TS_API
159 bool GetPreValue(
160 VtValue *valueOut) const;
161
162 template <typename T>
163 bool GetPreValue(
164 T *valueOut) const;
165
166 TS_API
167 bool ClearPreValue();
168
178
179 TS_API
180 bool SetCurveType(TsCurveType curveType);
181
182 TS_API
183 TsCurveType GetCurveType() const;
184
197
198 TS_API
199 bool SetPreTanWidth(TsTime width);
200
201 TS_API
202 TsTime GetPreTanWidth() const;
203
204 TS_API
205 bool SetPreTanSlope(VtValue slope);
206
207 template <typename T>
208 bool SetPreTanSlope(T slope);
209
210 TS_API
211 bool GetPreTanSlope(VtValue *slopeOut) const;
212
213 template <typename T>
214 bool GetPreTanSlope(T *slopeOut) const;
215
224 TS_API
225 bool SetPreTanAlgorithm(TsTangentAlgorithm algorithm);
226
228 TS_API
229 TsTangentAlgorithm GetPreTanAlgorithm() const;
230
234
235 TS_API
236 bool SetPostTanWidth(TsTime width);
237
238 TS_API
239 TsTime GetPostTanWidth() const;
240
241 TS_API
242 bool SetPostTanSlope(VtValue slope);
243
244 template <typename T>
245 bool SetPostTanSlope(T slope);
246
247 TS_API
248 bool GetPostTanSlope(VtValue *slopeOut) const;
249
250 template <typename T>
251 bool GetPostTanSlope(T *slopeOut) const;
252
261 TS_API
262 bool SetPostTanAlgorithm(TsTangentAlgorithm algorithm);
263
265 TS_API
266 TsTangentAlgorithm GetPostTanAlgorithm() const;
267
271
294 TS_API
295 bool UpdateTangents(const std::optional<TsKnot> prevKnot,
296 const std::optional<TsKnot> nextKnot,
297 TsCurveType curveType = TsCurveTypeBezier);
298
313
314 TS_API
315 bool SetCustomData(
316 VtDictionary customData);
317
318 TS_API
319 VtDictionary GetCustomData() const;
320
321 TS_API
322 bool SetCustomDataByKey(
323 const std::string &keyPath,
324 VtValue value);
325
326 TS_API
327 VtValue GetCustomDataByKey(
328 const std::string &keyPath) const;
329
333
335 TS_API
336 bool IsC0Continuous() const;
337
339 TS_API
340 bool IsG1Continuous() const;
341
343 TS_API
344 bool IsC1Continuous() const;
345
347
348protected:
349 friend class TsSpline;
350 friend class TsKnotMap;
351 friend class TsRegressionPreventer;
352
353 // Constructor for copying knot data from SplineData. The data has been
354 // copied for us, and we take ownership of it.
355 TsKnot(
356 Ts_KnotData *data,
357 TfType valueType,
358 VtDictionary &&customData);
359
360 // Accessors for low-level knot data.
361 Ts_KnotData* _GetData() { return _data; }
362 const Ts_KnotData* _GetData() const { return _data; }
363
364private:
365 template <typename T>
366 bool _CheckInParam(T value) const;
367
368 template <typename T>
369 bool _CheckOutParam(T *valueOut) const;
370
371 bool _CheckSetWidth(TsTime width) const;
372 bool _CheckInParamVt(VtValue value) const;
373 bool _CheckOutParamVt(VtValue* value) const;
374
375 // Helpers to transform external VtValues holding time codes to and from
376 // internally stored VtValues holding doubles. If TsKnot::GetValueType
377 // isn't a time code, these functions return the stored value as-is.
378 VtValue _ToStorage(const VtValue& value) const;
379 VtValue _FromStorage(const VtValue& value) const;
380
381 template <typename T>
382 Ts_TypedKnotData<Ts_StorageType<T>>* _TypedData() const;
383
384 template <typename T>
385 const Ts_TypedKnotData<Ts_StorageType<T>>* _ConstTypedData() const;
386
387private:
388 // Main knot fields. Never null. The data is on the heap, and we own it
389 // exclusively, but we don't use unique_ptr because we need to deallocate in
390 // a type-aware way; see the destructor.
391 Ts_KnotData* _data;
392
393 // Proxy object, for typed data access. Never null.
394 //
395 // XXX: it would be possible to eliminate this member by encoding value type
396 // in a bitfield in Ts_KnotData; there are only three possible value types,
397 // and there are plenty of unused bits in the Ts_KnotData padding. Then we
398 // could create proxy objects on the fly, or make them singletons.
399 //
400 std::unique_ptr<Ts_KnotDataProxy> _proxy;
401
402 // Custom data. Optional; may be empty.
403 VtDictionary _customData;
404};
405
407TS_API
408std::ostream& operator<<(std::ostream& out, const TsKnot &knot);
409
410
431template <typename T,
432 typename = std::enable_if_t<Ts_IsSupportedValueType<T>::value>>
433class TsTypedKnot : public TsKnot
434{
435public:
436 TsTypedKnot() : TsKnot(Ts_GetType<T>()) {}
437};
438
442
446
450
454
455// Make sure we have coverage for all allowed types.
456#define _MAKE_CLAUSE(unused, tuple) \
457 static_assert(std::is_same_v<TF_PP_CAT(TF_PP_CAT(Ts, \
458 TS_SPLINE_VALUE_TYPE_NAME(tuple)), Knot), \
459 TsTypedKnot<TS_SPLINE_VALUE_CPP_TYPE(tuple)>>, \
460 "Incorrect type alias for TsKnot type: " #tuple);
461TF_PP_SEQ_FOR_EACH(_MAKE_CLAUSE, ~, TS_SPLINE_SUPPORTED_VALUE_TYPES)
462#undef _MAKE_CLAUSE
463
464
465
467// TEMPLATE HELPERS
468
469template <typename T>
470bool TsKnot::_CheckInParam(const T value) const
471{
472 if constexpr (!Ts_IsSupportedValueType<T>::value)
473 {
474 static_assert(Ts_IsSupportedValueType<T>::value,
475 "Cannot pass unsupported type as T-typed knot parameter");
476 return false;
477 }
478 else
479 {
480 if (GetValueType() != Ts_GetType<T>())
481 {
483 "Cannot set '%s' value into knot of type '%s'",
484 Ts_GetType<T>().GetTypeName().c_str(),
485 GetValueType().GetTypeName().c_str());
486 return false;
487 }
488
489 if (!Ts_IsFinite(value))
490 {
491 TF_CODING_ERROR("Set values must be finite.");
492 return false;
493 }
494
495 return true;
496 }
497}
498
499template <typename T>
500bool TsKnot::_CheckOutParam(T *valueOut) const
501{
502 if constexpr (!Ts_IsSupportedValueType<T>::value)
503 {
504 static_assert(Ts_IsSupportedValueType<T>::value,
505 "Cannot pass non-floating-point type as T-typed knot parameter");
506 return false;
507 }
508 else
509 {
510 if (!valueOut)
511 {
512 TF_CODING_ERROR("Null pointer");
513 return false;
514 }
515
516 if (GetValueType() != Ts_GetType<T>())
517 {
519 "Cannot read from knot of type '%s' into '%s'",
520 GetValueType().GetTypeName().c_str(),
521 Ts_GetType<T>().GetTypeName().c_str());
522 return false;
523 }
524
525 return true;
526 }
527}
528
529template <typename T>
530Ts_TypedKnotData<Ts_StorageType<T>>*
531TsKnot::_TypedData() const
532{
533 return static_cast<Ts_TypedKnotData<Ts_StorageType<T>>*>(_data);
534}
535
536template <typename T>
537const Ts_TypedKnotData<Ts_StorageType<T>>*
538TsKnot::_ConstTypedData() const
539{
540 return static_cast<const Ts_TypedKnotData<Ts_StorageType<T>>*>(_data);
541}
542
544// TEMPLATE IMPLEMENTATIONS
545
546template <typename T>
547bool TsKnot::IsHolding() const
548{
549 return GetValueType() == Ts_GetType<T>();
550}
551
552template <typename T>
553bool TsKnot::SetValue(const T value)
554{
555 if (!_CheckInParam(value))
556 {
557 return false;
558 }
559
560 _TypedData<T>()->value = Ts_StorageType<T>(value);
561 return true;
562}
563
564template <typename T>
565bool TsKnot::GetValue(T *valueOut) const
566{
567 if (!_CheckOutParam(valueOut))
568 {
569 return false;
570 }
571
572 *valueOut = _ConstTypedData<T>()->value;
573 return true;
574}
575
576template <typename T>
577bool TsKnot::SetPreValue(const T value)
578{
579 if (!_CheckInParam(value))
580 {
581 return false;
582 }
583
584 _data->dualValued = true;
585 _TypedData<T>()->preValue = Ts_StorageType<T>(value);
586 return true;
587}
588
589template <typename T>
590bool TsKnot::GetPreValue(T* const valueOut) const
591{
592 if (!_CheckOutParam(valueOut))
593 {
594 return false;
595 }
596
597 if (_data->dualValued)
598 {
599 *valueOut = _ConstTypedData<T>()->preValue;
600 }
601 else
602 {
603 *valueOut = _ConstTypedData<T>()->value;
604 }
605
606 return true;
607}
608
610// Pre-Tangent
611
612template <typename T>
613bool TsKnot::SetPreTanSlope(const T slope)
614{
615 if (!_CheckInParam(slope))
616 {
617 return false;
618 }
619
620 _TypedData<T>()->preTanSlope = Ts_StorageType<T>(slope);
621 return true;
622}
623
624template <typename T>
625bool TsKnot::GetPreTanSlope(T* const slopeOut) const
626{
627 if (!_CheckOutParam(slopeOut))
628 {
629 return false;
630 }
631
632 *slopeOut = _ConstTypedData<T>()->GetPreTanSlope();
633 return true;
634}
635
637// Post-Tangent
638
639template <typename T>
640bool TsKnot::SetPostTanSlope(const T slope)
641{
642 if (!_CheckInParam(slope))
643 {
644 return false;
645 }
646
647 _TypedData<T>()->postTanSlope = Ts_StorageType<T>(slope);
648 return true;
649}
650
651template <typename T>
652bool TsKnot::GetPostTanSlope(T* const slopeOut) const
653{
654 if (!_CheckOutParam(slopeOut))
655 {
656 return false;
657 }
658
659 *slopeOut = _ConstTypedData<T>()->GetPostTanSlope();
660 return true;
661}
662
663
664PXR_NAMESPACE_CLOSE_SCOPE
665
666#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 belonging to a TsSpline.
Definition knot.h:42
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:434
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:68
This header serves to simply bring in the half float datatype and provide a hash_value function.