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

com.barrybecker4.simulation.snake.geometry.Edge Maven / Gradle / Ivy

/** Copyright by Barry G. Becker, 2000-2011. Licensed under MIT License: http://www.opensource.org/licenses/MIT  */
package com.barrybecker4.simulation.snake.geometry;

import javax.vecmath.Vector2d;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;

/**
 *  A snake edge (line geometry) is modeled as a spring to simulate muscles.
 *
 *  @author Barry Becker
 */
public class Edge {

    // the 2 endpoints defining the edge endpoints
    private Particle firstParticle_;
    private Particle secondParticle_;

    private Line2D.Double segment_ = null;

    /** constants related the the spring for this edge segment  */
    private static final double K = 0.8; // default  .6

    /** the damping coefficient */
    private static final double D = 1.2; // default

    /** the spring constant K (large K = stiffer) */
    private double k_;

    /** damping constant  */
    private double damping;

    /** the resting magnitude of the spring  */
    private double restingLength;

    /** usually the effectiveLength is the same as restingLength except when muscular contraction are happening  */
    private double effectiveLength;

    /** the current magnitude of the spring */
    private double length;

    /** these act like temporary variables for some calculations avoiding many object constructions */
    private final Vector2d direction = new Vector2d();
    private final Vector2d force = new Vector2d();
    private final Vector2d dampingVec = new Vector2d();

    /**
     * Constructor - assumes defaults for the spring constant and damping
     * @param p1 particle that anchors one end of the
     * @param p2 particle that anchors the other end of the edge
     */
    Edge( Particle p1, Particle p2 ) {
        commonInit( p1, p2, K, D );
    }

    public Particle getFirstParticle() {
        return firstParticle_;
    }

    public Particle getSecondParticle() {
        return secondParticle_;
    }

    public double getRestingLength() {
        return restingLength;
    }

    public double getLength() {
        return length;
    }


    private void commonInit( Particle p1, Particle p2, double k, double d ) {
        segment_ = new Line2D.Double( p1.x, p1.y, p2.x, p2.y );
        firstParticle_ = p1;
        secondParticle_ = p2;

        k_ = k;
        damping = d;
        restingLength = firstParticle_.distance( secondParticle_ );
        effectiveLength = restingLength;
        length = restingLength; // current magnitude
    }

    /**
     *  This method simulates the contraction or expansion of a muscle
     *  the rest magnitude restingLength is effectively changed by the contraction factor.
     *  @param contraction the amount that the spring model for the edge is contracting
     */
    public void setContraction( double contraction )  {
        if (contraction <= 0) {
            throw new IllegalArgumentException( "Error contraction <=0 = "+contraction );
            //contraction = EPS;
        }
        effectiveLength = contraction * restingLength;
    }

    /**
     * The force that the spring edge exerts is k_ times the vector (L-l)p2-p1
     * where L is the resting magnitude of the edge and l is the current magnitude
     * The official formula in proceedings of Siggraph 1988 p169 is
     *   k(L-l) - D* dl/dt
     * @return the computed force exerted on the particle.
     */
    public Vector2d getForce() {
        force.set(secondParticle_);
        force.sub(firstParticle_);
        direction.set(force);
        direction.normalize();

        // adjust the force by the damping term
        dampingVec.set(secondParticle_.velocity);
        dampingVec.sub(firstParticle_.velocity);
        double halfEffectiveL = effectiveLength / 2.0;
        double damp = damping * dampingVec.dot(direction);

        length = force.length();
        // never let the force get too great or too small
        if ( length > 2.0 * effectiveLength)
            force.scale( (-k_ * (effectiveLength - length) * (effectiveLength - length) / effectiveLength - damp) );
        else if ( length < halfEffectiveL ) {
            // prevent the springs from getting too compressed
            double lengthDiff =  restingLength - length;
            force.scale(k_ * (lengthDiff + 100000.0 * (halfEffectiveL - length)) / halfEffectiveL - damp);
        }
        else {

            //if (d>1.0)
            //   System.out.println("f="+k_*(effectiveLength-length)+" - d="+d);
            force.scale( (k_ * (effectiveLength - length) - damp) );
        }

        return force;
    }

    /**
     * A unit vector in the direction p2-p1
     */
    public Vector2d getDirection() {
        direction.set(secondParticle_);
        direction.sub(firstParticle_);
        direction.normalize();
        return direction;
    }

    public boolean intersects( Rectangle2D.Double rect ) {
        return segment_.intersects( rect );
    }

    /**
     * find the result of taking the dot product of this edge iwth another
     * @param edge to dot this edge with
     * @return the dot product
     */
    public double dot( Edge edge ) {
        return getDirection().dot( edge.getDirection() );
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy