All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.jbox2d.dynamics.joints.MouseJoint Maven / Gradle / Ivy

The newest version!
/*
 * The MIT License (MIT)
 *
 * FXGL - JavaFX Game Library
 *
 * Copyright (c) 2015-2017 AlmasB ([email protected])
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */
package org.jbox2d.dynamics.joints;

import com.almasb.fxgl.core.math.Vec2;
import org.jbox2d.common.*;
import org.jbox2d.dynamics.SolverData;
import org.jbox2d.pooling.IWorldPool;

/**
 * A mouse joint is used to make a point on a body track a specified world point. This a soft
 * constraint with a maximum force. This allows the constraint to stretch and without applying huge
 * forces. NOTE: this joint is not documented in the manual because it was developed to be used in
 * the testbed. If you want to learn how to use the mouse joint, look at the testbed.
 *
 * @author Daniel
 */
public class MouseJoint extends Joint {

    private final Vec2 m_localAnchorB = new Vec2();
    private final Vec2 m_targetA = new Vec2();
    private float m_frequencyHz;
    private float m_dampingRatio;
    private float m_beta;

    // Solver shared
    private final Vec2 m_impulse = new Vec2();
    private float m_maxForce;
    private float m_gamma;

    // Solver temp
    private int m_indexB;
    private final Vec2 m_rB = new Vec2();
    private final Vec2 m_localCenterB = new Vec2();
    private float m_invMassB;
    private float m_invIB;
    private final Mat22 m_mass = new Mat22();
    private final Vec2 m_C = new Vec2();

    protected MouseJoint(IWorldPool argWorld, MouseJointDef def) {
        super(argWorld, def);
        assert (def.target.isValid());
        assert (def.maxForce >= 0);
        assert (def.frequencyHz >= 0);
        assert (def.dampingRatio >= 0);

        m_targetA.set(def.target);
        Transform.mulTransToOutUnsafe(m_bodyB.getTransform(), m_targetA, m_localAnchorB);

        m_maxForce = def.maxForce;
        m_impulse.setZero();

        m_frequencyHz = def.frequencyHz;
        m_dampingRatio = def.dampingRatio;

        m_beta = 0;
        m_gamma = 0;
    }

    @Override
    public void getAnchorA(Vec2 argOut) {
        argOut.set(m_targetA);
    }

    @Override
    public void getAnchorB(Vec2 argOut) {
        m_bodyB.getWorldPointToOut(m_localAnchorB, argOut);
    }

    @Override
    public void getReactionForce(float invDt, Vec2 argOut) {
        argOut.set(m_impulse).mulLocal(invDt);
    }

    @Override
    public float getReactionTorque(float invDt) {
        return invDt * 0.0f;
    }


    public void setTarget(Vec2 target) {
        if (m_bodyB.isAwake() == false) {
            m_bodyB.setAwake(true);
        }
        m_targetA.set(target);
    }

    public Vec2 getTarget() {
        return m_targetA;
    }

    // / set/get the maximum force in Newtons.
    public void setMaxForce(float force) {
        m_maxForce = force;
    }

    public float getMaxForce() {
        return m_maxForce;
    }

    // / set/get the frequency in Hertz.
    public void setFrequency(float hz) {
        m_frequencyHz = hz;
    }

    public float getFrequency() {
        return m_frequencyHz;
    }

    // / set/get the damping ratio (dimensionless).
    public void setDampingRatio(float ratio) {
        m_dampingRatio = ratio;
    }

    public float getDampingRatio() {
        return m_dampingRatio;
    }

    @Override
    public void initVelocityConstraints(final SolverData data) {
        m_indexB = m_bodyB.m_islandIndex;
        m_localCenterB.set(m_bodyB.m_sweep.localCenter);
        m_invMassB = m_bodyB.m_invMass;
        m_invIB = m_bodyB.m_invI;

        Vec2 cB = data.positions[m_indexB].c;
        float aB = data.positions[m_indexB].a;
        Vec2 vB = data.velocities[m_indexB].v;
        float wB = data.velocities[m_indexB].w;

        final Rotation qB = pool.popRot();

        qB.set(aB);

        float mass = m_bodyB.getMass();

        // Frequency
        float omega = 2.0f * JBoxUtils.PI * m_frequencyHz;

        // Damping coefficient
        float d = 2.0f * mass * m_dampingRatio * omega;

        // Spring stiffness
        float k = mass * (omega * omega);

        // magic formulas
        // gamma has units of inverse mass.
        // beta has units of inverse time.
        float h = data.step.dt;
        assert (d + h * k > JBoxSettings.EPSILON);
        m_gamma = h * (d + h * k);
        if (m_gamma != 0.0f) {
            m_gamma = 1.0f / m_gamma;
        }
        m_beta = h * k * m_gamma;

        Vec2 temp = pool.popVec2();

        // Compute the effective mass matrix.
        Rotation.mulToOutUnsafe(qB, temp.set(m_localAnchorB).subLocal(m_localCenterB), m_rB);

        // K = [(1/m1 + 1/m2) * eye(2) - skew(r1) * invI1 * skew(r1) - skew(r2) * invI2 * skew(r2)]
        // = [1/m1+1/m2 0 ] + invI1 * [r1.y*r1.y -r1.x*r1.y] + invI2 * [r1.y*r1.y -r1.x*r1.y]
        // [ 0 1/m1+1/m2] [-r1.x*r1.y r1.x*r1.x] [-r1.x*r1.y r1.x*r1.x]
        final Mat22 K = pool.popMat22();
        K.ex.x = m_invMassB + m_invIB * m_rB.y * m_rB.y + m_gamma;
        K.ex.y = -m_invIB * m_rB.x * m_rB.y;
        K.ey.x = K.ex.y;
        K.ey.y = m_invMassB + m_invIB * m_rB.x * m_rB.x + m_gamma;

        K.invertToOut(m_mass);

        m_C.set(cB).addLocal(m_rB).subLocal(m_targetA);
        m_C.mulLocal(m_beta);

        // Cheat with some damping
        wB *= 0.98f;

        if (data.step.warmStarting) {
            m_impulse.mulLocal(data.step.dtRatio);
            vB.x += m_invMassB * m_impulse.x;
            vB.y += m_invMassB * m_impulse.y;
            wB += m_invIB * Vec2.cross(m_rB, m_impulse);
        } else {
            m_impulse.setZero();
        }

//    data.velocities[m_indexB].v.set(vB);
        data.velocities[m_indexB].w = wB;

        pool.pushVec2(1);
        pool.pushMat22(1);
        pool.pushRot(1);
    }

    @Override
    public boolean solvePositionConstraints(final SolverData data) {
        return true;
    }

    @Override
    public void solveVelocityConstraints(final SolverData data) {

        Vec2 vB = data.velocities[m_indexB].v;
        float wB = data.velocities[m_indexB].w;

        // Cdot = v + cross(w, r)
        final Vec2 Cdot = pool.popVec2();
        Vec2.crossToOutUnsafe(wB, m_rB, Cdot);
        Cdot.addLocal(vB);

        final Vec2 impulse = pool.popVec2();
        final Vec2 temp = pool.popVec2();

        temp.set(m_impulse).mulLocal(m_gamma).addLocal(m_C).addLocal(Cdot).negateLocal();
        Mat22.mulToOutUnsafe(m_mass, temp, impulse);

        Vec2 oldImpulse = temp;
        oldImpulse.set(m_impulse);
        m_impulse.addLocal(impulse);
        float maxImpulse = data.step.dt * m_maxForce;
        if (m_impulse.lengthSquared() > maxImpulse * maxImpulse) {
            m_impulse.mulLocal(maxImpulse / m_impulse.length());
        }
        impulse.set(m_impulse).subLocal(oldImpulse);

        vB.x += m_invMassB * impulse.x;
        vB.y += m_invMassB * impulse.y;
        wB += m_invIB * Vec2.cross(m_rB, impulse);

//    data.velocities[m_indexB].v.set(vB);
        data.velocities[m_indexB].w = wB;

        pool.pushVec2(3);
    }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy