24 return {curve_index + points.
start(), points.
size() + 1};
31 for (const int i : range) {
32 dst.slice(bke::offsets_to_range(offsets, i)).fill(src[i]);
46 for (const int curve_i : curve_selection.slice(range)) {
47 const IndexRange src_points = src_curves.points_for_curve(curve_i);
48 const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
49 const Span<int> offsets = point_offsets.slice(curve_dst_offsets(src_points, curve_i));
50 threaded_slice_fill(src.slice(src_points), offsets, dst.slice(dst_points));
63 using T = decltype(dummy);
64 duplicate_fillet_point_data(
65 src_curves, dst_curves, selection, point_offsets, src.typed<T>(), dst.typed<T>());
81 for (const int curve_i : selection.slice(range)) {
82 const IndexRange src_points = src_curves.points_for_curve(curve_i);
83 const IndexRange offsets_range = curve_dst_offsets(src_points, curve_i);
85 MutableSpan<int> point_offsets = dst_point_offsets.slice(offsets_range);
86 MutableSpan<int> point_counts = point_offsets.drop_back(1);
88 counts.materialize_compressed(src_points, point_counts);
89 for (int &count : point_counts) {
91 count = std::max(count, 0) + 1;
93 if (!cyclic[curve_i]) {
95 point_counts.first() = 1;
96 point_counts.last() = 1;
99 devirtualize_varray(radii, [&](const auto radii) {
100 for (const int i : IndexRange(src_points.size())) {
101 if (radii[src_points[i]] == 0.0f) {
107 bke::curves::accumulate_counts_to_offsets(point_offsets);
109 dst_curve_offsets[curve_i] = point_offsets.last();
117 for (
const int i :
positions.index_range().drop_back(1)) {
138 const float3 &position_next,
139 const float angle_prev,
141 const float angle_next,
142 const float radius_prev,
144 const float radius_next)
148 const float displacement_prev = radius_prev *
std::tan(angle_prev / 2.0f);
149 const float segment_length_prev =
math::distance(position, position_prev);
150 const float total_displacement_prev = displacement_prev + displacement;
151 const float factor_prev =
std::clamp(segment_length_prev / total_displacement_prev, 0.0f, 1.0f);
153 const float displacement_next = radius_next *
std::tan(angle_next / 2.0f);
154 const float segment_length_next =
math::distance(position, position_next);
155 const float total_displacement_next = displacement_next + displacement;
156 const float factor_next =
std::clamp(segment_length_next / total_displacement_next, 0.0f, 1.0f);
158 return radius *
std::min(factor_prev, factor_next);
179 for (
const int i :
positions.index_range().drop_back(1).drop_front(1)) {
180 const int i_prev = i - 1;
181 const int i_next = i + 1;
204 const int i_last =
positions.index_range().last();
206 radii_clamped.
first() = 0.0f;
208 for (
const int i :
positions.index_range().drop_back(1).drop_front(1)) {
209 const int i_prev = i - 1;
210 const int i_next = i + 1;
213 const float radius_prev = i_prev == 0 ? 0.0f :
radii[i_prev];
214 const float radius_next = i_next == i_last ? 0.0f :
radii[i_next];
226 radii_clamped.
last() = 0.0f;
239 for (const int i_src : range) {
240 const IndexRange arc = bke::offsets_to_range(dst_offsets, i_src);
241 const float3 &src = src_positions[i_src];
242 if (arc.size() == 1) {
243 dst[arc.first()] = src;
247 const int i_src_prev = i_src == 0 ? i_src_last : i_src - 1;
248 const float angle = angles[i_src];
249 const float radius = radii[i_src];
250 const float displacement = radius * std::tan(angle / 2.0f);
251 const float3 prev_dir = -directions[i_src_prev];
252 const float3 &next_dir = directions[i_src];
253 const float3 arc_start = src + prev_dir * displacement;
254 const float3 arc_end = src + next_dir * displacement;
256 dst[arc.first()] = arc_start;
257 dst[arc.last()] = arc_end;
259 const IndexRange middle = arc.drop_front(1).drop_back(1);
260 if (middle.is_empty()) {
264 const float3 axis = -math::normalize(math::cross(prev_dir, next_dir));
265 const float3 center_direction = math::normalize(math::midpoint(next_dir, prev_dir));
266 const float distance_to_center = std::sqrt(pow2f(radius) + pow2f(displacement));
267 const float3 center = src + center_direction * distance_to_center;
270 const float segment_angle = angle / (middle.size() + 1);
271 for (const int i : IndexRange(middle.size())) {
272 const int point_i = middle[i];
273 dst[point_i] = math::rotate_around_axis(arc_start, center, axis, segment_angle * (i + 1));
301 for (const int i_src : range) {
302 const IndexRange arc = bke::offsets_to_range(dst_offsets, i_src);
303 if (arc.size() == 1) {
304 dst_handles_l[arc.first()] = src_handles_l[i_src];
305 dst_handles_r[arc.first()] = src_handles_r[i_src];
306 dst_types_l[arc.first()] = src_types_l[i_src];
307 dst_types_r[arc.first()] = src_types_r[i_src];
310 BLI_assert(arc.size() == 2);
311 const int i_dst_a = arc.first();
312 const int i_dst_b = arc.last();
314 const int i_src_prev = i_src == 0 ? i_src_last : i_src - 1;
315 const float angle = angles[i_src];
316 const float radius = radii[i_src];
317 const float3 prev_dir = -directions[i_src_prev];
318 const float3 &next_dir = directions[i_src];
320 const float3 &arc_start = dst_positions[arc.first()];
321 const float3 &arc_end = dst_positions[arc.last()];
325 const int i_dst_prev = i_dst_a == 0 ? i_dst_last : i_dst_a - 1;
326 const int i_dst_next = i_dst_b == i_dst_last ? 0 : i_dst_b + 1;
327 dst_handles_l[i_dst_a] = bke::curves::bezier::calculate_vector_handle(
328 dst_positions[i_dst_a], dst_positions[i_dst_prev]);
329 dst_handles_r[i_dst_b] = bke::curves::bezier::calculate_vector_handle(
330 dst_positions[i_dst_b], dst_positions[i_dst_next]);
331 dst_types_l[i_dst_a] = BEZIER_HANDLE_VECTOR;
332 dst_types_r[i_dst_b] = BEZIER_HANDLE_VECTOR;
336 const float handle_length = (4.0f / 3.0f) * radius * std::tan(angle / 4.0f);
337 dst_handles_r[i_dst_a] = arc_start - prev_dir * handle_length;
338 dst_handles_l[i_dst_b] = arc_end - next_dir * handle_length;
339 dst_types_r[i_dst_a] = BEZIER_HANDLE_ALIGN;
340 dst_types_l[i_dst_b] = BEZIER_HANDLE_ALIGN;
362 for (const int i_src : range) {
363 const IndexRange arc = bke::offsets_to_range(dst_offsets, i_src);
364 if (arc.size() == 1) {
365 dst_handles_l[arc.first()] = src_handles_l[i_src];
366 dst_handles_r[arc.first()] = src_handles_r[i_src];
367 dst_types_l[arc.first()] = src_types_l[i_src];
368 dst_types_r[arc.first()] = src_types_r[i_src];
373 dst_types_l.slice(arc).fill(BEZIER_HANDLE_VECTOR);
374 dst_types_r.slice(arc).fill(BEZIER_HANDLE_VECTOR);
379 const int i_dst_prev = arc.first() == 0 ? i_dst_last : arc.one_before_start();
380 const int i_dst_next = arc.last() == i_dst_last ? 0 : arc.one_after_last();
381 dst_handles_l[arc.first()] = bke::curves::bezier::calculate_vector_handle(
382 dst_positions[arc.first()], dst_positions[i_dst_prev]);
383 dst_handles_r[arc.last()] = bke::curves::bezier::calculate_vector_handle(
384 dst_positions[arc.last()], dst_positions[i_dst_next]);
387 const IndexRange middle = arc.drop_front(1).drop_back(1);
388 for (const int i : middle) {
389 dst_handles_r[i] = bke::curves::bezier::calculate_vector_handle(dst_positions[i],
390 dst_positions[i - 1]);
391 dst_handles_l[i] = bke::curves::bezier::calculate_vector_handle(dst_positions[i],
392 dst_positions[i + 1]);
403 const bool use_bezier_mode)
451 Array<float3> directions;
454 Array<float> input_radii_buffer;
456 for (const int curve_i : curve_selection.slice(range)) {
457 const IndexRange src_points = src_curves.points_for_curve(curve_i);
458 const Span<int> offsets = point_offsets.slice(curve_dst_offsets(src_points, curve_i));
459 const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
460 const Span<float3> src_positions = positions.slice(src_points);
462 directions.reinitialize(src_points.size());
463 calculate_directions(src_positions, directions);
465 angles.reinitialize(src_points.size());
466 calculate_angles(directions, angles);
468 radii.reinitialize(src_points.size());
470 input_radii_buffer.reinitialize(src_points.size());
471 radius_input.materialize_compressed(src_points, input_radii_buffer);
472 limit_radii(src_positions, angles, input_radii_buffer, cyclic[curve_i], radii);
475 radius_input.materialize_compressed(src_points, radii);
478 calculate_fillet_positions(positions.slice(src_points),
483 dst_positions.slice(dst_points));
485 if (src_curves.has_curve_with_type(CURVE_TYPE_BEZIER)) {
486 if (use_bezier_mode) {
487 calculate_bezier_handles_bezier_mode(src_handles_l.slice(src_points),
488 src_handles_r.slice(src_points),
489 src_types_l.slice(src_points),
490 src_types_r.slice(src_points),
495 dst_positions.slice(dst_points),
496 dst_handles_l.slice(dst_points),
497 dst_handles_r.slice(dst_points),
498 dst_types_l.slice(dst_points),
499 dst_types_r.slice(dst_points));
502 calculate_bezier_handles_poly_mode(src_handles_l.slice(src_points),
503 src_handles_r.slice(src_points),
504 src_types_l.slice(src_points),
505 src_types_r.slice(src_points),
507 dst_positions.slice(dst_points),
508 dst_handles_l.slice(dst_points),
509 dst_handles_r.slice(dst_points),
510 dst_types_l.slice(dst_points),
511 dst_types_r.slice(dst_points));
521 {
"position",
"handle_type_left",
"handle_type_right",
"handle_right",
"handle_left"})) {
523 src_curves, dst_curves, curve_selection, point_offsets,
attribute.src,
attribute.dst.span);
527 if (!unselected_ranges.is_empty()) {
Low-level operations for curves.
Low-level operations for curves.
float angle_v3v3(const float a[3], const float b[3]) ATTR_WARN_UNUSED_RESULT
in reality light always falls off quadratically Particle Retrieve the data of the particle that spawned the object for example to give variation to multiple instances of an object Point Retrieve information about points in a point cloud Retrieve the edges of an object as it appears to Cycles topology will always appear triangulated Convert a blackbody temperature to an RGB value Normal Generate a perturbed normal from an RGB normal map image Typically used for faking highly detailed surfaces Generate an OSL shader from a file or text data block Image Sample an image file as a texture Sky Generate a procedural sky texture Noise Generate fractal Perlin noise Wave Generate procedural bands or rings with noise Voronoi Generate Worley noise based on the distance to random points Typically used to generate textures such as or biological cells Brick Generate a procedural texture producing bricks Texture Retrieve multiple types of texture coordinates nTypically used as inputs for texture nodes Vector Convert a or normal between and object coordinate space Combine Create a color from its and value channels Color Retrieve a color attribute
SIMD_FORCE_INLINE btScalar angle(const btVector3 &v) const
Return the angle between this and another vector.
Span< T > as_span() const
const CPPType & type() const
Vector< IndexRange > extract_ranges_invert(const IndexRange full_range, Vector< int64_t > *r_skip_amounts=nullptr) const
IndexRange index_range() const
constexpr int64_t last(const int64_t n=0) const
constexpr int64_t size() const
constexpr int64_t start() const
constexpr IndexRange drop_front(int64_t n) const
constexpr T & last(const int64_t n=0) const
constexpr T & first() const
constexpr const T & first() const
constexpr const T & last(const int64_t n=0) const
constexpr IndexRange index_range() const
VArray< int8_t > handle_types_left() const
MutableSpan< float3 > positions_for_write()
MutableSpan< int8_t > handle_types_right_for_write()
VArray< int8_t > handle_types_right() const
IndexRange curves_range() const
MutableSpan< float3 > handle_positions_left_for_write()
MutableAttributeAccessor attributes_for_write()
MutableSpan< float3 > handle_positions_right_for_write()
Span< float3 > handle_positions_left() const
Span< int > offsets() const
Span< float3 > positions() const
bool has_curve_with_type(CurveType type) const
void resize(int points_num, int curves_num)
Span< float3 > handle_positions_right() const
AttributeAccessor attributes() const
MutableSpan< int > offsets_for_write()
VArray< bool > cyclic() const
MutableSpan< int8_t > handle_types_left_for_write()
SyclQueue void void * src
INLINE Rall1d< T, V, S > tan(const Rall1d< T, V, S > &arg)
void convert_to_static_type(const CPPType &cpp_type, const Func &func)
void fill_curve_counts(const bke::CurvesGeometry &curves, Span< IndexRange > curve_ranges, MutableSpan< int > counts)
void accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves)
void copy_point_data(const CurvesGeometry &src_curves, const CurvesGeometry &dst_curves, Span< IndexRange > curve_ranges, GSpan src, GMutableSpan dst)
Vector< AttributeTransferData > retrieve_attributes_for_transfer(const bke::AttributeAccessor src_attributes, bke::MutableAttributeAccessor dst_attributes, eAttrDomainMask domain_mask, const Set< std::string > &skip={})
static void calculate_bezier_handles_bezier_mode(const Span< float3 > src_handles_l, const Span< float3 > src_handles_r, const Span< int8_t > src_types_l, const Span< int8_t > src_types_r, const Span< float > angles, const Span< float > radii, const Span< float3 > directions, const Span< int > dst_offsets, const Span< float3 > dst_positions, MutableSpan< float3 > dst_handles_l, MutableSpan< float3 > dst_handles_r, MutableSpan< int8_t > dst_types_l, MutableSpan< int8_t > dst_types_r)
static void calculate_bezier_handles_poly_mode(const Span< float3 > src_handles_l, const Span< float3 > src_handles_r, const Span< int8_t > src_types_l, const Span< int8_t > src_types_r, const Span< int > dst_offsets, const Span< float3 > dst_positions, MutableSpan< float3 > dst_handles_l, MutableSpan< float3 > dst_handles_r, MutableSpan< int8_t > dst_types_l, MutableSpan< int8_t > dst_types_r)
static void calculate_result_offsets(const bke::CurvesGeometry &src_curves, const IndexMask selection, const Span< IndexRange > unselected_ranges, const VArray< float > &radii, const VArray< int > &counts, const Span< bool > cyclic, MutableSpan< int > dst_curve_offsets, MutableSpan< int > dst_point_offsets)
static IndexRange curve_dst_offsets(const IndexRange points, const int curve_index)
static void limit_radii(const Span< float3 > positions, const Span< float > angles, const Span< float > radii, const bool cyclic, MutableSpan< float > radii_clamped)
static void calculate_angles(const Span< float3 > directions, MutableSpan< float > angles)
static float limit_radius(const float3 &position_prev, const float3 &position, const float3 &position_next, const float angle_prev, const float angle, const float angle_next, const float radius_prev, const float radius, const float radius_next)
static bke::CurvesGeometry fillet_curves(const bke::CurvesGeometry &src_curves, const IndexMask curve_selection, const VArray< float > &radius_input, const VArray< int > &counts, const bool limit_radius, const bool use_bezier_mode)
static void threaded_slice_fill(const Span< T > src, const Span< int > offsets, MutableSpan< T > dst)
static void calculate_directions(const Span< float3 > positions, MutableSpan< float3 > directions)
static void calculate_fillet_positions(const Span< float3 > src_positions, const Span< float > angles, const Span< float > radii, const Span< float3 > directions, const Span< int > dst_offsets, MutableSpan< float3 > dst)
bke::CurvesGeometry fillet_curves_bezier(const bke::CurvesGeometry &src_curves, IndexMask curve_selection, const VArray< float > &radius, bool limit_radius)
bke::CurvesGeometry fillet_curves_poly(const bke::CurvesGeometry &src_curves, IndexMask curve_selection, const VArray< float > &radius, const VArray< int > &counts, bool limit_radius)
static void duplicate_fillet_point_data(const bke::CurvesGeometry &src_curves, const bke::CurvesGeometry &dst_curves, const IndexMask selection, const Span< int > point_offsets, const GSpan src, GMutableSpan dst)
T clamp(const T &a, const T &min, const T &max)
T distance(const T &a, const T &b)
vec_base< T, Size > normalize(const vec_base< T, Size > &v)
void parallel_for(IndexRange range, int64_t grain_size, const Function &function)
MutableSpan< float3 > positions
MutableSpan< float > radii