1 /*************************************************************************
3 * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
4 * All rights reserved. Email: russ@q12.org Web: www.q12.org *
6 * This library is free software; you can redistribute it and/or *
7 * modify it under the terms of EITHER: *
8 * (1) The GNU Lesser General Public License as published by the Free *
9 * Software Foundation; either version 2.1 of the License, or (at *
10 * your option) any later version. The text of the GNU Lesser *
11 * General Public License is included with this library in the *
13 * (2) The BSD-style license that is included with this library in *
14 * the file LICENSE-BSD.TXT. *
16 * This library is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the files *
19 * LICENSE.TXT and LICENSE-BSD.TXT for more details. *
21 *************************************************************************/
26 #include "joint_internal.h"
31 //****************************************************************************
32 // hinge 2. note that this joint must be attached to two bodies for it to work
35 dxJointHinge2::measureAngle() const
38 dMultiply0_331( a1
, node
[1].body
->posr
.R
, axis2
);
39 dMultiply1_331( a2
, node
[0].body
->posr
.R
, a1
);
40 dReal x
= dCalcVectorDot3( v1
, a2
);
41 dReal y
= dCalcVectorDot3( v2
, a2
);
42 return -dAtan2( y
, x
);
46 dxJointHinge2::dxJointHinge2( dxWorld
*w
) :
49 dSetZero( anchor1
, 4 );
50 dSetZero( anchor2
, 4 );
66 susp_erp
= world
->global_erp
;
67 susp_cfm
= world
->global_cfm
;
69 flags
|= dJOINT_TWOBODIES
;
74 dxJointHinge2::getSureMaxInfo( SureMaxInfo
* info
)
81 dxJointHinge2::getInfo1( dxJoint::Info1
*info
)
86 // see if we're powered or at a joint limit for axis 1
88 if (( limot1
.lostop
>= -M_PI
|| limot1
.histop
<= M_PI
) &&
89 limot1
.lostop
<= limot1
.histop
)
91 dReal angle
= measureAngle();
92 limot1
.testRotationalLimit( angle
);
94 if ( limot1
.limit
|| limot1
.fmax
> 0 ) info
->m
++;
96 // see if we're powering axis 2 (we currently never limit this axis)
98 if ( limot2
.fmax
> 0 ) info
->m
++;
102 ////////////////////////////////////////////////////////////////////////////////
103 /// Function that computes ax1,ax2 = axis 1 and 2 in global coordinates (they are
104 /// relative to body 1 and 2 initially) and then computes the constrained
105 /// rotational axis as the cross product of ax1 and ax2.
106 /// the sin and cos of the angle between axis 1 and 2 is computed, this comes
107 /// from dot and cross product rules.
109 /// @param ax1 Will contain the joint axis1 in world frame
110 /// @param ax2 Will contain the joint axis2 in world frame
111 /// @param axis Will contain the cross product of ax1 x ax2
114 ////////////////////////////////////////////////////////////////////////////////
116 dxJointHinge2::getAxisInfo(dVector3 ax1
, dVector3 ax2
, dVector3 axCross
,
117 dReal
&sin_angle
, dReal
&cos_angle
) const
119 dMultiply0_331 (ax1
, node
[0].body
->posr
.R
, axis1
);
120 dMultiply0_331 (ax2
, node
[1].body
->posr
.R
, axis2
);
121 dCalcVectorCross3(axCross
,ax1
,ax2
);
122 sin_angle
= dSqrt (axCross
[0]*axCross
[0] + axCross
[1]*axCross
[1] + axCross
[2]*axCross
[2]);
123 cos_angle
= dCalcVectorDot3 (ax1
,ax2
);
128 dxJointHinge2::getInfo2( dxJoint::Info2
*info
)
130 // get information we need to set the hinge row
133 const dxJointHinge2
*joint
= this;
136 joint
->getAxisInfo( ax1
, ax2
, q
, s
, c
);
137 dNormalize3( q
); // @@@ quicker: divide q by s ?
139 // set the three ball-and-socket rows (aligned to the suspension axis ax1)
140 setBall2( this, info
, anchor1
, anchor2
, ax1
, susp_erp
);
143 int s3
= 3 * info
->rowskip
;
144 info
->J1a
[s3
+0] = q
[0];
145 info
->J1a
[s3
+1] = q
[1];
146 info
->J1a
[s3
+2] = q
[2];
147 if ( joint
->node
[1].body
)
149 info
->J2a
[s3
+0] = -q
[0];
150 info
->J2a
[s3
+1] = -q
[1];
151 info
->J2a
[s3
+2] = -q
[2];
154 // compute the right hand side for the constrained rotational DOF.
155 // axis 1 and axis 2 are separated by an angle `theta'. the desired
156 // separation angle is theta0. sin(theta0) and cos(theta0) are recorded
157 // in the joint structure. the correcting angular velocity is:
158 // |angular_velocity| = angle/time = erp*(theta0-theta) / stepsize
159 // = (erp*fps) * (theta0-theta)
160 // (theta0-theta) can be computed using the following small-angle-difference
162 // theta0-theta ~= tan(theta0-theta)
163 // = sin(theta0-theta)/cos(theta0-theta)
164 // = (c*s0 - s*c0) / (c*c0 + s*s0)
165 // = c*s0 - s*c0 assuming c*c0 + s*s0 ~= 1
166 // where c = cos(theta), s = sin(theta)
167 // c0 = cos(theta0), s0 = sin(theta0)
169 dReal k
= info
->fps
* info
->erp
;
170 info
->c
[3] = k
* ( c0
* s
- joint
->s0
* c
);
172 // if the axis1 hinge is powered, or has joint limits, add in more stuff
173 int row
= 4 + limot1
.addLimot( this, info
, 4, ax1
, 1 );
175 // if the axis2 hinge is powered, add in more stuff
176 limot2
.addLimot( this, info
, row
, ax2
, 1 );
178 // set parameter for the suspension
179 info
->cfm
[0] = susp_cfm
;
183 // compute vectors v1 and v2 (embedded in body1), used to measure angle
184 // between body 1 and body 2
187 dxJointHinge2::makeV1andV2()
191 // get axis 1 and 2 in global coords
192 dVector3 ax1
, ax2
, v
;
193 dMultiply0_331( ax1
, node
[0].body
->posr
.R
, axis1
);
194 dMultiply0_331( ax2
, node
[1].body
->posr
.R
, axis2
);
196 // don't do anything if the axis1 or axis2 vectors are zero or the same
197 if (( ax1
[0] == 0 && ax1
[1] == 0 && ax1
[2] == 0 ) ||
198 ( ax2
[0] == 0 && ax2
[1] == 0 && ax2
[2] == 0 ) ||
199 ( ax1
[0] == ax2
[0] && ax1
[1] == ax2
[1] && ax1
[2] == ax2
[2] ) ) return;
201 // modify axis 2 so it's perpendicular to axis 1
202 dReal k
= dCalcVectorDot3( ax1
, ax2
);
203 for ( int i
= 0; i
< 3; i
++ ) ax2
[i
] -= k
* ax1
[i
];
206 // make v1 = modified axis2, v2 = axis1 x (modified axis2)
207 dCalcVectorCross3( v
, ax1
, ax2
);
208 dMultiply1_331( v1
, node
[0].body
->posr
.R
, ax2
);
209 dMultiply1_331( v2
, node
[0].body
->posr
.R
, v
);
214 void dJointSetHinge2Anchor( dJointID j
, dReal x
, dReal y
, dReal z
)
216 dxJointHinge2
* joint
= ( dxJointHinge2
* )j
;
217 dUASSERT( joint
, "bad joint argument" );
218 checktype( joint
, Hinge2
);
219 setAnchors( joint
, x
, y
, z
, joint
->anchor1
, joint
->anchor2
);
220 joint
->makeV1andV2();
224 void dJointSetHinge2Axis1( dJointID j
, dReal x
, dReal y
, dReal z
)
226 dxJointHinge2
* joint
= ( dxJointHinge2
* )j
;
227 dUASSERT( joint
, "bad joint argument" );
228 checktype( joint
, Hinge2
);
229 if ( joint
->node
[0].body
)
231 setAxes(joint
, x
, y
, z
, joint
->axis1
, NULL
);
233 // compute the sin and cos of the angle between axis 1 and axis 2
234 dVector3 ax1
, ax2
, ax
;
235 joint
->getAxisInfo( ax1
, ax2
, ax
, joint
->s0
, joint
->c0
);
237 joint
->makeV1andV2();
241 void dJointSetHinge2Axis2( dJointID j
, dReal x
, dReal y
, dReal z
)
243 dxJointHinge2
* joint
= ( dxJointHinge2
* )j
;
244 dUASSERT( joint
, "bad joint argument" );
245 checktype( joint
, Hinge2
);
246 if ( joint
->node
[1].body
)
248 setAxes(joint
, x
, y
, z
, NULL
, joint
->axis2
);
251 // compute the sin and cos of the angle between axis 1 and axis 2
252 dVector3 ax1
, ax2
, ax
;;
253 joint
->getAxisInfo( ax1
, ax2
, ax
, joint
->s0
, joint
->c0
);
255 joint
->makeV1andV2();
259 void dJointSetHinge2Param( dJointID j
, int parameter
, dReal value
)
261 dxJointHinge2
* joint
= ( dxJointHinge2
* )j
;
262 dUASSERT( joint
, "bad joint argument" );
263 checktype( joint
, Hinge2
);
264 if (( parameter
& 0xff00 ) == 0x100 )
266 joint
->limot2
.set( parameter
& 0xff, value
);
270 if ( parameter
== dParamSuspensionERP
) joint
->susp_erp
= value
;
271 else if ( parameter
== dParamSuspensionCFM
) joint
->susp_cfm
= value
;
272 else joint
->limot1
.set( parameter
, value
);
277 void dJointGetHinge2Anchor( dJointID j
, dVector3 result
)
279 dxJointHinge2
* joint
= ( dxJointHinge2
* )j
;
280 dUASSERT( joint
, "bad joint argument" );
281 dUASSERT( result
, "bad result argument" );
282 checktype( joint
, Hinge2
);
283 if ( joint
->flags
& dJOINT_REVERSE
)
284 getAnchor2( joint
, result
, joint
->anchor2
);
286 getAnchor( joint
, result
, joint
->anchor1
);
290 void dJointGetHinge2Anchor2( dJointID j
, dVector3 result
)
292 dxJointHinge2
* joint
= ( dxJointHinge2
* )j
;
293 dUASSERT( joint
, "bad joint argument" );
294 dUASSERT( result
, "bad result argument" );
295 checktype( joint
, Hinge2
);
296 if ( joint
->flags
& dJOINT_REVERSE
)
297 getAnchor( joint
, result
, joint
->anchor1
);
299 getAnchor2( joint
, result
, joint
->anchor2
);
303 void dJointGetHinge2Axis1( dJointID j
, dVector3 result
)
305 dxJointHinge2
* joint
= ( dxJointHinge2
* )j
;
306 dUASSERT( joint
, "bad joint argument" );
307 dUASSERT( result
, "bad result argument" );
308 checktype( joint
, Hinge2
);
309 if ( joint
->node
[0].body
)
311 dMultiply0_331( result
, joint
->node
[0].body
->posr
.R
, joint
->axis1
);
316 void dJointGetHinge2Axis2( dJointID j
, dVector3 result
)
318 dxJointHinge2
* joint
= ( dxJointHinge2
* )j
;
319 dUASSERT( joint
, "bad joint argument" );
320 dUASSERT( result
, "bad result argument" );
321 checktype( joint
, Hinge2
);
322 if ( joint
->node
[1].body
)
324 dMultiply0_331( result
, joint
->node
[1].body
->posr
.R
, joint
->axis2
);
329 dReal
dJointGetHinge2Param( dJointID j
, int parameter
)
331 dxJointHinge2
* joint
= ( dxJointHinge2
* )j
;
332 dUASSERT( joint
, "bad joint argument" );
333 checktype( joint
, Hinge2
);
334 if (( parameter
& 0xff00 ) == 0x100 )
336 return joint
->limot2
.get( parameter
& 0xff );
340 if ( parameter
== dParamSuspensionERP
) return joint
->susp_erp
;
341 else if ( parameter
== dParamSuspensionCFM
) return joint
->susp_cfm
;
342 else return joint
->limot1
.get( parameter
);
347 dReal
dJointGetHinge2Angle1( dJointID j
)
349 dxJointHinge2
* joint
= ( dxJointHinge2
* )j
;
350 dUASSERT( joint
, "bad joint argument" );
351 checktype( joint
, Hinge2
);
352 if ( joint
->node
[0].body
) return joint
->measureAngle();
357 dReal
dJointGetHinge2Angle1Rate( dJointID j
)
359 dxJointHinge2
* joint
= ( dxJointHinge2
* )j
;
360 dUASSERT( joint
, "bad joint argument" );
361 checktype( joint
, Hinge2
);
362 if ( joint
->node
[0].body
)
365 dMultiply0_331( axis
, joint
->node
[0].body
->posr
.R
, joint
->axis1
);
366 dReal rate
= dCalcVectorDot3( axis
, joint
->node
[0].body
->avel
);
367 if ( joint
->node
[1].body
)
368 rate
-= dCalcVectorDot3( axis
, joint
->node
[1].body
->avel
);
375 dReal
dJointGetHinge2Angle2Rate( dJointID j
)
377 dxJointHinge2
* joint
= ( dxJointHinge2
* )j
;
378 dUASSERT( joint
, "bad joint argument" );
379 checktype( joint
, Hinge2
);
380 if ( joint
->node
[0].body
&& joint
->node
[1].body
)
383 dMultiply0_331( axis
, joint
->node
[1].body
->posr
.R
, joint
->axis2
);
384 dReal rate
= dCalcVectorDot3( axis
, joint
->node
[0].body
->avel
);
385 if ( joint
->node
[1].body
)
386 rate
-= dCalcVectorDot3( axis
, joint
->node
[1].body
->avel
);
393 void dJointAddHinge2Torques( dJointID j
, dReal torque1
, dReal torque2
)
395 dxJointHinge2
* joint
= ( dxJointHinge2
* )j
;
396 dVector3 axis1
, axis2
;
397 dUASSERT( joint
, "bad joint argument" );
398 checktype( joint
, Hinge2
);
400 if ( joint
->node
[0].body
&& joint
->node
[1].body
)
402 dMultiply0_331( axis1
, joint
->node
[0].body
->posr
.R
, joint
->axis1
);
403 dMultiply0_331( axis2
, joint
->node
[1].body
->posr
.R
, joint
->axis2
);
404 axis1
[0] = axis1
[0] * torque1
+ axis2
[0] * torque2
;
405 axis1
[1] = axis1
[1] * torque1
+ axis2
[1] * torque2
;
406 axis1
[2] = axis1
[2] * torque1
+ axis2
[2] * torque2
;
407 dBodyAddTorque( joint
->node
[0].body
, axis1
[0], axis1
[1], axis1
[2] );
408 dBodyAddTorque( joint
->node
[1].body
, -axis1
[0], -axis1
[1], -axis1
[2] );
414 dxJointHinge2::type() const
416 return dJointTypeHinge2
;
421 dxJointHinge2::size() const
423 return sizeof( *this );
428 dxJointHinge2::setRelativeValues()
431 dJointGetHinge2Anchor(this, anchor
);
432 setAnchors( this, anchor
[0], anchor
[1], anchor
[2], anchor1
, anchor2
);
438 dJointGetHinge2Axis1(this, axis
);
439 setAxes( this, axis
[0],axis
[1],axis
[2], axis1
, NULL
);
444 dJointGetHinge2Axis2(this, axis
);
445 setAxes( this, axis
[0],axis
[1],axis
[2], NULL
, axis2
);
449 getAxisInfo( ax1
, ax2
, axis
, s0
, c0
);