Esempio n. 1
0
void dJointGetAMotorAxis( dJointID j, int anum, dVector3 result )
{
    dxJointAMotor* joint = ( dxJointAMotor* )j;
    dAASSERT( joint && anum >= 0 && anum < 3 );
    checktype( joint, AMotor );
    if ( anum < 0 ) anum = 0;
    if ( anum > 2 ) anum = 2;
    
    // If we're in Euler mode, joint->axis[1] doesn't
    // have anything sensible in it.  So don't just return
    // that, find the actual effective axis.
    // Likewise, the actual axis of rotation for the
    // the other axes is different from what's stored.
    if ( joint->mode == dAMotorEuler  ) {
      dVector3 axes[3];
      joint->computeGlobalAxes(axes);
      if (anum == 1) {
        result[0]=axes[1][0];
        result[1]=axes[1][1];
        result[2]=axes[1][2];
      } else if (anum == 0) {
        // This won't be unit length in general,
        // but it's what's used in getInfo2
        // This may be why things freak out as
        // the body-relative axes get close to each other.
        dCalcVectorCross3( result, axes[1], axes[2] );
      } else if (anum == 2) {
        // Same problem as above.
        dCalcVectorCross3( result, axes[0], axes[1] );
      }
    } else if ( joint->rel[anum] > 0 ) {
        if ( joint->rel[anum] == 1 )
        {
            dMultiply0_331( result, joint->node[0].body->posr.R, joint->axis[anum] );
        }
        else
        {
            if ( joint->node[1].body )   // jds
            {
                dMultiply0_331( result, joint->node[1].body->posr.R, joint->axis[anum] );
            }
            else
            {
                result[0] = joint->axis[anum][0];
                result[1] = joint->axis[anum][1];
                result[2] = joint->axis[anum][2];
                result[3] = joint->axis[anum][3];
            }
        }
    }
    else
    {
        result[0] = joint->axis[anum][0];
        result[1] = joint->axis[anum][1];
        result[2] = joint->axis[anum][2];
    }
}
// helper for less key strokes
inline void _CalculateAxis(const dVector3& v1,
                           const dVector3& v2,
                           const dVector3& v3,
                           const dVector3& v4,
                           dVector3& r)
{
    dVector3 t1;
    dVector3 t2;

    SUBTRACT(v1,v2,t1);
    dCalcVectorCross3(t2,t1,v3);
    dCalcVectorCross3(r,t2,v4);
}
Esempio n. 3
0
void
dxJointHinge2::makeW1andW2()
{
    if ( node[1].body )
    {
        // get axis 1 and 2 in global coords
        dVector3 ax1, ax2, w;
        dMultiply0_331( ax1, node[0].body->posr.R, axis1 );
        dMultiply0_331( ax2, node[1].body->posr.R, axis2 );

        // don't do anything if the axis1 or axis2 vectors are zero or the same
        if (( ax1[0] == 0 && ax1[1] == 0 && ax1[2] == 0 ) ||
            ( ax2[0] == 0 && ax2[1] == 0 && ax2[2] == 0 ) ||
            ( ax1[0] == ax2[0] && ax1[1] == ax2[1] && ax1[2] == ax2[2] ) ) return;

        // modify axis 1 so it's perpendicular to axis 2
        dReal k = dCalcVectorDot3( ax2, ax1 );
        for ( int i = 0; i < 3; i++ ) ax1[i] -= k * ax2[i];
        dNormalize3( ax1 );

        // make w1 = modified axis1, w2 = axis2 x (modified axis1)
        dCalcVectorCross3( w, ax2, ax1 );
        dMultiply1_331( w1, node[1].body->posr.R, ax1 );
        dMultiply1_331( w2, node[1].body->posr.R, w );
    }
}
Esempio n. 4
0
void
dxJointHinge2::makeV1andV2()
{
    if ( node[0].body )
    {
        // get axis 1 and 2 in global coords
        dVector3 ax1, ax2, v;
        dMultiply0_331( ax1, node[0].body->posr.R, axis1 );
        dMultiply0_331( ax2, node[1].body->posr.R, axis2 );

        // don't do anything if the axis1 or axis2 vectors are zero or the same
        if ((_dequal(ax1[0], 0.0) && _dequal(ax1[1], 0.0) && _dequal(ax1[2], 0.0)) ||
            (_dequal(ax2[0], 0.0) && _dequal(ax2[1], 0.0) && _dequal(ax2[2], 0.0)) ||
            (_dequal(ax1[0], ax2[0]) && _dequal(ax1[1], ax2[1]) && _dequal(ax1[2], ax2[2])))
          return;

        // modify axis 2 so it's perpendicular to axis 1
        dReal k = dCalcVectorDot3( ax1, ax2 );
        for ( int i = 0; i < 3; i++ ) ax2[i] -= k * ax1[i];
        dNormalize3( ax2 );

        // make v1 = modified axis2, v2 = axis1 x (modified axis2)
        dCalcVectorCross3( v, ax1, ax2 );
        dMultiply1_331( v1, node[0].body->posr.R, ax2 );
        dMultiply1_331( v2, node[0].body->posr.R, v );
    }
}
Esempio n. 5
0
static int edgeIntersectsRect (dVector3 v1, dVector3 v2,
			       dVector3 p1, dVector3 p2, dVector3 p3)
{
  int k;
  dVector3 u1,u2,n,tmp;
  for (k=0; k<3; k++) u1[k] = p3[k]-p1[k];
  for (k=0; k<3; k++) u2[k] = p2[k]-p1[k];
  dReal d1 = dSqrt(dCalcVectorDot3(u1,u1));
  dReal d2 = dSqrt(dCalcVectorDot3(u2,u2));
  dNormalize3 (u1);
  dNormalize3 (u2);
  if (dFabs(dCalcVectorDot3(u1,u2)) > 1e-6) dDebug (0,"bad u1/u2");
  dCalcVectorCross3(n,u1,u2);
  for (k=0; k<3; k++) tmp[k] = v2[k]-v1[k];
  dReal d = -dCalcVectorDot3(n,p1);
  if (dFabs(dCalcVectorDot3(n,p1)+d) > 1e-8) dDebug (0,"bad n wrt p1");
  if (dFabs(dCalcVectorDot3(n,p2)+d) > 1e-8) dDebug (0,"bad n wrt p2");
  if (dFabs(dCalcVectorDot3(n,p3)+d) > 1e-8) dDebug (0,"bad n wrt p3");
  dReal alpha = -(d+dCalcVectorDot3(n,v1))/dCalcVectorDot3(n,tmp);
  for (k=0; k<3; k++) tmp[k] = v1[k]+alpha*(v2[k]-v1[k]);
  if (dFabs(dCalcVectorDot3(n,tmp)+d) > 1e-6) dDebug (0,"bad tmp");
  if (alpha < 0) return 0;
  if (alpha > 1) return 0;
  for (k=0; k<3; k++) tmp[k] -= p1[k];
  dReal a1 = dCalcVectorDot3(u1,tmp);
  dReal a2 = dCalcVectorDot3(u2,tmp);
  if (a1<0 || a2<0 || a1>d1 || a2>d2) return 0;
  return 1;
}
Esempio n. 6
0
void
dxJointAMotor::getInfo2( dxJoint::Info2 *info )
{
    int i;

    // compute the axes (if not global)
    dVector3 ax[3];
    computeGlobalAxes( ax );

    // in euler angle mode we do not actually constrain the angular velocity
    // along the axes axis[0] and axis[2] (although we do use axis[1]) :
    //
    //    to get   constrain w2-w1 along  ...not
    //    ------   ---------------------  ------
    //    d(angle[0])/dt = 0 ax[1] x ax[2]   ax[0]
    //    d(angle[1])/dt = 0 ax[1]
    //    d(angle[2])/dt = 0 ax[0] x ax[1]   ax[2]
    //
    // constraining w2-w1 along an axis 'a' means that a'*(w2-w1)=0.
    // to prove the result for angle[0], write the expression for angle[0] from
    // GetInfo1 then take the derivative. to prove this for angle[2] it is
    // easier to take the euler rate expression for d(angle[2])/dt with respect
    // to the components of w and set that to 0.

    dVector3 *axptr[3];
    axptr[0] = &ax[0];
    axptr[1] = &ax[1];
    axptr[2] = &ax[2];

    dVector3 ax0_cross_ax1;
    dVector3 ax1_cross_ax2;
    if ( mode == dAMotorEuler )
    {
        dCalcVectorCross3( ax0_cross_ax1, ax[0], ax[1] );
        axptr[2] = &ax0_cross_ax1;
        dCalcVectorCross3( ax1_cross_ax2, ax[1], ax[2] );
        axptr[0] = &ax1_cross_ax2;
    }

    int row = 0;
    for ( i = 0; i < num; i++ )
    {
        row += limot[i].addLimot( this, info, row, *( axptr[i] ), 1 );
    }
}
Esempio n. 7
0
////////////////////////////////////////////////////////////////////////////////
/// Function that computes ax1,ax2 = axis 1 and 2 in global coordinates (they are
/// relative to body 1 and 2 initially) and then computes the constrained
/// rotational axis as the cross product of ax1 and ax2.
/// the sin and cos of the angle between axis 1 and 2 is computed, this comes
/// from dot and cross product rules.
///
/// @param ax1 Will contain the joint axis1 in world frame
/// @param ax2 Will contain the joint axis2 in world frame
/// @param axis Will contain the cross product of ax1 x ax2
/// @param sin_angle
/// @param cos_angle
////////////////////////////////////////////////////////////////////////////////
void
dxJointHinge2::getAxisInfo(dVector3 ax1, dVector3 ax2, dVector3 axCross,
                           dReal &sin_angle, dReal &cos_angle) const
{
    dMultiply0_331 (ax1, node[0].body->posr.R, axis1);
    dMultiply0_331 (ax2, node[1].body->posr.R, axis2);
    dCalcVectorCross3(axCross,ax1,ax2);
    sin_angle = dSqrt (axCross[0]*axCross[0] + axCross[1]*axCross[1] + axCross[2]*axCross[2]);
    cos_angle = dCalcVectorDot3 (ax1,ax2);
}
Esempio n. 8
0
// compute the 3 axes in global coordinates
void
dxJointAMotor::computeGlobalAxes( dVector3 ax[3] )
{
    if ( mode == dAMotorEuler )
    {
        // special handling for euler mode
        dMultiply0_331( ax[0], node[0].body->posr.R, axis[0] );
        if ( node[1].body )
        {
            dMultiply0_331( ax[2], node[1].body->posr.R, axis[2] );
        }
        else
        {
            ax[2][0] = axis[2][0];
            ax[2][1] = axis[2][1];
            ax[2][2] = axis[2][2];
        }
        dCalcVectorCross3( ax[1], ax[2], ax[0] );
        dNormalize3( ax[1] );
    }
    else
    {
        for ( int i = 0; i < num; i++ )
        {
            if ( rel[i] == 1 )
            {
                // relative to b1
                dMultiply0_331( ax[i], node[0].body->posr.R, axis[i] );
            }
            else if ( rel[i] == 2 )
            {
                // relative to b2
                if ( node[1].body )   // jds: don't assert, just ignore
                {
                    dMultiply0_331( ax[i], node[1].body->posr.R, axis[i] );
                }
                else
                {
                    // global - just copy it
                    ax[i][0] = axis[i][0];
                    ax[i][1] = axis[i][1];
                    ax[i][2] = axis[i][2];
                }
            }
            else
            {
                // global - just copy it
                ax[i][0] = axis[i][0];
                ax[i][1] = axis[i][1];
                ax[i][2] = axis[i][2];
            }
        }
    }
}
Esempio n. 9
0
void
dxJointAMotor::computeEulerAngles( dVector3 ax[3] )
{
    // assumptions:
    //   global axes already calculated --> ax
    //   axis[0] is relative to body 1 --> global ax[0]
    //   axis[2] is relative to body 2 --> global ax[2]
    //   ax[1] = ax[2] x ax[0]
    //   original ax[0] and ax[2] are perpendicular
    //   reference1 is perpendicular to ax[0] (in body 1 frame)
    //   reference2 is perpendicular to ax[2] (in body 2 frame)
    //   all ax[] and reference vectors are unit length

    // calculate references in global frame
    dVector3 ref1, ref2;
    dMultiply0_331( ref1, node[0].body->posr.R, reference1 );
    if ( node[1].body )
    {
        dMultiply0_331( ref2, node[1].body->posr.R, reference2 );
    }
    else
    {
        ref2[0] = reference2[0];
        ref2[1] = reference2[1];
        ref2[2] = reference2[2];
    }

    // get q perpendicular to both ax[0] and ref1, get first euler angle
    dVector3 q;
    dCalcVectorCross3( q, ax[0], ref1 );
    angle[0] = -dAtan2( dCalcVectorDot3( ax[2], q ), dCalcVectorDot3( ax[2], ref1 ) );

    // get q perpendicular to both ax[0] and ax[1], get second euler angle
    dCalcVectorCross3( q, ax[0], ax[1] );
    angle[1] = -dAtan2( dCalcVectorDot3( ax[2], ax[0] ), dCalcVectorDot3( ax[2], q ) );

    // get q perpendicular to both ax[1] and ax[2], get third euler angle
    dCalcVectorCross3( q, ax[1], ax[2] );
    angle[2] = -dAtan2( dCalcVectorDot3( ref2, ax[1] ), dCalcVectorDot3( ref2, q ) );
}
Esempio n. 10
0
void makeRandomRotation (dMatrix3 R)
{
  dReal *u1 = R, *u2=R+4, *u3=R+8;
  dMakeRandomVector (u1,3,1.0);
  dNormalize3 (u1);
  dMakeRandomVector (u2,3,1.0);
  dReal d = dCalcVectorDot3(u1,u2);
  u2[0] -= d*u1[0];
  u2[1] -= d*u1[1];
  u2[2] -= d*u1[2];
  dNormalize3(u2);
  dCalcVectorCross3(u3,u1,u2);
}
Esempio n. 11
0
void dRigidBodyArraySetAngularVel(dRigidBodyArrayID bodyArray, dReal ax, dReal ay, dReal az) {
    dBodyID center = bodyArray->center;
    const dReal *p0 = dBodyGetPosition(center);
    dVector3 omega = {ax, ay, az};
    for(size_t i = 0; i < dRigidBodyArraySize(bodyArray); i++) {
        dBodyID body = dRigidBodyArrayGet(bodyArray, i);
        const dReal *p = dBodyGetPosition(body);
        dVector3 pdot, r;
        dOP(r, -, p, p0);
        dCalcVectorCross3(pdot, omega, r);
        dBodySetLinearVel(body, pdot[0], pdot[1], pdot[2]);
        dBodySetAngularVel(body, ax, ay, az);
    }
}
Esempio n. 12
0
void testCrossProduct()
{
  HEADER;

  dVector3 a1,a2,b,c;
  dMatrix3 B;
  dMakeRandomVector (b,3,1.0);
  dMakeRandomVector (c,3,1.0);

  dCalcVectorCross3(a1,b,c);

  dSetZero (B,12);
  dSetCrossMatrixPlus(B,b,4);
  dMultiply0 (a2,B,c,3,3,1);

  dReal diff = dMaxDifference(a1,a2,3,1);
  printf ("\t%s\n", diff > tol ? "FAILED" : "passed");
}
Esempio n. 13
0
void dJointAddScrewForce ( dJointID j, dReal force )
{
    dxJointScrew* joint = ( dxJointScrew* ) j;
    dVector3 axis;
    dUASSERT ( joint, "bad joint argument" );
    checktype ( joint, Screw );

    if ( joint->flags & dJOINT_REVERSE )
        force -= force;

    getAxis ( joint, axis, joint->axis1 );
    axis[0] *= force;
    axis[1] *= force;
    axis[2] *= force;

    if ( joint->node[0].body != 0 )
        dBodyAddForce ( joint->node[0].body, axis[0], axis[1], axis[2] );
    if ( joint->node[1].body != 0 )
        dBodyAddForce ( joint->node[1].body, -axis[0], -axis[1], -axis[2] );

    if ( joint->node[0].body != 0 && joint->node[1].body != 0 )
    {
        // linear torque decoupling:
        // we have to compensate the torque, that this screw force may generate
        // if body centers are not aligned along the screw axis

        dVector3 ltd; // Linear Torque Decoupling vector (a torque)

        dVector3 cgdiff;
        cgdiff[0] = REAL ( 0.5 ) * ( joint->node[1].body->posr.pos[0] -
          joint->node[0].body->posr.pos[0] );
        cgdiff[1] = REAL ( 0.5 ) * ( joint->node[1].body->posr.pos[1] -
          joint->node[0].body->posr.pos[1] );
        cgdiff[2] = REAL ( 0.5 ) * ( joint->node[1].body->posr.pos[2] -
          joint->node[0].body->posr.pos[2] );
        dCalcVectorCross3( ltd, cgdiff, axis );

        dBodyAddTorque ( joint->node[0].body, ltd[0], ltd[1], ltd[2] );
        dBodyAddTorque ( joint->node[1].body, ltd[0], ltd[1], ltd[2] );
    }
}
Esempio n. 14
0
/*
* This takes what is supposed to be a rotation matrix,
* and make sure it is correct.
* Note: this operates on rows, not columns, because for rotations
* both ways give equivalent results.
*/
void dOrthogonalizeR(dMatrix3 m)
{
    dReal n0 = dCalcVectorLengthSquare3(m);
    if (n0 != 1)
        dSafeNormalize3(m);

    // project row[0] on row[1], should be zero
    dReal proj = dCalcVectorDot3(m, m+4);
    if (proj != 0) {
        // Gram-Schmidt step on row[1]
        m[4] -= proj * m[0];
        m[5] -= proj * m[1];
        m[6] -= proj * m[2];
    }
    dReal n1 = dCalcVectorLengthSquare3(m+4);
    if (n1 != 1)
        dSafeNormalize3(m+4);

    /* just overwrite row[2], this makes sure the matrix is not
    a reflection */
    dCalcVectorCross3(m+8, m, m+4);
    m[3] = m[4+3] = m[8+3] = 0;
}
Esempio n. 15
0
void
dxJointHinge::getInfo2( dxJoint::Info2 *info )
{
    // Added by OSRF
    // If joint values of erp and cfm are negative, then ignore them.
    // info->erp, info->cfm already have the global values from quickstep
    if (this->erp >= 0)
      info->erp = erp;
    if (this->cfm >= 0)
    {
      info->cfm[0] = cfm;
      info->cfm[1] = cfm;
      info->cfm[2] = cfm;
      info->cfm[3] = cfm;
      info->cfm[4] = cfm;
      info->cfm[5] = cfm;
    }

    // set the three ball-and-socket rows
    setBall( this, info, anchor1, anchor2 );

    // set the two hinge rows. the hinge axis should be the only unconstrained
    // rotational axis, the angular velocity of the two bodies perpendicular to
    // the hinge axis should be equal. thus the constraint equations are
    //    p*w1 - p*w2 = 0
    //    q*w1 - q*w2 = 0
    // where p and q are unit vectors normal to the hinge axis, and w1 and w2
    // are the angular velocity vectors of the two bodies.

    dVector3 ax1;  // length 1 joint axis in global coordinates, from 1st body
    dVector3 p, q; // plane space vectors for ax1
    dMultiply0_331( ax1, node[0].body->posr.R, axis1 );
    dPlaneSpace( ax1, p, q );

    // strange the rotation matrix is not really a rotation matrix (non-orthogonal vectors)
    // normals of columns and rows are not exactly 1 when velocity is large.
    // printf("posr.R\n[%f %f %f %f]\n[%f %f %f %f]\n[%f %f %f %f]\n",
    //   node[0].body->posr.R[0*4+0],node[0].body->posr.R[0*4+1],node[0].body->posr.R[0*4+2],node[0].body->posr.R[0*4+3],
    //   node[0].body->posr.R[1*4+0],node[0].body->posr.R[1*4+1],node[0].body->posr.R[1*4+2],node[0].body->posr.R[1*4+3],
    //   node[0].body->posr.R[2*4+0],node[0].body->posr.R[2*4+1],node[0].body->posr.R[2*4+2],node[0].body->posr.R[2*4+3]);

    // printf("axis1 [%f %f %f] ax1 [%f %f %f]\n",
    //         axis1[0], axis1[1], axis1[2],
    //         ax1[0], ax1[1], ax1[2]);


    int s3 = 3 * info->rowskip;
    int s4 = 4 * info->rowskip;

    info->J1a[s3+0] = p[0];
    info->J1a[s3+1] = p[1];
    info->J1a[s3+2] = p[2];
    info->J1a[s4+0] = q[0];
    info->J1a[s4+1] = q[1];
    info->J1a[s4+2] = q[2];

    if ( node[1].body )
    {
        info->J2a[s3+0] = -p[0];
        info->J2a[s3+1] = -p[1];
        info->J2a[s3+2] = -p[2];
        info->J2a[s4+0] = -q[0];
        info->J2a[s4+1] = -q[1];
        info->J2a[s4+2] = -q[2];
    }

    // compute the right hand side of the constraint equation. set relative
    // body velocities along p and q to bring the hinge back into alignment.
    // if ax1,ax2 are the unit length hinge axes as computed from body1 and
    // body2, we need to rotate both bodies along the axis u = (ax1 x ax2).
    // if `theta' is the angle between ax1 and ax2, we need an angular velocity
    // along u to cover angle erp*theta in one step :
    //   |angular_velocity| = angle/time = erp*theta / stepsize
    //                      = (erp*fps) * theta
    //    angular_velocity  = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2|
    //                      = (erp*fps) * theta * (ax1 x ax2) / sin(theta)
    // ...as ax1 and ax2 are unit length. if theta is smallish,
    // theta ~= sin(theta), so
    //    angular_velocity  = (erp*fps) * (ax1 x ax2)
    // ax1 x ax2 is in the plane space of ax1, so we project the angular
    // velocity to p and q to find the right hand side.

    dVector3 ax2, b;
    if ( node[1].body )
    {
        dMultiply0_331( ax2, node[1].body->posr.R, axis2 );
    }
    else
    {
        ax2[0] = axis2[0];
        ax2[1] = axis2[1];
        ax2[2] = axis2[2];
    }
    dCalcVectorCross3( b, ax1, ax2 );
    dReal k = info->fps * info->erp;
    info->c[3] = k * dCalcVectorDot3( b, p );
    info->c[4] = k * dCalcVectorDot3( b, q );

    // if the hinge is powered, or has joint limits, add in the stuff
    limot.addLimot( this, info, 5, ax1, 1 );

    // joint damping
    if (this->use_damping)
    {
      // added J1ad and J2ad for damping, only 1 row
      info->J1ad[0] = ax1[0];
      info->J1ad[1] = ax1[1];
      info->J1ad[2] = ax1[2];
      if ( this->node[1].body )
      {
        info->J2ad[0] = -ax1[0];
        info->J2ad[1] = -ax1[1];
        info->J2ad[2] = -ax1[2];
      }
      // there's no rhs for damping setup, all we want to use is the jacobian information above
    }
}
void SimpleTrackedVehicleEnvironment::nearCallbackGrouserTerrain(dGeomID o1, dGeomID o2) {
    dBodyID b1 = dGeomGetBody(o1);
    dBodyID b2 = dGeomGetBody(o2);
    if(b1 && b2 && dAreConnectedExcluding(b1, b2, dJointTypeContact)) return;

    // body of the whole vehicle
    dBodyID vehicleBody = ((SimpleTrackedVehicle*)this->v)->vehicleBody;

    unsigned long geom1Categories = dGeomGetCategoryBits(o1);

    // speeds of the belts
    const dReal leftBeltSpeed = ((SimpleTrackedVehicle*)this->v)->leftTrack->getVelocity();
    const dReal rightBeltSpeed = ((SimpleTrackedVehicle*)this->v)->rightTrack->getVelocity();

    dReal beltSpeed = 0; // speed of the belt which is in collision and examined right now
    if (geom1Categories & Category::LEFT) {
        beltSpeed = leftBeltSpeed;
    } else {
        beltSpeed = rightBeltSpeed;
    }

    // the desired linear and angular speeds (set by desired track velocities)
    const dReal linearSpeed = (leftBeltSpeed + rightBeltSpeed) / 2;
    const dReal angularSpeed = (leftBeltSpeed - rightBeltSpeed) * steeringEfficiency / tracksDistance;

    // radius of the turn the robot is doing
    const dReal desiredRotationRadiusSigned = (fabs(angularSpeed) < 0.1) ?
                                                dInfinity : // is driving straight
                                                ((fabs(linearSpeed) < 0.1) ?
                                                    0 : // is rotating about a single point
                                                    linearSpeed / angularSpeed // general movement
                                                );


    dVector3 yAxisGlobal; // vector pointing from vehicle body center in the direction of +y axis
    dVector3 centerOfRotation; // at infinity if driving straight, so we need to distinguish the case
    { // compute the center of rotation
        dBodyVectorToWorld(vehicleBody, 0, 1, 0, yAxisGlobal);

        dCopyVector3(centerOfRotation, yAxisGlobal);
        // make the unit vector as long as we need (and change orientation if needed; the radius is a signed number)
        dScaleVector3(centerOfRotation, desiredRotationRadiusSigned);

        const dReal *vehicleBodyPos = dBodyGetPosition(vehicleBody);
        dAddVectors3(centerOfRotation, centerOfRotation, vehicleBodyPos);
    }

    int maxContacts = 20;
    dContact contact[maxContacts];
    int numContacts = dCollide(o1, o2, maxContacts, &contact[0].geom, sizeof(dContact));

    for(size_t i = 0; i < numContacts; i++) {
        dVector3 contactInVehiclePos; // position of the contact point relative to vehicle body
        dBodyGetPosRelPoint(vehicleBody, contact[i].geom.pos[0], contact[i].geom.pos[1], contact[i].geom.pos[2], contactInVehiclePos);

        dVector3 beltDirection; // vector tangent to the belt pointing in the belt's movement direction
        dCalcVectorCross3(beltDirection, contact[i].geom.normal, yAxisGlobal);
        if (beltSpeed > 0) {
            dNegateVector3(beltDirection);
        }

        if (desiredRotationRadiusSigned != dInfinity) { // non-straight drive

            dVector3 COR2Contact; // vector pointing from the center of rotation to the contact point
            dSubtractVectors3(COR2Contact, contact[i].geom.pos, centerOfRotation);
            // the friction force should be perpendicular to COR2Contact
            dCalcVectorCross3(contact[i].fdir1, contact[i].geom.normal, COR2Contact);

            const dReal linearSpeedSignum = (fabs(linearSpeed) > 0.1) ? sgn(linearSpeed) : 1;

            // contactInVehiclePos[0] > 0 means the contact is in the front part of the track
            if (sgn(angularSpeed) * sgn(dCalcVectorDot3(yAxisGlobal, contact[i].fdir1)) !=
                    sgn(contactInVehiclePos[0]) * linearSpeedSignum) {
                dNegateVector3(contact[i].fdir1);
            }

        } else { // straight drive

            dCalcVectorCross3(contact[i].fdir1, contact[i].geom.normal, yAxisGlobal);

            if (dCalcVectorDot3(contact[i].fdir1, beltDirection) < 0) {
                dNegateVector3(contact[i].fdir1);
            }

        }

        // use friction direction and motion1 to simulate the track movement
        contact[i].surface.mode = dContactFDir1 | dContactMotion1 | dContactMu2;
        contact[i].surface.mu = 0.5;
        contact[i].surface.mu2 = 10;
        // the dot product <beltDirection,fdir1> is the cosine of the angle they form (because both are unit vectors)
        contact[i].surface.motion1 = -dCalcVectorDot3(beltDirection, contact[i].fdir1) * fabs(beltSpeed) * 0.07;

        // friction force visualization
        dMatrix3 forceRotation;
        dVector3 vec;
        dBodyVectorToWorld(vehicleBody, 1, 0, 0, vec);
        dRFrom2Axes(forceRotation, contact[i].fdir1[0], contact[i].fdir1[1], contact[i].fdir1[2], vec[0], vec[1], vec[2]);
        posr data;
        dCopyVector3(data.pos, contact[i].geom.pos);
        dCopyMatrix4x3(data.R, forceRotation);
        forces.push_back(data);

        dJointID c = dJointCreateContact(this->world, this->contactGroup, &contact[i]);
        dJointAttach(c, b1, b2);
        if(!isValidCollision(o1, o2, contact[i]))
            this->badCollision = true;
        if(config.contact_grouser_terrain.debug)
            this->contacts.push_back(contact[i].geom);
    }
}
int dCollideSTL(dxGeom* g1, dxGeom* SphereGeom, int Flags, dContactGeom* Contacts, int Stride){
    dIASSERT (Stride >= (int)sizeof(dContactGeom));
    dIASSERT (g1->type == dTriMeshClass);
    dIASSERT (SphereGeom->type == dSphereClass);
    dIASSERT ((Flags & NUMC_MASK) >= 1);

    dxTriMesh* TriMesh = (dxTriMesh*)g1;

    // Init
    const dVector3& TLPosition = *(const dVector3*)dGeomGetPosition(TriMesh);
    const dMatrix3& TLRotation = *(const dMatrix3*)dGeomGetRotation(TriMesh);

    const unsigned uiTLSKind = TriMesh->getParentSpaceTLSKind();
    dIASSERT(uiTLSKind == SphereGeom->getParentSpaceTLSKind()); // The colliding spaces must use matching cleanup method
    TrimeshCollidersCache *pccColliderCache = GetTrimeshCollidersCache(uiTLSKind);
    SphereCollider& Collider = pccColliderCache->_SphereCollider;

    const dVector3& Position = *(const dVector3*)dGeomGetPosition(SphereGeom);
    dReal Radius = dGeomSphereGetRadius(SphereGeom);

    // Sphere
    Sphere Sphere;
    dCopyVector3(Sphere.mCenter, Position);
    Sphere.mRadius = Radius;

    Matrix4x4 amatrix;

    // TC results
    if (TriMesh->doSphereTC) {
        dxTriMesh::SphereTC* sphereTC = 0;
        for (int i = 0; i < TriMesh->SphereTCCache.size(); i++){
            if (TriMesh->SphereTCCache[i].Geom == SphereGeom){
                sphereTC = &TriMesh->SphereTCCache[i];
                break;
            }
        }

        if (!sphereTC){
            TriMesh->SphereTCCache.push(dxTriMesh::SphereTC());

            sphereTC = &TriMesh->SphereTCCache[TriMesh->SphereTCCache.size() - 1];
            sphereTC->Geom = SphereGeom;
        }

        // Intersect
        Collider.SetTemporalCoherence(true);
        Collider.Collide(*sphereTC, Sphere, TriMesh->Data->BVTree, null, 
            &MakeMatrix(TLPosition, TLRotation, amatrix));
    }
    else {
        Collider.SetTemporalCoherence(false);
        Collider.Collide(pccColliderCache->defaultSphereCache, Sphere, TriMesh->Data->BVTree, null, 
            &MakeMatrix(TLPosition, TLRotation, amatrix));
    }

    if (! Collider.GetContactStatus()) {
        // no collision occurred
        return 0;
    }

    // get results
    int TriCount = Collider.GetNbTouchedPrimitives();
    const int* Triangles = (const int*)Collider.GetTouchedPrimitives();

    if (TriCount != 0){
        if (TriMesh->ArrayCallback != null){
            TriMesh->ArrayCallback(TriMesh, SphereGeom, Triangles, TriCount);
        }

        int OutTriCount = 0;
        for (int i = 0; i < TriCount; i++){
            if (OutTriCount == (Flags & NUMC_MASK)){
                break;
            }

            const int TriIndex = Triangles[i];

            dVector3 dv[3];
            if (!Callback(TriMesh, SphereGeom, TriIndex))
                continue;

            FetchTriangle(TriMesh, TriIndex, TLPosition, TLRotation, dv);

            dVector3& v0 = dv[0];
            dVector3& v1 = dv[1];
            dVector3& v2 = dv[2];

            dVector3 vu;
            dSubtractVectors3r4(vu, v1, v0);
            vu[3] = REAL(0.0);

            dVector3 vv;
            dSubtractVectors3r4(vv, v2, v0);
            vv[3] = REAL(0.0);

            // Get plane coefficients
            dVector4 Plane;
            dCalcVectorCross3(Plane, vu, vv);

            // Even though all triangles might be initially valid, 
            // a triangle may degenerate into a segment after applying 
            // space transformation.
            if (!dSafeNormalize3(Plane)) {
                continue;
            }

            /* If the center of the sphere is within the positive halfspace of the
            * triangle's plane, allow a contact to be generated.
            * If the center of the sphere made it into the positive halfspace of a
            * back-facing triangle, then the physics update and/or velocity needs
            * to be adjusted (penetration has occured anyway).
            */

            dReal side = dCalcVectorDot3(Plane, Position) - dCalcVectorDot3(Plane, v0);

            if(side < REAL(0.0))
            {
                continue;
            }

            dReal Depth;
            dReal u, v;
            if (!GetContactData(Position, Radius, v0, vu, vv, Depth, u, v)){
                continue;	// Sphere doesn't hit triangle
            }

            if (Depth < REAL(0.0)){
                continue; // Negative depth does not produce a contact
            }

            dVector3 ContactPos;

            dReal w = REAL(1.0) - u - v;
            dAddScaledVectors3r4(ContactPos, v1, v2, u, v);
            dAddScaledVector3r4(ContactPos, v0, w);

            // Depth returned from GetContactData is depth along 
            // contact point - sphere center direction
            // we'll project it to contact normal
            dVector3 dir;
            dSubtractVectors3r4(dir, Position, ContactPos);
            dReal dirProj = dCalcVectorDot3(dir, Plane) / dCalcVectorLength3(dir);

            // Since Depth already had a requirement to be non-negative,
            // negative direction projections should not be allowed as well,
            // as otherwise the multiplication will result in negative contact depth.
            if (dirProj < REAL(0.0))
                continue; // Zero contact depth could be ignored

            dContactGeom* Contact = SAFECONTACT(Flags, Contacts, OutTriCount, Stride);

            dCopyVector3r4(Contact->pos, ContactPos);

            // Using normal as plane (reversed)
            dCopyNegatedVector3r4(Contact->normal, Plane);
            Contact->depth = Depth * dirProj;
            //Contact->depth = Radius - side; // (mg) penetration depth is distance along normal not shortest distance

            // We need to set these unconditionally, as the merging may fail! - Bram
            Contact->g1 = TriMesh;
            Contact->g2 = SphereGeom;
            Contact->side2 = -1;

            Contact->side1 = TriIndex;

            OutTriCount++;
        }
        if (OutTriCount > 0)
        {
            if (TriMesh->SphereContactsMergeOption == MERGE_CONTACTS_FULLY)
            {
                dContactGeom* Contact = SAFECONTACT(Flags, Contacts, 0, Stride);
                Contact->g1 = TriMesh;
                Contact->g2 = SphereGeom;
                Contact->side2 = -1;

                if (OutTriCount > 1 && !(Flags & CONTACTS_UNIMPORTANT))
                {
                    dVector3 pos;
                    dCopyVector3r4(pos, Contact->pos);

                    dVector3 normal;
                    dCopyScaledVector3r4(normal, Contact->normal, Contact->depth);

                    int TriIndex = Contact->side1; 

                    for (int i = 1; i < OutTriCount; i++)
                    {
                        dContactGeom* TempContact = SAFECONTACT(Flags, Contacts, i, Stride);

                        dAddVector3r4(pos, TempContact->pos);
                        dAddScaledVector3r4(normal, TempContact->normal, TempContact->depth);
                        TriIndex = (TriMesh->TriMergeCallback) ? TriMesh->TriMergeCallback(TriMesh, TriIndex, TempContact->side1) : -1;
                    }

                    Contact->side1 = TriIndex;
                    dReal invOutTriCount = dRecip(OutTriCount);
                    dCopyScaledVector3r4(Contact->pos, pos, invOutTriCount);

                    if ( !dSafeNormalize3(normal) )
                        return OutTriCount;	// Cannot merge in this pathological case

                    // Using a merged normal, means that for each intersection, this new normal will be less effective in solving the intersection.
                    // That is why we need to correct this by increasing the depth for each intersection.
                    // The maximum of the adjusted depths is our newly merged depth value - Bram.

                    dReal mergedDepth = REAL(0.0);
                    dReal minEffectiveness = REAL(0.5);
                    for ( int i = 0; i < OutTriCount; ++i )
                    {
                        dContactGeom* TempContact = SAFECONTACT(Flags, Contacts, i, Stride);
                        dReal effectiveness = dCalcVectorDot3(normal, TempContact->normal);
                        if ( effectiveness < dEpsilon )
                            return OutTriCount; // Cannot merge this pathological case
                        // Cap our adjustment for the new normal to a factor 2, meaning a 60 deg change in normal.
                        effectiveness = ( effectiveness < minEffectiveness ) ? minEffectiveness : effectiveness;
                        dReal adjusted = TempContact->depth / effectiveness;
                        mergedDepth = ( mergedDepth < adjusted ) ? adjusted : mergedDepth;
                    }
                    Contact->depth = mergedDepth;
                    dCopyVector3r4(Contact->normal, normal);
                }

                return 1;
            }
            else if (TriMesh->SphereContactsMergeOption == MERGE_CONTACT_NORMALS)
            {
                if (OutTriCount != 1 && !(Flags & CONTACTS_UNIMPORTANT))
                {
                    dVector3 Normal;

                    dContactGeom* FirstContact = SAFECONTACT(Flags, Contacts, 0, Stride);
                    dCopyScaledVector3r4(Normal, FirstContact->normal, FirstContact->depth);

                    for (int i = 1; i < OutTriCount; i++)
                    {
                        dContactGeom* Contact = SAFECONTACT(Flags, Contacts, i, Stride);
                        dAddScaledVector3r4(Normal, Contact->normal, Contact->depth);
                    }

                    dNormalize3(Normal);

                    for (int i = 0; i < OutTriCount; i++)
                    {
                        dContactGeom* Contact = SAFECONTACT(Flags, Contacts, i, Stride);

                        dCopyVector3r4(Contact->normal, Normal);
                    }
                }

                return OutTriCount;
            }
            else
            {
                dIASSERT(TriMesh->SphereContactsMergeOption == DONT_MERGE_CONTACTS);
                return OutTriCount;
            }
        }
        else return 0;
    }
    else return 0;
}
Esempio n. 18
0
void
dxJointPU::getInfo2( dReal worldFPS, dReal worldERP, 
    int rowskip, dReal *J1, dReal *J2,
    int pairskip, dReal *pairRhsCfm, dReal *pairLoHi, 
    int *findex )
{
    const dReal k = worldFPS * worldERP;

    // ======================================================================
    // The angular constraint
    //
    dVector3 ax1, ax2; // Global axes of rotation
    getAxis(this, ax1, axis1);
    getAxis2(this,ax2, axis2);

    dVector3 uniPerp;  // Axis perpendicular to axes of rotation
    dCalcVectorCross3(uniPerp,ax1,ax2);
    dNormalize3( uniPerp );

    dCopyVector3( J1 + GI2__JA_MIN, uniPerp );

    dxBody *body1 = node[1].body;

    if ( body1 ) {
        dCopyNegatedVector3( J2 + GI2__JA_MIN , uniPerp );
    }
    // Corrective velocity attempting to keep uni axes perpendicular
    dReal val = dCalcVectorDot3( ax1, ax2 );
    // Small angle approximation : 
    // theta = asin(val)
    // theta is approximately val when val is near zero.
    pairRhsCfm[GI2_RHS] = -k * val; 
    
    // ==========================================================================
    // Handle axes orthogonal to the prismatic 
    dVector3 an1, an2; // Global anchor positions
    dVector3 axP, sep; // Prismatic axis and separation vector
    getAnchor(this, an1, anchor1);
    getAnchor2(this, an2, anchor2);

    if (flags & dJOINT_REVERSE) {
        getAxis2(this, axP, axisP1);
    } else {
        getAxis(this, axP, axisP1);
    }
    dSubtractVectors3(sep, an2, an1);

    dVector3 p, q;
    dPlaneSpace(axP, p, q);

    dCopyVector3( J1 + rowskip + GI2__JL_MIN, p );
    dCopyVector3( J1 + 2 * rowskip + GI2__JL_MIN, q );
    // Make the anchors be body local
    // Aliasing isn't a problem here.
    dSubtractVectors3(an1, an1, node[0].body->posr.pos);
    dCalcVectorCross3( J1 + rowskip + GI2__JA_MIN, an1, p );
    dCalcVectorCross3( J1 + 2 * rowskip + GI2__JA_MIN, an1, q );

    if (body1) {
        dCopyNegatedVector3( J2 + rowskip + GI2__JL_MIN, p );
        dCopyNegatedVector3( J2 + 2 * rowskip + GI2__JL_MIN, q );
        dSubtractVectors3(an2, an2, body1->posr.pos);
        dCalcVectorCross3( J2 + rowskip + GI2__JA_MIN, p, an2 );
        dCalcVectorCross3( J2 + 2 * rowskip + GI2__JA_MIN, q, an2 );
    }

    pairRhsCfm[pairskip + GI2_RHS] = k * dCalcVectorDot3( p, sep );
    pairRhsCfm[2 * pairskip + GI2_RHS] = k * dCalcVectorDot3( q, sep );
    
    // ==========================================================================
    // Handle the limits/motors
    int currRowSkip = 3 * rowskip, currPairSkip = 3 * pairskip;

    if (limot1.addLimot( this, worldFPS, J1 + currRowSkip, J2 + currRowSkip, pairRhsCfm + currPairSkip, pairLoHi + currPairSkip, ax1, 1 )) {
        currRowSkip += rowskip; currPairSkip += pairskip;
    }

    if (limot2.addLimot( this, worldFPS, J1 + currRowSkip, J2 + currRowSkip, pairRhsCfm + currPairSkip, pairLoHi + currPairSkip, ax2, 1 )) {
        currRowSkip += rowskip; currPairSkip += pairskip;
    }

    if (  body1 || (flags & dJOINT_REVERSE) == 0 ) {
        limotP.addTwoPointLimot( this, worldFPS, J1 + currRowSkip, J2 + currRowSkip, pairRhsCfm + currPairSkip, pairLoHi + currPairSkip, axP, an1, an2 );
    } else {
        dNegateVector3(axP);
        limotP.addTwoPointLimot ( this, worldFPS, J1 + currRowSkip, J2 + currRowSkip, pairRhsCfm + currPairSkip, pairLoHi + currPairSkip, axP, an1, an2  );
    }
}
Esempio n. 19
0
void
dxJointUniversal::getInfo2( dReal worldFPS, dReal worldERP, 
    int rowskip, dReal *J1, dReal *J2,
    int pairskip, dReal *pairRhsCfm, dReal *pairLoHi, 
    int *findex )
{
    // set the three ball-and-socket rows
    setBall( this, worldFPS, worldERP, rowskip, J1, J2, pairskip, pairRhsCfm, anchor1, anchor2 );

    // set the universal joint row. the angular velocity about an axis
    // perpendicular to both joint axes should be equal. thus the constraint
    // equation is
    //    p*w1 - p*w2 = 0
    // where p is a vector normal to both joint axes, and w1 and w2
    // are the angular velocity vectors of the two bodies.

    // length 1 joint axis in global coordinates, from each body
    dVector3 ax1, ax2;
    // length 1 vector perpendicular to ax1 and ax2. Neither body can rotate
    // about this.
    dVector3 p;
    
    // Since axis1 and axis2 may not be perpendicular
    // we find a axis2_tmp which is really perpendicular to axis1
    // and in the plane of axis1 and axis2
    getAxes( ax1, ax2 );

    dReal k = dCalcVectorDot3( ax1, ax2 );

    dVector3 ax2_temp;
    dAddVectorScaledVector3(ax2_temp, ax2, ax1, -k);
    dCalcVectorCross3( p, ax1, ax2_temp );
    dNormalize3( p );

    int currRowSkip = 3 * rowskip;
    {
        dCopyVector3( J1 + currRowSkip + GI2__JA_MIN, p);

        if ( node[1].body )
        {
            dCopyNegatedVector3( J2 + currRowSkip + GI2__JA_MIN, p);
        }
    }

    // compute the right hand side of the constraint equation. set relative
    // body velocities along p to bring the axes back to perpendicular.
    // If ax1, ax2 are unit length joint axes as computed from body1 and
    // body2, we need to rotate both bodies along the axis p.  If theta
    // is the angle between ax1 and ax2, we need an angular velocity
    // along p to cover the angle erp * (theta - Pi/2) in one step:
    //
    //   |angular_velocity| = angle/time = erp*(theta - Pi/2) / stepsize
    //                      = (erp*fps) * (theta - Pi/2)
    //
    // if theta is close to Pi/2,
    // theta - Pi/2 ~= cos(theta), so
    //    |angular_velocity|  ~= (erp*fps) * (ax1 dot ax2)

    int currPairSkip = 3 * pairskip;
    {
        pairRhsCfm[currPairSkip + GI2_RHS] = worldFPS * worldERP * (-k);
    }

    currRowSkip += rowskip; currPairSkip += pairskip;

    // if the first angle is powered, or has joint limits, add in the stuff
    if (limot1.addLimot( this, worldFPS, J1 + currRowSkip, J2 + currRowSkip, pairRhsCfm + currPairSkip, pairLoHi + currPairSkip, ax1, 1 ))
    {
        currRowSkip += rowskip; currPairSkip += pairskip;
    }

    // if the second angle is powered, or has joint limits, add in more stuff
    limot2.addLimot( this, worldFPS, J1 + currRowSkip, J2 + currRowSkip, pairRhsCfm + currPairSkip, pairLoHi + currPairSkip, ax2, 1 );
}
Esempio n. 20
0
void
dxJointTransmission::getInfo2( dReal worldFPS, 
                               dReal /*worldERP*/,
                               const Info2Descr* info )
 {
    dVector3 a[2], n[2], l[2], r[2], c[2], s, t, O, d, z, u, v;
    dReal theta, delta, nn, na_0, na_1, cosphi, sinphi, m;
    const dReal *p[2], *omega[2];
    int i;

    // Transform all needed quantities to the global frame.

    for (i = 0 ; i < 2 ; i += 1) {
        dBodyGetRelPointPos(node[i].body,
                            anchors[i][0], anchors[i][1], anchors[i][2],
                            a[i]);

        dBodyVectorToWorld(node[i].body, axes[i][0], axes[i][1], axes[i][2],
                           n[i]);

        p[i] = dBodyGetPosition(node[i].body);
        omega[i] = dBodyGetAngularVel(node[i].body);
    }

    if (update) {
        // Make sure both gear reference frames end up with the same
        // handedness.
    
        if (dCalcVectorDot3(n[0], n[1]) < 0) {
            dNegateVector3(axes[0]);
            dNegateVector3(n[0]);
        }
    }

    // Calculate the mesh geometry based on the current mode.
    
    switch (mode) {
    case dTransmissionParallelAxes:
        // Simply calculate the contact point as the point on the
        // baseline that will yield the correct ratio.

        dIASSERT (ratio > 0);
        
        dSubtractVectors3(d, a[1], a[0]);
        dAddScaledVectors3(c[0], a[0], d, 1, ratio / (1 + ratio));
        dCopyVector3(c[1], c[0]);
        
        dNormalize3(d);
        
        for (i = 0 ; i < 2 ; i += 1) {
            dCalcVectorCross3(l[i], d, n[i]);
        }

        break;
    case dTransmissionIntersectingAxes:
        // Calculate the line of intersection between the planes of the
        // gears.

        dCalcVectorCross3(l[0], n[0], n[1]);
        dCopyVector3(l[1], l[0]);

        nn = dCalcVectorDot3(n[0], n[1]);
        dIASSERT(fabs(nn) != 1);
        
        na_0 = dCalcVectorDot3(n[0], a[0]);
        na_1 = dCalcVectorDot3(n[1], a[1]);

        dAddScaledVectors3(O, n[0], n[1],
                           (na_0 - na_1 * nn) / (1 - nn * nn),
                           (na_1 - na_0 * nn) / (1 - nn * nn));

        // Find the contact point as:
        //
        // c = ((r_a - O) . l) l + O
        //
        // where r_a the anchor point of either gear and l, O the tangent
        // line direction and origin.

        for (i = 0 ; i < 2 ; i += 1) {
            dSubtractVectors3(d, a[i], O);
            m = dCalcVectorDot3(d, l[i]);        
            dAddScaledVectors3(c[i], O, l[i], 1, m);
        }

        break;
    case dTransmissionChainDrive:
        dSubtractVectors3(d, a[0], a[1]);
        m = dCalcVectorLength3(d);

        dIASSERT(m > 0);
        
        // Caclulate the angle of the contact point relative to the
        // baseline.

        cosphi = clamp((radii[1] - radii[0]) / m, REAL(-1.0), REAL(1.0)); // Force into range to fix possible computation errors
        sinphi = dSqrt (REAL(1.0) - cosphi * cosphi);

        dNormalize3(d);

        for (i = 0 ; i < 2 ; i += 1) {
            // Calculate the contact radius in the local reference
            // frame of the chain.  This has axis x pointing along the
            // baseline, axis y pointing along the sprocket axis and
            // the remaining axis normal to both.

            u[0] = radii[i] * cosphi;
            u[1] = 0;
            u[2] = radii[i] * sinphi;

            // Transform the contact radius into the global frame.

            dCalcVectorCross3(z, d, n[i]);
            
            v[0] = dCalcVectorDot3(d, u);
            v[1] = dCalcVectorDot3(n[i], u);
            v[2] = dCalcVectorDot3(z, u);

            // Finally calculate contact points and l.
            
            dAddVectors3(c[i], a[i], v);
            dCalcVectorCross3(l[i], v, n[i]);
            dNormalize3(l[i]);

            // printf ("%d: %f, %f, %f\n",
            //      i, l[i][0], l[i][1], l[i][2]);
        }

        break;
    }

    if (update) {
        // We need to calculate an initial reference frame for each
        // wheel which we can measure the current phase against.  This
        // frame will have the initial contact radius as the x axis,
        // the wheel axis as the z axis and their cross product as the
        // y axis.

        for (i = 0 ; i < 2 ; i += 1) {
            dSubtractVectors3 (r[i], c[i], a[i]);
            radii[i] = dCalcVectorLength3(r[i]);
            dIASSERT(radii[i] > 0);
            
            dBodyVectorFromWorld(node[i].body, r[i][0], r[i][1], r[i][2],
                                 reference[i]);
            dNormalize3(reference[i]);
            dCopyVector3(reference[i] + 8, axes[i]);
            dCalcVectorCross3(reference[i] + 4, reference[i] + 8, reference[i]);

            // printf ("%f\n", dDOT(r[i], n[i]));
            // printf ("(%f, %f, %f,\n %f, %f, %f,\n %f, %f, %f)\n",
            //      reference[i][0],reference[i][1],reference[i][2],
            //      reference[i][4],reference[i][5],reference[i][6],
            //      reference[i][8],reference[i][9],reference[i][10]);

            radii[i] = radii[i];
            phase[i] = 0;
        }

        ratio = radii[0] / radii[1];
        update = 0;
    }
    
    for (i = 0 ; i < 2 ; i += 1) {
        dReal phase_hat;

        dSubtractVectors3 (r[i], c[i], a[i]);
        
        // Transform the (global) contact radius into the gear's
        // reference frame.

        dBodyVectorFromWorld (node[i].body, r[i][0], r[i][1], r[i][2], s);
        dMultiply0_331(t, reference[i], s);

        // Now simply calculate its angle on the plane relative to the
        // x-axis which is the initial contact radius.  This will be
        // an angle between -pi and pi that is coterminal with the
        // actual phase of the wheel.  To find the real phase we
        // estimate it by adding omega * dt to the old phase and then
        // find the closest angle to that, that is coterminal to
        // theta.

        theta = atan2(t[1], t[0]);
        phase_hat = phase[i] + dCalcVectorDot3(omega[i], n[i]) / worldFPS;

        if (phase_hat > M_PI_2) {
            if (theta < 0) {
                theta += (dReal)(2 * M_PI);
            }

            theta += (dReal)(floor(phase_hat / (2 * M_PI)) * (2 * M_PI));
        } else if (phase_hat < -M_PI_2) {
            if (theta > 0) {
                theta -= (dReal)(2 * M_PI);
            }

            theta += (dReal)(ceil(phase_hat / (2 * M_PI)) * (2 * M_PI));
        }
                
        if (phase_hat - theta > M_PI) {
            phase[i] = theta + (dReal)(2 * M_PI);
        } else if (phase_hat - theta < -M_PI) {
            phase[i] = theta - (dReal)(2 * M_PI);
        } else {
            phase[i] = theta;
        }

        dIASSERT(fabs(phase_hat - phase[i]) < M_PI);
    }

    // Calculate the phase error.  Depending on the mode the condition
    // is that the distances traveled by each contact point must be
    // either equal (chain and sprockets) or opposite (gears).

    if (mode == dTransmissionChainDrive) {
        delta = (dCalcVectorLength3(r[0]) * phase[0] -
                 dCalcVectorLength3(r[1]) * phase[1]);
    } else {
        delta = (dCalcVectorLength3(r[0]) * phase[0] +
                 dCalcVectorLength3(r[1]) * phase[1]);
    }

    // When in chain mode a torque reversal, signified by the change
    // in sign of the wheel phase difference, has the added effect of
    // switching the active chain branch.  We must therefore reflect
    // the contact points and tangents across the baseline.
    
    if (mode == dTransmissionChainDrive && delta < 0) {
        dVector3 d;

        dSubtractVectors3(d, a[0], a[1]);
        
        for (i = 0 ; i < 2 ; i += 1) {
            dVector3 nn;
            dReal a;
            
            dCalcVectorCross3(nn, n[i], d);
            a = dCalcVectorDot3(nn, nn);
            dIASSERT(a > 0);
            
            dAddScaledVectors3(c[i], c[i], nn,
                               1, -2 * dCalcVectorDot3(c[i], nn) / a);
            dAddScaledVectors3(l[i], l[i], nn,
                               -1, 2 * dCalcVectorDot3(l[i], nn) / a);
        }
    }

    // Do not add the constraint if there's backlash and we're in the
    // backlash gap.

    if (backlash == 0 || fabs(delta) > backlash) {
        // The constraint is satisfied iff the absolute velocity of the
        // contact point projected onto the tangent of the wheels is equal
        // for both gears.  This velocity can be calculated as:
        // 
        // u = v + omega x r_c
        // 
        // The constraint therefore becomes:
        // (v_1 + omega_1 x r_c1) . l = (v_2 + omega_2 x r_c2) . l <=>
        // (v_1 . l + (r_c1 x l) . omega_1 = v_2 . l + (r_c2 x l) . omega_2

        for (i = 0 ; i < 2 ; i += 1) {
            dSubtractVectors3 (r[i], c[i], p[i]);
        }

        dCalcVectorCross3(info->J1a, r[0], l[0]);
        dCalcVectorCross3(info->J2a, l[1], r[1]);

        dCopyVector3(info->J1l, l[0]);
        dCopyNegatedVector3(info->J2l, l[1]);

        if (delta > 0) {
            if (backlash > 0) {
                info->lo[0] = -dInfinity;
                info->hi[0] = 0;
            }

            info->c[0] = -worldFPS * erp * (delta - backlash);
        } else {
            if (backlash > 0) {
                info->lo[0] = 0;
                info->hi[0] = dInfinity;
            }

            info->c[0] = -worldFPS * erp * (delta + backlash);
        }
    }

    info->cfm[0] = cfm;

    // printf ("%f, %f, %f, %f, %f\n", delta, phase[0], phase[1], -phase[1] / phase[0], ratio);

    // Cache the contact point (in world coordinates) to avoid
    // recalculation if requested by the user.

    dCopyVector3(contacts[0], c[0]);
    dCopyVector3(contacts[1], c[1]);
}
Esempio n. 21
0
void setBall2( dxJoint *joint, dxJoint::Info2 *info,
               dVector3 anchor1, dVector3 anchor2,
               dVector3 axis, dReal erp1 )
{
    // anchor points in global coordinates with respect to body PORs.
    dVector3 a1, a2;

    int i, s = info->rowskip;

    // get vectors normal to the axis. in setBall() axis,q1,q2 is [1 0 0],
    // [0 1 0] and [0 0 1], which makes everything much easier.
    dVector3 q1, q2;
    dPlaneSpace( axis, q1, q2 );

    // set jacobian
    for ( i = 0; i < 3; i++ ) info->J1l[i] = axis[i];
    for ( i = 0; i < 3; i++ ) info->J1l[s+i] = q1[i];
    for ( i = 0; i < 3; i++ ) info->J1l[2*s+i] = q2[i];
    dMultiply0_331( a1, joint->node[0].body->posr.R, anchor1 );
    dCalcVectorCross3( info->J1a, a1, axis );
    dCalcVectorCross3( info->J1a + s, a1, q1 );
    dCalcVectorCross3( info->J1a + 2*s, a1, q2 );
    if ( joint->node[1].body )
    {
        for ( i = 0; i < 3; i++ ) info->J2l[i] = -axis[i];
        for ( i = 0; i < 3; i++ ) info->J2l[s+i] = -q1[i];
        for ( i = 0; i < 3; i++ ) info->J2l[2*s+i] = -q2[i];
        dMultiply0_331( a2, joint->node[1].body->posr.R, anchor2 );
        dReal *J2a = info->J2a;
        dCalcVectorCross3( J2a, a2, axis );
        dNegateVector3( J2a );
        dReal *J2a_plus_s = J2a + s;
        dCalcVectorCross3( J2a_plus_s, a2, q1 );
        dNegateVector3( J2a_plus_s );
        dReal *J2a_plus_2s = J2a_plus_s + s;
        dCalcVectorCross3( J2a_plus_2s, a2, q2 );
        dNegateVector3( J2a_plus_2s );
    }

    // set right hand side - measure error along (axis,q1,q2)
    dReal k1 = info->fps * erp1;
    dReal k = info->fps * info->erp;

    for ( i = 0; i < 3; i++ ) a1[i] += joint->node[0].body->posr.pos[i];
    if ( joint->node[1].body )
    {
        for ( i = 0; i < 3; i++ ) a2[i] += joint->node[1].body->posr.pos[i];
        
        dVector3 a2_minus_a1;
        dSubtractVectors3(a2_minus_a1, a2, a1);
        info->c[0] = k1 * dCalcVectorDot3( axis, a2_minus_a1 );
        info->c[1] = k * dCalcVectorDot3( q1, a2_minus_a1 );
        info->c[2] = k * dCalcVectorDot3( q2, a2_minus_a1 );
    }
    else
    {
        dVector3 anchor2_minus_a1;
        dSubtractVectors3(anchor2_minus_a1, anchor2, a1);
        info->c[0] = k1 * dCalcVectorDot3( axis, anchor2_minus_a1 );
        info->c[1] = k * dCalcVectorDot3( q1, anchor2_minus_a1 );
        info->c[2] = k * dCalcVectorDot3( q2, anchor2_minus_a1 );
    }
}
Esempio n. 22
0
File: pu.cpp Progetto: JohnCrash/ode
void
dxJointPU::getInfo2( dReal worldFPS, dReal worldERP, const Info2Descr *info )
{
    const int s1 = info->rowskip;
    const int s2 = 2 * s1;
    const dReal k = worldFPS * worldERP;

    // ======================================================================
    // The angular constraint
    //
    dVector3 ax1, ax2; // Global axes of rotation
    getAxis(this, ax1, axis1);
    getAxis2(this,ax2, axis2);

    dVector3 uniPerp;  // Axis perpendicular to axes of rotation
    dCalcVectorCross3(uniPerp,ax1,ax2);
    dNormalize3( uniPerp );
    dCopyVector3( info->J1a , uniPerp );
    if ( node[1].body )
    {
        dCopyNegatedVector3( info->J2a , uniPerp );
    }
    // Corrective velocity attempting to keep uni axes perpendicular
    dReal val = dCalcVectorDot3( ax1, ax2 );
    // Small angle approximation : 
    // theta = asin(val)
    // theta is approximately val when val is near zero.
    info->c[0] = -k * val; 
    
    // ==========================================================================
    // Handle axes orthogonal to the prismatic 
    dVector3 an1, an2; // Global anchor positions
    dVector3 axP, sep; // Prismatic axis and separation vector
    getAnchor(this,an1,anchor1);
    getAnchor2(this,an2,anchor2);
    if (flags & dJOINT_REVERSE) {
        getAxis2(this, axP, axisP1);
    } else {
        getAxis(this, axP, axisP1);
    }
    dSubtractVectors3(sep,an2,an1);

    dVector3 p,q;
    dPlaneSpace(axP,p,q);

    dCopyVector3(( info->J1l ) + s1, p );
    dCopyVector3(( info->J1l ) + s2, q );
    // Make the anchors be body local
    // Aliasing isn't a problem here.
    dSubtractVectors3(an1,an1,node[0].body->posr.pos);
    dCalcVectorCross3(( info->J1a ) + s1, an1, p );
    dCalcVectorCross3(( info->J1a ) + s2, an1, q );

    if (node[1].body) {
        dCopyNegatedVector3(( info->J2l ) + s1, p );
        dCopyNegatedVector3(( info->J2l ) + s2, q );
        dSubtractVectors3(an2,an2,node[1].body->posr.pos);
        dCalcVectorCross3(( info->J2a ) + s1, p, an2 );
        dCalcVectorCross3(( info->J2a ) + s2, q, an2 );
    }

    info->c[1] = k * dCalcVectorDot3( p, sep );
    info->c[2] = k * dCalcVectorDot3( q, sep );
    
    // ==========================================================================
    // Handle the limits/motors
    int row = 3 + limot1.addLimot( this, worldFPS, info, 3, ax1, 1 );
    row += limot2.addLimot( this, worldFPS, info, row, ax2, 1 );

    if (  node[1].body || !(flags & dJOINT_REVERSE) )
        limotP.addTwoPointLimot( this, worldFPS, info, row, axP, an1, an2 );
    else
    {
        axP[0] = -axP[0];
        axP[1] = -axP[1];
        axP[2] = -axP[2];
        limotP.addTwoPointLimot ( this, worldFPS, info, row, axP, an1, an2  );
    }
}
Esempio n. 23
0
void
dxJointSlider::getInfo2 ( dReal worldFPS, dReal worldERP, const Info2Descr *info )
{
    int i, s = info->rowskip;
    int s3 = 3 * s, s4 = 4 * s;

    // pull out pos and R for both bodies. also get the `connection'
    // vector pos2-pos1.

    dReal *pos1, *pos2, *R1, *R2;
    dVector3 c;
    pos1 = node[0].body->posr.pos;
    R1 = node[0].body->posr.R;
    if ( node[1].body )
    {
        pos2 = node[1].body->posr.pos;
        R2 = node[1].body->posr.R;
        for ( i = 0; i < 3; i++ )
            c[i] = pos2[i] - pos1[i];
    }
    else
    {
        pos2 = 0;
        R2 = 0;
    }

    // 3 rows to make body rotations equal
    setFixedOrientation ( this, worldFPS, worldERP, info, qrel, 0 );

    // remaining two rows. we want: vel2 = vel1 + w1 x c ... but this would
    // result in three equations, so we project along the planespace vectors
    // so that sliding along the slider axis is disregarded. for symmetry we
    // also substitute (w1+w2)/2 for w1, as w1 is supposed to equal w2.

    dVector3 ax1; // joint axis in global coordinates (unit length)
    dVector3 p, q; // plane space of ax1
    dMultiply0_331 ( ax1, R1, axis1 );
    dPlaneSpace ( ax1, p, q );
    if ( node[1].body )
    {
        dVector3 tmp;
        dCalcVectorCross3( tmp, c, p );
        dScaleVector3r4( tmp, REAL( 0.5 ));
        for ( i = 0; i < 3; i++ ) info->J1a[s3+i] = tmp[i];
        for ( i = 0; i < 3; i++ ) info->J2a[s3+i] = tmp[i];
        dCalcVectorCross3( tmp, c, q );
        dScaleVector3r4( tmp, REAL( 0.5 ));
        for ( i = 0; i < 3; i++ ) info->J1a[s4+i] = tmp[i];
        for ( i = 0; i < 3; i++ ) info->J2a[s4+i] = tmp[i];
        for ( i = 0; i < 3; i++ ) info->J2l[s3+i] = -p[i];
        for ( i = 0; i < 3; i++ ) info->J2l[s4+i] = -q[i];
    }
    for ( i = 0; i < 3; i++ ) info->J1l[s3+i] = p[i];
    for ( i = 0; i < 3; i++ ) info->J1l[s4+i] = q[i];

    // compute last two elements of right hand side. we want to align the offset
    // point (in body 2's frame) with the center of body 1.
    dReal k = worldFPS * worldERP;
    if ( node[1].body )
    {
        dVector3 ofs;  // offset point in global coordinates
        dMultiply0_331 ( ofs, R2, offset );
        for ( i = 0; i < 3; i++ ) c[i] += ofs[i];
        info->c[3] = k * dCalcVectorDot3 ( p, c );
        info->c[4] = k * dCalcVectorDot3 ( q, c );
    }
    else
    {
        dVector3 ofs;  // offset point in global coordinates
        for ( i = 0; i < 3; i++ ) ofs[i] = offset[i] - pos1[i];
        info->c[3] = k * dCalcVectorDot3 ( p, ofs );
        info->c[4] = k * dCalcVectorDot3 ( q, ofs );

        if ( flags & dJOINT_REVERSE )
            for ( i = 0; i < 3; ++i ) ax1[i] = -ax1[i];
    }

    // if the slider is powered, or has joint limits, add in the extra row
    limot.addLimot ( this, worldFPS, info, 5, ax1, 0 );
}
Esempio n. 24
0
void
dxJointPU::getInfo2( dxJoint::Info2 *info )
{
    const int s0 = 0;
    const int s1 = info->rowskip;
    const int s2 = 2 * s1;

    const dReal k = info->fps * info->erp;

    // pull out pos and R for both bodies. also get the `connection'
    // vector pos2-pos1.

    dReal *pos1, *pos2 = 0, *R1, *R2 = 0;
    pos1 = node[0].body->posr.pos;
    R1 = node[0].body->posr.R;
    if ( node[1].body )
    {
        pos2 = node[1].body->posr.pos;
        R2 = node[1].body->posr.R;
    }

    dVector3 axP; // Axis of the prismatic joint in global frame
    dMultiply0_331( axP, R1, axisP1 );

    // distance between the body1 and the anchor2 in global frame
    // Calculated in the same way as the offset
    dVector3 dist;
    dVector3 wanchor2 = {0,0,0};
    if ( node[1].body )
    {
        dMultiply0_331( wanchor2, R2, anchor2 );
        dist[0] = wanchor2[0] + pos2[0] - pos1[0];
        dist[1] = wanchor2[1] + pos2[1] - pos1[1];
        dist[2] = wanchor2[2] + pos2[2] - pos1[2];
    }
    else
    {
        if (flags & dJOINT_REVERSE )
        {
            // Invert the sign of dist
            dist[0] = pos1[0] - anchor2[0];
            dist[1] = pos1[1] - anchor2[1];
            dist[2] = pos1[2] - anchor2[2];
        }
        else
        {
            dist[0] = anchor2[0] - pos1[0];
            dist[1] = anchor2[1] - pos1[1];
            dist[2] = anchor2[2] - pos1[2];
        }
    }

    dVector3 q; // Temporary axis vector
    // Will be used at 2 places with 2 different meaning

    // ======================================================================
    // Work on the angular part (i.e. row 0)
    //

    // The axis perpendicular to both axis1 and axis2 should be the only unconstrained
    // rotational axis, the angular velocity of the two bodies perpendicular to
    // the rotoide axes should be equal. Thus the constraint equations are
    //    p*w1 - p*w2 = 0
    // where p is a unit vector perpendicular to both axis1 and axis2
    // and w1 and w2 are the angular velocity vectors of the two bodies.
    dVector3 ax1, ax2;
    getAxes( ax1, ax2 );
    dReal val = dCalcVectorDot3( ax1, ax2 );
    q[0] = ax2[0] - val * ax1[0];
    q[1] = ax2[1] - val * ax1[1];
    q[2] = ax2[2] - val * ax1[2];

    dVector3 p;
    dCalcVectorCross3( p, ax1, q );
    dNormalize3( p );

    //   info->J1a[s0+i] = p[i];
    dCopyVector3(( info->J1a ) + s0, p );

    if ( node[1].body )
    {
        //   info->J2a[s0+i] = -p[i];
        dCopyNegatedVector3(( info->J2a ) + s0, p );
    }

    // compute the right hand side of the constraint equation. Set relative
    // body velocities along p to bring the axes back to perpendicular.
    // If ax1, ax2 are unit length joint axes as computed from body1 and
    // body2, we need to rotate both bodies along the axis p.  If theta
    // is the angle between ax1 and ax2, we need an angular velocity
    // along p to cover the angle erp * (theta - Pi/2) in one step:
    //
    //   |angular_velocity| = angle/time = erp*(theta - Pi/2) / stepsize
    //                      = (erp*fps) * (theta - Pi/2)
    //
    // if theta is close to Pi/2,
    // theta - Pi/2 ~= cos(theta), so
    //    |angular_velocity|  ~= (erp*fps) * (ax1 dot ax2)

    info->c[0] = k * - val;



    // ==========================================================================
    // Work on the linear part (i.e rows 1 and 2)
    //
    // We want: vel2 = vel1 + w1 x c ... but this would
    // result in three equations, so we project along the planespace vectors
    // so that sliding along the axisP is disregarded.
    //
    // p1 + R1 dist' = p2 + R2 anchor2'
    // v1 + w1 x R1 dist' + v_p = v2 + w2 x R2 anchor2'
    // v_p is speed of prismatic joint (i.e. elongation rate)
    // Since the constraints are perpendicular to v_p we have:
    // e1 dot v_p = 0 and e2 dot v_p = 0
    // e1 dot ( v1 + w1 x dist = v2 + w2 x anchor2 )
    // e2 dot ( v1 + w1 x dist = v2 + w2 x anchor2 )
    // ==
    // e1 . v1 + e1 . w1 x dist = e1 . v2 + e1 . w2 x anchor2
    // since a . (b x c) = - b . (a x c) = - (a x c) . b
    // and a x b = - b x a
    // e1 . v1 - e1 x dist . w1 - e1 . v2 - (- e1 x anchor2 . w2) = 0
    // e1 . v1 + dist x e1 . w1 - e1 . v2 - anchor2 x e1 . w2 = 0
    // Coeff for 1er line of: J1l => e1, J2l => -e1
    // Coeff for 2er line of: J1l => e2, J2l => -ax2
    // Coeff for 1er line of: J1a => dist x e1, J2a => - anchor2 x e1
    // Coeff for 2er line of: J1a => dist x e2, J2a => - anchor2 x e2
    // e1 and e2 are perpendicular to axP
    // so e1 = ax1 and e2 = ax1 x axP
    // N.B. ax2 is not always perpendicular to axP since it is attached to body 2
    dCalcVectorCross3( q , ax1, axP );

    dMultiply0_331( axP, R1, axisP1 );

    dCalcVectorCross3(( info->J1a ) + s1, dist, ax1 );
    dCalcVectorCross3(( info->J1a ) + s2, dist, q );

    // info->J1l[s1+i] = ax[i];
    dCopyVector3(( info->J1l ) + s1, ax1 );

    // info->J1l[s2+i] = q[i];
    dCopyVector3(( info->J1l ) + s2, q );

    if ( node[1].body )
    {
        // Calculate anchor2 in world coordinate

        // q x anchor2 instead of anchor2 x q since we want the negative value
        dCalcVectorCross3(( info->J2a ) + s1, ax1, wanchor2 );
        // The cross product is in reverse order since we want the negative value
        dCalcVectorCross3(( info->J2a ) + s2, q, wanchor2 );


        // info->J2l[s1+i] = -ax1[i];
        dCopyNegatedVector3(( info->J2l ) + s1, ax1 );
        // info->J2l[s2+i] = -ax1[i];
        dCopyNegatedVector3(( info->J2l ) + s2, q );

    }


    // We want to make correction for motion not in the line of the axisP
    // We calculate the displacement w.r.t. the anchor pt.
    //
    // compute the elements 1 and 2 of right hand side.
    // We want to align the offset point (in body 2's frame) with the center of body 1.
    // The position should be the same when we are not along the prismatic axis
    dVector3 err;
    dMultiply0_331( err, R1, anchor1 );
    // err[i] = dist[i] - err[i];
    dSubtractVectors3( err, dist, err );
    info->c[1] = k * dCalcVectorDot3( ax1, err );
    info->c[2] = k * dCalcVectorDot3( q, err );

    int row = 3 + limot1.addLimot( this, info, 3, ax1, 1 );
    row += limot2.addLimot( this, info, row, ax2, 1 );

    if (  node[1].body || !(flags & dJOINT_REVERSE) )
        limotP.addLimot( this, info, row, axP, 0 );
    else
    {
        axP[0] = -axP[0];
        axP[1] = -axP[1];
        axP[2] = -axP[2];
        limotP.addLimot ( this, info, row, axP, 0 );
    }
}
// test one mesh triangle on intersection with capsule
void sTrimeshCapsuleColliderData::_cldTestOneTriangleVSCapsule(
    const dVector3 &v0, const dVector3 &v1, const dVector3 &v2,
    uint8 flags)
{
    // calculate edges
    SUBTRACT(v1,v0,m_vE0);
    SUBTRACT(v2,v1,m_vE1);
    SUBTRACT(v0,v2,m_vE2);

    dVector3	_minus_vE0;
    SUBTRACT(v0,v1,_minus_vE0);

    // calculate poly normal
    dCalcVectorCross3(m_vN,m_vE1,_minus_vE0);

    // Even though all triangles might be initially valid, 
    // a triangle may degenerate into a segment after applying 
    // space transformation.
    if (!dSafeNormalize3(m_vN))
    {
        return;
    }

    // create plane from triangle
    dReal plDistance = -dCalcVectorDot3(v0,m_vN);
    dVector4 plTrianglePlane;
    CONSTRUCTPLANE(plTrianglePlane,m_vN,plDistance);

    // calculate capsule distance to plane
    dReal fDistanceCapsuleCenterToPlane = POINTDISTANCE(plTrianglePlane,m_vCapsulePosition);

    // Capsule must be over positive side of triangle
    if (fDistanceCapsuleCenterToPlane < 0 /* && !bDoubleSided*/) 
    {
        // if not don't generate contacts
        return;
    }

    dVector3 vPnt0;
    SET	(vPnt0,v0);
    dVector3 vPnt1;
    SET	(vPnt1,v1);
    dVector3 vPnt2;
    SET	(vPnt2,v2);

    if (fDistanceCapsuleCenterToPlane < 0 )
    {
        SET	(vPnt0,v0);
        SET	(vPnt1,v2);
        SET	(vPnt2,v1);
    }

    // do intersection test and find best separating axis
    if (!_cldTestSeparatingAxesOfCapsule(vPnt0, vPnt1, vPnt2, flags))
    {
        // if not found do nothing
        return;
    }

    // if best separation axis is not found
    if (m_iBestAxis == 0 ) 
    {
        // this should not happen (we should already exit in that case)
        dIASSERT(FALSE);
        // do nothing
        return;
    }

    // calculate caps centers in absolute space
    dVector3 vCposTrans;
    vCposTrans[0] = m_vCapsulePosition[0] + m_vNormal[0]*m_vCapsuleRadius;
    vCposTrans[1] = m_vCapsulePosition[1] + m_vNormal[1]*m_vCapsuleRadius;
    vCposTrans[2] = m_vCapsulePosition[2] + m_vNormal[2]*m_vCapsuleRadius;

    dVector3 vCEdgePoint0;
    vCEdgePoint0[0]  = vCposTrans[0] + m_vCapsuleAxis[0]*(m_fCapsuleSize*REAL(0.5)-m_vCapsuleRadius);
    vCEdgePoint0[1]  = vCposTrans[1] + m_vCapsuleAxis[1]*(m_fCapsuleSize*REAL(0.5)-m_vCapsuleRadius);
    vCEdgePoint0[2]  = vCposTrans[2] + m_vCapsuleAxis[2]*(m_fCapsuleSize*REAL(0.5)-m_vCapsuleRadius);

    dVector3 vCEdgePoint1;
    vCEdgePoint1[0] = vCposTrans[0] - m_vCapsuleAxis[0]*(m_fCapsuleSize*REAL(0.5)-m_vCapsuleRadius);
    vCEdgePoint1[1] = vCposTrans[1] - m_vCapsuleAxis[1]*(m_fCapsuleSize*REAL(0.5)-m_vCapsuleRadius);
    vCEdgePoint1[2] = vCposTrans[2] - m_vCapsuleAxis[2]*(m_fCapsuleSize*REAL(0.5)-m_vCapsuleRadius);

    // transform capsule edge points into triangle space
    vCEdgePoint0[0] -= vPnt0[0];
    vCEdgePoint0[1] -= vPnt0[1];
    vCEdgePoint0[2] -= vPnt0[2];

    vCEdgePoint1[0] -= vPnt0[0];
    vCEdgePoint1[1] -= vPnt0[1];
    vCEdgePoint1[2] -= vPnt0[2];

    dVector4 plPlane;
    dVector3 _minus_vN;
    _minus_vN[0] = -m_vN[0];
    _minus_vN[1] = -m_vN[1];
    _minus_vN[2] = -m_vN[2];
    // triangle plane
    CONSTRUCTPLANE(plPlane,_minus_vN,0);
    //plPlane = Plane4f( -m_vN, 0);

    if (!_cldClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) 
    { 
        return; 
    }

    // plane with edge 0
    dVector3 vTemp;
    dCalcVectorCross3(vTemp,m_vN,m_vE0);
    CONSTRUCTPLANE(plPlane, vTemp, REAL(1e-5));
    if (!_cldClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane ))
    { 
        return; 
    }

    dCalcVectorCross3(vTemp,m_vN,m_vE1);
    CONSTRUCTPLANE(plPlane, vTemp, -(dCalcVectorDot3(m_vE0,vTemp)-REAL(1e-5)));
    if (!_cldClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) 
    { 
        return; 
    }

    dCalcVectorCross3(vTemp,m_vN,m_vE2);
    CONSTRUCTPLANE(plPlane, vTemp, REAL(1e-5));
    if (!_cldClipEdgeToPlane( vCEdgePoint0, vCEdgePoint1, plPlane )) { 
        return; 
    }

    // return capsule edge points into absolute space
    vCEdgePoint0[0] += vPnt0[0];
    vCEdgePoint0[1] += vPnt0[1];
    vCEdgePoint0[2] += vPnt0[2];

    vCEdgePoint1[0] += vPnt0[0];
    vCEdgePoint1[1] += vPnt0[1];
    vCEdgePoint1[2] += vPnt0[2];

    // calculate depths for both contact points
    SUBTRACT(vCEdgePoint0,m_vCapsulePosition,vTemp);
    dReal fDepth0 = dCalcVectorDot3(vTemp,m_vNormal) - (m_fBestCenter-m_fBestrt);
    SUBTRACT(vCEdgePoint1,m_vCapsulePosition,vTemp);
    dReal fDepth1 = dCalcVectorDot3(vTemp,m_vNormal) - (m_fBestCenter-m_fBestrt);

    // clamp depths to zero
    if (fDepth0 < 0) 
    {
        fDepth0 = 0.0f;
    }

    if (fDepth1 < 0 ) 
    {
        fDepth1 = 0.0f;
    }

    // Cached contacts's data
    // contact 0
    dIASSERT(m_ctContacts < (m_iFlags & NUMC_MASK)); // Do not call function if there is no room to store result
    m_gLocalContacts[m_ctContacts].fDepth = fDepth0;
    SET(m_gLocalContacts[m_ctContacts].vNormal,m_vNormal);
    SET(m_gLocalContacts[m_ctContacts].vPos,vCEdgePoint0);
    m_gLocalContacts[m_ctContacts].nFlags = 1;
    m_ctContacts++;

    if (m_ctContacts < (m_iFlags & NUMC_MASK)) {
        // contact 1
        m_gLocalContacts[m_ctContacts].fDepth = fDepth1;
        SET(m_gLocalContacts[m_ctContacts].vNormal,m_vNormal);
        SET(m_gLocalContacts[m_ctContacts].vPos,vCEdgePoint1);
        m_gLocalContacts[m_ctContacts].nFlags = 1;
        m_ctContacts++;
    }
}
Esempio n. 26
0
int dCollideRTL(dxGeom* g1, dxGeom* RayGeom, int Flags, dContactGeom* Contacts, int Stride){
    dIASSERT (Stride >= (int)sizeof(dContactGeom));
    dIASSERT (g1->type == dTriMeshClass);
    dIASSERT (RayGeom->type == dRayClass);
    dIASSERT ((Flags & NUMC_MASK) >= 1);

    dxTriMesh* TriMesh = (dxTriMesh*)g1;

    const dVector3& TLPosition = *(const dVector3*)dGeomGetPosition(TriMesh);
    const dMatrix3& TLRotation = *(const dMatrix3*)dGeomGetRotation(TriMesh);

    const unsigned uiTLSKind = TriMesh->getParentSpaceTLSKind();
    dIASSERT(uiTLSKind == RayGeom->getParentSpaceTLSKind()); // The colliding spaces must use matching cleanup method
    TrimeshCollidersCache *pccColliderCache = GetTrimeshCollidersCache(uiTLSKind);
    RayCollider& Collider = pccColliderCache->_RayCollider;

    dReal Length = dGeomRayGetLength(RayGeom);

    int FirstContact, BackfaceCull;
    dGeomRayGetParams(RayGeom, &FirstContact, &BackfaceCull);
    int ClosestHit = dGeomRayGetClosestHit(RayGeom);

    Collider.SetFirstContact(FirstContact != 0);
    Collider.SetClosestHit(ClosestHit != 0);
    Collider.SetCulling(BackfaceCull != 0);
    Collider.SetMaxDist(Length);

    dVector3 Origin, Direction;
    dGeomRayGet(RayGeom, Origin, Direction);

    /* Make Ray */
    Ray WorldRay;
    WorldRay.mOrig.x = Origin[0];
    WorldRay.mOrig.y = Origin[1];
    WorldRay.mOrig.z = Origin[2];
    WorldRay.mDir.x = Direction[0];
    WorldRay.mDir.y = Direction[1];
    WorldRay.mDir.z = Direction[2];

    /* Intersect */
    Matrix4x4 amatrix;
    int TriCount = 0;
    if (Collider.Collide(WorldRay, TriMesh->Data->BVTree, &MakeMatrix(TLPosition, TLRotation, amatrix))) {
        TriCount = pccColliderCache->Faces.GetNbFaces();
    }

    if (TriCount == 0) {
        return 0;
    }

    const CollisionFace* Faces = pccColliderCache->Faces.GetFaces();

    int OutTriCount = 0;
    for (int i = 0; i < TriCount; i++) {
        if (TriMesh->RayCallback == null ||
            TriMesh->RayCallback(TriMesh, RayGeom, Faces[i].mFaceID,
            Faces[i].mU, Faces[i].mV)) {
                const int& TriIndex = Faces[i].mFaceID;
                if (!Callback(TriMesh, RayGeom, TriIndex)) {
                    continue;
                }

                dContactGeom* Contact = SAFECONTACT(Flags, Contacts, OutTriCount, Stride);

                dVector3 dv[3];
                FetchTriangle(TriMesh, TriIndex, TLPosition, TLRotation, dv);

                dVector3 vu;
                vu[0] = dv[1][0] - dv[0][0];
                vu[1] = dv[1][1] - dv[0][1];
                vu[2] = dv[1][2] - dv[0][2];
                vu[3] = REAL(0.0);

                dVector3 vv;
                vv[0] = dv[2][0] - dv[0][0];
                vv[1] = dv[2][1] - dv[0][1];
                vv[2] = dv[2][2] - dv[0][2];
                vv[3] = REAL(0.0);

                dCalcVectorCross3(Contact->normal, vv, vu);	// Reversed

                // Even though all triangles might be initially valid, 
                // a triangle may degenerate into a segment after applying 
                // space transformation.
                if (dSafeNormalize3(Contact->normal))
                {
                    // No sense to save on single type conversion in algorithm of this size.
                    // If there would be a custom typedef for distance type it could be used 
                    // instead of dReal. However using float directly is the loss of abstraction 
                    // and possible loss of precision in future.
                    /*float*/ dReal T = Faces[i].mDistance;
                    Contact->pos[0] = Origin[0] + (Direction[0] * T);
                    Contact->pos[1] = Origin[1] + (Direction[1] * T);
                    Contact->pos[2] = Origin[2] + (Direction[2] * T);
                    Contact->pos[3] = REAL(0.0);

                    Contact->depth = T;
                    Contact->g1 = TriMesh;
                    Contact->g2 = RayGeom;
                    Contact->side1 = TriIndex;
                    Contact->side2 = -1;

                    OutTriCount++;

                    // Putting "break" at the end of loop prevents unnecessary checks on first pass and "continue"
                    if (OutTriCount >= (Flags & NUMC_MASK)) {
                        break;
                    }
                }
        }
    }
    return OutTriCount;
}
Esempio n. 27
0
void
dxJointScrew::getInfo2( dxJoint::Info2 *info )
{
    // Added by OSRF
    //
    // Screw Constraint Overview 
    //
    // make 5 constraint rows.
    // given screw axis, first create two orthogonal axis p and q.
    // row 1: linear constraint along p
    // row 2: linear constraint along q
    // row 3: screw constraint about user specified axis
    // row 4: rotational constraint about p
    // row 5: rotational constraint about q

    // Added by OSRF
    // If joint values of erp and cfm are negative, then ignore them.
    // info->erp, info->cfm already have the global values from quickstep
    if (this->erp >= 0)
      info->erp = erp;
    if (this->cfm >= 0)
    {
      info->cfm[0] = cfm;
      info->cfm[1] = cfm;
      info->cfm[2] = cfm;
      info->cfm[3] = cfm;
      info->cfm[4] = cfm;
    }

    // constraint rows 1 to 3
    {
      // pull out pos and R for both bodies. also get the `connection'
      // vector pos2-pos1.
      dReal *pos1, *pos2, *R1, *R2;
      dVector3 cgdiff;
      cgdiff[0] = cgdiff[1] = cgdiff[2] = 0;
      pos1 = node[0].body->posr.pos;
      R1 = node[0].body->posr.R;
      if ( node[1].body )
      {
          pos2 = node[1].body->posr.pos;
          R2 = node[1].body->posr.R;
          for (int i = 0; i < 3; ++i )
          {
              // store distance between cg's in cgdiff
              cgdiff[i] = pos2[i] - pos1[i];
          }
      }
      else
      {
          pos2 = 0;
          R2 = 0;
      }



      // compute error for screw due to drift
      dReal lin_disp; // linear displacement
      dReal lin_err; // linear displacement
      {
        // get linear disp for screw
        // get axis1 in global coordinates
        dVector3 ax1, q;
        dMultiply0_331 ( ax1, node[0].body->posr.R, axis1 );
        if ( node[1].body )
        {
            // get body2 + offset point in global coordinates
            dMultiply0_331 ( q, node[1].body->posr.R, offset );
            //printf("debug offset q[%f %f %f] p0[%f %f %f] p1[%f %f %f] \t",
            //  q[0],q[1],q[2],
            //  node[0].body->posr.pos[0], node[0].body->posr.pos[1],
            //  node[0].body->posr.pos[2],
            //  node[1].body->posr.pos[0], node[1].body->posr.pos[1],
            //  node[1].body->posr.pos[2]);
            for ( int ii = 0; ii < 3; ++ii )
              q[ii] = node[0].body->posr.pos[ii] - q[ii] -
                node[1].body->posr.pos[ii];
        }
        else
        {
            q[0] = node[0].body->posr.pos[0] - offset[0];
            q[1] = node[0].body->posr.pos[1] - offset[1];
            q[2] = node[0].body->posr.pos[2] - offset[2];
        }
        lin_disp = dCalcVectorDot3 ( ax1, q );

        // linear error should be length scaled, BUT
        if (dFabs(thread_pitch) > 1.0)
        {
          // constraint is written in length scale, so
          // linear error is length scaled.
          lin_err = -(lin_disp-cumulative_angle/thread_pitch);
        }
        else
        {
          // here the entire constraint equation, including lin_err
          // is multiplied by thread_pitch for |thread_pitch| less than 1.0
          // for added numerical stability,
          lin_err = -(thread_pitch*lin_disp-cumulative_angle);
        }
        // printf("lin disp: %f lin err: %f\n", lin_disp, lin_err);
      }



      int s0 = 0 * info->rowskip;
      int s1 = 1 * info->rowskip;
      int s2 = 2 * info->rowskip;

      // remaining two rows. we want: vel2 = vel1 + w1 x cgdiff ... but this would
      // result in three equations, so we project along the planespace vectors
      // so that sliding along the slider axis is disregarded. for symmetry we
      // also substitute (w1+w2)/2 for w1, as w1 is supposed to equal w2.

      // ax1 is axis1 converted to body1 frame
      dVector3 ax1;
      dMultiply0_331 ( ax1, R1, axis1 );

      // p and q are vectors perpendicular to ax1 in body1 frame
      dVector3 p, q;
      dPlaneSpace ( ax1, p, q );

      // linear constraints for the hinge joint
      // perpendicular to the sliding axis direction.
      for (int i = 0; i < 3; ++i ) info->J1l[s0+i] = p[i];
      for (int i = 0; i < 3; ++i ) info->J1l[s1+i] = q[i];

      // if p and q do not pass through body CG's,
      // we need to add angular constraints to balance out the forces
      // from these linear constraints.  See below:

      // a1 and a2 are axis vectors in the body frame
      // (whereas anchor1 and anchor2 are in world frame).
      // anchor1 is the vector from CG to joint anchor in world frame.
      dVector3 a1, a2;
      dMultiply0_331( a1, R1, anchor1 );

      // tmpp is a vector perpendicular to a1 and p in body frame,
      // it is the direction of the angular constraint that will
      // cancel out moment generated by linear constraint p
      // if p does not pass through CG.
      {
        dVector3 tmpp;
        dCalcVectorCross3(tmpp, p, a1);
        for (int i = 0; i < 3; ++i ) info->J1a[s0+i] = -tmpp[i];
      }

      // tmpq is similar to tmpp, but for q.
      {
        dVector3 tmpq;
        dCalcVectorCross3(tmpq, q, a1);
        for (int i = 0; i < 3; ++i ) info->J1a[s1+i] = -tmpq[i];
      }

      // screw constraint:
      // now constrain the sliding axis by rotation of the other body
      if (dFabs(thread_pitch) > 1.0)
      {
        for (int i = 0; i < 3; ++i ) info->J1l[s2+i] = ax1[i];
        for (int i = 0; i < 3; ++i ) info->J1a[s2+i] = -ax1[i]/thread_pitch;
      }
      else
      {
        // here the entire constraint equation, including lin_err
        // is multiplied by thread_pitch for |thread_pitch| less than 1.0
        // for added numerical stability,
        for (int i = 0; i < 3; ++i ) info->J1l[s2+i] = ax1[i]*thread_pitch;
        for (int i = 0; i < 3; ++i ) info->J1a[s2+i] = -ax1[i];
      }

      // repeat above for child body if one exists
      if ( node[1].body )
      {
        // linear constraints for s0 and s1
        for (int i = 0; i < 3; ++i ) info->J2l[s0+i] = -p[i];
        for (int i = 0; i < 3; ++i ) info->J2l[s1+i] = -q[i];

        // angular compensation if p and q do not pass through CG
        dMultiply0_331( a2, R2, anchor2 );
        dVector3 tmpp;
        dCalcVectorCross3(tmpp, p, a2);
        for (int i = 0; i < 3; ++i ) info->J2a[s0+i] = tmpp[i];
        dVector3 tmpq;
        dCalcVectorCross3(tmpq, q, a2);
        for (int i = 0; i < 3; ++i ) info->J2a[s1+i] = tmpq[i];

        // screw constraint:
        // constrain the sliding axis by rotation of the other body
        if (dFabs(thread_pitch) > 1.0)
        {
          for (int i = 0; i < 3; ++i ) info->J2a[s2+i] =  ax1[i]/thread_pitch;
          for (int i = 0; i < 3; ++i ) info->J2l[s2+i] = -ax1[i];
        }
        else
        {
          // here the entire constraint equation, including lin_err
          // is multiplied by thread_pitch for |thread_pitch| less than 1.0
          // for added numerical stability,
          for (int i = 0; i < 3; ++i ) info->J2a[s2+i] =  ax1[i];
          for (int i = 0; i < 3; ++i ) info->J2l[s2+i] = -ax1[i]*thread_pitch;
        }
      }

      // debug
      // printf ("anchor1 %f %f %f\n", anchor1[0], anchor1[1], anchor1[2]);
      // printf ("a1 %f %f %f\n", a1[0], a1[1], a1[2]);
      // printf ("ax1 %f %f %f\n", ax1[0], ax1[1], ax1[2]);
      // printf ("tmpp %f %f %f\n", tmpp[0], tmpp[1], tmpp[2]);
      // printf ("p %f %f %f\n", p[0], p[1], p[2]);
      // printf ("q %f %f %f\n", q[0], q[1], q[2]);
      // printf ("J1a[s0] %f %f %f\n", info->J1a[s0+0], info->J1a[s0+1],
      //   info->J1a[s0+2]);
      // printf ("J1a[s1] %f %f %f\n", info->J1a[s1+0], info->J1a[s1+1],
      //   info->J1a[s1+2]);
      // info->J1a[s0+0] = 1;
      // info->J1a[s0+1] = 0;
      // info->J1a[s0+2] = 0;
      // info->J1a[s1+0] = -1;
      // info->J1a[s1+1] = 0;
      // info->J1a[s1+2] = 0;
      // printf("screw err lin[%f], ang[%f], diff[%f] tp[%f]\n",
      //   thread_pitch*lin_disp, cumulative_angle, lin_err, thread_pitch);

      // compute last two elements of right hand side. we want to align the offset
      // point (in body 2's frame) with the center of body 1.
      dReal k = info->fps * info->erp;
      if ( node[1].body )
      {
          // dVector3 ofs;  // offset point in global coordinates
          // dMultiply0_331 ( ofs, R2, offset );
          // for (int i = 0; i < 3; ++i ) cgdiff[i] += ofs[i];

          // error between body anchors
          dVector3 error12;
          for (int i = 0; i < 3; ++i)
            error12[i] = a2[i] + node[1].body->posr.pos[i] - a1[i] -
              node[0].body->posr.pos[i];

          // error in the p direction is error12 dot p
          info->c[0] = k * (dCalcVectorDot3(error12, p));
          // error in the q direction is error12 dot p
          info->c[1] = k * (dCalcVectorDot3(error12, q));
          // interpenetration error for screw constraint
          info->c[2] = k * lin_err;
      }
      else
      {
          // debug
          // printf ("anchor1 %f %f %f\n", anchor1[0], anchor1[1], anchor1[2]);
          // printf ("anchor2 %f %f %f\n", anchor2[0], anchor2[1], anchor2[2]);
          // printf ("a1 %f %f %f\n", a1[0], a1[1], a1[2]);
          // printf ("p1 %f %f %f\n",
          //   node[0].body->posr.pos[0],
          //   node[0].body->posr.pos[1],
          //   node[0].body->posr.pos[2]);

          // error of body's anchor
          dVector3 error1;
          for (int i = 0; i < 3; ++i) error1[i] = anchor2[i] - a1[i] -
            node[0].body->posr.pos[i];
          // printf ("error1 %f %f %f\n", error1[0], error1[1], error1[2]);

          // error in the p direction is error1 dot p
          info->c[0] = k * (dCalcVectorDot3(error1, p));
          // error in the q direction
          info->c[1] = k * (dCalcVectorDot3(error1, q));
          // interpenetration error for screw constraint
          info->c[2] = k * lin_err;

          if ( flags & dJOINT_REVERSE )
              for (int i = 0; i < 3; ++i ) ax1[i] = -ax1[i];
      }

      // uncommnet to enforce slider joint limit
      // limot.addLimot ( this, info, 5, ax1, 0 );
    }

    // constraint rows 4 and 5
    {
      // set the two hinge rows. the screw axis should be the only unconstrained
      // rotational axis, the angular velocity of the two bodies perpendicular to
      // the hinge axis should be equal. thus the constraint equations are
      //    p*w1 - p*w2 = 0
      //    q*w1 - q*w2 = 0
      // where p and q are unit vectors normal to the hinge axis, and w1 and w2
      // are the angular velocity vectors of the two bodies.

      dVector3 ax1;  // length 1 joint axis in global coordinates, from 1st body
      dVector3 p, q; // plane space vectors for ax1
      dMultiply0_331( ax1, node[0].body->posr.R, axis1 );
      dPlaneSpace( ax1, p, q );

      int s3 = 3 * info->rowskip;
      int s4 = 4 * info->rowskip;

      info->J1a[s3+0] = p[0];
      info->J1a[s3+1] = p[1];
      info->J1a[s3+2] = p[2];
      info->J1a[s4+0] = q[0];
      info->J1a[s4+1] = q[1];
      info->J1a[s4+2] = q[2];

      if ( node[1].body )
      {
          info->J2a[s3+0] = -p[0];
          info->J2a[s3+1] = -p[1];
          info->J2a[s3+2] = -p[2];
          info->J2a[s4+0] = -q[0];
          info->J2a[s4+1] = -q[1];
          info->J2a[s4+2] = -q[2];
      }

      // compute the right hand side of the constraint equation. set relative
      // body velocities along p and q to bring the screw back into alignment.
      // if ax1,ax2 are the unit length screw axes as computed from body1 and
      // body2, we need to rotate both bodies along the axis u = (ax1 x ax2).
      // if `theta' is the angle between ax1 and ax2, we need an angular velocity
      // along u to cover angle erp*theta in one step :
      //   |angular_velocity| = angle/time = erp*theta / stepsize
      //                      = (erp*fps) * theta
      //    angular_velocity  = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2|
      //                      = (erp*fps) * theta * (ax1 x ax2) / sin(theta)
      // ...as ax1 and ax2 are unit length. if theta is smallish,
      // theta ~= sin(theta), so
      //    angular_velocity  = (erp*fps) * (ax1 x ax2)
      // ax1 x ax2 is in the plane space of ax1, so we project the angular
      // velocity to p and q to find the right hand side.

      dVector3 ax2, b;
      if ( node[1].body )
      {
          dMultiply0_331( ax2, node[1].body->posr.R, axis2 );
      }
      else
      {
          ax2[0] = axis2[0];
          ax2[1] = axis2[1];
          ax2[2] = axis2[2];
      }
      dCalcVectorCross3( b, ax1, ax2 );
      dReal k = info->fps * info->erp;
      info->c[3] = k * dCalcVectorDot3( b, p );
      info->c[4] = k * dCalcVectorDot3( b, q );

      // enforcing rotation joint limit
      limot.addLimot( this, info, 5, ax1, 1 );
    }
}
Esempio n. 28
0
dReal dJointGetPUPositionRate( dJointID j )
{
    dxJointPU* joint = ( dxJointPU* ) j;
    dUASSERT( joint, "bad joint argument" );
    checktype( joint, PU );

    if ( joint->node[0].body )
    {
        // We want to find the rate of change of the prismatic part of the joint
        // We can find it by looking at the speed difference between body1 and the
        // anchor point.

        // r will be used to find the distance between body1 and the anchor point
        dVector3 r;
        dVector3 anchor2 = {0,0,0};
        if ( joint->node[1].body )
        {
            // Find joint->anchor2 in global coordinates
            dMultiply0_331( anchor2, joint->node[1].body->posr.R, joint->anchor2 );

            r[0] = ( joint->node[0].body->posr.pos[0] -
                ( anchor2[0] + joint->node[1].body->posr.pos[0] ) );
            r[1] = ( joint->node[0].body->posr.pos[1] -
                ( anchor2[1] + joint->node[1].body->posr.pos[1] ) );
            r[2] = ( joint->node[0].body->posr.pos[2] -
                ( anchor2[2] + joint->node[1].body->posr.pos[2] ) );
        }
        else
        {
            //N.B. When there is no body 2 the joint->anchor2 is already in
            //     global coordinates
            // r = joint->node[0].body->posr.pos -  joint->anchor2;
            dSubtractVectors3( r, joint->node[0].body->posr.pos, joint->anchor2 );
        }

        // The body1 can have velocity coming from the rotation of
        // the rotoide axis. We need to remove this.

        // N.B. We do vel = r X w instead of vel = w x r to have vel negative
        //      since we want to remove it from the linear velocity of the body
        dVector3 lvel1;
        dCalcVectorCross3( lvel1, r, joint->node[0].body->avel );

        // lvel1 += joint->node[0].body->lvel;
        dAddVectors3( lvel1, lvel1, joint->node[0].body->lvel );

        // Since we want rate of change along the prismatic axis
        // get axisP1 in global coordinates and get the component
        // along this axis only
        dVector3 axP1;
        dMultiply0_331( axP1, joint->node[0].body->posr.R, joint->axisP1 );

        if ( joint->node[1].body )
        {
            // Find the contribution of the angular rotation to the linear speed
            // N.B. We do vel = r X w instead of vel = w x r to have vel negative
            //      since we want to remove it from the linear velocity of the body
            dVector3 lvel2;
            dCalcVectorCross3( lvel2, anchor2, joint->node[1].body->avel );

            // lvel1 -=  lvel2 + joint->node[1].body->lvel;
            dVector3 tmp;
            dAddVectors3( tmp, lvel2, joint->node[1].body->lvel );
            dSubtractVectors3( lvel1, lvel1, tmp );

            return dCalcVectorDot3( axP1, lvel1 );
        }
        else
        {
            dReal rate = dCalcVectorDot3( axP1, lvel1 );
            return ( (joint->flags & dJOINT_REVERSE) ? -rate : rate);
        }
    }

    return 0.0;
}
BOOL sTrimeshCapsuleColliderData::_cldTestSeparatingAxesOfCapsule(
    const dVector3 &v0,
    const dVector3 &v1,
    const dVector3 &v2,
    uint8 flags) 
{
    // calculate caps centers in absolute space
    dVector3 vCp0;
    vCp0[0] = m_vCapsulePosition[0] + m_vCapsuleAxis[0]*(m_fCapsuleSize*REAL(0.5)-m_vCapsuleRadius);
    vCp0[1] = m_vCapsulePosition[1] + m_vCapsuleAxis[1]*(m_fCapsuleSize*REAL(0.5)-m_vCapsuleRadius);
    vCp0[2] = m_vCapsulePosition[2] + m_vCapsuleAxis[2]*(m_fCapsuleSize*REAL(0.5)-m_vCapsuleRadius);

    dVector3 vCp1;
    vCp1[0] = m_vCapsulePosition[0] - m_vCapsuleAxis[0]*(m_fCapsuleSize*REAL(0.5)-m_vCapsuleRadius);
    vCp1[1] = m_vCapsulePosition[1] - m_vCapsuleAxis[1]*(m_fCapsuleSize*REAL(0.5)-m_vCapsuleRadius);
    vCp1[2] = m_vCapsulePosition[2] - m_vCapsuleAxis[2]*(m_fCapsuleSize*REAL(0.5)-m_vCapsuleRadius);

    // reset best axis
    m_iBestAxis = 0;
    // reset best depth
    m_fBestDepth  = -MAX_REAL;
    // reset separating axis vector
    dVector3 vAxis = {REAL(0.0),REAL(0.0),REAL(0.0),REAL(0.0)};

    // Epsilon value for checking axis vector length 
    const dReal fEpsilon = 1e-6f;

    // Translate triangle to Cc cord.
    SUBTRACT(v0, m_vCapsulePosition, m_vV0);
    SUBTRACT(v1, m_vCapsulePosition, m_vV1);
    SUBTRACT(v2, m_vCapsulePosition, m_vV2);

    // We begin to test for 19 separating axis now
    // I wonder does it help if we employ the method like ISA-GJK???
    // Or at least we should do experiment and find what axis will
    // be most likely to be separating axis to check it first.

    // Original
    // axis m_vN
    //vAxis = -m_vN;
    vAxis[0] = - m_vN[0];
    vAxis[1] = - m_vN[1];
    vAxis[2] = - m_vN[2];
    if (!_cldTestAxis(v0, v1, v2, vAxis, 1, TRUE)) 
    { 
        return FALSE; 
    }

    if (flags & dxTriMeshData::kEdge0)
    {
        // axis CxE0 - Edge 0
        dCalcVectorCross3(vAxis,m_vCapsuleAxis,m_vE0);
        //vAxis = dCalcVectorCross3( m_vCapsuleAxis cross vE0 );
        if (_length2OfVector3( vAxis ) > fEpsilon) {
            if (!_cldTestAxis(v0, v1, v2, vAxis, 2)) { 
                return FALSE;
            }
        }
    }

    if (flags & dxTriMeshData::kEdge1)
    {
        // axis CxE1 - Edge 1
        dCalcVectorCross3(vAxis,m_vCapsuleAxis,m_vE1);
        //vAxis = ( m_vCapsuleAxis cross m_vE1 );
        if (_length2OfVector3( vAxis ) > fEpsilon) {
            if (!_cldTestAxis(v0, v1, v2, vAxis, 3)) {
                return FALSE;
            }
        }
    }

    if (flags & dxTriMeshData::kEdge2)
    {
        // axis CxE2 - Edge 2
        //vAxis = ( m_vCapsuleAxis cross m_vE2 );
        dCalcVectorCross3(vAxis,m_vCapsuleAxis,m_vE2);
        if (_length2OfVector3( vAxis ) > fEpsilon) {
            if (!_cldTestAxis(v0, v1, v2, vAxis, 4)) {
                return FALSE;
            }
        }
    }

    if (flags & dxTriMeshData::kEdge0)
    {
        // first capsule point
        // axis ((Cp0-V0) x E0) x E0
        _CalculateAxis(vCp0,v0,m_vE0,m_vE0,vAxis);
        //	vAxis = ( ( vCp0-v0) cross vE0 ) cross vE0;
        if (_length2OfVector3( vAxis ) > fEpsilon) {
            if (!_cldTestAxis(v0, v1, v2, vAxis, 5)) {
                return FALSE;
            }
        }
    }

    if (flags & dxTriMeshData::kEdge1)
    {
        // axis ((Cp0-V1) x E1) x E1
        _CalculateAxis(vCp0,v1,m_vE1,m_vE1,vAxis);
        //vAxis = ( ( vCp0-v1) cross vE1 ) cross vE1;
        if (_length2OfVector3( vAxis ) > fEpsilon) {
            if (!_cldTestAxis(v0, v1, v2, vAxis, 6)) {
                return FALSE;
            }
        }
    }

    if (flags & dxTriMeshData::kEdge2)
    {
        // axis ((Cp0-V2) x E2) x E2
        _CalculateAxis(vCp0,v2,m_vE2,m_vE2,vAxis);
        //vAxis = ( ( vCp0-v2) cross vE2 ) cross vE2;
        if (_length2OfVector3( vAxis ) > fEpsilon) {
            if (!_cldTestAxis(v0, v1, v2, vAxis, 7)) {
                return FALSE;
            }
        }
    }

    if (flags & dxTriMeshData::kEdge0)
    {
        // second capsule point
        // axis ((Cp1-V0) x E0) x E0
        _CalculateAxis(vCp1,v0,m_vE0,m_vE0,vAxis);
        //vAxis = ( ( vCp1-v0 ) cross vE0 ) cross vE0;
        if (_length2OfVector3( vAxis ) > fEpsilon) {
            if (!_cldTestAxis(v0, v1, v2, vAxis, 8)) {
                return FALSE;
            }
        }
    }

    if (flags & dxTriMeshData::kEdge1)
    {
        // axis ((Cp1-V1) x E1) x E1
        _CalculateAxis(vCp1,v1,m_vE1,m_vE1,vAxis);
        //vAxis = ( ( vCp1-v1 ) cross vE1 ) cross vE1;
        if (_length2OfVector3( vAxis ) > fEpsilon) {
            if (!_cldTestAxis(v0, v1, v2, vAxis, 9)) {
                return FALSE;
            }
        }
    }

    if (flags & dxTriMeshData::kEdge2)
    {
        // axis ((Cp1-V2) x E2) x E2
        _CalculateAxis(vCp1,v2,m_vE2,m_vE2,vAxis);
        //vAxis = ( ( vCp1-v2 ) cross vE2 ) cross vE2;
        if (_length2OfVector3( vAxis ) > fEpsilon) {
            if (!_cldTestAxis(v0, v1, v2, vAxis, 10)) {
                return FALSE;
            }
        }
    }

    if (flags & dxTriMeshData::kVert0)
    {
        // first vertex on triangle
        // axis ((V0-Cp0) x C) x C
        _CalculateAxis(v0,vCp0,m_vCapsuleAxis,m_vCapsuleAxis,vAxis);
        //vAxis = ( ( v0-vCp0 ) cross m_vCapsuleAxis ) cross m_vCapsuleAxis;
        if (_length2OfVector3( vAxis ) > fEpsilon) {
            if (!_cldTestAxis(v0, v1, v2, vAxis, 11)) {
                return FALSE;
            }
        }
    }

    if (flags & dxTriMeshData::kVert1)
    {
        // second vertex on triangle
        // axis ((V1-Cp0) x C) x C
        _CalculateAxis(v1,vCp0,m_vCapsuleAxis,m_vCapsuleAxis,vAxis);	
        //vAxis = ( ( v1-vCp0 ) cross vCapsuleAxis ) cross vCapsuleAxis;
        if (_length2OfVector3( vAxis ) > fEpsilon) {
            if (!_cldTestAxis(v0, v1, v2, vAxis, 12)) {
                return FALSE;
            }
        }
    }

    if (flags & dxTriMeshData::kVert2)
    {
        // third vertex on triangle
        // axis ((V2-Cp0) x C) x C
        _CalculateAxis(v2,vCp0,m_vCapsuleAxis,m_vCapsuleAxis,vAxis);
        //vAxis = ( ( v2-vCp0 ) cross vCapsuleAxis ) cross vCapsuleAxis;
        if (_length2OfVector3( vAxis ) > fEpsilon) {
            if (!_cldTestAxis(v0, v1, v2, vAxis, 13)) {
                return FALSE;
            }
        }
    }

    // Test as separating axes direction vectors between each triangle
    // edge and each capsule's cap center

    if (flags & dxTriMeshData::kVert0)
    {
        // first triangle vertex and first capsule point
        //vAxis = v0 - vCp0;
        SUBTRACT(v0,vCp0,vAxis);
        if (_length2OfVector3( vAxis ) > fEpsilon) {
            if (!_cldTestAxis(v0, v1, v2, vAxis, 14)) {
                return FALSE;
            }
        }
    }

    if (flags & dxTriMeshData::kVert1)
    {
        // second triangle vertex and first capsule point
        //vAxis = v1 - vCp0;
        SUBTRACT(v1,vCp0,vAxis);
        if (_length2OfVector3( vAxis ) > fEpsilon) {
            if (!_cldTestAxis(v0, v1, v2, vAxis, 15)) {
                return FALSE;
            }
        }
    }

    if (flags & dxTriMeshData::kVert2)
    {
        // third triangle vertex and first capsule point
        //vAxis = v2 - vCp0;
        SUBTRACT(v2,vCp0,vAxis);
        if (_length2OfVector3( vAxis ) > fEpsilon) {
            if (!_cldTestAxis(v0, v1, v2, vAxis, 16)) {
                return FALSE;
            }
        }
    }

    if (flags & dxTriMeshData::kVert0)
    {
        // first triangle vertex and second capsule point
        //vAxis = v0 - vCp1;
        SUBTRACT(v0,vCp1,vAxis);
        if (_length2OfVector3( vAxis ) > fEpsilon) {
            if (!_cldTestAxis(v0, v1, v2, vAxis, 17)) {
                return FALSE;
            }
        }
    }

    if (flags & dxTriMeshData::kVert1)
    {
        // second triangle vertex and second capsule point
        //vAxis = v1 - vCp1;
        SUBTRACT(v1,vCp1,vAxis);
        if (_length2OfVector3( vAxis ) > fEpsilon) {
            if (!_cldTestAxis(v0, v1, v2, vAxis, 18)) {
                return FALSE;
            }
        }
    }

    if (flags & dxTriMeshData::kVert2)
    {
        // third triangle vertex and second capsule point
        //vAxis = v2 - vCp1;
        SUBTRACT(v2,vCp1,vAxis);
        if (_length2OfVector3( vAxis ) > fEpsilon) {
            if (!_cldTestAxis(v0, v1, v2, vAxis, 19)) {
                return FALSE;
            }
        }
    }

    return TRUE;
}
Esempio n. 30
0
int dxJointLimitMotor::addLimot( dxJoint *joint,
                                 dxJoint::Info2 *info, int row,
                                 const dVector3 ax1, int rotational )
{
    int srow = row * info->rowskip;

    // if the joint is powered, or has joint limits, add in the extra row
    int powered = fmax > 0;
    if ( powered || limit )
    {
        dReal *J1 = rotational ? info->J1a : info->J1l;
        dReal *J2 = rotational ? info->J2a : info->J2l;

        J1[srow+0] = ax1[0];
        J1[srow+1] = ax1[1];
        J1[srow+2] = ax1[2];
        if ( joint->node[1].body )
        {
            J2[srow+0] = -ax1[0];
            J2[srow+1] = -ax1[1];
            J2[srow+2] = -ax1[2];
        }

        // linear limot torque decoupling step:
        //
        // if this is a linear limot (e.g. from a slider), we have to be careful
        // that the linear constraint forces (+/- ax1) applied to the two bodies
        // do not create a torque couple. in other words, the points that the
        // constraint force is applied at must lie along the same ax1 axis.
        // a torque couple will result in powered or limited slider-jointed free
        // bodies from gaining angular momentum.
        // the solution used here is to apply the constraint forces at the point
        // halfway between the body centers. there is no penalty (other than an
        // extra tiny bit of computation) in doing this adjustment. note that we
        // only need to do this if the constraint connects two bodies.

        dVector3 ltd = {0,0,0}; // Linear Torque Decoupling vector (a torque)
        if ( !rotational && joint->node[1].body )
        {
            dVector3 c;
            c[0] = REAL( 0.5 ) * ( joint->node[1].body->posr.pos[0] - joint->node[0].body->posr.pos[0] );
            c[1] = REAL( 0.5 ) * ( joint->node[1].body->posr.pos[1] - joint->node[0].body->posr.pos[1] );
            c[2] = REAL( 0.5 ) * ( joint->node[1].body->posr.pos[2] - joint->node[0].body->posr.pos[2] );
            dCalcVectorCross3( ltd, c, ax1 );
            info->J1a[srow+0] = ltd[0];
            info->J1a[srow+1] = ltd[1];
            info->J1a[srow+2] = ltd[2];
            info->J2a[srow+0] = ltd[0];
            info->J2a[srow+1] = ltd[1];
            info->J2a[srow+2] = ltd[2];
        }

        // if we're limited low and high simultaneously, the joint motor is
        // ineffective
        if ( limit && ( lostop == histop ) ) powered = 0;

        if ( powered )
        {
            info->cfm[row] = normal_cfm;
            if ( ! limit )
            {
                info->c[row] = vel;
                info->lo[row] = -fmax;
                info->hi[row] = fmax;
            }
            else
            {
                // the joint is at a limit, AND is being powered. if the joint is
                // being powered into the limit then we apply the maximum motor force
                // in that direction, because the motor is working against the
                // immovable limit. if the joint is being powered away from the limit
                // then we have problems because actually we need *two* lcp
                // constraints to handle this case. so we fake it and apply some
                // fraction of the maximum force. the fraction to use can be set as
                // a fudge factor.

                dReal fm = fmax;
                if (( vel > 0 ) || ( vel == 0 && limit == 2 ) ) fm = -fm;

                // if we're powering away from the limit, apply the fudge factor
                if (( limit == 1 && vel > 0 ) || ( limit == 2 && vel < 0 ) ) fm *= fudge_factor;

                if ( rotational )
                {
                    dBodyAddTorque( joint->node[0].body, -fm*ax1[0], -fm*ax1[1],
                                    -fm*ax1[2] );
                    if ( joint->node[1].body )
                        dBodyAddTorque( joint->node[1].body, fm*ax1[0], fm*ax1[1], fm*ax1[2] );
                }
                else
                {
                    dBodyAddForce( joint->node[0].body, -fm*ax1[0], -fm*ax1[1], -fm*ax1[2] );
                    if ( joint->node[1].body )
                    {
                        dBodyAddForce( joint->node[1].body, fm*ax1[0], fm*ax1[1], fm*ax1[2] );

                        // linear limot torque decoupling step: refer to above discussion
                        dBodyAddTorque( joint->node[0].body, -fm*ltd[0], -fm*ltd[1],
                                        -fm*ltd[2] );
                        dBodyAddTorque( joint->node[1].body, -fm*ltd[0], -fm*ltd[1],
                                        -fm*ltd[2] );
                    }
                }
            }
        }

        if ( limit )
        {
            dReal k = info->fps * stop_erp;
            info->c[row] = -k * limit_err;
            info->cfm[row] = stop_cfm;

            if ( lostop == histop )
            {
                // limited low and high simultaneously
                info->lo[row] = -dInfinity;
                info->hi[row] = dInfinity;
            }
            else
            {
                if ( limit == 1 )
                {
                    // low limit
                    info->lo[row] = 0;
                    info->hi[row] = dInfinity;
                }
                else
                {
                    // high limit
                    info->lo[row] = -dInfinity;
                    info->hi[row] = 0;
                }

                // deal with bounce
                if ( bounce > 0 )
                {
                    // calculate joint velocity
                    dReal vel;
                    if ( rotational )
                    {
                        vel = dCalcVectorDot3( joint->node[0].body->avel, ax1 );
                        if ( joint->node[1].body )
                            vel -= dCalcVectorDot3( joint->node[1].body->avel, ax1 );
                    }
                    else
                    {
                        vel = dCalcVectorDot3( joint->node[0].body->lvel, ax1 );
                        if ( joint->node[1].body )
                            vel -= dCalcVectorDot3( joint->node[1].body->lvel, ax1 );
                    }

                    // only apply bounce if the velocity is incoming, and if the
                    // resulting c[] exceeds what we already have.
                    if ( limit == 1 )
                    {
                        // low limit
                        if ( vel < 0 )
                        {
                            dReal newc = -bounce * vel;
                            if ( newc > info->c[row] ) info->c[row] = newc;
                        }
                    }
                    else
                    {
                        // high limit - all those computations are reversed
                        if ( vel > 0 )
                        {
                            dReal newc = -bounce * vel;
                            if ( newc < info->c[row] ) info->c[row] = newc;
                        }
                    }
                }
            }
        }
        return 1;
    }
    else return 0;
}