Source code for ars.model.physics.ode_adapter

"""Classes and functions to interface the ODE physics engine with
the API defined in :mod:`physics`.

"""
from abc import ABCMeta

from ...constants import G_VECTOR
from ...lib.pydispatch import dispatcher
from ..collision import ode_adapter as shapes

from . import base, ode_objects_factories, signals

#==============================================================================
# Environment
#==============================================================================


[docs]class Engine(base.Engine): """Adapter to the ODE physics engine""" world_class = None # we have to define it below World's definition
[docs]class World(base.World): """Adapter to :class:`ode.World`. .. seealso:: Read abouth ERP and CFM in ODE's wiki http://ode-wiki.org/wiki/index.php?title=Manual:_Concepts """ def __init__(self, gravity=G_VECTOR, ERP=0.2, CFM=1E-10, *args, **kwargs): """Constructor. :param gravity: gravity acceleration vector :type gravity: 3-sequence of floats :param ERP: Error Reduction Parameter :type ERP: float :param CFM: Constraint Force Mixing :type CFM: float """ super(World, self).__init__(gravity, *args, **kwargs) self._inner_object = ode_objects_factories.create_ode_world( gravity, ERP, CFM) @property def gravity(self): return self._inner_object.getGravity()
[docs] def step(self, time_step): dispatcher.send(signals.WORLD_PRE_STEP, sender=self) self._inner_object.step(time_step) dispatcher.send(signals.WORLD_POST_STEP, sender=self)
# This is a workaround necessary to solve the issue caused by the fact World # is defined after Engine thus the latter can't use the former in its own # definition (class attribute). Engine.world_class = World #============================================================================== # Parents #==============================================================================
[docs]class Body(object): """Abstract class, sort of equivalent to :class:`ode.Body`.""" __metaclass__ = ABCMeta def __init__(self, world, space, mass=None, density=None, *args, **kwargs): """Constructor. :param world: :type world: :class:`.base.World` :param space: :type space: :class:`.collision.base.Space` :param mass: :type mass: float or None :param density: :type density: float or None """ self._inner_object = None #========================================================================== # Getters and setters #==========================================================================
[docs] def get_position(self): """Get the position of the body. :return: position :rtype: 3-sequence of floats """ return self._inner_object.getPosition()
[docs] def get_linear_velocity(self): return self._inner_object.getLinearVel()
[docs] def get_rotation(self): """Get the orientation of the body. :return: rotation matrix :rtype: 9-sequence of floats """ return self._inner_object.getRotation()
[docs] def get_angular_velocity(self): return self._inner_object.getAngularVel()
[docs] def get_mass(self): return self._inner_object.getMass().mass
[docs] def get_center_of_gravity(self): return self._inner_object.getMass().c
[docs] def get_inertia_tensor(self): return self._inner_object.getMass().I
[docs] def set_position(self, pos): """Set the position of the body. Sends :data:`signals.BODY_PRE_SET_POSITION` and :data:`signals.BODY_POST_SET_POSITION`. :param pos: position :type pos: 3-sequence of floats """ dispatcher.send(signals.BODY_PRE_SET_POSITION, sender=self) self._inner_object.setPosition(pos) dispatcher.send(signals.BODY_POST_SET_POSITION, sender=self)
[docs] def set_rotation(self, rot): """Set the orientation of the body. Sends :data:`signals.BODY_PRE_SET_ROTATION` and :data:`signals.BODY_POST_SET_ROTATION`. :param rot: rotation matrix :type rot: 9-sequence of floats """ dispatcher.send(signals.BODY_PRE_SET_ROTATION, sender=self) self._inner_object.setRotation(rot) dispatcher.send(signals.BODY_POST_SET_ROTATION, sender=self)
#============================================================================== # Bodies #==============================================================================
[docs]class Box(Body, base.Box): def __init__(self, world, space, size, mass=None, density=None): Body.__init__(self, world, space, mass, density) base.Box.__init__(self, size, mass, density) body = ode_objects_factories.create_ode_box( world._inner_object, size, mass, density) geom = shapes.Box(space, size) self._inner_object = body self.attach_geom(geom)
[docs]class Sphere(Body, base.Sphere): def __init__(self, world, space, radius, mass=None, density=None): Body.__init__(self, world, space, mass, density) base.Sphere.__init__(self, radius, mass, density) body = ode_objects_factories.create_ode_sphere( world._inner_object, radius, mass, density) geom = shapes.Sphere(space, radius) self._inner_object = body self.attach_geom(geom)
[docs]class Capsule(Body, base.Capsule): def __init__(self, world, space, length, radius, mass=None, density=None): """create capsule body (aligned along the z-axis so that it matches the Geom created below, which is aligned along the Z-axis by default)""" Body.__init__(self, world, space, mass, density) base.Capsule.__init__(self, length, radius, mass, density) body = ode_objects_factories.create_ode_capsule( world._inner_object, length, radius, mass, density) geom = shapes.Capsule(space, length, radius) self._inner_object = body self.attach_geom(geom)
[docs]class Cylinder(Body, base.Cylinder): def __init__(self, world, space, length, radius, mass=None, density=None): """create cylinder body (aligned along the z-axis so that it matches the Geom created below, which is aligned along the Z-axis by default)""" Body.__init__(self, world, space, mass, density) base.Cylinder.__init__(self, length, radius, mass, density) body = ode_objects_factories.create_ode_cylinder( world._inner_object, length, radius, mass, density) geom = shapes.Cylinder(space, length, radius) self._inner_object = body self.attach_geom(geom)