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:
authorHans Goudey <h.goudey@me.com>2022-03-18 00:46:58 +0300
committerHans Goudey <h.goudey@me.com>2022-03-18 00:46:58 +0300
commitee2d39b3a74a80eeec9f002d733f3e7e71018191 (patch)
treeda0a12523d25059001b5bfa119732f52438c70bc /source/blender/nodes
parent663bd38ed65eb08013677bab2e581bc384a29efe (diff)
Cleanup: Reorganize duplicate elements file
Use sections to keep all the code for a specific mode together, rather than keeping the attribute duplication separate.
Diffstat (limited to 'source/blender/nodes')
-rw-r--r--source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc530
1 files changed, 289 insertions, 241 deletions
diff --git a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
index 535392fbca7..bfa19bd650e 100644
--- a/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
+++ b/source/blender/nodes/geometry/nodes/node_geo_duplicate_elements.cc
@@ -57,7 +57,7 @@ struct IndexAttributes {
};
/* -------------------------------------------------------------------- */
-/** \name Attribute Copy/Creation Functions
+/** \name Utility Functions
* \{ */
static void gather_attributes_without_id(const GeometrySet &geometry_set,
@@ -181,142 +181,6 @@ static void copy_stable_id_point(const Span<int> offsets,
dst_attribute.save();
}
-/**
- * Copy the stable ids to the first duplicate and create new ids based on a hash of the original id
- * and the duplicate number. This function is used for points when duplicating the edge domain.
- */
-static void copy_stable_id_edges(const Mesh &mesh,
- const IndexMask selection,
- const Span<int> edge_offsets,
- const MeshComponent &src_component,
- MeshComponent &dst_component)
-{
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
- if (!src_attribute) {
- return;
- }
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
- if (!dst_attribute) {
- return;
- }
-
- Span<MEdge> edges(mesh.medge, mesh.totedge);
-
- VArray_Span<int> src{src_attribute.varray.typed<int>()};
- MutableSpan<int> dst = dst_attribute.as_span<int>();
- threading::parallel_for(IndexRange(selection.size()), 1024, [&](IndexRange range) {
- for (const int i_edge : range) {
- const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_edge);
- if (edge_range.size() == 0) {
- continue;
- }
- const MEdge &edge = edges[i_edge];
- const IndexRange vert_range = {edge_range.start() * 2, edge_range.size() * 2};
-
- dst[vert_range[0]] = src[edge.v1];
- dst[vert_range[1]] = src[edge.v2];
- for (const int i_duplicate : IndexRange(1, edge_range.size() - 1)) {
- dst[vert_range[i_duplicate * 2]] = noise::hash(src[edge.v1], i_duplicate);
- dst[vert_range[i_duplicate * 2 + 1]] = noise::hash(src[edge.v2], i_duplicate);
- }
- }
- });
- dst_attribute.save();
-}
-
-/**
- * Copy the stable ids to the first duplicate and create new ids based on a hash of the original id
- * and the duplicate number. This function is used for points when duplicating the face domain.
- *
- * This function could be threaded in the future, but since it is only 1 attribute and the
- * `face->edge->vert` mapping would mean creating a 1/1 mapping to allow for it, is it worth it?
- */
-static void copy_stable_id_faces(const Mesh &mesh,
- const IndexMask selection,
- const Span<int> poly_offsets,
- const Span<int> vert_mapping,
- const MeshComponent &src_component,
- MeshComponent &dst_component)
-{
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
- if (!src_attribute) {
- return;
- }
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
- if (!dst_attribute) {
- return;
- }
-
- VArray_Span<int> src{src_attribute.varray.typed<int>()};
- MutableSpan<int> dst = dst_attribute.as_span<int>();
-
- Span<MPoly> polys(mesh.mpoly, mesh.totpoly);
- int loop_index = 0;
- for (const int i_poly : selection.index_range()) {
- const IndexRange range = range_for_offsets_index(poly_offsets, i_poly);
- if (range.size() == 0) {
- continue;
- }
- const MPoly &source = polys[i_poly];
- for ([[maybe_unused]] const int i_duplicate : IndexRange(range.size())) {
- for ([[maybe_unused]] const int i_loops : IndexRange(source.totloop)) {
- if (i_duplicate == 0) {
- dst[loop_index] = src[vert_mapping[loop_index]];
- }
- else {
- dst[loop_index] = noise::hash(src[vert_mapping[loop_index]], i_duplicate);
- }
- loop_index++;
- }
- }
- }
-
- dst_attribute.save();
-}
-
-/**
- * Copy the stable ids to the first duplicate and create new ids based on a hash of the original id
- * and the duplicate number. In the spline case, copy the entire spline's points to the
- * destination,
- * then loop over the remaining ones point by point, hashing their ids to the new ids.
- */
-static void copy_stable_id_splines(const bke::CurvesGeometry &src_curves,
- const IndexMask selection,
- const Span<int> curve_offsets,
- const CurveComponent &src_component,
- bke::CurvesGeometry &dst_curves,
- CurveComponent &dst_component)
-{
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
- if (!src_attribute) {
- return;
- }
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
- if (!dst_attribute) {
- return;
- }
-
- VArray_Span<int> src{src_attribute.varray.typed<int>()};
- MutableSpan<int> dst = dst_attribute.as_span<int>();
-
- threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
- for (const int i_selection : range) {
- const int i_src_curve = selection[i_selection];
- const Span<int> curve_src = src.slice(src_curves.range_for_curve(i_src_curve));
- const IndexRange duplicates_range = range_for_offsets_index(curve_offsets, i_selection);
- for (const int i_duplicate : IndexRange(duplicates_range.size()).drop_front(1)) {
- const int i_dst_curve = duplicates_range[i_duplicate];
- copy_hashed_ids(
- curve_src, i_duplicate, dst.slice(dst_curves.range_for_curve(i_dst_curve)));
- }
- }
- });
- dst_attribute.save();
-}
-
/* The attributes for the point (also instance) duplicated elements are stored sequentially
* (1,1,1,2,2,2,3,3,3,etc) They can be copied by using a simple offset array. For each domain, if
* elements are ordered differently a custom function is called to copy the attributes.
@@ -357,6 +221,12 @@ static void copy_point_attributes_without_id(GeometrySet &geometry_set,
}
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Splines
+ * \{ */
+
/**
* Copies the attributes for spline duplicates. If copying the spline domain, the attributes are
* copied with an offset fill, otherwise a mapping is used.
@@ -419,118 +289,46 @@ static void copy_spline_attributes_without_id(const GeometrySet &geometry_set,
}
/**
- * Copies the attributes for edge duplicates. If copying the edge domain, the attributes are
- * copied with an offset fill, for point domain a mapping is used.
+ * Copy the stable ids to the first duplicate and create new ids based on a hash of the original id
+ * and the duplicate number. In the spline case, copy the entire spline's points to the
+ * destination,
+ * then loop over the remaining ones point by point, hashing their ids to the new ids.
*/
-static void copy_edge_attributes_without_id(GeometrySet &geometry_set,
- const Span<int> point_mapping,
- const Span<int> offsets,
- const GeometryComponent &src_component,
- GeometryComponent &dst_component)
+static void copy_stable_id_splines(const bke::CurvesGeometry &src_curves,
+ const IndexMask selection,
+ const Span<int> curve_offsets,
+ const CurveComponent &src_component,
+ bke::CurvesGeometry &dst_curves,
+ CurveComponent &dst_component)
{
- Map<AttributeIDRef, AttributeKind> gathered_attributes;
- gather_attributes_without_id(
- geometry_set, GEO_COMPONENT_TYPE_MESH, {}, false, gathered_attributes);
-
- for (const Map<AttributeIDRef, AttributeKind>::Item entry : gathered_attributes.items()) {
- const AttributeIDRef attribute_id = entry.key;
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id);
- if (!src_attribute) {
- continue;
- }
-
- const AttributeDomain out_domain = src_attribute.domain;
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
- src_attribute.varray.type());
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- attribute_id, out_domain, data_type);
- if (!dst_attribute) {
- continue;
- }
- attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
- using T = decltype(dummy);
- VArray_Span<T> src{src_attribute.varray.typed<T>()};
- MutableSpan<T> dst = dst_attribute.as_span<T>();
-
- switch (out_domain) {
- case ATTR_DOMAIN_EDGE:
- threaded_slice_fill<T>(offsets, src, dst);
- break;
- case ATTR_DOMAIN_POINT:
- threaded_mapped_copy<T>(point_mapping, src, dst);
- break;
- default:
- break;
- }
- });
- dst_attribute.save();
+ ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
+ if (!src_attribute) {
+ return;
+ }
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
+ if (!dst_attribute) {
+ return;
}
-}
-
-/**
- * Copies the attributes for face duplicates. If copying the face domain, the attributes are
- * copied with an offset fill, otherwise a mapping is used.
- */
-static void copy_face_attributes_without_id(GeometrySet &geometry_set,
- const Span<int> edge_mapping,
- const Span<int> vert_mapping,
- const Span<int> loop_mapping,
- const Span<int> offsets,
- const GeometryComponent &src_component,
- GeometryComponent &dst_component)
-{
- Map<AttributeIDRef, AttributeKind> gathered_attributes;
- gather_attributes_without_id(
- geometry_set, GEO_COMPONENT_TYPE_MESH, {}, false, gathered_attributes);
-
- for (const Map<AttributeIDRef, AttributeKind>::Item entry : gathered_attributes.items()) {
- const AttributeIDRef attribute_id = entry.key;
- ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id);
- if (!src_attribute) {
- continue;
- }
-
- AttributeDomain out_domain = src_attribute.domain;
- const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
- src_attribute.varray.type());
- OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
- attribute_id, out_domain, data_type);
- if (!dst_attribute) {
- continue;
- }
- attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
- using T = decltype(dummy);
- VArray_Span<T> src{src_attribute.varray.typed<T>()};
- MutableSpan<T> dst = dst_attribute.as_span<T>();
+ VArray_Span<int> src{src_attribute.varray.typed<int>()};
+ MutableSpan<int> dst = dst_attribute.as_span<int>();
- switch (out_domain) {
- case ATTR_DOMAIN_FACE:
- threaded_slice_fill<T>(offsets, src, dst);
- break;
- case ATTR_DOMAIN_EDGE:
- threaded_mapped_copy<T>(edge_mapping, src, dst);
- break;
- case ATTR_DOMAIN_POINT:
- threaded_mapped_copy<T>(vert_mapping, src, dst);
- break;
- case ATTR_DOMAIN_CORNER:
- threaded_mapped_copy<T>(loop_mapping, src, dst);
- break;
- default:
- break;
+ threading::parallel_for(selection.index_range(), 512, [&](IndexRange range) {
+ for (const int i_selection : range) {
+ const int i_src_curve = selection[i_selection];
+ const Span<int> curve_src = src.slice(src_curves.range_for_curve(i_src_curve));
+ const IndexRange duplicates_range = range_for_offsets_index(curve_offsets, i_selection);
+ for (const int i_duplicate : IndexRange(duplicates_range.size()).drop_front(1)) {
+ const int i_dst_curve = duplicates_range[i_duplicate];
+ copy_hashed_ids(
+ curve_src, i_duplicate, dst.slice(dst_curves.range_for_curve(i_dst_curve)));
}
- });
- dst_attribute.save();
- }
+ }
+ });
+ dst_attribute.save();
}
-/** \} */
-
-/* -------------------------------------------------------------------- */
-/** \name Duplication Functions
- * \{ */
-
static void duplicate_splines(GeometrySet &geometry_set,
const Field<int> &count_field,
const Field<bool> &selection_field,
@@ -605,6 +403,121 @@ static void duplicate_splines(GeometrySet &geometry_set,
geometry_set.replace_curves(new_curves_id);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Faces
+ * \{ */
+
+/**
+ * Copies the attributes for face duplicates. If copying the face domain, the attributes are
+ * copied with an offset fill, otherwise a mapping is used.
+ */
+static void copy_face_attributes_without_id(GeometrySet &geometry_set,
+ const Span<int> edge_mapping,
+ const Span<int> vert_mapping,
+ const Span<int> loop_mapping,
+ const Span<int> offsets,
+ const GeometryComponent &src_component,
+ GeometryComponent &dst_component)
+{
+ Map<AttributeIDRef, AttributeKind> gathered_attributes;
+ gather_attributes_without_id(
+ geometry_set, GEO_COMPONENT_TYPE_MESH, {}, false, gathered_attributes);
+
+ for (const Map<AttributeIDRef, AttributeKind>::Item entry : gathered_attributes.items()) {
+ const AttributeIDRef attribute_id = entry.key;
+ ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id);
+ if (!src_attribute) {
+ continue;
+ }
+
+ AttributeDomain out_domain = src_attribute.domain;
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ src_attribute.varray.type());
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ attribute_id, out_domain, data_type);
+ if (!dst_attribute) {
+ continue;
+ }
+
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ VArray_Span<T> src{src_attribute.varray.typed<T>()};
+ MutableSpan<T> dst = dst_attribute.as_span<T>();
+
+ switch (out_domain) {
+ case ATTR_DOMAIN_FACE:
+ threaded_slice_fill<T>(offsets, src, dst);
+ break;
+ case ATTR_DOMAIN_EDGE:
+ threaded_mapped_copy<T>(edge_mapping, src, dst);
+ break;
+ case ATTR_DOMAIN_POINT:
+ threaded_mapped_copy<T>(vert_mapping, src, dst);
+ break;
+ case ATTR_DOMAIN_CORNER:
+ threaded_mapped_copy<T>(loop_mapping, src, dst);
+ break;
+ default:
+ break;
+ }
+ });
+ dst_attribute.save();
+ }
+}
+
+/**
+ * Copy the stable ids to the first duplicate and create new ids based on a hash of the original id
+ * and the duplicate number. This function is used for points when duplicating the face domain.
+ *
+ * This function could be threaded in the future, but since it is only 1 attribute and the
+ * `face->edge->vert` mapping would mean creating a 1/1 mapping to allow for it, is it worth it?
+ */
+static void copy_stable_id_faces(const Mesh &mesh,
+ const IndexMask selection,
+ const Span<int> poly_offsets,
+ const Span<int> vert_mapping,
+ const MeshComponent &src_component,
+ MeshComponent &dst_component)
+{
+ ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
+ if (!src_attribute) {
+ return;
+ }
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
+ if (!dst_attribute) {
+ return;
+ }
+
+ VArray_Span<int> src{src_attribute.varray.typed<int>()};
+ MutableSpan<int> dst = dst_attribute.as_span<int>();
+
+ Span<MPoly> polys(mesh.mpoly, mesh.totpoly);
+ int loop_index = 0;
+ for (const int i_poly : selection.index_range()) {
+ const IndexRange range = range_for_offsets_index(poly_offsets, i_poly);
+ if (range.size() == 0) {
+ continue;
+ }
+ const MPoly &source = polys[i_poly];
+ for ([[maybe_unused]] const int i_duplicate : IndexRange(range.size())) {
+ for ([[maybe_unused]] const int i_loops : IndexRange(source.totloop)) {
+ if (i_duplicate == 0) {
+ dst[loop_index] = src[vert_mapping[loop_index]];
+ }
+ else {
+ dst[loop_index] = noise::hash(src[vert_mapping[loop_index]], i_duplicate);
+ }
+ loop_index++;
+ }
+ }
+ }
+
+ dst_attribute.save();
+}
+
static void duplicate_faces(GeometrySet &geometry_set,
const Field<int> &count_field,
const Field<bool> &selection_field,
@@ -704,6 +617,105 @@ static void duplicate_faces(GeometrySet &geometry_set,
geometry_set.replace_mesh(new_mesh);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Edges
+ * \{ */
+
+/**
+ * Copies the attributes for edge duplicates. If copying the edge domain, the attributes are
+ * copied with an offset fill, for point domain a mapping is used.
+ */
+static void copy_edge_attributes_without_id(GeometrySet &geometry_set,
+ const Span<int> point_mapping,
+ const Span<int> offsets,
+ const GeometryComponent &src_component,
+ GeometryComponent &dst_component)
+{
+ Map<AttributeIDRef, AttributeKind> gathered_attributes;
+ gather_attributes_without_id(
+ geometry_set, GEO_COMPONENT_TYPE_MESH, {}, false, gathered_attributes);
+
+ for (const Map<AttributeIDRef, AttributeKind>::Item entry : gathered_attributes.items()) {
+ const AttributeIDRef attribute_id = entry.key;
+ ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read(attribute_id);
+ if (!src_attribute) {
+ continue;
+ }
+
+ const AttributeDomain out_domain = src_attribute.domain;
+ const CustomDataType data_type = bke::cpp_type_to_custom_data_type(
+ src_attribute.varray.type());
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ attribute_id, out_domain, data_type);
+ if (!dst_attribute) {
+ continue;
+ }
+ attribute_math::convert_to_static_type(data_type, [&](auto dummy) {
+ using T = decltype(dummy);
+ VArray_Span<T> src{src_attribute.varray.typed<T>()};
+ MutableSpan<T> dst = dst_attribute.as_span<T>();
+
+ switch (out_domain) {
+ case ATTR_DOMAIN_EDGE:
+ threaded_slice_fill<T>(offsets, src, dst);
+ break;
+ case ATTR_DOMAIN_POINT:
+ threaded_mapped_copy<T>(point_mapping, src, dst);
+ break;
+ default:
+ break;
+ }
+ });
+ dst_attribute.save();
+ }
+}
+
+/**
+ * Copy the stable ids to the first duplicate and create new ids based on a hash of the original id
+ * and the duplicate number. This function is used for points when duplicating the edge domain.
+ */
+static void copy_stable_id_edges(const Mesh &mesh,
+ const IndexMask selection,
+ const Span<int> edge_offsets,
+ const MeshComponent &src_component,
+ MeshComponent &dst_component)
+{
+ ReadAttributeLookup src_attribute = src_component.attribute_try_get_for_read("id");
+ if (!src_attribute) {
+ return;
+ }
+ OutputAttribute dst_attribute = dst_component.attribute_try_get_for_output_only(
+ "id", ATTR_DOMAIN_POINT, CD_PROP_INT32);
+ if (!dst_attribute) {
+ return;
+ }
+
+ Span<MEdge> edges(mesh.medge, mesh.totedge);
+
+ VArray_Span<int> src{src_attribute.varray.typed<int>()};
+ MutableSpan<int> dst = dst_attribute.as_span<int>();
+ threading::parallel_for(IndexRange(selection.size()), 1024, [&](IndexRange range) {
+ for (const int i_edge : range) {
+ const IndexRange edge_range = range_for_offsets_index(edge_offsets, i_edge);
+ if (edge_range.size() == 0) {
+ continue;
+ }
+ const MEdge &edge = edges[i_edge];
+ const IndexRange vert_range = {edge_range.start() * 2, edge_range.size() * 2};
+
+ dst[vert_range[0]] = src[edge.v1];
+ dst[vert_range[1]] = src[edge.v2];
+ for (const int i_duplicate : IndexRange(1, edge_range.size() - 1)) {
+ dst[vert_range[i_duplicate * 2]] = noise::hash(src[edge.v1], i_duplicate);
+ dst[vert_range[i_duplicate * 2 + 1]] = noise::hash(src[edge.v2], i_duplicate);
+ }
+ }
+ });
+ dst_attribute.save();
+}
+
static void duplicate_edges(GeometrySet &geometry_set,
const Field<int> &count_field,
const Field<bool> &selection_field,
@@ -774,6 +786,12 @@ static void duplicate_edges(GeometrySet &geometry_set,
geometry_set.replace_mesh(new_mesh);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Points (Curves)
+ * \{ */
+
static void duplicate_points_curve(GeometrySet &geometry_set,
const Field<int> &count_field,
const Field<bool> &selection_field,
@@ -871,6 +889,12 @@ static void duplicate_points_curve(GeometrySet &geometry_set,
geometry_set.replace_curves(new_curves_id);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Points (Mesh)
+ * \{ */
+
static void duplicate_points_mesh(GeometrySet &geometry_set,
const Field<int> &count_field,
const Field<bool> &selection_field,
@@ -910,6 +934,12 @@ static void duplicate_points_mesh(GeometrySet &geometry_set,
geometry_set.replace_mesh(new_mesh);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Points (Point Cloud)
+ * \{ */
+
static void duplicate_points_pointcloud(GeometrySet &geometry_set,
const Field<int> &count_field,
const Field<bool> &selection_field,
@@ -945,6 +975,12 @@ static void duplicate_points_pointcloud(GeometrySet &geometry_set,
geometry_set.replace_pointcloud(pointcloud);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Points
+ * \{ */
+
static void duplicate_points(GeometrySet &geometry_set,
const Field<int> &count_field,
const Field<bool> &selection_field,
@@ -976,6 +1012,12 @@ static void duplicate_points(GeometrySet &geometry_set,
geometry_set.keep_only(component_types);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Duplicate Instances
+ * \{ */
+
static void duplicate_instances(GeometrySet &geometry_set,
const Field<int> &count_field,
const Field<bool> &selection_field,
@@ -1030,6 +1072,12 @@ static void duplicate_instances(GeometrySet &geometry_set,
geometry_set = std::move(dst_geometry);
}
+/** \} */
+
+/* -------------------------------------------------------------------- */
+/** \name Entry Point
+ * \{ */
+
static void node_geo_exec(GeoNodeExecParams params)
{
GeometrySet geometry_set = params.extract_input<GeometrySet>("Geometry");