Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/geometry')
-rw-r--r--source/blender/geometry/CMakeLists.txt2
-rw-r--r--source/blender/geometry/GEO_resample_curves.hh15
-rw-r--r--source/blender/geometry/GEO_trim_curves.hh24
-rw-r--r--source/blender/geometry/intern/add_curves_on_mesh.cc9
-rw-r--r--source/blender/geometry/intern/fillet_curves.cc6
-rw-r--r--source/blender/geometry/intern/mesh_merge_by_distance.cc33
-rw-r--r--source/blender/geometry/intern/mesh_primitive_cuboid.cc6
-rw-r--r--source/blender/geometry/intern/mesh_to_curve_convert.cc16
-rw-r--r--source/blender/geometry/intern/mesh_to_volume.cc14
-rw-r--r--source/blender/geometry/intern/realize_instances.cc84
-rw-r--r--source/blender/geometry/intern/resample_curves.cc186
-rw-r--r--source/blender/geometry/intern/set_curve_type.cc13
-rw-r--r--source/blender/geometry/intern/trim_curves.cc1031
-rw-r--r--source/blender/geometry/intern/uv_parametrizer.cc44
14 files changed, 1297 insertions, 186 deletions
diff --git a/source/blender/geometry/CMakeLists.txt b/source/blender/geometry/CMakeLists.txt
index 0f06890cbfa..9e1929b60a8 100644
--- a/source/blender/geometry/CMakeLists.txt
+++ b/source/blender/geometry/CMakeLists.txt
@@ -27,6 +27,7 @@ set(SRC
intern/reverse_uv_sampler.cc
intern/set_curve_type.cc
intern/subdivide_curves.cc
+ intern/trim_curves.cc
intern/uv_parametrizer.cc
GEO_add_curves_on_mesh.hh
@@ -41,6 +42,7 @@ set(SRC
GEO_reverse_uv_sampler.hh
GEO_set_curve_type.hh
GEO_subdivide_curves.hh
+ GEO_trim_curves.hh
GEO_uv_parametrizer.h
)
diff --git a/source/blender/geometry/GEO_resample_curves.hh b/source/blender/geometry/GEO_resample_curves.hh
index 7ecfb5c26ec..35365167eba 100644
--- a/source/blender/geometry/GEO_resample_curves.hh
+++ b/source/blender/geometry/GEO_resample_curves.hh
@@ -4,12 +4,18 @@
#include "FN_field.hh"
+#include "BKE_anonymous_attribute.hh"
#include "BKE_curves.hh"
namespace blender::geometry {
using bke::CurvesGeometry;
+struct ResampleCurvesOutputAttributeIDs {
+ bke::AttributeIDRef tangent_id;
+ bke::AttributeIDRef normal_id;
+};
+
/**
* Create new curves where the selected curves have been resampled with a number of uniform-length
* samples defined by the count field. Interpolate attributes to the result, with an accuracy that
@@ -19,7 +25,8 @@ using bke::CurvesGeometry;
*/
CurvesGeometry resample_to_count(const CurvesGeometry &src_curves,
const fn::Field<bool> &selection_field,
- const fn::Field<int> &count_field);
+ const fn::Field<int> &count_field,
+ const ResampleCurvesOutputAttributeIDs &output_ids = {});
/**
* Create new curves resampled to make each segment have the length specified by the
@@ -28,12 +35,14 @@ CurvesGeometry resample_to_count(const CurvesGeometry &src_curves,
*/
CurvesGeometry resample_to_length(const CurvesGeometry &src_curves,
const fn::Field<bool> &selection_field,
- const fn::Field<float> &segment_length_field);
+ const fn::Field<float> &segment_length_field,
+ const ResampleCurvesOutputAttributeIDs &output_ids = {});
/**
* Evaluate each selected curve to its implicit evaluated points.
*/
CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
- const fn::Field<bool> &selection_field);
+ const fn::Field<bool> &selection_field,
+ const ResampleCurvesOutputAttributeIDs &output_ids = {});
} // namespace blender::geometry
diff --git a/source/blender/geometry/GEO_trim_curves.hh b/source/blender/geometry/GEO_trim_curves.hh
new file mode 100644
index 00000000000..197ef79c25b
--- /dev/null
+++ b/source/blender/geometry/GEO_trim_curves.hh
@@ -0,0 +1,24 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+#pragma once
+
+#include "BLI_span.hh"
+#include "DNA_node_types.h"
+
+#include "BKE_curves.hh"
+#include "BKE_curves_utils.hh"
+#include "BKE_geometry_set.hh"
+
+namespace blender::geometry {
+
+/*
+ * Create a new Curves instance by trimming the input curves. Copying the selected splines
+ * between the start and end points.
+ */
+bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves,
+ IndexMask selection,
+ const VArray<float> &starts,
+ const VArray<float> &ends,
+ GeometryNodeCurveSampleMode mode);
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/add_curves_on_mesh.cc b/source/blender/geometry/intern/add_curves_on_mesh.cc
index bb5e2a0a28a..a03c9b994a9 100644
--- a/source/blender/geometry/intern/add_curves_on_mesh.cc
+++ b/source/blender/geometry/intern/add_curves_on_mesh.cc
@@ -51,7 +51,7 @@ static void initialize_straight_curve_positions(const float3 &p1,
const float3 &p2,
MutableSpan<float3> r_positions)
{
- const float step = 1.0f / (float)(r_positions.size() - 1);
+ const float step = 1.0f / float(r_positions.size() - 1);
for (const int i : r_positions.index_range()) {
r_positions[i] = math::interpolate(p1, p2, i * step);
}
@@ -385,10 +385,11 @@ AddCurvesOnMeshOutputs add_curves_on_mesh(CurvesGeometry &curves,
return true;
}
bke::GSpanAttributeWriter attribute = attributes.lookup_for_write_span(id);
- const int new_elements_num = attribute.domain == ATTR_DOMAIN_POINT ? new_points_num :
- new_curves_num;
+ /* The new elements are added at the end of the array. */
+ const int old_elements_num = attribute.domain == ATTR_DOMAIN_POINT ? old_points_num :
+ old_curves_num;
const CPPType &type = attribute.span.type();
- GMutableSpan new_data = attribute.span.take_back(new_elements_num);
+ GMutableSpan new_data = attribute.span.drop_front(old_elements_num);
type.fill_assign_n(type.default_value(), new_data.data(), new_data.size());
attribute.finish();
return true;
diff --git a/source/blender/geometry/intern/fillet_curves.cc b/source/blender/geometry/intern/fillet_curves.cc
index 1bbbee6edef..2479458f88d 100644
--- a/source/blender/geometry/intern/fillet_curves.cc
+++ b/source/blender/geometry/intern/fillet_curves.cc
@@ -148,12 +148,14 @@ static float limit_radius(const float3 &position_prev,
const float displacement_prev = radius_prev * std::tan(angle_prev / 2.0f);
const float segment_length_prev = math::distance(position, position_prev);
const float total_displacement_prev = displacement_prev + displacement;
- const float factor_prev = std::clamp(segment_length_prev / total_displacement_prev, 0.0f, 1.0f);
+ const float factor_prev = std::clamp(
+ safe_divide(segment_length_prev, total_displacement_prev), 0.0f, 1.0f);
const float displacement_next = radius_next * std::tan(angle_next / 2.0f);
const float segment_length_next = math::distance(position, position_next);
const float total_displacement_next = displacement_next + displacement;
- const float factor_next = std::clamp(segment_length_next / total_displacement_next, 0.0f, 1.0f);
+ const float factor_next = std::clamp(
+ safe_divide(segment_length_next, total_displacement_next), 0.0f, 1.0f);
return radius * std::min(factor_prev, factor_next);
}
diff --git a/source/blender/geometry/intern/mesh_merge_by_distance.cc b/source/blender/geometry/intern/mesh_merge_by_distance.cc
index 17318c277aa..288fd407641 100644
--- a/source/blender/geometry/intern/mesh_merge_by_distance.cc
+++ b/source/blender/geometry/intern/mesh_merge_by_distance.cc
@@ -21,11 +21,11 @@
namespace blender::geometry {
/* Indicates when the element was not computed. */
-#define OUT_OF_CONTEXT (int)(-1)
+#define OUT_OF_CONTEXT int(-1)
/* Indicates if the edge or face will be collapsed. */
-#define ELEM_COLLAPSED (int)(-2)
+#define ELEM_COLLAPSED int(-2)
/* indicates whether an edge or vertex in groups_map will be merged. */
-#define ELEM_MERGED (int)(-2)
+#define ELEM_MERGED int(-2)
/* Used to indicate a range in an array specifying a group. */
struct WeldGroup {
@@ -702,7 +702,7 @@ static bool weld_iter_loop_of_poly_next(WeldLoopOfPolyIter &iter)
else {
const MLoop &ml = iter.mloop[l];
#ifdef USE_WELD_DEBUG
- BLI_assert((uint)iter.v != ml.v);
+ BLI_assert(uint(iter.v) != ml.v);
#endif
iter.v = ml.v;
iter.e = ml.e;
@@ -1232,7 +1232,6 @@ static void customdata_weld(
#ifdef USE_WELD_NORMALS
float no[3] = {0.0f, 0.0f, 0.0f};
#endif
- int crease = 0;
short flag = 0;
/* interpolates a layer at a time */
@@ -1266,13 +1265,11 @@ static void customdata_weld(
no[1] += mv_src_no[1];
no[2] += mv_src_no[2];
#endif
- flag |= mv_src->flag;
}
}
else if (type == CD_MEDGE) {
for (j = 0; j < count; j++) {
MEdge *me_src = &((MEdge *)src_data)[src_indices[j]];
- crease += me_src->crease;
flag |= me_src->flag;
}
}
@@ -1283,10 +1280,10 @@ static void customdata_weld(
else if (CustomData_layer_has_math(dest, dest_i)) {
const int size = CustomData_sizeof(type);
void *dst_data = dest->layers[dest_i].data;
- void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size);
+ void *v_dst = POINTER_OFFSET(dst_data, size_t(dest_index) * size);
for (j = 0; j < count; j++) {
CustomData_data_add(
- type, v_dst, POINTER_OFFSET(src_data, (size_t)src_indices[j] * size));
+ type, v_dst, POINTER_OFFSET(src_data, size_t(src_indices[j]) * size));
}
}
else {
@@ -1314,19 +1311,13 @@ static void customdata_weld(
#ifdef USE_WELD_NORMALS
mul_v3_fl(no, fac);
short *mv_no = mv->no;
- mv_no[0] = (short)no[0];
- mv_no[1] = (short)no[1];
- mv_no[2] = (short)no[2];
+ mv_no[0] = short(no[0]);
+ mv_no[1] = short(no[1]);
+ mv_no[2] = short(no[2]);
#endif
-
- mv->flag = (char)flag;
}
else if (type == CD_MEDGE) {
MEdge *me = &((MEdge *)layer_dst->data)[dest_index];
- crease *= fac;
- CLAMP_MAX(crease, 255);
-
- me->crease = (char)crease;
me->flag = flag;
}
else if (CustomData_layer_has_interp(dest, dest_i)) {
@@ -1335,7 +1326,7 @@ static void customdata_weld(
else if (CustomData_layer_has_math(dest, dest_i)) {
const int size = CustomData_sizeof(type);
void *dst_data = layer_dst->data;
- void *v_dst = POINTER_OFFSET(dst_data, (size_t)dest_index * size);
+ void *v_dst = POINTER_OFFSET(dst_data, size_t(dest_index) * size);
CustomData_data_multiply(type, v_dst, fac);
}
}
@@ -1541,7 +1532,7 @@ static Mesh *create_merged_mesh(const Mesh &mesh,
r_i++;
}
- BLI_assert((int)r_i == result_npolys);
+ BLI_assert(int(r_i) == result_npolys);
BLI_assert(loop_cur == result_nloops);
return result;
@@ -1639,7 +1630,7 @@ std::optional<Mesh *> mesh_merge_by_distance_connected(const Mesh &mesh,
const float dist_sq = len_squared_v3(edgedir);
if (dist_sq <= merge_dist_sq) {
float influence = (v2_cluster->merged_verts + 1) /
- (float)(v1_cluster->merged_verts + v2_cluster->merged_verts + 2);
+ float(v1_cluster->merged_verts + v2_cluster->merged_verts + 2);
madd_v3_v3fl(v1_cluster->co, edgedir, influence);
v1_cluster->merged_verts += v2_cluster->merged_verts + 1;
diff --git a/source/blender/geometry/intern/mesh_primitive_cuboid.cc b/source/blender/geometry/intern/mesh_primitive_cuboid.cc
index 39571f2931e..a014c488a3b 100644
--- a/source/blender/geometry/intern/mesh_primitive_cuboid.cc
+++ b/source/blender/geometry/intern/mesh_primitive_cuboid.cc
@@ -328,9 +328,9 @@ static void calculate_uvs(const CuboidConfig &config, Mesh *mesh, const bke::Att
int loop_index = 0;
- const float x_delta = 0.25f / static_cast<float>(config.edges_x);
- const float y_delta = 0.25f / static_cast<float>(config.edges_y);
- const float z_delta = 0.25f / static_cast<float>(config.edges_z);
+ const float x_delta = 0.25f / float(config.edges_x);
+ const float y_delta = 0.25f / float(config.edges_y);
+ const float z_delta = 0.25f / float(config.edges_z);
/* Calculate bottom face UVs. */
for (const int y : IndexRange(config.edges_y)) {
diff --git a/source/blender/geometry/intern/mesh_to_curve_convert.cc b/source/blender/geometry/intern/mesh_to_curve_convert.cc
index 22961504015..c2a9b16c8b6 100644
--- a/source/blender/geometry/intern/mesh_to_curve_convert.cc
+++ b/source/blender/geometry/intern/mesh_to_curve_convert.cc
@@ -1,6 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-or-later */
#include "BLI_array.hh"
+#include "BLI_array_utils.hh"
#include "BLI_devirtualize_parameters.hh"
#include "BLI_set.hh"
#include "BLI_task.hh"
@@ -18,19 +19,6 @@
namespace blender::geometry {
-template<typename T>
-static void copy_with_map(const VArray<T> &src, Span<int> map, MutableSpan<T> dst)
-{
- devirtualize_varray(src, [&](const auto &src) {
- threading::parallel_for(map.index_range(), 1024, [&](const IndexRange range) {
- for (const int i : range) {
- const int vert_index = map[i];
- dst[i] = src[vert_index];
- }
- });
- });
-}
-
bke::CurvesGeometry create_curve_from_vert_indices(const Mesh &mesh,
const Span<int> vert_indices,
const Span<int> curve_offsets,
@@ -71,7 +59,7 @@ bke::CurvesGeometry create_curve_from_vert_indices(const Mesh &mesh,
using T = decltype(dummy);
bke::SpanAttributeWriter<T> attribute =
curves_attributes.lookup_or_add_for_write_only_span<T>(attribute_id, ATTR_DOMAIN_POINT);
- copy_with_map<T>(mesh_attribute.typed<T>(), vert_indices, attribute.span);
+ array_utils::gather<T>(mesh_attribute.typed<T>(), vert_indices, attribute.span);
attribute.finish();
});
}
diff --git a/source/blender/geometry/intern/mesh_to_volume.cc b/source/blender/geometry/intern/mesh_to_volume.cc
index b1c7be38609..b6025f8f1a9 100644
--- a/source/blender/geometry/intern/mesh_to_volume.cc
+++ b/source/blender/geometry/intern/mesh_to_volume.cc
@@ -25,30 +25,26 @@ class OpenVDBMeshAdapter {
OpenVDBMeshAdapter(const Mesh &mesh, float4x4 transform);
size_t polygonCount() const;
size_t pointCount() const;
- size_t vertexCount(size_t UNUSED(polygon_index)) const;
+ size_t vertexCount(size_t /*polygon_index*/) const;
void getIndexSpacePoint(size_t polygon_index, size_t vertex_index, openvdb::Vec3d &pos) const;
};
OpenVDBMeshAdapter::OpenVDBMeshAdapter(const Mesh &mesh, float4x4 transform)
- : verts_(mesh.verts()), loops_(mesh.loops()), transform_(transform)
+ : verts_(mesh.verts()), loops_(mesh.loops()), looptris_(mesh.looptris()), transform_(transform)
{
- /* This only updates a cache and can be considered to be logically const. */
- const MLoopTri *looptris = BKE_mesh_runtime_looptri_ensure(&mesh);
- const int looptris_len = BKE_mesh_runtime_looptri_len(&mesh);
- looptris_ = Span(looptris, looptris_len);
}
size_t OpenVDBMeshAdapter::polygonCount() const
{
- return static_cast<size_t>(looptris_.size());
+ return size_t(looptris_.size());
}
size_t OpenVDBMeshAdapter::pointCount() const
{
- return static_cast<size_t>(verts_.size());
+ return size_t(verts_.size());
}
-size_t OpenVDBMeshAdapter::vertexCount(size_t UNUSED(polygon_index)) const
+size_t OpenVDBMeshAdapter::vertexCount(size_t /*polygon_index*/) const
{
/* All polygons are triangles. */
return 3;
diff --git a/source/blender/geometry/intern/realize_instances.cc b/source/blender/geometry/intern/realize_instances.cc
index 29a9f51c0a7..2d9c23df348 100644
--- a/source/blender/geometry/intern/realize_instances.cc
+++ b/source/blender/geometry/intern/realize_instances.cc
@@ -17,6 +17,7 @@
#include "BKE_curves.hh"
#include "BKE_deform.h"
#include "BKE_geometry_set_instances.hh"
+#include "BKE_instances.hh"
#include "BKE_material.h"
#include "BKE_mesh.h"
#include "BKE_pointcloud.h"
@@ -30,6 +31,8 @@ using blender::bke::AttributeMetaData;
using blender::bke::custom_data_type_to_cpp_type;
using blender::bke::CustomDataAttributes;
using blender::bke::GSpanAttributeWriter;
+using blender::bke::InstanceReference;
+using blender::bke::Instances;
using blender::bke::object_get_evaluated_geometry_set;
using blender::bke::SpanAttributeWriter;
@@ -370,11 +373,11 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
*/
static Vector<std::pair<int, GSpan>> prepare_attribute_fallbacks(
GatherTasksInfo &gather_info,
- const InstancesComponent &instances_component,
+ const Instances &instances,
const OrderedAttributes &ordered_attributes)
{
Vector<std::pair<int, GSpan>> attributes_to_override;
- const CustomDataAttributes &attributes = instances_component.instance_attributes();
+ const CustomDataAttributes &attributes = instances.custom_data_attributes();
attributes.foreach_attribute(
[&](const AttributeIDRef &attribute_id, const AttributeMetaData &meta_data) {
const int attribute_index = ordered_attributes.ids.index_of_try(attribute_id);
@@ -394,7 +397,7 @@ static Vector<std::pair<int, GSpan>> prepare_attribute_fallbacks(
}
/* Convert the attribute on the instances component to the expected attribute type. */
std::unique_ptr<GArray<>> temporary_array = std::make_unique<GArray<>>(
- to_type, instances_component.instances_num());
+ to_type, instances.instances_num());
conversions.convert_to_initialized_n(span, temporary_array->as_mutable_span());
span = temporary_array->as_span();
gather_info.r_temporary_arrays.append(std::move(temporary_array));
@@ -430,7 +433,7 @@ static void foreach_geometry_in_reference(
int index = 0;
FOREACH_COLLECTION_OBJECT_RECURSIVE_BEGIN (&collection, object) {
const GeometrySet object_geometry_set = object_get_evaluated_geometry_set(*object);
- const float4x4 matrix = base_transform * offset_matrix * object->obmat;
+ const float4x4 matrix = base_transform * offset_matrix * object->object_to_world;
const int sub_id = noise::hash(id, index);
fn(object_geometry_set, matrix, sub_id);
index++;
@@ -450,17 +453,17 @@ static void foreach_geometry_in_reference(
}
static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info,
- const InstancesComponent &instances_component,
+ const Instances &instances,
const float4x4 &base_transform,
const InstanceContext &base_instance_context)
{
- const Span<InstanceReference> references = instances_component.references();
- const Span<int> handles = instances_component.instance_reference_handles();
- const Span<float4x4> transforms = instances_component.instance_transforms();
+ const Span<InstanceReference> references = instances.references();
+ const Span<int> handles = instances.reference_handles();
+ const Span<float4x4> transforms = instances.transforms();
Span<int> stored_instance_ids;
if (gather_info.create_id_attribute_on_any_component) {
- std::optional<GSpan> ids = instances_component.instance_attributes().get_for_read("id");
+ std::optional<GSpan> ids = instances.custom_data_attributes().get_for_read("id");
if (ids.has_value()) {
stored_instance_ids = ids->typed<int>();
}
@@ -469,11 +472,11 @@ static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info,
/* Prepare attribute fallbacks. */
InstanceContext instance_context = base_instance_context;
Vector<std::pair<int, GSpan>> pointcloud_attributes_to_override = prepare_attribute_fallbacks(
- gather_info, instances_component, gather_info.pointclouds.attributes);
+ gather_info, instances, gather_info.pointclouds.attributes);
Vector<std::pair<int, GSpan>> mesh_attributes_to_override = prepare_attribute_fallbacks(
- gather_info, instances_component, gather_info.meshes.attributes);
+ gather_info, instances, gather_info.meshes.attributes);
Vector<std::pair<int, GSpan>> curve_attributes_to_override = prepare_attribute_fallbacks(
- gather_info, instances_component, gather_info.curves.attributes);
+ gather_info, instances, gather_info.curves.attributes);
for (const int i : transforms.index_range()) {
const int handle = handles[i];
@@ -495,10 +498,10 @@ static void gather_realize_tasks_for_instances(GatherTasksInfo &gather_info,
uint32_t local_instance_id = 0;
if (gather_info.create_id_attribute_on_any_component) {
if (stored_instance_ids.is_empty()) {
- local_instance_id = (uint32_t)i;
+ local_instance_id = uint32_t(i);
}
else {
- local_instance_id = (uint32_t)stored_instance_ids[i];
+ local_instance_id = uint32_t(stored_instance_ids[i]);
}
}
const uint32_t instance_id = noise::hash(base_instance_context.id, local_instance_id);
@@ -584,8 +587,11 @@ static void gather_realize_tasks_recursive(GatherTasksInfo &gather_info,
case GEO_COMPONENT_TYPE_INSTANCES: {
const InstancesComponent &instances_component = *static_cast<const InstancesComponent *>(
component);
- gather_realize_tasks_for_instances(
- gather_info, instances_component, base_transform, base_instance_context);
+ const Instances *instances = instances_component.get_for_read();
+ if (instances != nullptr && instances->instances_num() > 0) {
+ gather_realize_tasks_for_instances(
+ gather_info, *instances, base_transform, base_instance_context);
+ }
break;
}
case GEO_COMPONENT_TYPE_VOLUME: {
@@ -645,8 +651,7 @@ static void gather_pointclouds_to_realize(const GeometrySet &geometry_set,
r_pointclouds.add(pointcloud);
}
}
- if (const InstancesComponent *instances =
- geometry_set.get_component_for_read<InstancesComponent>()) {
+ if (const Instances *instances = geometry_set.get_instances_for_read()) {
instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
gather_pointclouds_to_realize(instance_geometry_set, r_pointclouds);
});
@@ -782,9 +787,7 @@ static void execute_realize_pointcloud_tasks(const RealizeInstancesOptions &opti
dst_attribute.finish();
}
positions.finish();
- if (point_ids) {
- point_ids.finish();
- }
+ point_ids.finish();
}
/** \} */
@@ -811,7 +814,6 @@ static OrderedAttributes gather_generic_mesh_attributes_to_propagate(
attributes_to_propagate.remove("position");
attributes_to_propagate.remove("normal");
attributes_to_propagate.remove("shade_smooth");
- attributes_to_propagate.remove("crease");
r_create_id = attributes_to_propagate.pop_try("id").has_value();
r_create_material_index = attributes_to_propagate.pop_try("material_index").has_value();
OrderedAttributes ordered_attributes;
@@ -830,8 +832,7 @@ static void gather_meshes_to_realize(const GeometrySet &geometry_set,
r_meshes.add(mesh);
}
}
- if (const InstancesComponent *instances =
- geometry_set.get_component_for_read<InstancesComponent>()) {
+ if (const Instances *instances = geometry_set.get_instances_for_read()) {
instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
gather_meshes_to_realize(instance_geometry_set, r_meshes);
});
@@ -858,6 +859,7 @@ static AllMeshesInfo preprocess_meshes(const GeometrySet &geometry_set,
}
}
}
+ info.create_material_index_attribute |= info.materials.size() > 1;
info.realize_info.reinitialize(info.order.size());
for (const int mesh_index : info.realize_info.index_range()) {
MeshRealizeInfo &mesh_info = info.realize_info[mesh_index];
@@ -1107,12 +1109,8 @@ static void execute_realize_mesh_tasks(const RealizeInstancesOptions &options,
for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
dst_attribute.finish();
}
- if (vertex_ids) {
- vertex_ids.finish();
- }
- if (material_indices) {
- material_indices.finish();
- }
+ vertex_ids.finish();
+ material_indices.finish();
}
/** \} */
@@ -1155,8 +1153,7 @@ static void gather_curves_to_realize(const GeometrySet &geometry_set,
r_curves.add(curves);
}
}
- if (const InstancesComponent *instances =
- geometry_set.get_component_for_read<InstancesComponent>()) {
+ if (const Instances *instances = geometry_set.get_instances_for_read()) {
instances->foreach_referenced_geometry([&](const GeometrySet &instance_geometry_set) {
gather_curves_to_realize(instance_geometry_set, r_curves);
});
@@ -1406,19 +1403,11 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
for (GSpanAttributeWriter &dst_attribute : dst_attribute_writers) {
dst_attribute.finish();
}
- if (point_ids) {
- point_ids.finish();
- }
- if (radius) {
- radius.finish();
- }
- if (resolution) {
- resolution.finish();
- }
- if (all_curves_info.create_handle_postion_attributes) {
- handle_left.finish();
- handle_right.finish();
- }
+ point_ids.finish();
+ radius.finish();
+ resolution.finish();
+ handle_left.finish();
+ handle_right.finish();
}
/** \} */
@@ -1430,9 +1419,8 @@ static void execute_realize_curve_tasks(const RealizeInstancesOptions &options,
static void remove_id_attribute_from_instances(GeometrySet &geometry_set)
{
geometry_set.modify_geometry_sets([&](GeometrySet &sub_geometry) {
- if (sub_geometry.has<InstancesComponent>()) {
- InstancesComponent &component = sub_geometry.get_component_for_write<InstancesComponent>();
- component.instance_attributes().remove("id");
+ if (Instances *instances = sub_geometry.get_instances_for_write()) {
+ instances->custom_data_attributes().remove("id");
}
});
}
diff --git a/source/blender/geometry/intern/resample_curves.cc b/source/blender/geometry/intern/resample_curves.cc
index d5560a95a18..3be850ec097 100644
--- a/source/blender/geometry/intern/resample_curves.cc
+++ b/source/blender/geometry/intern/resample_curves.cc
@@ -116,14 +116,21 @@ struct AttributesForInterpolation : NonCopyable, NonMovable {
Vector<GSpan> src_no_interpolation;
Vector<GMutableSpan> dst_no_interpolation;
+
+ Span<float3> src_evaluated_tangents;
+ Span<float3> src_evaluated_normals;
+ MutableSpan<float3> dst_tangents;
+ MutableSpan<float3> dst_normals;
};
/**
* Gather a set of all generic attribute IDs to copy to the result curves.
*/
-static void gather_point_attributes_to_interpolate(const CurvesGeometry &src_curves,
- CurvesGeometry &dst_curves,
- AttributesForInterpolation &result)
+static void gather_point_attributes_to_interpolate(
+ const CurvesGeometry &src_curves,
+ CurvesGeometry &dst_curves,
+ AttributesForInterpolation &result,
+ const ResampleCurvesOutputAttributeIDs &output_ids)
{
VectorSet<bke::AttributeIDRef> ids;
VectorSet<bke::AttributeIDRef> ids_no_interpolation;
@@ -132,6 +139,9 @@ static void gather_point_attributes_to_interpolate(const CurvesGeometry &src_cur
if (meta_data.domain != ATTR_DOMAIN_POINT) {
return true;
}
+ if (meta_data.data_type == CD_PROP_STRING) {
+ return true;
+ }
if (!interpolate_attribute_to_curves(id, dst_curves.curve_type_counts())) {
return true;
}
@@ -159,11 +169,75 @@ static void gather_point_attributes_to_interpolate(const CurvesGeometry &src_cur
result.src_no_interpolation,
result.dst_no_interpolation,
result.dst_attributes);
+
+ bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
+ if (output_ids.tangent_id) {
+ result.src_evaluated_tangents = src_curves.evaluated_tangents();
+ bke::GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span(
+ output_ids.tangent_id, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
+ result.dst_tangents = dst_attribute.span.typed<float3>();
+ result.dst_attributes.append(std::move(dst_attribute));
+ }
+ if (output_ids.normal_id) {
+ result.src_evaluated_normals = src_curves.evaluated_normals();
+ bke::GSpanAttributeWriter dst_attribute = dst_attributes.lookup_or_add_for_write_only_span(
+ output_ids.normal_id, ATTR_DOMAIN_POINT, CD_PROP_FLOAT3);
+ result.dst_normals = dst_attribute.span.typed<float3>();
+ result.dst_attributes.append(std::move(dst_attribute));
+ }
+}
+
+static void copy_or_defaults_for_unselected_curves(const CurvesGeometry &src_curves,
+ const Span<IndexRange> unselected_ranges,
+ const AttributesForInterpolation &attributes,
+ CurvesGeometry &dst_curves)
+{
+ bke::curves::copy_point_data(src_curves,
+ dst_curves,
+ unselected_ranges,
+ src_curves.positions(),
+ dst_curves.positions_for_write());
+
+ for (const int i : attributes.src.index_range()) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
+ }
+ for (const int i : attributes.src_no_interpolation.index_range()) {
+ bke::curves::copy_point_data(src_curves,
+ dst_curves,
+ unselected_ranges,
+ attributes.src_no_interpolation[i],
+ attributes.dst_no_interpolation[i]);
+ }
+
+ if (!attributes.dst_tangents.is_empty()) {
+ bke::curves::fill_points(dst_curves, unselected_ranges, float3(0), attributes.dst_tangents);
+ }
+ if (!attributes.dst_normals.is_empty()) {
+ bke::curves::fill_points(dst_curves, unselected_ranges, float3(0), attributes.dst_normals);
+ }
+}
+
+static void normalize_span(MutableSpan<float3> data)
+{
+ for (const int i : data.index_range()) {
+ data[i] = math::normalize(data[i]);
+ }
+}
+
+static void normalize_curve_point_data(const CurvesGeometry &curves,
+ const IndexMask curve_selection,
+ MutableSpan<float3> data)
+{
+ for (const int i_curve : curve_selection) {
+ normalize_span(data.slice(curves.points_for_curve(i_curve)));
+ }
}
static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
const fn::Field<bool> &selection_field,
- const fn::Field<int> &count_field)
+ const fn::Field<int> &count_field,
+ const ResampleCurvesOutputAttributeIDs &output_ids)
{
/* Create the new curves without any points and evaluate the final count directly
* into the offsets array, in order to be accumulated into offsets later. */
@@ -200,7 +274,7 @@ static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
AttributesForInterpolation attributes;
- gather_point_attributes_to_interpolate(src_curves, dst_curves, attributes);
+ gather_point_attributes_to_interpolate(src_curves, dst_curves, attributes, output_ids);
src_curves.ensure_evaluated_lengths();
@@ -272,14 +346,27 @@ static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
});
}
+ auto interpolate_evaluated_data = [&](const Span<float3> src, MutableSpan<float3> dst) {
+ for (const int i_curve : sliced_selection) {
+ const IndexRange src_points = src_curves.evaluated_points_for_curve(i_curve);
+ const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
+ length_parameterize::interpolate(src.slice(src_points),
+ sample_indices.as_span().slice(dst_points),
+ sample_factors.as_span().slice(dst_points),
+ dst.slice(dst_points));
+ }
+ };
+
/* Interpolate the evaluated positions to the resampled curves. */
- for (const int i_curve : sliced_selection) {
- const IndexRange src_points = src_curves.evaluated_points_for_curve(i_curve);
- const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
- length_parameterize::interpolate(evaluated_positions.slice(src_points),
- sample_indices.as_span().slice(dst_points),
- sample_factors.as_span().slice(dst_points),
- dst_positions.slice(dst_points));
+ interpolate_evaluated_data(evaluated_positions, dst_positions);
+
+ if (!attributes.dst_tangents.is_empty()) {
+ interpolate_evaluated_data(attributes.src_evaluated_tangents, attributes.dst_tangents);
+ normalize_curve_point_data(dst_curves, sliced_selection, attributes.dst_tangents);
+ }
+ if (!attributes.dst_normals.is_empty()) {
+ interpolate_evaluated_data(attributes.src_evaluated_normals, attributes.dst_normals);
+ normalize_curve_point_data(dst_curves, sliced_selection, attributes.dst_normals);
}
/* Fill the default value for non-interpolating attributes that still must be copied. */
@@ -291,23 +378,7 @@ static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
}
});
- /* Any attribute data from unselected curve points can be directly copied. */
- for (const int i : attributes.src.index_range()) {
- bke::curves::copy_point_data(
- src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
- }
- for (const int i : attributes.src_no_interpolation.index_range()) {
- bke::curves::copy_point_data(src_curves,
- dst_curves,
- unselected_ranges,
- attributes.src_no_interpolation[i],
- attributes.dst_no_interpolation[i]);
- }
-
- /* Copy positions for unselected curves. */
- Span<float3> src_positions = src_curves.positions();
- bke::curves::copy_point_data(
- src_curves, dst_curves, unselected_ranges, src_positions, dst_positions);
+ copy_or_defaults_for_unselected_curves(src_curves, unselected_ranges, attributes, dst_curves);
for (bke::GSpanAttributeWriter &attribute : attributes.dst_attributes) {
attribute.finish();
@@ -318,21 +389,25 @@ static CurvesGeometry resample_to_uniform(const CurvesGeometry &src_curves,
CurvesGeometry resample_to_count(const CurvesGeometry &src_curves,
const fn::Field<bool> &selection_field,
- const fn::Field<int> &count_field)
+ const fn::Field<int> &count_field,
+ const ResampleCurvesOutputAttributeIDs &output_ids)
{
- return resample_to_uniform(src_curves, selection_field, get_count_input_max_one(count_field));
+ return resample_to_uniform(
+ src_curves, selection_field, get_count_input_max_one(count_field), output_ids);
}
CurvesGeometry resample_to_length(const CurvesGeometry &src_curves,
const fn::Field<bool> &selection_field,
- const fn::Field<float> &segment_length_field)
+ const fn::Field<float> &segment_length_field,
+ const ResampleCurvesOutputAttributeIDs &output_ids)
{
return resample_to_uniform(
- src_curves, selection_field, get_count_input_from_length(segment_length_field));
+ src_curves, selection_field, get_count_input_from_length(segment_length_field), output_ids);
}
CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
- const fn::Field<bool> &selection_field)
+ const fn::Field<bool> &selection_field,
+ const ResampleCurvesOutputAttributeIDs &output_ids)
{
src_curves.ensure_evaluated_offsets();
@@ -368,11 +443,11 @@ CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
dst_curves.resize(dst_offsets.last(), dst_curves.curves_num());
/* Create the correct number of uniform-length samples for every selected curve. */
- Span<float3> evaluated_positions = src_curves.evaluated_positions();
+ const Span<float3> evaluated_positions = src_curves.evaluated_positions();
MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
AttributesForInterpolation attributes;
- gather_point_attributes_to_interpolate(src_curves, dst_curves, attributes);
+ gather_point_attributes_to_interpolate(src_curves, dst_curves, attributes, output_ids);
threading::parallel_for(selection.index_range(), 512, [&](IndexRange selection_range) {
const IndexMask sliced_selection = selection.slice(selection_range);
@@ -393,11 +468,24 @@ CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
});
}
+ auto copy_evaluated_data = [&](const Span<float3> src, MutableSpan<float3> dst) {
+ for (const int i_curve : sliced_selection) {
+ const IndexRange src_points = src_curves.evaluated_points_for_curve(i_curve);
+ const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
+ dst.slice(dst_points).copy_from(src.slice(src_points));
+ }
+ };
+
/* Copy the evaluated positions to the selected curves. */
- for (const int i_curve : sliced_selection) {
- const IndexRange src_points = src_curves.evaluated_points_for_curve(i_curve);
- const IndexRange dst_points = dst_curves.points_for_curve(i_curve);
- dst_positions.slice(dst_points).copy_from(evaluated_positions.slice(src_points));
+ copy_evaluated_data(evaluated_positions, dst_positions);
+
+ if (!attributes.dst_tangents.is_empty()) {
+ copy_evaluated_data(attributes.src_evaluated_tangents, attributes.dst_tangents);
+ normalize_curve_point_data(dst_curves, sliced_selection, attributes.dst_tangents);
+ }
+ if (!attributes.dst_normals.is_empty()) {
+ copy_evaluated_data(attributes.src_evaluated_normals, attributes.dst_normals);
+ normalize_curve_point_data(dst_curves, sliced_selection, attributes.dst_normals);
}
/* Fill the default value for non-interpolating attributes that still must be copied. */
@@ -409,23 +497,7 @@ CurvesGeometry resample_to_evaluated(const CurvesGeometry &src_curves,
}
});
- /* Any attribute data from unselected curve points can be directly copied. */
- for (const int i : attributes.src.index_range()) {
- bke::curves::copy_point_data(
- src_curves, dst_curves, unselected_ranges, attributes.src[i], attributes.dst[i]);
- }
- for (const int i : attributes.src_no_interpolation.index_range()) {
- bke::curves::copy_point_data(src_curves,
- dst_curves,
- unselected_ranges,
- attributes.src_no_interpolation[i],
- attributes.dst_no_interpolation[i]);
- }
-
- /* Copy positions for unselected curves. */
- Span<float3> src_positions = src_curves.positions();
- bke::curves::copy_point_data(
- src_curves, dst_curves, unselected_ranges, src_positions, dst_positions);
+ copy_or_defaults_for_unselected_curves(src_curves, unselected_ranges, attributes, dst_curves);
for (bke::GSpanAttributeWriter &attribute : attributes.dst_attributes) {
attribute.finish();
diff --git a/source/blender/geometry/intern/set_curve_type.cc b/source/blender/geometry/intern/set_curve_type.cc
index 92609a45bdc..e069732ca9b 100644
--- a/source/blender/geometry/intern/set_curve_type.cc
+++ b/source/blender/geometry/intern/set_curve_type.cc
@@ -186,12 +186,12 @@ static Vector<float3> create_nurbs_to_bezier_handles(const Span<float3> nurbs_po
const int segments_num = nurbs_positions_num - 1;
const bool ignore_interior_segment = segments_num == 3 && is_periodic == false;
if (ignore_interior_segment == false) {
- const float mid_offset = (float)(segments_num - 1) / 2.0f;
+ const float mid_offset = float(segments_num - 1) / 2.0f;
for (const int i : IndexRange(1, segments_num - 2)) {
/* Divisor can have values: 1, 2 or 3. */
const int divisor = is_periodic ?
3 :
- std::min(3, (int)(-std::abs(i - mid_offset) + mid_offset + 1.0f));
+ std::min(3, int(-std::abs(i - mid_offset) + mid_offset + 1.0f));
const float3 &p1 = nurbs_positions[i];
const float3 &p2 = nurbs_positions[i + 1];
const float3 displacement = (p2 - p1) / divisor;
@@ -257,7 +257,7 @@ static int to_bezier_size(const CurveType src_type,
switch (src_type) {
case CURVE_TYPE_NURBS: {
if (is_nurbs_to_bezier_one_to_one(knots_mode)) {
- return cyclic ? src_size : src_size - 2;
+ return cyclic ? src_size : std::max(1, src_size - 2);
}
return (src_size + 1) / 3;
}
@@ -392,6 +392,13 @@ static bke::CurvesGeometry convert_curves_to_bezier(const bke::CurvesGeometry &s
const IndexRange src_points = src_curves.points_for_curve(i);
const IndexRange dst_points = dst_curves.points_for_curve(i);
const Span<float3> src_curve_positions = src_positions.slice(src_points);
+ if (dst_points.size() == 1) {
+ const float3 &position = src_positions[src_points.first()];
+ dst_positions[dst_points.first()] = position;
+ dst_handles_l[dst_points.first()] = position;
+ dst_handles_r[dst_points.first()] = position;
+ continue;
+ }
KnotsMode knots_mode = KnotsMode(src_knot_modes[i]);
Span<float3> nurbs_positions = src_curve_positions;
diff --git a/source/blender/geometry/intern/trim_curves.cc b/source/blender/geometry/intern/trim_curves.cc
new file mode 100644
index 00000000000..82e9ee78592
--- /dev/null
+++ b/source/blender/geometry/intern/trim_curves.cc
@@ -0,0 +1,1031 @@
+/* SPDX-License-Identifier: GPL-2.0-or-later */
+
+/** \file
+ * \ingroup bke
+ */
+
+#include "BLI_array_utils.hh"
+#include "BLI_length_parameterize.hh"
+
+#include "BKE_attribute.hh"
+#include "BKE_attribute_math.hh"
+#include "BKE_curves.hh"
+#include "BKE_curves_utils.hh"
+#include "BKE_geometry_set.hh"
+
+#include "GEO_trim_curves.hh"
+
+namespace blender::geometry {
+
+/* -------------------------------------------------------------------- */
+/** \name Lookup Curve Points
+ * \{ */
+
+/**
+ * Find the point on the curve defined by the distance along the curve. Assumes curve resolution is
+ * constant for all curve segments and evaluated curve points are uniformly spaced between the
+ * segment endpoints in relation to the curve parameter.
+ *
+ * \param lengths: Accumulated length for the evaluated curve.
+ * \param sample_length: Distance along the curve to determine the #CurvePoint for.
+ * \param cyclic: If curve is cyclic.
+ * \param resolution: Curve resolution (number of evaluated points per segment).
+ * \param num_curve_points: Total number of control points in the curve.
+ * \return: Point on the piecewise segment matching the given distance.
+ */
+static bke::curves::CurvePoint lookup_point_uniform_spacing(const Span<float> lengths,
+ const float sample_length,
+ const bool cyclic,
+ const int resolution,
+ const int num_curve_points)
+{
+ BLI_assert(!cyclic || lengths.size() / resolution >= 2);
+ const int last_index = num_curve_points - 1;
+ if (sample_length <= 0.0f) {
+ return {{0, 1}, 0.0f};
+ }
+ if (sample_length >= lengths.last()) {
+ return cyclic ? bke::curves::CurvePoint{{last_index, 0}, 1.0} :
+ bke::curves::CurvePoint{{last_index - 1, last_index}, 1.0};
+ }
+ int eval_index;
+ float eval_factor;
+ length_parameterize::sample_at_length(lengths, sample_length, eval_index, eval_factor);
+
+ const int index = eval_index / resolution;
+ const int next_index = (index == last_index) ? 0 : index + 1;
+ const float parameter = (eval_factor + eval_index) / resolution - index;
+
+ return bke::curves::CurvePoint{{index, next_index}, parameter};
+}
+
+/**
+ * Find the point on the 'evaluated' polygonal curve.
+ */
+static bke::curves::CurvePoint lookup_point_polygonal(const Span<float> lengths,
+ const float sample_length,
+ const bool cyclic,
+ const int evaluated_size)
+{
+ const int last_index = evaluated_size - 1;
+ if (sample_length <= 0.0f) {
+ return {{0, 1}, 0.0f};
+ }
+ if (sample_length >= lengths.last()) {
+ return cyclic ? bke::curves::CurvePoint{{last_index, 0}, 1.0} :
+ bke::curves::CurvePoint{{last_index - 1, last_index}, 1.0};
+ }
+
+ int eval_index;
+ float eval_factor;
+ length_parameterize::sample_at_length(lengths, sample_length, eval_index, eval_factor);
+
+ const int next_eval_index = (eval_index == last_index) ? 0 : eval_index + 1;
+ return bke::curves::CurvePoint{{eval_index, next_eval_index}, eval_factor};
+}
+
+/**
+ * Find the point on a Bezier curve using the 'bezier_offsets' cache.
+ */
+static bke::curves::CurvePoint lookup_point_bezier(const Span<int> bezier_offsets,
+ const Span<float> lengths,
+ const float sample_length,
+ const bool cyclic,
+ const int num_curve_points)
+{
+ const int last_index = num_curve_points - 1;
+ if (sample_length <= 0.0f) {
+ return {{0, 1}, 0.0f};
+ }
+ if (sample_length >= lengths.last()) {
+ return cyclic ? bke::curves::CurvePoint{{last_index, 0}, 1.0} :
+ bke::curves::CurvePoint{{last_index - 1, last_index}, 1.0};
+ }
+ int eval_index;
+ float eval_factor;
+ length_parameterize::sample_at_length(lengths, sample_length, eval_index, eval_factor);
+
+ /* Find the segment index from the offset mapping. */
+ const int *offset = std::upper_bound(bezier_offsets.begin(), bezier_offsets.end(), eval_index);
+ const int left = offset - bezier_offsets.begin();
+ const int right = left == last_index ? 0 : left + 1;
+
+ const int prev_offset = left == 0 ? 0 : bezier_offsets[int64_t(left) - 1];
+ const float offset_in_segment = eval_factor + (eval_index - prev_offset);
+ const int segment_resolution = bezier_offsets[left] - prev_offset;
+ const float parameter = std::clamp(offset_in_segment / segment_resolution, 0.0f, 1.0f);
+
+ return {{left, right}, parameter};
+}
+
+static bke::curves::CurvePoint lookup_point_bezier(const bke::CurvesGeometry &src_curves,
+ const int64_t curve_index,
+ const Span<float> accumulated_lengths,
+ const float sample_length,
+ const bool cyclic,
+ const int resolution,
+ const int num_curve_points)
+{
+ if (bke::curves::bezier::has_vector_handles(
+ num_curve_points,
+ src_curves.evaluated_points_for_curve(curve_index).size(),
+ cyclic,
+ resolution)) {
+ const Span<int> bezier_offsets = src_curves.bezier_evaluated_offsets_for_curve(curve_index);
+ return lookup_point_bezier(
+ bezier_offsets, accumulated_lengths, sample_length, cyclic, num_curve_points);
+ }
+ else {
+ return lookup_point_uniform_spacing(
+ accumulated_lengths, sample_length, cyclic, resolution, num_curve_points);
+ }
+}
+
+static bke::curves::CurvePoint lookup_curve_point(const bke::CurvesGeometry &src_curves,
+ const CurveType curve_type,
+ const int64_t curve_index,
+ const Span<float> accumulated_lengths,
+ const float sample_length,
+ const bool cyclic,
+ const int resolution,
+ const int num_curve_points)
+{
+ if (num_curve_points == 1) {
+ return {{0, 0}, 0.0f};
+ }
+
+ if (curve_type == CURVE_TYPE_CATMULL_ROM) {
+ return lookup_point_uniform_spacing(
+ accumulated_lengths, sample_length, cyclic, resolution, num_curve_points);
+ }
+ else if (curve_type == CURVE_TYPE_BEZIER) {
+ return lookup_point_bezier(src_curves,
+ curve_index,
+ accumulated_lengths,
+ sample_length,
+ cyclic,
+ resolution,
+ num_curve_points);
+ }
+ else if (curve_type == CURVE_TYPE_POLY) {
+ return lookup_point_polygonal(accumulated_lengths, sample_length, cyclic, num_curve_points);
+ }
+ else {
+ /* Handle evaluated curve. */
+ BLI_assert(resolution > 0);
+ return lookup_point_polygonal(accumulated_lengths,
+ sample_length,
+ cyclic,
+ src_curves.evaluated_points_for_curve(curve_index).size());
+ }
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Utility Functions
+ * \{ */
+
+static void fill_bezier_data(bke::CurvesGeometry &dst_curves, const IndexMask selection)
+{
+ if (!dst_curves.has_curve_with_type(CURVE_TYPE_BEZIER)) {
+ return;
+ }
+ MutableSpan<float3> handle_positions_left = dst_curves.handle_positions_left_for_write();
+ MutableSpan<float3> handle_positions_right = dst_curves.handle_positions_right_for_write();
+ MutableSpan<int8_t> handle_types_left = dst_curves.handle_types_left_for_write();
+ MutableSpan<int8_t> handle_types_right = dst_curves.handle_types_right_for_write();
+
+ threading::parallel_for(selection.index_range(), 4096, [&](const IndexRange range) {
+ for (const int64_t curve_i : selection.slice(range)) {
+ const IndexRange points = dst_curves.points_for_curve(curve_i);
+ handle_types_right.slice(points).fill(int8_t(BEZIER_HANDLE_FREE));
+ handle_types_left.slice(points).fill(int8_t(BEZIER_HANDLE_FREE));
+ handle_positions_left.slice(points).fill({0.0f, 0.0f, 0.0f});
+ handle_positions_right.slice(points).fill({0.0f, 0.0f, 0.0f});
+ }
+ });
+}
+static void fill_nurbs_data(bke::CurvesGeometry &dst_curves, const IndexMask selection)
+{
+ if (!dst_curves.has_curve_with_type(CURVE_TYPE_NURBS)) {
+ return;
+ }
+ bke::curves::fill_points(dst_curves, selection, 0.0f, dst_curves.nurbs_weights_for_write());
+}
+
+template<typename T>
+static int64_t copy_point_data_between_endpoints(const Span<T> src_data,
+ MutableSpan<T> dst_data,
+ const bke::curves::IndexRangeCyclic src_range,
+ int64_t dst_index)
+{
+ int64_t increment;
+ if (src_range.cycles()) {
+ increment = src_range.size_before_loop();
+ dst_data.slice(dst_index, increment).copy_from(src_data.slice(src_range.first(), increment));
+ dst_index += increment;
+
+ increment = src_range.size_after_loop();
+ dst_data.slice(dst_index, increment)
+ .copy_from(src_data.slice(src_range.curve_range().first(), increment));
+ dst_index += increment;
+ }
+ else {
+ increment = src_range.one_after_last() - src_range.first();
+ dst_data.slice(dst_index, increment).copy_from(src_data.slice(src_range.first(), increment));
+ dst_index += increment;
+ }
+ return dst_index;
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sampling Utilities
+ * \{ */
+
+template<typename T>
+static T interpolate_catmull_rom(const Span<T> src_data,
+ const bke::curves::CurvePoint insertion_point,
+ const bool src_cyclic)
+{
+ BLI_assert(insertion_point.index >= 0 && insertion_point.next_index < src_data.size());
+ int i0;
+ if (insertion_point.index == 0) {
+ i0 = src_cyclic ? src_data.size() - 1 : insertion_point.index;
+ }
+ else {
+ i0 = insertion_point.index - 1;
+ }
+ int i3 = insertion_point.next_index + 1;
+ if (i3 == src_data.size()) {
+ i3 = src_cyclic ? 0 : insertion_point.next_index;
+ }
+ return bke::curves::catmull_rom::interpolate<T>(src_data[i0],
+ src_data[insertion_point.index],
+ src_data[insertion_point.next_index],
+ src_data[i3],
+ insertion_point.parameter);
+}
+
+static bke::curves::bezier::Insertion knot_insert_bezier(
+ const Span<float3> positions,
+ const Span<float3> handles_left,
+ const Span<float3> handles_right,
+ const bke::curves::CurvePoint insertion_point)
+{
+ BLI_assert(
+ insertion_point.index + 1 == insertion_point.next_index ||
+ (insertion_point.next_index >= 0 && insertion_point.next_index < insertion_point.index));
+ return bke::curves::bezier::insert(positions[insertion_point.index],
+ handles_right[insertion_point.index],
+ handles_left[insertion_point.next_index],
+ positions[insertion_point.next_index],
+ insertion_point.parameter);
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Sample Curve Interval (Trim)
+ * \{ */
+
+/**
+ * Sample source curve data in the interval defined by the points [start_point, end_point].
+ * Uses linear interpolation to compute the endpoints.
+ *
+ * \tparam include_start_point If False, the 'start_point' point sample will not be copied
+ * and not accounted for in the destination range.
+ * \param src_data: Source to sample from.
+ * \param dst_data: Destination to write samples to.
+ * \param src_range: Interval within [start_point, end_point] to copy from the source point domain.
+ * \param dst_range: Interval to copy point data to in the destination buffer.
+ * \param start_point: Point on the source curve to start sampling from.
+ * \param end_point: Last point to sample in the source curve.
+ */
+template<typename T, bool include_start_point = true>
+static void sample_interval_linear(const Span<T> src_data,
+ MutableSpan<T> dst_data,
+ bke::curves::IndexRangeCyclic src_range,
+ const IndexRange dst_range,
+ const bke::curves::CurvePoint start_point,
+ const bke::curves::CurvePoint end_point)
+{
+ int64_t dst_index = dst_range.first();
+
+ if (start_point.is_controlpoint()) {
+ /* 'start_point' is included in the copy iteration. */
+ if constexpr (!include_start_point) {
+ /* Skip first. */
+ src_range = src_range.drop_front();
+ }
+ }
+ else if constexpr (!include_start_point) {
+ /* Do nothing (excluded). */
+ }
+ else {
+ /* General case, sample 'start_point' */
+ dst_data[dst_index] = attribute_math::mix2(
+ start_point.parameter, src_data[start_point.index], src_data[start_point.next_index]);
+ ++dst_index;
+ }
+
+ dst_index = copy_point_data_between_endpoints(src_data, dst_data, src_range, dst_index);
+ if (dst_range.size() == 1) {
+ BLI_assert(dst_index == dst_range.one_after_last());
+ return;
+ }
+
+ /* Handle last case */
+ if (end_point.is_controlpoint()) {
+ /* 'end_point' is included in the copy iteration. */
+ }
+ else {
+ dst_data[dst_index] = attribute_math::mix2(
+ end_point.parameter, src_data[end_point.index], src_data[end_point.next_index]);
+#ifdef DEBUG
+ ++dst_index;
+#endif
+ }
+ BLI_assert(dst_index == dst_range.one_after_last());
+}
+
+template<typename T>
+static void sample_interval_catmull_rom(const Span<T> src_data,
+ MutableSpan<T> dst_data,
+ bke::curves::IndexRangeCyclic src_range,
+ const IndexRange dst_range,
+ const bke::curves::CurvePoint start_point,
+ const bke::curves::CurvePoint end_point,
+ const bool src_cyclic)
+{
+ int64_t dst_index = dst_range.first();
+
+ if (start_point.is_controlpoint()) {
+ }
+ else {
+ /* General case, sample 'start_point' */
+ dst_data[dst_index] = interpolate_catmull_rom(src_data, start_point, src_cyclic);
+ ++dst_index;
+ }
+
+ dst_index = copy_point_data_between_endpoints(src_data, dst_data, src_range, dst_index);
+ if (dst_range.size() == 1) {
+ BLI_assert(dst_index == dst_range.one_after_last());
+ return;
+ }
+
+ /* Handle last case */
+ if (end_point.is_controlpoint()) {
+ /* 'end_point' is included in the copy iteration. */
+ }
+ else {
+ dst_data[dst_index] = interpolate_catmull_rom(src_data, end_point, src_cyclic);
+#ifdef DEBUG
+ ++dst_index;
+#endif
+ }
+ BLI_assert(dst_index == dst_range.one_after_last());
+}
+
+template<bool include_start_point = true>
+static void sample_interval_bezier(const Span<float3> src_positions,
+ 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,
+ MutableSpan<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::curves::IndexRangeCyclic src_range,
+ const IndexRange dst_range,
+ const bke::curves::CurvePoint start_point,
+ const bke::curves::CurvePoint end_point)
+{
+ bke::curves::bezier::Insertion start_point_insert;
+ int64_t dst_index = dst_range.first();
+
+ bool start_point_trimmed = false;
+ if (start_point.is_controlpoint()) {
+ /* The 'start_point' control point is included in the copy iteration. */
+ if constexpr (!include_start_point) {
+ src_range = src_range.drop_front();
+ }
+ }
+ else if constexpr (!include_start_point) {
+ /* Do nothing, 'start_point' is excluded. */
+ }
+ else {
+ /* General case, sample 'start_point'. */
+ start_point_insert = knot_insert_bezier(
+ src_positions, src_handles_l, src_handles_r, start_point);
+ dst_positions[dst_range.first()] = start_point_insert.position;
+ dst_handles_l[dst_range.first()] = start_point_insert.left_handle;
+ dst_handles_r[dst_range.first()] = start_point_insert.right_handle;
+ dst_types_l[dst_range.first()] = src_types_l[start_point.index];
+ dst_types_r[dst_range.first()] = src_types_r[start_point.index];
+
+ start_point_trimmed = true;
+ ++dst_index;
+ }
+
+ /* Copy point data between the 'start_point' and 'end_point'. */
+ int64_t increment = src_range.cycles() ? src_range.size_before_loop() :
+ src_range.one_after_last() - src_range.first();
+
+ const IndexRange dst_range_to_end(dst_index, increment);
+ const IndexRange src_range_to_end(src_range.first(), increment);
+ dst_positions.slice(dst_range_to_end).copy_from(src_positions.slice(src_range_to_end));
+ dst_handles_l.slice(dst_range_to_end).copy_from(src_handles_l.slice(src_range_to_end));
+ dst_handles_r.slice(dst_range_to_end).copy_from(src_handles_r.slice(src_range_to_end));
+ dst_types_l.slice(dst_range_to_end).copy_from(src_types_l.slice(src_range_to_end));
+ dst_types_r.slice(dst_range_to_end).copy_from(src_types_r.slice(src_range_to_end));
+ dst_index += increment;
+
+ if (dst_range.size() == 1) {
+ BLI_assert(dst_index == dst_range.one_after_last());
+ return;
+ }
+
+ increment = src_range.size_after_loop();
+ if (src_range.cycles() && increment > 0) {
+ const IndexRange dst_range_looped(dst_index, increment);
+ const IndexRange src_range_looped(src_range.curve_range().first(), increment);
+ dst_positions.slice(dst_range_looped).copy_from(src_positions.slice(src_range_looped));
+ dst_handles_l.slice(dst_range_looped).copy_from(src_handles_l.slice(src_range_looped));
+ dst_handles_r.slice(dst_range_looped).copy_from(src_handles_r.slice(src_range_looped));
+ dst_types_l.slice(dst_range_looped).copy_from(src_types_l.slice(src_range_looped));
+ dst_types_r.slice(dst_range_looped).copy_from(src_types_r.slice(src_range_looped));
+ dst_index += increment;
+ }
+
+ if (start_point_trimmed) {
+ dst_handles_l[dst_range.first() + 1] = start_point_insert.handle_next;
+ /* No need to set handle type (remains the same)! */
+ }
+
+ /* Handle 'end_point' */
+ bke::curves::bezier::Insertion end_point_insert;
+ if (end_point.is_controlpoint()) {
+ /* Do nothing, the 'end_point' control point is included in the copy iteration. */
+ }
+ else {
+ /* Trimmed in both ends within the same (and only) segment! Ensure both end points is not a
+ * loop. */
+ if (start_point_trimmed && start_point.index == end_point.index &&
+ start_point.parameter <= end_point.parameter) {
+
+ /* Copy following segment control point. */
+ dst_positions[dst_index] = src_positions[end_point.next_index];
+ dst_handles_r[dst_index] = src_handles_r[end_point.next_index];
+
+ /* Compute interpolation in the result curve. */
+ const float parameter = (end_point.parameter - start_point.parameter) /
+ (1.0f - start_point.parameter);
+ end_point_insert = knot_insert_bezier(
+ dst_positions,
+ dst_handles_l,
+ dst_handles_r,
+ {{int(dst_range.first()), int(dst_range.first() + 1)}, parameter});
+ }
+ else {
+ /* General case, compute the insertion point. */
+ end_point_insert = knot_insert_bezier(
+ src_positions, src_handles_l, src_handles_r, end_point);
+ }
+
+ dst_handles_r[dst_index - 1] = end_point_insert.handle_prev;
+ dst_types_r[dst_index - 1] = src_types_l[end_point.index];
+
+ dst_handles_l[dst_index] = end_point_insert.left_handle;
+ dst_handles_r[dst_index] = end_point_insert.right_handle;
+ dst_positions[dst_index] = end_point_insert.position;
+ dst_types_l[dst_index] = src_types_l[end_point.next_index];
+ dst_types_r[dst_index] = src_types_r[end_point.next_index];
+#ifdef DEBUG
+ ++dst_index;
+#endif // DEBUG
+ }
+ BLI_assert(dst_index == dst_range.one_after_last());
+}
+
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Trim Curves
+ * \{ */
+
+static void trim_attribute_linear(const bke::CurvesGeometry &src_curves,
+ bke::CurvesGeometry &dst_curves,
+ const IndexMask selection,
+ const Span<bke::curves::CurvePoint> start_points,
+ const Span<bke::curves::CurvePoint> end_points,
+ const Span<bke::curves::IndexRangeCyclic> src_ranges,
+ MutableSpan<bke::AttributeTransferData> transfer_attributes)
+{
+ for (bke::AttributeTransferData &attribute : transfer_attributes) {
+ attribute_math::convert_to_static_type(attribute.meta_data.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+
+ threading::parallel_for(selection.index_range(), 512, [&](const IndexRange range) {
+ for (const int64_t curve_i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(curve_i);
+
+ sample_interval_linear<T>(attribute.src.template typed<T>().slice(src_points),
+ attribute.dst.span.typed<T>(),
+ src_ranges[curve_i],
+ dst_curves.points_for_curve(curve_i),
+ start_points[curve_i],
+ end_points[curve_i]);
+ }
+ });
+ });
+ }
+}
+
+static void trim_polygonal_curves(const bke::CurvesGeometry &src_curves,
+ bke::CurvesGeometry &dst_curves,
+ const IndexMask selection,
+ const Span<bke::curves::CurvePoint> start_points,
+ const Span<bke::curves::CurvePoint> end_points,
+ const Span<bke::curves::IndexRangeCyclic> src_ranges,
+ MutableSpan<bke::AttributeTransferData> transfer_attributes)
+{
+ const Span<float3> src_positions = src_curves.positions();
+ MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
+
+ threading::parallel_for(selection.index_range(), 512, [&](const IndexRange range) {
+ for (const int64_t curve_i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(curve_i);
+ const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
+
+ sample_interval_linear<float3>(src_positions.slice(src_points),
+ dst_positions,
+ src_ranges[curve_i],
+ dst_points,
+ start_points[curve_i],
+ end_points[curve_i]);
+ }
+ });
+ fill_bezier_data(dst_curves, selection);
+ fill_nurbs_data(dst_curves, selection);
+ trim_attribute_linear(src_curves,
+ dst_curves,
+ selection,
+ start_points,
+ end_points,
+ src_ranges,
+ transfer_attributes);
+}
+
+static void trim_catmull_rom_curves(const bke::CurvesGeometry &src_curves,
+ bke::CurvesGeometry &dst_curves,
+ const IndexMask selection,
+ const Span<bke::curves::CurvePoint> start_points,
+ const Span<bke::curves::CurvePoint> end_points,
+ const Span<bke::curves::IndexRangeCyclic> src_ranges,
+ MutableSpan<bke::AttributeTransferData> transfer_attributes)
+{
+ const Span<float3> src_positions = src_curves.positions();
+ const VArray<bool> src_cyclic = src_curves.cyclic();
+ MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
+
+ threading::parallel_for(selection.index_range(), 512, [&](const IndexRange range) {
+ for (const int64_t curve_i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(curve_i);
+ const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
+
+ sample_interval_catmull_rom<float3>(src_positions.slice(src_points),
+ dst_positions,
+ src_ranges[curve_i],
+ dst_points,
+ start_points[curve_i],
+ end_points[curve_i],
+ src_cyclic[curve_i]);
+ }
+ });
+ fill_bezier_data(dst_curves, selection);
+ fill_nurbs_data(dst_curves, selection);
+
+ for (bke::AttributeTransferData &attribute : transfer_attributes) {
+ attribute_math::convert_to_static_type(attribute.meta_data.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+
+ threading::parallel_for(selection.index_range(), 512, [&](const IndexRange range) {
+ for (const int64_t curve_i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(curve_i);
+ const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
+
+ sample_interval_catmull_rom<T>(attribute.src.template typed<T>().slice(src_points),
+ attribute.dst.span.typed<T>(),
+ src_ranges[curve_i],
+ dst_points,
+ start_points[curve_i],
+ end_points[curve_i],
+ src_cyclic[curve_i]);
+ }
+ });
+ });
+ }
+}
+
+static void trim_bezier_curves(const bke::CurvesGeometry &src_curves,
+ bke::CurvesGeometry &dst_curves,
+ const IndexMask selection,
+ const Span<bke::curves::CurvePoint> start_points,
+ const Span<bke::curves::CurvePoint> end_points,
+ const Span<bke::curves::IndexRangeCyclic> src_ranges,
+ MutableSpan<bke::AttributeTransferData> transfer_attributes)
+{
+ const Span<float3> src_positions = src_curves.positions();
+ const VArraySpan<int8_t> src_types_l{src_curves.handle_types_left()};
+ const VArraySpan<int8_t> src_types_r{src_curves.handle_types_right()};
+ const Span<float3> src_handles_l = src_curves.handle_positions_left();
+ const Span<float3> src_handles_r = src_curves.handle_positions_right();
+
+ MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
+ MutableSpan<int8_t> dst_types_l = dst_curves.handle_types_left_for_write();
+ MutableSpan<int8_t> dst_types_r = dst_curves.handle_types_right_for_write();
+ MutableSpan<float3> dst_handles_l = dst_curves.handle_positions_left_for_write();
+ MutableSpan<float3> dst_handles_r = dst_curves.handle_positions_right_for_write();
+
+ threading::parallel_for(selection.index_range(), 512, [&](const IndexRange range) {
+ for (const int64_t curve_i : selection.slice(range)) {
+ const IndexRange src_points = src_curves.points_for_curve(curve_i);
+ const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
+
+ sample_interval_bezier(src_positions.slice(src_points),
+ src_handles_l.slice(src_points),
+ src_handles_r.slice(src_points),
+ src_types_l.slice(src_points),
+ src_types_r.slice(src_points),
+ dst_positions,
+ dst_handles_l,
+ dst_handles_r,
+ dst_types_l,
+ dst_types_r,
+ src_ranges[curve_i],
+ dst_points,
+ start_points[curve_i],
+ end_points[curve_i]);
+ }
+ });
+ fill_nurbs_data(dst_curves, selection);
+ trim_attribute_linear(src_curves,
+ dst_curves,
+ selection,
+ start_points,
+ end_points,
+ src_ranges,
+ transfer_attributes);
+}
+
+static void trim_evaluated_curves(const bke::CurvesGeometry &src_curves,
+ bke::CurvesGeometry &dst_curves,
+ const IndexMask selection,
+ const Span<bke::curves::CurvePoint> start_points,
+ const Span<bke::curves::CurvePoint> end_points,
+ const Span<bke::curves::IndexRangeCyclic> src_ranges,
+ MutableSpan<bke::AttributeTransferData> transfer_attributes)
+{
+ const Span<float3> src_eval_positions = src_curves.evaluated_positions();
+ MutableSpan<float3> dst_positions = dst_curves.positions_for_write();
+
+ threading::parallel_for(selection.index_range(), 512, [&](const IndexRange range) {
+ for (const int64_t curve_i : selection.slice(range)) {
+ const IndexRange dst_points = dst_curves.points_for_curve(curve_i);
+ const IndexRange src_evaluated_points = src_curves.evaluated_points_for_curve(curve_i);
+
+ sample_interval_linear<float3>(src_eval_positions.slice(src_evaluated_points),
+ dst_positions,
+ src_ranges[curve_i],
+ dst_points,
+ start_points[curve_i],
+ end_points[curve_i]);
+ }
+ });
+ fill_bezier_data(dst_curves, selection);
+ fill_nurbs_data(dst_curves, selection);
+
+ for (bke::AttributeTransferData &attribute : transfer_attributes) {
+ attribute_math::convert_to_static_type(attribute.meta_data.data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+
+ threading::parallel_for(selection.index_range(), 512, [&](const IndexRange range) {
+ for (const int64_t curve_i : selection.slice(range)) {
+ /* Interpolate onto the evaluated point domain and sample the evaluated domain. */
+ const IndexRange src_evaluated_points = src_curves.evaluated_points_for_curve(curve_i);
+ GArray evaluated_data(CPPType::get<T>(), src_evaluated_points.size());
+ GMutableSpan evaluated_span = evaluated_data.as_mutable_span();
+ src_curves.interpolate_to_evaluated(
+ curve_i, attribute.src.slice(src_curves.points_for_curve(curve_i)), evaluated_span);
+ sample_interval_linear<T>(evaluated_span.typed<T>(),
+ attribute.dst.span.typed<T>(),
+ src_ranges[curve_i],
+ dst_curves.points_for_curve(curve_i),
+ start_points[curve_i],
+ end_points[curve_i]);
+ }
+ });
+ });
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/** \name Compute trim parameters
+ * \{ */
+
+static float trim_sample_length(const Span<float> accumulated_lengths,
+ const float sample_length,
+ const GeometryNodeCurveSampleMode mode)
+{
+ float length = mode == GEO_NODE_CURVE_SAMPLE_FACTOR ?
+ sample_length * accumulated_lengths.last() :
+ sample_length;
+ return std::clamp(length, 0.0f, accumulated_lengths.last());
+}
+
+/**
+ * Compute the selection for the given curve type. Tracks indices for splitting the selection if
+ * there are curves reduced to a single point.
+ */
+static void compute_curve_trim_parameters(const bke::CurvesGeometry &curves,
+ const IndexMask selection,
+ const VArray<float> &starts,
+ const VArray<float> &ends,
+ const GeometryNodeCurveSampleMode mode,
+ MutableSpan<int> dst_curve_size,
+ MutableSpan<int8_t> dst_curve_types,
+ MutableSpan<bke::curves::CurvePoint> start_points,
+ MutableSpan<bke::curves::CurvePoint> end_points,
+ MutableSpan<bke::curves::IndexRangeCyclic> src_ranges)
+{
+ const VArray<bool> src_cyclic = curves.cyclic();
+ const VArray<int> resolution = curves.resolution();
+ const VArray<int8_t> curve_types = curves.curve_types();
+
+ /* Compute. */
+ threading::parallel_for(selection.index_range(), 128, [&](const IndexRange selection_range) {
+ for (const int64_t curve_i : selection.slice(selection_range)) {
+ CurveType curve_type = CurveType(curve_types[curve_i]);
+
+ int point_count;
+ if (curve_type == CURVE_TYPE_NURBS) {
+ dst_curve_types[curve_i] = CURVE_TYPE_POLY;
+ point_count = curves.evaluated_points_for_curve(curve_i).size();
+ }
+ else {
+ dst_curve_types[curve_i] = curve_type;
+ point_count = curves.points_num_for_curve(curve_i);
+ }
+ if (point_count == 1) {
+ /* Single point. */
+ dst_curve_size[curve_i] = 1;
+ src_ranges[curve_i] = bke::curves::IndexRangeCyclic(0, 0, 1, 1);
+ start_points[curve_i] = {0, 0, 0.0f};
+ end_points[curve_i] = {0, 0, 0.0f};
+ continue;
+ }
+
+ const bool cyclic = src_cyclic[curve_i];
+ const Span<float> lengths = curves.evaluated_lengths_for_curve(curve_i, cyclic);
+ BLI_assert(lengths.size() > 0);
+
+ const float start_length = trim_sample_length(lengths, starts[curve_i], mode);
+ float end_length;
+
+ bool equal_sample_point;
+ if (cyclic) {
+ end_length = trim_sample_length(lengths, ends[curve_i], mode);
+ const float cyclic_start = start_length == lengths.last() ? 0.0f : start_length;
+ const float cyclic_end = end_length == lengths.last() ? 0.0f : end_length;
+ equal_sample_point = cyclic_start == cyclic_end;
+ }
+ else {
+ end_length = ends[curve_i] <= starts[curve_i] ?
+ start_length :
+ trim_sample_length(lengths, ends[curve_i], mode);
+ equal_sample_point = start_length == end_length;
+ }
+
+ start_points[curve_i] = lookup_curve_point(curves,
+ curve_type,
+ curve_i,
+ lengths,
+ start_length,
+ cyclic,
+ resolution[curve_i],
+ point_count);
+ if (equal_sample_point) {
+ end_points[curve_i] = start_points[curve_i];
+ if (end_length <= start_length) {
+ /* Single point. */
+ dst_curve_size[curve_i] = 1;
+ src_ranges[curve_i] = bke::curves::IndexRangeCyclic::get_range_from_size(
+ start_points[curve_i].index,
+ start_points[curve_i].is_controlpoint(), /* Only iterate if control point. */
+ point_count);
+ }
+ else {
+ /* Split. */
+ src_ranges[curve_i] = bke::curves::IndexRangeCyclic::get_range_between_endpoints(
+ start_points[curve_i], end_points[curve_i], point_count)
+ .push_loop();
+ const int count = 1 + !start_points[curve_i].is_controlpoint() + point_count;
+ BLI_assert(count > 1);
+ dst_curve_size[curve_i] = count;
+ }
+ }
+ else {
+ /* General case. */
+ end_points[curve_i] = lookup_curve_point(curves,
+ curve_type,
+ curve_i,
+ lengths,
+ end_length,
+ cyclic,
+ resolution[curve_i],
+ point_count);
+
+ src_ranges[curve_i] = bke::curves::IndexRangeCyclic::get_range_between_endpoints(
+ start_points[curve_i], end_points[curve_i], point_count);
+ const int count = src_ranges[curve_i].size() + !start_points[curve_i].is_controlpoint() +
+ !end_points[curve_i].is_controlpoint();
+ BLI_assert(count > 1);
+ dst_curve_size[curve_i] = count;
+ }
+ BLI_assert(dst_curve_size[curve_i] > 0);
+ }
+ });
+}
+
+/** \} */
+
+bke::CurvesGeometry trim_curves(const bke::CurvesGeometry &src_curves,
+ const IndexMask selection,
+ const VArray<float> &starts,
+ const VArray<float> &ends,
+ const GeometryNodeCurveSampleMode mode)
+{
+ BLI_assert(selection.size() > 0);
+ BLI_assert(selection.last() <= src_curves.curves_num());
+ BLI_assert(starts.size() == src_curves.curves_num());
+ BLI_assert(starts.size() == ends.size());
+ src_curves.ensure_evaluated_lengths();
+
+ Vector<int64_t> inverse_selection_indices;
+ const IndexMask inverse_selection = selection.invert(src_curves.curves_range(),
+ inverse_selection_indices);
+
+ /* Create destination curves. */
+ bke::CurvesGeometry dst_curves(0, src_curves.curves_num());
+ MutableSpan<int> dst_curve_offsets = dst_curves.offsets_for_write();
+ MutableSpan<int8_t> dst_curve_types = dst_curves.curve_types_for_write();
+ Array<bke::curves::CurvePoint, 12> start_points(src_curves.curves_num());
+ Array<bke::curves::CurvePoint, 12> end_points(src_curves.curves_num());
+ Array<bke::curves::IndexRangeCyclic, 12> src_ranges(src_curves.curves_num());
+
+ if (src_curves.has_curve_with_type({CURVE_TYPE_BEZIER, CURVE_TYPE_NURBS})) {
+ src_curves.ensure_evaluated_offsets();
+ if (src_curves.has_curve_with_type(CURVE_TYPE_NURBS)) {
+ src_curves.evaluated_positions();
+ }
+ }
+
+ /* Compute destination curves. */
+ compute_curve_trim_parameters(src_curves,
+ selection,
+ starts,
+ ends,
+ mode,
+ dst_curve_offsets,
+ dst_curve_types,
+ start_points,
+ end_points,
+ src_ranges);
+
+ /* Transfer copied curves parameters. */
+ const VArray<int8_t> src_curve_types = src_curves.curve_types();
+ threading::parallel_for(
+ inverse_selection.index_range(), 4096, [&](const IndexRange selection_range) {
+ for (const int64_t curve_i : inverse_selection.slice(selection_range)) {
+ dst_curve_offsets[curve_i] = src_curves.points_num_for_curve(curve_i);
+ dst_curve_types[curve_i] = src_curve_types[curve_i];
+ }
+ });
+ /* Finalize and update the geometry container. */
+ bke::curves::accumulate_counts_to_offsets(dst_curve_offsets);
+ dst_curves.resize(dst_curves.offsets().last(), dst_curves.curves_num());
+ dst_curves.update_curve_types();
+
+ /* Populate curve domain. */
+ const bke::AttributeAccessor src_attributes = src_curves.attributes();
+ bke::MutableAttributeAccessor dst_attributes = dst_curves.attributes_for_write();
+ Set<std::string> transfer_curve_skip = {"cyclic", "curve_type", "nurbs_order", "knots_mode"};
+ if (dst_curves.has_curve_with_type(CURVE_TYPE_NURBS)) {
+ /* If a NURBS curve is copied keep */
+ transfer_curve_skip.remove("nurbs_order");
+ transfer_curve_skip.remove("knots_mode");
+ }
+ bke::copy_attribute_domain(
+ src_attributes, dst_attributes, selection, ATTR_DOMAIN_CURVE, transfer_curve_skip);
+
+ /* Fetch custom point domain attributes for transfer (copy). */
+ Vector<bke::AttributeTransferData> transfer_attributes = bke::retrieve_attributes_for_transfer(
+ src_attributes,
+ dst_attributes,
+ ATTR_DOMAIN_MASK_POINT,
+ {"position",
+ "handle_left",
+ "handle_right",
+ "handle_type_left",
+ "handle_type_right",
+ "nurbs_weight"});
+
+ auto trim_catmull = [&](const IndexMask selection) {
+ trim_catmull_rom_curves(src_curves,
+ dst_curves,
+ selection,
+ start_points,
+ end_points,
+ src_ranges,
+ transfer_attributes);
+ };
+ auto trim_poly = [&](const IndexMask selection) {
+ trim_polygonal_curves(src_curves,
+ dst_curves,
+ selection,
+ start_points,
+ end_points,
+ src_ranges,
+ transfer_attributes);
+ };
+ auto trim_bezier = [&](const IndexMask selection) {
+ trim_bezier_curves(src_curves,
+ dst_curves,
+ selection,
+ start_points,
+ end_points,
+ src_ranges,
+ transfer_attributes);
+ };
+ auto trim_evaluated = [&](const IndexMask selection) {
+ /* Ensure evaluated positions are available. */
+ src_curves.ensure_evaluated_offsets();
+ src_curves.evaluated_positions();
+ trim_evaluated_curves(src_curves,
+ dst_curves,
+ selection,
+ start_points,
+ end_points,
+ src_ranges,
+ transfer_attributes);
+ };
+
+ /* Populate point domain. */
+ bke::curves::foreach_curve_by_type(src_curves.curve_types(),
+ src_curves.curve_type_counts(),
+ selection,
+ trim_catmull,
+ trim_poly,
+ trim_bezier,
+ trim_evaluated);
+
+ /* Cleanup/close context */
+ for (bke::AttributeTransferData &attribute : transfer_attributes) {
+ attribute.dst.finish();
+ }
+
+ /* Copy unselected */
+ if (!inverse_selection.is_empty()) {
+ transfer_curve_skip.remove("cyclic");
+ bke::copy_attribute_domain(
+ src_attributes, dst_attributes, inverse_selection, ATTR_DOMAIN_CURVE, transfer_curve_skip);
+ /* Trim curves are no longer cyclic. If all curves are trimmed, this will be set implicitly. */
+ dst_curves.cyclic_for_write().fill_indices(selection, false);
+
+ Set<std::string> copy_point_skip;
+ if (!dst_curves.has_curve_with_type(CURVE_TYPE_NURBS) &&
+ src_curves.has_curve_with_type(CURVE_TYPE_NURBS)) {
+ copy_point_skip.add("nurbs_weight");
+ }
+
+ /* Copy point domain. */
+ for (auto &attribute : bke::retrieve_attributes_for_transfer(
+ src_attributes, dst_attributes, ATTR_DOMAIN_MASK_POINT, copy_point_skip)) {
+ bke::curves::copy_point_data(
+ src_curves, dst_curves, inverse_selection, attribute.src, attribute.dst.span);
+ attribute.dst.finish();
+ }
+ }
+
+ dst_curves.tag_topology_changed();
+ return dst_curves;
+}
+
+/** \} */
+
+} // namespace blender::geometry
diff --git a/source/blender/geometry/intern/uv_parametrizer.cc b/source/blender/geometry/intern/uv_parametrizer.cc
index f074febe23a..070703f5228 100644
--- a/source/blender/geometry/intern/uv_parametrizer.cc
+++ b/source/blender/geometry/intern/uv_parametrizer.cc
@@ -22,11 +22,11 @@
/* Utils */
#define param_assert(condition) \
- if (!(condition)) { /*printf("Assertion %s:%d\n", __FILE__, __LINE__); abort();*/ \
+ if (!(condition)) { /* `printf("Assertion %s:%d\n", __FILE__, __LINE__); abort();` */ \
} \
(void)0
#define param_warning(message) \
- {/*printf("Warning %s:%d: %s\n", __FILE__, __LINE__, message);*/}(void)0
+ {/* `printf("Warning %s:%d: %s\n", __FILE__, __LINE__, message);` */}(void)0
/* Special Purpose Hash */
@@ -195,7 +195,7 @@ static int PHashSizes[] = {
1048583, 2097169, 4194319, 8388617, 16777259, 33554467, 67108879, 134217757, 268435459,
};
-#define PHASH_hash(ph, item) (((uintptr_t)(item)) % ((uint)(ph)->cursize))
+#define PHASH_hash(ph, item) (uintptr_t(item) % uint((ph)->cursize))
#define PHASH_edge(v1, v2) (((v1) < (v2)) ? ((v1)*39) ^ ((v2)*31) : ((v1)*31) ^ ((v2)*39))
static PHash *phash_new(PHashLink **list, int sizehint)
@@ -319,7 +319,7 @@ static void fix_large_angle(const float v_fix[3],
float *r_a1,
float *r_a2)
{
- const float max_angle = (float)M_PI * (179.0f / 180.0f);
+ const float max_angle = float(M_PI) * (179.0f / 180.0f);
const float fix_amount = *r_fix - max_angle;
if (fix_amount < 0.0f) {
return; /* angle is reasonable, i.e. less than 179 degrees. */
@@ -1903,7 +1903,7 @@ static bool p_collapse_allowed_geometric(PEdge *edge, PEdge *pair)
if (p_vert_interior(oldv)) {
/* HLSCM criterion: angular defect smaller than threshold. */
- if (fabsf(angulardefect) > (float)(M_PI * 30.0 / 180.0)) {
+ if (fabsf(angulardefect) > float(M_PI * 30.0 / 180.0)) {
return false;
}
}
@@ -2465,7 +2465,7 @@ static float p_abf_compute_gradient(PAbfSystem *sys, PChart *chart)
norm += galpha1 * galpha1 + galpha2 * galpha2 + galpha3 * galpha3;
- gtriangle = sys->alpha[e1->u.id] + sys->alpha[e2->u.id] + sys->alpha[e3->u.id] - (float)M_PI;
+ gtriangle = sys->alpha[e1->u.id] + sys->alpha[e2->u.id] + sys->alpha[e3->u.id] - float(M_PI);
sys->bTriangle[f->u.id] = -gtriangle;
norm += gtriangle * gtriangle;
}
@@ -2696,8 +2696,8 @@ static bool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
/* clamp */
PEdge *e = f->edge;
do {
- if (sys->alpha[e->u.id] > (float)M_PI) {
- sys->alpha[e->u.id] = (float)M_PI;
+ if (sys->alpha[e->u.id] > float(M_PI)) {
+ sys->alpha[e->u.id] = float(M_PI);
}
else if (sys->alpha[e->u.id] < 0.0f) {
sys->alpha[e->u.id] = 0.0f;
@@ -2706,8 +2706,8 @@ static bool p_abf_matrix_invert(PAbfSystem *sys, PChart *chart)
}
for (int i = 0; i < ninterior; i++) {
- sys->lambdaPlanar[i] += (float)EIG_linear_solver_variable_get(context, 0, i);
- sys->lambdaLength[i] += (float)EIG_linear_solver_variable_get(context, 0, ninterior + i);
+ sys->lambdaPlanar[i] += float(EIG_linear_solver_variable_get(context, 0, i));
+ sys->lambdaLength[i] += float(EIG_linear_solver_variable_get(context, 0, ninterior + i));
}
}
@@ -2780,7 +2780,7 @@ static bool p_chart_abf_solve(PChart *chart)
e = e->next->next->pair;
} while (e && (e != v->edge));
- scale = (anglesum == 0.0f) ? 0.0f : 2.0f * (float)M_PI / anglesum;
+ scale = (anglesum == 0.0f) ? 0.0f : 2.0f * float(M_PI) / anglesum;
e = v->edge;
do {
@@ -3061,7 +3061,7 @@ static void p_chart_lscm_begin(PChart *chart, bool live, bool abf)
}
}
- if ((live && (!select || !deselect))) {
+ if (live && (!select || !deselect)) {
chart->u.lscm.context = nullptr;
}
else {
@@ -3409,7 +3409,7 @@ static void p_chart_stretch_minimize(PChart *chart, RNG *rng)
trusted_radius /= 2 * nedges;
- random_angle = BLI_rng_get_float(rng) * 2.0f * (float)M_PI;
+ random_angle = BLI_rng_get_float(rng) * 2.0f * float(M_PI);
dir[0] = trusted_radius * cosf(random_angle);
dir[1] = trusted_radius * sinf(random_angle);
@@ -3588,7 +3588,7 @@ static float p_chart_minimum_area_angle(PChart *chart)
p2 = points[i];
p3 = (i == npoints - 1) ? points[0] : points[i + 1];
- angles[i] = (float)M_PI - p_vec2_angle(p1->uv, p2->uv, p3->uv);
+ angles[i] = float(M_PI) - p_vec2_angle(p1->uv, p2->uv, p3->uv);
if (points[i]->uv[1] < miny) {
miny = points[i]->uv[1];
@@ -3628,7 +3628,7 @@ static float p_chart_minimum_area_angle(PChart *chart)
minarea = 1e10;
minangle = 0.0;
- while (rotated <= (float)M_PI_2) { /* INVESTIGATE: how far to rotate? */
+ while (rotated <= float(M_PI_2)) { /* INVESTIGATE: how far to rotate? */
/* rotate with the smallest angle */
i_min = 0;
mina = 1e10;
@@ -3675,8 +3675,8 @@ static float p_chart_minimum_area_angle(PChart *chart)
}
/* try keeping rotation as small as possible */
- if (minangle > (float)M_PI_4) {
- minangle -= (float)M_PI_2;
+ if (minangle > float(M_PI_4)) {
+ minangle -= float(M_PI_2);
}
MEM_freeN(angles);
@@ -3869,9 +3869,9 @@ static void p_add_ngon(ParamHandle *handle,
Heap *heap = handle->polyfill_heap;
uint nfilltri = nverts - 2;
uint(*tris)[3] = static_cast<uint(*)[3]>(
- BLI_memarena_alloc(arena, sizeof(*tris) * (size_t)nfilltri));
+ BLI_memarena_alloc(arena, sizeof(*tris) * size_t(nfilltri)));
float(*projverts)[2] = static_cast<float(*)[2]>(
- BLI_memarena_alloc(arena, sizeof(*projverts) * (size_t)nverts));
+ BLI_memarena_alloc(arena, sizeof(*projverts) * size_t(nverts)));
/* Calc normal, flipped: to get a positive 2d cross product. */
float normal[3];
@@ -4209,7 +4209,7 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle,
box->index = i; /* Warning this index skips chart->has_pins boxes. */
if (margin > 0.0f) {
- area += (double)sqrtf(box->w * box->h);
+ area += double(sqrtf(box->w * box->h));
}
}
@@ -4218,7 +4218,7 @@ void GEO_uv_parametrizer_pack(ParamHandle *handle,
* ...Without using the area running pack multiple times also gives a bad feedback loop.
* multiply by 0.1 so the margin value from the UI can be from
* 0.0 to 1.0 but not give a massive margin */
- margin = (margin * (float)area) * 0.1f;
+ margin = (margin * float(area)) * 0.1f;
unpacked = 0;
for (i = 0; i < handle->ncharts; i++) {
chart = handle->charts[i];
@@ -4342,7 +4342,7 @@ void GEO_uv_parametrizer_average(ParamHandle *phandle,
/* Compute correction transform. */
float t[2][2];
t[0][0] = scale_factor_u;
- t[1][0] = clamp_f((float)(scale_cross / weight_sum), -0.5f, 0.5f);
+ t[1][0] = clamp_f(float(scale_cross / weight_sum), -0.5f, 0.5f);
t[0][1] = 0;
t[1][1] = 1.0f / scale_factor_u;