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

org.dyn4j.geometry.AABB Maven / Gradle / Ivy

/*
 * Copyright (c) 2010-2013 William Bittle  http://www.dyn4j.org/
 * 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 dyn4j 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 org.dyn4j.geometry;

import org.dyn4j.resources.Messages;

/**
 * Represents an axis aligned bounding box.
 * @author William Bittle
 * @version 3.1.5
 * @since 3.0.0
 */
public class AABB {
	/** The minimum extent */
	protected Vector2 min;
	
	/** The maximum extent */
	protected Vector2 max;
	
	/**
	 * Full constructor.
	 * @param minX the minimum x extent
	 * @param minY the minimum y extent
	 * @param maxX the maximum x extent
	 * @param maxY the maximum y extent
	 */
	public AABB(double minX, double minY, double maxX, double maxY) {
		this(new Vector2(minX, minY), new Vector2(maxX, maxY));
	}
	
	/**
	 * Full constructor.
	 * @param min the minimum extent
	 * @param max the maximum extent
	 */
	public AABB(Vector2 min, Vector2 max) {
		// check the min and max
		if (min.x > max.x || min.y > max.y) throw new IllegalArgumentException(Messages.getString("geometry.aabb.invalidMinMax"));
		this.min = min;
		this.max = max;
	}
	
	/**
	 * Full constructor.
	 * @param radius the radius of a circle fitting inside an AABB
	 * @since 3.1.5
	 */
	public AABB(double radius) {
		this(null, radius);
	}
	
	/**
	 * Full constructor.
	 * 

* Creates an AABB for a circle with the given center and radius. * @param center the center of the circle * @param radius the radius of the circle * @since 3.1.5 */ public AABB(Vector2 center, double radius) { if (radius < 0) throw new IllegalArgumentException(Messages.getString("geometry.aabb.invalidRadius")); if (center == null) { this.min = new Vector2(-radius, -radius); this.max = new Vector2( radius, radius); } else { this.min = new Vector2(center.x - radius, center.y - radius); this.max = new Vector2(center.x + radius, center.y + radius); } } /** * Copy constructor. * @param aabb the {@link AABB} to copy * @since 3.1.1 */ public AABB(AABB aabb) { this.min = aabb.min.copy(); this.max = aabb.max.copy(); } /* (non-Javadoc) * @see java.lang.Object#toString() */ @Override public String toString() { StringBuilder sb = new StringBuilder(); sb.append("AABB[Min=").append(this.min) .append("|Max=").append(this.max) .append("]"); return sb.toString(); } /** * Translates the AABB by the given translation. * @param translation the translation * @since 3.1.0 */ public void translate(Vector2 translation) { this.max.add(translation); this.min.add(translation); } /** * Returns a new AABB of this AABB translated by the * given translation amount. * @param translation the translation * @return AABB * @since 3.1.1 */ public AABB getTranslated(Vector2 translation) { return new AABB( this.min.sum(translation), this.max.sum(translation)); } /** * Returns the width of this {@link AABB}. * @return double * @since 3.0.1 */ public double getWidth() { return this.max.x - this.min.x; } /** * Returns the height of this {@link AABB}. * @return double * @since 3.0.1 */ public double getHeight() { return this.max.y - this.min.y; } /** * Returns the perimeter of this {@link AABB}. * @return double */ public double getPerimeter() { return 2 * (this.max.x - this.min.x + this.max.y - this.min.y); } /** * Returns the area of this {@link AABB};. * @return double */ public double getArea() { return (this.max.x - this.min.x) * (this.max.y - this.min.y); } /** * Performs a union of this {@link AABB} and the given {@link AABB} placing * the result of the union into this {@link AABB}. * @param aabb the {@link AABB} to union */ public void union(AABB aabb) { this.min.x = Math.min(this.min.x, aabb.min.x); this.min.y = Math.min(this.min.y, aabb.min.y); this.max.x = Math.max(this.max.x, aabb.max.x); this.max.y = Math.max(this.max.y, aabb.max.y); } /** * Performs a union of this {@link AABB} and the given {@link AABB} returning * a new {@link AABB} containing the result. * @param aabb the {@link AABB} to union * @return {@link AABB} the resulting union */ public AABB getUnion(AABB aabb) { Vector2 min = new Vector2(); Vector2 max = new Vector2(); min.x = Math.min(this.min.x, aabb.min.x); min.y = Math.min(this.min.y, aabb.min.y); max.x = Math.max(this.max.x, aabb.max.x); max.y = Math.max(this.max.y, aabb.max.y); return new AABB(min, max); } /** * Performs the intersection of this {@link AABB} and the given {@link AABB} placing * the result into this {@link AABB}. *

* If the given {@link AABB} does not overlap this {@link AABB}, this {@link AABB} is * set to a zero {@link AABB}. * @param aabb the {@link AABB} to intersect * @since 3.1.1 */ public void intersection(AABB aabb) { this.min.x = Math.max(this.min.x, aabb.min.x); this.min.y = Math.max(this.min.y, aabb.min.y); this.max.x = Math.min(this.max.x, aabb.max.x); this.max.y = Math.min(this.max.y, aabb.max.y); // check for a bad AABB if (this.min.x > this.max.x || this.min.y > this.max.y) { // the two AABBs were not overlapping // set this AABB to a degenerate one this.min.x = 0.0; this.min.y = 0.0; this.max.x = 0.0; this.max.y = 0.0; } } /** * Performs the intersection of this {@link AABB} and the given {@link AABB} returning * the result in a new {@link AABB}. *

* If the given {@link AABB} does not overlap this {@link AABB}, a zero {@link AABB} is * returned. * @param aabb the {@link AABB} to intersect * @return {@link AABB} * @since 3.1.1 */ public AABB getIntersection(AABB aabb) { Vector2 min = new Vector2(); Vector2 max = new Vector2(); min.x = Math.max(this.min.x, aabb.min.x); min.y = Math.max(this.min.y, aabb.min.y); max.x = Math.min(this.max.x, aabb.max.x); max.y = Math.min(this.max.y, aabb.max.y); // check for a bad AABB if (min.x > max.x || min.y > max.y) { // the two AABBs were not overlapping // return a degenerate one return new AABB(new Vector2(), new Vector2()); } return new AABB(min, max); } /** * Expands this {@link AABB} by half the given expansion in each direction. *

* The expansion can be negative to shrink the {@link AABB}. However, if the expansion is * greater than the current width/height, the {@link AABB} can become invalid. In this * case, the AABB will become a degenerate AABB at the mid point of the min and max for * the respective coordinates. * @param expansion the expansion amount */ public void expand(double expansion) { double e = expansion * 0.5; this.min.x -= e; this.min.y -= e; this.max.x += e; this.max.y += e; // we only need to verify the new aabb if the expansion // was inwardly if (expansion < 0.0) { // if the aabb is invalid then set the min/max(es) to // the middle value of their current values if (this.min.x > this.max.x) { double mid = (this.min.x + this.max.x) * 0.5; this.min.x = mid; this.max.x = mid; } if (this.min.y > this.max.y) { double mid = (this.min.y + this.max.y) * 0.5; this.min.y = mid; this.max.y = mid; } } } /** * Returns a new {@link AABB} of this AABB expanded by half the given expansion * in both the x and y directions. *

* The expansion can be negative to shrink the {@link AABB}. However, if the expansion is * greater than the current width/height, the {@link AABB} can become invalid. In this * case, the AABB will become a degenerate AABB at the mid point of the min and max for * the respective coordinates. * @param expansion the expansion amount * @return {@link AABB} * @since 3.1.1 */ public AABB getExpanded(double expansion) { double e = expansion * 0.5; double minx = this.min.x - e; double miny = this.min.y - e; double maxx = this.max.x + e; double maxy = this.max.y + e; // we only need to verify the new aabb if the expansion // was inwardly if (expansion < 0.0) { // if the aabb is invalid then set the min/max(es) to // the middle value of their current values if (minx > maxx) { double mid = (minx + maxx) * 0.5; minx = mid; maxx = mid; } if (miny > maxy) { double mid = (miny + maxy) * 0.5; miny = mid; maxy = mid; } } return new AABB( new Vector2(minx, miny), new Vector2(maxx, maxy)); } /** * Returns true if the given {@link AABB} and this {@link AABB} overlap. * @param aabb the {@link AABB} to test * @return boolean true if the {@link AABB}s overlap */ public boolean overlaps(AABB aabb) { // check for overlap along the x-axis if (this.min.x > aabb.max.x || this.max.x < aabb.min.x) { // the aabbs do not overlap along the x-axis return false; } else { // check for overlap along the y-axis if (this.min.y > aabb.max.y || this.max.y < aabb.min.y) { // the aabbs do not overlap along the y-axis return false; } else { return true; } } } /** * Returns true if the given {@link AABB} is contained within this {@link AABB}. * @param aabb the {@link AABB} to test * @return boolean */ public boolean contains(AABB aabb) { if (this.min.x <= aabb.min.x && this.max.x >= aabb.max.x) { if (this.min.y <= aabb.min.y && this.max.y >= aabb.max.y) { return true; } } return false; } /** * Returns true if the given point is contained within this {@link AABB}. * @param point the point to test * @return boolean * @since 3.1.1 */ public boolean contains(Vector2 point) { return this.contains(point.x, point.y); } /** * Returns true if the given point's coordinates are contained within this {@link AABB}. * @param x the x coordinate of the point * @param y the y coordinate of the point * @return boolean * @since 3.1.1 */ public boolean contains(double x, double y) { if (this.min.x <= x && this.max.x >= x) { if (this.min.y <= y && this.max.y >= y) { return true; } } return false; } /** * Returns true if this {@link AABB} is degenerate. *

* A degenerate {@link AABB} is one where its min and max x or y * coordinates are equal. * @return boolean * @since 3.1.1 */ public boolean isDegenerate() { return this.min.x == this.max.x || this.min.y == this.max.y; } /** * Returns true if this {@link AABB} is degenerate given * the specified error. *

* An {@link AABB} is degenerate given some error if * max - min <= error for either the x or y coordinate. * @param error the allowed error * @return boolean * @since 3.1.1 * @see #isDegenerate() */ public boolean isDegenerate(double error) { return Math.abs(this.max.x - this.min.x) <= error || Math.abs(this.max.y - this.min.y) <= error; } /** * Returns the minimum x extent. * @return double */ public double getMinX() { return this.min.x; } /** * Returns the maximum x extent. * @return double */ public double getMaxX() { return this.max.x; } /** * Returns the maximum y extent. * @return double */ public double getMaxY() { return this.max.y; } /** * Returns the minimum y extent. * @return double */ public double getMinY() { return this.min.y; } }





© 2015 - 2025 Weber Informatics LLC | Privacy Policy