ArraySamplers-Impl.hpp
Go to the documentation of this file.
1 // This code is based on Jet framework.
2 // Copyright (c) 2018 Doyub Kim
3 // CubbyFlow is voxel-based fluid simulation engine for computer games.
4 // Copyright (c) 2020 CubbyFlow Team
5 // Core Part: Chris Ohk, Junwoo Hwang, Jihong Sin, Seungwoo Yoo
6 // AI Part: Dongheon Cho, Minseo Kim
7 // We are making my contributions/submissions to this project solely in our
8 // personal capacity and are not conveying any rights to any intellectual
9 // property of any third parties.
10 
11 #ifndef CUBBYFLOW_ARRAY_SAMPLERS_IMPL_HPP
12 #define CUBBYFLOW_ARRAY_SAMPLERS_IMPL_HPP
13 
14 #include <Core/Math/MathUtils.hpp>
15 
16 namespace CubbyFlow
17 {
18 namespace Internal
19 {
20 template <typename T, size_t N, size_t I>
21 struct Lerp
22 {
24 
25  template <typename View, typename... RemainingIndices>
26  static auto Call(const View& view, Vector<ssize_t, N> i,
27  Vector<ScalarType, N> t, RemainingIndices... indices)
28  {
29  using Next = Lerp<T, N, I - 1>;
30 
31  return CubbyFlow::Lerp(Next::Call(view, i, t, i[I - 1], indices...),
32  Next::Call(view, i, t, i[I - 1] + 1, indices...),
33  t[I - 1]);
34  }
35 };
36 
37 template <typename T, size_t N>
38 struct Lerp<T, N, 1>
39 {
41 
42  template <typename View, typename... RemainingIndices>
43  static auto Call(const View& view, Vector<ssize_t, N> i,
44  Vector<ScalarType, N> t, RemainingIndices... indices)
45  {
46  return CubbyFlow::Lerp(view(i[0], indices...),
47  view(i[0] + 1, indices...), t[0]);
48  }
49 };
50 
51 template <typename T, size_t N, size_t I>
52 struct Cubic
53 {
55 
56  template <typename View, typename CubicInterpolationOp,
57  typename... RemainingIndices>
58  static auto Call(const View& view, Vector<ssize_t, N> i,
59  Vector<ScalarType, N> t, CubicInterpolationOp op,
60  RemainingIndices... indices)
61  {
62  using Next = Cubic<T, N, I - 1>;
63 
64  return op(
65  Next::Call(view, i, t, op, std::max(i[I - 1] - 1, ZERO_SSIZE),
66  indices...),
67  Next::Call(view, i, t, op, i[I - 1], indices...),
68  Next::Call(view, i, t, op,
69  std::min(i[I - 1] + 1,
70  static_cast<ssize_t>(view.Size()[I - 1]) - 1),
71  indices...),
72  Next::Call(view, i, t, op,
73  std::min(i[I - 1] + 2,
74  static_cast<ssize_t>(view.Size()[I - 1]) - 1),
75  indices...),
76  t[I - 1]);
77  }
78 };
79 
80 template <typename T, size_t N>
81 struct Cubic<T, N, 1>
82 {
84 
85  template <typename View, typename CubicInterpolationOp,
86  typename... RemainingIndices>
87  static auto Call(const View& view, Vector<ssize_t, N> i,
88  Vector<ScalarType, N> t, CubicInterpolationOp op,
89  RemainingIndices... indices)
90  {
91  return op(
92  view(std::max(i[0] - 1, ZERO_SSIZE), indices...),
93  view(i[0], indices...),
94  view(std::min(i[0] + 1, static_cast<ssize_t>(view.Size()[0]) - 1),
95  indices...),
96  view(std::min(i[0] + 2, static_cast<ssize_t>(view.Size()[0]) - 1),
97  indices...),
98  t[0]);
99  }
100 };
101 
102 template <typename T, size_t N, size_t I>
104 {
106 
107  template <typename Coords, typename Weights, typename... RemainingIndices>
108  static void Call(Coords& c, Weights& w, Vector<size_t, N> i,
109  Vector<ScalarType, N> t, T acc, RemainingIndices... idx)
110  {
111  using Next = GetCoordinatesAndWeights<T, N, I - 1>;
112 
113  Next::Call(c, w, i, t, acc * (1 - t[I - 1]), 0, idx...);
114  Next::Call(c, w, i, t, acc * t[I - 1], 1, idx...);
115  }
116 };
117 
118 template <typename T, size_t N>
120 {
122 
123  template <typename Coords, typename Weights, typename... RemainingIndices>
124  static void Call(Coords& c, Weights& w, Vector<size_t, N> i,
125  Vector<ScalarType, N> t, T acc, RemainingIndices... idx)
126  {
127  c(0, idx...) = Vector<size_t, N>(0, idx...) + i;
128  c(1, idx...) = Vector<size_t, N>(1, idx...) + i;
129 
130  w(0, idx...) = acc * (1 - t[0]);
131  w(1, idx...) = acc * (t[0]);
132  }
133 };
134 
135 template <typename T, size_t N, size_t I>
137 {
138  template <typename Coords, typename Weights, typename... RemainingIndices>
139  static void Call(Coords& c, Weights& w, Vector<size_t, N> i, Vector<T, N> t,
140  Vector<T, N> acc, RemainingIndices... idx)
141  {
142  Vector<T, N> w0 = Vector<T, N>::MakeConstant(1 - t[I - 1]);
143  w0[I - 1] = -1;
145  w1[I - 1] = 1;
146 
147  using Next = GetCoordinatesAndGradientWeights<T, N, I - 1>;
148  Next::Call(c, w, i, t, ElemMul(acc, w0), 0, idx...);
149  Next::Call(c, w, i, t, ElemMul(acc, w1), 1, idx...);
150  }
151 };
152 
153 template <typename T, size_t N>
155 {
156  template <typename Coords, typename Weights, typename... RemainingIndices>
157  static void Call(Coords& c, Weights& w, Vector<size_t, N> i, Vector<T, N> t,
158  Vector<T, N> acc, RemainingIndices... idx)
159  {
160  c(0, idx...) = Vector<size_t, N>(0, idx...) + i;
161  c(1, idx...) = Vector<size_t, N>(1, idx...) + i;
162 
164  w0[0] = -1;
166  w1[0] = 1;
167 
168  w(0, idx...) = ElemMul(acc, w0);
169  w(1, idx...) = ElemMul(acc, w1);
170  }
171 };
172 } // namespace Internal
173 
174 template <typename T, size_t N>
176  const ArrayView<const T, N>& view, const VectorType& gridSpacing,
177  const VectorType& gridOrigin)
178  : m_view(view),
179  m_gridSpacing(gridSpacing),
180  m_invGridSpacing(ScalarType{ 1 } / gridSpacing),
181  m_gridOrigin(gridOrigin)
182 {
183  // Do nothing
184 }
185 
186 template <typename T, size_t N>
188  : m_view(other.m_view),
189  m_gridSpacing(other.m_gridSpacing),
190  m_invGridSpacing(other.m_invGridSpacing),
191  m_gridOrigin(other.m_gridOrigin)
192 {
193  // Do nothing
194 }
195 
196 template <typename T, size_t N>
198  : m_view(std::move(other.m_view)),
199  m_gridSpacing(std::move(other.m_gridSpacing)),
200  m_invGridSpacing(std::move(other.m_invGridSpacing)),
201  m_gridOrigin(std::move(other.m_gridOrigin))
202 {
203  // Do nothing
204 }
205 
206 template <typename T, size_t N>
208  const NearestArraySampler& other)
209 {
210  m_view = other.m_view;
211  m_gridSpacing = other.m_gridSpacing;
212  m_invGridSpacing = other.m_invGridSpacing;
213  m_gridOrigin = other.m_gridOrigin;
214 
215  return *this;
216 }
217 
218 template <typename T, size_t N>
220  NearestArraySampler&& other) noexcept
221 {
222  m_view = std::move(other.m_view);
223  m_gridSpacing = std::move(other.m_gridSpacing);
224  m_invGridSpacing = std::move(other.m_invGridSpacing);
225  m_gridOrigin = std::move(other.m_gridOrigin);
226 
227  return *this;
228 }
229 
230 template <typename T, size_t N>
232 {
233  return m_view(GetCoordinate(pt));
234 }
235 
236 template <typename T, size_t N>
239 {
241  VectorType npt = ElemMul(pt - m_gridOrigin, m_invGridSpacing);
242  Vector<ssize_t, N> size = m_view.Size().template CastTo<ssize_t>();
243 
244  for (size_t i = 0; i < N; ++i)
245  {
247  GetBarycentric(npt[i], 0, size[i], is[i], ts[i]);
248  is[i] =
249  std::min(static_cast<ssize_t>(is[i] + ts[i] + 0.5), size[i] - 1);
250  }
251 
252  return is.template CastTo<size_t>();
253 }
254 
255 template <typename T, size_t N>
256 std::function<T(const typename NearestArraySampler<T, N>::VectorType&)>
258 {
259  NearestArraySampler sampler(*this);
260 
261  return [sampler](const VectorType& x) -> T { return sampler(x); };
262 }
263 
264 template <typename T, size_t N>
266  const VectorType& gridSpacing,
267  const VectorType& gridOrigin)
268  : m_view(view),
269  m_gridSpacing(gridSpacing),
270  m_invGridSpacing(ScalarType{ 1 } / gridSpacing),
271  m_gridOrigin(gridOrigin)
272 {
273  // Do nothing
274 }
275 
276 template <typename T, size_t N>
278  : m_view(other.m_view),
279  m_gridSpacing(other.m_gridSpacing),
280  m_invGridSpacing(other.m_invGridSpacing),
281  m_gridOrigin(other.m_gridOrigin)
282 {
283  // Do nothing
284 }
285 
286 template <typename T, size_t N>
288  : m_view(std::move(other.m_view)),
289  m_gridSpacing(std::move(other.m_gridSpacing)),
290  m_invGridSpacing(std::move(other.m_invGridSpacing)),
291  m_gridOrigin(std::move(other.m_gridOrigin))
292 {
293  // Do nothing
294 }
295 
296 template <typename T, size_t N>
298  const LinearArraySampler& other)
299 {
300  m_view = other.m_view;
301  m_gridSpacing = other.m_gridSpacing;
302  m_invGridSpacing = other.m_invGridSpacing;
303  m_gridOrigin = other.m_gridOrigin;
304 
305  return *this;
306 }
307 
308 template <typename T, size_t N>
310  LinearArraySampler&& other) noexcept
311 {
312  m_view = std::move(other.m_view);
313  m_gridSpacing = std::move(other.m_gridSpacing);
314  m_invGridSpacing = std::move(other.m_invGridSpacing);
315  m_gridOrigin = std::move(other.m_gridOrigin);
316 
317  return *this;
318 }
319 
320 template <typename T, size_t N>
322 {
325  VectorType npt = ElemMul(pt - m_gridOrigin, m_invGridSpacing);
326  Vector<ssize_t, N> size = m_view.Size().template CastTo<ssize_t>();
327 
328  for (size_t i = 0; i < N; ++i)
329  {
330  GetBarycentric(npt[i], 0, size[i], is[i], ts[i]);
331  }
332 
333  return Internal::Lerp<T, N, N>::Call(m_view, is, ts);
334 }
335 
336 template <typename T, size_t N>
338  const VectorType& pt, std::array<CoordIndexType, FLAT_KERNEL_SIZE>& indices,
339  std::array<ScalarType, FLAT_KERNEL_SIZE>& weights) const
340 {
343  VectorType npt = ElemMul(pt - m_gridOrigin, m_invGridSpacing);
344  Vector<ssize_t, N> size = m_view.Size().template CastTo<ssize_t>();
345 
346  for (size_t i = 0; i < N; ++i)
347  {
348  GetBarycentric(npt[i], 0, size[i], is[i], ts[i]);
349  }
350 
352  ArrayView<CoordIndexType, N> indexView(indices.data(), viewSize);
353  ArrayView<ScalarType, N> weightView(weights.data(), viewSize);
354 
356  indexView, weightView, is.template CastTo<size_t>(), ts, 1);
357 }
358 
359 template <typename T, size_t N>
361  const VectorType& pt, std::array<CoordIndexType, FLAT_KERNEL_SIZE>& indices,
362  std::array<VectorType, FLAT_KERNEL_SIZE>& weights) const
363 {
366  VectorType npt = ElemMul(pt - m_gridOrigin, m_invGridSpacing);
367  Vector<ssize_t, N> size = m_view.Size().template CastTo<ssize_t>();
368 
369  for (size_t i = 0; i < N; ++i)
370  {
371  GetBarycentric(npt[i], 0, size[i], is[i], ts[i]);
372  }
373 
375  ArrayView<CoordIndexType, N> indexView(indices.data(), viewSize);
376  ArrayView<VectorType, N> weightView(weights.data(), viewSize);
377 
379  indexView, weightView, is.template CastTo<size_t>(), ts,
380  m_invGridSpacing);
381 }
382 
383 template <typename T, size_t N>
384 std::function<T(const typename LinearArraySampler<T, N>::VectorType&)>
386 {
387  LinearArraySampler sampler(*this);
388 
389  return [sampler](const VectorType& x) -> T { return sampler(x); };
390 }
391 
392 template <typename T, size_t N, typename CIOp>
394  const ArrayView<const T, N>& view, const VectorType& gridSpacing,
395  const VectorType& gridOrigin)
396  : m_view(view),
397  m_gridSpacing(gridSpacing),
398  m_invGridSpacing(ScalarType{ 1 } / gridSpacing),
399  m_gridOrigin(gridOrigin)
400 {
401  // Do nothing
402 }
403 
404 template <typename T, size_t N, typename CIOp>
406  : m_view(other.m_view),
407  m_gridSpacing(other.m_gridSpacing),
408  m_invGridSpacing(other.m_invGridSpacing),
409  m_gridOrigin(other.m_gridOrigin)
410 {
411  // Do nothing
412 }
413 
414 template <typename T, size_t N, typename CIOp>
416  : m_view(std::move(other.m_view)),
417  m_gridSpacing(std::move(other.m_gridSpacing)),
418  m_invGridSpacing(std::move(other.m_invGridSpacing)),
419  m_gridOrigin(std::move(other.m_gridOrigin))
420 {
421  // Do nothing
422 }
423 
424 template <typename T, size_t N, typename CIOp>
426  const CubicArraySampler& other)
427 {
428  m_view = other.m_view;
429  m_gridSpacing = other.m_gridSpacing;
430  m_invGridSpacing = other.m_invGridSpacing;
431  m_gridOrigin = other.m_gridOrigin;
432 
433  return *this;
434 }
435 
436 template <typename T, size_t N, typename CIOp>
438  CubicArraySampler&& other) noexcept
439 {
440  m_view = std::move(other.m_view);
441  m_gridSpacing = std::move(other.m_gridSpacing);
442  m_invGridSpacing = std::move(other.m_invGridSpacing);
443  m_gridOrigin = std::move(other.m_gridOrigin);
444 
445  return *this;
446 }
447 
448 template <typename T, size_t N, typename CIOp>
450 {
453  VectorType npt = ElemMul(pt - m_gridOrigin, m_invGridSpacing);
454  Vector<ssize_t, N> size = m_view.Size().template CastTo<ssize_t>();
455 
456  for (size_t i = 0; i < N; ++i)
457  {
458  GetBarycentric(npt[i], 0, size[i], is[i], ts[i]);
459  }
460 
461  return Internal::Cubic<T, N, N>::Call(m_view, is, ts, CIOp());
462 }
463 
464 template <typename T, size_t N, typename CIOp>
465 std::function<T(const typename CubicArraySampler<T, N, CIOp>::VectorType&)>
467 {
468  CubicArraySampler sampler(*this);
469 
470  return [sampler](const VectorType& x) -> T { return sampler(x); };
471 }
472 } // namespace CubbyFlow
473 
474 #endif
Definition: ArraySamplers-Impl.hpp:21
NearestArraySampler()=default
Default constructor.
std::enable_if_t< std::is_arithmetic< T >::value, S > Lerp(const S &f0, const S &f1, T t)
Computes linear interpolation.
Definition: MathUtils-Impl.hpp:295
static void Call(Coords &c, Weights &w, Vector< size_t, N > i, Vector< ScalarType, N > t, T acc, RemainingIndices... idx)
Definition: ArraySamplers-Impl.hpp:124
static auto Call(const View &view, Vector< ssize_t, N > i, Vector< ScalarType, N > t, CubicInterpolationOp op, RemainingIndices... indices)
Definition: ArraySamplers-Impl.hpp:87
N-D nearest array sampler class.
Definition: ArraySamplers.hpp:29
typename GetScalarType< T >::value ScalarType
Definition: ArraySamplers-Impl.hpp:121
std::enable_if_t< std::is_arithmetic< T >::value > GetBarycentric(T x, size_t begin, size_t end, size_t &i, T &t)
Computes the barycentric coordinate.
Definition: MathUtils-Impl.hpp:196
Definition: ArrayView.hpp:60
static auto Call(const View &view, Vector< ssize_t, N > i, Vector< ScalarType, N > t, RemainingIndices... indices)
Definition: ArraySamplers-Impl.hpp:43
static auto Call(const View &view, Vector< ssize_t, N > i, Vector< ScalarType, N > t, RemainingIndices... indices)
Definition: ArraySamplers-Impl.hpp:26
T operator()(const VectorType &pt) const
Returns sampled value at point pt.
Definition: ArraySamplers-Impl.hpp:449
NearestArraySampler & operator=(const NearestArraySampler &other)
Copy assignment operator.
Definition: ArraySamplers-Impl.hpp:207
LinearArraySampler()=default
Default constructor.
typename GetScalarType< T >::value ScalarType
Definition: ArraySamplers-Impl.hpp:23
static auto Call(const View &view, Vector< ssize_t, N > i, Vector< ScalarType, N > t, CubicInterpolationOp op, RemainingIndices... indices)
Definition: ArraySamplers-Impl.hpp:58
Definition: ArraySamplers-Impl.hpp:103
CubicArraySampler()=default
Default constructor.
typename GetScalarType< CubbyFlow::Matrix< double, N > >::value ScalarType
Definition: ArraySamplers.hpp:111
Definition: ArraySamplers-Impl.hpp:136
typename GetScalarType< T >::value ScalarType
Definition: ArraySamplers.hpp:34
Definition: Matrix.hpp:27
static std::enable_if_t< IsMatrixSizeStatic< Rows, Cols >), D > MakeConstant(ValueType val)
Makes a static matrix with constant entries.
Definition: MatrixDenseBase-Impl.hpp:152
T operator()(const VectorType &pt) const
Returns sampled value at point pt.
Definition: ArraySamplers-Impl.hpp:231
Definition: pybind11Utils.hpp:20
CubicArraySampler & operator=(const CubicArraySampler &other)
Copy assignment operator.
Definition: ArraySamplers-Impl.hpp:425
constexpr auto ElemMul(const MatrixExpression< T, Rows, Cols, M1 > &a, const MatrixExpression< T, Rows, Cols, M2 > &b)
Definition: MatrixExpression-Impl.hpp:1085
N-D cubic array sampler class.
Definition: ArraySamplers.hpp:195
static void Call(Coords &c, Weights &w, Vector< size_t, N > i, Vector< ScalarType, N > t, T acc, RemainingIndices... idx)
Definition: ArraySamplers-Impl.hpp:108
typename GetScalarType< T >::value ScalarType
Definition: ArraySamplers-Impl.hpp:83
typename GetScalarType< T >::value ScalarType
Definition: ArraySamplers-Impl.hpp:54
typename GetScalarType< T >::value ScalarType
Definition: ArraySamplers-Impl.hpp:105
Definition: ArraySamplers-Impl.hpp:52
Generic N-dimensional array class interface.
Definition: Array.hpp:32
constexpr ssize_t ZERO_SSIZE
Zero ssize_t.
Definition: Constants.hpp:22
CoordIndexType GetCoordinate(const VectorType &pt) const
Returns the nearest array index for point pt.
Definition: ArraySamplers-Impl.hpp:238
typename GetScalarType< T >::value ScalarType
Definition: ArraySamplers-Impl.hpp:40
N-D array sampler using linear interpolation.
Definition: ArraySamplers.hpp:106
const Vector< size_t, N > & Size() const
Definition: ArrayBase-Impl.hpp:51
static void Call(Coords &c, Weights &w, Vector< size_t, N > i, Vector< T, N > t, Vector< T, N > acc, RemainingIndices... idx)
Definition: ArraySamplers-Impl.hpp:139
T value
Definition: TypeHelpers.hpp:20
static void Call(Coords &c, Weights &w, Vector< size_t, N > i, Vector< T, N > t, Vector< T, N > acc, RemainingIndices... idx)
Definition: ArraySamplers-Impl.hpp:157
typename GetScalarType< T >::value ScalarType
Definition: ArraySamplers.hpp:200