Пример #1
0
    def createCapsule(self, mass=100, length=1, radius=1, pos=(0, 0, 0)):
        """Creates a capsule body and corresponding geom."""
        body = ode.Body(self.world)
        m = ode.Mass()
        m.setCappedCylinderTotal(mass, 3, radius, length)
        body.setMass(m)

        # set parameters for drawing the body
        body.shape = "capsule"
        body.length = length
        body.radius = radius

        # create a capsule geom for collision detection
        geom = ode.GeomCCylinder(self.space, radius, length)
        geom.setBody(body)
        # create a reference to the body geom in case the user does not want to keep track of it.
        body.geom = geom

        body.color = (128, 0, 0, 255)
        # This is the constant offset for aligning with the physics element
        # This is a 4x4 opengl style matrix, expressing an offset and a rotation
        offset = (0, 0, 0)
        rot    = calcRotMatrix((0, 0, 1), 0)
        body.glObjOffset = makeOpenGLMatrix(rot, offset, (1.0, 1.0, 1.0))
        body.setPosition(pos)
        self.bodies.append(body)

        return body, geom
Пример #2
0
    def addBody(self,
                p1,
                p2,
                radius,
                mass=None,
                upVec=(0, 0, 1),
                collide=True):
        """
        Adds a capsule body between joint positions p1 and p2 and with given
        radius to the ragdoll.
        upVec is the vector pointing up.  This resolves the ambiguity of
        orienting a rotationally symetrical object between 2 points.
        TODO: If p1->p2 || upVec, this will crash
        """

        p1 = add3(p1, self.offset)
        p2 = add3(p2, self.offset)

        # cylinder length not including endcaps, make capsules overlap by half
        #   radius at joints
        cyllen = dist3(p1, p2) - radius

        body = ode.Body(self.sim.world)
        body.color = (128, 128, 40, 255)
        m = ode.Mass()
        if mass is None:
            m.setCappedCylinder(self.density, 3, radius, cyllen)
        else:
            m.setCappedCylinderTotal(mass, 3, radius, cyllen)
        body.setMass(m)

        # set parameters for drawing the body
        body.shape = "capsule"
        body.length = cyllen
        body.radius = radius

        # create a capsule geom for collision detection
        if collide:
            geom = ode.GeomCCylinder(self.sim.space, radius, cyllen)
            geom.setBody(body)
            self.geoms.append(geom)

        # define body rotation automatically from body axis
        za = norm3(sub3(p2, p1))
        # if (abs(dot3(za, (1.0, 0.0, 0.0))) < 0.7): xa = (1.0, 0.0, 0.0)
        # else: xa = (0.0, 1.0, 0.0)
        xa = upVec
        ya = cross(za, xa)
        xa = norm3(cross(ya, za))
        ya = cross(za, xa)
        rot = (xa[0], ya[0], za[0], xa[1], ya[1], za[1], xa[2], ya[2], za[2])

        body.setPosition(mul3(add3(p1, p2), 0.5))
        body.setRotation(rot)

        self.bodies.append(body)

        self.totalMass += body.getMass().mass

        return body
Пример #3
0
    def create_capsule(self,key,density,length,radius,pos,base=0,rot=0,R=0.):
        """Creates a capsule body and corresponding geom.
        
        Arguments:
        key : number id to assign to the capsule
        density : density of the given body
        length : length of the capsule
        radius : radius of the capsule
        pos : position of the center of the capsule (x,y,z list)
        base : place new object at negative end of base object

        """
        # Auto label the joint key or not.
        key = len(self.bodies) if key == -1 else key

        # create capsule body (aligned along the z-axis so that it matches the
        #   GeomCCylinder created below, which is aligned along the z-axis by
        #   default)
        body = ode.Body(self.world)
        M = ode.Mass()
        M.setCapsule(density, 3, radius, length)
        body.setMass(M)
        
        # create a capsule geom for collision detection
        geom = ode.GeomCCylinder(self.space, radius, length)
        geom.setBody(body)
        
        # set the position of the capsule
        body.setPosition((pos[0],pos[1],pos[2]))

        # set parameters for drawing the body
        body.shape = "capsule"
        body.length = length
        body.radius = radius

        # set the rotation of the capsule
        if(rot):
            body.setRotation(self.form_rotation(rot))
       
        # set the rotation of the capsule directly
        if R:
            body.setRotation(R)

        self.bodies[key] = body
        self.geoms[key] = geom

        if(base):
            Placement.place_object(self.bodies[base],body)

        if(self.fluid_dynamics):
            self.create_surfaces(key,1.)  

        return key      
Пример #4
0
def create_cylinder(world, space, density, radius, height):

    body = ode.Body(world)
    M = ode.Mass()
    M.setCappedCylinder(density, direction=1, r=radius, h=height)
    body.setMass(M)
    # Set parameters for drawing the body
    body.shape = "ccylinder"
    body.radius = radius
    body.height = height
    # Create a CCylinder geom for collision detection
    geom = ode.GeomCCylinder(space, radius, height)
    geom.setBody(body)
    return body, geom
Пример #5
0
    def addBody(self, p1, p2, radius):
        """
        adds a capsule body between joint posotions p1 and p2 with given
        radius to the ragdoll.
        """
        p1 = add3(p1, self.offset)
        p2 = add3(p2, self.offset)

        # cylinder length not including endcaps, make capsules overlap by half
        #   radius at joints
        cyllen = dist3(p1, p2) - radius

        body = ode.Body(self.world)
        m = ode.Mass()
        m.setCappedCylinder(self.density, 3, radius, cyllen)
        body.setMass(m)

        # set parameters for drawing the body
        body.shape = "capsule"
        body.length = cyllen
        body.radius = radius

        # create a capsule geom for collision detection
        geom = ode.GeomCCylinder(self.space, radius, cyllen)
        geom.setBody(body)

        # define body rotation automatically from body axis
        za = norm3(sub3(p2, p1))
        if (abs(dot3(za, (1.0, 0.0, 0.0))) < 0.7): xa = (1.0, 0.0, 0.0)
        else: xa = (0.0, 1.0, 0.0)
        ya = cross(za, xa)
        xa = norm3(cross(ya, za))
        ya = cross(za, xa)
        rot = (xa[0], ya[0], za[0], xa[1], ya[1], za[1], xa[2], ya[2], za[2])

        body.setPosition(mul3(add3(p1, p2), 0.5))
        body.setRotation(rot)

        self.bodies.append(body)
        self.geoms.append(geom)

        self.totalMass += body.getMass().mass

        return body
def createCapsule(world, space, density, length, radius):
    """Creates a capsule body and corresponding geom."""

    # create capsule body (aligned along the z-axis so that it matches the
    #   GeomCCylinder created below, which is aligned along the z-axis by
    #   default)
    body = ode.Body(world)
    M = ode.Mass()
    M.setCappedCylinder(density, 3, radius, length)
    body.setMass(M)

    # set parameters for drawing the body
    body.shape = "capsule"
    body.length = length
    body.radius = radius

    # create a capsule geom for collision detection
    geom = ode.GeomCCylinder(space, radius, length)
    geom.setBody(body)

    return body, geom
Пример #7
0
    def addSpringyCappedCylinder(self,
                                 p1,
                                 p2,
                                 radius,
                                 n_members=2,
                                 k_bend=1e5,
                                 k_torsion=1e5):
        """
        Adds a capsule body between joint positions p1 and p2 and with given
        radius to the ragdoll.
        Along the axis of the capsule distribute n_joints ball joints
        With spring constants given by k_bend and k_torsion
        TODO: FUNCTION NOT FINISHED  Wed 14 Dec 2011 06:06:24 PM EST   
        """

        p_start = p1 = add3(p1, self.offset)
        p_end = add3(p2, self.offset)
        iteration_jump = div3(sub3(p_end, p_start), n_members)
        p2 = add3(p1, iteration_jump)

        for i in range(n_members):
            # cylinder length not including endcaps, make capsules overlap by half
            #   radius at joints
            cyllen = dist3(p1, p2) - radius

            body = ode.Body(self.sim.world)
            m = ode.Mass()
            m.setCappedCylinder(self.density, 3, radius, cyllen)
            body.setMass(m)

            # set parameters for drawing the body
            body.shape = "capsule"
            body.length = cyllen
            body.radius = radius

            # create a capsule geom for collision detection
            geom = ode.GeomCCylinder(self.sim.space, radius, cyllen)
            geom.setBody(body)

            # define body rotation automatically from body axis
            za = norm3(sub3(p2, p1))
            if (abs(dot3(za, (1.0, 0.0, 0.0))) < 0.7):
                xa = (1.0, 0.0, 0.0)
            else:
                xa = (0.0, 1.0, 0.0)
            ya = cross(za, xa)
            xa = norm3(cross(ya, za))
            ya = cross(za, xa)
            rot = (xa[0], ya[0], za[0], xa[1], ya[1], za[1], xa[2], ya[2],
                   za[2])

            body.setPosition(mul3(add3(p1, p2), 0.5))
            body.setRotation(rot)

            self.bodies.append(body)
            self.geoms.append(geom)

            self.totalMass += body.getMass().mass

            if i != n_members:
                p1 = p2
                p2 = add3(p1, iteration_jump)

        return body
Пример #8
0
    def addBP(self, bp, parent=None, joint_end=None):
        """Recursively add BodyParts to the simulation.

        bp -- current BodyPart to process
        parent -- parent BP to add to
        joint_end -- which end of the parent ccylinder we should add to"""

        log.debug('addBP')
        body = ode.Body(self.world)
        mass = ode.Mass()
        if not parent:
            # if this is the root we have an absolute length,
            # root scale is relative to midpoint of min..max
            bp.length = bp.scale * (
                bpg.BP_MIN_LENGTH +
                (bpg.BP_MAX_LENGTH - bpg.BP_MIN_LENGTH) / 2)
            bp.isRoot = 1
        else:
            # otherwise child scale is relative to parent
            bp.length = parent.length * bp.scale
            bp.isRoot = 0
    # limit the bp length
        bp.length = min(bp.length, bpg.BP_MAX_LENGTH)
        # mass along x axis, with length without caps==bp.length
        # arg 3 means aligned along z-axis - must be same in renderer and Geoms
        mass.setCappedCylinder(CYLINDER_DENSITY, 3, CYLINDER_RADIUS, bp.length)
        # attach mass to body
        body.setMass(mass)
        # create Geom
        # aligned along z-axis by default!!
        geom = ode.GeomCCylinder(self.space, CYLINDER_RADIUS, bp.length)
        self.geoms.append(geom)
        self.geom_contact[geom] = 0
        # remember parent for collison detection
        if not parent:
            geom.parent = None
        else:
            geom.parent = parent.geom
    # attach geom to body
        geom.setBody(body)
        log.debug('created CappedCylinder(radius=%f, len=%f)', CYLINDER_RADIUS,
                  bp.length)
        # assert(not in a loop)
        assert not hasattr(bp, 'geom')
        # ref geom from bodypart (used above to find parent geom)
        bp.geom = geom

        # set rotation
        (radians, v) = bp.rotation
        log.debug('radians,v = %f,%s', radians, str(v))
        q = quat(radians, vec3(v))
        rotmat = q.toMat3()
        if parent:
            # rotate relative to parent
            p_r = mat3(parent.geom.getRotation())  # joint_end *
            log.debug('parent rotation = %s', str(p_r))
            rotmat = p_r * rotmat
        geom.setRotation(rotmat.toList(rowmajor=1))
        log.debug('r=%s', str(rotmat))
        geom_axis = rotmat * vec3(0, 0, 1)
        log.debug('set geom axis to %s', str(geom_axis))
        (x, y, z) = geom.getBody().getRelPointPos((0, 0, bp.length / 2.0))
        log.debug('real position of joint is %f,%f,%f', x, y, z)
        # set position
        if not parent:
            # root  - initially located at 0,0,0
            # (once the model is constructed we translate it until all
            # bodies have z>0)
            geom.setPosition((0, 0, 0))
            log.debug('set root geom x,y,z = 0,0,0')
        else:
            # child - located relative to the parent. from the
            # parents position move along their axis of orientation to
            # the joint position, then pick a random angle within the
            # joint limits, move along that vector by half the length
            # of the child cylinder, and we have the position of the
            # child.
            # vector from parent xyz is half of parent length along
            # +/- x axis rotated by r
            p_v = vec3(parent.geom.getPosition())
            p_r = mat3(parent.geom.getRotation())
            p_hl = parent.geom.getParams()[1] / 2.0  # half len of par
            j_v = p_v + p_r * vec3(0, 0, p_hl * joint_end)  # joint vector
            # rotation is relative to parent
            c_v = j_v + rotmat * vec3(0, 0, bp.length / 2.0)
            geom.setPosition(tuple(c_v))
            log.debug('set geom x,y,z = %f,%f,%f', c_v[0], c_v[1], c_v[2])

            jointclass = {
                'hinge': ode.HingeJoint,
                'universal': ode.UniversalJoint,
                'ball': ode.BallJoint
            }
            j = jointclass[bp.joint](self.world)

            self.joints.append(j)
            # attach bodies to joint
            j.attach(parent.geom.getBody(), body)
            # set joint position
            j.setAnchor(j_v)
            geom.parent_joint = j

            # create motor and attach to this geom
            motor = Motor(self.world, None)
            motor.setJoint(j)
            self.joints.append(motor)
            bp.motor = motor
            geom.motor = motor
            motor.attach(parent.geom.getBody(), body)
            motor.setMode(ode.AMotorEuler)

            if bp.joint == 'hinge':
                # we have 3 points - parent body, joint, child body
                # find the normal to these points
                # (hinge only has 1 valid axis!)
                try:
                    axis1 = ((j_v - p_v).cross(j_v - c_v)).normalize()
                except ZeroDivisionError:
                    v = (j_v - p_v).cross(j_v - c_v)
                    v.z = 1**-10
                    axis1 = v.normalize()
                log.debug('setting hinge joint axis to %s', axis1)
                log.debug('hinge axis = %s', j.getAxis())
                axis_inv = rotmat.inverse() * axis1
                axis2 = vec3((0, 0, 1)).cross(axis_inv)
                log.debug('hinge axis2 = %s', axis2)
                j.setAxis(tuple(axis1))
                # some anomaly here.. if we change the order of axis2 and axis1,
                # it should make no difference. instead there appears to be an
                # instability when the angle switches from -pi to +pi
                # so.. use parameter3 to control the hinge
                # (maybe this is only a problem in the test case with perfect axis alignment?)
                motor.setAxes(axis2, rotmat * axis1)
            elif bp.joint == 'universal':
                # bp.axis1/2 is relative to bp rotation, so rotate axes
                axis1 = rotmat * vec3(bp.axis1)
                axis2 = rotmat * vec3((0, 0, 1)).cross(vec3(bp.axis1))
                j.setAxis1(tuple(axis1))
                j.setAxis2(tuple(axis2))
                motor.setAxes(axis1, axis2)
            elif bp.joint == 'ball':
                axis1 = rotmat * vec3(bp.axis1)
                axis2 = rotmat * vec3((0, 0, 1)).cross(vec3(bp.axis1))
                motor.setAxes(axis1, axis2)

            log.debug('created joint with parent at %f,%f,%f', j_v[0], j_v[1],
                      j_v[2])

    # recurse on children
        geom.child_joint_ends = set([e.joint_end for e in bp.edges])
        geom.parent_joint_end = joint_end
        if joint_end == None:
            # root
            if -1 in geom.child_joint_ends:
                geom.left = 'internal'
            else:
                geom.left = 'external'
            if 1 in geom.child_joint_ends:
                geom.right = 'internal'
            else:
                geom.right = 'external'
        else:
            # not root
            geom.left = 'internal'
            if 1 in geom.child_joint_ends:
                geom.right = 'internal'
            else:
                geom.right = 'external'

        for e in bp.edges:
            self.addBP(e.child, bp, e.joint_end)
Пример #9
0
    def _createGeom(self, geom, M):
        """Create an ODE geom object for the given cgkit geom.

        Create an ODE geom of the appropriate type (depening on \a geom)
        and apply the transformation \a M to it (currently, M may only
        contain a translation and a rotation, otherwise a warning is
        printed).

        The returned geom is not assigned to a Body yet.

        \param geom (\c GeomObject) cgkit geom object
        \param M (\c mat4) Transformation that's applied to the geom
        \return ODE geom
        """

        # Create the raw geom object that's defined in the local
        # coordinate system L of the world object this geom belongs to.

        # Sphere geom?
        if isinstance(geom, SphereGeom):
            odegeom = ode.GeomSphere(None, geom.radius)
        # CCylinder geom?
        elif isinstance(geom, CCylinderGeom):
            odegeom = ode.GeomCCylinder(None, geom.radius, geom.length)
        # Box geom?
        elif isinstance(geom, BoxGeom):
            odegeom = ode.GeomBox(None, (geom.lx, geom.ly, geom.lz))
        # TriMesh geom?
        elif isinstance(geom, TriMeshGeom):
            verts = []
            for i in range(geom.verts.size()):
                verts.append(geom.verts.getValue(i))
#                print "V",i,verts[i]
            faces = []
            for i in range(geom.faces.size()):
                f = geom.faces.getValue(i)
                faces.append(f)
                #                print "F",i,faces[i]
                ia, ib, ic = faces[i]
                a = verts[ia]
                b = verts[ib]
                c = verts[ic]
                sa = ((b - a).cross(c - a)).length()
#                if sa<0.0001:
#                    print "*****KLEIN*****",sa

            tmd = ode.TriMeshData()
            tmd.build(verts, faces)
            odegeom = ode.GeomTriMesh(tmd, None)
        # Plane geom?
        elif isinstance(geom, PlaneGeom):
            L = obj.localTransform()
            n = L * vec3(0, 0, 1) - L * vec3(0)
            n = n.normalize()
            d = n * obj.pos
            odegeom = ode.GeomPlane(space, n, d)
        # Unknown geometry
        else:
            raise ValueError, 'WARNING: ODEDynamics: Cannot determine collision geometry of object "%s".' % geom.name
#            print 'WARNING: ODEDynamics: Cannot determine collision geometry of object "%s". Using bounding box instead.'%obj.name
#            bmin, bmax = obj.boundingBox().getBounds()
#            s = bmax-bmin
#            odegeom = ode.GeomBox(None, s)
#            pos,rot,scale = P.inverse().decompose()
#            odegeom.setPosition(pos + 0.5*(bmax+bmin))
#            odegeomtransform = ode.GeomTransform(space)
#            odegeomtransform.setGeom(odegeom)
#            return odegeomtransform

# Displace the geom by M
        pos, rot, scale = M.decompose()
        if scale != vec3(1, 1, 1):
            print 'WARNING: ODEDynamics: Scaled geometries are not supported'
        odegeom.setPosition(pos)
        # row major or column major?
        odegeom.setRotation(rot.getMat3().toList(rowmajor=True))

        return odegeom