Package toxi.physics3d

Source Code of toxi.physics3d.VerletPhysics3D

/*
*   __               .__       .__  ._____.          
* _/  |_  _______  __|__| ____ |  | |__\_ |__   ______
* \   __\/  _ \  \/  /  |/ ___\|  | |  || __ \ /  ___/
*  |  | (  <_> >    <|  \  \___|  |_|  || \_\ \\___ \
*  |__|  \____/__/\_ \__|\___  >____/__||___  /____  >
*                   \/       \/             \/     \/
*
* Copyright (c) 2006-2011 Karsten Schmidt
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* http://creativecommons.org/licenses/LGPL/2.1/
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
*/

package toxi.physics3d;

import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import toxi.geom.AABB;
import toxi.geom.Vec3D;
import toxi.physics3d.behaviors.GravityBehavior3D;
import toxi.physics3d.behaviors.ParticleBehavior3D;
import toxi.physics3d.constraints.ParticleConstraint3D;

/**
* 3D particle physics engine using Verlet integration based on:
* http://en.wikipedia.org/wiki/Verlet_integration
* http://www.teknikus.dk/tj/gdc2001.htm
*
*/
public class VerletPhysics3D {

    public static void addConstraintToAll(ParticleConstraint3D c,
            List<VerletParticle3D> list) {
        for (VerletParticle3D p : list) {
            p.addConstraint(c);
        }
    }

    public static void removeConstraintFromAll(ParticleConstraint3D c,
            List<VerletParticle3D> list) {
        for (VerletParticle3D p : list) {
            p.removeConstraint(c);
        }
    }

    /**
     * List of particles (Vec3D subclassed)
     */
    public List<VerletParticle3D> particles;
    /**
     * List of spring/sticks connectors
     */
    public List<VerletSpring3D> springs;

    /**
     * Default time step = 1.0
     */
    protected float timeStep;

    /**
     * Default iterations for verlet solver = 50
     */
    protected int numIterations;

    /**
     * Optional 3D bounding box to constrain particles too
     */
    protected AABB worldBounds;

    public final List<ParticleBehavior3D> behaviors = new ArrayList<ParticleBehavior3D>(
            1);

    public final List<ParticleConstraint3D> constraints = new ArrayList<ParticleConstraint3D>(
            1);

    protected float drag;

    /**
     * Initializes a Verlet engine instance using the default values.
     */
    public VerletPhysics3D() {
        this(null, 50, 0, 1);
    }

    /**
     * Initializes an Verlet engine instance with the passed in configuration.
     *
     * @param gravity
     *            3D gravity vector
     * @param numIterations
     *            iterations per time step for verlet solver
     * @param drag
     *            drag value 0...1
     * @param timeStep
     *            time step for calculating forces
     */
    public VerletPhysics3D(Vec3D gravity, int numIterations, float drag,
            float timeStep) {
        particles = new ArrayList<VerletParticle3D>();
        springs = new ArrayList<VerletSpring3D>();
        this.numIterations = numIterations;
        this.timeStep = timeStep;
        setDrag(drag);
        if (gravity != null) {
            addBehavior(new GravityBehavior3D(gravity));
        }
    }

    public void addBehavior(ParticleBehavior3D behavior) {
        behavior.configure(timeStep);
        behaviors.add(behavior);
    }

    public void addConstraint(ParticleConstraint3D constraint) {
        constraints.add(constraint);
    }

    /**
     * Adds a particle to the list
     *
     * @param p
     * @return itself
     */
    public VerletPhysics3D addParticle(VerletParticle3D p) {
        particles.add(p);
        return this;
    }

    /**
     * Adds a spring connector
     *
     * @param s
     * @return itself
     */
    public VerletPhysics3D addSpring(VerletSpring3D s) {
        if (getSpring(s.a, s.b) == null) {
            springs.add(s);
        }
        return this;
    }

    /**
     * Applies all global constraints and constrains all particle positions to
     * the world bounding box set
     */
    protected void applyConstaints() {
        boolean hasGlobalConstraints = constraints.size() > 0;
        for (VerletParticle3D p : particles) {
            if (hasGlobalConstraints) {
                for (ParticleConstraint3D c : constraints) {
                    c.apply(p);
                }
            }
            if (p.bounds != null) {
                p.constrain(p.bounds);
            }
            if (worldBounds != null) {
                p.constrain(worldBounds);
            }
        }
    }

    public VerletPhysics3D clear() {
        behaviors.clear();
        constraints.clear();
        particles.clear();
        springs.clear();
        return this;
    }

    public AABB getCurrentBounds() {
        Vec3D min = new Vec3D(Float.MAX_VALUE, Float.MAX_VALUE, Float.MAX_VALUE);
        Vec3D max = new Vec3D(Float.MIN_VALUE, Float.MIN_VALUE, Float.MIN_VALUE);
        for (Iterator<VerletParticle3D> i = particles.iterator(); i.hasNext();) {
            VerletParticle3D p = i.next();
            min.minSelf(p);
            max.maxSelf(p);
        }
        return AABB.fromMinMax(min, max);
    }

    public float getDrag() {
        return 1f - drag;
    }

    /**
     * @return the numIterations
     */
    public int getNumIterations() {
        return numIterations;
    }

    /**
     * Attempts to find the spring element between the 2 particles supplied
     *
     * @param a
     *            particle 1
     * @param b
     *            particle 2
     * @return spring instance, or null if not found
     */
    public VerletSpring3D getSpring(Vec3D a, Vec3D b) {
        for (VerletSpring3D s : springs) {
            if ((s.a == a && s.b == b) || (s.a == b && s.b == a)) {
                return s;
            }
        }
        return null;
    }

    /**
     * @return the timeStep
     */
    public float getTimeStep() {
        return timeStep;
    }

    /**
     * @return the worldBounds
     */
    public AABB getWorldBounds() {
        return worldBounds;
    }

    public boolean removeBehavior(ParticleBehavior3D b) {
        return behaviors.remove(b);
    }

    public boolean removeConstraint(ParticleConstraint3D c) {
        return constraints.remove(c);
    }

    /**
     * Removes a particle from the simulation.
     *
     * @param p
     *            particle to remove
     * @return true, if removed successfully
     */
    public boolean removeParticle(VerletParticle3D p) {
        return particles.remove(p);
    }

    /**
     * Removes a spring connector from the simulation instance.
     *
     * @param s
     *            spring to remove
     * @return true, if the spring has been removed
     */
    public boolean removeSpring(VerletSpring3D s) {
        return springs.remove(s);
    }

    /**
     * Removes a spring connector and its both end point particles from the
     * simulation
     *
     * @param s
     *            spring to remove
     * @return true, only if spring AND particles have been removed successfully
     */
    public boolean removeSpringElements(VerletSpring3D s) {
        if (removeSpring(s)) {
            return (removeParticle(s.a) && removeParticle(s.b));
        }
        return false;
    }

    public void setDrag(float drag) {
        this.drag = 1f - drag;
    }

    /**
     * @param numIterations
     *            the numIterations to set
     */
    public void setNumIterations(int numIterations) {
        this.numIterations = numIterations;
    }

    /**
     * @param timeStep
     *            the timeStep to set
     */
    public void setTimeStep(float timeStep) {
        this.timeStep = timeStep;
        for (ParticleBehavior3D b : behaviors) {
            b.configure(timeStep);
        }
    }

    /**
     * Sets bounding box
     *
     * @param world
     * @return itself
     */
    public VerletPhysics3D setWorldBounds(AABB world) {
        worldBounds = world;
        return this;
    }

    /**
     * Progresses the physics simulation by 1 time step and updates all forces
     * and particle positions accordingly
     *
     * @return itself
     */
    public VerletPhysics3D update() {
        updateParticles();
        updateSprings();
        applyConstaints();
        return this;
    }

    /**
     * Updates all particle positions
     */
    protected void updateParticles() {
        for (ParticleBehavior3D b : behaviors) {
            for (VerletParticle3D p : particles) {
                b.apply(p);
            }
        }
        for (VerletParticle3D p : particles) {
            p.scaleVelocity(drag);
            p.update();
        }
    }

    /**
     * Updates all spring connections based on new particle positions
     */
    protected void updateSprings() {
        if (springs.size() > 0) {
            for (int i = numIterations; i > 0; i--) {
                for (VerletSpring3D s : springs) {
                    s.update(i == 1);
                }
            }
        }
    }
}
TOP

Related Classes of toxi.physics3d.VerletPhysics3D

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.