/* 
 | 
 * 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. 
 | 
 */ 
 | 
  
 | 
package com.bulletphysics.dynamics.constraintsolver; 
 | 
  
 | 
import com.bulletphysics.dynamics.RigidBody; 
 | 
import com.bulletphysics.linearmath.Transform; 
 | 
import com.bulletphysics.linearmath.VectorUtil; 
 | 
import cz.advel.stack.Stack; 
 | 
import javax.vecmath.Matrix3f; 
 | 
import javax.vecmath.Vector3f; 
 | 
  
 | 
/** 
 | 
 * Point to point constraint between two rigid bodies each with a pivot point that 
 | 
 * descibes the "ballsocket" location in local space. 
 | 
 *  
 | 
 * @author jezek2 
 | 
 */ 
 | 
public class Point2PointConstraint extends TypedConstraint { 
 | 
  
 | 
    private final JacobianEntry[] jac = new JacobianEntry[]/*[3]*/ { new JacobianEntry(), new JacobianEntry(), new JacobianEntry() }; // 3 orthogonal linear constraints 
 | 
     
 | 
    private final Vector3f pivotInA = new Vector3f(); 
 | 
    private final Vector3f pivotInB = new Vector3f(); 
 | 
  
 | 
    public ConstraintSetting setting = new ConstraintSetting(); 
 | 
     
 | 
    public Point2PointConstraint() { 
 | 
        super(TypedConstraintType.POINT2POINT_CONSTRAINT_TYPE); 
 | 
    } 
 | 
  
 | 
    public Point2PointConstraint(RigidBody rbA, RigidBody rbB, Vector3f pivotInA, Vector3f pivotInB) { 
 | 
        super(TypedConstraintType.POINT2POINT_CONSTRAINT_TYPE, rbA, rbB); 
 | 
        this.pivotInA.set(pivotInA); 
 | 
        this.pivotInB.set(pivotInB); 
 | 
    } 
 | 
  
 | 
    public Point2PointConstraint(RigidBody rbA, Vector3f pivotInA) { 
 | 
        super(TypedConstraintType.POINT2POINT_CONSTRAINT_TYPE, rbA); 
 | 
        this.pivotInA.set(pivotInA); 
 | 
        this.pivotInB.set(pivotInA); 
 | 
        rbA.getCenterOfMassTransform(Stack.alloc(Transform.class)).transform(this.pivotInB); 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public void buildJacobian() { 
 | 
        appliedImpulse = 0f; 
 | 
  
 | 
        Vector3f normal = Stack.alloc(Vector3f.class); 
 | 
        normal.set(0f, 0f, 0f); 
 | 
  
 | 
        Matrix3f tmpMat1 = Stack.alloc(Matrix3f.class); 
 | 
        Matrix3f tmpMat2 = Stack.alloc(Matrix3f.class); 
 | 
        Vector3f tmp1 = Stack.alloc(Vector3f.class); 
 | 
        Vector3f tmp2 = Stack.alloc(Vector3f.class); 
 | 
        Vector3f tmpVec = Stack.alloc(Vector3f.class); 
 | 
         
 | 
        Transform centerOfMassA = rbA.getCenterOfMassTransform(Stack.alloc(Transform.class)); 
 | 
        Transform centerOfMassB = rbB.getCenterOfMassTransform(Stack.alloc(Transform.class)); 
 | 
  
 | 
        for (int i = 0; i < 3; i++) { 
 | 
            VectorUtil.setCoord(normal, i, 1f); 
 | 
  
 | 
            tmpMat1.transpose(centerOfMassA.basis); 
 | 
            tmpMat2.transpose(centerOfMassB.basis); 
 | 
  
 | 
            tmp1.set(pivotInA); 
 | 
            centerOfMassA.transform(tmp1); 
 | 
            tmp1.sub(rbA.getCenterOfMassPosition(tmpVec)); 
 | 
  
 | 
            tmp2.set(pivotInB); 
 | 
            centerOfMassB.transform(tmp2); 
 | 
            tmp2.sub(rbB.getCenterOfMassPosition(tmpVec)); 
 | 
  
 | 
            jac[i].init( 
 | 
                    tmpMat1, 
 | 
                    tmpMat2, 
 | 
                    tmp1, 
 | 
                    tmp2, 
 | 
                    normal, 
 | 
                    rbA.getInvInertiaDiagLocal(Stack.alloc(Vector3f.class)), 
 | 
                    rbA.getInvMass(), 
 | 
                    rbB.getInvInertiaDiagLocal(Stack.alloc(Vector3f.class)), 
 | 
                    rbB.getInvMass()); 
 | 
            VectorUtil.setCoord(normal, i, 0f); 
 | 
        } 
 | 
    } 
 | 
  
 | 
    @Override 
 | 
    public void solveConstraint(float timeStep) { 
 | 
        Vector3f tmp = Stack.alloc(Vector3f.class); 
 | 
        Vector3f tmp2 = Stack.alloc(Vector3f.class); 
 | 
        Vector3f tmpVec = Stack.alloc(Vector3f.class); 
 | 
  
 | 
        Transform centerOfMassA = rbA.getCenterOfMassTransform(Stack.alloc(Transform.class)); 
 | 
        Transform centerOfMassB = rbB.getCenterOfMassTransform(Stack.alloc(Transform.class)); 
 | 
         
 | 
        Vector3f pivotAInW = (Vector3f) Stack.alloc(pivotInA); 
 | 
        centerOfMassA.transform(pivotAInW); 
 | 
  
 | 
        Vector3f pivotBInW = (Vector3f) Stack.alloc(pivotInB); 
 | 
        centerOfMassB.transform(pivotBInW); 
 | 
  
 | 
        Vector3f normal = Stack.alloc(Vector3f.class); 
 | 
        normal.set(0f, 0f, 0f); 
 | 
  
 | 
        //btVector3 angvelA = m_rbA.getCenterOfMassTransform().getBasis().transpose() * m_rbA.getAngularVelocity(); 
 | 
        //btVector3 angvelB = m_rbB.getCenterOfMassTransform().getBasis().transpose() * m_rbB.getAngularVelocity(); 
 | 
  
 | 
        for (int i = 0; i < 3; i++) { 
 | 
            VectorUtil.setCoord(normal, i, 1f); 
 | 
            float jacDiagABInv = 1f / jac[i].getDiagonal(); 
 | 
  
 | 
            Vector3f rel_pos1 = Stack.alloc(Vector3f.class); 
 | 
            rel_pos1.sub(pivotAInW, rbA.getCenterOfMassPosition(tmpVec)); 
 | 
            Vector3f rel_pos2 = Stack.alloc(Vector3f.class); 
 | 
            rel_pos2.sub(pivotBInW, rbB.getCenterOfMassPosition(tmpVec)); 
 | 
            // this jacobian entry could be re-used for all iterations 
 | 
  
 | 
            Vector3f vel1 = rbA.getVelocityInLocalPoint(rel_pos1, Stack.alloc(Vector3f.class)); 
 | 
            Vector3f vel2 = rbB.getVelocityInLocalPoint(rel_pos2, Stack.alloc(Vector3f.class)); 
 | 
            Vector3f vel = Stack.alloc(Vector3f.class); 
 | 
            vel.sub(vel1, vel2); 
 | 
  
 | 
            float rel_vel; 
 | 
            rel_vel = normal.dot(vel); 
 | 
  
 | 
            /* 
 | 
            //velocity error (first order error) 
 | 
            btScalar rel_vel = m_jac[i].getRelativeVelocity(m_rbA.getLinearVelocity(),angvelA, 
 | 
            m_rbB.getLinearVelocity(),angvelB); 
 | 
             */ 
 | 
  
 | 
            // positional error (zeroth order error) 
 | 
            tmp.sub(pivotAInW, pivotBInW); 
 | 
            float depth = -tmp.dot(normal); //this is the error projected on the normal 
 | 
  
 | 
            float impulse = depth * setting.tau / timeStep * jacDiagABInv - setting.damping * rel_vel * jacDiagABInv; 
 | 
  
 | 
            float impulseClamp = setting.impulseClamp; 
 | 
            if (impulseClamp > 0f) { 
 | 
                if (impulse < -impulseClamp) { 
 | 
                    impulse = -impulseClamp; 
 | 
                } 
 | 
                if (impulse > impulseClamp) { 
 | 
                    impulse = impulseClamp; 
 | 
                } 
 | 
            } 
 | 
  
 | 
            appliedImpulse += impulse; 
 | 
            Vector3f impulse_vector = Stack.alloc(Vector3f.class); 
 | 
            impulse_vector.scale(impulse, normal); 
 | 
            tmp.sub(pivotAInW, rbA.getCenterOfMassPosition(tmpVec)); 
 | 
            rbA.applyImpulse(impulse_vector, tmp); 
 | 
            tmp.negate(impulse_vector); 
 | 
            tmp2.sub(pivotBInW, rbB.getCenterOfMassPosition(tmpVec)); 
 | 
            rbB.applyImpulse(tmp, tmp2); 
 | 
  
 | 
            VectorUtil.setCoord(normal, i, 0f); 
 | 
        } 
 | 
    } 
 | 
     
 | 
    public void updateRHS(float timeStep) { 
 | 
    } 
 | 
  
 | 
    public void setPivotA(Vector3f pivotA) { 
 | 
        pivotInA.set(pivotA); 
 | 
    } 
 | 
  
 | 
    public void setPivotB(Vector3f pivotB) { 
 | 
        pivotInB.set(pivotB); 
 | 
    } 
 | 
  
 | 
    public Vector3f getPivotInA(Vector3f out) { 
 | 
        out.set(pivotInA); 
 | 
        return out; 
 | 
    } 
 | 
  
 | 
    public Vector3f getPivotInB(Vector3f out) { 
 | 
        out.set(pivotInB); 
 | 
        return out; 
 | 
    } 
 | 
     
 | 
    //////////////////////////////////////////////////////////////////////////// 
 | 
     
 | 
    public static class ConstraintSetting { 
 | 
        public float tau = 0.3f; 
 | 
        public float damping = 1f; 
 | 
        public float impulseClamp = 0f; 
 | 
    } 
 | 
     
 | 
} 
 |