Plane2d.patch

From ODE Wiki

Jump to: navigation, search

Below is a patch to ODE 0.6 to add the dJointPlane2D functionality described in HOWTO constrain objects to 2d. To apply, save the text below to a file called "plane2d.patch", and move the patch file to the directory just below the ODE-0.6 directory. From there, run the following command:

patch -Np0 <plane2d.patch

Then make and re-install ODE as before. Note that this places the test code in a strange place: drawstuff/test.pserocka/.

plane2d.patch:

diff -Naur ode-0.6.old/drawstuff/test.pserocka/GNUmakefile ode-0.6/drawstuff/test.pserocka/GNUmakefile
--- ode-0.6.old/drawstuff/test.pserocka/GNUmakefile	1969-12-31 19:00:00.000000000 -0500
+++ ode-0.6/drawstuff/test.pserocka/GNUmakefile	2006-07-31 19:24:01.859329000 -0400
@@ -0,0 +1,21 @@
+CXX         :=  g++
+CXXFLAGS    :=  -O
+
+CPPFLAGS    :=
+LDFLAGS     :=
+LDLIBS      :=
+
+CPPFLAGS    +=  -I ../include
+LDFLAGS     +=  -L ../lib -L ../drawstuff/src
+LDLIBS      +=  -lode -ldrawstuff
+
+CPPFLAGS    +=  -I /usr/X11R6/include
+LDFLAGS     +=  -L /usr/X11R6/lib
+LDLIBS      +=  -lGLU -lGL -lX11
+LDLIBS      +=  -lm
+
+all:    test_plane2d
+
+test_plane2d:   test_plane2d.o
+	$(CXX) -o $@ $< $(CXXFLAGS) $(LDFLAGS) $(LDLIBS)
+
diff -Naur ode-0.6.old/drawstuff/test.pserocka/test_plane2d.cc ode-0.6/drawstuff/test.pserocka/test_plane2d.cc
--- ode-0.6.old/drawstuff/test.pserocka/test_plane2d.cc	1969-12-31 19:00:00.000000000 -0500
+++ ode-0.6/drawstuff/test.pserocka/test_plane2d.cc	2006-07-31 13:53:29.211866000 -0400
@@ -0,0 +1,273 @@
+// Test my Plane2D constraint.
+// Uses ode-0.35 collision API.
+
+# include       <stdio.h>
+# include       <stdlib.h>
+# include       <math.h>
+# include       <ode/ode.h>
+# include       <drawstuff/drawstuff.h>
+
+
+# define        N_BODIES        40
+# define        STAGE_SIZE      8.0  // in m
+
+# define        TIME_STEP       0.01
+# define        K_SPRING        10.0
+# define        K_DAMP          10.0
+
+// select correct drawing functions
+
+#ifdef dDOUBLE
+#define dsDrawBox dsDrawBoxD
+#define dsDrawSphere dsDrawSphereD
+#define dsDrawCylinder dsDrawCylinderD
+#define dsDrawCapsule dsDrawCapsuleD
+#endif
+
+static dWorld   dyn_world;
+static dBody    dyn_bodies[N_BODIES];
+static dReal    bodies_sides[N_BODIES][3];
+
+static dSpaceID coll_space_id;
+static dJointID plane2d_joint_ids[N_BODIES];
+static dJointGroup
+                coll_contacts;
+
+
+
+static void     cb_start ()
+/*************************/
+{
+    static float    xyz[3] = { 0.5*STAGE_SIZE, 0.5*STAGE_SIZE, 0.65*STAGE_SIZE};
+    static float    hpr[3] = { 90, -90, 0 };
+
+    dsSetViewpoint (xyz, hpr);
+}
+
+
+
+static void     cb_near_collision (void *data, dGeomID o1, dGeomID o2)
+/********************************************************************/
+{
+    dBodyID     b1 = dGeomGetBody (o1);
+    dBodyID     b2 = dGeomGetBody (o2);
+    dContact    contact;
+
+
+    // exit without doing anything if the two bodies are static
+    if (b1 == 0 && b2 == 0)
+        return;
+
+    // exit without doing anything if the two bodies are connected by a joint
+    if (b1 && b2 && dAreConnected (b1, b2))
+    {
+        /* MTRAP; */
+        return;
+    }
+
+    contact.surface.mode = 0;
+    contact.surface.mu = 0; // frictionless
+
+    if (dCollide (o1, o2, 0, &contact.geom, sizeof (dContactGeom)))
+    {
+        dJointID c = dJointCreateContact (dyn_world.id(),
+                        coll_contacts.id (), &contact);
+        dJointAttach (c, b1, b2);
+    }
+}
+
+    
+static void     track_to_pos (dBody &body, dJointID joint_id,
+                              dReal target_x, dReal target_y)
+/************************************************************************/
+{
+    double  curr_x = body.getPosition()[0];
+    double  curr_y = body.getPosition()[1];
+
+    dJointSetPlane2DXParam (joint_id, dParamVel, 1 * (target_x - curr_x));
+    dJointSetPlane2DYParam (joint_id, dParamVel, 1 * (target_y - curr_y));
+}
+
+
+
+static void     cb_sim_step (int pause)
+/*************************************/
+{
+    if (! pause)
+    {
+        static double
+                angle = 0;
+
+        angle += 0.01;
+
+        track_to_pos (dyn_bodies[0], plane2d_joint_ids[0],
+            STAGE_SIZE/2 + STAGE_SIZE/2.0 * cos (angle),
+            STAGE_SIZE/2 + STAGE_SIZE/2.0 * sin (angle));
+        
+        /* double   f0 = 0.001; */
+        /* for (int b = 0; b < N_BODIES; b ++) */
+        /* { */
+            /* double   p = 1 + b / (double) N_BODIES; */
+            /* double   q = 2 - b / (double) N_BODIES; */
+            /* dyn_bodies[b].addForce (f0 * cos (p*angle), f0 * sin (q*angle), 0); */
+        /* } */
+        /* dyn_bodies[0].addTorque (0, 0, 0.1); */
+
+        const int n = 10;
+        for (int i = 0; i < n; i ++)
+        {
+            dSpaceCollide (coll_space_id, 0, &cb_near_collision);
+            dyn_world.step (TIME_STEP/n);
+            coll_contacts.empty ();
+        }
+    }
+
+# if 1  /* [ */
+    {
+        // @@@ hack Plane2D constraint error reduction here:
+        for (int b = 0; b < N_BODIES; b ++)
+        {
+            const dReal     *rot = dBodyGetAngularVel (dyn_bodies[b].id());
+            const dReal     *quat_ptr;
+            dReal           quat[4],
+                            quat_len;
+
+
+            quat_ptr = dBodyGetQuaternion (dyn_bodies[b].id());
+            quat[0] = quat_ptr[0];
+            quat[1] = 0;
+            quat[2] = 0; 
+            quat[3] = quat_ptr[3]; 
+            quat_len = sqrt (quat[0] * quat[0] + quat[3] * quat[3]);
+            quat[0] /= quat_len;
+            quat[3] /= quat_len;
+            dBodySetQuaternion (dyn_bodies[b].id(), quat);
+            dBodySetAngularVel (dyn_bodies[b].id(), 0, 0, rot[2]);
+        }
+    }
+# endif  /* ] */
+
+
+# if 0  /* [ */
+    {
+        // @@@ friction
+        for (int b = 0; b < N_BODIES; b ++)
+        {
+            const dReal *vel = dBodyGetLinearVel (dyn_bodies[b].id()),
+                        *rot = dBodyGetAngularVel (dyn_bodies[b].id());
+            dReal       s = 1.00;
+            dReal       t = 0.99;
+
+            dBodySetLinearVel (dyn_bodies[b].id(), s*vel[0],s*vel[1],s*vel[2]);
+            dBodySetAngularVel (dyn_bodies[b].id(),t*rot[0],t*rot[1],t*rot[2]);
+        }
+    }
+# endif  /* ] */
+    
+
+    {
+        // ode  drawstuff
+
+        dsSetTexture (DS_WOOD);
+        for (int b = 0; b < N_BODIES; b ++)
+        {
+            if (b == 0)
+            dsSetColor (1.0, 0.5, 1.0);
+            else
+            dsSetColor (0, 0.5, 1.0);
+            /* if (b == 0) */
+                /* dsDrawSphere (dyn_bodies[b].getPosition(), */
+                        /* dyn_bodies[b].getRotation(), bodies_sides[b][0]); */
+            /* else */
+                dsDrawBox (dyn_bodies[b].getPosition(),
+                        dyn_bodies[b].getRotation(), bodies_sides[b]);
+        }
+    }
+}
+
+
+
+extern int      main
+/******************/
+(
+    int         argc,
+    char        **argv
+)
+{
+    int         b;
+    dsFunctions drawstuff_functions;
+
+
+    // dynamic world
+
+    double  cf_mixing = 1 / (TIME_STEP * K_SPRING + K_DAMP);
+    double  err_reduct = TIME_STEP * K_SPRING * cf_mixing;
+    err_reduct = 0.5;
+    cf_mixing = 0.001;
+    dWorldSetERP (dyn_world.id (), err_reduct);
+    dWorldSetCFM (dyn_world.id (), cf_mixing);
+    dyn_world.setGravity (0, 0.0, -1.0);
+
+    coll_space_id = dSimpleSpaceCreate (0);
+
+    // dynamic bodies
+    for (b = 0; b < N_BODIES; b ++)
+    {
+        int     l = (int) (1 + sqrt ((double) N_BODIES));
+        double  x = (0.5 + (b / l)) / l * STAGE_SIZE;
+        double  y = (0.5 + (b % l)) / l * STAGE_SIZE;
+        double  z = 1.0 + 0.1 * drand48 ();
+
+        bodies_sides[b][0] = 5 * (0.2 + 0.7*drand48()) / sqrt((double)N_BODIES);
+        bodies_sides[b][1] = 5 * (0.2 + 0.7*drand48()) / sqrt((double)N_BODIES);
+        bodies_sides[b][2] = z;
+
+        dyn_bodies[b].create (dyn_world);
+        dyn_bodies[b].setPosition (x, y, z/2);
+        dyn_bodies[b].setData ((void*) b);
+        dBodySetLinearVel (dyn_bodies[b].id (),
+            3 * (drand48 () - 0.5), 3 * (drand48 () - 0.5), 0);
+
+        dMass m;
+        m.setBox (1, bodies_sides[b][0],bodies_sides[b][1],bodies_sides[b][2]);
+        m.adjust (0.1 * bodies_sides[b][0] * bodies_sides[b][1]);
+        dyn_bodies[b].setMass (&m);
+
+        plane2d_joint_ids[b] = dJointCreatePlane2D (dyn_world.id (), 0);
+        dJointAttach (plane2d_joint_ids[b], dyn_bodies[b].id (), 0);
+    }
+
+    dJointSetPlane2DXParam (plane2d_joint_ids[0], dParamFMax, 10);
+    dJointSetPlane2DYParam (plane2d_joint_ids[0], dParamFMax, 10);
+
+
+    // collision geoms and joints
+    dCreatePlane (coll_space_id,  1, 0, 0, 0);
+    dCreatePlane (coll_space_id, -1, 0, 0, -STAGE_SIZE);
+    dCreatePlane (coll_space_id,  0,  1, 0, 0);
+    dCreatePlane (coll_space_id,  0, -1, 0, -STAGE_SIZE);
+
+    for (b = 0; b < N_BODIES; b ++)
+    {
+        dGeomID coll_box_id;
+        coll_box_id = dCreateBox (coll_space_id,
+            bodies_sides[b][0], bodies_sides[b][1], bodies_sides[b][2]);
+        dGeomSetBody (coll_box_id, dyn_bodies[b].id ());
+    }
+
+    coll_contacts.create (0);
+
+    {
+        // simulation loop (by drawstuff lib) 
+        drawstuff_functions.version = DS_VERSION;
+        drawstuff_functions.start = &cb_start;
+        drawstuff_functions.step = &cb_sim_step;
+        drawstuff_functions.command = 0;
+        drawstuff_functions.stop = 0;
+        drawstuff_functions.path_to_textures = getenv ("ODE_DRAWSTUFF_TEXPATH");
+
+        dsSimulationLoop (argc, argv, 800, 800, &drawstuff_functions);
+    }
+
+    return 0;
+}
diff -Naur ode-0.6.old/include/ode/common.h ode-0.6/include/ode/common.h
--- ode-0.6.old/include/ode/common.h	2006-05-31 15:08:15.000000000 -0400
+++ ode-0.6/include/ode/common.h	2006-07-31 19:44:15.307164750 -0400
@@ -254,7 +254,8 @@
   dJointTypeFixed,
   dJointTypeNull,
   dJointTypeAMotor,
-  dJointTypeLMotor
+  dJointTypeLMotor, 
+  dJointTypePlane2D
 };
 
 
diff -Naur ode-0.6.old/include/ode/objects.h ode-0.6/include/ode/objects.h
--- ode-0.6.old/include/ode/objects.h	2006-05-08 14:52:52.000000000 -0400
+++ ode-0.6/include/ode/objects.h	2006-08-01 14:45:37.135979000 -0400
@@ -1093,15 +1093,16 @@
  * @brief Get the type of the joint
  * @ingroup joints
  * @return the type, being one of these:
- * \li JointTypeBall
- * \li JointTypeHinge
- * \li JointTypeSlider
- * \li JointTypeContact
- * \li JointTypeUniversal
- * \li JointTypeHinge2
- * \li JointTypeFixed
- * \li JointTypeAMotor
- * \li JointTypeLMotor
+ * \li dJointTypeBall
+ * \li dJointTypeHinge
+ * \li dJointTypeSlider
+ * \li dJointTypeContact
+ * \li dJointTypeUniversal
+ * \li dJointTypeHinge2
+ * \li dJointTypeFixed
+ * \li dJointTypeAMotor
+ * \li dJointTypeLMotor
+ * \li dJointTypePlane2D
  */
 ODE_API int dJointGetType (dJointID);
 
@@ -1694,6 +1695,32 @@
  */
 ODE_API int dAreConnectedExcluding (dBodyID, dBodyID, int joint_type);
 
+/**
+ * @brief Create a new planar constraint joint.
+ * @ingroup joints
+ * @param dJointGroupID set to 0 to allocate the joint normally.
+ * If it is nonzero the joint is allocated in the given joint group.
+ */
+ODE_API dJointID dJointCreatePlane2D (dWorldID, dJointGroupID);
+
+/**
+ * @brief Set a motor parameter for the X-axis motor.
+ * @ingroup joints
+ */
+ODE_API void dJointSetPlane2DXParam (dJointID, int parameter, dReal value);
+
+/**
+ * @brief Set a motor parameter for the Y-axis motor.
+ * @ingroup joints
+ */
+ODE_API void dJointSetPlane2DYParam (dJointID, int parameter, dReal value);
+
+/**
+ * @brief Set a motor parameter for the rotational motor.
+ * @ingroup joints
+ */
+ODE_API void dJointSetPlane2DAngleParam (dJointID, int parameter, dReal value);
+
 
 #ifdef __cplusplus
 }
diff -Naur ode-0.6.old/ode/src/joint.cpp ode-0.6/ode/src/joint.cpp
--- ode-0.6.old/ode/src/joint.cpp	2006-03-24 14:36:06.000000000 -0500
+++ ode-0.6/ode/src/joint.cpp	2006-08-01 14:50:38.942840750 -0400
@@ -2996,3 +2996,154 @@
   (dxJoint::getInfo1_fn*) nullGetInfo1,
   (dxJoint::getInfo2_fn*) nullGetInfo2,
   dJointTypeNull};
+
+
+# define        VoXYZ(v1, o1, x, y, z) \
+                    ( \
+                        (v1)[0] o1 (x), \
+                        (v1)[1] o1 (y), \
+                        (v1)[2] o1 (z)  \
+                    )
+
+static dReal   Midentity[3][3] =
+                {
+                    {   1,  0,  0   },
+                    {   0,  1,  0   },
+                    {   0,  0,  1,  }
+                };
+
+
+
+static void     plane2dInit (dxJointPlane2D *j)
+/*********************************************/
+{
+    /* MINFO ("plane2dInit ()"); */
+    j->motor_x.init (j->world);
+    j->motor_y.init (j->world);
+    j->motor_angle.init (j->world);
+}
+
+
+
+static void     plane2dGetInfo1 (dxJointPlane2D *j, dxJoint::Info1 *info)
+/***********************************************************************/
+{
+  /* MINFO ("plane2dGetInfo1 ()"); */
+
+  info->nub = 3;
+  info->m = 3;
+
+  if (j->motor_x.fmax > 0)
+      j->row_motor_x = info->m ++;
+  if (j->motor_y.fmax > 0)
+      j->row_motor_y = info->m ++;
+  if (j->motor_angle.fmax > 0)
+      j->row_motor_angle = info->m ++;
+}
+
+
+
+static void     plane2dGetInfo2 (dxJointPlane2D *joint, dxJoint::Info2 *info)
+/***************************************************************************/
+{
+    int         r0 = 0,
+                r1 = info->rowskip,
+                r2 = 2 * r1;
+    dReal       eps = info->fps * info->erp;
+
+    /* MINFO ("plane2dGetInfo2 ()"); */
+
+/*
+    v = v1, w = omega1
+    (v2, omega2 not important (== static environment))
+
+    constraint equations:
+        xz = 0
+        wx = 0
+        wy = 0
+
+    <=> ( 0 0 1 ) (vx)   ( 0 0 0 ) (wx)   ( 0 )
+        ( 0 0 0 ) (vy) + ( 1 0 0 ) (wy) = ( 0 )
+        ( 0 0 0 ) (vz)   ( 0 1 0 ) (wz)   ( 0 )
+        J1/J1l           Omega1/J1a
+*/
+
+    // fill in linear and angular coeff. for left hand side:
+
+    VoXYZ (&info->J1l[r0], =, 0, 0, 1);
+    VoXYZ (&info->J1l[r1], =, 0, 0, 0);
+    VoXYZ (&info->J1l[r2], =, 0, 0, 0);
+
+    VoXYZ (&info->J1a[r0], =, 0, 0, 0);
+    VoXYZ (&info->J1a[r1], =, 1, 0, 0);
+    VoXYZ (&info->J1a[r2], =, 0, 1, 0);
+
+    // error correction (against drift):
+
+    // a) linear vz, so that z (== pos[2]) == 0
+    //info->c[0] = eps * -joint->node[0].body->pos[2];
+    dBodyID body = joint->node[0].body;
+    info->c[0] = eps * -(dBodyGetPosition(body)[2]);
+
+# if 0
+    // b) angular correction? -> left to application !!!
+    //    dReal       *body_z_axis = &joint->node[0].body->R[8];
+    dReal       *body_z_axis = &(dBodyGetRotation(body)[8]);
+    info->c[1] = eps * +atan2 (body_z_axis[1], body_z_axis[2]); // wx error
+    info->c[2] = eps * -atan2 (body_z_axis[0], body_z_axis[2]); // wy error
+# endif
+
+    // if the slider is powered, or has joint limits, add in the extra row:
+
+    if (joint->row_motor_x > 0)
+        joint->motor_x.addLimot (
+            (dxJoint*)joint, info, joint->row_motor_x, Midentity[0], 0);
+
+    if (joint->row_motor_y > 0)
+        joint->motor_y.addLimot (
+            (dxJoint*)joint, info, joint->row_motor_y, Midentity[1], 0);
+
+    if (joint->row_motor_angle > 0)
+        joint->motor_angle.addLimot (
+            (dxJoint*)joint, info, joint->row_motor_angle, Midentity[2], 1);
+}
+
+
+
+dxJoint::Vtable __dplane2d_vtable =
+{
+  sizeof (dxJointPlane2D),
+  (dxJoint::init_fn*) plane2dInit,
+  (dxJoint::getInfo1_fn*) plane2dGetInfo1,
+  (dxJoint::getInfo2_fn*) plane2dGetInfo2,
+  dJointTypePlane2D
+};
+
+
+void dJointSetPlane2DXParam (dJointID joint,
+                      int parameter, dReal value)
+{
+  dUASSERT (joint, "bad joint argument");
+  dUASSERT (joint->vtable == &__dplane2d_vtable, "joint is not a plane2d");
+  ((dxJointPlane2D*)joint)->motor_x.set (parameter, value);
+}
+
+
+void dJointSetPlane2DYParam ( dJointID joint,
+			      int parameter, dReal value)
+{
+  dUASSERT (joint, "bad joint argument");
+  dUASSERT (joint->vtable == &__dplane2d_vtable, "joint is not a plane2d");
+  ((dxJointPlane2D*)joint)->motor_y.set (parameter, value);
+}
+
+
+void dJointSetPlane2DAngleParam ( dJointID joint,
+				  int parameter, dReal value)
+{
+  dUASSERT (joint, "bad joint argument");
+  dUASSERT (joint->vtable == &__dplane2d_vtable, "joint is not a plane2d");
+  ((dxJointPlane2D*)joint)->motor_angle.set (parameter, value);
+}
+
+
diff -Naur ode-0.6.old/ode/src/joint.h ode-0.6/ode/src/joint.h
--- ode-0.6.old/ode/src/joint.h	2006-03-14 14:03:58.000000000 -0500
+++ ode-0.6/ode/src/joint.h	2006-07-31 19:57:49.750064250 -0400
@@ -265,6 +265,21 @@
 extern struct dxJoint::Vtable __dfixed_vtable;
 
 
+// plane2D
+
+struct dxJointPlane2D : public dxJoint
+{
+    int                 row_motor_x;
+    int                 row_motor_y;
+    int                 row_motor_angle;
+    dxJointLimitMotor   motor_x;    
+    dxJointLimitMotor   motor_y;
+    dxJointLimitMotor   motor_angle;
+};
+
+extern struct dxJoint::Vtable __dplane2d_vtable;
+
+
 // null joint, for testing only
 
 struct dxJointNull : public dxJoint {
diff -Naur ode-0.6.old/ode/src/ode.cpp ode-0.6/ode/src/ode.cpp
--- ode-0.6.old/ode/src/ode.cpp	2006-05-05 11:29:49.000000000 -0400
+++ ode-0.6/ode/src/ode.cpp	2006-07-31 19:56:57.270784500 -0400
@@ -979,6 +979,13 @@
   return createJoint (w,group,&__dlmotor_vtable);
 }
 
+
+dxJoint * dJointCreatePlane2D (dWorldID w, dJointGroupID group)
+{
+  dAASSERT (w);
+  return createJoint (w,group,&__dplane2d_vtable);
+}
+
 void dJointDestroy (dxJoint *j)
 {
   dAASSERT (j);
Personal tools
Navigation