German Larrain avatar German Larrain committed 4ef20f0

-collision.base: new abstract classes Engine, Space, Geom. near_callback was moved to collision.adapters.OdeEngine.
-collision.adapters: new classes OdeEngine, Space.
-physics.base: new abstract classes Engine, Body, Box, Cone, Sphere, Cylinder, Capsule; the ones already implemented with the same names were moved to physics.adapters.
-physics.adapters: new classes OdeEngine, OdeBody, Capsule, Cylinder, Box, Sphere, Cone.
-simulator.Simulation: new attributes 'coll_engine', 'phs_engine'. Minor modifications for the new structure.

Comments (0)

Files changed (5)

ars/model/collision/adapters.py

 # Created on 2012.04.26
 #
 # @author: german
+
+import ode
+
+#from base import Engine, Space, NearCallbackArgs, RayContact
+import base
+
+
+class OdeEngine(base.Engine):
+	"""Adapter to the ODE collision engine"""
+
+	def __init__(self):
+		super(OdeEngine, self).__init__()
+		pass
+	
+	#===========================================================================
+	# Functions and methods not overriding base class functions and methods
+	#===========================================================================
+
+	@staticmethod
+	def near_callback(args, geom1, geom2):
+		"""Callback function for the collide() method (in ODE). This function
+		checks if the given geoms do collide and creates contact joints (c_joint)
+		if they do, except if they are connected."""
+		
+		c_joint_bounce = 0.2 # default: 0.2
+		c_joint_mu = 500 # default: 500. 0-5 = very slippery, 50-500 = normal, 5000 = very sticky
+	
+		if args.ignore_connected:
+			if (ode.areConnected(geom1.getBody(), geom2.getBody())):
+				return
+	
+		#===========================================================================
+		# create contact joints
+		#===========================================================================
+		#world, contact_group = args
+		world = args.world
+		contact_group = args.contact_group
+	
+		# check if the objects collide
+		contacts = ode.collide(geom1, geom2)
+		for c in contacts:
+			c.setBounce(c_joint_bounce)
+			c.setMu(c_joint_mu)
+			j = ode.ContactJoint(world, contact_group, c)
+			j.attach(geom1.getBody(), geom2.getBody())
+
+class Space(base.Space):
+	def __init__(self):
+		super(Space, self).__init__()
+		self._inner_object = ode.SimpleSpace() # same as ode.Space(space_type=0)
+
+	def collide(self, args):
+		self._inner_object.collide(args, OdeEngine.near_callback)
+
+class Geom(base.Geom):
+	pass
+
+class NearCallbackArgs(base.NearCallbackArgs):
+	pass

ars/model/collision/base.py

 #
 # @author: german
 
-import ode
-
-import ars.model.geometry.base as shapes
+from abc import ABCMeta, abstractmethod
 
 class Engine:
-	pass
+	__metaclass__ = ABCMeta
+
+	@abstractmethod
+	def __init__(self):
+		pass
+
+class Geom:
+	__metaclass__ = ABCMeta
+
+	@abstractmethod
+	def __init__(self):
+		pass
 
 class Space:
+	__metaclass__ = ABCMeta
+
+	@abstractmethod
 	def __init__(self):
-		self._inner_object = ode.SimpleSpace() # same as ode.Space(space_type=0)
+		pass
 
 	def get_inner_object(self):
 		return self._inner_object
 
+	@abstractmethod
 	def collide(self, args, callback):
-		self._inner_object.collide(args, callback)
+		pass
 	
 	#===========================================================================
 	# def add_ray(self, position, direction):
 		self.world = world
 		self.contact_group = contact_group
 		self.ignore_connected = ignore_connected
-
-def near_callback(args, geom1, geom2):
-	"""Callback function for the collide() method (in ODE). This function
-	checks if the given geoms do collide and creates contact joints (c_joint)
-	if they do, except if they are connected."""
-	
-	c_joint_bounce = 0.2 # default: 0.2
-	c_joint_mu = 500 # default: 500. 0-5 = very slippery, 50-500 = normal, 5000 = very sticky
-
-	if args.ignore_connected:
-		if (ode.areConnected(geom1.getBody(), geom2.getBody())):
-			return
-
-	#===========================================================================
-	# create contact joints
-	#===========================================================================
-	#world, contact_group = args
-	world = args.world
-	contact_group = args.contact_group
-
-	# check if the objects collide
-	contacts = ode.collide(geom1, geom2)
-	for c in contacts:
-		c.setBounce(c_joint_bounce)
-		c.setMu(c_joint_mu)
-		j = ode.ContactJoint(world, contact_group, c)
-		j.attach(geom1.getBody(), geom2.getBody())

ars/model/physics/adapters.py

 #
 # @author: german
 
+import ode
+
+import ars.model.geometry.base as shapes
+
+import base
+
+
+class OdeEngine(base.Engine):
+	"""Adapter to the ODE physics engine"""
+
+	def __init__(self):
+		super(OdeEngine, self).__init__()
+		pass
+	
+	@staticmethod
+	def create_joint_group():
+		return ode.JointGroup()
+	
+	@staticmethod
+	def create_world(gravity=(0.0,-9.81,0.0), ERP=0.8, CFM=1E-10):
+		"""Create an ODE world object"""
+		world = ode.World()
+		world.setGravity(gravity)
+		world.setERP(ERP)
+		world.setCFM(CFM)
+		return world
+
+	@staticmethod
+	def create_plane_geom(space, normal, dist):
+		return ode.GeomPlane(space.get_inner_object(), normal, dist)
+
+
+class OdeBody:
+
+	def __init__(self):
+		super(OdeBody, self).__init__()
+
+#===============================================================================
+# GETTERS AND SETTERS
+#===============================================================================
+
+	def get_position(self):
+		return self._inner_object.getPosition()
+
+	def get_linear_velocity(self):
+		return self._inner_object.getLinearVel()
+
+	def get_rotation(self):
+		return self._inner_object.getRotation()
+
+	def get_angular_velocity(self):
+		return self._inner_object.getAngularVel()
+
+	def get_mass(self):
+		return self._inner_object.getMass().mass
+
+	def get_center_of_gravity(self):
+		return self._inner_object.getMass().c
+
+	def get_inertia_tensor(self):
+		return self._inner_object.getMass().I
+
+	def set_position(self, pos):
+		self._inner_object.setPosition(pos)
+
+	def set_rotation(self, rot):
+		self._inner_object.setRotation(rot)
+
+class Capsule(OdeBody, 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)"""
+
+		if mass is not None:
+			if density is not None:
+				raise Exception('Both mass and density arguments were given')
+
+		self._length = length
+		self._radius = radius
+
+		body = _create_ode_capsule(world, space, length, radius, mass, density)
+		geom = shapes.Capsule(space, length, radius)
+		self._inner_object = body
+		self.attach_geom(geom)
+
+	def get_length(self):
+		return self._length
+
+	def get_radius(self):
+		return self._radius
+
+class Cylinder(OdeBody, 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)"""
+
+		if mass is not None:
+			if density is not None:
+				raise Exception('Both mass and density arguments were given')
+
+		self._length = length
+		self._radius = radius
+
+		body = _create_ode_cylinder(world, space, length, radius, mass, density)
+		geom = shapes.Cylinder(space, length, radius)
+		self._inner_object = body
+		self.attach_geom(geom)
+
+	def get_length(self):
+		return self._length
+
+	def get_radius(self):
+		return self._radius
+
+class Box(OdeBody, base.Box):
+	def __init__(self, world, space, size, mass=None, density=None):
+
+		if mass is not None:
+			if density is not None:
+				raise Exception('Both mass and density arguments were given')
+
+		self._size = size
+
+		body = _create_ode_box(world, space, size, mass, density)
+		geom = shapes.Box(space, size)
+		self._inner_object = body
+		self.attach_geom(geom)
+
+	def get_size(self):
+		return self._size
+
+class Sphere(OdeBody, base.Sphere):
+	def __init__(self, world, space, radius, mass=None, density=None):
+
+		if mass is not None:
+			if density is not None:
+				return Exception('Both mass and density arguments were given')
+
+		self._radius = radius
+
+		body = _create_ode_sphere(world, space, radius, mass, density)
+		geom = shapes.Sphere(space, radius)
+		self._inner_object = body
+		self.attach_geom(geom)
+
+	def get_radius(self):
+		return self._radius
+
+class Cone(OdeBody, base.Cone):
+	def __init__(self, world, space, height, radius, mass=None, density=None):
+		raise Exception("Not available in ODE")
+
+#===============================================================================
+# Private functions
+#===============================================================================
+
+def _create_ode_capsule(world, space, length, radius, mass=None, density=None):
+
+	capsule_direction = 3 # z-axis
+	body = ode.Body(world)
+
+	if mass is not None:
+		m = ode.Mass()
+		m.setCappedCylinderTotal(mass, capsule_direction, radius, length)
+		body.setMass(m)
+	elif density is not None:
+		m = ode.Mass()
+		m.setCappedCylinder(density, capsule_direction, radius, length)
+		body.setMass(m)
+
+	# set parameters for drawing the body
+	body.shape = "capsule" # TODO: delete this, because it is related to the original implementation
+	body.length = length
+	body.radius = radius
+
+	return body
+
+def _create_ode_cylinder(world, space, length, radius, mass=None, density=None):
+	cylinderDirection = 3 # Z-axis
+	body = ode.Body(world)
+
+	if mass is not None:
+		m = ode.Mass()
+		m.setCylinderTotal(mass, cylinderDirection, radius, length)
+		body.setMass(m)
+	elif density is not None:
+		m = ode.Mass()
+		m.setCylinder(density, cylinderDirection, radius, length)
+		body.setMass(m)
+
+	return body
+
+def _create_ode_box(world, space, size, mass=None, density=None):
+	body = ode.Body(world)
+
+	if mass is not None:
+		m = ode.Mass()
+		m.setBoxTotal(mass, *size)
+		body.setMass(m)
+	elif density is not None:
+		m = ode.Mass()
+		m.setBox(density, *size)
+		body.setMass(m)
+
+	return body
+
+def _create_ode_sphere(world, space, radius, mass=None, density=None):
+	body = ode.Body(world)
+
+	if mass is not None:
+		m = ode.Mass()
+		m.setSphereTotal(mass, radius)
+		body.setMass(m)
+	elif density is not None:
+		m = ode.Mass()
+		m.setSphere(density, radius)
+		body.setMass(m)
+
+	return body
+

ars/model/physics/base.py

 
 from abc import ABCMeta, abstractmethod
 
-import ode
-
-import ars.model.geometry.base as shapes
 
 class Engine:
-	pass
+	__metaclass__ = ABCMeta
+
+	@abstractmethod
+	def __init__(self):
+		pass
 
 class Body:
 	__metaclass__ = ABCMeta
 	def get_attached_geom(self):
 		return self._attached_geom
 
+	@abstractmethod
 	def get_position(self):
-		return self._inner_object.getPosition()
+		pass
 
+	@abstractmethod
 	def get_linear_velocity(self):
-		return self._inner_object.getLinearVel()
+		pass
 
+	@abstractmethod
 	def get_rotation(self):
-		return self._inner_object.getRotation()
+		pass
 
+	@abstractmethod
 	def get_angular_velocity(self):
-		return self._inner_object.getAngularVel()
+		pass
 
+	@abstractmethod
 	def get_mass(self):
-		return self._inner_object.getMass().mass
+		pass
 
+	@abstractmethod
 	def get_center_of_gravity(self):
-		return self._inner_object.getMass().c
+		pass
 
+	@abstractmethod
 	def get_inertia_tensor(self):
-		return self._inner_object.getMass().I
+		pass
 
+	@abstractmethod
 	def set_position(self, pos):
-		self._inner_object.setPosition(pos)
+		pass
 
+	@abstractmethod
 	def set_rotation(self, rot):
-		self._inner_object.setRotation(rot)
+		pass
+
+class Box(Body):
+	__metaclass__ = ABCMeta
+	def __init__(self, size, position, rotation=None):
+		super(Box, self).__init__(position, rotation) # http://docs.python.org/library/functions.html#super
+
+class Cone(Body):
+	__metaclass__ = ABCMeta
+	def __init__(self, height, radius, center, rotation=None):
+		super(Cone, self).__init__(center, rotation)
+
+class Sphere(Body):
+	__metaclass__ = ABCMeta
+	def __init__(self, radius, center, rotation=None):
+		super(Sphere, self).__init__(center, rotation)
+
+class Cylinder(Body):
+	__metaclass__ = ABCMeta
+	def __init__(self, length, radius, center, rotation=None):
+		super(Cylinder, self).__init__(center, rotation)
 
 class Capsule(Body):
-	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)"""
-
-		if mass is not None:
-			if density is not None:
-				raise Exception('Both mass and density arguments were given')
-
-		self._length = length
-		self._radius = radius
-
-		body = _create_ode_capsule(world, space, length, radius, mass, density)
-		geom = shapes.Capsule(space, length, radius)
-		self._inner_object = body
-		self.attach_geom(geom)
-
-	def get_length(self):
-		return self._length
-
-	def get_radius(self):
-		return self._radius
-
-class Cylinder(Body):
-
-	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)"""
-
-		if mass is not None:
-			if density is not None:
-				raise Exception('Both mass and density arguments were given')
-
-		self._length = length
-		self._radius = radius
-
-		body = _create_ode_cylinder(world, space, length, radius, mass, density)
-		geom = shapes.Cylinder(space, length, radius)
-		self._inner_object = body
-		self.attach_geom(geom)
-
-	def get_length(self):
-		return self._length
-
-	def get_radius(self):
-		return self._radius
-
-class Box(Body):
-	def __init__(self, world, space, size, mass=None, density=None):
-
-		if mass is not None:
-			if density is not None:
-				raise Exception('Both mass and density arguments were given')
-
-		self._size = size
-
-		body = _create_ode_box(world, space, size, mass, density)
-		geom = shapes.Box(space, size)
-		self._inner_object = body
-		self.attach_geom(geom)
-
-	def get_size(self):
-		return self._size
-
-class Sphere(Body):
-	def __init__(self, world, space, radius, mass=None, density=None):
-
-		if mass is not None:
-			if density is not None:
-				return Exception('Both mass and density arguments were given')
-
-		self._radius = radius
-
-		body = _create_ode_sphere(world, space, radius, mass, density)
-		geom = shapes.Sphere(space, radius)
-		self._inner_object = body
-		self.attach_geom(geom)
-
-	def get_radius(self):
-		return self._radius
-
-class Cone(Body):
-	def __init__(self, world, space, height, radius, mass=None, density=None):
-		raise Exception("Not available in ODE")
-
-def create_world(gravity=(0.0,-9.81,0.0), ERP=0.8, CFM=1E-10):
-	"""Create an ODE world object"""
-	world = ode.World()
-	world.setGravity(gravity)
-	world.setERP(ERP)
-	world.setCFM(CFM)
-	return world
-
-def _create_ode_capsule(world, space, length, radius, mass=None, density=None):
-
-	capsule_direction = 3 # z-axis
-	body = ode.Body(world)
-
-	if mass is not None:
-		m = ode.Mass()
-		m.setCappedCylinderTotal(mass, capsule_direction, radius, length)
-		body.setMass(m)
-	elif density is not None:
-		m = ode.Mass()
-		m.setCappedCylinder(density, capsule_direction, radius, length)
-		body.setMass(m)
-
-	# set parameters for drawing the body
-	body.shape = "capsule" # TODO: delete this, because it is related to the original implementation
-	body.length = length
-	body.radius = radius
-
-	return body
-
-def _create_ode_cylinder(world, space, length, radius, mass=None, density=None):
-	cylinderDirection = 3 # Z-axis
-	body = ode.Body(world)
-
-	if mass is not None:
-		m = ode.Mass()
-		m.setCylinderTotal(mass, cylinderDirection, radius, length)
-		body.setMass(m)
-	elif density is not None:
-		m = ode.Mass()
-		m.setCylinder(density, cylinderDirection, radius, length)
-		body.setMass(m)
-
-	return body
-
-def _create_ode_box(world, space, size, mass=None, density=None):
-	body = ode.Body(world)
-
-	if mass is not None:
-		m = ode.Mass()
-		m.setBoxTotal(mass, *size)
-		body.setMass(m)
-	elif density is not None:
-		m = ode.Mass()
-		m.setBox(density, *size)
-		body.setMass(m)
-
-	return body
-
-def _create_ode_sphere(world, space, radius, mass=None, density=None):
-	body = ode.Body(world)
-
-	if mass is not None:
-		m = ode.Mass()
-		m.setSphereTotal(mass, radius)
-		body.setMass(m)
-	elif density is not None:
-		m = ode.Mass()
-		m.setSphere(density, radius)
-		body.setMass(m)
-
-	return body
-
-def create_joint_group():
-	return ode.JointGroup()
-
-def create_plane_geom(space, normal, dist):
-	return ode.GeomPlane(space.get_inner_object(), normal, dist)
+	__metaclass__ = ABCMeta
+	def __init__(self, length, radius, center, rotation=None):
+		super(Capsule, self).__init__(center, rotation)

ars/model/simulator/__init__.py

 import ars.utilities.generic as gu
 import ars.utilities.mathematical as mu
 
-import ars.model.collision.base as coll
-import ars.model.physics.base as phs
+import ars.model.collision.adapters as coll
+import ars.model.physics.adapters as phs
 
 class Simulation:
 
 		self.all_frame_steps_callbacks = []
 
 		self.screenshot_recorder_callback = None
+		
+		self.coll_engine = coll.OdeEngine()
+		self.phs_engine = phs.OdeEngine()
 
 	def add_basic_simulation_objects(self):
 		"""create the basic simulation objects"""
-		self._contact_group = phs.create_joint_group() # for the contact joints generated during collisions
-		self._world = phs.create_world() # create a world object (physical)
+		self._contact_group = self.phs_engine.create_joint_group() # for the contact joints generated during collisions
+		self._world = self.phs_engine.create_world() # create a world object (physical)
 		self._space = coll.Space()
 
 	def on_idle(self):
 
 			# Detect collisions and create contact joints
 			coll_args = coll.NearCallbackArgs(self._world, self._contact_group)
-			self._space.collide(coll_args, coll.near_callback)
+			self._space.collide(coll_args)
 			# Simulation step
 			time_step = self.get_time_step()
 
 		"""Create a plane geom to simulate a floor. It won't be used explicitly
 		later (space object has a reference to it)"""
 		# FIXME: the relation between ODE's definition of plane and the center of the box
-		self._floor_geom = phs.create_plane_geom(self._space, normal, dist)
+		self._floor_geom = self.phs_engine.create_plane_geom(self._space, normal, dist)
 		gFloor = gp.Box(box_size, box_center) #TODO: use normal parameter for orientation
 		gFloor.set_color(color)
 		name = "floor"
Tip: Filter by directory path e.g. /media app.js to search for public/media/app.js.
Tip: Use camelCasing e.g. ProjME to search for ProjectModifiedEvent.java.
Tip: Filter by extension type e.g. /repo .js to search for all .js files in the /repo directory.
Tip: Separate your search with spaces e.g. /ssh pom.xml to search for src/ssh/pom.xml.
Tip: Use ↑ and ↓ arrow keys to navigate and return to view the file.
Tip: You can also navigate files with Ctrl+j (next) and Ctrl+k (previous) and view the file with Ctrl+o.
Tip: You can also navigate files with Alt+j (next) and Alt+k (previous) and view the file with Alt+o.