package com.project.shared.data;
import java.io.Serializable;
import com.google.gwt.user.client.rpc.IsSerializable;
import com.project.shared.interfaces.ICloneable;
import com.project.shared.utils.PolygonUtils;
public class Rectangle implements ICloneable<Rectangle>, Serializable, IsSerializable {
public class Corners {
public final Point2D topRight;
public final Point2D bottomRight;
public final Point2D bottomLeft;
public final Point2D topLeft;
public Corners(Point2D topRight, Point2D bottomRight, Point2D bottomLeft, Point2D topLeft)
{
this.topRight = topRight;
this.bottomRight = bottomRight;
this.bottomLeft = bottomLeft;
this.topLeft = topLeft;
}
public Point2D[] asArray()
{
return new Point2D[] { this.topRight, this.bottomRight, this.bottomLeft, this.topLeft };
}
}
/**
*
*/
private static final long serialVersionUID = 1L;
public static final Rectangle empty = new Rectangle(0, 0, 0, 0);
private int left = 0;
private int top = 0;
private int right = 0;
private int bottom = 0;
/* Rotation axis is center */
private double rotation = 0;
public Rectangle() {
this(0, 0, 0, 0);
}
public Rectangle(int left, int top, int size) {
this(left, top, left + size, top + size);
}
public Rectangle(int left, int top, int right, int bottom) {
this(left, top, right, bottom, 0);
}
public Rectangle(int left, int top, int right, int bottom, double rotation) {
this.left = left;
this.top = top;
this.right = right;
this.bottom = bottom;
this.rotation = rotation;
}
public Rectangle(Rectangle rectangle)
{
this(rectangle.getLeft(), rectangle.getTop(),
rectangle.getRight(), rectangle.getBottom(), rectangle.getRotation());
}
public Rectangle(Point2D topLeft, Point2D bottomRight)
{
this(topLeft.getX(), topLeft.getY(),
bottomRight.getX(), bottomRight.getY());
}
public boolean contains(Point2D point) {
// We compare by rotating the point to axis of the rectangle.
// An alternative implementation using crossing number or winding number may be more efficient
// see http://softsurfer.com/Archive/algorithm_0103/algorithm_0103.htm
Point2D rotatedPoint = point.getRotated(-Math.toRadians(rotation), getCenter());
int px = rotatedPoint.getX();
int py = rotatedPoint.getY();
return ((px >= left) && (px <= right) && (py <= bottom) && (py >= top));
}
@Override
public boolean equals(Object other) {
if (null == other) {
return false;
}
if (other.getClass() != this.getClass()) {
return false;
}
Rectangle otherRectangle = (Rectangle)other;
return ((this.bottom == otherRectangle.bottom) &&
(this.left == otherRectangle.left) &&
(this.right == otherRectangle.right) &&
(this.top == otherRectangle.top ) &&
(this.rotation == otherRectangle.rotation));
}
/**
* @return radius of smallest circle containing the rectangle
*/
public double externalRadius()
{
Point2D corner = new Point2D(right, top);
return corner.minus(getCenter()).getRadius();
}
public int getBottom()
{
return this.bottom;
}
public Point2D getCenter() {
return new Point2D((left + right) / 2, (top + bottom) / 2);
}
@Override
public Rectangle getClone()
{
return new Rectangle(this);
}
/**
* @return the actual positions of the corners taking rotation of the rectangle into account.
*/
public Corners getCorners() {
Point2D[] corners = new Point2D[] {
new Point2D(right, top),
new Point2D(right, bottom),
new Point2D(left, bottom),
new Point2D(left, top)
};
for (int i = 0; i < corners.length; i++) {
corners[i] = corners[i].getRotated(Math.toRadians(rotation), getCenter());
}
return new Corners(corners[0], corners[1], corners[2], corners[3]);
}
public int getLeft()
{
return this.left;
}
public int getRight()
{
return this.right;
}
public double getRotation()
{
return rotation;
}
public Point2D getSize()
{
return new Point2D(
Math.abs((this.right - this.left)),
Math.abs((this.bottom - this.top)));
}
public int getTop()
{
return this.top;
}
/**
* @param other rectangle to compare with
* @return Whether or not the smallest circles containing each of the two rectangles are overlapping
*/
public boolean isExternalCircleOverlapping(Rectangle other)
{
return this.getCenter().minus(other.getCenter()).getRadius() < (this.externalRadius() + other.externalRadius());
}
public boolean isOverlapping(Rectangle other)
{
return PolygonUtils.areOverlapping(this.getCorners().asArray(), other.getCorners().asArray());
}
public Rectangle move(Point2D target)
{
int newRight = this.right - (this.left - target.getX());
int newBottom = this.bottom - (this.top - target.getY());
return new Rectangle(target.getX(), target.getY(), newRight, newBottom);
}
public void setBottom(int bottom)
{
this.bottom = bottom;
}
public void setLeft(int left)
{
this.left = left;
}
public void setRight(int right)
{
this.right = right;
}
public void setRotation(double rotation)
{
this.rotation = rotation;
}
public void setTop(int top)
{
this.top = top;
}
}