HDK
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
composeTimeSampleSeries.h
Go to the documentation of this file.
1 //
2 // Copyright 2026 Pixar
3 //
4 // Licensed under the terms set forth in the LICENSE.txt file available at
5 // https://openusd.org/license.
6 //
7 #ifndef PXR_USD_SDF_COMPOSE_TIME_SAMPLE_SERIES_H
8 #define PXR_USD_SDF_COMPOSE_TIME_SAMPLE_SERIES_H
9 
10 #include "pxr/pxr.h"
11 #include "pxr/usd/sdf/api.h"
12 #include "pxr/base/gf/math.h"
13 
15 
16 // The default `timesEqual` function for SdfComposeTimeSampleSeries.
17 inline auto Sdf_timesEqualDefaultFn = [](double t1, double t2) {
18  return GfIsClose(t1, t2, 1e-6);
19 };
20 
21 ///
22 /// A helper function for composing a stronger time-sample series (times &
23 /// values) over a weaker one. This is mostly used as an implementation detail.
24 ///
25 /// Compose the `[strongBegin, strongEnd)` series over `[weakBegin, weakEnd)`.
26 /// The elements of each series must have an associated Time (double-valued) and
27 /// Value (arbitrary), fetched by the `getTime(Iter)` and `getValue(Iter)`
28 /// functions respectively. Iter must be a bidirectional iterator.
29 ///
30 /// The `composeFn(strong, weak)` must accept two Values (as obtained by
31 /// getValue()) and return a `std::optional<Value>`. If the `optional` has a
32 /// value it is used as the result of composing the values, otherwise the
33 /// `strong` value is used.
34 ///
35 /// The `outputFn(Value, Time)` is called to emit the results of the
36 /// composition. This function is always called with strictly increasing Times.
37 ///
38 /// The `timesEqual(Time, Time)` function can optionally be supplied to check
39 /// Time equivalence with a customized epsilon. The default calls GfIsClose
40 /// with an epsilon of 1e-6.
41 ///
42 template <class Iter,
43  class GetTimeFn, class GetValueFn,
44  class ComposeFn, class OutputFn,
45  class TimesEqualFn = decltype(Sdf_timesEqualDefaultFn)>
46 void
48  Iter strongBegin, Iter strongEnd,
49  Iter weakBegin, Iter weakEnd,
50  GetTimeFn const &getTime,
51  GetValueFn const &getValue,
52  ComposeFn const &composeFn,
53  OutputFn const &outputFn,
54  TimesEqualFn const &timesEqual = Sdf_timesEqualDefaultFn)
55 {
56  // If either series is empty, just copy the other.
57  if (weakBegin == weakEnd) {
58  while (strongBegin != strongEnd) {
59  outputFn(getValue(strongBegin), getTime(strongBegin));
60  ++strongBegin;
61  }
62  return;
63  }
64  if (strongBegin == strongEnd) {
65  while (weakBegin != weakEnd) {
66  outputFn(getValue(weakBegin), getTime(weakBegin));
67  ++weakBegin;
68  }
69  return;
70  }
71 
72  auto held = [&getTime, &timesEqual](Iter iter, Iter begin, Iter end,
73  double time) {
74  return iter == end || (!timesEqual(
75  getTime(iter), time) && iter != begin)
76  ? std::prev(iter)
77  : iter;
78  };
79 
80  constexpr double inf = std::numeric_limits<double>::infinity();
81 
82  Iter strongIter = strongBegin;
83  Iter weakIter = weakBegin;
84 
85  while (strongIter != strongEnd || weakIter != weakEnd) {
86  const double strongTime =
87  strongIter == strongEnd ? inf : getTime(strongIter);
88  const double weakTime =
89  weakIter == weakEnd ? inf : getTime(weakIter);
90  if (strongTime <= weakTime) {
91  if (auto composed = composeFn(
92  getValue(strongIter),
93  getValue(held(weakIter, weakBegin, weakEnd,
94  strongTime)))) {
95  outputFn(std::move(*composed), strongTime);
96  }
97  else {
98  outputFn(getValue(strongIter), strongTime);
99  }
100  }
101  else {
102  if (auto composed = composeFn(
103  getValue(held(strongIter, strongBegin, strongEnd,
104  weakTime)),
105  getValue(weakIter))) {
106  outputFn(std::move(*composed), weakTime);
107  }
108  else {
109  // Do nothing -- a non-composing stronger sample hides weaker
110  // samples.
111  }
112  }
113 
114  // Advance the iterator whose next time is less, or the one that has
115  // samples remaining. If they are both at the same time advance both.
116  if (strongIter == strongEnd) {
117  ++weakIter;
118  }
119  else if (weakIter == weakEnd) {
120  ++strongIter;
121  }
122  else {
123  if (timesEqual(strongTime, weakTime)) {
124  ++strongIter, ++weakIter;
125  }
126  else if (strongTime < weakTime) {
127  ++strongIter;
128  }
129  else {
130  ++weakIter;
131  }
132  }
133  }
134 }
135 
137 
138 #endif // PXR_USD_SDF_COMPOSE_TIME_SAMPLE_SERIES_H
GT_API const UT_StringHolder time
#define PXR_NAMESPACE_OPEN_SCOPE
Definition: pxr.h:73
__hostdev__ float getValue(uint32_t i) const
Definition: NanoVDB.h:5578
GLuint GLuint end
Definition: glcorearb.h:475
PcpNodeRef_ChildrenIterator begin(const PcpNodeRef::child_const_range &r)
Support for range-based for loops for PcpNodeRef children ranges.
Definition: node.h:587
void SdfComposeTimeSampleSeries(Iter strongBegin, Iter strongEnd, Iter weakBegin, Iter weakEnd, GetTimeFn const &getTime, GetValueFn const &getValue, ComposeFn const &composeFn, OutputFn const &outputFn, TimesEqualFn const &timesEqual=Sdf_timesEqualDefaultFn)
bool GfIsClose(GfColor const &c1, GfColor const &c2, double tolerance)
Definition: color.h:114
#define PXR_NAMESPACE_CLOSE_SCOPE
Definition: pxr.h:74
PXR_NAMESPACE_OPEN_SCOPE auto Sdf_timesEqualDefaultFn