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