Blender  V3.3
curve_catmull_rom.cc
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later */
2 
7 #include "BKE_attribute_math.hh"
8 #include "BKE_curves.hh"
9 
11 
12 int calculate_evaluated_num(const int points_num, const bool cyclic, const int resolution)
13 {
14  const int eval_num = resolution * segments_num(points_num, cyclic);
15  if (cyclic) {
16  /* Make sure there is a single evaluated point for the single-point curve case. */
17  return std::max(eval_num, 1);
18  }
19  /* If the curve isn't cyclic, one last point is added to the final point. */
20  return eval_num + 1;
21 }
22 
23 /* Adapted from Cycles #catmull_rom_basis_eval function. */
24 template<typename T>
25 static T calculate_basis(const T &a, const T &b, const T &c, const T &d, const float parameter)
26 {
27  const float t = parameter;
28  const float s = 1.0f - parameter;
29  const float n0 = -t * s * s;
30  const float n1 = 2.0f + t * t * (3.0f * t - 5.0f);
31  const float n2 = 2.0f + s * s * (3.0f * s - 5.0f);
32  const float n3 = -s * t * t;
33  return 0.5f * (a * n0 + b * n1 + c * n2 + d * n3);
34 }
35 
36 template<typename T>
37 static void evaluate_segment(const T &a, const T &b, const T &c, const T &d, MutableSpan<T> dst)
38 {
39  const float step = 1.0f / dst.size();
40  dst.first() = b;
41  for (const int i : dst.index_range().drop_front(1)) {
42  dst[i] = calculate_basis<T>(a, b, c, d, i * step);
43  }
44 }
45 
51 template<typename T, typename RangeForSegmentFn>
53  const bool cyclic,
54  const RangeForSegmentFn &range_fn,
55  MutableSpan<T> dst)
56 
57 {
58  /* - First deal with one and two point curves need special attention.
59  * - Then evaluate the first and last segment(s) whose control points need to wrap around
60  * to the other side of the source array.
61  * - Finally evaluate all of the segments in the middle in parallel. */
62 
63  if (src.size() == 1) {
64  dst.first() = src.first();
65  return;
66  }
67 
68  const IndexRange first = range_fn(0);
69 
70  if (src.size() == 2) {
71  evaluate_segment(src.first(), src.first(), src.last(), src.last(), dst.slice(first));
72  if (cyclic) {
73  const IndexRange last = range_fn(1);
74  evaluate_segment(src.last(), src.last(), src.first(), src.first(), dst.slice(last));
75  }
76  else {
77  dst.last() = src.last();
78  }
79  return;
80  }
81 
82  const IndexRange second_to_last = range_fn(src.index_range().last(1));
83  const IndexRange last = range_fn(src.index_range().last());
84  if (cyclic) {
85  evaluate_segment(src.last(), src[0], src[1], src[2], dst.slice(first));
86  evaluate_segment(src.last(2), src.last(1), src.last(), src.first(), dst.slice(second_to_last));
87  evaluate_segment(src.last(1), src.last(), src[0], src[1], dst.slice(last));
88  }
89  else {
90  evaluate_segment(src[0], src[0], src[1], src[2], dst.slice(first));
91  evaluate_segment(src.last(2), src.last(1), src.last(), src.last(), dst.slice(second_to_last));
92  /* For non-cyclic curves, the last segment should always just have a single point. We could
93  * assert that the size of the provided range is 1 here, but that would require specializing
94  * the #range_fn implementation for the last point, which may have a performance cost. */
95  dst.last() = src.last();
96  }
97 
98  /* Evaluate every segment that isn't the first or last. */
99  const IndexRange inner_range = src.index_range().drop_back(2).drop_front(1);
100  threading::parallel_for(inner_range, 512, [&](IndexRange range) {
101  for (const int i : range) {
102  const IndexRange segment = range_fn(i);
103  evaluate_segment(src[i - 1], src[i], src[i + 1], src[i + 2], dst.slice(segment));
104  }
105  });
106 }
107 
108 template<typename T>
110  const bool cyclic,
111  const int resolution,
112  MutableSpan<T> dst)
113 
114 {
115  BLI_assert(dst.size() == calculate_evaluated_num(src.size(), cyclic, resolution));
117  src,
118  cyclic,
119  [resolution](const int segment_i) -> IndexRange {
120  return {segment_i * resolution, resolution};
121  },
122  dst);
123 }
124 
125 template<typename T>
127  const bool cyclic,
128  const Span<int> evaluated_offsets,
129  MutableSpan<T> dst)
130 
131 {
133  src,
134  cyclic,
135  [evaluated_offsets](const int segment_i) -> IndexRange {
136  return bke::offsets_to_range(evaluated_offsets, segment_i);
137  },
138  dst);
139 }
140 
142  const bool cyclic,
143  const int resolution,
144  GMutableSpan dst)
145 {
146  attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
147  using T = decltype(dummy);
148  /* TODO: Use DefaultMixer or other generic mixing in the basis evaluation function to simplify
149  * supporting more types. */
150  if constexpr (is_same_any_v<T, float, float2, float3, float4, int8_t, int, int64_t>) {
151  interpolate_to_evaluated(src.typed<T>(), cyclic, resolution, dst.typed<T>());
152  }
153  });
154 }
155 
157  const bool cyclic,
158  const Span<int> evaluated_offsets,
159  GMutableSpan dst)
160 {
161  attribute_math::convert_to_static_type(src.type(), [&](auto dummy) {
162  using T = decltype(dummy);
163  /* TODO: Use DefaultMixer or other generic mixing in the basis evaluation function to simplify
164  * supporting more types. */
165  if constexpr (is_same_any_v<T, float, float2, float3, float4, int8_t, int, int64_t>) {
166  interpolate_to_evaluated(src.typed<T>(), cyclic, evaluated_offsets, dst.typed<T>());
167  }
168  });
169 }
170 
171 } // namespace blender::bke::curves::catmull_rom
Low-level operations for curves.
#define BLI_assert(a)
Definition: BLI_assert.h:46
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
constexpr IndexRange drop_front(int64_t n) const
constexpr int64_t size() const
Definition: BLI_span.hh:511
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
Definition: BLI_span.hh:581
constexpr T & last(const int64_t n=0) const
Definition: BLI_span.hh:680
constexpr IndexRange index_range() const
Definition: BLI_span.hh:661
constexpr T & first() const
Definition: BLI_span.hh:670
SyclQueue void void * src
#define T
static unsigned c
Definition: RandGen.cpp:83
Segment< FEdge *, Vec3r > segment
static unsigned a[3]
Definition: RandGen.cpp:78
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
static void interpolate_to_evaluated(const Span< T > src, const bool cyclic, const Span< int > evaluated_offsets, MutableSpan< T > dst)
static void evaluate_segment(const T &a, const T &b, const T &c, const T &d, MutableSpan< T > dst)
int calculate_evaluated_num(int points_num, bool cyclic, int resolution)
static T calculate_basis(const T &a, const T &b, const T &c, const T &d, const float parameter)
void interpolate_to_evaluated(GSpan src, bool cyclic, int resolution, GMutableSpan dst)
int segments_num(const int points_num, const bool cyclic)
Definition: BKE_curves.hh:462
constexpr IndexRange offsets_to_range(Span< T > offsets, int64_t index)
Definition: BKE_curves.hh:29
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
Definition: BLI_task.hh:51
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
float max