package org.opencv.core;

//javadoc:RotatedRect_
public class RotatedRect {

    public Point center;
    public Size size;
    public double angle;

    public RotatedRect() {
        this.center = new Point();
        this.size = new Size();
        this.angle = 0;
    }

    public RotatedRect(Point c, Size s, double a) {
        this.center = c.clone();
        this.size = s.clone();
        this.angle = a;
    }

    public RotatedRect(double[] vals) {
        this();
        set(vals);
    }

    public void set(double[] vals) {
        if (vals != null) {
            center.x = vals.length > 0 ? vals[0] : 0;
            center.y = vals.length > 1 ? vals[1] : 0;
            size.width = vals.length > 2 ? vals[2] : 0;
            size.height = vals.length > 3 ? vals[3] : 0;
            angle = vals.length > 4 ? vals[4] : 0;
        } else {
            center.x = 0;
            center.y = 0;
            size.width = 0;
            size.height = 0;
            angle = 0;
        }
    }

    public void points(Point[] pt)
    {
        double _angle = angle * Math.PI / 180.0;
        double b = Math.cos(_angle) * 0.5f;
        double a = Math.sin(_angle) * 0.5f;

        pt[0] = new Point(
                center.x - a * size.height - b * size.width,
                center.y + b * size.height - a * size.width);

        pt[1] = new Point(
                center.x + a * size.height - b * size.width,
                center.y - b * size.height - a * size.width);

        pt[2] = new Point(
                2 * center.x - pt[0].x,
                2 * center.y - pt[0].y);

        pt[3] = new Point(
                2 * center.x - pt[1].x,
                2 * center.y - pt[1].y);
    }

    public Rect boundingRect()
    {
        Point[] pt = new Point[4];
        points(pt);
        Rect r = new Rect((int) Math.floor(Math.min(Math.min(Math.min(pt[0].x, pt[1].x), pt[2].x), pt[3].x)),
                (int) Math.floor(Math.min(Math.min(Math.min(pt[0].y, pt[1].y), pt[2].y), pt[3].y)),
                (int) Math.ceil(Math.max(Math.max(Math.max(pt[0].x, pt[1].x), pt[2].x), pt[3].x)),
                (int) Math.ceil(Math.max(Math.max(Math.max(pt[0].y, pt[1].y), pt[2].y), pt[3].y)));
        r.width -= r.x - 1;
        r.height -= r.y - 1;
        return r;
    }

    public RotatedRect clone() {
        return new RotatedRect(center, size, angle);
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        long temp;
        temp = Double.doubleToLongBits(center.x);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(center.y);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(size.width);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(size.height);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        temp = Double.doubleToLongBits(angle);
        result = prime * result + (int) (temp ^ (temp >>> 32));
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (!(obj instanceof RotatedRect)) return false;
        RotatedRect it = (RotatedRect) obj;
        return center.equals(it.center) && size.equals(it.size) && angle == it.angle;
    }

    @Override
    public String toString() {
        return "{ " + center + " " + size + " * " + angle + " }";
    }
}
