Blender V5.0
node_geo_edge_paths_to_selection.cc
Go to the documentation of this file.
1/* SPDX-FileCopyrightText: 2023 Blender Authors
2 *
3 * SPDX-License-Identifier: GPL-2.0-or-later */
4
5#include "DNA_mesh_types.h"
6
7#include "BLI_task.hh"
8
10
12
14{
15 b.add_input<decl::Bool>("Start Vertices").default_value(true).hide_value().supports_field();
16 b.add_input<decl::Int>("Next Vertex Index").default_value(-1).hide_value().supports_field();
17 b.add_output<decl::Bool>("Selection").field_source_reference_all();
18}
19
20static void edge_paths_to_selection(const Mesh &src_mesh,
21 const IndexMask &start_selection,
22 const Span<int> next_indices,
23 MutableSpan<bool> r_edge_selection)
24{
25 Array<bool> vert_selection(src_mesh.verts_num, false);
26
27 const IndexRange vert_range(src_mesh.verts_num);
28 start_selection.foreach_index(GrainSize(2048), [&](const int start_vert) {
29 /* If vertex is selected, all next is already selected too. */
30 for (int current_vert = start_vert; !vert_selection[current_vert];
31 current_vert = next_indices[current_vert])
32 {
33 if (UNLIKELY(!vert_range.contains(current_vert))) {
34 break;
35 }
36 vert_selection[current_vert] = true;
37 }
38 });
39
40 const Span<int2> edges = src_mesh.edges();
41 threading::parallel_for(edges.index_range(), 4096, [&](const IndexRange range) {
42 for (const int i : range) {
43 const int2 edge = edges[i];
44 if (!(vert_selection[edge[0]] && vert_selection[edge[1]])) {
45 continue;
46 }
47 if (edge[0] == next_indices[edge[1]] || edge[1] == next_indices[edge[0]]) {
48 r_edge_selection[i] = true;
49 }
50 }
51 });
52}
53
55 private:
56 Field<bool> start_vertices_;
57 Field<int> next_vertex_;
58
59 public:
61 : bke::MeshFieldInput(CPPType::get<bool>(), "Edge Selection"),
62 start_vertices_(start_verts),
63 next_vertex_(next_vertex)
64 {
66 }
67
69 const AttrDomain domain,
70 const IndexMask & /*mask*/) const final
71 {
72 const bke::MeshFieldContext context{mesh, AttrDomain::Point};
73 fn::FieldEvaluator evaluator{context, mesh.verts_num};
74 evaluator.add(next_vertex_);
75 evaluator.add(start_vertices_);
76 evaluator.evaluate();
77 const VArraySpan<int> next_vert = evaluator.get_evaluated<int>(0);
78 const IndexMask start_verts = evaluator.get_evaluated_as_mask(1);
79 if (start_verts.is_empty()) {
80 return {};
81 }
82
83 Array<bool> selection(mesh.edges_num, false);
84 edge_paths_to_selection(mesh, start_verts, next_vert, selection);
85
86 return mesh.attributes().adapt_domain<bool>(
87 VArray<bool>::from_container(std::move(selection)), AttrDomain::Edge, domain);
88 }
89
90 void for_each_field_input_recursive(FunctionRef<void(const FieldInput &)> fn) const override
91 {
92 start_vertices_.node().for_each_field_input_recursive(fn);
93 next_vertex_.node().for_each_field_input_recursive(fn);
94 }
95
96 uint64_t hash() const override
97 {
98 return get_default_hash(start_vertices_, next_vertex_);
99 }
100
101 bool is_equal_to(const fn::FieldNode &other) const override
102 {
103 if (const PathToEdgeSelectionFieldInput *other_field =
104 dynamic_cast<const PathToEdgeSelectionFieldInput *>(&other))
105 {
106 return other_field->start_vertices_ == start_vertices_ &&
107 other_field->next_vertex_ == next_vertex_;
108 }
109 return false;
110 }
111
112 std::optional<AttrDomain> preferred_domain(const Mesh & /*mesh*/) const override
113 {
114 return AttrDomain::Edge;
115 }
116};
117
119{
120 Field<bool> start_verts = params.extract_input<Field<bool>>("Start Vertices");
121 Field<int> next_vertex = params.extract_input<Field<int>>("Next Vertex Index");
122 Field<bool> selection_field{
123 std::make_shared<PathToEdgeSelectionFieldInput>(start_verts, next_vertex)};
124 params.set_output("Selection", std::move(selection_field));
125}
126
127static void node_register()
128{
129 static blender::bke::bNodeType ntype;
130
131 geo_node_type_base(&ntype, "GeometryNodeEdgePathsToSelection", GEO_NODE_EDGE_PATHS_TO_SELECTION);
132 ntype.ui_name = "Edge Paths to Selection";
133 ntype.ui_description = "Output a selection of edges by following paths across mesh edges";
134 ntype.enum_name_legacy = "EDGE_PATHS_TO_SELECTION";
135 ntype.nclass = NODE_CLASS_INPUT;
136 ntype.declare = node_declare;
137 blender::bke::node_type_size(ntype, 150, 100, 300);
140}
141NOD_REGISTER_NODE(node_register)
142
143} // namespace blender::nodes::node_geo_edge_paths_to_selection_cc
#define NODE_CLASS_INPUT
Definition BKE_node.hh:447
#define GEO_NODE_EDGE_PATHS_TO_SELECTION
#define final(a, b, c)
Definition BLI_hash.h:19
#define UNLIKELY(x)
#define NOD_REGISTER_NODE(REGISTER_FUNC)
unsigned long long int uint64_t
static VArray from_container(ContainerT container)
constexpr bool contains(int64_t value) const
constexpr IndexRange index_range() const
Definition BLI_span.hh:401
FieldInput(const CPPType &type, std::string debug_name="")
Definition field.cc:677
int add(GField field, GVArray *varray_ptr)
Definition field.cc:751
IndexMask get_evaluated_as_mask(int field_index)
Definition field.cc:804
const GVArray & get_evaluated(const int field_index) const
Definition FN_field.hh:448
void foreach_index(Fn &&fn) const
GVArray get_varray_for_context(const Mesh &mesh, const AttrDomain domain, const IndexMask &) const final
void for_each_field_input_recursive(FunctionRef< void(const FieldInput &)> fn) const override
uiWidgetBaseParameters params[MAX_WIDGET_BASE_BATCH]
void node_type_size(bNodeType &ntype, int width, int minwidth, int maxwidth)
Definition node.cc:5384
void node_register_type(bNodeType &ntype)
Definition node.cc:2416
static void edge_paths_to_selection(const Mesh &src_mesh, const IndexMask &start_selection, const Span< int > next_indices, MutableSpan< bool > r_edge_selection)
void parallel_for(const IndexRange range, const int64_t grain_size, const Function &function, const TaskSizeHints &size_hints=detail::TaskSizeHints_Static(1))
Definition BLI_task.hh:93
uint64_t get_default_hash(const T &v, const Args &...args)
Definition BLI_hash.hh:233
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
int verts_num
Defines a node type.
Definition BKE_node.hh:238
std::string ui_description
Definition BKE_node.hh:244
NodeGeometryExecFunction geometry_node_execute
Definition BKE_node.hh:354
const char * enum_name_legacy
Definition BKE_node.hh:247
NodeDeclareFunction declare
Definition BKE_node.hh:362