1 /*************************************************************************
2 * *
3 * Open Dynamics Engine, Copyright (C) 2001,2002 Russell L. Smith. *
4 * All rights reserved. Email: russ@q12.org Web: www.q12.org *
5 * *
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 *
12 * file LICENSE.TXT. *
13 * (2) The BSD-style license that is included with this library in *
14 * the file LICENSE-BSD.TXT. *
15 * *
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. *
20 * *
21 *************************************************************************/
22
23
24 #include "hinge.h"
25 #include "joint_internal.h"
26
27
28 //****************************************************************************
29 // hinge
30
dxJointHinge(dxWorld * w)31 dxJointHinge::dxJointHinge( dxWorld *w ) :
32 dxJoint( w )
33 {
34 dSetZero( anchor1, 4 );
35 dSetZero( anchor2, 4 );
36 dSetZero( axis1, 4 );
37 axis1[0] = 1;
38 dSetZero( axis2, 4 );
39 axis2[0] = 1;
40 dSetZero( qrel, 4 );
41 limot.init( world );
42 }
43
44
45 void
getInfo1(dxJoint::Info1 * info)46 dxJointHinge::getInfo1( dxJoint::Info1 *info )
47 {
48 info->nub = 5;
49
50 // see if joint is powered
51 if ( limot.fmax > 0 )
52 info->m = 6; // powered hinge needs an extra constraint row
53 else info->m = 5;
54
55 // see if we're at a joint limit.
56 if (( limot.lostop >= -M_PI || limot.histop <= M_PI ) &&
57 limot.lostop <= limot.histop )
58 {
59 dReal angle = getHingeAngle( node[0].body,
60 node[1].body,
61 axis1, qrel );
62 if ( limot.testRotationalLimit( angle ) )
63 info->m = 6;
64 }
65 }
66
67
68 void
getInfo2(dxJoint::Info2 * info)69 dxJointHinge::getInfo2( dxJoint::Info2 *info )
70 {
71 // set the three ball-and-socket rows
72 setBall( this, info, anchor1, anchor2 );
73
74 // set the two hinge rows. the hinge axis should be the only unconstrained
75 // rotational axis, the angular velocity of the two bodies perpendicular to
76 // the hinge axis should be equal. thus the constraint equations are
77 // p*w1 - p*w2 = 0
78 // q*w1 - q*w2 = 0
79 // where p and q are unit vectors normal to the hinge axis, and w1 and w2
80 // are the angular velocity vectors of the two bodies.
81
82 dVector3 ax1; // length 1 joint axis in global coordinates, from 1st body
83 dVector3 p, q; // plane space vectors for ax1
84 dMULTIPLY0_331( ax1, node[0].body->posr.R, axis1 );
85 dPlaneSpace( ax1, p, q );
86
87 int s3 = 3 * info->rowskip;
88 int s4 = 4 * info->rowskip;
89
90 info->J1a[s3+0] = p[0];
91 info->J1a[s3+1] = p[1];
92 info->J1a[s3+2] = p[2];
93 info->J1a[s4+0] = q[0];
94 info->J1a[s4+1] = q[1];
95 info->J1a[s4+2] = q[2];
96
97 if ( node[1].body )
98 {
99 info->J2a[s3+0] = -p[0];
100 info->J2a[s3+1] = -p[1];
101 info->J2a[s3+2] = -p[2];
102 info->J2a[s4+0] = -q[0];
103 info->J2a[s4+1] = -q[1];
104 info->J2a[s4+2] = -q[2];
105 }
106
107 // compute the right hand side of the constraint equation. set relative
108 // body velocities along p and q to bring the hinge back into alignment.
109 // if ax1,ax2 are the unit length hinge axes as computed from body1 and
110 // body2, we need to rotate both bodies along the axis u = (ax1 x ax2).
111 // if `theta' is the angle between ax1 and ax2, we need an angular velocity
112 // along u to cover angle erp*theta in one step :
113 // |angular_velocity| = angle/time = erp*theta / stepsize
114 // = (erp*fps) * theta
115 // angular_velocity = |angular_velocity| * (ax1 x ax2) / |ax1 x ax2|
116 // = (erp*fps) * theta * (ax1 x ax2) / sin(theta)
117 // ...as ax1 and ax2 are unit length. if theta is smallish,
118 // theta ~= sin(theta), so
119 // angular_velocity = (erp*fps) * (ax1 x ax2)
120 // ax1 x ax2 is in the plane space of ax1, so we project the angular
121 // velocity to p and q to find the right hand side.
122
123 dVector3 ax2, b;
124 if ( node[1].body )
125 {
126 dMULTIPLY0_331( ax2, node[1].body->posr.R, axis2 );
127 }
128 else
129 {
130 ax2[0] = axis2[0];
131 ax2[1] = axis2[1];
132 ax2[2] = axis2[2];
133 }
134 dCROSS( b, = , ax1, ax2 );
135 dReal k = info->fps * info->erp;
136 info->c[3] = k * dDOT( b, p );
137 info->c[4] = k * dDOT( b, q );
138
139 // if the hinge is powered, or has joint limits, add in the stuff
140 limot.addLimot( this, info, 5, ax1, 1 );
141 }
142
143
144
dJointSetHingeAnchor(dJointID j,dReal x,dReal y,dReal z)145 void dJointSetHingeAnchor( dJointID j, dReal x, dReal y, dReal z )
146 {
147 dxJointHinge* joint = ( dxJointHinge* )j;
148 dUASSERT( joint, "bad joint argument" );
149 checktype( joint, Hinge );
150 setAnchors( joint, x, y, z, joint->anchor1, joint->anchor2 );
151 joint->computeInitialRelativeRotation();
152 }
153
154
dJointSetHingeAnchorDelta(dJointID j,dReal x,dReal y,dReal z,dReal dx,dReal dy,dReal dz)155 void dJointSetHingeAnchorDelta( dJointID j, dReal x, dReal y, dReal z, dReal dx, dReal dy, dReal dz )
156 {
157 dxJointHinge* joint = ( dxJointHinge* )j;
158 dUASSERT( joint, "bad joint argument" );
159 checktype( joint, Hinge );
160
161 if ( joint->node[0].body )
162 {
163 dReal q[4];
164 q[0] = x - joint->node[0].body->posr.pos[0];
165 q[1] = y - joint->node[0].body->posr.pos[1];
166 q[2] = z - joint->node[0].body->posr.pos[2];
167 q[3] = 0;
168 dMULTIPLY1_331( joint->anchor1, joint->node[0].body->posr.R, q );
169
170 if ( joint->node[1].body )
171 {
172 q[0] = x - joint->node[1].body->posr.pos[0];
173 q[1] = y - joint->node[1].body->posr.pos[1];
174 q[2] = z - joint->node[1].body->posr.pos[2];
175 q[3] = 0;
176 dMULTIPLY1_331( joint->anchor2, joint->node[1].body->posr.R, q );
177 }
178 else
179 {
180 // Move the relative displacement between the passive body and the
181 // anchor in the same direction as the passive body has just moved
182 joint->anchor2[0] = x + dx;
183 joint->anchor2[1] = y + dy;
184 joint->anchor2[2] = z + dz;
185 }
186 }
187 joint->anchor1[3] = 0;
188 joint->anchor2[3] = 0;
189
190 joint->computeInitialRelativeRotation();
191 }
192
193
194
dJointSetHingeAxis(dJointID j,dReal x,dReal y,dReal z)195 void dJointSetHingeAxis( dJointID j, dReal x, dReal y, dReal z )
196 {
197 dxJointHinge* joint = ( dxJointHinge* )j;
198 dUASSERT( joint, "bad joint argument" );
199 checktype( joint, Hinge );
200 setAxes( joint, x, y, z, joint->axis1, joint->axis2 );
201 joint->computeInitialRelativeRotation();
202 }
203
204
dJointSetHingeAxisOffset(dJointID j,dReal x,dReal y,dReal z,dReal dangle)205 void dJointSetHingeAxisOffset( dJointID j, dReal x, dReal y, dReal z, dReal dangle )
206 {
207 dxJointHinge* joint = ( dxJointHinge* )j;
208 dUASSERT( joint, "bad joint argument" );
209 checktype( joint, Hinge );
210 setAxes( joint, x, y, z, joint->axis1, joint->axis2 );
211 joint->computeInitialRelativeRotation();
212
213 if ( joint->flags & dJOINT_REVERSE ) dangle = -dangle;
214
215 dQuaternion qAngle, qOffset;
216 dQFromAxisAndAngle(qAngle, x, y, z, dangle);
217 dQMultiply3(qOffset, qAngle, joint->qrel);
218 joint->qrel[0] = qOffset[0];
219 joint->qrel[1] = qOffset[1];
220 joint->qrel[2] = qOffset[2];
221 joint->qrel[3] = qOffset[3];
222 }
223
224
225
dJointGetHingeAnchor(dJointID j,dVector3 result)226 void dJointGetHingeAnchor( dJointID j, dVector3 result )
227 {
228 dxJointHinge* joint = ( dxJointHinge* )j;
229 dUASSERT( joint, "bad joint argument" );
230 dUASSERT( result, "bad result argument" );
231 checktype( joint, Hinge );
232 if ( joint->flags & dJOINT_REVERSE )
233 getAnchor2( joint, result, joint->anchor2 );
234 else
235 getAnchor( joint, result, joint->anchor1 );
236 }
237
238
dJointGetHingeAnchor2(dJointID j,dVector3 result)239 void dJointGetHingeAnchor2( dJointID j, dVector3 result )
240 {
241 dxJointHinge* joint = ( dxJointHinge* )j;
242 dUASSERT( joint, "bad joint argument" );
243 dUASSERT( result, "bad result argument" );
244 checktype( joint, Hinge );
245 if ( joint->flags & dJOINT_REVERSE )
246 getAnchor( joint, result, joint->anchor1 );
247 else
248 getAnchor2( joint, result, joint->anchor2 );
249 }
250
251
dJointGetHingeAxis(dJointID j,dVector3 result)252 void dJointGetHingeAxis( dJointID j, dVector3 result )
253 {
254 dxJointHinge* joint = ( dxJointHinge* )j;
255 dUASSERT( joint, "bad joint argument" );
256 dUASSERT( result, "bad result argument" );
257 checktype( joint, Hinge );
258 getAxis( joint, result, joint->axis1 );
259 }
260
261
dJointSetHingeParam(dJointID j,int parameter,dReal value)262 void dJointSetHingeParam( dJointID j, int parameter, dReal value )
263 {
264 dxJointHinge* joint = ( dxJointHinge* )j;
265 dUASSERT( joint, "bad joint argument" );
266 checktype( joint, Hinge );
267 joint->limot.set( parameter, value );
268 }
269
270
dJointGetHingeParam(dJointID j,int parameter)271 dReal dJointGetHingeParam( dJointID j, int parameter )
272 {
273 dxJointHinge* joint = ( dxJointHinge* )j;
274 dUASSERT( joint, "bad joint argument" );
275 checktype( joint, Hinge );
276 return joint->limot.get( parameter );
277 }
278
279
dJointGetHingeAngle(dJointID j)280 dReal dJointGetHingeAngle( dJointID j )
281 {
282 dxJointHinge* joint = ( dxJointHinge* )j;
283 dAASSERT( joint );
284 checktype( joint, Hinge );
285 if ( joint->node[0].body )
286 {
287 dReal ang = getHingeAngle( joint->node[0].body,
288 joint->node[1].body,
289 joint->axis1,
290 joint->qrel );
291 if ( joint->flags & dJOINT_REVERSE )
292 return -ang;
293 else
294 return ang;
295 }
296 else return 0;
297 }
298
299
dJointGetHingeAngleRate(dJointID j)300 dReal dJointGetHingeAngleRate( dJointID j )
301 {
302 dxJointHinge* joint = ( dxJointHinge* )j;
303 dAASSERT( joint );
304 checktype( joint, Hinge );
305 if ( joint->node[0].body )
306 {
307 dVector3 axis;
308 dMULTIPLY0_331( axis, joint->node[0].body->posr.R, joint->axis1 );
309 dReal rate = dDOT( axis, joint->node[0].body->avel );
310 if ( joint->node[1].body ) rate -= dDOT( axis, joint->node[1].body->avel );
311 if ( joint->flags & dJOINT_REVERSE ) rate = - rate;
312 return rate;
313 }
314 else return 0;
315 }
316
317
dJointAddHingeTorque(dJointID j,dReal torque)318 void dJointAddHingeTorque( dJointID j, dReal torque )
319 {
320 dxJointHinge* joint = ( dxJointHinge* )j;
321 dVector3 axis;
322 dAASSERT( joint );
323 checktype( joint, Hinge );
324
325 if ( joint->flags & dJOINT_REVERSE )
326 torque = -torque;
327
328 getAxis( joint, axis, joint->axis1 );
329 axis[0] *= torque;
330 axis[1] *= torque;
331 axis[2] *= torque;
332
333 if ( joint->node[0].body != 0 )
334 dBodyAddTorque( joint->node[0].body, axis[0], axis[1], axis[2] );
335 if ( joint->node[1].body != 0 )
336 dBodyAddTorque( joint->node[1].body, -axis[0], -axis[1], -axis[2] );
337 }
338
339
340 dJointType
type() const341 dxJointHinge::type() const
342 {
343 return dJointTypeHinge;
344 }
345
346
347
348 size_t
size() const349 dxJointHinge::size() const
350 {
351 return sizeof( *this );
352 }
353
354
355 void
setRelativeValues()356 dxJointHinge::setRelativeValues()
357 {
358 dVector3 vec;
359 dJointGetHingeAnchor(this, vec);
360 setAnchors( this, vec[0], vec[1], vec[2], anchor1, anchor2 );
361
362 dJointGetHingeAxis(this, vec);
363 setAxes( this, vec[0], vec[1], vec[2], axis1, axis2 );
364 computeInitialRelativeRotation();
365 }
366
367
368 /// Compute initial relative rotation body1 -> body2, or env -> body1
369 void
computeInitialRelativeRotation()370 dxJointHinge::computeInitialRelativeRotation()
371 {
372 if ( node[0].body )
373 {
374 if ( node[1].body )
375 {
376 dQMultiply1( qrel, node[0].body->q, node[1].body->q );
377 }
378 else
379 {
380 // set qrel to the transpose of the first body q
381 qrel[0] = node[0].body->q[0];
382 qrel[1] = -node[0].body->q[1];
383 qrel[2] = -node[0].body->q[2];
384 qrel[3] = -node[0].body->q[3];
385 }
386 }
387 }
388
389