/************************************************************************* * * * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. * * All rights reserved. Email: russ@q12.org Web: www.q12.org * * * * This library is free software; you can redistribute it and/or * * modify it under the terms of EITHER: * * (1) The GNU Lesser General Public License as published by the Free * * Software Foundation; either version 2.1 of the License, or (at * * your option) any later version. The text of the GNU Lesser * * General Public License is included with this library in the * * file LICENSE.TXT. * * (2) The BSD-style license that is included with this library in * * the file LICENSE-BSD.TXT. * * * * This library is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files * * LICENSE.TXT and LICENSE-BSD.TXT for more details. * * * * Created by: Remi Ricard * * (remi.ricard@simlog.com or papaDoc@videotron.ca) * * Creation date: 2007/05/04 * *************************************************************************/ /* This program demonstrates how the Piston joint works. A Piston joint enables the sliding of a body with respect to another body and the 2 bodies are free to rotate about the sliding axis. - The yellow body is fixed to the world. - The yellow body and the blue body are attached by a Piston joint with the axis along the x direction. - The purple object is a geometry obstacle. - The red line is the representation of the prismatic axis - The orange line is the representation of the rotoide axis - The light blue ball is the anchor position N.B. Many command options are available type -h to print them. */ #include #include #include #include #include "texturepath.h" #ifdef _MSC_VER #pragma warning(disable:4244 4305) // for VC++, no precision loss complaints #endif // select correct drawing functions #ifdef dDOUBLE #define dsDrawBox dsDrawBoxD #define dsDrawCylinder dsDrawCylinderD #define dsDrawCapsule dsDrawCapsuleD #define dsDrawSphere dsDrawSphereD #endif const dReal VEL_INC = 0.01; // Velocity increment // physics parameters const dReal PI = 3.14159265358979323846264338327950288419716939937510; const dReal BODY1_LENGTH = 1.5; // Size along the X axis const dReal RADIUS = 0.2; const dReal AXIS_RADIUS = 0.01; #define X 0 #define Y 1 #define Z 2 enum INDEX { BODY1 = 0, BODY2, RECT, BOX, OBS, GROUND, NUM_PARTS, ALL = NUM_PARTS }; const int catBits[NUM_PARTS+1] = { 0x0001, ///< Ext Cylinder category 0x0002, ///< Int Cylinder category 0x0004, ///< Int_Rect Cylinder category 0x0008, ///< Box category 0x0010, ///< Obstacle category 0x0020, ///< Ground category ~0L ///< All categories }; #define Mass1 10 #define Mass2 8 //camera view static float xyz[3] = {2.0f,-3.5f,2.0000f}; static float hpr[3] = {90.000f,-25.5000f,0.0000f}; //world,space,body & geom static dWorldID world; static dSpaceID space; static dJointGroupID contactgroup; static dBodyID body[NUM_PARTS]; static dGeomID geom[NUM_PARTS]; // Default Positions and anchor of the 2 bodies dVector3 pos1; dVector3 pos2; dVector3 anchor; static dJoint *joint; const dReal BODY2_SIDES[3] = {0.4, 0.4, 0.4}; const dReal OBS_SIDES[3] = {1,1,1}; const dReal RECT_SIDES[3] = {0.3, 0.1, 0.2}; int type = dJointTypePiston; //#pragma message("tc to be changed to 0") int tc = 0; // The test case choice; //collision detection static void nearCallback (void *, dGeomID o1, dGeomID o2) { int i,n; dBodyID b1 = dGeomGetBody (o1); dBodyID b2 = dGeomGetBody (o2); if (b1 && b2 && dAreConnectedExcluding (b1,b2,dJointTypeContact) ) return; const int N = 10; dContact contact[N]; n = dCollide (o1,o2,N,&contact[0].geom,sizeof (dContact) ); if (n > 0) { for (i=0; iattach (body[BODY1], body[BODY2]); if (joint->getType() == dJointTypePiston) dJointSetPistonAnchor(joint->id(), anchor[X], anchor[Y], anchor[Z]); } } // function to update camera position at each step. void update() { // static FILE *file = fopen("x:/sim/src/libode/tstsrcSF/export.dat", "w"); // static int cnt = 0; // char str[24]; // sprintf(str, "%06d",cnt++); // dWorldExportDIF(world, file, str); } // called when a key pressed static void command (int cmd) { switch (cmd) { case 'h' : case 'H' : case '?' : printKeyBoardShortCut(); break; // Force case 'q' : case 'Q' : dBodyAddForce (body[BODY1],4,0,0); break; case 'w' : case 'W' : dBodyAddForce (body[BODY1],-4,0,0); break; case 'a' : case 'A' : dBodyAddForce (body[BODY1],0,40,0); break; case 's' : case 'S' : dBodyAddForce (body[BODY1],0,-40,0); break; case 'z' : case 'Z' : dBodyAddForce (body[BODY1],0,0,4); break; case 'x' : case 'X' : dBodyAddForce (body[BODY1],0,0,-4); break; // Torque case 'e': case 'E': dBodyAddTorque (body[BODY1],0.1,0,0); break; case 'r': case 'R': dBodyAddTorque (body[BODY1],-0.1,0,0); break; case 'd': case 'D': dBodyAddTorque (body[BODY1],0, 0.1,0); break; case 'f': case 'F': dBodyAddTorque (body[BODY1],0,-0.1,0); break; case 'c': case 'C': dBodyAddTorque (body[BODY1],0.1,0,0); break; case 'v': case 'V': dBodyAddTorque (body[BODY1],-0.1,0,0); break; case 't': case 'T': if (joint->getType() == dJointTypePiston) dJointAddPistonForce (joint->id(),1); else dJointAddSliderForce (joint->id(),1); break; case 'y': case 'Y': if (joint->getType() == dJointTypePiston) dJointAddPistonForce (joint->id(),-1); else dJointAddSliderForce (joint->id(),-1); break; case '8' : dJointAttach(joint->id(), body[0], 0); break; case '9' : dJointAttach(joint->id(), 0, body[0]); break; case 'i': case 'I' : joint->setParam (dParamLoStop, 0); joint->setParam (dParamHiStop, 0); break; case 'o': case 'O' : joint->setParam (dParamLoStop2, 0); joint->setParam (dParamHiStop2, 0); break; case 'k': case 'K': joint->setParam (dParamLoStop2, -45.0*3.14159267/180.0); joint->setParam (dParamHiStop2, 45.0*3.14159267/180.0); break; case 'l': case 'L': joint->setParam (dParamLoStop2, -dInfinity); joint->setParam (dParamHiStop2, dInfinity); break; // Velocity of joint case ',': case '<' : { dReal vel = joint->getParam (dParamVel) - VEL_INC; joint->setParam (dParamVel, vel); std::cout<<"Velocity = "<' : { dReal vel = joint->getParam (dParamVel) + VEL_INC; joint->setParam (dParamVel, vel); std::cout<<"Velocity = "<getType() ) { case dJointTypeSlider : { dSliderJoint *sj = reinterpret_cast (joint); std::cout<<"Position ="<getPosition() <<"\n"; } break; case dJointTypePiston : { dPistonJoint *rj = reinterpret_cast (joint); std::cout<<"Position ="<getPosition() <<"\n"; } break; default: {} // keep the compiler happy } } break; case '+' : (++tc) %= 4; setPositionBodies (tc); break; case '-' : (--tc) %= 4; setPositionBodies (tc); break; } } static void drawBox (dGeomID id, int R, int G, int B) { if (!id) return; const dReal *pos = dGeomGetPosition (id); const dReal *rot = dGeomGetRotation (id); dsSetColor (R,G,B); dVector3 l; dGeomBoxGetLengths (id, l); dsDrawBox (pos, rot, l); } // simulation loop static void simLoop (int pause) { const dReal *rot; dVector3 ax; dReal l=0; switch (joint->getType() ) { case dJointTypeSlider : ( (dSliderJoint *) joint)->getAxis (ax); l = ( (dSliderJoint *) joint)->getPosition(); break; case dJointTypePiston : ( (dPistonJoint *) joint)->getAxis (ax); l = ( (dPistonJoint *) joint)->getPosition(); break; default: {} // keep the compiler happy } if (!pause) { double simstep = 0.01; // 1ms simulation steps double dt = dsElapsedTime(); int nrofsteps = (int) ceilf (dt/simstep); if (!nrofsteps) nrofsteps = 1; for (int i=0; igetType() == dJointTypePiston ) { dVector3 anchor; dJointGetPistonAnchor(joint->id(), anchor); // Draw the rotoide axis rot = dGeomGetRotation (geom[BODY2]); dsSetColor (1,0.5,0); dsDrawCylinder (anchor, rot, 4, AXIS_RADIUS); dsSetColor (0,1,1); rot = dGeomGetRotation (geom[BODY1]); dsDrawSphere (anchor, rot, 1.5*RADIUS); } } } void Help (char **argv) { printf ("%s ", argv[0]); printf (" -h | --help : print this help\n"); printf (" -s | --slider : Set the joint as a slider\n"); printf (" -p | --piston : Set the joint as a Piston. (Default joint)\n"); printf (" -1 | --offset1 : Create an offset between the 2 bodies\n"); printf (" Offset one of the body by z=-0.5 and keep the anchor\n"); printf (" point in the middle of the fixed body\n"); printf (" -2 | --offset2 : Create an offset between the 2 bodies\n"); printf (" Offset one of the body by z=-0.5 and set the anchor\n"); printf (" point in the middle of the movable body\n"); printf (" -3 | --offset3 : Create an offset between the 2 bodies\n"); printf (" Offset one of the body by z=-0.5 and set the anchor\n"); printf (" point in the middle of the 2 bodies\n"); printf (" -t | --texture-path path : Path to the texture.\n"); printf (" Default = %s\n", DRAWSTUFF_TEXTURE_PATH); printf (" -n | --notFixed : In free space with no gravity mode"); printf ("-notex : Don't use texture\n"); printf ("-noshadow : No shadow\n"); printf ("-noshadows : No shadows\n"); printf ("-pause : Initial pause\n"); printf ("--------------------------------------------------\n"); printf ("Hit any key to continue:"); getchar(); exit (0); } int main (int argc, char **argv) { dInitODE2(0); bool fixed = true; // setup pointers to drawstuff callback functions dsFunctions fn; fn.version = DS_VERSION; fn.start = &start; fn.step = &simLoop; fn.command = &command; fn.stop = 0; fn.path_to_textures = DRAWSTUFF_TEXTURE_PATH; dVector3 offset; dSetZero (offset, 4); // Default test case if (argc >= 2 ) { for (int i=1; i < argc; ++i) { //static int tata = 0; if (1) { if ( 0 == strcmp ("-h", argv[i]) || 0 == strcmp ("--help", argv[i]) ) Help (argv); if ( 0 == strcmp ("-s", argv[i]) || 0 == strcmp ("--slider", argv[i]) ) type = dJointTypeSlider; if ( 0 == strcmp ("-t", argv[i]) || 0 == strcmp ("--texture-path", argv[i]) ) { int j = i+1; if ( j >= argc || // Check if we have enough arguments argv[j][0] == '\0' || // We should have a path here argv[j][0] == '-' ) // We should have a path not a command line Help (argv); else fn.path_to_textures = argv[++i]; // Increase i since we use this argument } } if ( 0 == strcmp ("-1", argv[i]) || 0 == strcmp ("--offset1", argv[i]) ) tc = 1; if ( 0 == strcmp ("-2", argv[i]) || 0 == strcmp ("--offset2", argv[i]) ) tc = 2; if ( 0 == strcmp ("-3", argv[i]) || 0 == strcmp ("--offset3", argv[i]) ) tc = 3; if (0 == strcmp ("-n", argv[i]) || 0 == strcmp ("--notFixed", argv[i]) ) fixed = false; } } world = dWorldCreate(); dWorldSetERP (world, 0.8); space = dSimpleSpaceCreate (0); contactgroup = dJointGroupCreate (0); geom[GROUND] = dCreatePlane (space, 0,0,1,0); dGeomSetCategoryBits (geom[GROUND], catBits[GROUND]); dGeomSetCollideBits (geom[GROUND], catBits[ALL]); dMass m; dMatrix3 R; // Create the Obstacle geom[OBS] = dCreateBox (space, OBS_SIDES[0], OBS_SIDES[1], OBS_SIDES[2]); dGeomSetCategoryBits (geom[OBS], catBits[OBS]); dGeomSetCollideBits (geom[OBS], catBits[ALL]); //Rotation of 45deg around y dRFromAxisAndAngle (R, 1,1,0, -0.25*PI); dGeomSetRotation (geom[OBS], R); dGeomSetPosition (geom[OBS], 1.95, -0.2, 0.5); //Rotation of 90deg around y // Will orient the Z axis along X dRFromAxisAndAngle (R, 0,1,0, -0.5*PI); // Create Body2 (Wiil be attached to the world) body[BODY2] = dBodyCreate (world); // Main axis of cylinder is along X=1 dMassSetBox (&m, 1, BODY2_SIDES[0], BODY2_SIDES[1], BODY2_SIDES[2]); dMassAdjust (&m, Mass1); geom[BODY2] = dCreateBox (space, BODY2_SIDES[0], BODY2_SIDES[1], BODY2_SIDES[2]); dGeomSetBody (geom[BODY2], body[BODY2]); dGeomSetOffsetRotation (geom[BODY2], R); dGeomSetCategoryBits (geom[BODY2], catBits[BODY2]); dGeomSetCollideBits (geom[BODY2], catBits[ALL] & (~catBits[BODY1]) ); dBodySetMass (body[BODY2], &m); // Create Body 1 (Slider on the prismatic axis) body[BODY1] = dBodyCreate (world); // Main axis of capsule is along X=1 dMassSetCapsule (&m, 1, 1, RADIUS, BODY1_LENGTH); dMassAdjust (&m, Mass1); geom[BODY1] = dCreateCapsule (space, RADIUS, BODY1_LENGTH); dGeomSetBody (geom[BODY1], body[BODY1]); dGeomSetOffsetRotation (geom[BODY1], R); dGeomSetCategoryBits (geom[BODY1], catBits[BODY1]); dGeomSetCollideBits (geom[BODY1], catBits[ALL] & ~catBits[BODY2] & ~catBits[RECT]); dMass mRect; dMassSetBox (&mRect, 1, RECT_SIDES[0], RECT_SIDES[1], RECT_SIDES[2]); dMassAdd (&m, &mRect); // TODO: translate m? geom[RECT] = dCreateBox (space, RECT_SIDES[0], RECT_SIDES[1], RECT_SIDES[2]); dGeomSetBody (geom[RECT], body[BODY1]); dGeomSetOffsetPosition (geom[RECT], (BODY1_LENGTH-RECT_SIDES[0]) /2.0, 0.0, -RADIUS -RECT_SIDES[2]/2.0); dGeomSetCategoryBits (geom[RECT], catBits[RECT]); dGeomSetCollideBits (geom[RECT], catBits[ALL] & (~catBits[BODY1]) ); dBodySetMass (body[BODY1], &m); setPositionBodies (tc); if ( fixed ) { // Attache external cylinder to the world dJointID fixed = dJointCreateFixed (world,0); dJointAttach (fixed , NULL, body[BODY2]); dJointSetFixed (fixed ); dWorldSetGravity (world,0,0,-0.8); } else { dWorldSetGravity (world,0,0,0); } // The static is here only to help debugging switch (type) { case dJointTypeSlider : { dSliderJoint *sj = new dSliderJoint (world, 0); sj->attach (body[BODY1], body[BODY2]); sj->setAxis (1, 0, 0); joint = sj; } break; case dJointTypePiston : // fall through default default: { dPistonJoint *pj = new dPistonJoint (world, 0); pj->attach (body[BODY1], body[BODY2]); pj->setAxis (1, 0, 0); dJointSetPistonAnchor(pj->id(), anchor[X], anchor[Y], anchor[Z]); joint = pj; } break; }; // run simulation dsSimulationLoop (argc,argv,400,300,&fn); delete joint; dJointGroupDestroy (contactgroup); dSpaceDestroy (space); dWorldDestroy (world); dCloseODE(); return 0; }