Browse Source

* Added check for unit vector in Ray.setDirection()
* Changed Ray constructor to set direction to 0, 0, 1 to satisfy above requirement
* Ray no longer steals references

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@8859 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

Sha..om 14 years ago
parent
commit
cebf822f0e
1 changed files with 523 additions and 520 deletions
  1. 523 520
      engine/src/core/com/jme3/math/Ray.java

+ 523 - 520
engine/src/core/com/jme3/math/Ray.java

@@ -1,520 +1,523 @@
-/*
- * Copyright (c) 2009-2010 jMonkeyEngine
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions are
- * met:
- *
- * * Redistributions of source code must retain the above copyright
- *   notice, this list of conditions and the following disclaimer.
- *
- * * Redistributions in binary form must reproduce the above copyright
- *   notice, this list of conditions and the following disclaimer in the
- *   documentation and/or other materials provided with the distribution.
- *
- * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
- *   may be used to endorse or promote products derived from this software
- *   without specific prior written permission.
- *
- * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
- * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
- * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
- * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
- * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
- * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
- * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
- * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
- * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
- * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-package com.jme3.math;
-
-import com.jme3.bounding.BoundingVolume;
-import com.jme3.collision.Collidable;
-import com.jme3.collision.CollisionResult;
-import com.jme3.collision.CollisionResults;
-import com.jme3.collision.UnsupportedCollisionException;
-import com.jme3.export.*;
-import com.jme3.util.TempVars;
-import java.io.IOException;
-
-/**
- * <code>Ray</code> defines a line segment which has an origin and a direction.
- * That is, a point and an infinite ray is cast from this point. The ray is
- * defined by the following equation: R(t) = origin + t*direction for t >= 0.
- * 
- * @author Mark Powell
- * @author Joshua Slack
- */
-public final class Ray implements Savable, Cloneable, Collidable, java.io.Serializable {
-
-    static final long serialVersionUID = 1;
-
-    //todo: merge with Line?
-    /** The ray's begining point. */
-    public Vector3f origin;
-    /** The direction of the ray. */
-    public Vector3f direction;
-    public float limit = Float.POSITIVE_INFINITY;
-
-//    protected static final Vector3f tempVa=new Vector3f();
-//    protected static final Vector3f tempVb=new Vector3f();
-//    protected static final Vector3f tempVc=new Vector3f();
-//    protected static final Vector3f tempVd=new Vector3f();
-    /**
-     * Constructor instantiates a new <code>Ray</code> object. As default, the
-     * origin is (0,0,0) and the direction is (0,0,0).
-     *
-     */
-    public Ray() {
-        origin = new Vector3f();
-        direction = new Vector3f();
-    }
-
-    /**
-     * Constructor instantiates a new <code>Ray</code> object. The origin and
-     * direction are given.
-     * @param origin the origin of the ray.
-     * @param direction the direction the ray travels in.
-     */
-    public Ray(Vector3f origin, Vector3f direction) {
-        this.origin = origin;
-        this.direction = direction;
-    }
-
-    /**
-     * <code>intersect</code> determines if the Ray intersects a triangle.
-     * @param t the Triangle to test against.
-     * @return true if the ray collides.
-     */
-//    public boolean intersect(Triangle t) {
-//        return intersect(t.get(0), t.get(1), t.get(2));
-//    }
-    /**
-     * <code>intersect</code> determines if the Ray intersects a triangle
-     * defined by the specified points.
-     *
-     * @param v0
-     *            first point of the triangle.
-     * @param v1
-     *            second point of the triangle.
-     * @param v2
-     *            third point of the triangle.
-     * @return true if the ray collides.
-     */
-//    public boolean intersect(Vector3f v0,Vector3f v1,Vector3f v2){
-//        return intersectWhere(v0, v1, v2, null);
-//    }
-    /**
-     * <code>intersectWhere</code> determines if the Ray intersects a triangle. It then
-     * stores the point of intersection in the given loc vector
-     * @param t the Triangle to test against.
-     * @param loc
-     *            storage vector to save the collision point in (if the ray
-     *            collides)
-     * @return true if the ray collides.
-     */
-    public boolean intersectWhere(Triangle t, Vector3f loc) {
-        return intersectWhere(t.get(0), t.get(1), t.get(2), loc);
-    }
-
-    /**
-     * <code>intersectWhere</code> determines if the Ray intersects a triangle
-     * defined by the specified points and if so it stores the point of
-     * intersection in the given loc vector.
-     *
-     * @param v0
-     *            first point of the triangle.
-     * @param v1
-     *            second point of the triangle.
-     * @param v2
-     *            third point of the triangle.
-     * @param loc
-     *            storage vector to save the collision point in (if the ray
-     *            collides)  if null, only boolean is calculated.
-     * @return true if the ray collides.
-     */
-    public boolean intersectWhere(Vector3f v0, Vector3f v1, Vector3f v2,
-            Vector3f loc) {
-        return intersects(v0, v1, v2, loc, false, false);
-    }
-
-    /**
-     * <code>intersectWherePlanar</code> determines if the Ray intersects a
-     * triangle and if so it stores the point of
-     * intersection in the given loc vector as t, u, v where t is the distance
-     * from the origin to the point of intersection and u,v is the intersection
-     * point in terms of the triangle plane.
-     *
-     * @param t the Triangle to test against.
-     * @param loc
-     *            storage vector to save the collision point in (if the ray
-     *            collides) as t, u, v
-     * @return true if the ray collides.
-     */
-    public boolean intersectWherePlanar(Triangle t, Vector3f loc) {
-        return intersectWherePlanar(t.get(0), t.get(1), t.get(2), loc);
-    }
-
-    /**
-     * <code>intersectWherePlanar</code> determines if the Ray intersects a
-     * triangle defined by the specified points and if so it stores the point of
-     * intersection in the given loc vector as t, u, v where t is the distance
-     * from the origin to the point of intersection and u,v is the intersection
-     * point in terms of the triangle plane.
-     *
-     * @param v0
-     *            first point of the triangle.
-     * @param v1
-     *            second point of the triangle.
-     * @param v2
-     *            third point of the triangle.
-     * @param loc
-     *            storage vector to save the collision point in (if the ray
-     *            collides) as t, u, v
-     * @return true if the ray collides.
-     */
-    public boolean intersectWherePlanar(Vector3f v0, Vector3f v1, Vector3f v2,
-            Vector3f loc) {
-        return intersects(v0, v1, v2, loc, true, false);
-    }
-
-    /**
-     * <code>intersects</code> does the actual intersection work.
-     *
-     * @param v0
-     *            first point of the triangle.
-     * @param v1
-     *            second point of the triangle.
-     * @param v2
-     *            third point of the triangle.
-     * @param store
-     *            storage vector - if null, no intersection is calc'd
-     * @param doPlanar
-     *            true if we are calcing planar results.
-     * @param quad
-     * @return true if ray intersects triangle
-     */
-    private boolean intersects(Vector3f v0, Vector3f v1, Vector3f v2,
-            Vector3f store, boolean doPlanar, boolean quad) {
-        TempVars vars = TempVars.get();
-
-        Vector3f tempVa = vars.vect1,
-                tempVb = vars.vect2,
-                tempVc = vars.vect3,
-                tempVd = vars.vect4;
-
-        Vector3f diff = origin.subtract(v0, tempVa);
-        Vector3f edge1 = v1.subtract(v0, tempVb);
-        Vector3f edge2 = v2.subtract(v0, tempVc);
-        Vector3f norm = edge1.cross(edge2, tempVd);
-
-        float dirDotNorm = direction.dot(norm);
-        float sign;
-        if (dirDotNorm > FastMath.FLT_EPSILON) {
-            sign = 1;
-        } else if (dirDotNorm < -FastMath.FLT_EPSILON) {
-            sign = -1f;
-            dirDotNorm = -dirDotNorm;
-        } else {
-            // ray and triangle/quad are parallel
-            vars.release();
-            return false;
-        }
-
-        float dirDotDiffxEdge2 = sign * direction.dot(diff.cross(edge2, edge2));
-        if (dirDotDiffxEdge2 >= 0.0f) {
-            float dirDotEdge1xDiff = sign
-                    * direction.dot(edge1.crossLocal(diff));
-
-            if (dirDotEdge1xDiff >= 0.0f) {
-                if (!quad ? dirDotDiffxEdge2 + dirDotEdge1xDiff <= dirDotNorm : dirDotEdge1xDiff <= dirDotNorm) {
-                    float diffDotNorm = -sign * diff.dot(norm);
-                    if (diffDotNorm >= 0.0f) {
-                        // this method always returns
-                        vars.release();
-
-                        // ray intersects triangle
-                        // if storage vector is null, just return true,
-                        if (store == null) {
-                            return true;
-                        }
-
-                        // else fill in.
-                        float inv = 1f / dirDotNorm;
-                        float t = diffDotNorm * inv;
-                        if (!doPlanar) {
-                            store.set(origin).addLocal(direction.x * t,
-                                    direction.y * t, direction.z * t);
-                        } else {
-                            // these weights can be used to determine
-                            // interpolated values, such as texture coord.
-                            // eg. texcoord s,t at intersection point:
-                            // s = w0*s0 + w1*s1 + w2*s2;
-                            // t = w0*t0 + w1*t1 + w2*t2;
-                            float w1 = dirDotDiffxEdge2 * inv;
-                            float w2 = dirDotEdge1xDiff * inv;
-                            //float w0 = 1.0f - w1 - w2;
-                            store.set(t, w1, w2);
-                        }
-                        return true;
-                    }
-                }
-            }
-        }
-        vars.release();
-        return false;
-    }
-
-    public float intersects(Vector3f v0, Vector3f v1, Vector3f v2) {
-        float edge1X = v1.x - v0.x;
-        float edge1Y = v1.y - v0.y;
-        float edge1Z = v1.z - v0.z;
-
-        float edge2X = v2.x - v0.x;
-        float edge2Y = v2.y - v0.y;
-        float edge2Z = v2.z - v0.z;
-
-        float normX = ((edge1Y * edge2Z) - (edge1Z * edge2Y));
-        float normY = ((edge1Z * edge2X) - (edge1X * edge2Z));
-        float normZ = ((edge1X * edge2Y) - (edge1Y * edge2X));
-
-        float dirDotNorm = direction.x * normX + direction.y * normY + direction.z * normZ;
-
-        float diffX = origin.x - v0.x;
-        float diffY = origin.y - v0.y;
-        float diffZ = origin.z - v0.z;
-
-        float sign;
-        if (dirDotNorm > FastMath.FLT_EPSILON) {
-            sign = 1;
-        } else if (dirDotNorm < -FastMath.FLT_EPSILON) {
-            sign = -1f;
-            dirDotNorm = -dirDotNorm;
-        } else {
-            // ray and triangle/quad are parallel
-            return Float.POSITIVE_INFINITY;
-        }
-
-        float diffEdge2X = ((diffY * edge2Z) - (diffZ * edge2Y));
-        float diffEdge2Y = ((diffZ * edge2X) - (diffX * edge2Z));
-        float diffEdge2Z = ((diffX * edge2Y) - (diffY * edge2X));
-
-        float dirDotDiffxEdge2 = sign * (direction.x * diffEdge2X
-                + direction.y * diffEdge2Y
-                + direction.z * diffEdge2Z);
-
-        if (dirDotDiffxEdge2 >= 0.0f) {
-            diffEdge2X = ((edge1Y * diffZ) - (edge1Z * diffY));
-            diffEdge2Y = ((edge1Z * diffX) - (edge1X * diffZ));
-            diffEdge2Z = ((edge1X * diffY) - (edge1Y * diffX));
-
-            float dirDotEdge1xDiff = sign * (direction.x * diffEdge2X
-                    + direction.y * diffEdge2Y
-                    + direction.z * diffEdge2Z);
-
-            if (dirDotEdge1xDiff >= 0.0f) {
-                if (dirDotDiffxEdge2 + dirDotEdge1xDiff <= dirDotNorm) {
-                    float diffDotNorm = -sign * (diffX * normX + diffY * normY + diffZ * normZ);
-                    if (diffDotNorm >= 0.0f) {
-                        // ray intersects triangle
-                        // fill in.
-                        float inv = 1f / dirDotNorm;
-                        float t = diffDotNorm * inv;
-                        return t;
-                    }
-                }
-            }
-        }
-
-        return Float.POSITIVE_INFINITY;
-    }
-
-    /**
-     * <code>intersectWherePlanar</code> determines if the Ray intersects a
-     * quad defined by the specified points and if so it stores the point of
-     * intersection in the given loc vector as t, u, v where t is the distance
-     * from the origin to the point of intersection and u,v is the intersection
-     * point in terms of the quad plane.
-     * One edge of the quad is [v0,v1], another one [v0,v2]. The behaviour thus is like
-     * {@link #intersectWherePlanar(Vector3f, Vector3f, Vector3f, Vector3f)} except for
-     * the extended area, which is equivalent to the union of the triangles [v0,v1,v2]
-     * and [-v0+v1+v2,v1,v2].
-     *
-     * @param v0
-     *            top left point of the quad.
-     * @param v1
-     *            top right point of the quad.
-     * @param v2
-     *            bottom left point of the quad.
-     * @param loc
-     *            storage vector to save the collision point in (if the ray
-     *            collides) as t, u, v
-     * @return true if the ray collides with the quad.
-     */
-    public boolean intersectWherePlanarQuad(Vector3f v0, Vector3f v1, Vector3f v2,
-            Vector3f loc) {
-        return intersects(v0, v1, v2, loc, true, true);
-    }
-
-    /**
-     * 
-     * @param p
-     * @param loc
-     * @return true if the ray collides with the given Plane
-     */
-    public boolean intersectsWherePlane(Plane p, Vector3f loc) {
-        float denominator = p.getNormal().dot(direction);
-
-        if (denominator > -FastMath.FLT_EPSILON && denominator < FastMath.FLT_EPSILON) {
-            return false; // coplanar
-        }
-        float numerator = -(p.getNormal().dot(origin) - p.getConstant());
-        float ratio = numerator / denominator;
-
-        if (ratio < FastMath.FLT_EPSILON) {
-            return false; // intersects behind origin
-        }
-        loc.set(direction).multLocal(ratio).addLocal(origin);
-
-        return true;
-    }
-
-    public int collideWith(Collidable other, CollisionResults results) {
-        if (other instanceof BoundingVolume) {
-            BoundingVolume bv = (BoundingVolume) other;
-            return bv.collideWith(this, results);
-        } else if (other instanceof AbstractTriangle) {
-            AbstractTriangle tri = (AbstractTriangle) other;
-            float d = intersects(tri.get1(), tri.get2(), tri.get3());
-            if (Float.isInfinite(d) || Float.isNaN(d)) {
-                return 0;
-            }
-
-            Vector3f point = new Vector3f(direction).multLocal(d).addLocal(origin);
-            results.addCollision(new CollisionResult(point, d));
-            return 1;
-        } else {
-            throw new UnsupportedCollisionException();
-        }
-    }
-
-    public float distanceSquared(Vector3f point) {
-        TempVars vars = TempVars.get();
-
-        Vector3f tempVa = vars.vect1,
-                tempVb = vars.vect2;
-
-        point.subtract(origin, tempVa);
-        float rayParam = direction.dot(tempVa);
-        if (rayParam > 0) {
-            origin.add(direction.mult(rayParam, tempVb), tempVb);
-        } else {
-            tempVb.set(origin);
-            rayParam = 0.0f;
-        }
-
-        tempVb.subtract(point, tempVa);
-        float len = tempVa.lengthSquared();
-        vars.release();
-        return len;
-    }
-
-    /**
-     *
-     * <code>getOrigin</code> retrieves the origin point of the ray.
-     *
-     * @return the origin of the ray.
-     */
-    public Vector3f getOrigin() {
-        return origin;
-    }
-
-    /**
-     *
-     * <code>setOrigin</code> sets the origin of the ray.
-     * @param origin the origin of the ray.
-     */
-    public void setOrigin(Vector3f origin) {
-        this.origin.set(origin);
-    }
-
-    /**
-     * <code>getLimit</code> returns the limit or the ray, aka the length.
-     * If the limit is not infinity, then this ray is a line with length <code>
-     * limit</code>.
-     * 
-     * @return the limit or the ray, aka the length.
-     */
-    public float getLimit() {
-        return limit;
-    }
-
-    /**
-     * <code>setLimit</code> sets the limit of the ray.
-     * @param limit the limit of the ray.
-     * @see Ray#getLimit() 
-     */
-    public void setLimit(float limit) {
-        this.limit = limit;
-    }
-
-    /**
-     *
-     * <code>getDirection</code> retrieves the direction vector of the ray.
-     * @return the direction of the ray.
-     */
-    public Vector3f getDirection() {
-        return direction;
-    }
-
-    /**
-     *
-     * <code>setDirection</code> sets the direction vector of the ray.
-     * @param direction the direction of the ray.
-     */
-    public void setDirection(Vector3f direction) {
-        this.direction.set(direction);
-    }
-
-    /**
-     * Copies information from a source ray into this ray.
-     * 
-     * @param source
-     *            the ray to copy information from
-     */
-    public void set(Ray source) {
-        origin.set(source.getOrigin());
-        direction.set(source.getDirection());
-    }
-
-    public String toString() {
-        return getClass().getSimpleName() + " [Origin: " + origin + ", Direction: " + direction + "]";
-    }
-
-    public void write(JmeExporter e) throws IOException {
-        OutputCapsule capsule = e.getCapsule(this);
-        capsule.write(origin, "origin", Vector3f.ZERO);
-        capsule.write(direction, "direction", Vector3f.ZERO);
-    }
-
-    public void read(JmeImporter e) throws IOException {
-        InputCapsule capsule = e.getCapsule(this);
-        origin = (Vector3f) capsule.readSavable("origin", Vector3f.ZERO.clone());
-        direction = (Vector3f) capsule.readSavable("direction", Vector3f.ZERO.clone());
-    }
-
-    @Override
-    public Ray clone() {
-        try {
-            Ray r = (Ray) super.clone();
-            r.direction = direction.clone();
-            r.origin = origin.clone();
-            return r;
-        } catch (CloneNotSupportedException e) {
-            throw new AssertionError();
-        }
-    }
-}
+/*
+ * Copyright (c) 2009-2010 jMonkeyEngine
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are
+ * met:
+ *
+ * * Redistributions of source code must retain the above copyright
+ *   notice, this list of conditions and the following disclaimer.
+ *
+ * * Redistributions in binary form must reproduce the above copyright
+ *   notice, this list of conditions and the following disclaimer in the
+ *   documentation and/or other materials provided with the distribution.
+ *
+ * * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *   may be used to endorse or promote products derived from this software
+ *   without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.math;
+
+import com.jme3.bounding.BoundingVolume;
+import com.jme3.collision.Collidable;
+import com.jme3.collision.CollisionResult;
+import com.jme3.collision.CollisionResults;
+import com.jme3.collision.UnsupportedCollisionException;
+import com.jme3.export.*;
+import com.jme3.util.TempVars;
+import java.io.IOException;
+
+/**
+ * <code>Ray</code> defines a line segment which has an origin and a direction.
+ * That is, a point and an infinite ray is cast from this point. The ray is
+ * defined by the following equation: R(t) = origin + t*direction for t >= 0.
+ * 
+ * @author Mark Powell
+ * @author Joshua Slack
+ */
+public final class Ray implements Savable, Cloneable, Collidable, java.io.Serializable {
+
+    static final long serialVersionUID = 1;
+
+    /** 
+     * The ray's begining point. 
+     */
+    public Vector3f origin = new Vector3f();
+    
+    /** 
+     * The direction of the ray. 
+     */
+    public Vector3f direction = new Vector3f(0, 0, 1);
+    
+    
+    public float limit = Float.POSITIVE_INFINITY;
+
+    /**
+     * Constructor instantiates a new <code>Ray</code> object. As default, the
+     * origin is (0,0,0) and the direction is (0,0,1).
+     *
+     */
+    public Ray() {
+    }
+
+    /**
+     * Constructor instantiates a new <code>Ray</code> object. The origin and
+     * direction are given.
+     * @param origin the origin of the ray.
+     * @param direction the direction the ray travels in.
+     */
+    public Ray(Vector3f origin, Vector3f direction) {
+        setOrigin(origin)
+        setDirection(direction);
+    }
+
+    /**
+     * <code>intersect</code> determines if the Ray intersects a triangle.
+     * @param t the Triangle to test against.
+     * @return true if the ray collides.
+     */
+//    public boolean intersect(Triangle t) {
+//        return intersect(t.get(0), t.get(1), t.get(2));
+//    }
+    /**
+     * <code>intersect</code> determines if the Ray intersects a triangle
+     * defined by the specified points.
+     *
+     * @param v0
+     *            first point of the triangle.
+     * @param v1
+     *            second point of the triangle.
+     * @param v2
+     *            third point of the triangle.
+     * @return true if the ray collides.
+     */
+//    public boolean intersect(Vector3f v0,Vector3f v1,Vector3f v2){
+//        return intersectWhere(v0, v1, v2, null);
+//    }
+    /**
+     * <code>intersectWhere</code> determines if the Ray intersects a triangle. It then
+     * stores the point of intersection in the given loc vector
+     * @param t the Triangle to test against.
+     * @param loc
+     *            storage vector to save the collision point in (if the ray
+     *            collides)
+     * @return true if the ray collides.
+     */
+    public boolean intersectWhere(Triangle t, Vector3f loc) {
+        return intersectWhere(t.get(0), t.get(1), t.get(2), loc);
+    }
+
+    /**
+     * <code>intersectWhere</code> determines if the Ray intersects a triangle
+     * defined by the specified points and if so it stores the point of
+     * intersection in the given loc vector.
+     *
+     * @param v0
+     *            first point of the triangle.
+     * @param v1
+     *            second point of the triangle.
+     * @param v2
+     *            third point of the triangle.
+     * @param loc
+     *            storage vector to save the collision point in (if the ray
+     *            collides)  if null, only boolean is calculated.
+     * @return true if the ray collides.
+     */
+    public boolean intersectWhere(Vector3f v0, Vector3f v1, Vector3f v2,
+            Vector3f loc) {
+        return intersects(v0, v1, v2, loc, false, false);
+    }
+
+    /**
+     * <code>intersectWherePlanar</code> determines if the Ray intersects a
+     * triangle and if so it stores the point of
+     * intersection in the given loc vector as t, u, v where t is the distance
+     * from the origin to the point of intersection and u,v is the intersection
+     * point in terms of the triangle plane.
+     *
+     * @param t the Triangle to test against.
+     * @param loc
+     *            storage vector to save the collision point in (if the ray
+     *            collides) as t, u, v
+     * @return true if the ray collides.
+     */
+    public boolean intersectWherePlanar(Triangle t, Vector3f loc) {
+        return intersectWherePlanar(t.get(0), t.get(1), t.get(2), loc);
+    }
+
+    /**
+     * <code>intersectWherePlanar</code> determines if the Ray intersects a
+     * triangle defined by the specified points and if so it stores the point of
+     * intersection in the given loc vector as t, u, v where t is the distance
+     * from the origin to the point of intersection and u,v is the intersection
+     * point in terms of the triangle plane.
+     *
+     * @param v0
+     *            first point of the triangle.
+     * @param v1
+     *            second point of the triangle.
+     * @param v2
+     *            third point of the triangle.
+     * @param loc
+     *            storage vector to save the collision point in (if the ray
+     *            collides) as t, u, v
+     * @return true if the ray collides.
+     */
+    public boolean intersectWherePlanar(Vector3f v0, Vector3f v1, Vector3f v2,
+            Vector3f loc) {
+        return intersects(v0, v1, v2, loc, true, false);
+    }
+
+    /**
+     * <code>intersects</code> does the actual intersection work.
+     *
+     * @param v0
+     *            first point of the triangle.
+     * @param v1
+     *            second point of the triangle.
+     * @param v2
+     *            third point of the triangle.
+     * @param store
+     *            storage vector - if null, no intersection is calc'd
+     * @param doPlanar
+     *            true if we are calcing planar results.
+     * @param quad
+     * @return true if ray intersects triangle
+     */
+    private boolean intersects(Vector3f v0, Vector3f v1, Vector3f v2,
+            Vector3f store, boolean doPlanar, boolean quad) {
+        TempVars vars = TempVars.get();
+
+        Vector3f tempVa = vars.vect1,
+                tempVb = vars.vect2,
+                tempVc = vars.vect3,
+                tempVd = vars.vect4;
+
+        Vector3f diff = origin.subtract(v0, tempVa);
+        Vector3f edge1 = v1.subtract(v0, tempVb);
+        Vector3f edge2 = v2.subtract(v0, tempVc);
+        Vector3f norm = edge1.cross(edge2, tempVd);
+
+        float dirDotNorm = direction.dot(norm);
+        float sign;
+        if (dirDotNorm > FastMath.FLT_EPSILON) {
+            sign = 1;
+        } else if (dirDotNorm < -FastMath.FLT_EPSILON) {
+            sign = -1f;
+            dirDotNorm = -dirDotNorm;
+        } else {
+            // ray and triangle/quad are parallel
+            vars.release();
+            return false;
+        }
+
+        float dirDotDiffxEdge2 = sign * direction.dot(diff.cross(edge2, edge2));
+        if (dirDotDiffxEdge2 >= 0.0f) {
+            float dirDotEdge1xDiff = sign
+                    * direction.dot(edge1.crossLocal(diff));
+
+            if (dirDotEdge1xDiff >= 0.0f) {
+                if (!quad ? dirDotDiffxEdge2 + dirDotEdge1xDiff <= dirDotNorm : dirDotEdge1xDiff <= dirDotNorm) {
+                    float diffDotNorm = -sign * diff.dot(norm);
+                    if (diffDotNorm >= 0.0f) {
+                        // this method always returns
+                        vars.release();
+
+                        // ray intersects triangle
+                        // if storage vector is null, just return true,
+                        if (store == null) {
+                            return true;
+                        }
+
+                        // else fill in.
+                        float inv = 1f / dirDotNorm;
+                        float t = diffDotNorm * inv;
+                        if (!doPlanar) {
+                            store.set(origin).addLocal(direction.x * t,
+                                    direction.y * t, direction.z * t);
+                        } else {
+                            // these weights can be used to determine
+                            // interpolated values, such as texture coord.
+                            // eg. texcoord s,t at intersection point:
+                            // s = w0*s0 + w1*s1 + w2*s2;
+                            // t = w0*t0 + w1*t1 + w2*t2;
+                            float w1 = dirDotDiffxEdge2 * inv;
+                            float w2 = dirDotEdge1xDiff * inv;
+                            //float w0 = 1.0f - w1 - w2;
+                            store.set(t, w1, w2);
+                        }
+                        return true;
+                    }
+                }
+            }
+        }
+        vars.release();
+        return false;
+    }
+
+    public float intersects(Vector3f v0, Vector3f v1, Vector3f v2) {
+        float edge1X = v1.x - v0.x;
+        float edge1Y = v1.y - v0.y;
+        float edge1Z = v1.z - v0.z;
+
+        float edge2X = v2.x - v0.x;
+        float edge2Y = v2.y - v0.y;
+        float edge2Z = v2.z - v0.z;
+
+        float normX = ((edge1Y * edge2Z) - (edge1Z * edge2Y));
+        float normY = ((edge1Z * edge2X) - (edge1X * edge2Z));
+        float normZ = ((edge1X * edge2Y) - (edge1Y * edge2X));
+
+        float dirDotNorm = direction.x * normX + direction.y * normY + direction.z * normZ;
+
+        float diffX = origin.x - v0.x;
+        float diffY = origin.y - v0.y;
+        float diffZ = origin.z - v0.z;
+
+        float sign;
+        if (dirDotNorm > FastMath.FLT_EPSILON) {
+            sign = 1;
+        } else if (dirDotNorm < -FastMath.FLT_EPSILON) {
+            sign = -1f;
+            dirDotNorm = -dirDotNorm;
+        } else {
+            // ray and triangle/quad are parallel
+            return Float.POSITIVE_INFINITY;
+        }
+
+        float diffEdge2X = ((diffY * edge2Z) - (diffZ * edge2Y));
+        float diffEdge2Y = ((diffZ * edge2X) - (diffX * edge2Z));
+        float diffEdge2Z = ((diffX * edge2Y) - (diffY * edge2X));
+
+        float dirDotDiffxEdge2 = sign * (direction.x * diffEdge2X
+                + direction.y * diffEdge2Y
+                + direction.z * diffEdge2Z);
+
+        if (dirDotDiffxEdge2 >= 0.0f) {
+            diffEdge2X = ((edge1Y * diffZ) - (edge1Z * diffY));
+            diffEdge2Y = ((edge1Z * diffX) - (edge1X * diffZ));
+            diffEdge2Z = ((edge1X * diffY) - (edge1Y * diffX));
+
+            float dirDotEdge1xDiff = sign * (direction.x * diffEdge2X
+                    + direction.y * diffEdge2Y
+                    + direction.z * diffEdge2Z);
+
+            if (dirDotEdge1xDiff >= 0.0f) {
+                if (dirDotDiffxEdge2 + dirDotEdge1xDiff <= dirDotNorm) {
+                    float diffDotNorm = -sign * (diffX * normX + diffY * normY + diffZ * normZ);
+                    if (diffDotNorm >= 0.0f) {
+                        // ray intersects triangle
+                        // fill in.
+                        float inv = 1f / dirDotNorm;
+                        float t = diffDotNorm * inv;
+                        return t;
+                    }
+                }
+            }
+        }
+
+        return Float.POSITIVE_INFINITY;
+    }
+
+    /**
+     * <code>intersectWherePlanar</code> determines if the Ray intersects a
+     * quad defined by the specified points and if so it stores the point of
+     * intersection in the given loc vector as t, u, v where t is the distance
+     * from the origin to the point of intersection and u,v is the intersection
+     * point in terms of the quad plane.
+     * One edge of the quad is [v0,v1], another one [v0,v2]. The behaviour thus is like
+     * {@link #intersectWherePlanar(Vector3f, Vector3f, Vector3f, Vector3f)} except for
+     * the extended area, which is equivalent to the union of the triangles [v0,v1,v2]
+     * and [-v0+v1+v2,v1,v2].
+     *
+     * @param v0
+     *            top left point of the quad.
+     * @param v1
+     *            top right point of the quad.
+     * @param v2
+     *            bottom left point of the quad.
+     * @param loc
+     *            storage vector to save the collision point in (if the ray
+     *            collides) as t, u, v
+     * @return true if the ray collides with the quad.
+     */
+    public boolean intersectWherePlanarQuad(Vector3f v0, Vector3f v1, Vector3f v2,
+            Vector3f loc) {
+        return intersects(v0, v1, v2, loc, true, true);
+    }
+
+    /**
+     * 
+     * @param p
+     * @param loc
+     * @return true if the ray collides with the given Plane
+     */
+    public boolean intersectsWherePlane(Plane p, Vector3f loc) {
+        float denominator = p.getNormal().dot(direction);
+
+        if (denominator > -FastMath.FLT_EPSILON && denominator < FastMath.FLT_EPSILON) {
+            return false; // coplanar
+        }
+        float numerator = -(p.getNormal().dot(origin) - p.getConstant());
+        float ratio = numerator / denominator;
+
+        if (ratio < FastMath.FLT_EPSILON) {
+            return false; // intersects behind origin
+        }
+        loc.set(direction).multLocal(ratio).addLocal(origin);
+
+        return true;
+    }
+
+    public int collideWith(Collidable other, CollisionResults results) {
+        if (other instanceof BoundingVolume) {
+            BoundingVolume bv = (BoundingVolume) other;
+            return bv.collideWith(this, results);
+        } else if (other instanceof AbstractTriangle) {
+            AbstractTriangle tri = (AbstractTriangle) other;
+            float d = intersects(tri.get1(), tri.get2(), tri.get3());
+            if (Float.isInfinite(d) || Float.isNaN(d)) {
+                return 0;
+            }
+
+            Vector3f point = new Vector3f(direction).multLocal(d).addLocal(origin);
+            results.addCollision(new CollisionResult(point, d));
+            return 1;
+        } else {
+            throw new UnsupportedCollisionException();
+        }
+    }
+
+    public float distanceSquared(Vector3f point) {
+        TempVars vars = TempVars.get();
+
+        Vector3f tempVa = vars.vect1,
+                tempVb = vars.vect2;
+
+        point.subtract(origin, tempVa);
+        float rayParam = direction.dot(tempVa);
+        if (rayParam > 0) {
+            origin.add(direction.mult(rayParam, tempVb), tempVb);
+        } else {
+            tempVb.set(origin);
+            rayParam = 0.0f;
+        }
+
+        tempVb.subtract(point, tempVa);
+        float len = tempVa.lengthSquared();
+        vars.release();
+        return len;
+    }
+
+    /**
+     *
+     * <code>getOrigin</code> retrieves the origin point of the ray.
+     *
+     * @return the origin of the ray.
+     */
+    public Vector3f getOrigin() {
+        return origin;
+    }
+
+    /**
+     *
+     * <code>setOrigin</code> sets the origin of the ray.
+     * @param origin the origin of the ray.
+     */
+    public void setOrigin(Vector3f origin) {
+        this.origin.set(origin);
+    }
+
+    /**
+     * <code>getLimit</code> returns the limit or the ray, aka the length.
+     * If the limit is not infinity, then this ray is a line with length <code>
+     * limit</code>.
+     * 
+     * @return the limit or the ray, aka the length.
+     */
+    public float getLimit() {
+        return limit;
+    }
+
+    /**
+     * <code>setLimit</code> sets the limit of the ray.
+     * @param limit the limit of the ray.
+     * @see Ray#getLimit() 
+     */
+    public void setLimit(float limit) {
+        this.limit = limit;
+    }
+
+    /**
+     *
+     * <code>getDirection</code> retrieves the direction vector of the ray.
+     * @return the direction of the ray.
+     */
+    public Vector3f getDirection() {
+        return direction;
+    }
+
+    /**
+     *
+     * <code>setDirection</code> sets the direction vector of the ray.
+     * @param direction the direction of the ray.
+     */
+    public void setDirection(Vector3f direction) {
+        if (!direction.isUnitVector()) {
+            throw new IllegalArgumentException("direction must be a unit vector");
+        }
+        this.direction.set(direction);
+    }
+
+    /**
+     * Copies information from a source ray into this ray.
+     * 
+     * @param source
+     *            the ray to copy information from
+     */
+    public void set(Ray source) {
+        origin.set(source.getOrigin());
+        direction.set(source.getDirection());
+    }
+
+    public String toString() {
+        return getClass().getSimpleName() + " [Origin: " + origin + ", Direction: " + direction + "]";
+    }
+
+    public void write(JmeExporter e) throws IOException {
+        OutputCapsule capsule = e.getCapsule(this);
+        capsule.write(origin, "origin", Vector3f.ZERO);
+        capsule.write(direction, "direction", Vector3f.ZERO);
+    }
+
+    public void read(JmeImporter e) throws IOException {
+        InputCapsule capsule = e.getCapsule(this);
+        origin = (Vector3f) capsule.readSavable("origin", Vector3f.ZERO.clone());
+        direction = (Vector3f) capsule.readSavable("direction", Vector3f.ZERO.clone());
+    }
+
+    @Override
+    public Ray clone() {
+        try {
+            Ray r = (Ray) super.clone();
+            r.direction = direction.clone();
+            r.origin = origin.clone();
+            return r;
+        } catch (CloneNotSupportedException e) {
+            throw new AssertionError();
+        }
+    }
+}