HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
attributeLimits.h
Go to the documentation of this file.
1 //
2 // Copyright 2025 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_USD_USD_ATTRIBUTE_LIMITS_H
9 #define PXR_USD_USD_ATTRIBUTE_LIMITS_H
10 
11 #include "pxr/usd/usd/attribute.h"
12 
14 #include "pxr/base/tf/token.h"
15 #include "pxr/base/vt/value.h"
16 
17 #include <optional>
18 #include <string>
19 
21 
22 #define USD_LIMITS_KEYS \
23  ((Soft, "soft")) \
24  ((Hard, "hard")) \
25  ((Minimum, "minimum")) \
26  ((Maximum, "maximum"))
27 
29  UsdLimitsKeys, USD_API, USD_LIMITS_KEYS);
30 
31 /// \class UsdAttributeLimits
32 ///
33 /// Provides API for retrieving and authoring values within a particular
34 /// sub-dictionary of the \c limits dictionary metadata field on a UsdAttribute
35 /// instance. Within a given sub-dictionary, minimum and maximum values are
36 /// encoded under the \c UsdLimitsKeys->Minimum and \c UsdLimitsKeys->Maximum
37 /// keys, respectively.
38 ///
39 /// For example, to express that an attribute's typical useful value range is
40 /// between 5 and 10 (the "soft limits"), but that it _must_ be between 0 and 15
41 /// (the "hard limits"), a typical limits dictionary might look like the
42 /// following:
43 ///
44 /// \code
45 /// def "MyPrim"
46 /// {
47 /// int attr = 7 (
48 /// limits = {
49 /// dictionary soft = {
50 /// int minimum = 5
51 /// int maximum = 10
52 /// }
53 /// dictionary hard = {
54 /// int minimum = 0
55 /// int maximum = 15
56 /// }
57 /// }
58 /// )
59 /// }
60 /// \endcode
61 ///
62 /// To work with these values, use the UsdAttributeLimits objects returned by
63 /// UsdAttribute::GetSoftLimits() and UsdAttribute::GetHardLimits(), which edit
64 /// and interpret the "soft" and "hard" sub-dictionaries, respectively.
65 ///
66 /// \code
67 /// UsdAttributeLimits softLimits = attr.GetSoftLimits();
68 /// if (x >= softLimits.GetMinimumOr(0) && x <= softLimits.GetMaximumOr(100)) {
69 /// // x is within the soft limits, 5 and 10. The passed-in defaults
70 /// // (0 and 100) are ignored since both min and max values are authored
71 /// }
72 /// \endcode
73 ///
74 /// You can also create custom sub-dictionaries:
75 ///
76 /// \code
77 /// UsdAttributeLimits customLimits = attr.GetLimits(TfToken("myCustomSubDict"));
78 /// customLimits.SetMinimum(50);
79 /// customLimits.SetMaximum(100);
80 /// customLimits.Set(TfToken("customKey"), 42.5));
81 /// \endcode
82 ///
83 /// Combined with the starting limits dictionary above, this would produce:
84 ///
85 /// \code
86 /// def "MyPrim"
87 /// {
88 /// int attr = 7 (
89 /// limits = {
90 /// dictionary soft = {
91 /// int minimum = 5
92 /// int maximum = 10
93 /// }
94 /// dictionary hard = {
95 /// int minimum = 0
96 /// int maximum = 15
97 /// }
98 /// dictionary myCustomSubDict = {
99 /// int minimum = 50,
100 /// int maximum = 100,
101 /// double customKey = 42.5
102 /// }
103 /// }
104 /// )
105 /// }
106 /// \endcode
108 {
109 public:
110  /// Construct an invalid limits object.
111  ///
112  /// Calling "set" operations on an invalid limits object will post errors.
113  /// "Get" operations will return empty.
114  UsdAttributeLimits() = default;
115 
116  /// Construct a limits object for the sub-dictionary given by \p subDictKey
117  /// in \p attr's limits dictionary.
118  USD_API
120  const UsdAttribute& attr,
121  const TfToken& subDictKey);
122 
123  /// \name Object Information
124  ///
125  /// Information about the limits object itself.
126  ///
127  /// @{
128 
129  /// Return whether the limits object is valid.
130  ///
131  /// Calling "set" operations on an invalid limits object will post errors.
132  /// "Get" operations will return empty.
133  USD_API
134  bool IsValid() const;
135 
136  /// Return the limits object's attribute.
137  USD_API
138  UsdAttribute GetAttribute() const;
139 
140  /// Return the sub-dictionary key the limits object is using.
141  USD_API
142  TfToken GetSubDictKey() const;
143 
144  /// @}
145 
146  /// \name Opinions API
147  ///
148  /// API for determining whether authored opinions exist, and clearing them.
149  ///
150  /// @{
151 
152  /// Return whether any authored opinions exist for the limits
153  /// sub-dictionary.
154  USD_API
155  bool HasAuthored() const;
156 
157  /// Clear all authored opinions for the limits sub-dictionary at the current
158  /// edit target. Return \c true if successful.
159  USD_API
160  bool Clear();
161 
162  /// Return whether an authored opinion for \p key exists in the limits
163  /// sub-dictionary.
164  USD_API
165  bool HasAuthored(const TfToken& key) const;
166 
167  /// Clear the authored opinion for \p key in the limits sub-dictionary.
168  /// Return \c true if successful.
169  USD_API
170  bool Clear(const TfToken& key);
171 
172  /// Return whether an authored minimum value opinion exists in the limits
173  /// sub-dictionary.
174  USD_API
175  bool HasAuthoredMinimum() const;
176 
177  /// Clear the authored minimum value opinion in the limits sub-dictionary.
178  /// Return \c true if successful.
179  USD_API
180  bool ClearMinimum();
181 
182  /// Return whether an authored maximum value opinion exists in the limits
183  /// sub-dictionary.
184  USD_API
185  bool HasAuthoredMaximum() const;
186 
187  /// Clear the authored maximum value opinion in the limits sub-dictionary.
188  /// Return \c true if successful.
189  USD_API
190  bool ClearMaximum();
191 
192  /// @}
193 
194  /// \name Sub-dictionary Operations
195  ///
196  /// Operations related to the entire limits sub-dictionary.
197  /// @{
198 
199  /// Validation information for a limits sub-dictionary.
200  ///
201  /// \sa Validate()
203  {
204  public:
205  /// Construct an empty result.
206  ValidationResult() = default;
207 
208  /// Return whether validation was successful.
209  bool Success() const {
210  return _success;
211  }
212 
213  /// Return a dictionary containing values from the source sub-dictionary
214  /// that did not match (and could not be casted to) the attribute's
215  /// type.
216  ///
217  /// Only minimum and maximum values must match the attribute's value
218  /// type. Other keys are not validated.
220  return _invalidValuesDict;
221  }
222 
223  /// Return the conformed limits sub-dictionary. Any values from the
224  /// source sub-dictionary that were of an unexpected type will have been
225  /// casted to the attribute's value type, if possible, in the conformed
226  /// sub-dictionary.
227  ///
228  /// If any unexpected values from the source sub-dictionary could not be
229  /// casted, they will appear in the invalid values dictionary, and the
230  /// conformed sub-dictionary will be empty.
232  return _conformedSubDict;
233  }
234 
235  /// Return a formatted error string describing the keys and values in
236  /// the invalid values dictionary. Return an empty string if there are
237  /// no invalid values.
238  USD_API
239  std::string GetErrorString() const;
240 
241  /// Return \c true if validation was successful.
242  ///
243  /// \sa Success()
244  explicit operator bool() const {
245  return Success();
246  }
247 
248  /// Equality operator.
249  bool operator==(const ValidationResult& rhs) const {
250  return _success == rhs._success &&
251  _invalidValuesDict == rhs._invalidValuesDict &&
252  _conformedSubDict == rhs._conformedSubDict &&
253  _attrPath == rhs._attrPath &&
254  _attrTypeName == rhs._attrTypeName;
255  }
256 
257  /// Inequality operator.
258  bool operator!=(const ValidationResult& rhs) const {
259  return !(*this == rhs);
260  }
261 
262  private:
263  friend class UsdAttributeLimits;
265  bool success,
266  const VtDictionary& invalidValuesDict,
267  const VtDictionary& conformedSubDict,
268  const SdfPath& attrPath,
269  const std::string& attrTypeName)
270  : _success(success),
271  _invalidValuesDict(invalidValuesDict),
272  _conformedSubDict(conformedSubDict),
273  _attrPath(attrPath),
274  _attrTypeName(attrTypeName) {}
275 
276  private:
277  bool _success = false;
278  VtDictionary _invalidValuesDict;
279  VtDictionary _conformedSubDict;
280  SdfPath _attrPath;
281  std::string _attrTypeName;
282  };
283 
284  /// Return whether \p subDict is a valid limits sub-dictionary. If \p result
285  /// is provided, fill it in.
286  //
287  /// To be valid, the types of encoded minimum and maximum values must match
288  /// the value type of the attribute.
289  ///
290  /// \sa ValidationResult
291  USD_API
292  bool Validate(
293  const VtDictionary& subDict,
294  ValidationResult* result = nullptr) const;
295 
296  /// Set the entire limits sub-dictionary to \p subDict. Return \c true
297  /// if successful.
298  ///
299  /// The types of encoded minimum and maximum values must match the value
300  /// type of the attribute.
301  USD_API
302  bool Set(const VtDictionary& subDict);
303 
304  /// @}
305 
306  /// \name Typed Value API
307  ///
308  /// Templated API for retrieving and authoring individual limits values.
309  ///
310  /// @{
311 
312  /// Return the value encoded under \p key in the limits sub-dictionary.
313  /// Return an empty \c std::optional if no authored or fallback
314  /// value is present, or if the template type \c T does not match the type
315  /// of the stored value.
316  template <typename T>
317  std::optional<T> Get(const TfToken& key) const;
318 
319  /// Return the value encoded under \p key in the limits sub-dictionary.
320  /// Return \p defaultValue if no authored or fallback value is present, or
321  /// if the template type \c T does not match the type of the stored value.
322  template <typename T>
323  T GetOr(const TfToken& key, const T& defaultValue) const;
324 
325  /// Set the value encoded under \p key in the limits sub-dictionary to
326  /// \p value. Return \c true if successful.
327  template <typename T>
328  bool Set(const TfToken& key, const T& value);
329 
330  /// Return the minimum value from the limits sub-dictionary. Return an
331  /// empty \c std::optional if no authored or fallback value is present, or
332  /// if the template type \c T does not match the type of the stored value.
333  template <typename T>
334  std::optional<T> GetMinimum() const;
335 
336  /// Return the minimum value from the limits sub-dictionary. Return
337  /// \p defaultValue if no authored or fallback value is present, or
338  /// if the template type \c T does not match the type of the stored value.
339  template <typename T>
340  T GetMinimumOr(const T& defaultValue) const;
341 
342  /// Set the minimum value in the limits sub-dictionary. Return \c true if
343  /// successful.
344  ///
345  /// The type of \p value must match the attribute's value type.
346  template <typename T>
347  bool SetMinimum(const T& value);
348 
349  /// Return the maximum value from the limits sub-dictionary. Return an
350  /// empty \c std::optional if no authored or fallback value is present, or
351  /// if the template type \c T does not match the type of the stored value.
352  template <typename T>
353  std::optional<T> GetMaximum() const;
354 
355  /// Return the maximum value from the limits sub-dictionary. Return
356  /// \p defaultValue if no authored or fallback value is present, or if
357  /// the template type \c T does not match the type of the stored value.
358  template <typename T>
359  T GetMaximumOr(const T& defaultValue) const;
360 
361  /// Set the maximum value in the limits sub-dictionary. Return \c true if
362  /// successful.
363  ///
364  /// The type of \p value must match the attribute's value type.
365  template <typename T>
366  bool SetMaximum(const T& value);
367 
368  /// @}
369 
370  /// \name Type-erased Value API
371  ///
372  /// VtValue-based overloads, mainly for use by the Python wrapping.
373  ///
374  /// @{
375 
376  /// \overload
377  USD_API
378  VtValue Get(const TfToken& key) const;
379 
380  /// \overload
381  USD_API
382  bool Set(const TfToken& key, const VtValue& value);
383 
384  /// \overload
385  USD_API
386  VtValue GetMinimum() const;
387 
388  /// \overload
389  USD_API
390  bool SetMinimum(const VtValue& value);
391 
392  /// \overload
393  USD_API
394  VtValue GetMaximum() const;
395 
396  /// \overload
397  USD_API
398  bool SetMaximum(const VtValue& value);
399 
400  /// @}
401 
402  /// Return \c true if this limits object is valid.
403  ///
404  /// \sa IsValid()
405  explicit operator bool() const {
406  return IsValid();
407  }
408 
409  /// Equality operator.
410  bool operator==(const UsdAttributeLimits& rhs) const {
411  return _attr == rhs._attr && _subDictKey == rhs._subDictKey;
412  }
413 
414  /// Inequality operator.
415  bool operator!=(const UsdAttributeLimits& rhs) const {
416  return !(*this == rhs);
417  }
418 
419 private:
420  USD_API
421  static TfToken _MakeKeyPath(const TfToken&, const TfToken&);
422 
423 private:
424  UsdAttribute _attr;
425  TfToken _subDictKey;
426 };
427 
428 template <typename T>
429 inline std::optional<T>
431 {
432  if (!IsValid() || key.IsEmpty()) {
433  return {};
434  }
435 
436  T value;
437  if (_attr.GetMetadataByDictKey(
438  SdfFieldKeys->Limits,
439  _MakeKeyPath(_subDictKey, key),
440  &value)) {
441  return value;
442  }
443  return {};
444 }
445 
446 template <typename T>
447 inline T
449  const TfToken& key,
450  const T& defaultValue) const
451 {
452  if (!IsValid() || key.IsEmpty()) {
453  return defaultValue;
454  }
455 
456  T value;
457  if (_attr.GetMetadataByDictKey(
458  SdfFieldKeys->Limits,
459  _MakeKeyPath(_subDictKey, key),
460  &value)) {
461  return value;
462  }
463  return defaultValue;
464 }
465 
466 template <typename T>
467 inline bool
469  const TfToken& key,
470  const T& value)
471 {
472  return Set(key, VtValue(value));
473 }
474 
475 template <typename T>
476 inline std::optional<T>
478 {
479  return Get<T>(UsdLimitsKeys->Minimum);
480 }
481 
482 template <typename T>
483 inline T
484 UsdAttributeLimits::GetMinimumOr(const T& defaultValue) const
485 {
486  return GetOr<T>(UsdLimitsKeys->Minimum, defaultValue);
487 }
488 
489 template <typename T>
490 inline bool
492 {
493  return Set(UsdLimitsKeys->Minimum, value);
494 }
495 
496 template <typename T>
497 inline std::optional<T>
499 {
500  return Get<T>(UsdLimitsKeys->Maximum);
501 }
502 
503 template <typename T>
504 inline T
505 UsdAttributeLimits::GetMaximumOr(const T& defaultValue) const
506 {
507  return GetOr<T>(UsdLimitsKeys->Maximum, defaultValue);
508 }
509 
510 template <typename T>
511 inline bool
513 {
514  return Set(UsdLimitsKeys->Maximum, value);
515 }
516 
518 
519 #endif
#define USD_API
Definition: api.h:23
bool SetMinimum(const T &value)
std::optional< T > Get(const TfToken &key) const
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
GLsizei const GLfloat * value
Definition: glcorearb.h:824
USD_API UsdAttribute GetAttribute() const
Return the limits object's attribute.
**But if you need a result
Definition: thread.h:622
bool operator!=(const ValidationResult &rhs) const
Inequality operator.
USD_API bool HasAuthored() const
ValidationResult()=default
Construct an empty result.
bool GetMetadataByDictKey(const TfToken &key, const TfToken &keyPath, T *value) const
Definition: object.h:747
OutGridT const XformOp bool bool
USD_API std::string GetErrorString() const
USD_API bool Clear()
Definition: token.h:70
bool operator==(const ValidationResult &rhs) const
Equality operator.
USD_API TfToken GetSubDictKey() const
Return the sub-dictionary key the limits object is using.
USD_API bool HasAuthoredMaximum() const
bool Success() const
Return whether validation was successful.
std::optional< T > GetMaximum() const
bool SetMaximum(const T &value)
USD_API bool HasAuthoredMinimum() const
Definition: path.h:280
UsdAttributeLimits()=default
USD_API bool IsValid() const
USD_API bool Set(const VtDictionary &subDict)
T GetMaximumOr(const T &defaultValue) const
#define USD_LIMITS_KEYS
USD_API bool ClearMaximum()
bool operator!=(const UsdAttributeLimits &rhs) const
Inequality operator.
USD_API bool Validate(const VtDictionary &subDict, ValidationResult *result=nullptr) const
bool operator==(const UsdAttributeLimits &rhs) const
Equality operator.
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
T GetOr(const TfToken &key, const T &defaultValue) const
const VtDictionary & GetConformedSubDict() const
const VtDictionary & GetInvalidValuesDict() const
std::optional< T > GetMinimum() const
USD_API bool ClearMinimum()
TF_DECLARE_PUBLIC_TOKENS(UsdLimitsKeys, USD_API, USD_LIMITS_KEYS)
T GetMinimumOr(const T &defaultValue) const
Definition: value.h:89
bool IsEmpty() const
Returns true iff this token contains the empty string "".
Definition: token.h:288