20 "The shortest angle in radians between two faces where they meet at an edge. Flat edges "
21 "and Non-manifold edges have an angle of zero. Computing this value is faster than the "
26 "The signed angle in radians between two faces where they meet at an edge. Flat edges "
27 "and Non-manifold edges have an angle of zero. Concave angles are positive and convex "
28 "angles are negative. Computing this value is slower than the unsigned angle");
33 const int total_edges)
37 for (
const int i_face :
faces.index_range()) {
38 for (
const int edge : corner_edges.
slice(
faces[i_face])) {
39 int2 &entry = edge_map[edge];
43 else if (entry[1] == -1) {
67 const Span<int> corner_verts = mesh.corner_verts();
68 const Span<int> corner_edges = mesh.corner_edges();
72 [edge_map = std::move(edge_map), positions,
faces, corner_verts](
const int i) ->
float {
73 if (edge_map[
i][0] < 0 || edge_map[
i][1] < 0) {
84 return mesh.attributes().adapt_domain<
float>(std::move(angles), AttrDomain::Edge, domain);
100 return AttrDomain::Edge;
107 const int face_index,
112 const int3 &tri = corner_tris[tri_index];
113 const int3 vert_tri(corner_verts[tri[0]], corner_verts[tri[1]], corner_verts[tri[2]]);
114 if (ordered_edge ==
OrderedEdge(vert_tri[0], vert_tri[1])) {
117 if (ordered_edge ==
OrderedEdge(vert_tri[1], vert_tri[2])) {
120 if (ordered_edge ==
OrderedEdge(vert_tri[2], vert_tri[0])) {
142 const Span<int> corner_verts = mesh.corner_verts();
143 const Span<int> corner_edges = mesh.corner_edges();
144 const Span<int3> corner_tris = mesh.corner_tris();
148 [edge_map = std::move(edge_map), positions, edges,
faces, corner_verts, corner_tris](
149 const int i) ->
float {
150 if (edge_map[
i][0] < 0 || edge_map[
i][1] < 0) {
153 const int face_index_1 = edge_map[
i][0];
154 const int face_index_2 = edge_map[
i][1];
160 corner_verts.
slice(face_1));
162 corner_verts.
slice(face_2));
166 positions[edges[
i][1]]);
171 faces, corner_verts, corner_tris, face_index_2, edges[
i]);
173 const float concavity =
math::dot(face_1_normal, face_2_tangent);
185 return mesh.attributes().adapt_domain<
float>(std::move(angles), AttrDomain::Edge, domain);
201 return AttrDomain::Edge;
207 if (
params.output_is_required(
"Unsigned Angle")) {
208 Field<float> angle_field{std::make_shared<AngleFieldInput>()};
209 params.set_output(
"Unsigned Angle", std::move(angle_field));
211 if (
params.output_is_required(
"Signed Angle")) {
212 Field<float> angle_field{std::make_shared<SignedAngleFieldInput>()};
213 params.set_output(
"Signed Angle", std::move(angle_field));
222 ntype.
ui_description =
"The angle between the normals of connected manifold faces";
#define GEO_NODE_INPUT_MESH_EDGE_ANGLE
#define BLI_assert_unreachable()
float angle_normalized_v3v3(const float v1[3], const float v2[3]) ATTR_WARN_UNUSED_RESULT
static double angle(const Eigen::Vector3d &v1, const Eigen::Vector3d &v2)
#define NOD_REGISTER_NODE(REGISTER_FUNC)
unsigned long long int uint64_t
constexpr Span slice(int64_t start, int64_t size) const
static VArray from_func(const int64_t size, GetFunc get_func)
float3 face_normal_calc(Span< float3 > vert_positions, Span< int > face_verts)
IndexRange face_triangles_range(OffsetIndices< int > faces, int face_i)
void node_register_type(bNodeType &ntype)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
T midpoint(const T &a, const T &b)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
VecBase< int32_t, 2 > int2
VecBase< int32_t, 3 > int3
VecBase< float, 3 > float3
void geo_node_type_base(blender::bke::bNodeType *ntype, std::string idname, const std::optional< int16_t > legacy_type)
std::string ui_description
NodeGeometryExecFunction geometry_node_execute
const char * enum_name_legacy
NodeDeclareFunction declare