From: Miles J. <mil...@ho...> - 2006-03-27 23:20:20
|
I've tried to make VPython work with PyODE (http://pyode.sourceforge.net). The blocks seem to collide properly but they often settle on their edges. I probably misunderstand the rotation matrix provided by PyODE or the "up" method of VPython. Any help would be appreciated. The VPython "cubes" get their positional and angular information from the PyODE "bodies". # 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. _________________________________________________________________ Dont just search. Find. Check out the new MSN Search! http://search.msn.click-url.com/go/onm00200636ave/direct/01/ |
From: Jonathan B. <jbr...@ea...> - 2006-03-28 16:13:01
|
On Mon, 2006-03-27 at 23:20 +0000, Miles Jacobs wrote: > I've tried to make VPython work with PyODE (http://pyode.sourceforge.net). > The blocks seem to collide properly but they often settle on their edges. I > probably misunderstand the rotation matrix provided by PyODE or the "up" > method of VPython. Both up and axis define the orientation of a VPython body ("angle" is not used for anything). See src/prim.cpp for the full story (there are some corner cases that the code follows to avoid degeneration). The following is a reasonable approximation of what happens in there: # Returns the direction cosine matrix of a VPython renderable body # The result is a right-handed 3x3 orthonormal matrix def DCM( renderable): z_axis = renderable.axis.cross( renderable.up).norm() y_axis = z_axis.cross( renderable.axis).norm() x_axis = renderable.axis.norm() # Can probably use Tensor here... ret = Numeric.array( shape=(3,3), type=Numeric.Float64) ret[:,0] = x_axis ret[:,1] = y_axis ret[:,2] = z_axis return ret # Set the orientation of a renderable object from a 3x3 direction # cosine matrix, while retaining scaling information on the Visual # object. # renderable: A VPython renderable object # DCM: A right-handed 3x3 orthonormal matrix # returns: None def move_renderable_from_DCM( renderable, DCM): renderable.axis = vector(DCM[:,0]) * renderable.axis.mag renderable.up = vector(DCM[:,1]) > Any help would be appreciated. The VPython "cubes" get > their positional and angular information from the PyODE "bodies". HTH, -Jonathan |
From: Bruce S. <Bru...@nc...> - 2006-03-29 04:46:13
|
Also, in case you didn't spot this, look at the Visual documentation on the box object and the accompanying diagram. Bruce Sherwood Jonathan Brandmeyer wrote: >On Mon, 2006-03-27 at 23:20 +0000, Miles Jacobs wrote: > > >>I've tried to make VPython work with PyODE (http://pyode.sourceforge.net). >>The blocks seem to collide properly but they often settle on their edges. I >>probably misunderstand the rotation matrix provided by PyODE or the "up" >>method of VPython. >> >> > >Both up and axis define the orientation of a VPython body ("angle" is >not used for anything). See src/prim.cpp for the full story (there are >some corner cases that the code follows to avoid degeneration). The >following is a reasonable approximation of what happens in there: > ># Returns the direction cosine matrix of a VPython renderable body ># The result is a right-handed 3x3 orthonormal matrix >def DCM( renderable): > z_axis = renderable.axis.cross( renderable.up).norm() > y_axis = z_axis.cross( renderable.axis).norm() > x_axis = renderable.axis.norm() > # Can probably use Tensor here... > ret = Numeric.array( shape=(3,3), type=Numeric.Float64) > ret[:,0] = x_axis > ret[:,1] = y_axis > ret[:,2] = z_axis > return ret > ># Set the orientation of a renderable object from a 3x3 direction ># cosine matrix, while retaining scaling information on the Visual ># object. ># renderable: A VPython renderable object ># DCM: A right-handed 3x3 orthonormal matrix ># returns: None >def move_renderable_from_DCM( renderable, DCM): > renderable.axis = vector(DCM[:,0]) * renderable.axis.mag > renderable.up = vector(DCM[:,1]) > > > >> Any help would be appreciated. The VPython "cubes" get >>their positional and angular information from the PyODE "bodies". >> >> > >HTH, >-Jonathan > > > > >------------------------------------------------------- >This SF.Net email is sponsored by xPML, a groundbreaking scripting language >that extends applications into web and mobile media. Attend the live webcast >and join the prime developer group breaking into this new coding territory! >http://sel.as-us.falkag.net/sel?cmd=lnk&kid=110944&bid=241720&dat=121642 >_______________________________________________ >Visualpython-users mailing list >Vis...@li... >https://lists.sourceforge.net/lists/listinfo/visualpython-users > > |