18 "The shortest angle in radians between two faces where they meet at an edge. Flat edges "
19 "and Non-manifold edges have an angle of zero. Computing this value is faster than the "
24 "The signed angle in radians between two faces where they meet at an edge. Flat edges "
25 "and Non-manifold edges have an angle of zero. Concave angles are positive and convex "
26 "angles are negative. Computing this value is slower than the unsigned angle");
37 const int total_edges)
41 for (
const int i_face : faces.index_range()) {
42 for (
const int edge : corner_edges.
slice(faces[i_face])) {
64 const AttrDomain domain,
69 const Span<int> corner_verts = mesh.corner_verts();
70 const Span<int> corner_edges = mesh.corner_edges();
74 [edge_map = std::move(edge_map), positions,
faces, corner_verts](
const int i) ->
float {
75 if (edge_map[i].face_count != 2) {
78 const IndexRange face_1 = faces[edge_map[i].face_index_1];
79 const IndexRange face_2 = faces[edge_map[i].face_index_2];
86 return mesh.attributes().adapt_domain<
float>(std::move(angles), AttrDomain::Edge, domain);
102 return AttrDomain::Edge;
114 const AttrDomain domain,
120 const Span<int> corner_verts = mesh.corner_verts();
121 const Span<int> corner_edges = mesh.corner_edges();
124 auto angle_fn = [edge_map = std::move(edge_map), positions, edges,
faces, corner_verts](
125 const int i) ->
float {
126 if (edge_map[i].face_count != 2) {
129 const IndexRange face_1 = faces[edge_map[i].face_index_1];
130 const IndexRange face_2 = faces[edge_map[i].face_index_2];
134 corner_verts.
slice(face_1));
136 corner_verts.
slice(face_2));
139 const float3 edge_centerpoint = (positions[edges[i][0]] + positions[edges[i][1]]) * 0.5f;
144 corner_verts.
slice(face_2));
146 const float concavity =
math::dot(face_1_normal, face_2_tangent);
151 if (angle == 0.0f || angle == 2.0f *
M_PI || concavity < 0) {
158 return mesh.attributes().adapt_domain<
float>(std::move(angles), AttrDomain::Edge, domain);
174 return AttrDomain::Edge;
180 if (
params.output_is_required(
"Unsigned Angle")) {
181 Field<float> angle_field{std::make_shared<AngleFieldInput>()};
182 params.set_output(
"Unsigned Angle", std::move(angle_field));
184 if (
params.output_is_required(
"Signed Angle")) {
185 Field<float> angle_field{std::make_shared<SignedAngleFieldInput>()};
186 params.set_output(
"Signed Angle", std::move(angle_field));
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)
constexpr Span slice(int64_t start, int64_t size) const
static VArray ForFunc(const int64_t size, GetFunc get_func)
local_group_size(16, 16) .push_constant(Type b
draw_view in_light_buf[] float
float3 face_normal_calc(Span< float3 > vert_positions, Span< int > face_verts)
float3 face_center_calc(Span< float3 > vert_positions, Span< int > face_verts)
void node_register_type(bNodeType *ntype)
T dot(const QuaternionBase< T > &a, const QuaternionBase< T > &b)
MatBase< T, NumCol, NumRow > normalize(const MatBase< T, NumCol, NumRow > &a)
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
unsigned __int64 uint64_t
NodeGeometryExecFunction geometry_node_execute
NodeDeclareFunction declare