package xapi.ui.api;
import static xapi.ui.api.Coord.coord;
import javax.validation.constraints.NotNull;
import java.util.function.IntSupplier;
/**
* A class meant to contain an x,y position, and a w,h size.
*
* Uses ui-standard top,left for x,y,
* with always positive w,h for width and height.
*
* Any negative size supplied will be normalized to a positive size.
*
* Created by James X. Nelson (james @wetheinter.net) on 7/31/16.
*/
public final class Rect {
private final Coord pos;
private final Coord size;
private IntSupplier hash;
public Rect(@NotNull Coord position, @NotNull Coord size) {
assert position != null;
assert size != null;
if (size.bothPositive()) {
this.pos = position;
this.size = size;
} else {
final double x, y, w, h;
if (size.getX() < 0) {
x = position.getX() + size.getX();
w = -size.getX();
} else {
x = position.getX();
w = size.getX();
}
if (size.getY() < 0) {
y = position.getY() + size.getY();
h = -size.getY();
} else {
y = position.getY();
h = size.getY();
}
this.pos = coord(x, y);
this.size = coord(w, h);
}
hash = () -> {
int base = 7;
base = base*31 + pos.hashCode();
base = base*31 + this.size.hashCode();
int value = base;
hash = ()->value;
return value;
};
}
public Rect(Coord position, double width, double height) {
this(position, coord(width, height));
}
public Rect(double x, double y, double width, double height) {
this(coord(x, y), coord(width, height));
}
public Rect(double x, double y, Coord size) {
this(coord(x, y), size);
}
public static Rect normalized(Coord point1, Coord point2){
final double x, y, w, h;
if (point1.getX() > point2.getX()) {
x = point2.getX();
w = point1.getX() - x;
} else {
x = point1.getX();
w = point2.getX() - x;
}
if (point1.getY() > point2.getY()) {
y = point2.getY();
h = point1.getY() - y;
} else {
y = point1.getY();
h = point2.getY() - y;
}
return new Rect(x, y, w, h);
}
double getLeft() {
return pos.getX();
}
double getTop() {
return pos.getY();
}
double getRight() {
return pos.getX() + size.getX();
}
double getBottom() {
return pos.getY() + size.getY();
}
double getWidth() {
return size.getX();
}
double getHeight() {
return size.getY();
}
public Rect addPosition(double x, double y) {
if (x == 0 && y == 0) {
return this;
}
return new Rect(coord(getLeft() + x, getTop() + y), size);
}
public Rect subtractPosition(double x, double y) {
if (x == 0 && y == 0) {
return this;
}
return new Rect(coord(getLeft() - x, getTop() - y), size);
}
public Rect addSize(double x, double y) {
if (x == 0 && y == 0) {
return this;
}
return new Rect(pos, coord(getWidth() + x, getWidth() + y));
}
public Rect subtractSize(double x, double y) {
if (x == 0 && y == 0) {
return this;
}
return new Rect(pos, coord(getWidth() - x, getWidth() - y));
}
public boolean contains(double x, double y) {
if (x < getLeft() || x > getRight()) {
return false;
}
if (y < getTop() || x > getBottom()) {
return false;
}
return true;
}
public boolean contains(Coord pos) {
return contains(pos.getX(), pos.getY());
}
public boolean contains(Rect rect) {
if (rect.getLeft() < getLeft()) {
return false;
}
if (rect.getRight() > getRight()) {
return false;
}
if (rect.getTop() < getTop()) {
return false;
}
if (rect.getBottom() > getBottom()) {
return false;
}
return true;
}
public boolean overlaps(Rect rect) {
if (rect.getRight() < getLeft()) {
return false;
}
if (rect.getLeft() > getRight()) {
return false;
}
if (rect.getBottom() < getTop()) {
return false;
}
if (rect.getTop() > getBottom()) {
return false;
}
return true;
}
public boolean isEmpty() {
return size.isZero();
}
@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof Rect))
return false;
final Rect rect = (Rect) o;
if (!pos.equals(rect.pos))
return false;
return size.equals(rect.size);
}
@Override
public int hashCode() {
return hash.getAsInt();
}
@Override
public String toString() {
return "{ x: " + getLeft() + ", y: " + getTop() + ", w: " + getWidth() + ", h: " + getHeight() + "}";
}
}