OMKJoint.cpp

Go to the documentation of this file.
00001 /************************************************************************/
00002 /* This file is part of openMask(c) INRIA, CNRS, Universite de Rennes 1 */
00003 /* 1993-2002, thereinafter the Software                                 */
00004 /*                                                                      */
00005 /* The Software has been developped within the Siames Project.          */
00006 /* INRIA, the University of Rennes 1 and CNRS jointly hold intellectual */
00007 /* property rights                                                      */
00008 /*                                                                      */
00009 /* The Software has been registered with the Agence pour la Protection  */
00010 /* des Programmes (APP) under registration number                       */
00011 /* IDDN.FR.001.510008.00.S.P.2001.000.41200                             */
00012 /*                                                                      */
00013 /* This file may be distributed under the terms of the Q Public License */
00014 /* version 1.0 as defined by Trolltech AS of Norway and appearing in    */
00015 /* the file LICENSE.QPL included in the packaging of this file.         */
00016 /*                                                                      */
00017 /* Licensees holding valid specific licenses issued by INRIA, CNRS or   */
00018 /* Universite Rennes 1 for the software may use this file in            */
00019 /* acordance with that specific license                                 */
00020 /************************************************************************/
00021     
00022 #include "OMKJointExtension.h"
00023 #include "OMKJoint.h"
00024 #include "OMKExtensibleSimulatedObject.h"
00025 #include "OMKInteractorExtension.h"
00026 #include "OMKParametersAccessor.inl"
00027 #include "OMKInputNT.h"
00028 #include "OMKSessionPrm.h"
00029 #include "OMKTransformType.h"
00030 #include "Wm4Plane3.h"
00031 #include "Wm4IntrLine3Plane3.h"
00032 #include "Wm4IntrRay3Sphere3.h"
00033 
00034 namespace OMK  
00035 {
00036   namespace Iii 
00037   {
00038 //=================================================================
00039 // Joint
00040 //=================================================================
00041 
00042 REGISTER_JOINT_FACTORY( Joint, "Lock" ) ;
00043 
00044 //-----------------------------------------------------------------
00045 Joint::Joint( JointExtension* owner, const ConfigurationParameterDescriptor * node ) 
00046 : _jointOffset( OMK::Type::Transform::sk_identity ),
00047   _jointOffsetInverse( OMK::Type::Transform::sk_identity ),
00048   _objectOffset( OMK::Type::Transform::sk_identity ),
00049   _objectOffsetInverse( OMK::Type::Transform::sk_identity ),
00050   _owner( owner ),
00051   _objectPosition( owner->_objectPosition ),
00052   _referencePosition( &owner->_referencePosition ), 
00053   _jointPosition( &owner->_jointPosition )
00054 {
00055 }
00056 //-----------------------------------------------------------------
00057 Joint::~Joint()
00058 {
00059 }
00060 //-----------------------------------------------------------------
00061 void Joint::establishLink() 
00062 {
00063   // Must calculate the new offset between the reference position and the joint position
00064   // It is the current offset
00065   _jointOffset = product( _referencePosition->get().inverse(), _jointPosition->get() ) ;
00066   _jointOffset.updateFlags() ;
00067   
00068   // Must calculate the new offset between the joint position and the object position
00069   // It is the current offset
00070   _objectOffset = product( _jointPosition->get().inverse(), _objectPosition->get() ) ;
00071   _objectOffset.updateFlags() ;
00072   
00073   // Calculates the inverse transforms for optimisation
00074   _jointOffsetInverse = _jointOffset.inverse() ;
00075   _jointOffsetInverse.updateFlags() ;
00076   
00077   _objectOffsetInverse = _objectOffset.inverse() ;
00078   _objectOffsetInverse.updateFlags() ;
00079 }
00080 
00081 //-----------------------------------------------------------------
00082 void Joint::currentJointPosition() 
00083 {
00084   // calculates the new joint position
00085   _jointPosition->set( product( _referencePosition->get(), _jointOffset ) ) ;
00086 }
00087 //-----------------------------------------------------------------
00088 bool Joint::retroPropagation() 
00089 {
00090   // Calculates the optimal position of the reference position to retro-propagates
00091   _referencePosition->set( product( product( _objectPosition->get(), _objectOffsetInverse ), _jointOffsetInverse ) ) ;
00092   return true ;
00093 }
00094 //-----------------------------------------------------------------
00095 void Joint::currentObjectPosition() 
00096 {
00097   // calculates the new object position
00098   _objectPosition->set( product( _jointPosition->get(), _objectOffset ) ) ;
00099 }
00100 //-----------------------------------------------------------------
00101 
00102 //=================================================================
00103 // BallJoint
00104 //=================================================================
00105 REGISTER_JOINT_FACTORY( BallJoint, "Ball" ) ;
00106 
00107 //-----------------------------------------------------------------
00108 BallJoint::BallJoint( JointExtension* owner, const ConfigurationParameterDescriptor * node ) 
00109 : Joint( owner, node ),
00110   _newObjectPosition(),
00111   _alreadyKnow( false ),
00112   _radius( 0.0f )
00113 {
00114 }
00115 //-----------------------------------------------------------------
00116 BallJoint::~BallJoint()
00117 {
00118 }
00119 //-----------------------------------------------------------------
00120 void BallJoint::establishLink() 
00121 {
00122   Joint::establishLink() ;
00123   _radius = _objectOffset.getTranslate().Length() ;
00124   
00125     // stores the reference offset
00126   _refObjectOffset = _objectOffset ;
00127   _newObjectPosition = _objectPosition->get() ;
00128   _reset = true ;
00129 }
00130 //-----------------------------------------------------------------
00131 bool BallJoint::retroPropagation() 
00132 {
00133   if( _reset )
00134   {
00135     _previousPosition = _objectPosition->get().getTranslate() ;
00136     _reset = false ;
00137   }
00138   // Get the joint axis and perpendicular plane
00139   Wm4::Vector3f axis( _refObjectOffset.getTranslate() ) ;
00140   axis.Normalize() ;
00141   
00142   // the reference position according to the position of the joint and the reference offset
00143   OMK::Type::Transform refObjectPosition( product( _jointPosition->get(), _refObjectOffset ) ) ;
00144   
00145   // The reference orientation
00146   Wm4::Matrix3f refOrientation = _jointPosition->get().getRotate() ;
00147   // get the new orientation
00148   Wm4::Matrix3f newOrientation = _objectPosition->get().getRotate() * ( refObjectPosition.getRotate().Transpose() * refOrientation ) ;
00149   
00150   // Only the translation
00151   bool isConstraint = _objectPosition->get().getTranslate() != refObjectPosition.getTranslate() ;
00152   
00153   // The new object position
00154   // = the position of the joint
00155   // + the position along the axis
00156   _newObjectPosition.setTranslate( _jointPosition->get().getTranslate() + ( newOrientation * axis ) * _radius ) ;
00157   _newObjectPosition.setRotate( newOrientation ) ;
00158   _alreadyKnow = true ;
00159   // update the current object offset
00160   _objectOffset = product( _jointPosition->get().inverse(), _newObjectPosition ) ;
00161   _objectOffset.updateFlags() ;
00162   _objectOffsetInverse = _objectOffset.inverse() ;
00163   _objectOffsetInverse.updateFlags() ;
00164 
00165   if( isConstraint )
00166   {
00167     // Calculates the optimal position of the reference position to retro-propagates
00168     OMK::Type::Transform newJointPosition( _jointPosition->get().getTranslate() 
00169                                         + _objectPosition->get().getTranslate() 
00170                                         - _previousPosition,
00171                                           _jointPosition->get().getRotate() ) ;
00172     _referencePosition->set( product( newJointPosition, _jointOffsetInverse ) ) ;
00173     _reset = true ;
00174   }
00175 
00176   return isConstraint ;
00177 }
00178 //-----------------------------------------------------------------
00179 void BallJoint::currentObjectPosition() 
00180 {
00181   if( _alreadyKnow )
00182   {
00183     _alreadyKnow = false ;
00184     _objectPosition->set( _newObjectPosition ) ;
00185   }
00186   else
00187   {
00188     // calculates the new object position
00189     _objectPosition->set( product( _jointPosition->get(), _objectOffset ) ) ;
00190   }
00191 }
00192 
00193 
00194 //=================================================================
00195 // HingeSlideJoint
00196 //=================================================================
00197 REGISTER_JOINT_FACTORY( HingeSlideJoint, "Hinge" ) ;
00198 
00199 //-----------------------------------------------------------------
00200 HingeSlideJoint::HingeSlideJoint( JointExtension* owner, const ConfigurationParameterDescriptor * node ) 
00201 : Joint( owner, node ),
00202   _newObjectPosition(),
00203   _refObjectOffset(),
00204   _alreadyKnow( false ),
00205   _radius( 0.0f ),
00206   _refSlide( 0.0f ),
00207   _minSlide( 0.0f ),
00208   _maxSlide( 0.0f ),
00209   _minSlideEnable( false ),
00210   _maxSlideEnable( false ),
00211   _minAngle( 0.0f ),
00212   _maxAngle( 0.0f ),
00213   _angleEnable( false ),
00214   _rotateOnly( false ),
00215   _ignoreTranslate( false )
00216                              
00217 {
00218   _minSlideEnable = ParametersAccessor::get( node, "MinSlide", _minSlide ) ;
00219   _maxSlideEnable = ParametersAccessor::get( node, "MaxSlide", _maxSlide ) ;
00220   _angleEnable = ParametersAccessor::get( node, "MinAngle", _minAngle ) 
00221       && ParametersAccessor::get( node, "MaxAngle", _maxAngle ) ;
00222   ParametersAccessor::get( node, "RotateOnly", _rotateOnly ) ;
00223 }
00224 //-----------------------------------------------------------------
00225 HingeSlideJoint::~HingeSlideJoint()
00226 {
00227 }
00228 //-----------------------------------------------------------------
00229 void HingeSlideJoint::establishLink() 
00230 {
00231   Joint::establishLink() ;
00232   // Get the joint plane
00233   Wm4::Vector3f axis( _jointPosition->get().getUp() ) ;
00234   axis.Normalize() ;
00235   Wm4::Plane3f plane( axis, _jointPosition->get().getTranslate() ) ;
00236   // The reference slide position
00237     // projection of the current position over the plane perpendicular to the joint axis
00238     Wm4::IntrLine3Plane3f objectOnPlane( Wm4::Line3f( _objectPosition->get().getTranslate(), axis ), plane ) ;
00239     objectOnPlane.Find() ;
00240     // to get the reference slide position
00241     _refSlide = objectOnPlane.GetLineT() ;
00242     // to get the radius on the plane
00243     Wm4::Vector3f projection( _objectPosition->get().getTranslate() + _refSlide * axis ) ;
00244     Wm4::Vector3f radiusVector( projection - _jointPosition->get().getTranslate() ) ;
00245     _radius = radiusVector.Length() ;
00246     _ignoreTranslate = ( _radius < Wm4::Math<float>::ZERO_TOLERANCE ) || _rotateOnly ;
00247 
00248     // stores the reference offset
00249     _refObjectOffset = _objectOffset ;
00250 }
00251 //-----------------------------------------------------------------
00252 bool HingeSlideJoint::retroPropagation() 
00253 {
00254   // Get the joint axis and perpendicular plane
00255   Wm4::Vector3f axis( _jointPosition->get().getUp() ) ;
00256   axis.Normalize() ;
00257   Wm4::Plane3f plane( axis, _jointPosition->get().getTranslate() ) ;
00258   // the reference position according to the position of the joint and the reference offset
00259   OMK::Type::Transform refObjectPosition( product( _jointPosition->get(), _refObjectOffset ) ) ;
00260   float currentSlide = 0.0f ;
00261   Wm4::Vector3f refOrientation ;
00262   Wm4::Vector3f newOrientation ;
00263   
00264   if( _ignoreTranslate )
00265   { // The axis is on the object position, only rotate
00266     // get a reference position over the joint plane
00267     refOrientation = _jointPosition->get().getRight() ;
00268     // get the new orientation
00269     newOrientation = _objectPosition->get().getRotate() * ( refObjectPosition.getRotate().Transpose() * _jointPosition->get().getRight() ) ;
00270     
00271     // the new slide offset
00272     currentSlide = axis.Dot( _jointPosition->get().getTranslate() - _objectPosition->get().getTranslate() ) - _refSlide ;
00273     
00274   }
00275   else
00276   { // The axis is far of the object position, only translate
00277     
00278     // projection of the reference position over the joint plane
00279     Wm4::Vector3f refIntersection( refObjectPosition.getTranslate() + _refSlide * axis ) ;
00280     // reference orientation
00281     refOrientation = refIntersection - _jointPosition->get().getTranslate() ;
00282     refOrientation.Normalize() ;
00283     
00284     // projection of the current position over the joint plane
00285     Wm4::IntrLine3Plane3f objectOnPlane( Wm4::Line3f( _objectPosition->get().getTranslate(), axis ), plane ) ;
00286     objectOnPlane.Find() ;
00287     // the new slide offset
00288     float currentSlideOverThePlane = objectOnPlane.GetLineT() ;
00289     
00290     // The new orientation
00291     Wm4::Vector3f projection( _objectPosition->get().getTranslate() + currentSlideOverThePlane * axis ) ;
00292     newOrientation = projection - _jointPosition->get().getTranslate() ;
00293     newOrientation.Normalize() ;
00294     
00295     // the new slide offset
00296     currentSlide = currentSlideOverThePlane - _refSlide ;
00297   }  
00298   
00299   // Compute the angle between the reference and the new orientation
00300   float angle = Wm4::Math<float>::ACos( newOrientation.Dot( refOrientation ) ) 
00301       * ( axis.Dot( newOrientation.Cross( refOrientation ) ) < 0.0f ? 1.0f : -1.0f ) ;
00302   
00303   Wm4::Matrix3f overRotationMatrix( Wm4::Matrix3f::IDENTITY ) ;
00304   float overSlide = 0.0f ;
00305   bool isConstraint = computeConstraints( angle, currentSlide, 
00306                                           overRotationMatrix, overSlide, newOrientation, 
00307                                           refOrientation, axis ) ; 
00308   
00309   // The new object position
00310   // = the position of the joint
00311   // + the position on the plane of the joint
00312   // + the position along the axis
00313   _newObjectPosition.setTranslate( _jointPosition->get().getTranslate() + newOrientation * _radius - ( _refSlide + currentSlide ) * axis ) ;
00314   // the rotation of the object compared to the position of reference
00315   Wm4::Matrix3f rotationMatrix( axis, angle ) ;
00316   _newObjectPosition.setRotate( rotationMatrix * refObjectPosition.getRotate() ) ;
00317   _alreadyKnow = true ;
00318   // update the current object offset
00319   _objectOffset = product( _jointPosition->get().inverse(), _newObjectPosition ) ;
00320   _objectOffset.updateFlags() ;
00321   _objectOffsetInverse = _objectOffset.inverse() ;
00322   _objectOffsetInverse.updateFlags() ;
00323 
00324   if( isConstraint )
00325   {
00326     // Calculates the optimal position of the reference position to retro-propagates
00327     OMK::Type::Transform newJointPosition( _jointPosition->get().getTranslate() - overSlide * axis, overRotationMatrix * _jointPosition->get().getRotate() ) ;
00328     _referencePosition->set( product( newJointPosition, _jointOffsetInverse ) ) ;
00329   }
00330 
00331   return isConstraint ;
00332 }
00333 //-----------------------------------------------------------------
00334 bool HingeSlideJoint::computeConstraints( float& angle, float& currentSlide,
00335                                      Wm4::Matrix3f& overRotationMatrix, float& overSlide, 
00336                                      Wm4::Vector3f& newOrientation, 
00337                                      const Wm4::Vector3f& refOrientation, const Wm4::Vector3f& axis ) 
00338 {
00339   bool isConstraint = false ; 
00340   overRotationMatrix.MakeIdentity() ;
00341   overSlide = 0.0f ;
00342   // Compute the constraint
00343   if( _angleEnable )
00344   {
00345     if( angle < _minAngle )
00346     {
00347       overRotationMatrix.FromAxisAngle( axis, angle - _minAngle ) ;
00348       angle = _minAngle ;
00349       isConstraint = true ;
00350     }
00351     else if( _maxAngle < angle )
00352     {
00353       overRotationMatrix.FromAxisAngle( axis, angle - _maxAngle ) ;
00354       angle = _maxAngle ;
00355       isConstraint = true ;
00356     }
00357     if( isConstraint )
00358     {
00359       newOrientation = Wm4::Matrix3f( axis, angle ) * refOrientation ;
00360     }
00361   }
00362     
00363   // Compute the constraint
00364   if( _minSlideEnable && ( currentSlide < _minSlide ) )
00365   {
00366     overSlide = currentSlide - _minSlide ;
00367     currentSlide = _minSlide ;
00368     isConstraint = true ;
00369   }
00370   else if( _maxSlideEnable && ( _maxSlide < currentSlide ) )
00371   {
00372     overSlide = currentSlide - _maxSlide ;
00373     currentSlide = _maxSlide ;
00374     isConstraint = true ;
00375   }
00376   return isConstraint ;
00377 }
00378 //-----------------------------------------------------------------
00379 void HingeSlideJoint::currentObjectPosition() 
00380 {
00381   if( _alreadyKnow )
00382   {
00383     _alreadyKnow = false ;
00384     _objectPosition->set( _newObjectPosition ) ;
00385   }
00386   else
00387   {
00388     // calculates the new object position
00389     _objectPosition->set( product( _jointPosition->get(), _objectOffset ) ) ;
00390   }
00391 }
00392 
00393 
00394 
00395 //=================================================================
00396 // ScrewJoint
00397 //=================================================================
00398 REGISTER_JOINT_FACTORY( ScrewJoint, "Screw" ) ;
00399 
00400 //-----------------------------------------------------------------
00401 ScrewJoint::ScrewJoint( JointExtension* owner, const ConfigurationParameterDescriptor * node ) 
00402 : HingeSlideJoint( owner, node ),
00403   _pitch( 0.0f ),
00404   _reverse( false ),
00405   _state( NOSCREW ),
00406   _stateMin( NOSCREW ),
00407   _stateMax( NOSCREW ),
00408   _previousAngle( 0.0f ),
00409   _turns( 0.0f )
00410 {
00411   ParametersAccessor::get( node, "Pitch", _pitch ) ;
00412   _stateMin = ( 0.0f < _pitch ) ? UNSCREW : SCREW ;
00413   _stateMax = ( 0.0f < _pitch ) ? SCREW : UNSCREW ;
00414   OMASSERTM( _pitch != 0.0f, "The screw pitch cannot be null" ) ;
00415   ParametersAccessor::get( node, "Reverse", _reverse ) ;
00416   _angleEnable = false ;
00417 }
00418 //-----------------------------------------------------------------
00419 ScrewJoint::~ScrewJoint()
00420 {
00421 }
00422 //-----------------------------------------------------------------
00423 void ScrewJoint::establishLink() 
00424 {
00425   _turns = 0.0f ;
00426   _previousAngle = 0.0f ;
00427   _state = NOSCREW ;
00428   HingeSlideJoint::establishLink() ;
00429   _previousOrientation = _jointPosition->get().getRight() ;
00430 }
00431 //-----------------------------------------------------------------
00432 bool ScrewJoint::computeConstraints( float& angle, float& currentSlide,
00433                                      Wm4::Matrix3f& overRotationMatrix, float& overSlide, 
00434                                      Wm4::Vector3f& newOrientation, 
00435                                      const Wm4::Vector3f& refOrientation, const Wm4::Vector3f& axis ) 
00436 {
00437   overRotationMatrix.MakeIdentity() ;
00438   overSlide = 0.0f ;
00439   bool isConstraint = false ;
00440   if( _reverse )
00441   { // angle is a function of the slide
00442     // Compute the constraint
00443     if( _minSlideEnable && ( currentSlide < _minSlide ) )
00444     {
00445       overSlide = currentSlide - _minSlide ;
00446       currentSlide = _minSlide ;
00447       isConstraint = true ;
00448     }
00449     else if( _maxSlideEnable && ( _maxSlide < currentSlide ) )
00450     {
00451       overSlide = currentSlide - _maxSlide ;
00452       currentSlide = _maxSlide ;
00453       isConstraint = true ;
00454     }
00455     // The angle is only a function of the slide offset
00456     angle = currentSlide / _pitch * -Wm4::Math<float>::TWO_PI ;
00457     newOrientation = Wm4::Matrix3f( axis, angle ) * refOrientation ;
00458   }
00459   else
00460   { // slide is a function of the angle
00461      // Computes the angle between the previous and the new orientation to determine if it screws or unscrews
00462     float screw = axis.Dot( newOrientation.Cross( _previousOrientation ) ) ;
00463     switch( _state )
00464     {
00465       case NOSCREW :
00466         if( Wm4::Math<float>::ZERO_TOLERANCE < screw ) _state = SCREW ;
00467         else if( screw < -Wm4::Math<float>::ZERO_TOLERANCE ) _state = UNSCREW ;
00468         // Calculates the slide
00469         currentSlide = ( _turns + angle * -Wm4::Math<float>::INV_TWO_PI ) * _pitch ;
00470         break ;
00471       case SCREW :
00472       case UNSCREW :
00473         if( Wm4::Math<float>::ZERO_TOLERANCE < screw )
00474         {
00475           _state = SCREW ;
00476           if( _previousAngle < angle ) _turns += 1.0f ;
00477         }
00478         else if( screw < -Wm4::Math<float>::ZERO_TOLERANCE )
00479         {
00480           _state = UNSCREW ;
00481           if( angle < _previousAngle ) _turns -= 1.0f ;
00482         }
00483         else _state = NOSCREW ;
00484         // Calculates the slide
00485         currentSlide = ( _turns + angle * -Wm4::Math<float>::INV_TWO_PI ) * _pitch ;
00486         // Applies the constraintes
00487         if( _state == _stateMin && _minSlideEnable && ( currentSlide < _minSlide ) )
00488         {
00489           _state = IS_MIN ;
00490           computeConstraintAngle( angle, _minSlide, newOrientation, refOrientation, axis ) ;
00491         }
00492         else if( _state == _stateMax && _maxSlideEnable && ( _maxSlide < currentSlide ) )
00493         {
00494           _state = IS_MAX ;
00495           computeConstraintAngle( angle, _maxSlide, newOrientation, refOrientation, axis ) ;
00496         }
00497         break ;
00498       case IS_MIN :
00499         {
00500           if( -Wm4::Math<float>::ZERO_TOLERANCE < screw ) _state = NOSCREW ;
00501           // The angle is only a function of the slide offset
00502           currentSlide = _minSlide ;
00503           overRotationMatrix.FromAxisAngle( axis, angle - computeConstraintAngle( angle, currentSlide, newOrientation, refOrientation, axis ) ) ;
00504           isConstraint = true ;
00505         }
00506         break ;    
00507       case IS_MAX :
00508         {
00509           if( screw < Wm4::Math<float>::ZERO_TOLERANCE) _state = NOSCREW ;
00510           // The angle is only a function of the slide offset
00511           currentSlide = _maxSlide ;
00512           overRotationMatrix.FromAxisAngle( axis, angle - computeConstraintAngle( angle, currentSlide, newOrientation, refOrientation, axis ) ) ;
00513           isConstraint = true ;
00514         }
00515         break ;    
00516     }
00517     // min and max slide saturation
00518     if( _minSlideEnable && ( currentSlide < _minSlide ) )
00519     {
00520       currentSlide = _minSlide ;
00521     }
00522     else if( _maxSlideEnable && ( _maxSlide < currentSlide ) )
00523     {
00524       currentSlide = _maxSlide ;
00525     }
00526     _turns = currentSlide / _pitch + angle * Wm4::Math<float>::INV_TWO_PI ;
00527     // Stores current values which will be the previous ones of the next step
00528     _previousAngle = angle ;
00529     _previousOrientation = newOrientation ;
00530   }
00531     
00532   return isConstraint ;
00533 }
00534 float ScrewJoint::computeConstraintAngle( float& angle, const float& currentSlide,
00535                                          Wm4::Vector3f& newOrientation, 
00536                                          const Wm4::Vector3f& refOrientation, const Wm4::Vector3f& axis ) 
00537 {
00538   float constraintAngle = currentSlide / _pitch * -Wm4::Math<float>::TWO_PI ;
00539   if( constraintAngle < 0.0f )
00540   {
00541     constraintAngle = Wm4::Math<float>::FMod( -constraintAngle + Wm4::Math<float>::TWO_PI + Wm4::Math<float>::PI, Wm4::Math<float>::TWO_PI ) - Wm4::Math<float>::PI ;
00542   }
00543   else
00544   {
00545     constraintAngle = Wm4::Math<float>::FMod( constraintAngle + Wm4::Math<float>::PI, Wm4::Math<float>::TWO_PI ) - Wm4::Math<float>::PI ;            
00546   }
00547   newOrientation = Wm4::Matrix3f( axis, constraintAngle ) * refOrientation ;
00548   angle = constraintAngle ;
00549   return constraintAngle ;
00550 }
00551 
00552   }// namespace Iii
00553 }// namespace OMK

logo OpenMask

Documentation generated on Mon Jun 9 11:45:56 2008

Generated with doxygen by Dimitri van Heesch ,   1997-2007