24 const bool smooth_ends,
25 const bool keep_shape,
58 if (src.
size() == 1) {
63 const int n_half = keep_shape ? (iterations * iterations) / 8 + iterations :
64 (iterations * iterations) / 4 + 2 * iterations + 12;
65 double w = keep_shape ? 2.0 : 1.0;
66 double w2 = keep_shape ?
67 (1.0 /
M_SQRT3) *
exp((2 * iterations * iterations) /
double(n_half * 3)) :
72 const int64_t last_pt = total_points - 1;
74 auto is_end_and_fixed = [smooth_ends,
is_cyclic, last_pt](
int index) {
80 for (const int64_t index : range) {
81 if (!is_end_and_fixed(index)) {
91 for (const int64_t index : range) {
93 if (is_end_and_fixed(index)) {
97 double w_before = w - w2;
98 double w_after = w - w2;
101 int64_t before = index - offset;
102 int64_t after = index + offset;
104 before = (before % total_points + total_points) % total_points;
105 after = after % total_points;
108 if (!smooth_ends && (before < 0)) {
109 w_before *= -before / float(index);
111 before = math::max(before, int64_t(0));
113 if (!smooth_ends && (after > last_pt)) {
114 w_after *= (after - (total_points - 1)) / float(total_points - 1 - index);
116 after = math::min(after, last_pt);
120 const T bval = src[before];
121 const T aval = src[after];
122 const T cval = src[index];
124 dst[index] += (bval - cval) * w_before;
125 dst[index] += (aval - cval) * w_after;
128 total_weight[index] += w_before;
129 total_weight[index] += w_after;
133 w *= (n_half + offset) /
double(n_half + 1 - offset);
134 w2 *= (n_half * 3 + offset) /
double(n_half * 3 + 1 - offset);
139 threading::parallel_for(dst.index_range(), 1024, [&](
const IndexRange range) {
140 for (const int64_t index : range) {
141 if (!is_end_and_fixed(index)) {
142 total_weight[index] += w - w2;
143 dst[index] = src[index] + influence_by_point[index] * dst[index] / total_weight[index];
151 const int iterations,
153 const bool smooth_ends,
154 const bool keep_shape,
159 using T = decltype(dummy);
162 if constexpr (is_same_any_v<T, float, float2, float3>) {
163 gaussian_blur_1D(src.typed<T>(),
178 const int iterations,
180 const bool smooth_ends,
181 const bool keep_shape,
186 auto smooth_points_range =
191 const GSpan src_data(dst_data.
type(), orig_data.data(), range.
size());
204 const IndexRange points = points_by_curve[curve_i];
212 const std::optional<IndexRange> selection_range = selection_mask.
to_range();
213 if (selection_range && *selection_range == points) {
214 smooth_points_range(points, cyclic[curve_i], orig_data);
219 smooth_points_range(range,
false, orig_data);
229 const int iterations,
230 const float influence,
231 const bool smooth_ends,
232 const bool keep_shape,
249 const int iterations,
251 const bool smooth_ends,
252 const bool keep_shape)
279 curves, bezier_curves_to_smooth);
284 const IndexRange points = points_by_curve[curve];
295 if (!smooth_ends && !cyclic[curve]) {
305 if (!smooth_ends && !cyclic[curve]) {
308 for (const int index : influences_range) {
311 point_influences[index] = influences.slice(range)[(index + 1) / 3];
317 positions_range.index_range(), 4096, [&](
const IndexRange influences_range) {
318 for (const int index : influences_range) {
319 point_influences[index] = influences.slice(range)[index / 3];
340 curves.curves_range(), memory);
341 if (!other_curves_to_smooth.
is_empty()) {
343 smooth_curve_attribute(other_curves_to_smooth,
355 curves.calculate_bezier_auto_handles();
358 curves.tag_positions_changed();
364 const int iterations,
365 const float influence,
366 const bool smooth_ends,
367 const bool keep_shape)
Low-level operations for curves.
Low-level operations for curves.
SIMD_FORCE_INLINE const btScalar & w() const
Return the w value.
static IndexMask from_bools(Span< bool > bools, IndexMaskMemory &memory)
MutableSpan< T > as_mutable_span()
void copy_assign_n(const void *src, void *dst, int64_t n) const
int64_t size_in_bytes() const
GMutableSpan slice(const int64_t start, int64_t size) const
const CPPType & type() const
const CPPType & type() const
constexpr IndexRange drop_back(int64_t n) const
constexpr int64_t size() const
constexpr int64_t start() const
constexpr IndexRange index_range() const
constexpr IndexRange drop_front(int64_t n) const
constexpr int64_t size() const
constexpr IndexRange index_range() const
constexpr Span slice(int64_t start, int64_t size) const
constexpr int64_t size() const
constexpr bool is_empty() const
static VArray from_single(T value, const int64_t size)
static VArray from_span(Span< T > values)
void resize(const int64_t new_size)
MutableSpan< T > as_mutable_span()
OffsetIndices< int > points_by_curve() const
MutableAttributeAccessor attributes_for_write()
bool has_curve_with_type(CurveType type) const
IndexMask indices_for_curve_type(CurveType type, IndexMaskMemory &memory) const
VArray< bool > cyclic() const
GSpanAttributeWriter lookup_for_write_span(StringRef attribute_id)
std::optional< IndexRange > to_range() const
IndexMask complement(const IndexMask &universe, IndexMaskMemory &memory) const
void foreach_range(Fn &&fn) const
void foreach_index(Fn &&fn) const
static bool is_cyclic(const Nurb *nu)
VecBase< float, D > step(VecOp< float, D >, VecOp< float, D >) RET
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
Array< float3 > retrieve_all_positions(const bke::CurvesGeometry &curves, const IndexMask &curves_selection)
void write_all_positions(bke::CurvesGeometry &curves, const IndexMask &curves_selection, Span< float3 > all_positions)
void smooth_curve_positions(bke::CurvesGeometry &curves, const IndexMask &curves_to_smooth, const VArray< bool > &point_selection, int iterations, const VArray< float > &influence_by_point, bool smooth_ends, bool keep_shape)
void smooth_curve_attribute(const IndexMask &curves_to_smooth, const OffsetIndices< int > points_by_curve, const VArray< bool > &point_selection, const VArray< bool > &cyclic, int iterations, float influence, bool smooth_ends, bool keep_shape, GMutableSpan attribute_data)
void gaussian_blur_1D(const GSpan src, int iterations, const VArray< float > &influence_by_point, const bool smooth_ends, const bool keep_shape, const bool is_cyclic, GMutableSpan dst)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
void devirtualize_varray(const VArray< T > &varray, const Func &func, bool enable=true)