diff options
Diffstat (limited to 'source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc')
-rw-r--r-- | source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc | 89 |
1 files changed, 89 insertions, 0 deletions
diff --git a/source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc b/source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc new file mode 100644 index 00000000000..88cccfb2f94 --- /dev/null +++ b/source/blender/nodes/geometry/nodes/node_geo_mesh_face_set_boundaries.cc @@ -0,0 +1,89 @@ +/* SPDX-License-Identifier: GPL-2.0-or-later */ + +#include "DNA_mesh_types.h" +#include "DNA_meshdata_types.h" + +#include "BKE_mesh.h" + +#include "node_geometry_util.hh" + +namespace blender::nodes::node_geo_mesh_face_set_boundaries_cc { + +static void node_declare(NodeDeclarationBuilder &b) +{ + b.add_input<decl::Int>(N_("Face Set")) + .default_value(0) + .hide_value() + .supports_field() + .description(N_("An identifier for the group of each face. All contiguous faces with the " + "same value are in the same region")); + b.add_output<decl::Bool>(N_("Boundary Edges")) + .field_source() + .description(N_("The edges that lie on the boundaries between the different face sets")); +} + +class BoundaryFieldInput final : public bke::MeshFieldInput { + private: + const Field<int> face_set; + + public: + BoundaryFieldInput(const Field<int> face_set) + : bke::MeshFieldInput(CPPType::get<bool>(), "Boundary Field"), face_set(face_set) + { + category_ = Category::Generated; + } + + GVArray get_varray_for_context(const Mesh &mesh, + const eAttrDomain domain, + const IndexMask /*mask*/) const final + { + const bke::MeshFieldContext face_context{mesh, ATTR_DOMAIN_FACE}; + FieldEvaluator face_evaluator{face_context, mesh.totpoly}; + face_evaluator.add(face_set); + face_evaluator.evaluate(); + const VArray<int> face_set = face_evaluator.get_evaluated<int>(0); + + Array<bool> boundary(mesh.totedge, false); + Array<bool> edge_visited(mesh.totedge, false); + Array<int> edge_face_set(mesh.totedge, 0); + const Span<MPoly> polys = mesh.polys(); + const Span<MLoop> loops = mesh.loops(); + for (const int i : polys.index_range()) { + const MPoly &poly = polys[i]; + for (const MLoop &loop : loops.slice(poly.loopstart, poly.totloop)) { + const int edge = loop.e; + if (edge_visited[edge]) { + if (edge_face_set[edge] != face_set[i]) { + /* This edge is connected to two faces on different face sets. */ + boundary[edge] = true; + } + } + edge_visited[edge] = true; + edge_face_set[edge] = face_set[i]; + } + } + return mesh.attributes().adapt_domain<bool>( + VArray<bool>::ForContainer(std::move(boundary)), ATTR_DOMAIN_EDGE, domain); + } +}; + +static void node_geo_exec(GeoNodeExecParams params) +{ + const Field<int> face_set_field = params.extract_input<Field<int>>("Face Set"); + Field<bool> face_set_boundaries{std::make_shared<BoundaryFieldInput>(face_set_field)}; + params.set_output("Boundary Edges", std::move(face_set_boundaries)); +} + +} // namespace blender::nodes::node_geo_mesh_face_set_boundaries_cc + +void register_node_type_geo_mesh_face_set_boundaries() +{ + namespace file_ns = blender::nodes::node_geo_mesh_face_set_boundaries_cc; + + static bNodeType ntype; + geo_node_type_base( + &ntype, GEO_NODE_MESH_FACE_SET_BOUNDARIES, "Face Set Boundaries", NODE_CLASS_INPUT); + ntype.declare = file_ns::node_declare; + ntype.geometry_node_execute = file_ns::node_geo_exec; + nodeRegisterType(&ntype); +} |