using System; using System.Collections.Generic; using UnityEngine; namespace BrewMonster.Scripts { public class ARect where T : IComparable { public T left, top, right, bottom; public ARect() { left = default(T); top = default(T); right = default(T); bottom = default(T); } public ARect(ARect rc) { left = rc.left; top = rc.top; right = rc.right; bottom = rc.bottom; } public ARect(T left, T top, T right, T bottom) { this.left = left; this.top = top; this.right = right; this.bottom = bottom; } // helpers for int/float only static int Cmp(T a, T b) => Comparer.Default.Compare(a, b); static T Min(T a, T b) => Cmp(a, b) <= 0 ? a : b; static T Max(T a, T b) => Cmp(a, b) >= 0 ? a : b; static T Add(T a, T b) { if (typeof(T) == typeof(int)) return (T)(object)((int)(object)a + (int)(object)b); if (typeof(T) == typeof(float)) return (T)(object)((float)(object)a + (float)(object)b); throw new NotSupportedException("ARect supports only int and float"); } static T Sub(T a, T b) { if (typeof(T) == typeof(int)) return (T)(object)((int)(object)a - (int)(object)b); if (typeof(T) == typeof(float)) return (T)(object)((float)(object)a - (float)(object)b); throw new NotSupportedException("ARect supports only int and float"); } static T Neg(T a) { if (typeof(T) == typeof(int)) return (T)(object)(-(int)(object)a); if (typeof(T) == typeof(float)) return (T)(object)(-(float)(object)a); throw new NotSupportedException("ARect supports only int and float"); } static bool IsZero(T v) { if (typeof(T) == typeof(int)) return (int)(object)v == 0; if (typeof(T) == typeof(float)) return (float)(object)v == 0f; throw new NotSupportedException("ARect supports only int and float"); } static T FromInt(int v) { if (typeof(T) == typeof(int)) return (T)(object)v; if (typeof(T) == typeof(float)) return (T)(object)(float)v; throw new NotSupportedException("ARect supports only int and float"); } // == and != operator public static bool operator !=(ARect rc1, ARect rc2) { return !(rc1 == rc2); } public static bool operator ==(ARect rc1, ARect rc2) { return EqualityComparer.Default.Equals(rc1.left, rc2.left) && EqualityComparer.Default.Equals(rc1.top, rc2.top) && EqualityComparer.Default.Equals(rc1.right, rc2.right) && EqualityComparer.Default.Equals(rc1.bottom, rc2.bottom); } // + and - operator public static ARect operator +(ARect rc1, ARect rc2) { return new ARect( Add(rc1.left, rc2.left), Add(rc1.top, rc2.top), Add(rc1.right, rc2.right), Add(rc1.bottom, rc2.bottom) ); } public static ARect operator -(ARect rc1, ARect rc2) { return new ARect( Sub(rc1.left, rc2.left), Sub(rc1.top, rc2.top), Sub(rc1.right, rc2.right), Sub(rc1.bottom, rc2.bottom) ); } //public static ARect operator +(ARect rc1, APoint pt) //{ // return new ARect((dynamic)rc1.left + (dynamic)pt.x, // (dynamic)rc1.top + (dynamic)pt.y, // (dynamic)rc1.right + (dynamic)pt.x, // (dynamic)rc1.bottom + (dynamic)pt.y); //} //public static ARect operator -(ARect rc1, APoint pt) //{ // return new ARect((dynamic)rc1.left - (dynamic)pt.x, // (dynamic)rc1.top - (dynamic)pt.y, // (dynamic)rc1.right - (dynamic)pt.x, // (dynamic)rc1.bottom - (dynamic)pt.y); //} // &= and |= operator public ARect AndAssign(ARect rc) => this & rc; public ARect OrAssign(ARect rc) => this | rc; public static ARect operator &(ARect rc1, ARect rc2) { if (rc1.IsEmpty() || rc2.IsEmpty()) return new ARect(default, default, default, default); var l1 = rc1.left; var r1 = rc1.right; var t1 = rc1.top; var b1 = rc1.bottom; var l2 = rc2.left; var r2 = rc2.right; var t2 = rc2.top; var b2 = rc2.bottom; if (Cmp(l1, r2) >= 0 || Cmp(l2, r1) >= 0 || Cmp(t1, b2) >= 0 || Cmp(t2, b1) >= 0) return new ARect(default, default, default, default); return new ARect( Max(l1, l2), Max(t1, t2), Min(r1, r2), Min(b1, b2) ); } public static ARect operator |(ARect rc1, ARect rc2) { if (rc1.IsEmpty()) return rc2; if (rc2.IsEmpty()) return rc1; var l1 = rc1.left; var r1 = rc1.right; var t1 = rc1.top; var b1 = rc1.bottom; var l2 = rc2.left; var r2 = rc2.right; var t2 = rc2.top; var b2 = rc2.bottom; return new ARect( Min(l1, l2), Min(t1, t2), Max(r1, r2), Max(b1, b2) ); } public static ARect operator +(ARect rc) { return rc; } public static ARect operator -(ARect rc) { return new ARect( Neg(rc.left), Neg(rc.top), Neg(rc.right), Neg(rc.bottom) ); } // = operator //public static ARect operator = (ARect rc) { left = rc.left; top = rc.top; right = rc.right; bottom = rc.bottom; return *this; } // += and -= operator public ARect AdditionAssign(ARect rc) { left = Add(left, rc.left); top = Add(top, rc.top); right = Add(right, rc.right); bottom = Add(bottom, rc.bottom); return this; } public ARect SubtractionAssign(ARect rc) { left = Sub(left, rc.left); top = Sub(top, rc.top); right = Sub(right, rc.right); bottom = Sub(bottom, rc.bottom); return this; } //public ARect AdditionAssign(APoint pt) { left += pt.x; top += pt.y; right += pt.x; bottom += pt.y; return this; } //public ARect SubtractionAssign(APoint pt) { left -= pt.x; top -= pt.y; right -= pt.x; bottom -= pt.y; return this; } // Get width of rectangle public T Width() { return Sub(right, left); } // Get height of rectangle public T Height() { return Sub(bottom, top); } // Get center point of rectangle //public APoint CenterPoint() { return new APoint((left + right) / 2, (top + bottom) / 2); } // Set rectangle value public void SetRect(T _left, T _top, T _right, T _bottom) { left = _left; top = _top; right = _right; bottom = _bottom; } // Point in rectangle public bool PtInRect(T x, T y) { return Cmp(x, left) >= 0 && Cmp(x, right) < 0 && Cmp(y, top) >= 0 && Cmp(y, bottom) < 0; } //public bool PtInRect(APoint pt) { return PtInRect(pt.x, pt.y); } // Normalize rectangle. Note: The following CRect member functions require // normalized rectangles in order to work properly: Height, Width, Size, // IsEmpty, PtInRect, SetUnion, SetIntersect, operator ==, operator !=, // operator |, operator |=, operator &, and operator &= void Normalize() { if (Cmp(left, right) > 0) a_Swap(ref left, ref right); if (Cmp(top, bottom) > 0) a_Swap(ref top, ref bottom); } private void a_Swap(ref T lhs, ref T rhs) { T tmp; tmp = lhs; lhs = rhs; rhs = tmp; } // All members are 0 ? public bool IsRectNull() { return IsZero(left) && IsZero(top) && IsZero(right) && IsZero(bottom); } // Rectangle is empty ? public bool IsEmpty() { return IsZero(Width()) || IsZero(Height()); } // Set all members to 0 public void Clear() { left = top = right = bottom = default(T); } // Deflate rectangle public void Deflate(T x, T y) { left = Add(left, x); top = Add(top, y); right = Sub(right, x); bottom = Sub(bottom, y); } public void Deflate(ARect rc) { left = Add(left, rc.left); top = Add(top, rc.top); right = Sub(right, rc.right); bottom = Sub(bottom, rc.bottom); } public void Deflate(T l, T t, T r, T b) { left = Add(left, l); top = Add(top, t); right = Sub(right, r); bottom = Sub(bottom, b); } // Inflate rectangle public void Inflate(T x, T y) { left = Sub(left, x); top = Sub(top, y); right = Add(right, x); bottom = Add(bottom, y); } public void Inflate(ARect rc) { left = Sub(left, rc.left); top = Sub(top, rc.top); right = Add(right, rc.right); bottom = Add(bottom, rc.bottom); } public void Inflate(T l, T t, T r, T b) { left = Sub(left, l); top = Sub(top, t); right = Add(right, r); bottom = Add(bottom, b); } // Offset rectangle public void Offset(int x, int y) { var dx = FromInt(x); var dy = FromInt(y); left = Add(left, dx); top = Add(top, dy); right = Add(right, dx); bottom = Add(bottom, dy); } //public void Offset(APoint pt) { this += pt; } // Set rectangle as union result public void SetUnion(ARect rc1, ARect rc2) { var result = rc1 | rc2; left = result.left; right = result.right; bottom = result.bottom; top = result.top; } // Set rectangle as intersect result public void SetIntersect(ARect rc1, ARect rc2) { var result = rc1 & rc2; left = result.left; right = result.right; bottom = result.bottom; top = result.top; } } }