24 const IndexRange src_points = src_points_by_curve[curve_i];
25 const IndexRange dst_points = dst_points_by_curve[curve_i];
30 src.
slice(src_points),
31 dst.
slice(dst_points));
47 const IndexRange src_points = src_points_by_curve[curve_i];
55 for (
int &
count : point_counts) {
59 if (!cyclic[curve_i]) {
61 point_counts.
first() = 1;
62 point_counts.
last() = 1;
67 if (radii[src_points[i]] == 0.0f) {
75 dst_curve_offsets[curve_i] = point_offsets.
last();
103 const float3 &position_next,
104 const float angle_prev,
106 const float angle_next,
107 const float radius_prev,
109 const float radius_next)
111 const float displacement = radius * std::tan(
angle / 2.0f);
113 const float displacement_prev = radius_prev * std::tan(angle_prev / 2.0f);
114 const float segment_length_prev =
math::distance(position, position_prev);
115 const float total_displacement_prev = displacement_prev + displacement;
116 const float factor_prev = std::clamp(
119 const float displacement_next = radius_next * std::tan(angle_next / 2.0f);
120 const float segment_length_next =
math::distance(position, position_next);
121 const float total_displacement_next = displacement_next + displacement;
122 const float factor_next = std::clamp(
125 return radius * std::min(factor_prev, factor_next);
147 const int i_prev = i - 1;
148 const int i_next = i + 1;
173 radii_clamped.
first() = 0.0f;
176 const int i_prev = i - 1;
177 const int i_next = i + 1;
180 const float radius_prev = i_prev == 0 ? 0.0f : radii[i_prev];
181 const float radius_next = i_next == i_last ? 0.0f : radii[i_next];
193 radii_clamped.
last() = 0.0f;
206 for (const int i_src : range) {
207 const IndexRange arc = dst_offsets[i_src];
208 const float3 &src = src_positions[i_src];
209 if (arc.size() == 1) {
210 dst[arc.first()] = src;
214 const int i_src_prev = i_src == 0 ? i_src_last : i_src - 1;
215 const float angle = angles[i_src];
216 const float radius = radii[i_src];
217 const float displacement = radius * std::tan(angle / 2.0f);
218 const float3 prev_dir = -directions[i_src_prev];
219 const float3 &next_dir = directions[i_src];
220 const float3 arc_start = src + prev_dir * displacement;
221 const float3 arc_end = src + next_dir * displacement;
223 dst[arc.first()] = arc_start;
224 dst[arc.last()] = arc_end;
226 const IndexRange middle = arc.drop_front(1).drop_back(1);
227 if (middle.is_empty()) {
231 const float3 axis = -math::normalize(math::cross(prev_dir, next_dir));
232 const float3 center_direction = math::normalize(math::midpoint(next_dir, prev_dir));
233 const float distance_to_center = std::sqrt(pow2f(radius) + pow2f(displacement));
234 const float3 center = src + center_direction * distance_to_center;
237 const float segment_angle = angle / (middle.size() + 1);
238 for (const int i : IndexRange(middle.size())) {
239 const int point_i = middle[i];
240 dst[point_i] = math::rotate_around_axis(arc_start, center, axis, segment_angle * (i + 1));
268 for (const int i_src : range) {
269 const IndexRange arc = dst_offsets[i_src];
270 if (arc.size() == 1) {
271 dst_handles_l[arc.first()] = src_handles_l[i_src];
272 dst_handles_r[arc.first()] = src_handles_r[i_src];
273 dst_types_l[arc.first()] = src_types_l[i_src];
274 dst_types_r[arc.first()] = src_types_r[i_src];
277 BLI_assert(arc.size() == 2);
278 const int i_dst_a = arc.first();
279 const int i_dst_b = arc.last();
281 const int i_src_prev = i_src == 0 ? i_src_last : i_src - 1;
282 const float angle = angles[i_src];
283 const float radius = radii[i_src];
284 const float3 prev_dir = -directions[i_src_prev];
285 const float3 &next_dir = directions[i_src];
287 const float3 &arc_start = dst_positions[arc.first()];
288 const float3 &arc_end = dst_positions[arc.last()];
292 const int i_dst_prev = i_dst_a == 0 ? i_dst_last : i_dst_a - 1;
293 const int i_dst_next = i_dst_b == i_dst_last ? 0 : i_dst_b + 1;
294 dst_handles_l[i_dst_a] = bke::curves::bezier::calculate_vector_handle(
295 dst_positions[i_dst_a], dst_positions[i_dst_prev]);
296 dst_handles_r[i_dst_b] = bke::curves::bezier::calculate_vector_handle(
297 dst_positions[i_dst_b], dst_positions[i_dst_next]);
298 dst_types_l[i_dst_a] = BEZIER_HANDLE_VECTOR;
299 dst_types_r[i_dst_b] = BEZIER_HANDLE_VECTOR;
303 const float handle_length = (4.0f / 3.0f) * radius * std::tan(angle / 4.0f);
304 dst_handles_r[i_dst_a] = arc_start - prev_dir * handle_length;
305 dst_handles_l[i_dst_b] = arc_end - next_dir * handle_length;
306 dst_types_r[i_dst_a] = BEZIER_HANDLE_ALIGN;
307 dst_types_l[i_dst_b] = BEZIER_HANDLE_ALIGN;
329 for (const int i_src : range) {
330 const IndexRange arc = dst_offsets[i_src];
331 if (arc.size() == 1) {
332 dst_handles_l[arc.first()] = src_handles_l[i_src];
333 dst_handles_r[arc.first()] = src_handles_r[i_src];
334 dst_types_l[arc.first()] = src_types_l[i_src];
335 dst_types_r[arc.first()] = src_types_r[i_src];
340 dst_types_l.slice(arc).fill(BEZIER_HANDLE_VECTOR);
341 dst_types_r.slice(arc).fill(BEZIER_HANDLE_VECTOR);
346 const int i_dst_prev = arc.first() == 0 ? i_dst_last : arc.one_before_start();
347 const int i_dst_next = arc.last() == i_dst_last ? 0 : arc.one_after_last();
348 dst_handles_l[arc.first()] = bke::curves::bezier::calculate_vector_handle(
349 dst_positions[arc.first()], dst_positions[i_dst_prev]);
350 dst_handles_r[arc.last()] = bke::curves::bezier::calculate_vector_handle(
351 dst_positions[arc.last()], dst_positions[i_dst_next]);
354 const IndexRange middle = arc.drop_front(1).drop_back(1);
355 for (const int i : middle) {
356 dst_handles_r[i] = bke::curves::bezier::calculate_vector_handle(dst_positions[i],
357 dst_positions[i - 1]);
358 dst_handles_l[i] = bke::curves::bezier::calculate_vector_handle(dst_positions[i],
359 dst_positions[i + 1]);
370 const bool use_bezier_mode,
425 for (
const int curve_i : segment) {
426 const IndexRange src_points = src_points_by_curve[curve_i];
430 const IndexRange dst_points = dst_points_by_curve[curve_i];
443 limit_radii(src_positions, angles, input_radii_buffer, cyclic[curve_i], radii);
454 dst_positions.
slice(dst_points));
457 if (use_bezier_mode) {
459 src_handles_r.
slice(src_points),
460 src_types_l.
slice(src_points),
461 src_types_r.
slice(src_points),
466 dst_positions.
slice(dst_points),
467 dst_handles_l.
slice(dst_points),
468 dst_handles_r.
slice(dst_points),
469 dst_types_l.
slice(dst_points),
470 dst_types_r.
slice(dst_points));
474 src_handles_r.
slice(src_points),
475 src_types_l.
slice(src_points),
476 src_types_r.
slice(src_points),
478 dst_positions.
slice(dst_points),
479 dst_handles_l.
slice(dst_points),
480 dst_handles_r.
slice(dst_points),
481 dst_types_l.
slice(dst_points),
482 dst_types_r.
slice(dst_points));
528 src_curves, curve_selection, radius,
count,
limit_radius,
false, attribute_filter);
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
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
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 Gabor Generate Gabor noise Gradient Generate interpolated color and intensity values based on the input vector Magic Generate a psychedelic color texture 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
constexpr const T & last(const int64_t n=0) const
Span< T > as_span() const
void reinitialize(const int64_t new_size)
GMutableSpan slice(const int64_t start, int64_t size) const
GSpan slice(const int64_t start, int64_t size) const
constexpr IndexRange drop_back(int64_t n) const
constexpr int64_t last(const int64_t n=0) const
constexpr int64_t size() const
constexpr IndexRange drop_front(int64_t n) const
constexpr MutableSpan slice(const int64_t start, const int64_t size) const
constexpr MutableSpan drop_back(const int64_t n) const
constexpr T & first() const
constexpr T & last(const int64_t n=0) const
constexpr Span slice(int64_t start, int64_t size) const
constexpr const T & first() const
constexpr const T & last(const int64_t n=0) const
constexpr IndexRange index_range() const
void materialize_compressed(const IndexMask &mask, MutableSpan< T > r_span) const
static VArray ForSingle(T value, const int64_t size)
VArray< int8_t > handle_types_left() const
MutableSpan< float3 > positions_for_write()
OffsetIndices< int > points_by_curve() const
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()
IndexMask complement(const IndexMask &universe, IndexMaskMemory &memory) const
void foreach_index(Fn &&fn) const
void foreach_segment(Fn &&fn) const
void gather_to_groups(OffsetIndices< int > dst_offsets, const IndexMask &src_selection, GSpan src, GMutableSpan dst)
bke::CurvesGeometry copy_only_curve_domain(const bke::CurvesGeometry &src_curves)
IndexRange per_curve_point_offsets_range(const IndexRange points, const int curve_index)
Vector< AttributeTransferData > retrieve_attributes_for_transfer(const AttributeAccessor src_attributes, MutableAttributeAccessor dst_attributes, AttrDomainMask domain_mask, const AttributeFilter &attribute_filter={})
auto attribute_filter_with_skip_ref(AttributeFilter filter, const Span< StringRef > skip)
void copy_attributes_group_to_group(AttributeAccessor src_attributes, AttrDomain src_domain, AttrDomain dst_domain, const AttributeFilter &attribute_filter, OffsetIndices< int > src_offsets, OffsetIndices< int > dst_offsets, const IndexMask &selection, MutableAttributeAccessor dst_attributes)
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 OffsetIndices< 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)
bke::CurvesGeometry fillet_curves_bezier(const bke::CurvesGeometry &src_curves, const IndexMask &curve_selection, const VArray< float > &radius, bool limit_radius, const bke::AttributeFilter &attribute_filter)
static void calculate_result_offsets(const OffsetIndices< int > src_points_by_curve, const IndexMask &selection, const IndexMask &unselected, const VArray< float > &radii, const VArray< int > &counts, const Span< bool > cyclic, MutableSpan< int > dst_curve_offsets, MutableSpan< int > dst_point_offsets)
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)
bke::CurvesGeometry fillet_curves_poly(const bke::CurvesGeometry &src_curves, const IndexMask &curve_selection, const VArray< float > &radius, const VArray< int > &counts, bool limit_radius, const bke::AttributeFilter &attribute_filter)
static void calculate_fillet_positions(const Span< float3 > src_positions, const Span< float > angles, const Span< float > radii, const Span< float3 > directions, const OffsetIndices< int > dst_offsets, MutableSpan< float3 > dst)
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, const bke::AttributeFilter &attribute_filter)
static void calculate_directions(const Span< float3 > positions, MutableSpan< float3 > directions)
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 OffsetIndices< 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 duplicate_fillet_point_data(const OffsetIndices< int > src_points_by_curve, const OffsetIndices< int > dst_points_by_curve, const IndexMask &curve_selection, const Span< int > all_point_offsets, const GSpan src, GMutableSpan dst)
T safe_divide(const T &a, const T &b)
T distance(const T &a, const T &b)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
void copy_group_sizes(OffsetIndices< int > offsets, const IndexMask &mask, MutableSpan< int > sizes)
OffsetIndices< int > accumulate_counts_to_offsets(MutableSpan< int > counts_to_offsets, int start_offset=0)
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)
VecBase< float, 3 > float3
GPU_SHADER_INTERFACE_INFO(overlay_edit_curve_handle_iface, "vert").flat(Type pos vertex_in(1, Type::UINT, "data") .vertex_out(overlay_edit_curve_handle_iface) .geometry_layout(PrimitiveIn Frequency::GEOMETRY storage_buf(1, Qualifier::READ, "uint", "data[]", Frequency::GEOMETRY) .push_constant(Type Frequency::GEOMETRY selection[]