|
From: Miles J. <mil...@ho...> - 2006-03-24 21:18:10
|
I have tried to modify tutorial 3 to work with VPython. The blocks seem to
collide OK, but some of them come to rest on their edges. I probably
misunderstand the nature of the rotation matrix, or the "up" method in
VPython. Would appreciate any help.
Here is the code (running on Windows):
# pyODE example 3: Collision detection
# Originally by Matthias Baas.
# Attempt by Miles Jacobs to make collision detection work with VPython.
import sys, os, random, time
from math import *
from visual import *
import ode
from Scientific.Geometry import *
from Scientific.Geometry.TensorModule import *
from Scientific.Geometry.Transformation import *
# geometric utility functions
def scalp (vec, scal):
vec[0] *= scal
vec[1] *= scal
vec[2] *= scal
def length (vec):
return sqrt (vec[0]**2 + vec[1]**2 + vec[2]**2)
# create_box
def create_box(world, space, density, lx, ly, lz):
"""Create a box body and its corresponding geom."""
# Create body
body = ode.Body(world)
M = ode.Mass()
M.setBox(density, lx, ly, lz)
body.setMass(M)
# Set parameters for drawing the body
body.shape = "box"
body.boxsize = (lx, ly, lz)
# Create a box geom for collision detection
geom = ode.GeomBox(space, lengths=body.boxsize)
geom.setBody(body)
return body
# drop_object
def drop_object():
"""Drop an object into the scene."""
global bodies, counter, objcount
body = create_box(world, space, 1000, 1.0,1.0,1.0)
body.setPosition((random.gauss(0,0.1),10.0,random.gauss(0,0.1)))
theta = random.uniform(0,2*pi)
ct = cos (theta)
st = sin (theta)
body.setRotation([ct, 0., -st, 0., 1., 0., st, 0., ct])
matpot=Tensor([[ct, 0., -st],[0., 1., 0.],[st, 0., ct]])
matkettle=Rotation(matpot)
bodyaxis, bodyangle = matkettle.axisAndAngle()
icecube = box(pos=body.getPosition(), axis=bodyaxis,
length=1.0, height=1.0, width=1.0,
color=(random.gauss(0,1),random.gauss(0,1),random.gauss(0,1)))
bodies.append(body)
cubes.append(icecube)
counter=0
objcount+=1
# explosion
def explosion():
"""Simulate an explosion.
Every object is pushed away from the origin.
The force is dependent on the objects distance from the origin.
"""
global bodies
for b in bodies:
l=b.getPosition ()
d = length (l)
a = max(0, 800000*(1.0-0.2*d*d))
l = [l[0] / 4, l[1], l[2] /4]
scalp (l, a / length (l))
b.addForce(l)
# pull
def pull():
"""Pull the objects back to the origin.
Every object will be pulled back to the origin.
Every couple of frames there'll be a thrust upwards so that
the objects won't stick to the ground all the time.
"""
global bodies, counter
for b in bodies:
l=list (b.getPosition ())
scalp (l, -100000 / length (l))
b.addForce(l)
if counter%60==0:
b.addForce((0,100000,0))
# Collision callback
def near_callback(args, geom1, geom2):
"""Callback function for the collide() method.
This function checks if the given geoms do collide and
creates contact joints if they do.
"""
# Check if the objects do collide
contacts = ode.collide(geom1, geom2)
# Create contact joints
world,contactgroup = args
for c in contacts:
c.setBounce(0.2)
c.setMu(5000)
j = ode.ContactJoint(world, contactgroup, c)
j.attach(geom1.getBody(), geom2.getBody())
######################################################################
# Create a world object
world = ode.World()
world.setGravity( (0,-9.81,0) )
world.setERP(0.8)
world.setCFM(1E-5)
# Create a space object
space = ode.Space()
# Create a plane geom which prevent the objects from falling forever
floor = ode.GeomPlane(space, (0,1,0), 0)
ground=box(pos=(0,-0.1,0), width=20, height=0.1, length=20,
color=color.white)
# A list with ODE bodies and Visual objects to see the bodies
bodies = []
cubes = []
# A joint group for the contact joints that are generated whenever
# two bodies collide
contactgroup = ode.JointGroup()
# Some variables used inside the simulation loop
fps = 25
dt = 1.0/fps
running = True
state = 0
counter = 0
objcount = 0
scene.autoscale=0
scene.forward=(-5,-5,-5)
while(1):
global counter, state
counter += 1
if state==0:
if counter==20:
drop_object()
if objcount==10:
state=1
counter=0
# State 1: Explosion and pulling back the objects
elif state==1:
if counter==100:
explosion()
if counter>300:
pull()
if counter==500:
counter=20
for b in range(len(bodies)):
x,y,z = bodies[b].getPosition()
R = bodies[b].getRotation()
pot=Tensor([[R[0],R[3],R[6]],[R[1],R[4],R[7]],[R[2],R[5],R[8]]])
kettle=Rotation(pot)
bodyaxis, bodyangle = kettle.axisAndAngle()
cubes[b].pos=(x,y,z)
cubes[b].axis=bodyaxis
cubes[b].angle=bodyangle
print state, counter
# Simulate
n = 2
for i in range(n):
# Detect collisions and create contact joints
space.collide((world,contactgroup), near_callback)
# Simulation step
world.step(dt/n)
# Remove all contact joints
contactgroup.empty()
rate(10)
Miles.
_________________________________________________________________
Express yourself instantly with MSN Messenger! Download today - it's FREE!
http://messenger.msn.click-url.com/go/onm00200471ave/direct/01/
|