Source code for blenderproc.python.modules.provider.getter.Attribute

import mathutils
import numpy as np

from blenderproc.python.modules.main.Provider import Provider
from blenderproc.python.types.MeshObjectUtility import MeshObject


[docs]class Attribute(Provider): """ Returns a value that is the result of selecting entities using getter.Entity Provider, getting the list of values of selected entities' attributes/custom properties/custom-processed data, and of the optional operations on this list. Example 1: Get a list of locations of objects (which names match the pattern). .. code-block:: yaml { "provider": "getter.Attribute", "entities": { "provider": "getter.Entity", "conditions": { "name": "Icosphere.*" } }, "get": "location" # add "transform_by": "sum" to get one value that represents the sum of those locations. } Example 2: Get a list of custom property "id" values of objects (which "physics" cp value is True). .. code-block:: yaml { "provider": "getter.Attribute", "entities": { "provider": "getter.Entity", "conditions": { "cp_physics": "True" } }, "get": "cp_id" } Example 3: Get a list of mean coordinates of objects (which name matches the pattern) bounding boxes. .. code-block:: yaml { "provider": "getter.Attribute", "entities": { "provider": "getter.Entity", "conditions": { "name": "Cube.*" } }, "get": "cf_bounding_box_means" # add "transform_by": "avg" to get one value that represents the average coordinates of those bounding boxes } **Configuration**: .. list-table:: :widths: 25 100 10 :header-rows: 1 * - Parameter - Description - Type * - entities - List of objects selected by the getter.Entity Provider. - list * - get - Attribute/Custom property/custom function name on which the return value is based. Must be a valid name of selected entities' attribute/custom property, or a custom function name. Every entity selected must have this attribute, custom prop, or must be usable in a custom function, otherwise an exception will be thrown. " In order to specify, what exactly one wants to get (e.g. attribute, custom property, etc.): For attribute: key of the pair must be a valid attribute name of the all selected entities. For custom property: key of the pair must start with `cp_` prefix. For calling custom function: key of the pair must start with `cf_` prefix. See table below for supported custom function names. - string * - transform_by - Name of the operation to perform on the list of attributes/custom property/custom data values. See table below for supported operation names. - string. * - index - If set, after the conditions are applied only the corresponding value of entity with the specified index is returned. - int **Custom functions**: .. list-table:: :widths: 25 100 10 :header-rows: 1 * - Parameter - Description - Type * - cf_bounding_box_means - Custom function name for `get` parameter. Invokes a chain of operations which returns a list of arithmetic means of coordinates of object aligned bounding boxes' of selected objects in world coordinates format. (return). - list **Operations**: .. list-table:: :widths: 25 100 10 :header-rows: 1 * - Parameter - Description - Type * - sum - Returns the sum of all values of the input list. (return). - float * - avg - Returns the average value of all values of the input list. (return). - float """ def __init__(self, config): Provider.__init__(self, config)
[docs] def run(self): """ Selects objects, gets a list of appropriate values of objects' attributes, custom properties, or some processed custom data and optionally performs some operation of this list. :return: List of values (only if `get` was specified or a custom function was called) or a singular int, float, or mathutils.Vector value (if some operation was applied). """ objects = self.config.get_list("entities") look_for = self.config.get_string("get") cp_search = False cf_search = False if look_for.startswith('cp_'): look_for = look_for[3:] cp_search = True elif look_for.startswith('cf_'): look_for = look_for[3:] cf_search = True raw_result = [] for obj in objects: if hasattr(obj, look_for) and not cp_search: raw_result.append(getattr(obj, look_for)) elif look_for in obj and cp_search: raw_result.append(obj[look_for]) elif look_for == "bounding_box_means" and cf_search: bb_mean = np.mean(MeshObject(obj).get_bound_box(), axis=0) raw_result.append(mathutils.Vector(bb_mean)) else: raise RuntimeError("Unknown parameter name: " + look_for) if self.config.has_param("transform_by"): transform_by = self.config.get_string("transform_by") if self._check_compatibility(raw_result): if transform_by == "sum": ref_result = self._sum(raw_result) elif transform_by == "avg": ref_result = self._avg(raw_result) else: raise RuntimeError("Unknown transform_by: " + transform_by) else: raise RuntimeError("Performing " + str(transform_by) + " on " + str(look_for) + " " + str(type(raw_result[0])) + " type is not allowed!") result = ref_result else: result = raw_result if self.config.has_param("index"): result = result[self.config.get_int("index")] return result
[docs] def _check_compatibility(self, raw_result): """ Checks if the list of values contains appropriate data of int, float, or mathutils.Vector type. :param raw_result: list of selected objects' attribute/custom prop./or custom data values. Type: List :return: True if list is of int (and or) float, or mathutils.Vector data type. False if not. Type: bool. """ return any([all(isinstance(item, mathutils.Vector) for item in raw_result), all(isinstance(item, (float, int)) for item in raw_result)])
[docs] def _sum(self, raw_result): """ Sums up the values of the list. :return: The sum of all values of the input list. """ ref_result = raw_result[0].copy() for item in raw_result[1:]: ref_result += item return ref_result
[docs] def _avg(self, raw_result): """ Sums up the values of the list and divides the sum by the amount of items in the list. :return: The average value of all values of the input list. """ ref_result = self._sum(raw_result) ref_result = ref_result/float(len(raw_result)) return ref_result