<commit_before>from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import itertools

from compas.geometry import Frame
from compas.geometry import Scale
from compas.geometry import Transformation
from compas.robots import Geometry
from compas.robots.model.link import LinkItem

from .artist import Artist


class AbstractRobotModelArtist(object):
    def transform(self, geometry, transformation):
        """Transforms a CAD-specific geometry using a Transformation.

        Parameters
        ----------
        geometry : object
            A CAD-specific (i.e. native) geometry object as returned by :meth:`create_geometry`.
        transformation : :class:`~compas.geometry.Transformation`
            Transformation to update the geometry object.

        """
        raise NotImplementedError

    def create_geometry(self, geometry, name=None, color=None):
        """Draw geometry in the respective CAD environment.

        Note
        ----
        This is an abstract method that needs to be implemented by derived classes.

        Parameters
        ----------
        geometry : :class:`~compas.datastructures.Mesh`
            Instance of a mesh data structure
        name : str, optional
            The name of the mesh to draw.

        Returns
        -------
        object
            CAD-specific geometry

        """
        raise NotImplementedError


class RobotModelArtist(AbstractRobotModelArtist, Artist):
    """Provides common functionality to most robot model artist implementations.

    In COMPAS, "artists" are classes that assist with the visualization of
    datastructures and models, in a way that maintains the data separated from the
    specific CAD interfaces, while providing a way to leverage native performance
    of the CAD environment.

    There are two methods that implementers of this base class should provide, one
    is concerned with the actual creation of geometry in the native format of the
    CAD environment (:meth:`create_geometry`) and the other is one to apply a transformation
    to geometry (:meth:`transform`).

    Attributes
    ----------
    model : :class:`~compas.robots.RobotModel`
        Instance of a robot model.

    """

    def __init__(self, model):
        super(RobotModelArtist, self).__init__()
        self.model = model
        self.create()
        self.scale_factor = 1.0
        self.attached_tool_models = {}
        self.attached_items = {}

    @property
    def attached_tool_model(self):
        """
        For backwards compatibility. Returns the tool attached to the first end effector link or,
        if not availabel, the first tool from the dictionary.
        Returns None if no tool are attached.

        Returns
        -------
        :class: `~compas.robots.model.ToolModel`

        """
        if self.attached_tool_models:
            link_name = self.model.get_end_effector_link()
            tool_model = self.attached_tool_models.get(link_name) or list(self.attached_tool_models.values())[0]
        return tool_model

    def attach_tool_model(self, tool_model):
        """Attach a tool to the robot artist for visualization.

        Parameters
        ----------
        tool_model : :class:`~compas.robots.ToolModel`
            The tool that should be attached to the robot's flange.

        """
        self.create(tool_model.root, "attached_tool")

        if not tool_model.link_name:
            link = self.model.get_end_effector_link()
            tool_model.link_name = link.name
        else:
            link = self.model.get_link_by_name(tool_model.link_name)

        # don't attach twice on the same link<commit_msg>fixed NameError in attached_tool_model<commit_after>from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import itertools

from compas.geometry import Frame
from compas.geometry import Scale
from compas.geometry import Transformation
from compas.robots import Geometry
from compas.robots.model.link import LinkItem

from .artist import Artist


class AbstractRobotModelArtist(object):
    def transform(self, geometry, transformation):
        """Transforms a CAD-specific geometry using a Transformation.

        Parameters
        ----------
        geometry : object
            A CAD-specific (i.e. native) geometry object as returned by :meth:`create_geometry`.
        transformation : :class:`~compas.geometry.Transformation`
            Transformation to update the geometry object.

        """
        raise NotImplementedError

    def create_geometry(self, geometry, name=None, color=None):
        """Draw geometry in the respective CAD environment.

        Note
        ----
        This is an abstract method that needs to be implemented by derived classes.

        Parameters
        ----------
        geometry : :class:`~compas.datastructures.Mesh`
            Instance of a mesh data structure
        name : str, optional
            The name of the mesh to draw.

        Returns
        -------
        object
            CAD-specific geometry

        """
        raise NotImplementedError


class RobotModelArtist(AbstractRobotModelArtist, Artist):
    """Provides common functionality to most robot model artist implementations.

    In COMPAS, "artists" are classes that assist with the visualization of
    datastructures and models, in a way that maintains the data separated from the
    specific CAD interfaces, while providing a way to leverage native performance
    of the CAD environment.

    There are two methods that implementers of this base class should provide, one
    is concerned with the actual creation of geometry in the native format of the
    CAD environment (:meth:`create_geometry`) and the other is one to apply a transformation
    to geometry (:meth:`transform`).

    Attributes
    ----------
    model : :class:`~compas.robots.RobotModel`
        Instance of a robot model.

    """

    def __init__(self, model):
        super(RobotModelArtist, self).__init__()
        self.model = model
        self.create()
        self.scale_factor = 1.0
        self.attached_tool_models = {}
        self.attached_items = {}

    @property
    def attached_tool_model(self):
        """
        For backwards compatibility. Returns the tool attached to the first end effector link or,
        if not availabel, the first tool from the dictionary.
        Returns None if no tool are attached.

        Returns
        -------
        :class: `~compas.robots.model.ToolModel`

        """
        tool_model = None
        if self.attached_tool_models:
            link_name = self.model.get_end_effector_link()
            tool_model = self.attached_tool_models.get(link_name) or list(self.attached_tool_models.values())[0]
        return tool_model

    def attach_tool_model(self, tool_model):
        """Attach a tool to the robot artist for visualization.

        Parameters
        ----------
        tool_model : :class:`~compas.robots.ToolModel`
            The tool that should be attached to the robot's flange.

        """
        self.create(tool_model.root, "attached_tool")

        if not tool_model.link_name:
            link = self.model.get_end_effector_link()
            tool_model.link_name = link.name
        else:
            link = self.model.get_link_by_name(tool_model.link_name)

        # don't attach twice on the same link
{'fraction_non_alphanumeric': 0.07741676694745286, 'fraction_numerical': 0.0008022462896109105, 'mean_word_length': 2.432767324460762, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 3, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2350891', 'n_tokens_mistral': 1956, 'n_tokens_neox': 1859, 'n_words': 660}