Source code for _body

# specialized class designed to be Mixin to pyrosim.py
# Contains all send and add functions related to bodies,
# geoms, physical things, etc.

class Mixin(object):
    def _send_body(self, *args):
        """Sends an entity categorized as Body"""
        return self._send_entity('Body', *args)

    def add_impulse_to_body(self,
                            body_id,
                            force,
                            time_step=0):
        """Adds an impulse force to a body at specified time step

        Parameters
        ----------
        body_id   : int
            The id tag of the target body
        force     : triple float
            The force vector to apply
        time_step : int (optional)
            The tme step to apply the specified force
        """
        self._assert_body(body_id, 'body_id')
        assert len(force) == 3, ('Force must be size 3')
        assert time_step >= 0, ('time_step must be >= 0')

        self._send_add_command(body_id,
                               'Impulse',
                               time_step,
                               force
                               )

    def add_box_to_composite(self,
                         composite_id,
                         position = (0.0, 0.0, 0.0),
                         orientation = (0.0, 0.0, 1.0),
                         sides = (0.25, 0.25, 0.25),
                         density = 1.0,
                         color = (1.0, 1.0, 1.0)):
        """Adds box geometry to a composite body

        Parameters
        ----------
        composite_id : int
            The id tag of the target composite body
        position     : triple float (optional)
            The global position of the body. (default [0, 0, 0])
        orientation  : triple float (optional)
            The gloabl orientation of the body. (default [0, 0, 1])
        sides        : triple float (optional)
            The length, width, and height of the body. (default [.25, .25, .25])
        density      : float (optional)
            The density of the body
        color        : triple float (optional)
            Color of the body. (default is [1, 1, 1])
        """

        self._assert_body(composite_id, 'composite_id')
        self._send_add_command(composite_id,
                               'Geom',
                               'Box', 
                               position,
                               orientation,
                               sides,
                               density,
                               color)

    def add_cylinder_to_composite(self,
                                  composite_id,
                                  position = (0.0, 0.0, 0.0),
                                  orientation = (0.0, 0.0, 1.0),
                                  length=0.5,
                                  radius=0.05,
                                  capped=True,
                                  density = 1.0,
                                  color = (1.0, 1.0, 1.0)):
        """Adds cylinder geometry to a composite body

        Parameters
        ----------
        composite_id : int
            The id tag of the target composite body
        position     : triple float (optional)
            The global position of the body. (default [0, 0, 0])
        orientation  : triple float (optional)
            The gloabl orientation of the body. (default [0, 0, 1])
        length       : float (optional)
            The length of the long axis of the cylinder. (default 0.5)
        radius       : float (optional)
            The radius of the cylinder. (default 0.05)
        capped       : boolean (optional)
            If true, the cylinder has rounded edges. If false, the cylinder
            has flat edges. (default True)
        density      : float (optional)
            The density of the body
        color        : triple float (optional)
            Color of the body. (default is [1, 1, 1])
        """
        self._assert_body(composite_id, 'composite_id')
        capped = int(capped)
        self._send_add_command(composite_id,
                               'Geom',
                               'Cylinder',
                               position,
                               orientation,
                               length,
                               radius,
                               capped,
                               density,
                               color)

    def add_sphere_to_composite(self,
                                composite_id,
                                position = (0.0, 0.0, 0.0),
                                orientation = (0.0, 0.0, 1.0),
                                radius=0.25,
                                density=1.0,
                                color=(1.0, 1.0, 1.0)):
        """Adds sphere geometry to a composite body

        Parameters
        ----------
        composite_id : int
            The id tag of the target composite body
        position     : triple float (optional)
            The global position of the body. (default [0, 0, 0])
        orientation  : triple float (optional)
            The gloabl orientation of the body. (default [0, 0, 1])
        radius       : float (optional)
            The radius of the sphere. (default 0.25)
        density      : float (optional)
            The density of the body
        color        : triple float (optional)
            Color of the body. (default is [1, 1, 1])
        """
        self._assert_body(composite_id, 'composite_id')
        self._send_add_command(composite_id,
                               'Geom',
                               'Sphere',
                               position,
                               orientation,
                               radius,
                               density,
                               color)

    def add_light_to_body( self, body_id, intensity = 1.0 ):
        """Makes the target body emit a light that can be sensed by light sensors"""

        self._assert_body( body_id, 'body_id' )
        self._send_add_command( body_id,
                                'Light',
                                intensity )

    def send_ray(self,
                 body_id,
                 position,
                 direction,
                 max_length=10.0):
        """Send a ray entity and attach to a body
        
        Parameters
        ----------
        body_id     : int
            The body entity id to attach to
        position    : triple float
            The starting position of the ray.
        direction   : triple float
            The starting orientation of the ray
        max_length  : float
            The total length the ray can sense
        """
        self._assert_body(body_id, 'composite_id')
        return self._send_body('Ray', body_id, position, direction, max_length)

    def send_box(self,
                 position = (0.0, 0.0, 0.0),
                 orientation = (0.0, 0.0, 1.0),
                 sides = (0.25, 0.25, 0.25),
                 density = 1.0,
                 color = (1.0, 1.0, 1.0),
                 space = None,
                 collision_group = None):
        """Send a box geometry to the simulator

        Parameters
        ----------
        position        : triple float (optional)
            The global position of the body. (default [0, 0, 0])
        orientation     : triple float (optional)
            The gloabl orientation of the body. (default [0, 0, 1])
        sides           : triple float (optional)
            The length, width, and height of the body. (default [.25, .25, .25])
        density         : float (optional)
            The density of the body
        color           : triple float (optional)
            Color of the body. (default is [1, 1, 1])
        space           : str (optional)
            The string name of the space in which to place the body.
            (default is to use the string set by :func:`set_current_space()` function)
        collision_group : str (optional)
            The string name of the collision group in which to place the body.
            Collision groups specify how bodies collide. (default is to use
            the string set by :func:`set_current_collision_group()` function)
        Returns
        -------
        int
            The id tag of the box
        """

        if collision_group is None:
            collision_group = self._current_collision_group

        if space is None:
            space = self._current_space

        return self._send_body('Box',
                               position,
                               orientation,
                               sides,
                               density,
                               color,
                               space,
                               collision_group)

    def send_cylinder(self,
                      position = (0.0, 0.0, 0.0),
                      orientation = (0.0, 0.0, 1.0),
                      length = 0.5,
                      radius = 0.05,
                      capped = True,
                      density = 1.0,
                      color = (1.0, 1.0, 1.0),
                      space = None,
                      collision_group = None):
        """Send a cylinder geometry to the simulator

        Parameters
        ----------
        position        : triple float (optional)
            The global position of the body. (default [0, 0, 0])
        orientation     : triple float (optional)
            The gloabl orientation of the body. (default [0, 0, 1])
        length       : float (optional)
            The length of the long axis of the cylinder. (default 0.5)
        radius       : float (optional)
            The radius of the cylinder. (default 0.05)
        capped       : boolean (optional)
            If true, the cylinder has rounded edges. If false, the cylinder
            has flat edges. (default True)
        density         : float (optional)
            The density of the body
        color           : triple float (optional)
            Color of the body. (default is [1, 1, 1])
        space           : str (optional)
            The string name of the space in which to place the body.
            (default is to use the string set by :func:`set_current_space()` function)
        collision_group : str (optional)
            The string name of the collision group in which to place the body.
            Collision groups specify how bodies collide. (default is to use
            the string set by :func:`set_current_collision_group()` function)
        Returns
        -------
        int
            The id tag of the cylinder
        """
        if collision_group is None:
            collision_group = self._current_collision_group

        if space is None:
            space = self._current_space

        capped = int(capped)

        return self._send_body('Cylinder',
                               position,
                               orientation,
                               length,
                               radius,
                               capped,
                               density,
                               color,
                               space,
                               collision_group)

    def send_composite_body(self, space=None, collision_group=None):
        """Send a composite body base

        Parameters
        ----------
        space           : str (optional)
            The string name of the space in which to place the body.
            (default is to use the string set by :func:`set_current_space()` function)
        collision_group : str (optional)
            The string name of the collision group in which to place the body.
            Collision groups specify how bodies collide. (default is to use
            the string set by :func:`set_current_collision_group()` function)
        Returns
        -------
        int
            The id tag of the composite body
        """
        if collision_group is None:
            collision_group = self._current_collision_group

        if space is None:
            space = self._current_space

        return self._send_body('Composite',
                               space,
                               collision_group)

    def send_height_map(self, height_matrix,
                        position=(0, 0, 0),
                        size=10.0,
                        height_scale=1.0):
        """Send a height map to the simulator

        Parameters
        ----------
        height_matrix : 2D numpy matrix
            A matrix filled in with the height (z) values. Each dimension
            must be at least size 2
        position      : triple float (optional)
            The center position of the height map. (default is [0, 0, 0])
        size          : float, tuple float (optional)
            The length of each side. When a singular value, height map is
            a square. (default is (10, 10))
        height_scale  : float (optional)
            Height multiplier. (default is 1.0)
        """
        import numpy as np
        M, N= np.shape(height_matrix)

        try:
            len(size)
        except:
            size = (size, size)

        assert (len(size) == 2)

        height_vec = height_matrix.ravel('C')

        return self._send_entity('Entity',
                                 'HeightMap',
                                  position,
                                  M, N,
                                  height_vec,
                                  size,
                                  height_scale,
                                  0.0, # offset (unecessary with position)
                                  1.0, # min aabb thickness
                                  0, # infinite wrap, not implemented
                                  )

    def send_sphere(self,
                    position = (0.0, 0.0, 0.0),
                    orientation = (0.0, 0.0, 1.0),
                    radius = 0.25,
                    density = 1.0,
                    color = (1.0, 1.0, 1.0),
                    space = None,
                    collision_group = None):
        """Send a sphere geometry to the simulator

        Parameters
        ----------
        position        : triple float (optional)
            The global position of the body. (default [0, 0, 0])
        orientation     : triple float (optional)
            The gloabl orientation of the body. (default [0, 0, 1])
        radius       : float (optional)
            The radius of the sphere. (default 0.25)
        density         : float (optional)
            The density of the body
        color           : triple float (optional)
            Color of the body. (default is [1, 1, 1])
        space           : str (optional)
            The string name of the space in which to place the body.
            (default is to use the string set by :func:`set_current_space()` function)
        collision_group : str (optional)
            The string name of the collision group in which to place the body.
            Collision groups specify how bodies collide. (default is to use
            the string set by :func:`set_current_collision_group()` function)
        Returns
        -------
        int
            The id tag of the shpere
        """
        if collision_group is None:
            collision_group = self._current_collision_group

        if space is None:
            space = self._current_space

        return self._send_body('Sphere',
                               position,
                               orientation,
                               radius,
                               density,
                               color,
                               space,
                               collision_group)