25 const bNode *node =
b.node_or_null();
30 if (node !=
nullptr) {
32 b.add_input(data_type,
"Attribute").hide_value().field_on_all();
34 b.add_output(data_type,
N_(
"Mean"));
35 b.add_output(data_type,
N_(
"Median"));
36 b.add_output(data_type,
N_(
"Sum"));
37 b.add_output(data_type,
N_(
"Min"));
38 b.add_output(data_type,
N_(
"Max"));
39 b.add_output(data_type,
N_(
"Range"));
40 b.add_output(data_type,
N_(
"Standard Deviation"));
41 b.add_output(data_type,
N_(
"Variance"));
59 switch (socket.
type) {
88 params.update_and_connect_available_socket(node,
"Attribute");
93 {
"Mean",
"Median",
"Sum",
"Min",
"Max",
"Range",
"Standard Deviation",
"Variance"})
96 bNode &node = params.add_node(node_type);
98 params.update_and_connect_available_socket(node, name);
106 return std::accumulate(
data.begin(),
data.end(),
T());
111 if (
data.size() <= 1) {
115 float sum_of_squared_differences = std::accumulate(
116 data.begin(),
data.end(), 0.0f, [mean](
float accumulator,
float value) {
117 float difference = mean - value;
118 return accumulator + difference * difference;
121 return sum_of_squared_differences /
data.size();
126 if (
data.is_empty()) {
130 const float median =
data[
data.size() / 2];
133 if (
data.size() % 2 == 0) {
134 return (median +
data[
data.size() / 2 - 1]) * 0.5f;
154 const std::optional<AttributeAccessor> attributes = component->attributes();
155 if (!attributes.has_value()) {
158 if (attributes->domain_supported(domain)) {
161 data_evaluator.
add(input_field);
167 const int next_data_index =
data.size();
181 float standard_deviation = 0.0f;
182 float variance = 0.0f;
183 const bool sort_required =
params.output_is_required(
"Min") ||
184 params.output_is_required(
"Max") ||
185 params.output_is_required(
"Range") ||
186 params.output_is_required(
"Median");
187 const bool sum_required =
params.output_is_required(
"Sum") ||
188 params.output_is_required(
"Mean");
189 const bool variance_required =
params.output_is_required(
"Standard Deviation") ||
190 params.output_is_required(
"Variance");
192 if (
data.size() != 0) {
194 std::sort(
data.begin(),
data.end());
201 if (sum_required || variance_required) {
205 if (variance_required) {
207 standard_deviation = std::sqrt(variance);
214 params.set_output(
"Mean", mean);
219 params.set_output(
"Range", range);
220 params.set_output(
"Median", median);
222 if (variance_required) {
223 params.set_output(
"Standard Deviation", standard_deviation);
224 params.set_output(
"Variance", variance);
232 const std::optional<AttributeAccessor> attributes = component->attributes();
233 if (!attributes.has_value()) {
236 if (attributes->domain_supported(domain)) {
239 data_evaluator.
add(input_field);
245 const int next_data_index =
data.size();
260 float3 standard_deviation{0};
261 const bool sort_required =
params.output_is_required(
"Min") ||
262 params.output_is_required(
"Max") ||
263 params.output_is_required(
"Range") ||
264 params.output_is_required(
"Median");
265 const bool sum_required =
params.output_is_required(
"Sum") ||
266 params.output_is_required(
"Mean");
267 const bool variance_required =
params.output_is_required(
"Standard Deviation") ||
268 params.output_is_required(
"Variance");
273 if (sort_required || variance_required) {
277 for (
const int i :
data.index_range()) {
278 data_x[i] =
data[i].x;
279 data_y[i] =
data[i].y;
280 data_z[i] =
data[i].z;
284 if (
data.size() != 0) {
286 std::sort(data_x.
begin(), data_x.
end());
287 std::sort(data_y.
begin(), data_y.
end());
288 std::sort(data_z.
begin(), data_z.
end());
293 median =
float3(x_median, y_median, z_median);
299 if (sum_required || variance_required) {
303 if (variance_required) {
307 variance =
float3(x_variance, y_variance, z_variance);
308 standard_deviation =
float3(
309 std::sqrt(variance.x), std::sqrt(variance.y), std::sqrt(variance.z));
316 params.set_output(
"Mean", mean);
321 params.set_output(
"Range", range);
322 params.set_output(
"Median", median);
324 if (variance_required) {
325 params.set_output(
"Standard Deviation", standard_deviation);
326 params.set_output(
"Variance", variance);
341 "The data type the attribute is converted to before calculating the results",
355 "Which domain to read the data from",
358 int(AttrDomain::Point),
#define GEO_NODE_ATTRIBUTE_STATISTIC
#define NODE_CLASS_ATTRIBUTE
#define NOD_REGISTER_NODE(REGISTER_FUNC)
#define NOD_inline_enum_accessors(member)
void uiItemR(uiLayout *layout, PointerRNA *ptr, const char *propname, eUI_Item_Flag flag, const char *name, int icon)
static T sum(const btAlignedObjectArray< T > &items)
const T & last(const int64_t n=0) const
void reinitialize(const int64_t new_size)
void set_selection(Field< bool > selection)
int add(GField field, GVArray *varray_ptr)
IndexMask get_evaluated_selection_as_mask() const
const GVArray & get_evaluated(const int field_index) const
Vector< SocketDeclaration * > inputs
local_group_size(16, 16) .push_constant(Type b
void gather(const GVArray &src, const IndexMask &indices, GMutableSpan dst, int64_t grain_size=4096)
void node_register_type(bNodeType *ntype)
static T compute_sum(const Span< T > data)
static float median_of_sorted_span(const Span< float > data)
static std::optional< eCustomDataType > node_type_from_other_socket(const bNodeSocket &socket)
static void node_rna(StructRNA *srna)
static void node_init(bNodeTree *, bNode *node)
static void node_register()
static void node_declare(NodeDeclarationBuilder &b)
static float compute_variance(const Span< float > data, const float mean)
static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms)
static void node_layout(uiLayout *layout, bContext *, PointerRNA *ptr)
static void node_geo_exec(GeoNodeExecParams params)
void search_link_ops_for_declarations(GatherLinkSearchOpParams ¶ms, Span< SocketDeclaration * > declarations)
PropertyRNA * RNA_def_node_enum(StructRNA *srna, const char *identifier, const char *ui_name, const char *ui_description, const EnumPropertyItem *static_items, const EnumRNAAccessors accessors, std::optional< int > default_value, const EnumPropertyItemFunc item_func, const bool allow_animation)
const EnumPropertyItem * enum_items_filter(const EnumPropertyItem *original_item_array, FunctionRef< bool(const EnumPropertyItem &item)> fn)
VecBase< float, 3 > float3
void geo_node_type_base(blender::bke::bNodeType *ntype, int type, const char *name, short nclass)
GPU_SHADER_INTERFACE_INFO(overlay_edit_curve_handle_iface, "vert").flat(Type pos vertex_in(1, Type::UINT, "data") .vertex_out(overlay_edit_curve_handle_iface) .geometry_layout(PrimitiveIn Frequency::GEOMETRY storage_buf(1, Qualifier::READ, "uint", "data[]", Frequency::GEOMETRY) .push_constant(Type Frequency::GEOMETRY selection[]
const EnumPropertyItem rna_enum_attribute_domain_items[]
const EnumPropertyItem rna_enum_attribute_type_items[]
Vector< const GeometryComponent * > get_components() const
void(* initfunc)(bNodeTree *ntree, bNode *node)
NodeGeometryExecFunction geometry_node_execute
void(* draw_buttons)(uiLayout *, bContext *C, PointerRNA *ptr)
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
NodeDeclareFunction declare