#ifndef __GEOMETRY_HPP__ #define __GEOMETRY_HPP__ #include #include #include #include namespace ostd { class OutputHandlerBase; template class Point { public: T x; T y; public: inline Point(void) : x(0), y(0) {} inline Point(T xx, T yy) : x(xx), y(yy) {} inline bool operator==(const Point& op2 ) const { return (x == op2.x && y == op2.y); } inline bool operator!=(const Point& op2 ) const { return (x != op2.x || y != op2.y); } template inline Point(Point copy) { x = (T2)(copy.x); y = (T2)(copy.y); } }; typedef Point FPoint; typedef Point DPoint; typedef Point UIPoint; typedef Point UI64Point; typedef Point UI16Point; typedef Point UI8Point; typedef Point IPoint; typedef Point I64Point; typedef Point I16Point; typedef Point I8Point; struct Vec2 { //======================== Data ======================== float x; float y; //====================================================== //==================== Construction ==================== inline Vec2(float xx = 0, float yy = 0) : x(xx), y(yy) { } inline Vec2(const Vec2& v2) { set(v2); } inline Vec2& set(const Vec2& v2) { x = v2.x; y = v2.y; return *this; } inline Vec2& set(float xx, float yy) { x = xx; y = yy; return *this; } //====================================================== //================== Static Functions ================== inline static Vec2 fromAngle(float angle) { return Vec2(std::cos(angle), std::sin(angle)); } inline static float angleBetween(const Vec2& v1, const Vec2& v2) { return std::acos(v1.dot(v2) / (v1.mag() * v2.mag())); } //====================================================== //===================== Conversion ===================== inline Vec2 toIsometric(void) const { return Vec2(x - y, (x + y) / 2.0f); } inline Vec2 toCartesian(void) const { return Vec2((2 * y + x) / 2.0f, (2 * y - x) / 2.0f); } String toString(void) const; //====================================================== //===================== Operations ===================== inline float mag(void) const { return std::sqrt((x * x) + (y * y)); } inline Vec2 add(Vec2 v2) const { return { x + v2.x, y + v2.y }; } inline Vec2 add(float x2, float y2) const { return { x + x2, y + y2 }; } inline Vec2 sub(Vec2 v2) const { return { x - v2.x, y - v2.y }; } inline Vec2 sub(float x2, float y2) const { return { x - x2, y - y2 }; } inline Vec2 mul(float scalar) const { return { x * scalar, y * scalar }; } inline Vec2 div(float scalar) const { return { x / scalar, y / scalar }; } inline Vec2 normalize(void) const { float m = _zp(mag()); return { x / m, y / m }; } inline float dist(Vec2 v2) const { return std::sqrt((float)((v2.x - x) * (v2.x - x)) + ((v2.y - y) * (v2.y - y))); } inline float heading(void) const { return std::atan2(y, x); } inline Vec2 rotate(float angle) const { return Vec2(*this).rotate(angle); } inline float dot(const Vec2& v2) const { return (x * v2.x) + (y * v2.y); } inline float cross(const Vec2& v2) const { return (x * v2.y) - (v2.x * y); } //====================================================== //===================== Modifiers ====================== inline Vec2& addm(const Vec2& v2) { x += v2.x; y += v2.y; return *this; } inline Vec2& addm(const float& x2, const float& y2) { x += x2; y += y2; return *this; } inline Vec2& subm(const Vec2& v2) { x -= v2.x; y -= v2.y; return *this; } inline Vec2& subm(const float& x2, const float& y2) { x -= x2; y -= y2; return *this; } inline Vec2& mulm(const float& scalar) { x *= scalar; y *= scalar; return *this; } inline Vec2& divm(const float& scalar) { x /= scalar; y /= scalar; return *this; } inline Vec2& normalizem(void) { float m = _zp(mag()); x /= m; y /= m; return *this; } inline Vec2& setMag(const float& mag) { return normalizem().mulm(mag); } inline Vec2& setHeading(const float& angle) { float m = mag(); set(m * std::cos(angle), m * std::sin(angle)); return *this; } inline Vec2& rotate(const float& angle) { return setHeading(heading() + angle); } inline Vec2& limit(const float& max) { float msq = mag(); msq *= msq; if (msq > (max * max)) divm(std::sqrt(msq)).mulm(max); return *this; } //====================================================== //===================== Operators ====================== inline bool operator==(const Vec2& op2 ) const { return (x == op2.x && y == op2.y); } inline bool operator!=(const Vec2& op2 ) const { return (x != op2.x || y != op2.y); } inline Vec2 operator+ (const Vec2& op2 ) const { return add(op2); } inline Vec2 operator- (const Vec2& op2 ) const { return sub(op2); } inline Vec2 operator+ (const float& op2) const { return add(op2, op2); } inline Vec2 operator- (const float& op2) const { return sub(op2, op2); } inline Vec2 operator* (const float& op2) const { return mul(op2); } inline Vec2 operator/ (const float& op2) const { return div(op2); } inline Vec2& operator= (const Vec2& val ) { return set(val); } inline Vec2& operator= (const float& val) { return set(val, val); } inline Vec2& operator+=(const Vec2& op2 ) { return addm(op2); } inline Vec2& operator-=(const Vec2& op2 ) { return subm(op2); } inline Vec2& operator+=(const float& op2) { return addm(op2, op2); } inline Vec2& operator-=(const float& op2) { return subm(op2, op2); } inline Vec2& operator*=(const float& op2) { return mulm(op2); } inline Vec2& operator/=(const float& op2) { return divm(op2); } friend std::ostream& operator<<(std::ostream& out, const Vec2& val); //====================================================== private: inline float _zp(float n1) const { return (n1 == 0 ? 1 : n1); } }; inline std::ostream& operator<<(std::ostream& out, const Vec2& val) { out << val.toString(); return out; } struct Vec3 { inline Vec3(float xx = 0, float yy = 0, float zz = 0) { x = xx; y = yy; z = zz; } inline Vec3(const Vec2& xy, float _z = 0.0f) { x = xy.x; y = xy.y; z = _z; } inline Vec2 xy(void) const { return Vec2(x, y); } inline Vec2 yz(void) const { return Vec2(y, z); } inline Vec2 zx(void) const { return Vec2(z, x); } String toString(void) const; inline bool operator==(const Vec3& op2 ) const { return (x == op2.x && y == op2.y && op2.z == z); } inline bool operator!=(const Vec3& op2 ) const { return (x != op2.x || y != op2.y || op2.z != z); } inline Vec3& operator+=(const Vec3& op2 ) { x += op2.x; y += op2.y; z += op2.z; return *this; } friend std::ostream& operator<<(std::ostream& out, const Vec2& val); float x; float y; float z; }; inline std::ostream& operator<<(std::ostream& out, const Vec3& val) { out << val.toString(); return out; } struct Vec4 { inline Vec4(float xx = 0, float yy = 0, float zz = 0, float ww = 0) { x = xx; y = yy; z = zz; w = ww; } inline Vec4(const Vec2& xy, float _z = 0.0f, float _w = 0.0f) { x = xy.x; y = xy.y; z = _z; w = _w; } inline Vec4(const Vec3& xyz, float _w = 0.0f) { x = xyz.x; y = xyz.y; z = xyz.z; w = _w; } inline Vec4(const Vec2& xy, const Vec2& zw) { x = xy.x; y = xy.y; z = zw.x; w = zw.y; } inline Vec2 xy(void) const { return Vec2(x, y); } inline Vec2 yz(void) const { return Vec2(y, z); } inline Vec2 zw(void) const { return Vec2(z, w); } inline Vec2 wx(void) const { return Vec2(w, x); } float x; float y; float z; float w; }; struct Triangle { Vec2 vA; Vec2 vB; Vec2 vC; inline Triangle(void) {} inline Triangle(Vec2 a, Vec2 b, Vec2 c) { vA = a; vB = b; vC = c; } inline Triangle(float ax, float ay, float bx, float by, float cx, float cy) { vA.x = ax; vA.y = ay; vB.x = bx; vB.y = by; vC.x = cx; vC.y = cy; } bool contains(Vec2 p) { float d1, d2, d3; bool has_neg, has_pos; d1 = __sign(p, vA, vB); d2 = __sign(p, vB, vC); d3 = __sign(p, vC, vA); has_neg = (d1 < 0) || (d2 < 0) || (d3 < 0); has_pos = (d1 > 0) || (d2 > 0) || (d3 > 0); return !(has_neg && has_pos); } private: inline float __sign(Vec2 p1, Vec2 p2, Vec2 p3) { return (p1.x - p3.x) * (p2.y - p3.y) - (p2.x - p3.x) * (p1.y - p3.y); } }; class Rectangle { public: inline Rectangle(void) : x(0), y(0), w(0), h(0) {} inline Rectangle(float xx, float yy, float ww, float hh) : x(xx), y(yy), w(ww), h(hh) {} inline Rectangle(float xw, float yh, bool position = true) { if (position) { x = xw; y = yh; } else { w = xw; h = yh; } } inline Rectangle(float xx, float yy, Vec2 size) { x = xx; y = yy; w = size.x; h = size.y; } inline Rectangle(Vec2 position, float ww, float hh) { x = position.x; y = position.y; w = ww; h = hh; } inline Rectangle(Vec2 position, Vec2 size) { x = position.x; y = position.y; w = size.x; h = size.y; } virtual ~Rectangle(void) = default; inline virtual float getx(void) const { return x; } inline virtual float gety(void) const { return y; } inline virtual float getw(void) const { return w; } inline virtual float geth(void) const { return h; } inline virtual float getCenterX(void) const { return getx() + getw() / 2; } inline virtual float getCenterY(void) const { return gety() + geth() / 2; } inline virtual void setx(float xx) { x = xx; } inline virtual void sety(float yy) { y = yy; } inline virtual void setw(float ww) { w = ww; } inline virtual void seth(float hh) { h = hh; } inline virtual Vec2 getPosition(void) const { return Vec2(getx(), gety()); } inline virtual Vec2 getSize(void) const { return Vec2(getw(), geth()); } inline virtual Vec2 getCenter(void) const { return Vec2(getx() + getw() / 2, gety() + geth() / 2); } inline virtual void setPosition(Vec2 pos) { setx(pos.x); sety(pos.y); } inline virtual void setPosition(float xx, float yy) { setx(xx); sety(yy); } inline virtual void setSize(Vec2 size) { setw(size.x); seth(size.y); } inline virtual void setSize(float ww, float hh) { setw(ww); seth(hh); } inline virtual void setBounds(float xx, float yy, float ww, float hh) { setx(xx); sety(yy); setw(ww); seth(hh); } inline virtual float addx(float xx) { setx(getx() + xx); return getx(); } inline virtual float addy(float yy) { sety(gety() + yy); return gety(); } inline virtual Vec2 addPos(float xx, float yy) { return Vec2(addx(xx), addy(yy)); } inline virtual Vec2 addPos(Vec2 pos) { return addPos(pos.x, pos.y); } inline virtual float addw(float ww) { setw(getw() + ww); return getw(); } inline virtual float addh(float hh) { seth(geth() + hh); return geth(); } inline virtual Vec2 addSize(float ww, float hh) { return Vec2(addw(ww), addh(hh)); } inline virtual Vec2 addSize(Vec2 size) { return addPos(size.x, size.y); } inline virtual float subx(float xx) { setx(getx() - xx); return getx(); } inline virtual float suby(float yy) { sety(gety() - yy); return gety(); } inline virtual Vec2 subPos(float xx, float yy) { return Vec2(subx(xx), suby(yy)); } inline virtual Vec2 subPos(Vec2 pos) { return subPos(pos.x, pos.y); } inline virtual float subw(float ww) { setw(getw() - ww); return getw(); } inline virtual float subh(float hh) { seth(geth() - hh); return geth(); } inline virtual Vec2 subSize(float ww, float hh) { return Vec2(subw(ww), subh(hh)); } inline virtual Vec2 subSize(Vec2 size) { return subPos(size.x, size.y); } inline virtual float mulx(float xx) { setx(getx() * xx); return getx(); } inline virtual float muly(float yy) { sety(gety() * yy); return gety(); } inline virtual Vec2 mulPos(float xx, float yy) { return Vec2(mulx(xx), muly(yy)); } inline virtual Vec2 mulPos(Vec2 pos) { return mulPos(pos.x, pos.y); } inline virtual float mulw(float ww) { setw(getw() * ww); return getw(); } inline virtual float mulh(float hh) { seth(geth() * hh); return geth(); } inline virtual Vec2 mulSize(float ww, float hh) { return Vec2(mulw(ww), mulh(hh)); } inline virtual Vec2 mulSize(Vec2 size) { return mulPos(size.x, size.y); } inline virtual float divx(float xx) { setx(getx() / xx); return getx(); } inline virtual float divy(float yy) { sety(gety() / yy); return gety(); } inline virtual Vec2 divPos(float xx, float yy) { return Vec2(divx(xx), divy(yy)); } inline virtual Vec2 divPos(Vec2 pos) { return divPos(pos.x, pos.y); } inline virtual float divw(float ww) { setw(getw() / ww); return getw(); } inline virtual float divh(float hh) { seth(geth() / hh); return geth(); } inline virtual Vec2 divSize(float ww, float hh) { return Vec2(divw(ww), divh(hh)); } inline virtual Vec2 divSize(Vec2 size) { return divPos(size.x, size.y); } inline virtual Vec2 topLeft(void) const { return getPosition(); } inline virtual Vec2 topRight(void) const { return Vec2(getx() + getw(), gety()); } inline virtual Vec2 bottomLeft(void) const { return Vec2(getx(), gety() + geth()); } inline virtual Vec2 bottomRight(void) const { return Vec2(getx() + getw(), gety() + geth()); } inline virtual bool intersects(Rectangle rect, bool includeBounds = true) const { if (includeBounds) { if (x + w <= rect.x || x >= rect.x + rect.w) return false; if (y + h <= rect.y || y >= rect.y + rect.h) return false; } else { if (x + w < rect.x || x > rect.x + rect.w) return false; if (y + h < rect.y || y > rect.y + rect.h) return false; } return true; } inline virtual Rectangle getIntersection(Rectangle rect, bool includeBounds = true) const { if (!intersects(rect, includeBounds)) return Rectangle(); float leftX = std::max(x, rect.x); float rightX = std::min(x + w, rect.x + rect.w); float topY = std::max(y, rect.y); float bottomY = std::min(y + h, rect.y + rect.h); return { leftX, topY, rightX - leftX, bottomY - topY }; } inline virtual bool contains(Vec2 p, bool includeBounds = false) const { if (includeBounds) return p.x >= x && p.y >= y & p.x <= x + w && p.y <= y + h; else return p.x > x && p.y > y & p.x < x + w && p.y < y + h; } inline virtual bool contains(float xx, float yy, bool includeBounds = false) const { return contains({ xx, yy }); } inline virtual float getDistance(Vec2 p) const { return sqrt(fabs((p.x - getx()) * (p.x - getx()) + (p.y - gety()) * (p.y - gety()))); } public: float x; float y; float w; float h; }; } #endif