20 b.add_input<
decl::Bool>(
N_(
"Selection")).default_value(
true).supports_field().hide_value();
21 b.add_input<
decl::Float>(
N_(
"Attribute")).hide_value().supports_field();
22 b.add_input<
decl::Vector>(
N_(
"Attribute"),
"Attribute_001").hide_value().supports_field();
39 b.add_output<
decl::Vector>(
N_(
"Standard Deviation"),
"Standard Deviation_001");
45 uiItemR(layout,
ptr,
"data_type", 0,
"", ICON_NONE);
46 uiItemR(layout,
ptr,
"domain", 0,
"", ICON_NONE);
105 switch (socket.
type) {
133 params.update_and_connect_available_socket(
node,
"Attribute");
138 {
"Mean",
"Median",
"Sum",
"Min",
"Max",
"Range",
"Standard Deviation",
"Variance"}) {
140 bNode &node = params.add_node(node_type);
141 node.custom1 = *type;
142 params.update_and_connect_available_socket(node, name);
150 return std::accumulate(
data.begin(),
data.end(),
T());
155 if (
data.size() <= 1) {
159 float sum_of_squared_differences = std::accumulate(
160 data.begin(),
data.end(), 0.0f, [mean](
float accumulator,
float value) {
161 float difference = mean - value;
162 return accumulator + difference * difference;
165 return sum_of_squared_differences / (
data.size() - 1);
170 if (
data.is_empty()) {
174 const float median =
data[
data.size() / 2];
177 if (
data.size() % 2 == 0) {
178 return (median +
data[
data.size() / 2 - 1]) * 0.5f;
198 const std::optional<AttributeAccessor> attributes =
component->attributes();
199 if (!attributes.has_value()) {
202 if (attributes->domain_supported(domain)) {
204 const int domain_num = attributes->domain_size(domain);
207 data_evaluator.add(input_field);
208 data_evaluator.set_selection(selection_field);
209 data_evaluator.evaluate();
210 const VArray<float> component_data = data_evaluator.get_evaluated<
float>(0);
211 const IndexMask selection = data_evaluator.get_evaluated_selection_as_mask();
213 const int next_data_index =
data.size();
214 data.resize(next_data_index + selection.size());
217 for (
const int i : selection.index_range()) {
218 selected_data[i] = component_data[selection[i]];
229 float standard_deviation = 0.0f;
230 float variance = 0.0f;
231 const bool sort_required =
params.output_is_required(
"Min") ||
232 params.output_is_required(
"Max") ||
233 params.output_is_required(
"Range") ||
234 params.output_is_required(
"Median");
235 const bool sum_required =
params.output_is_required(
"Sum") ||
236 params.output_is_required(
"Mean");
237 const bool variance_required =
params.output_is_required(
"Standard Deviation") ||
238 params.output_is_required(
"Variance");
240 if (
data.size() != 0) {
249 if (sum_required || variance_required) {
250 sum = compute_sum<float>(
data);
253 if (variance_required) {
255 standard_deviation =
std::sqrt(variance);
262 params.set_output(
"Mean", mean);
267 params.set_output(
"Range", range);
268 params.set_output(
"Median", median);
270 if (variance_required) {
271 params.set_output(
"Standard Deviation", standard_deviation);
272 params.set_output(
"Variance", variance);
280 const std::optional<AttributeAccessor> attributes =
component->attributes();
281 if (!attributes.has_value()) {
284 if (attributes->domain_supported(domain)) {
286 const int domain_num = attributes->domain_size(domain);
289 data_evaluator.add(input_field);
290 data_evaluator.set_selection(selection_field);
291 data_evaluator.evaluate();
293 const IndexMask selection = data_evaluator.get_evaluated_selection_as_mask();
295 const int next_data_index =
data.size();
296 data.resize(
data.size() + selection.size());
299 for (
const int i : selection.index_range()) {
300 selected_data[i] = component_data[selection[i]];
312 float3 standard_deviation{0};
313 const bool sort_required =
params.output_is_required(
"Min_001") ||
314 params.output_is_required(
"Max_001") ||
315 params.output_is_required(
"Range_001") ||
316 params.output_is_required(
"Median_001");
317 const bool sum_required =
params.output_is_required(
"Sum_001") ||
318 params.output_is_required(
"Mean_001");
319 const bool variance_required =
params.output_is_required(
"Standard Deviation_001") ||
320 params.output_is_required(
"Variance_001");
325 if (sort_required || variance_required) {
329 for (
const int i :
data.index_range()) {
330 data_x[i] =
data[i].x;
331 data_y[i] =
data[i].y;
332 data_z[i] =
data[i].z;
336 if (
data.size() != 0) {
345 median =
float3(x_median, y_median, z_median);
351 if (sum_required || variance_required) {
355 if (variance_required) {
359 variance =
float3(x_variance, y_variance, z_variance);
360 standard_deviation =
float3(
368 params.set_output(
"Mean_001", mean);
373 params.set_output(
"Range_001", range);
374 params.set_output(
"Median_001", median);
376 if (variance_required) {
377 params.set_output(
"Standard Deviation_001", standard_deviation);
378 params.set_output(
"Variance_001", variance);
void node_type_update(struct bNodeType *ntype, void(*updatefunc)(struct bNodeTree *ntree, struct bNode *node))
#define GEO_NODE_ATTRIBUTE_STATISTIC
void nodeSetSocketAvailability(struct bNodeTree *ntree, struct bNodeSocket *sock, bool is_available)
void node_type_init(struct bNodeType *ntype, void(*initfunc)(struct bNodeTree *ntree, struct bNode *node))
#define NODE_CLASS_ATTRIBUTE
void nodeRegisterType(struct bNodeType *ntype)
static uint8 component(Color32 c, uint i)
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum type
void uiItemR(uiLayout *layout, struct PointerRNA *ptr, const char *propname, int flag, const char *name, int icon)
void sort(btMatrix3x3 &U, btVector3 &sigma, btMatrix3x3 &V, int t)
Helper function of 3X3 SVD for sorting singular values.
static T sum(const btAlignedObjectArray< T > &items)
const T & last(const int64_t n=0) const
void reinitialize(const int64_t new_size)
Span< SocketDeclarationPtr > inputs() const
static int domain_num(const CurvesGeometry &curves, const eAttrDomain domain)
static T compute_sum(const Span< T > data)
static void node_layout(uiLayout *layout, bContext *UNUSED(C), PointerRNA *ptr)
static float median_of_sorted_span(const Span< float > data)
static void node_init(bNodeTree *UNUSED(tree), bNode *node)
static void node_declare(NodeDeclarationBuilder &b)
static std::optional< eCustomDataType > node_type_from_other_socket(const bNodeSocket &socket)
static float compute_variance(const Span< float > data, const float mean)
static void node_gather_link_searches(GatherLinkSearchOpParams ¶ms)
static void node_update(bNodeTree *ntree, bNode *node)
static void node_geo_exec(GeoNodeExecParams params)
void search_link_ops_for_declarations(GatherLinkSearchOpParams ¶ms, Span< SocketDeclarationPtr > declarations)
vec_base< float, 3 > float3
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
static void node_init(const struct bContext *C, bNodeTree *ntree, bNode *node)
void register_node_type_geo_attribute_statistic()
void geo_node_type_base(bNodeType *ntype, int type, const char *name, short nclass)
blender::Vector< const GeometryComponent * > get_components_for_read() const
struct bNodeSocket * next
NodeGeometryExecFunction geometry_node_execute
NodeGatherSocketLinkOperationsFunction gather_link_search_ops
void(* draw_buttons)(struct uiLayout *, struct bContext *C, struct PointerRNA *ptr)
NodeDeclareFunction declare