summaryrefslogtreecommitdiff
path: root/libs/ode-0.16.1/ode/src/joints/hinge.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'libs/ode-0.16.1/ode/src/joints/hinge.cpp')
-rw-r--r--libs/ode-0.16.1/ode/src/joints/hinge.cpp394
1 files changed, 394 insertions, 0 deletions
diff --git a/libs/ode-0.16.1/ode/src/joints/hinge.cpp b/libs/ode-0.16.1/ode/src/joints/hinge.cpp
new file mode 100644
index 0000000..70dcd78
--- /dev/null
+++ b/libs/ode-0.16.1/ode/src/joints/hinge.cpp
@@ -0,0 +1,394 @@
+/*************************************************************************
+ * *
+ * 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. *
+ * *
+ *************************************************************************/
+
+
+#include <ode/odeconfig.h>
+#include "config.h"
+#include "hinge.h"
+#include "joint_internal.h"
+
+
+//****************************************************************************
+// hinge
+
+dxJointHinge::dxJointHinge( dxWorld *w ) :
+ dxJoint( w )
+{
+ dSetZero( anchor1, 4 );
+ dSetZero( anchor2, 4 );
+ dSetZero( axis1, 4 );
+ axis1[0] = 1;
+ dSetZero( axis2, 4 );
+ axis2[0] = 1;
+ dSetZero( qrel, 4 );
+ limot.init( world );
+}
+
+
+void
+dxJointHinge::getSureMaxInfo( SureMaxInfo* info )
+{
+ info->max_m = 6;
+}
+
+
+void
+dxJointHinge::getInfo1( dxJoint::Info1 *info )
+{
+ info->nub = 5;
+
+ // see if joint is powered
+ if ( limot.fmax > 0 )
+ info->m = 6; // powered hinge needs an extra constraint row
+ else info->m = 5;
+
+ // see if we're at a joint limit.
+ if (( limot.lostop >= -M_PI || limot.histop <= M_PI ) &&
+ limot.lostop <= limot.histop )
+ {
+ dReal angle = getHingeAngle( node[0].body,
+ node[1].body,
+ axis1, qrel );
+ if ( limot.testRotationalLimit( angle ) )
+ info->m = 6;
+ }
+}
+
+
+void dxJointHinge::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 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 );
+
+ dxBody *body1 = node[1].body;
+
+ int currRowSkip = 3 * rowskip;
+ dCopyVector3(J1 + currRowSkip + GI2__JA_MIN, p);
+ if ( body1 ) {
+ dCopyNegatedVector3(J2 + currRowSkip + GI2__JA_MIN, p);
+ }
+
+ currRowSkip += rowskip;
+ dCopyVector3(J1 + currRowSkip + GI2__JA_MIN, q);
+ if ( body1 ) {
+ dCopyNegatedVector3(J2 + currRowSkip + GI2__JA_MIN, q);
+ }
+
+ // 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 b;
+ if ( body1 ) {
+ dVector3 ax2;
+ dMultiply0_331( ax2, body1->posr.R, axis2 );
+ dCalcVectorCross3( b, ax1, ax2 );
+ } else {
+ dCalcVectorCross3( b, ax1, axis2 );
+ }
+
+ dReal k = worldFPS * worldERP;
+ int currPairSkip = 3 * pairskip;
+ pairRhsCfm[currPairSkip + GI2_RHS] = k * dCalcVectorDot3( b, p );
+ currPairSkip += pairskip;
+ pairRhsCfm[currPairSkip + GI2_RHS] = k * dCalcVectorDot3( b, q );
+
+ // if the hinge is powered, or has joint limits, add in the stuff
+ currRowSkip += rowskip;
+ currPairSkip += pairskip;
+ limot.addLimot( this, worldFPS, J1 + currRowSkip, J2 + currRowSkip, pairRhsCfm + currPairSkip, pairLoHi + currPairSkip, ax1, 1 );
+}
+
+
+
+void dJointSetHingeAnchor( dJointID j, dReal x, dReal y, dReal z )
+{
+ dxJointHinge* joint = ( dxJointHinge* )j;
+ dUASSERT( joint, "bad joint argument" );
+ checktype( joint, Hinge );
+ setAnchors( joint, x, y, z, joint->anchor1, joint->anchor2 );
+ joint->computeInitialRelativeRotation();
+}
+
+
+void dJointSetHingeAnchorDelta( dJointID j, dReal x, dReal y, dReal z, dReal dx, dReal dy, dReal dz )
+{
+ dxJointHinge* joint = ( dxJointHinge* )j;
+ dUASSERT( joint, "bad joint argument" );
+ checktype( joint, Hinge );
+
+ if ( joint->node[0].body )
+ {
+ dReal q[4];
+ q[0] = x - joint->node[0].body->posr.pos[0];
+ q[1] = y - joint->node[0].body->posr.pos[1];
+ q[2] = z - joint->node[0].body->posr.pos[2];
+ q[3] = 0;
+ dMultiply1_331( joint->anchor1, joint->node[0].body->posr.R, q );
+
+ if ( joint->node[1].body )
+ {
+ q[0] = x - joint->node[1].body->posr.pos[0];
+ q[1] = y - joint->node[1].body->posr.pos[1];
+ q[2] = z - joint->node[1].body->posr.pos[2];
+ q[3] = 0;
+ dMultiply1_331( joint->anchor2, joint->node[1].body->posr.R, q );
+ }
+ else
+ {
+ // Move the relative displacement between the passive body and the
+ // anchor in the same direction as the passive body has just moved
+ joint->anchor2[0] = x + dx;
+ joint->anchor2[1] = y + dy;
+ joint->anchor2[2] = z + dz;
+ }
+ }
+ joint->anchor1[3] = 0;
+ joint->anchor2[3] = 0;
+
+ joint->computeInitialRelativeRotation();
+}
+
+
+
+void dJointSetHingeAxis( dJointID j, dReal x, dReal y, dReal z )
+{
+ dxJointHinge* joint = ( dxJointHinge* )j;
+ dUASSERT( joint, "bad joint argument" );
+ checktype( joint, Hinge );
+ setAxes( joint, x, y, z, joint->axis1, joint->axis2 );
+ joint->computeInitialRelativeRotation();
+}
+
+
+void dJointSetHingeAxisOffset( dJointID j, dReal x, dReal y, dReal z, dReal dangle )
+{
+ dxJointHinge* joint = ( dxJointHinge* )j;
+ dUASSERT( joint, "bad joint argument" );
+ checktype( joint, Hinge );
+ setAxes( joint, x, y, z, joint->axis1, joint->axis2 );
+ joint->computeInitialRelativeRotation();
+
+ if ( joint->flags & dJOINT_REVERSE ) dangle = -dangle;
+
+ dQuaternion qAngle, qOffset;
+ dQFromAxisAndAngle(qAngle, x, y, z, dangle);
+ dQMultiply3(qOffset, qAngle, joint->qrel);
+ joint->qrel[0] = qOffset[0];
+ joint->qrel[1] = qOffset[1];
+ joint->qrel[2] = qOffset[2];
+ joint->qrel[3] = qOffset[3];
+}
+
+
+
+void dJointGetHingeAnchor( dJointID j, dVector3 result )
+{
+ dxJointHinge* joint = ( dxJointHinge* )j;
+ dUASSERT( joint, "bad joint argument" );
+ dUASSERT( result, "bad result argument" );
+ checktype( joint, Hinge );
+ if ( joint->flags & dJOINT_REVERSE )
+ getAnchor2( joint, result, joint->anchor2 );
+ else
+ getAnchor( joint, result, joint->anchor1 );
+}
+
+
+void dJointGetHingeAnchor2( dJointID j, dVector3 result )
+{
+ dxJointHinge* joint = ( dxJointHinge* )j;
+ dUASSERT( joint, "bad joint argument" );
+ dUASSERT( result, "bad result argument" );
+ checktype( joint, Hinge );
+ if ( joint->flags & dJOINT_REVERSE )
+ getAnchor( joint, result, joint->anchor1 );
+ else
+ getAnchor2( joint, result, joint->anchor2 );
+}
+
+
+void dJointGetHingeAxis( dJointID j, dVector3 result )
+{
+ dxJointHinge* joint = ( dxJointHinge* )j;
+ dUASSERT( joint, "bad joint argument" );
+ dUASSERT( result, "bad result argument" );
+ checktype( joint, Hinge );
+ getAxis( joint, result, joint->axis1 );
+}
+
+
+void dJointSetHingeParam( dJointID j, int parameter, dReal value )
+{
+ dxJointHinge* joint = ( dxJointHinge* )j;
+ dUASSERT( joint, "bad joint argument" );
+ checktype( joint, Hinge );
+ joint->limot.set( parameter, value );
+}
+
+
+dReal dJointGetHingeParam( dJointID j, int parameter )
+{
+ dxJointHinge* joint = ( dxJointHinge* )j;
+ dUASSERT( joint, "bad joint argument" );
+ checktype( joint, Hinge );
+ return joint->limot.get( parameter );
+}
+
+
+dReal dJointGetHingeAngle( dJointID j )
+{
+ dxJointHinge* joint = ( dxJointHinge* )j;
+ dAASSERT( joint );
+ checktype( joint, Hinge );
+ if ( joint->node[0].body )
+ {
+ dReal ang = getHingeAngle( joint->node[0].body,
+ joint->node[1].body,
+ joint->axis1,
+ joint->qrel );
+ if ( joint->flags & dJOINT_REVERSE )
+ return -ang;
+ else
+ return ang;
+ }
+ else return 0;
+}
+
+
+dReal dJointGetHingeAngleRate( dJointID j )
+{
+ dxJointHinge* joint = ( dxJointHinge* )j;
+ dAASSERT( joint );
+ checktype( joint, Hinge );
+ if ( joint->node[0].body )
+ {
+ dVector3 axis;
+ dMultiply0_331( axis, joint->node[0].body->posr.R, joint->axis1 );
+ dReal rate = dCalcVectorDot3( axis, joint->node[0].body->avel );
+ if ( joint->node[1].body ) rate -= dCalcVectorDot3( axis, joint->node[1].body->avel );
+ if ( joint->flags & dJOINT_REVERSE ) rate = - rate;
+ return rate;
+ }
+ else return 0;
+}
+
+
+void dJointAddHingeTorque( dJointID j, dReal torque )
+{
+ dxJointHinge* joint = ( dxJointHinge* )j;
+ dVector3 axis;
+ dAASSERT( joint );
+ checktype( joint, Hinge );
+
+ if ( joint->flags & dJOINT_REVERSE )
+ torque = -torque;
+
+ getAxis( joint, axis, joint->axis1 );
+ axis[0] *= torque;
+ axis[1] *= torque;
+ axis[2] *= torque;
+
+ if ( joint->node[0].body != 0 )
+ dBodyAddTorque( joint->node[0].body, axis[0], axis[1], axis[2] );
+ if ( joint->node[1].body != 0 )
+ dBodyAddTorque( joint->node[1].body, -axis[0], -axis[1], -axis[2] );
+}
+
+
+dJointType
+dxJointHinge::type() const
+{
+ return dJointTypeHinge;
+}
+
+
+
+sizeint
+dxJointHinge::size() const
+{
+ return sizeof( *this );
+}
+
+
+void
+dxJointHinge::setRelativeValues()
+{
+ dVector3 vec;
+ dJointGetHingeAnchor(this, vec);
+ setAnchors( this, vec[0], vec[1], vec[2], anchor1, anchor2 );
+
+ dJointGetHingeAxis(this, vec);
+ setAxes( this, vec[0], vec[1], vec[2], axis1, axis2 );
+ computeInitialRelativeRotation();
+}
+
+
+/// Compute initial relative rotation body1 -> body2, or env -> body1
+void
+dxJointHinge::computeInitialRelativeRotation()
+{
+ if ( node[0].body )
+ {
+ if ( node[1].body )
+ {
+ dQMultiply1( qrel, node[0].body->q, node[1].body->q );
+ }
+ else
+ {
+ // set qrel to the transpose of the first body q
+ qrel[0] = node[0].body->q[0];
+ qrel[1] = -node[0].body->q[1];
+ qrel[2] = -node[0].body->q[2];
+ qrel[3] = -node[0].body->q[3];
+ }
+ }
+}
+