org.mini2Dx.gdx.math.Rectangle Maven / Gradle / Ivy
/*******************************************************************************
* Copyright 2011 See AUTHORS file.
*
* 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.mini2Dx.gdx.math;
import java.io.Serializable;
import org.mini2Dx.gdx.utils.GdxRuntimeException;
import org.mini2Dx.gdx.utils.NumberUtils;
/** Encapsulates a 2D rectangle defined by its corner point in the bottom left and its extents in x (width) and y (height).
* @author [email protected] */
public class Rectangle implements Serializable, Shape2D {
/** Static temporary rectangle. Use with care! Use only when sure other code will not also use this. */
static public final Rectangle tmp = new Rectangle();
/** Static temporary rectangle. Use with care! Use only when sure other code will not also use this. */
static public final Rectangle tmp2 = new Rectangle();
private static final long serialVersionUID = 5733252015138115702L;
public float x, y;
public float width, height;
/** Constructs a new rectangle with all values set to zero */
public Rectangle () {
}
/** Constructs a new rectangle with the given corner point in the bottom left and dimensions.
* @param x The corner point x-coordinate
* @param y The corner point y-coordinate
* @param width The width
* @param height The height */
public Rectangle (float x, float y, float width, float height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
}
/** Constructs a rectangle based on the given rectangle
* @param rect The rectangle */
public Rectangle (Rectangle rect) {
x = rect.x;
y = rect.y;
width = rect.width;
height = rect.height;
}
/** @param x bottom-left x coordinate
* @param y bottom-left y coordinate
* @param width width
* @param height height
* @return this rectangle for chaining */
public Rectangle set (float x, float y, float width, float height) {
this.x = x;
this.y = y;
this.width = width;
this.height = height;
return this;
}
/** @return the x-coordinate of the bottom left corner */
public float getX () {
return x;
}
/** Sets the x-coordinate of the bottom left corner
* @param x The x-coordinate
* @return this rectangle for chaining */
public Rectangle setX (float x) {
this.x = x;
return this;
}
/** @return the y-coordinate of the bottom left corner */
public float getY () {
return y;
}
/** Sets the y-coordinate of the bottom left corner
* @param y The y-coordinate
* @return this rectangle for chaining */
public Rectangle setY (float y) {
this.y = y;
return this;
}
/** @return the width */
public float getWidth () {
return width;
}
/** Sets the width of this rectangle
* @param width The width
* @return this rectangle for chaining */
public Rectangle setWidth (float width) {
this.width = width;
return this;
}
/** @return the height */
public float getHeight () {
return height;
}
/** Sets the height of this rectangle
* @param height The height
* @return this rectangle for chaining */
public Rectangle setHeight (float height) {
this.height = height;
return this;
}
/** return the Vector2 with coordinates of this rectangle
* @param position The Vector2 */
public Vector2 getPosition (Vector2 position) {
return position.set(x, y);
}
/** Sets the x and y-coordinates of the bottom left corner from vector
* @param position The position vector
* @return this rectangle for chaining */
public Rectangle setPosition (Vector2 position) {
this.x = position.x;
this.y = position.y;
return this;
}
/** Sets the x and y-coordinates of the bottom left corner
* @param x The x-coordinate
* @param y The y-coordinate
* @return this rectangle for chaining */
public Rectangle setPosition (float x, float y) {
this.x = x;
this.y = y;
return this;
}
/** Sets the width and height of this rectangle
* @param width The width
* @param height The height
* @return this rectangle for chaining */
public Rectangle setSize (float width, float height) {
this.width = width;
this.height = height;
return this;
}
/** Sets the squared size of this rectangle
* @param sizeXY The size
* @return this rectangle for chaining */
public Rectangle setSize (float sizeXY) {
this.width = sizeXY;
this.height = sizeXY;
return this;
}
/** @return the Vector2 with size of this rectangle
* @param size The Vector2 */
public Vector2 getSize (Vector2 size) {
return size.set(width, height);
}
/** @param x point x coordinate
* @param y point y coordinate
* @return whether the point is contained in the rectangle */
public boolean contains (float x, float y) {
return this.x <= x && this.x + this.width >= x && this.y <= y && this.y + this.height >= y;
}
/** @param point The coordinates vector
* @return whether the point is contained in the rectangle */
public boolean contains (Vector2 point) {
return contains(point.x, point.y);
}
/** @param circle the circle
* @return whether the circle is contained in the rectangle */
public boolean contains (Circle circle) {
return (circle.x - circle.radius >= x) && (circle.x + circle.radius <= x + width)
&& (circle.y - circle.radius >= y) && (circle.y + circle.radius <= y + height);
}
/** @param rectangle the other {@link Rectangle}.
* @return whether the other rectangle is contained in this rectangle. */
public boolean contains (Rectangle rectangle) {
float xmin = rectangle.x;
float xmax = xmin + rectangle.width;
float ymin = rectangle.y;
float ymax = ymin + rectangle.height;
return ((xmin > x && xmin < x + width) && (xmax > x && xmax < x + width))
&& ((ymin > y && ymin < y + height) && (ymax > y && ymax < y + height));
}
/** @param r the other {@link Rectangle}
* @return whether this rectangle overlaps the other rectangle. */
public boolean overlaps (Rectangle r) {
return x < r.x + r.width && x + width > r.x && y < r.y + r.height && y + height > r.y;
}
/** Sets the values of the given rectangle to this rectangle.
* @param rect the other rectangle
* @return this rectangle for chaining */
public Rectangle set (Rectangle rect) {
this.x = rect.x;
this.y = rect.y;
this.width = rect.width;
this.height = rect.height;
return this;
}
/** Merges this rectangle with the other rectangle. The rectangle should not have negative width or negative height.
* @param rect the other rectangle
* @return this rectangle for chaining */
public Rectangle merge (Rectangle rect) {
float minX = Math.min(x, rect.x);
float maxX = Math.max(x + width, rect.x + rect.width);
x = minX;
width = maxX - minX;
float minY = Math.min(y, rect.y);
float maxY = Math.max(y + height, rect.y + rect.height);
y = minY;
height = maxY - minY;
return this;
}
/** Merges this rectangle with a point. The rectangle should not have negative width or negative height.
* @param x the x coordinate of the point
* @param y the y coordinate of the point
* @return this rectangle for chaining */
public Rectangle merge (float x, float y) {
float minX = Math.min(this.x, x);
float maxX = Math.max(this.x + width, x);
this.x = minX;
this.width = maxX - minX;
float minY = Math.min(this.y, y);
float maxY = Math.max(this.y + height, y);
this.y = minY;
this.height = maxY - minY;
return this;
}
/** Merges this rectangle with a point. The rectangle should not have negative width or negative height.
* @param vec the vector describing the point
* @return this rectangle for chaining */
public Rectangle merge (Vector2 vec) {
return merge(vec.x, vec.y);
}
/** Merges this rectangle with a list of points. The rectangle should not have negative width or negative height.
* @param vecs the vectors describing the points
* @return this rectangle for chaining */
public Rectangle merge (Vector2[] vecs) {
float minX = x;
float maxX = x + width;
float minY = y;
float maxY = y + height;
for (int i = 0; i < vecs.length; ++i) {
Vector2 v = vecs[i];
minX = Math.min(minX, v.x);
maxX = Math.max(maxX, v.x);
minY = Math.min(minY, v.y);
maxY = Math.max(maxY, v.y);
}
x = minX;
width = maxX - minX;
y = minY;
height = maxY - minY;
return this;
}
/** Calculates the aspect ratio ( width / height ) of this rectangle
* @return the aspect ratio of this rectangle. Returns Float.NaN if height is 0 to avoid ArithmeticException */
public float getAspectRatio () {
return (height == 0) ? Float.NaN : width / height;
}
/** Calculates the center of the rectangle. Results are located in the given Vector2
* @param vector the Vector2 to use
* @return the given vector with results stored inside */
public Vector2 getCenter (Vector2 vector) {
vector.x = x + width / 2;
vector.y = y + height / 2;
return vector;
}
/** Moves this rectangle so that its center point is located at a given position
* @param x the position's x
* @param y the position's y
* @return this for chaining */
public Rectangle setCenter (float x, float y) {
setPosition(x - width / 2, y - height / 2);
return this;
}
/** Moves this rectangle so that its center point is located at a given position
* @param position the position
* @return this for chaining */
public Rectangle setCenter (Vector2 position) {
setPosition(position.x - width / 2, position.y - height / 2);
return this;
}
/** Fits this rectangle around another rectangle while maintaining aspect ratio. This scales and centers the rectangle to the
* other rectangle (e.g. Having a camera translate and scale to show a given area)
* @param rect the other rectangle to fit this rectangle around
* @return this rectangle for chaining
* @see Scaling */
public Rectangle fitOutside (Rectangle rect) {
float ratio = getAspectRatio();
if (ratio > rect.getAspectRatio()) {
// Wider than tall
setSize(rect.height * ratio, rect.height);
} else {
// Taller than wide
setSize(rect.width, rect.width / ratio);
}
setPosition((rect.x + rect.width / 2) - width / 2, (rect.y + rect.height / 2) - height / 2);
return this;
}
/** Fits this rectangle into another rectangle while maintaining aspect ratio. This scales and centers the rectangle to the
* other rectangle (e.g. Scaling a texture within a arbitrary cell without squeezing)
* @param rect the other rectangle to fit this rectangle inside
* @return this rectangle for chaining
* @see Scaling */
public Rectangle fitInside (Rectangle rect) {
float ratio = getAspectRatio();
if (ratio < rect.getAspectRatio()) {
// Taller than wide
setSize(rect.height * ratio, rect.height);
} else {
// Wider than tall
setSize(rect.width, rect.width / ratio);
}
setPosition((rect.x + rect.width / 2) - width / 2, (rect.y + rect.height / 2) - height / 2);
return this;
}
/** Converts this {@code Rectangle} to a string in the format {@code [x,y,width,height]}.
* @return a string representation of this object. */
public String toString () {
return "[" + x + "," + y + "," + width + "," + height + "]";
}
/** Sets this {@code Rectangle} to the value represented by the specified string according to the format of {@link #toString()}
* .
* @param v the string.
* @return this rectangle for chaining */
public Rectangle fromString (String v) {
int s0 = v.indexOf(',', 1);
int s1 = v.indexOf(',', s0 + 1);
int s2 = v.indexOf(',', s1 + 1);
if (s0 != -1 && s1 != -1 && s2 != -1 && v.charAt(0) == '[' && v.charAt(v.length() - 1) == ']') {
try {
float x = Float.parseFloat(v.substring(1, s0));
float y = Float.parseFloat(v.substring(s0 + 1, s1));
float width = Float.parseFloat(v.substring(s1 + 1, s2));
float height = Float.parseFloat(v.substring(s2 + 1, v.length() - 1));
return this.set(x, y, width, height);
} catch (NumberFormatException ex) {
// Throw a GdxRuntimeException
}
}
throw new GdxRuntimeException("Malformed Rectangle: " + v);
}
public float area () {
return this.width * this.height;
}
public float perimeter () {
return 2 * (this.width + this.height);
}
public int hashCode () {
final int prime = 31;
int result = 1;
result = prime * result + NumberUtils.floatToRawIntBits(height);
result = prime * result + NumberUtils.floatToRawIntBits(width);
result = prime * result + NumberUtils.floatToRawIntBits(x);
result = prime * result + NumberUtils.floatToRawIntBits(y);
return result;
}
public boolean equals (Object obj) {
if (this == obj) return true;
if (obj == null) return false;
if (getClass() != obj.getClass()) return false;
Rectangle other = (Rectangle)obj;
if (NumberUtils.floatToRawIntBits(height) != NumberUtils.floatToRawIntBits(other.height)) return false;
if (NumberUtils.floatToRawIntBits(width) != NumberUtils.floatToRawIntBits(other.width)) return false;
if (NumberUtils.floatToRawIntBits(x) != NumberUtils.floatToRawIntBits(other.x)) return false;
if (NumberUtils.floatToRawIntBits(y) != NumberUtils.floatToRawIntBits(other.y)) return false;
return true;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy