#ifndef SHAPE_HPP #define SHAPE_HPP 1 #include "vex.hpp" #include #include namespace shapes { template struct shape { vex::vec2 position; constexpr shape(const vex::vec2 p) : position(p) {} constexpr shape(T x, T y) : position(x, y) {} virtual void scale(T by) = 0; virtual void translate(vex::vec2 by) { position += by; } }; template struct point : public shape { constexpr point(T x, T y) : shape(vex::vec2(x, y)) {} constexpr point(const vex::vec2 &pos) : shape(pos) {} void scale(T by) override { (void)by; } }; template struct line : public shape { vex::vec2 end; constexpr line(T x, T y, T z, T w) : shape(vex::vec2(x, y)), end(z, w){} constexpr line(const vex::vec2 &pos, const vex::vec2 End) : shape(pos), end(End) {} void translate(vex::vec2 by) { this->position += by; end += by; } void scale(T by) override { end = vex::vec2( (T)std::floor((double)end[0] / (double)by), (T)std::floor((double)end[1] / (double)by)); } }; template struct circle : public shape { T radius; constexpr circle(T x, T y, T r) : shape(vex::vec2(x, y)), radius(r) {} constexpr circle(const vex::vec2 &pos, T r) : shape(pos), radius(r) {} void scale(T by) override { radius /= by; } }; template struct ellipse : public shape { T a, b; constexpr ellipse(T x, T y, T A, T B) : shape(x, y), a(A), b(B) {} constexpr ellipse(const vex::vec2 &pos, T A, T B) : shape(pos), a(A), b(B) {} void scale(T by) override {a /= by; b /= by; } }; template struct rectangle : public shape { vex::vec2 bounds; constexpr rectangle(T x, T y, T w, T h) : shape(vex::vec2(x, y)), bounds(w, h) {} constexpr rectangle(const vex::vec2 &pos, const vex::vec2 &wh) : shape(pos), bounds(wh) {} void scale(T by) override { bounds /= by; } }; template using shapes_variant = std::variant< point, line, circle, ellipse, rectangle >; template static bool intersects(const circle &lhs, const point &rhs) { vex::vec2 dist = rhs.position - lhs.position; //std::cout << dist.magnitude() << ' ' << lhs.radius << ' ' << dist.magnitude() - lhs.radius << std::endl; return dist.magnitude() < lhs.radius; } template static bool intersects(const point &lhs, const circle &rhs) { return intersects(rhs, lhs); } template static bool intersects(const ellipse &lhs, const point &rhs) { auto ds = lhs.position - rhs.position; auto d2 = ds * ds; L a2 = lhs.a * lhs.a; L b2 = lhs.b * lhs.b; return (((double)d2[0] / a2) + ((double)d2[1] / b2)) <= 1; } template static bool intersects(const point &lhs, const ellipse &rhs) { return intersects(rhs, lhs); } template static bool intersects(const rectangle &lhs, const point &rhs) { vex::vec2 corner = lhs.position + lhs.bounds; return (rhs.position[0] > lhs.position[0] && rhs.position[0] < corner[0] && rhs.position[1] > lhs.position[1] && rhs.position[1] < corner[1]); } template static bool intersects(const point &lhs, const rectangle &rhs) { return intersects(rhs, lhs); } template static bool intersects(const line &lhs, const line &rhs) { double x1 = lhs.position[0], x2 = lhs.end[0], x3 = rhs.position[0], x4 = rhs.end[0]; double y1 = lhs.position[1], y2 = lhs.end[1], y3 = rhs.position[1], y4 = rhs.end[1]; double uA = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1)); double uB = ((x2-x1)*(y1-y3) - (y2-y1)*(x1-x3)) / ((y4-y3)*(x2-x1) - (x4-x3)*(y2-y1)); if(uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1) return true; return false; } template static bool intersects(const rectangle &lhs, const line &rhs) { vex::vec2 corner = lhs.position + lhs.bounds; line l(lhs.position, lhs.position + vex::vec2(0, lhs.bounds[1])); line r(lhs.position + vex::vec2(lhs.bounds[0], 0), corner); line d(lhs.position, lhs.position + vex::vec2(lhs.bounds[0], 0)); line u(lhs.position + vex::vec2(0, lhs.bounds[1]), corner); if(intersects(rhs, l) || intersects(rhs, r) || intersects(rhs, d) || intersects(rhs, u)) return true; return (rhs.position[0] > lhs.position[0] && rhs.position[0] < corner[0] && rhs.position[1] > lhs.position[1] && rhs.position[1] < corner[1]) && (rhs.end[0] > lhs.position[0] && rhs.end[0] < corner[0] && rhs.end[1] > lhs.position[1] && rhs.end[1] < corner[1]); } template static bool intersects(const line &lhs, const rectangle &rhs) { return intersects(rhs, lhs); } template static bool intersects(const rectangle &lhs, const circle &rhs) { vex::vec2 dist{ rhs.position[0] - std::max(lhs.position[0], std::min(rhs.position[0], lhs.position[0] + lhs.bounds[0])), rhs.position[1] - std::max(lhs.position[1], std::min(rhs.position[1], lhs.position[1] + lhs.bounds[1])), }; return (dist[0] * dist[0]) + (dist[1] * dist[1]) < (rhs.radius * rhs.radius); } template static bool intersects(const circle &lhs, const rectangle &rhs) { return intersects(rhs, lhs); } template static bool intersects(const rectangle &lhs, const ellipse &rhs) { vex::vec2 dist{ rhs.position[0] - std::max(lhs.position[0], std::min(rhs.position[0], lhs.position[0] + lhs.bounds[0])), rhs.position[1] - std::max(lhs.position[1], std::min(rhs.position[1], lhs.position[1] + lhs.bounds[1])), }; vex::vec2 ab2 { std::max(1, rhs.a * rhs.a), std::max(1, rhs.b * rhs.b) }; return ((dist[0] * dist[0]) / ab2[0]) + ((dist[1] * dist[1]) / ab2[1]) <= 1.0; } template static bool intersects(const ellipse &lhs, const rectangle &rhs) { return intersects(rhs, lhs); } template static bool intersects(const rectangle &lhs, const rectangle &rhs) { return ( (lhs.position[0] < rhs.position[0] + rhs.bounds[0]) && (lhs.position[0] + lhs.bounds[0] > rhs.position[0]) && (lhs.position[1] + lhs.bounds[1] < rhs.position[1]) && (lhs.position[1] > rhs.position[1] + rhs.position[1]) ); } } #endif