Source code for xamla_motion.data_types.joint_set

# joint_set.py
#
# Copyright (c) 2018, Xamla and/or its affiliates. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation; either version 2
# of the License, or any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.

#!/usr/bin/env python3

from functools import total_ordering
from typing import Iterable


[docs]@total_ordering class JointSet(object): """ Manages a list of unique joint names Methods ------- empty() Creates emtpy JointSet add_prefix(prefix) Creates new JointSet where prefix is added to every joint name is_subset(other) Checks if it is a subset of the JointSet in parameter other is_superset(other) Checks if it is a superset of the JointSet in parameter other is_similar(other) Checks if it contains the same joint names as in JointSet other union(other) Creates new JointSet which contains the union of self and other joints try_get_index_of(name) Tries to get the list index of the joint by name get_index_of(name) Returns the list index of joint name specificed paramerter name contains(name) Checks if this JointSet contains a specific joint name """ def __init__(self, names): """ Initialization of the JointSet class Parameters ---------- names : str or Iterable[str convertable] The Joint set class is initializable in different ways. -by a string which only contains one joint name -by a string which contains multiple joints names separated by a comma as delimiter -Iterable container where each time is convertable to str Returns ------ An instance of class JointSet Raises ------ TypeError : type mismatch If input parameter names is not of type str or Iterable[str convertable] Examples -------- Create an instance of JointSet by string and iterable type >>> from xamla_motion.data_types import JointSet >>> JointSet('Joint1, Joint2') JointSet: Joint1 Joint2 >>> JointSet(['Joint1','Joint2']) JointSet: Joint1 Joint2 >>> JointSet('Joint1,Joint1,Joint2') JointSet: Joint1 Joint2 """ self._names = [] self._names_set = set() if isinstance(names, str): names = map(lambda x: x.strip(), names.split(',')) for name in names: if name not in self._names_set: self._names_set.add(str(name)) self._names.append(str(name)) self._names = tuple(self._names)
[docs] @staticmethod def empty(): """ Creates a empty JointSet Returns ------ JointSet The created empty JointSet Examples -------- Create a empty JointSet instance >>> from xamla_motion.data_types import JointSet >>> JointSet.empty() JointSet: """ joint_set = JointSet('') joint_set.__JointSet__names_set = set() joint_set.__JointSet__names = tuple() return joint_set
@property def names(self): """ names : List[str] (readonly) List of joint names """ return list(self._names)
[docs] def add_prefix(self, prefix): """ Creates new JointSet where prefix is added to every joint name Parameters ---------- prefix : str Defines the prefix which is added in front of every joint name Raises ------ TypeError : type mismatch If input parameter prefix is not of type str Returns ------ JointSet The created JointSet with added prefix to joint names Examples -------- Create new JointSet instance with added prefix >>> from xamla_motion.data_types import JointSet >>> joint_set = JointSet('joint1, joint2') >>> joint_set.add_prefix('robot1_') JointSet: robot1_joint1 robot1_joint2 """ if not isinstance(prefix, str): raise TypeError('prefix expected type is str') names = list(map(lambda x: prefix + x, self._names)) return self.__class__(names)
[docs] def union(self, others): """ Creates new JointSet which contains the union of self and others joints Parameters ---------- others : JointSet or Iterable[JointSet] JointSet with which the union is performed Raises ------ TypeError : type mismatch If others is not one of expected types JointSet or Iterable of JointSet Returns ------ JointSet The created JointSet with union joint names Examples -------- Create new JointSet instance which is the union of two existing ones >>> from xamla_motion.data_types import JointSet >>> joint_set1 = JointSet('joint1, joint2') >>> joint_set2 = JointSet('joint2, joint3') >>> joint_set1.union(joint_set2) JointSet: joint1 joint2 joint3 """ names = list(self._names) names_set = set(self._names_set) if isinstance(others, JointSet): for name in others.names: if name not in self._names_set: names.append(name) elif all(isinstance(i, JointSet) for i in others): for other in others: for name in other.names: if name not in names_set: names.append(name) names_set.add(name) else: raise TypeError('others is not one of expected types' ' JointSet or Iterable of JointSet') return self.__class__(names)
[docs] def intersection(self, others): """ Creates new JointSet which contains the intersection of self and others joints Parameters ---------- others : JointSet or Iterable[JointSet] JointSet with which the union is performed Raises ------ TypeError : type mismatch If others is not one of expected types JointSet or Iterable of JointSet Returns ------ JointSet The created JointSet with intersecting joint names Examples -------- Create new JointSet instance which is the intersection of two existing ones >>> from xamla_motion.data_types import JointSet >>> joint_set1 = JointSet('joint1, joint2') >>> joint_set2 = JointSet('joint2') >>> joint_set1.intersection(joint_set2) JointSet: joint2 """ names = [] if isinstance(others, JointSet): intersection_names = self._names_set.intersection( others._names_set) elif all(isinstance(i, JointSet) for i in others): intersection_names = self._names_set.intersection( o._names_set for o in others) else: raise TypeError('others is not one of expected types' ' JointSet or Iterable of JointSet') for name in self._names: if name in intersection_names: names.append(name) return self.__class__(names)
[docs] def difference(self, others): """ Creates new JointSet which contains the union of self and others joints Parameters ---------- others : JointSet JointSet with which the union is performed Raises ------ TypeError : type mismatch If others is not one of expected type JointSet Returns ------ JointSet The created JointSet with union joint names Examples -------- Create new JointSet instance which is the union of two existing ones >>> from xamla_motion.data_types import JointSet >>> joint_set1 = JointSet('joint1, joint2, joint3') >>> joint_set2 = JointSet('joint1, joint2') >>> joint_set1.difference(joint_set2) JointSet: joint3 """ names = [] if isinstance(others, JointSet): diff = self._names_set.difference(others._names_set) for name in self._names: if name in diff: names.append(name) else: raise TypeError('others is not one of expected types' ' JointSet or Iterable of JointSet') return self.__class__(names)
[docs] def is_subset(self, other): """ Checks if it is a subset of the JointSet in parameter other The method returns True if it is a subset or similar to other. The ordering of the joint names is not checked. Parameters ---------- other : JointSet JointSet which is used for comparision Returns ------- result : bool If this JointSet is a subset of the other JointSet returns True else False Raises ------ TypeError : type mismatch If the parameter other is not of type JointSet Examples -------- Check if one joint set is the subset of another >>> from xamla_motion.data_types import JointSet >>> joint_set1 = JointSet('joint1, joint2, joint3') >>> joint_set2 = JointSet('joint1, joint2') >>> joint_set2.is_subset(joint_set1) True """ if not isinstance(other, self.__class__): raise TypeError('other has not expected type JointSet') return self._names_set.issubset(other._names_set)
[docs] def is_superset(self, other): """ Checks if it is a superset of the JointSet in parameter other The method returns True if it is a superset or similar to other. The ordering of the joint names is not checked. Parameters ---------- other : JointSet JointSet which is used for comparision Returns ------- result : bool If this JointSet is a superset of the other JointSet returns True else False Raises ------ TypeError : type mismatch If the parameter other is not of type JointSet Examples -------- Check if one joint set is the superset of another >>> from xamla_motion.data_types import JointSet >>> joint_set1 = JointSet('joint1, joint2, joint3') >>> joint_set2 = JointSet('joint1, joint2') >>> joint_set1.is_superset(joint_set2) True """ if not isinstance(other, self.__class__): raise TypeError('other has not expected type JointSet') return self._names_set.issuperset(other._names_set)
[docs] def is_similar(self, other): """ Checks if it contains the same joint names as in JointSet other The method returns true if all joint names are available in the other join set. It is not necessary that both have the same order. Parameters ---------- other : JointSet JointSet which is used for comparision Returns ------- result : bool If this JointSet the joint names and number of joint names returns True else False Raises ------ TypeError : type mismatch If the parameter other is not of type JointSet Examples -------- Check if one joint set is the similar to another >>> from xamla_motion.data_types import JointSet >>> joint_set1 = JointSet('joint1, joint2, joint3') >>> joint_set2 = JointSet('joint1, joint3, joint2') >>> joint_set3 = JointSet('joint1, joint3') >>> joint_set1.is_similar(joint_set2) True >>> joint_set3.is_similar(joint_set1) False """ if not isinstance(other, self.__class__): raise TypeError('other has not expected type JointSet') return len(other) == len(self._names) and self.is_subset(other)
[docs] def try_get_index_of(self, name): """ Tries to get the list index of the joint by name Parameters ---------- name : str joint name for which it tries to find the list index Returns ------- is_found : bool If the index is found it resturns True else False index : int If index is found returns the index else returns None Raises ------ TypeError : type mismatch If parameter name is not type of str Examples -------- Try to get index of a specific joint in JointSet >>> from xamla_motion.data_types import JointSet >>> joint_set1 = JointSet('joint0') >>> joint_set1.try_get_index_of('joint0') (True, 0) >>> joint_set1.try_get_index_of('joint1') (False, None) """ if not isinstance(name, str): raise TypeError('name expected is type str') try: return True, self._names.index(name) except ValueError as exc: return False, None
[docs] def get_index_of(self, name): """ Returns the list index of joint name specificed paramerter name Parameter --------- name : str joint name for which it finds the list index Returns ------- index : int List index of the searched joint name Raises ------ TypeError : type mismatch If parameter name is not type of str ValueError : value not exists If joint name not exists Examples -------- Get index of a specific joint in JointSet >>> from xamla_motion.data_types import JointSet >>> joint_set1 = JointSet('joint0') >>> joint_set1.get_index_of('joint0') 0 >>> joint_set1.try_get_index_of('joint1') ValueError: This JointSet not contains a joint with name: joint1 """ if not isinstance(name, str): raise TypeError('name expected type is str') try: return self._names.index(name) except ValueError as exc: raise ValueError('This JointSet not contains a' ' joint with name: ' + name) from exc
def __contains__(self, names): """ Checks if this JointSet contains a specific joint names Parameters ---------- names : str or Iterable[str] joint names for which it checks that it is available Returns ------- is_found : bool or Iterable of bool If joint names specified by names is found retruns True else False Raises ------ TypeError : type mismatch If parameter names is not type of str Examples -------- Get index of a specific joint in JointSet >>> from xamla_motion.data_types import JointSet >>> joint_set1 = JointSet('joint0') >>> 'joint0' in joint_set1 True >>> 'joint1' in joint_set1 False """ if isinstance(names, str): return names in self._names_set else: raise TypeError('name expected type is str') def __getitem__(self, index): """ Returns the joint name stored at index Parameters ---------- index : int list index where to get the joint name from Returns ------- joint_name : str Retruns the joint name at list index specifed by index Raises ------ TypeError : type mismatch If parameter index is not type of int IndexError : index out of range If index is out of internal joint name list range """ if not isinstance(index, int): raise TypeError('index expected type is int') try: return self._names[index] except IndexError as exc: raise IndexError('index out of range') return self._names[index] def __len__(self): return len(self._names) def __iter__(self): return self._names.__iter__() def __str__(self): return 'JointSet:\n'+'\n'.join(self._names) def __repr__(self): return self.__str__() def __eq__(self, other): if not isinstance(other, self.__class__): return False if id(other) == id(self): return True if (len(self._names) != len(other.names) or self._names_set.difference(other.names)): return False return True def __ne__(self, other): return not self.__eq__(other) def __gt__(self, other): if not isinstance(other, self.__class__): return False if len(other) != len(self._names) and self.is_superset(other): return True else: return False