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

node_geo_input_mesh_island.cc « nodes « geometry « nodes « blender « source - git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
blob: bd57924d685c1c8fb45a9ca4463c006e38b4d165 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
/* SPDX-License-Identifier: GPL-2.0-or-later */

#include "DNA_mesh_types.h"
#include "DNA_meshdata_types.h"

#include "BKE_mesh.h"

#include "BLI_disjoint_set.hh"

#include "node_geometry_util.hh"

namespace blender::nodes::node_geo_input_mesh_island_cc {

static void node_declare(NodeDeclarationBuilder &b)
{
  b.add_output<decl::Int>(N_("Island Index"))
      .field_source()
      .description(N_("The index of the each vertex's island. Indices are based on the "
                      "lowest vertex index contained in each island"));
  b.add_output<decl::Int>(N_("Island Count"))
      .field_source()
      .description(N_("The total number of mesh islands"));
}

class IslandFieldInput final : public GeometryFieldInput {
 public:
  IslandFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Island Index")
  {
    category_ = Category::Generated;
  }

  GVArray get_varray_for_context(const GeometryComponent &component,
                                 const eAttrDomain domain,
                                 IndexMask UNUSED(mask)) const final
  {
    if (component.type() != GEO_COMPONENT_TYPE_MESH) {
      return {};
    }
    const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
    const Mesh *mesh = mesh_component.get_for_read();
    if (mesh == nullptr) {
      return {};
    }

    DisjointSet islands(mesh->totvert);
    for (const int i : IndexRange(mesh->totedge)) {
      islands.join(mesh->medge[i].v1, mesh->medge[i].v2);
    }

    Array<int> output(mesh->totvert);
    VectorSet<int> ordered_roots;
    for (const int i : IndexRange(mesh->totvert)) {
      const int64_t root = islands.find_root(i);
      output[i] = ordered_roots.index_of_or_add(root);
    }

    return mesh_component.attribute_try_adapt_domain<int>(
        VArray<int>::ForContainer(std::move(output)), ATTR_DOMAIN_POINT, domain);
  }

  uint64_t hash() const override
  {
    /* Some random constant hash. */
    return 635467354;
  }

  bool is_equal_to(const fn::FieldNode &other) const override
  {
    return dynamic_cast<const IslandFieldInput *>(&other) != nullptr;
  }
};

class IslandCountFieldInput final : public GeometryFieldInput {
 public:
  IslandCountFieldInput() : GeometryFieldInput(CPPType::get<int>(), "Island Count")
  {
    category_ = Category::Generated;
  }

  GVArray get_varray_for_context(const GeometryComponent &component,
                                 const eAttrDomain domain,
                                 IndexMask UNUSED(mask)) const final
  {
    if (component.type() != GEO_COMPONENT_TYPE_MESH) {
      return {};
    }
    const MeshComponent &mesh_component = static_cast<const MeshComponent &>(component);
    const Mesh *mesh = mesh_component.get_for_read();
    if (mesh == nullptr) {
      return {};
    }

    DisjointSet islands(mesh->totvert);
    for (const int i : IndexRange(mesh->totedge)) {
      islands.join(mesh->medge[i].v1, mesh->medge[i].v2);
    }

    Set<int> island_list;
    for (const int i_vert : IndexRange(mesh->totvert)) {
      const int64_t root = islands.find_root(i_vert);
      island_list.add(root);
    }

    return VArray<int>::ForSingle(island_list.size(), mesh_component.attribute_domain_num(domain));
  }

  uint64_t hash() const override
  {
    /* Some random hash. */
    return 45634572457;
  }

  bool is_equal_to(const fn::FieldNode &other) const override
  {
    return dynamic_cast<const IslandCountFieldInput *>(&other) != nullptr;
  }
};

static void node_geo_exec(GeoNodeExecParams params)
{
  if (params.output_is_required("Island Index")) {
    Field<int> field{std::make_shared<IslandFieldInput>()};
    params.set_output("Island Index", std::move(field));
  }
  if (params.output_is_required("Island Count")) {
    Field<int> field{std::make_shared<IslandCountFieldInput>()};
    params.set_output("Island Count", std::move(field));
  }
}

}  // namespace blender::nodes::node_geo_input_mesh_island_cc

void register_node_type_geo_input_mesh_island()
{
  namespace file_ns = blender::nodes::node_geo_input_mesh_island_cc;

  static bNodeType ntype;
  geo_node_type_base(&ntype, GEO_NODE_INPUT_MESH_ISLAND, "Mesh Island", NODE_CLASS_INPUT);
  ntype.declare = file_ns::node_declare;
  ntype.geometry_node_execute = file_ns::node_geo_exec;
  nodeRegisterType(&ntype);
}