Package org.terasology.math

Source Code of org.terasology.math.AABB

/*
* Copyright 2013 MovingBlocks
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*      http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/

package org.terasology.math;

import com.bulletphysics.linearmath.AabbUtil2;
import com.bulletphysics.linearmath.Transform;
import com.google.common.base.Objects;
import gnu.trove.list.TFloatList;

import javax.vecmath.Matrix4f;
import javax.vecmath.Quat4f;
import javax.vecmath.Vector3d;
import javax.vecmath.Vector3f;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

/**
* An axis-aligned bounding box. Provides basic support for inclusion
* and intersection tests.
*
* @author Benjamin Glatzel <benjamin.glatzel@me.com>
*/
public final class AABB {

    private final Vector3f min;
    private final Vector3f max;

    private Vector3f[] vertices;

    private AABB(Vector3f min, Vector3f max) {
        this.min = min;
        this.max = max;
    }

    public static AABB createMinMax(Vector3f min, Vector3f max) {
        return new AABB(new Vector3f(min), new Vector3f(max));
    }

    public static AABB createCenterExtent(Vector3f center, Vector3f extent) {
        Vector3f min = new Vector3f(center);
        min.sub(extent);
        Vector3f max = new Vector3f(center);
        max.add(extent);
        return new AABB(min, max);
    }

    public static AABB createEmpty() {
        return new AABB(new Vector3f(), new Vector3f());
    }

    /**
     * Creates a new AABB that encapsulates a set of AABBs
     *
     * @param others
     */
    public static AABB createEncompassing(Iterable<AABB> others) {
        Vector3f min;
        Vector3f max;
        Iterator<AABB> i = others.iterator();
        if (i.hasNext()) {
            AABB next = i.next();
            min = next.getMin();
            max = next.getMax();
        } else {
            return createEmpty();
        }
        while (i.hasNext()) {
            AABB next = i.next();
            Vector3f otherMin = next.getMin();
            Vector3f otherMax = next.getMax();
            Vector3fUtil.min(min, otherMin, min);
            Vector3fUtil.max(max, otherMax, max);
        }
        return new AABB(min, max);
    }

    public static AABB createEncompasing(TFloatList vertices) {
        int vertexCount = vertices.size() / 3;
        if (vertexCount == 0) {
            return AABB.createEmpty();
        }

        Vector3f min = new Vector3f(vertices.get(0), vertices.get(1), vertices.get(2));
        Vector3f max = new Vector3f(vertices.get(0), vertices.get(1), vertices.get(2));
        for (int index = 1; index < vertexCount; ++index) {
            min.x = Math.min(min.x, vertices.get(3 * index));
            max.x = Math.max(max.x, vertices.get(3 * index));
            min.y = Math.min(min.y, vertices.get(3 * index + 1));
            max.y = Math.max(max.y, vertices.get(3 * index + 1));
            min.z = Math.min(min.z, vertices.get(3 * index + 2));
            max.z = Math.max(max.z, vertices.get(3 * index + 2));
        }
        return AABB.createMinMax(min, max);
    }

    public Vector3f getExtents() {
        Vector3f dimensions = new Vector3f(max);
        dimensions.sub(min);
        dimensions.scale(0.5f);
        return dimensions;
    }

    public Vector3f getCenter() {
        Vector3f dimensions = new Vector3f(max);
        dimensions.add(min);
        dimensions.scale(0.5f);
        return dimensions;
    }

    public Vector3f getMin() {
        return new Vector3f(min);
    }

    public Vector3f getMax() {
        return new Vector3f(max);
    }

    public AABB move(Vector3f offset) {
        Vector3f newMin = new Vector3f(min);
        newMin.add(offset);
        Vector3f newMax = new Vector3f(max);
        newMax.add(offset);
        return new AABB(newMin, newMax);
    }

    public AABB transform(Quat4f rotation, Vector3f offset, float scale) {
        Transform transform = new Transform(new Matrix4f(rotation, offset, scale));
        Vector3f newMin = new Vector3f();
        Vector3f newMax = new Vector3f();
        AabbUtil2.transformAabb(min, max, 0.01f, transform, newMin, newMax);
        return new AABB(newMin, newMax);
    }

    public AABB transform(Transform transform) {
        Vector3f newMin = new Vector3f();
        Vector3f newMax = new Vector3f();
        AabbUtil2.transformAabb(min, max, 0.01f, transform, newMin, newMax);
        return new AABB(newMin, newMax);
    }

    /**
     * Returns true if this AABB overlaps the given AABB.
     *
     * @param aabb2 The AABB to check for overlapping
     * @return True if overlapping
     */
    public boolean overlaps(AABB aabb2) {
        return !(max.x < aabb2.min.x || min.x > aabb2.max.x)
                && !(max.y < aabb2.min.y || min.y > aabb2.max.y)
                && !(max.z < aabb2.min.z || min.z > aabb2.max.z);
    }

    /**
     * Returns true if the AABB contains the given point.
     *
     * @param point The point to check for inclusion
     * @return True if containing
     */
    public boolean contains(Vector3d point) {
        return !(max.x < point.x || min.x >= point.x)
                && !(max.y < point.y || min.y >= point.y)
                && !(max.z < point.z || min.z >= point.z);
    }

    /**
     * Returns true if the AABB contains the given point.
     *
     * @param point The point to check for inclusion
     * @return True if containing
     */
    public boolean contains(Vector3f point) {
        return !(max.x < point.x || min.x >= point.x)
                && !(max.y < point.y || min.y >= point.y)
                && !(max.z < point.z || min.z >= point.z);
    }

    /**
     * Returns the closest point on the AABB to a given point.
     *
     * @param p The point
     * @return The point on the AABB closest to the given point
     */
    public Vector3f closestPointOnAABBToPoint(Vector3f p) {
        Vector3f r = new Vector3f(p);

        if (p.x < min.x) {
            r.x = min.x;
        }
        if (p.x > max.x) {
            r.x = max.x;
        }
        if (p.y < min.y) {
            r.y = min.y;
        }
        if (p.y > max.y) {
            r.y = max.y;
        }
        if (p.z < min.z) {
            r.z = min.z;
        }
        if (p.z > max.z) {
            r.z = max.z;
        }

        return r;
    }

    public Vector3f getFirstHitPlane(Vector3f direction, Vector3f pos, Vector3f dimensions, boolean testX, boolean testY, boolean testZ) {
        Vector3f hitNormal = new Vector3f();

        float dist = Float.POSITIVE_INFINITY;

        if (testX) {
            float distX;
            if (direction.x > 0) {
                distX = (min.x - pos.x - dimensions.x) / direction.x;
            } else {
                distX = (max.x - pos.x + dimensions.x) / direction.x;
            }
            if (distX >= 0 && distX < dist) {
                hitNormal.set(Math.copySign(1, direction.x), 0, 0);
            }
        }
        if (testY) {
            float distY;
            if (direction.y > 0) {
                distY = (min.y - pos.y - dimensions.y) / direction.y;
            } else {
                distY = (max.y - pos.y + dimensions.y) / direction.y;
            }
            if (distY >= 0 && distY < dist) {
                hitNormal.set(0, Math.copySign(1, direction.y), 0);
            }
        }
        if (testZ) {
            float distZ;
            if (direction.z > 0) {
                distZ = (min.z - pos.z - dimensions.z) / direction.z;
            } else {
                distZ = (max.z - pos.z + dimensions.z) / direction.z;
            }
            if (distZ >= 0 && distZ < dist) {
                hitNormal.set(0, 0, Math.copySign(1, direction.z));
            }
        }
        return hitNormal;

    }

    /**
     * Returns the normal of the plane closest to the given origin.
     *
     * @param pointOnAABB A point on the AABB
     * @param origin      The origin
     * @param testX       True if the x-axis should be tested
     * @param testY       True if the y-axis should be tested
     * @param testZ       True if the z-axis should be tested
     * @return The normal
     */
    public Vector3f normalForPlaneClosestToOrigin(Vector3f pointOnAABB, Vector3f origin, boolean testX, boolean testY, boolean testZ) {
        List<Vector3f> normals = new ArrayList<>();

        if (pointOnAABB.z == min.z && testZ) {
            normals.add(new Vector3f(0, 0, -1));
        }
        if (pointOnAABB.z == max.z && testZ) {
            normals.add(new Vector3f(0, 0, 1));
        }
        if (pointOnAABB.x == min.x && testX) {
            normals.add(new Vector3f(-1, 0, 0));
        }
        if (pointOnAABB.x == max.x && testX) {
            normals.add(new Vector3f(1, 0, 0));
        }
        if (pointOnAABB.y == min.y && testY) {
            normals.add(new Vector3f(0, -1, 0));
        }
        if (pointOnAABB.y == max.y && testY) {
            normals.add(new Vector3f(0, 1, 0));
        }

        float minDistance = Float.MAX_VALUE;
        Vector3f closestNormal = new Vector3f();

        for (int i = 0; i < normals.size(); i++) {
            Vector3f n = normals.get(i);

            Vector3f diff = new Vector3f(centerPointForNormal(n));
            diff.sub(origin);

            float distance = diff.length();

            if (distance < minDistance) {
                minDistance = distance;
                closestNormal = n;
            }
        }

        return closestNormal;
    }

    /**
     * Returns the center point of one of the six planes for the given normal.
     *
     * @param normal The normal
     * @return The center point
     */
    public Vector3f centerPointForNormal(Vector3f normal) {
        if (normal.x == 1 && normal.y == 0 && normal.z == 0) {
            return new Vector3f(max.x, getCenter().y, getCenter().z);
        }
        if (normal.x == -1 && normal.y == 0 && normal.z == 0) {
            return new Vector3f(min.x, getCenter().y, getCenter().z);
        }
        if (normal.x == 0 && normal.y == 0 && normal.z == 1) {
            return new Vector3f(getCenter().x, getCenter().y, max.z);
        }
        if (normal.x == 0 && normal.y == 0 && normal.z == -1) {
            return new Vector3f(getCenter().x, getCenter().y, min.z);
        }
        if (normal.x == 0 && normal.y == 1 && normal.z == 0) {
            return new Vector3f(getCenter().x, max.y, getCenter().z);
        }
        if (normal.x == 0 && normal.y == -1 && normal.z == 0) {
            return new Vector3f(getCenter().x, min.y, getCenter().z);
        }

        return new Vector3f();
    }

    public float minX() {
        return min.x;
    }

    public float minY() {
        return min.y;
    }

    public float minZ() {
        return min.z;
    }

    public float maxX() {
        return max.x;
    }

    public float maxY() {
        return max.y;
    }

    public float maxZ() {
        return max.z;
    }

    /**
     * Returns the vertices of this AABB.
     *
     * @return The vertices
     */
    public Vector3f[] getVertices() {
        if (vertices == null) {
            vertices = new Vector3f[8];

            // Front
            vertices[0] = new Vector3f(min.x, min.y, max.z);
            vertices[1] = new Vector3f(max.x, min.y, max.z);
            vertices[2] = new Vector3f(max.x, max.y, max.z);
            vertices[3] = new Vector3f(min.x, max.y, max.z);
            // Back
            vertices[4] = new Vector3f(min.x, min.y, min.z);
            vertices[5] = new Vector3f(max.x, min.y, min.z);
            vertices[6] = new Vector3f(max.x, max.y, min.z);
            vertices[7] = new Vector3f(min.x, max.y, min.z);
        }

        return vertices;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj instanceof AABB) {
            AABB other = (AABB) obj;
            return Objects.equal(min, other.min) && Objects.equal(max, other.max);
        }
        return false;
    }

    public int hashCode() {
        return Objects.hashCode(min, max);
    }

    public boolean intersectRectangle(Vector3f from, Vector3f direction) {
        Vector3f dirfrac = new Vector3f();

        dirfrac.x = 1.0f / direction.x;
        dirfrac.y = 1.0f / direction.y;
        dirfrac.z = 1.0f / direction.z;

        float t1 = (min.x - from.x) * dirfrac.x;
        float t2 = (max.x - from.x) * dirfrac.x;
        float t3 = (min.y - from.y) * dirfrac.y;
        float t4 = (max.y - from.y) * dirfrac.y;
        float t5 = (min.z - from.z) * dirfrac.z;
        float t6 = (max.z - from.z) * dirfrac.z;

        float tmin = Math.max(Math.max(Math.min(t1, t2), Math.min(t3, t4)), Math.min(t5, t6));
        float tmax = Math.min(Math.min(Math.max(t1, t2), Math.max(t3, t4)), Math.max(t5, t6));

        if (tmax < 0) {
            return false;
        }

        if (tmin > tmax) {
            return false;
        }

        return true;
    }
}
TOP

Related Classes of org.terasology.math.AABB

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.