Source code for lacecore._group_map

import numpy as np
import vg


[docs]class GroupMap: """ An immutable map of groups of elements, which are allowed to overlap. These can be used for face or vertex groups, as in the Wavefront OBJ standard. Args: num_elements (int): The total number of elements. This determines the length of the masks. group_names (list): The names of the groups. masks (np.array): A boolean array with a row containing a boolean mask for each group. See also: http://paulbourke.net/dataformats/obj/ """ def __init__(self, num_elements, group_names, masks, copy_masks=False): if not isinstance(num_elements, int) or num_elements < 0: raise ValueError("num_elements should be a non-negative integer") if not all(isinstance(group_name, str) for group_name in group_names): raise ValueError("group_names should be a list of strings") vg.shape.check(locals(), "masks", (len(group_names), num_elements)) if masks.dtype != np.bool: raise ValueError("Expected masks to be a bool array") if copy_masks: masks = masks.copy() masks.setflags(write=False) self._num_elements = num_elements self._masks = masks self._group_names = {k: i for i, k in enumerate(group_names)}
[docs] @classmethod def from_dict(cls, group_data, num_elements): """ Create a group map from a dictionary of elements. The keys are the group names and the values are lists of element indices. Args: group_data (dict): The group data. num_elements (int): The total number of elements. """ masks = np.zeros((len(group_data), num_elements), dtype=np.bool) for i, element_indices in enumerate(group_data.values()): try: masks[i][element_indices] = True except IndexError: raise ValueError( "Element indices should be less than {}".format(num_elements) ) return cls( num_elements=num_elements, group_names=group_data.keys(), masks=masks, copy_masks=False, )
[docs] def __len__(self): """ Get the number of groups. Returns: int: The number of groups. """ return len(self._group_names)
[docs] def __iter__(self): """ Iterate over the groups. Returns: list_iterator: An iterator over the groups. """ return iter(self._group_names)
[docs] def __getitem__(self, group_name): """ Get the read-only mask for the requested group. Args: group_name (string): The desired group. Returns: np.array: A read-only boolean array with length equal to `self.num_elements`. """ try: index = self._group_names[group_name] except KeyError: raise KeyError("Unknown group: {}".format(group_name)) return self._masks[index]
[docs] def keys(self): """ Get the names of all the groups. Returns: list: A list of the group names. """ return list(self._group_names)
@property def num_elements(self): return self._num_elements
[docs] def union(self, *group_names): """ Construct the union of the requested groups and return it as a writable mask. Args: group_names (list): The requested groups. Returns: np.array: A boolean mask with length equal to `self.num_elements`. """ indices = [] invalid_group_names = [] for group_name in group_names: try: indices.append(self._group_names[group_name]) except KeyError: invalid_group_names.append(group_name) if len(invalid_group_names): raise KeyError("Unknown groups: {}".format(", ".join(invalid_group_names))) return np.any(self._masks[indices], axis=0)