/* 
 | 
 * Java port of Bullet (c) 2008 Martin Dvorak <jezek2@advel.cz> 
 | 
 * 
 | 
 * Bullet Continuous Collision Detection and Physics Library 
 | 
 * Copyright (c) 2003-2008 Erwin Coumans  http://www.bulletphysics.com/ 
 | 
 * 
 | 
 * This software is provided 'as-is', without any express or implied warranty. 
 | 
 * In no event will the authors be held liable for any damages arising from 
 | 
 * the use of this software. 
 | 
 *  
 | 
 * Permission is granted to anyone to use this software for any purpose,  
 | 
 * including commercial applications, and to alter it and redistribute it 
 | 
 * freely, subject to the following restrictions: 
 | 
 *  
 | 
 * 1. The origin of this software must not be misrepresented; you must not 
 | 
 *    claim that you wrote the original software. If you use this software 
 | 
 *    in a product, an acknowledgment in the product documentation would be 
 | 
 *    appreciated but is not required. 
 | 
 * 2. Altered source versions must be plainly marked as such, and must not be 
 | 
 *    misrepresented as being the original software. 
 | 
 * 3. This notice may not be removed or altered from any source distribution. 
 | 
 */ 
 | 
  
 | 
/* 
 | 
2007-09-09 
 | 
btGeneric6DofConstraint Refactored by Francisco Le�n 
 | 
email: projectileman@yahoo.com 
 | 
http://gimpact.sf.net 
 | 
*/ 
 | 
  
 | 
package com.bulletphysics.dynamics.constraintsolver; 
 | 
  
 | 
import com.bulletphysics.BulletGlobals; 
 | 
import com.bulletphysics.dynamics.RigidBody; 
 | 
import cz.advel.stack.Stack; 
 | 
import cz.advel.stack.StaticAlloc; 
 | 
import javax.vecmath.Vector3f; 
 | 
  
 | 
/** 
 | 
 * Rotation limit structure for generic joints. 
 | 
 *  
 | 
 * @author jezek2 
 | 
 */ 
 | 
public class RotationalLimitMotor  implements java.io.Serializable { 
 | 
     
 | 
    //protected final BulletStack stack = BulletStack.get(); 
 | 
  
 | 
    public float loLimit; //!< joint limit 
 | 
    public float hiLimit; //!< joint limit 
 | 
    public float targetVelocity; //!< target motor velocity 
 | 
    public float maxMotorForce; //!< max force on motor 
 | 
    public float maxLimitForce; //!< max force on limit 
 | 
    public float damping; //!< Damping. 
 | 
    public float limitSoftness; //! Relaxation factor 
 | 
    public float ERP; //!< Error tolerance factor when joint is at limit 
 | 
    public float bounce; //!< restitution factor 
 | 
    public boolean enableMotor; 
 | 
     
 | 
    public float currentLimitError;//!  How much is violated this limit 
 | 
    public int currentLimit;//!< 0=free, 1=at lo limit, 2=at hi limit 
 | 
    public float accumulatedImpulse; 
 | 
  
 | 
    public RotationalLimitMotor() { 
 | 
        accumulatedImpulse = 0.f; 
 | 
        targetVelocity = 0; 
 | 
        maxMotorForce = 0.1f; 
 | 
        maxLimitForce = 300.0f; 
 | 
        loLimit = -BulletGlobals.SIMD_INFINITY; 
 | 
        hiLimit = BulletGlobals.SIMD_INFINITY; 
 | 
        ERP = 0.5f; 
 | 
        bounce = 0.0f; 
 | 
        damping = 1.0f; 
 | 
        limitSoftness = 0.5f; 
 | 
        currentLimit = 0; 
 | 
        currentLimitError = 0; 
 | 
        enableMotor = false; 
 | 
    } 
 | 
     
 | 
    public RotationalLimitMotor(RotationalLimitMotor limot) { 
 | 
        targetVelocity = limot.targetVelocity; 
 | 
        maxMotorForce = limot.maxMotorForce; 
 | 
        limitSoftness = limot.limitSoftness; 
 | 
        loLimit = limot.loLimit; 
 | 
        hiLimit = limot.hiLimit; 
 | 
        ERP = limot.ERP; 
 | 
        bounce = limot.bounce; 
 | 
        currentLimit = limot.currentLimit; 
 | 
        currentLimitError = limot.currentLimitError; 
 | 
        enableMotor = limot.enableMotor; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * Is limited? 
 | 
     */ 
 | 
    public boolean isLimited() 
 | 
    { 
 | 
        if(loLimit>=hiLimit) return false; 
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * Need apply correction? 
 | 
     */ 
 | 
    public boolean needApplyTorques() 
 | 
    { 
 | 
        if(currentLimit == 0 && enableMotor == false) return false; 
 | 
        return true; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * Calculates error. Calculates currentLimit and currentLimitError. 
 | 
     */ 
 | 
    public int testLimitValue(float test_value) { 
 | 
        if (loLimit > hiLimit) { 
 | 
            currentLimit = 0; // Free from violation 
 | 
            return 0; 
 | 
        } 
 | 
  
 | 
        if (test_value < loLimit) { 
 | 
            currentLimit = 1; // low limit violation 
 | 
            currentLimitError = test_value - loLimit; 
 | 
            return 1; 
 | 
        } 
 | 
        else if (test_value > hiLimit) { 
 | 
            currentLimit = 2; // High limit violation 
 | 
            currentLimitError = test_value - hiLimit; 
 | 
            return 2; 
 | 
        } 
 | 
  
 | 
        currentLimit = 0; // Free from violation 
 | 
        return 0; 
 | 
    } 
 | 
  
 | 
    /** 
 | 
     * Apply the correction impulses for two bodies. 
 | 
     */ 
 | 
    @StaticAlloc 
 | 
    public float solveAngularLimits(float timeStep, Vector3f axis, float jacDiagABInv, RigidBody body0, RigidBody body1) { 
 | 
        if (needApplyTorques() == false) { 
 | 
            return 0.0f; 
 | 
        } 
 | 
  
 | 
        float target_velocity = this.targetVelocity; 
 | 
        float maxMotorForce = this.maxMotorForce; 
 | 
  
 | 
        // current error correction 
 | 
        if (currentLimit != 0) { 
 | 
            target_velocity = -ERP * currentLimitError / (timeStep); 
 | 
            maxMotorForce = maxLimitForce; 
 | 
        } 
 | 
  
 | 
        maxMotorForce *= timeStep; 
 | 
  
 | 
        // current velocity difference 
 | 
        Vector3f vel_diff = body0.getAngularVelocity(Stack.alloc(Vector3f.class)); 
 | 
        if (body1 != null) { 
 | 
            vel_diff.sub(body1.getAngularVelocity(Stack.alloc(Vector3f.class))); 
 | 
        } 
 | 
  
 | 
        float rel_vel = axis.dot(vel_diff); 
 | 
  
 | 
        // correction velocity 
 | 
        float motor_relvel = limitSoftness * (target_velocity - damping * rel_vel); 
 | 
  
 | 
        if (motor_relvel < BulletGlobals.FLT_EPSILON && motor_relvel > -BulletGlobals.FLT_EPSILON) { 
 | 
            return 0.0f; // no need for applying force 
 | 
        } 
 | 
  
 | 
        // correction impulse 
 | 
        float unclippedMotorImpulse = (1 + bounce) * motor_relvel * jacDiagABInv; 
 | 
  
 | 
        // clip correction impulse 
 | 
        float clippedMotorImpulse; 
 | 
  
 | 
        // todo: should clip against accumulated impulse 
 | 
        if (unclippedMotorImpulse > 0.0f) { 
 | 
            clippedMotorImpulse = unclippedMotorImpulse > maxMotorForce ? maxMotorForce : unclippedMotorImpulse; 
 | 
        } 
 | 
        else { 
 | 
            clippedMotorImpulse = unclippedMotorImpulse < -maxMotorForce ? -maxMotorForce : unclippedMotorImpulse; 
 | 
        } 
 | 
  
 | 
        // sort with accumulated impulses 
 | 
        float lo = -1e30f; 
 | 
        float hi = 1e30f; 
 | 
  
 | 
        float oldaccumImpulse = accumulatedImpulse; 
 | 
        float sum = oldaccumImpulse + clippedMotorImpulse; 
 | 
        accumulatedImpulse = sum > hi ? 0f : sum < lo ? 0f : sum; 
 | 
  
 | 
        clippedMotorImpulse = accumulatedImpulse - oldaccumImpulse; 
 | 
  
 | 
        Vector3f motorImp = Stack.alloc(Vector3f.class); 
 | 
        motorImp.scale(clippedMotorImpulse, axis); 
 | 
  
 | 
        body0.applyTorqueImpulse(motorImp); 
 | 
        if (body1 != null) { 
 | 
            motorImp.negate(); 
 | 
            body1.applyTorqueImpulse(motorImp); 
 | 
        } 
 | 
  
 | 
        return clippedMotorImpulse; 
 | 
    } 
 | 
     
 | 
} 
 |