From b4f6694338127977933ee3acbfe39251062c6258 Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Wed, 24 Jul 2024 21:08:27 +0100 Subject: [PATCH 1/3] Stub for v2.27 --- olcPixelGameEngine.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/olcPixelGameEngine.h b/olcPixelGameEngine.h index 74456c09..1fc11c46 100644 --- a/olcPixelGameEngine.h +++ b/olcPixelGameEngine.h @@ -3,7 +3,7 @@ olcPixelGameEngine.h +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine v2.26 | + | OneLoneCoder Pixel Game Engine v2.27 | | "What do you need? Pixels... Lots of Pixels..." - javidx9 | +-------------------------------------------------------------+ @@ -331,6 +331,7 @@ +adv_FlushLayerDecals() - [ADVANCED] Force layer's decal render to buffer +FillTriangleDecal() - Draws a triangle decal +GradientTriangleDecal() - Draws a triangle decal with unique vertex colours + 2.27: !! Apple Platforms will not see these updates immediately - Sorry, I dont have a mac to test... !! !! Volunteers willing to help appreciated, though PRs are manually integrated with credit !! @@ -410,7 +411,7 @@ int main() #include #pragma endregion -#define PGE_VER 226 +#define PGE_VER 227 // O------------------------------------------------------------------------------O // | COMPILER CONFIGURATION ODDITIES | From 97c05ec1175e51e290b7ad63b61349f5f10cde04 Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Mon, 2 Sep 2024 20:30:46 +0100 Subject: [PATCH 2/3] Post-jam cleanup --- extensions/olcPGEX_SplashScreen.h | 2 +- olcPixelGameEngine.h | 15 +- utilities/olcUTIL_Animate2D.h | 2 +- utilities/olcUTIL_Geometry2D.h | 502 +++++++++++++++++++++++------- utilities/olcUTIL_QuadTree.h | 17 +- 5 files changed, 422 insertions(+), 116 deletions(-) diff --git a/extensions/olcPGEX_SplashScreen.h b/extensions/olcPGEX_SplashScreen.h index 7d6adf7b..5217b9fa 100644 --- a/extensions/olcPGEX_SplashScreen.h +++ b/extensions/olcPGEX_SplashScreen.h @@ -211,7 +211,7 @@ namespace olc } olc::vi2d vSize = pge->GetTextSizeProp("Copyright OneLoneCoder.com 2024"); - pge->DrawStringPropDecal(olc::vf2d(float(pge->ScreenWidth()/2) - vSize.x/2, float(pge->ScreenHeight()) - vSize.y * 3.0f), "Copyright OneLoneCoder.com 2023", olc::PixelF(1.0f, 1.0f, 1.0f, 0.5f), olc::vf2d(1.0, 2.0f)); + pge->DrawStringPropDecal(olc::vf2d(float(pge->ScreenWidth()/2) - vSize.x/2, float(pge->ScreenHeight()) - vSize.y * 3.0f), "Copyright OneLoneCoder.com 2024", olc::PixelF(1.0f, 1.0f, 1.0f, 0.5f), olc::vf2d(1.0, 2.0f)); return true; } diff --git a/olcPixelGameEngine.h b/olcPixelGameEngine.h index 74456c09..f355bf88 100644 --- a/olcPixelGameEngine.h +++ b/olcPixelGameEngine.h @@ -3,7 +3,7 @@ olcPixelGameEngine.h +-------------------------------------------------------------+ - | OneLoneCoder Pixel Game Engine v2.26 | + | OneLoneCoder Pixel Game Engine v2.27 | | "What do you need? Pixels... Lots of Pixels..." - javidx9 | +-------------------------------------------------------------+ @@ -331,6 +331,13 @@ +adv_FlushLayerDecals() - [ADVANCED] Force layer's decal render to buffer +FillTriangleDecal() - Draws a triangle decal +GradientTriangleDecal() - Draws a triangle decal with unique vertex colours + 2.27: Restructuring of connected files (post-jam clean up) + +Guarding olc::v_2d with less faff + +Updated olcUTIL_Geometry2D.h + +Updated olcUTIL_QuadTree.h + +Updated olcUTIL_Animate2D.h + +Updated olcUTIL_SplashScreen.h + +File Resolution for PGEtinker.com !! Apple Platforms will not see these updates immediately - Sorry, I dont have a mac to test... !! !! Volunteers willing to help appreciated, though PRs are manually integrated with credit !! @@ -410,7 +417,7 @@ int main() #include #pragma endregion -#define PGE_VER 226 +#define PGE_VER 227 // O------------------------------------------------------------------------------O // | COMPILER CONFIGURATION ODDITIES | @@ -686,7 +693,7 @@ namespace olc // O------------------------------------------------------------------------------O // | olc::vX2d - A generic 2D vector type | // O------------------------------------------------------------------------------O -#if !defined(OLC_IGNORE_VEC2D) +#if !defined(OLC_VECTOR2D_DEFINED) template struct v2d_generic { @@ -758,6 +765,8 @@ namespace olc typedef v2d_generic vu2d; typedef v2d_generic vf2d; typedef v2d_generic vd2d; + +#define OLC_VECTOR2D_DEFINED 1 #endif diff --git a/utilities/olcUTIL_Animate2D.h b/utilities/olcUTIL_Animate2D.h index ee158cbd..39bf839d 100644 --- a/utilities/olcUTIL_Animate2D.h +++ b/utilities/olcUTIL_Animate2D.h @@ -58,8 +58,8 @@ #pragma once +#include #include "olcPixelGameEngine.h" -#include "utilities/olcUTIL_Geometry2D.h" #include namespace olc::utils::Animate2D diff --git a/utilities/olcUTIL_Geometry2D.h b/utilities/olcUTIL_Geometry2D.h index 902ee305..cae3175e 100644 --- a/utilities/olcUTIL_Geometry2D.h +++ b/utilities/olcUTIL_Geometry2D.h @@ -50,11 +50,11 @@ Authors ~~~~~~~ David Barr, aka javidx9, (c) OneLoneCoder 2019, 2020, 2021, 2022, 2023, 2024 - + With significant contributions from: - - Piratux, Gusgo99, Gorbit99, MagetzUb, Dandistine - cstdint, sigonasr, bixxy, Qwerasd + + Piratux, Gusgo99, Gorbit99, MaGetzUb, Dandistine, Moros1138 + cstdint, sigonasr, bixxy, Qwerasd, starfreakclone, fux Changes: v1.01: +Made constants inline @@ -111,7 +111,10 @@ ray reflect(ray, a) Returns a ray that is a reflection of supplied incident ray against Shape A - + + optional collision(ray, a) + Returns the point and normal where a ray collides with Shape A + */ /* @@ -124,57 +127,59 @@ where: - f = overlaps, intersects, contains, closest, envelope_r, envelope_b + f = overlaps, intersects, contains, closest, envelope_r, envelope_b, reflects, collision a = p, l, r, c, t, q, pol (point, line, rect, circ, triangle, ray, polygon) example: - "contains(r,c)" - takes you to implementation for contains(rect, circ) + "contains(r,c)" - takes you to implementation for contains(rect, circ) - Does the rectangle contain the circle? */ /* - Function Matrix - Function(A, B) - ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - - A B>| POINT | LINE | RECT | CIRCLE | TRIANGLE | RAY | - ---------+--------------+--------------+--------------+--------------+--------------+--------------+ - POINT | contains | contains | contains | contains | contains | | - | closest | closest | closest | closest | closest | closest | - | overlaps | overlaps | overlaps | overlaps | overlaps | | - | intersects | intersects | intersects | intersects | intersects | | - | | | | | | | - ---------+--------------+--------------+--------------+--------------+--------------+--------------+ - LINE | contains | contains | contains | contains | contains | | - | closest | | | closest | | | - | overlaps | overlaps | overlaps | overlaps | overlaps | | - | intersects | intersects | intersects | intersects | intersects | | - | | | | | | | - ---------+--------------+--------------+--------------+--------------+--------------+--------------+ - RECT | contains | contains | contains | contains | contains | | - | closest | | | | | | - | overlaps | overlaps | overlaps | overlaps | overlaps | | - | intersects | intersects | intersects | intersects | intersects | | - | | | | | | | - ---------+--------------+--------------+--------------+--------------+--------------+--------------+ - CIRCLE | contains | contains | contains | contains | contains | | - | closest | closest | | | | | - | overlaps | overlaps | overlaps | overlaps | overlaps | | - | intersects | intersects | intersects | intersects | intersects | | - | project | project | | project | | | - ---------+--------------+--------------+--------------+--------------+--------------+--------------+ - TRIANGLE | contains | contains | contains | contains | contains | | - | closest | | | | | | - | overlaps | overlaps | overlaps | overlaps | overlaps | | - | intersects | intersects | intersects | intersects | intersects | | - | | | | | | | - ---------+--------------+--------------+--------------+--------------+--------------+--------------+ - RAY | | | | | | | - | | | | | | | - | | | | | | | - | | intersects | intersects | intersects | intersects | intersects | - | | | | | | | - ---------+--------------+--------------+--------------+--------------+--------------+--------------+ + Function Matrix - Function(A, B) + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + A B>| POINT | LINE | RECT | CIRCLE | TRIANGLE | RAY | + ---------+--------------+--------------+--------------+--------------+--------------+--------------+ + POINT | contains | contains | contains | contains | contains | | + | closest | closest | closest | closest | closest | closest | + | overlaps | overlaps | overlaps | overlaps | overlaps | | + | intersects | intersects | intersects | intersects | intersects | | + | | | | | | | + ---------+--------------+--------------+--------------+--------------+--------------+--------------+ + LINE | contains | contains | contains | contains | contains | | + | closest | | | closest | | | + | overlaps | overlaps | overlaps | overlaps | overlaps | | + | intersects | intersects | intersects | intersects | intersects | | + | | | | | | | + ---------+--------------+--------------+--------------+--------------+--------------+--------------+ + RECT | contains | contains | contains | contains | contains | | + | closest | | | | | | + | overlaps | overlaps | overlaps | overlaps | overlaps | | + | intersects | intersects | intersects | intersects | intersects | | + | | | | | | | + ---------+--------------+--------------+--------------+--------------+--------------+--------------+ + CIRCLE | contains | contains | contains | contains | contains | | + | closest | closest | | | | | + | overlaps | overlaps | overlaps | overlaps | overlaps | | + | intersects | intersects | intersects | intersects | intersects | | + | project | project | | project | | | + ---------+--------------+--------------+--------------+--------------+--------------+--------------+ + TRIANGLE | contains | contains | contains | contains | contains | | + | closest | | | | | | + | overlaps | overlaps | overlaps | overlaps | overlaps | | + | intersects | intersects | intersects | intersects | intersects | | + | | | | | | | + ---------+--------------+--------------+--------------+--------------+--------------+--------------+ + RAY | contains | | | | | | + | | | | | | | + | | collision | collision | collision | collision | collision* | + | | intersects | intersects | intersects | intersects | intersects | + | | reflect | reflect | reflect | reflect | reflect* | + ---------+--------------+--------------+--------------+--------------+--------------+--------------+ + + * Exists but always fails */ #pragma once @@ -185,9 +190,15 @@ #include #include #include +#include + -#ifndef OLC_V2D_TYPE -#define OLC_V2D_TYPE +#ifdef PGE_VER +#error "olcUTIL_Geometry2D.h must be included BEFORE olcPixelGameEngine.h" +#else + + +#if !defined(OLC_VECTOR2D_DEFINED) namespace olc { /* @@ -306,7 +317,7 @@ namespace olc // Linearly interpolate between this vector, and another vector, given normalised parameter 't' inline constexpr v_2d lerp(const v_2d& v1, const double t) const { - return (T(1.0 - t)) + (v1 * T(t)); + return (*this) * (T(1.0 - t)) + (v1 * T(t)); } // Compare if this vector is numerically equal to another @@ -322,11 +333,17 @@ namespace olc } // Return this vector as a std::string, of the form "(x,y)" - inline constexpr std::string str() const + inline std::string str() const { return std::string("(") + std::to_string(this->x) + "," + std::to_string(this->y) + ")"; } + // Assuming this vector is incident, given a normal, return the reflection + inline constexpr v_2d reflect(const v_2d& n) const + { + return (*this) - 2.0 * (this->dot(n) * n); + } + // Allow 'casting' from other v_2d types template inline constexpr operator v_2d() const @@ -479,7 +496,7 @@ namespace olc { os << rhs.str(); return os; - } + } // Convenient types ready-to-go typedef v_2d vi2d; @@ -487,8 +504,7 @@ namespace olc typedef v_2d vf2d; typedef v_2d vd2d; } -#else - #include "olcPixelGameEngine.h" +#define OLC_VECTOR2D_DEFINED 1 #endif @@ -564,7 +580,7 @@ namespace olc::utils::geom2d return vector().mag2(); } - + // Given a real distance, get point along line inline constexpr olc::v_2d rpoint(const T& distance) const @@ -608,7 +624,7 @@ namespace olc::utils::geom2d } double m = (y2 - y1) / (x2 - x1); - return olc::vd2d {m, -m * x1 + y1}; + return olc::vd2d{ m, -m * x1 + y1 }; } }; @@ -670,7 +686,8 @@ namespace olc::utils::geom2d if ((i & 0b11) == 0) return top(); if ((i & 0b11) == 1) return right(); if ((i & 0b11) == 2) return bottom(); - if ((i & 0b11) == 3) return left(); + //if ((i & 0b11) == 3) return left(); // Dumb compilers cant fathom this + return left(); } // Get area of rectangle @@ -788,7 +805,7 @@ namespace olc::utils::geom2d // Returns closest point on line to point template inline olc::v_2d closest(const line& l, const olc::v_2d& p) - { + { auto d = l.vector(); double u = std::clamp(double(d.dot(p - l.start)) / d.mag2(), 0.0, 1.0); return l.start + u * d; @@ -798,7 +815,7 @@ namespace olc::utils::geom2d // Returns closest point on circle to point template inline olc::v_2d closest(const circle& c, const olc::v_2d& p) - { + { return c.pos + olc::vd2d(p - c.pos).norm() * c.radius; } @@ -865,6 +882,15 @@ namespace olc::utils::geom2d } } + // closest(ray,p) + // Returns closest point on ray to point + template + inline olc::v_2d closest(const ray& r, const olc::v_2d& p) + { + // TODO: implement + return p; + } + // Closest location on [SHAPE] to Line @@ -928,10 +954,9 @@ namespace olc::utils::geom2d // closest(c,c) // Returns closest point on circle to circle template - inline olc::v_2d closest(const circle& c, const circle& l) + inline olc::v_2d closest(const circle& c1, const circle& c2) { - // TODO: - return {}; + return closest(c1, c2.pos); } // closest(t,c) @@ -982,7 +1007,7 @@ namespace olc::utils::geom2d return {}; } - + @@ -1019,7 +1044,7 @@ namespace olc::utils::geom2d inline constexpr bool contains(const rect& r, const olc::v_2d& p) { return !(p.x < r.pos.x || p.y < r.pos.y || - p.x > (r.pos.x + r.size.x) || p.y > (r.pos.y + r.size.y)); + p.x >(r.pos.x + r.size.x) || p.y >(r.pos.y + r.size.y)); } // contains(c,p) @@ -1043,10 +1068,35 @@ namespace olc::utils::geom2d return s >= T2(0) && v >= T2(0) && (s + v) <= T2(2) * A * sign; } + template + inline constexpr bool contains(const ray& r, const olc::v_2d& p) + { + // Calculate the vector from the ray's origin to point p + olc::v_2d op = p - r.origin; + + // Calculate the dot product between op and the ray's direction + // This checks if p is in the direction of the ray and not behind the origin + T2 dotProduct = op.dot(r.direction); + + if (dotProduct < 0) { + // p is behind the ray's origin + return false; + } + + // Project op onto the ray's direction (which is already normalized) + olc::v_2d projection = { r.direction.x * dotProduct, r.direction.y * dotProduct }; + + // Check if the projection of op onto the ray's direction is equivalent to op + // This is true if p lies on the ray + + T2 distance = std::sqrt((projection.x - op.x) * (projection.x - op.x) + (projection.y - op.y) * (projection.y - op.y)); + // Assuming a small threshold for floating point arithmetic issues + return distance < epsilon; + } // overlaps(p,p) - // Check if point overlaps with point (analagous to contains()) + // Check if point overlaps with point (analogous to contains()) template inline constexpr bool overlaps(const olc::v_2d& p1, const olc::v_2d& p2) { @@ -1095,7 +1145,7 @@ namespace olc::utils::geom2d { if (contains(p1, p2)) return { p1 }; - + return {}; } @@ -1106,7 +1156,7 @@ namespace olc::utils::geom2d { if (contains(l, p)) return { p }; - + return {}; } @@ -1216,8 +1266,8 @@ namespace olc::utils::geom2d inline constexpr bool overlaps(const line& l1, const line& l2) { double D = ((l2.end.y - l2.start.y) * (l1.end.x - l1.start.x) - (l2.end.x - l2.start.x) * (l1.end.y - l1.start.y)); - double uA = ((l2.end.x-l2.start.x)*(l1.start.y-l2.start.y) - (l2.end.y-l2.start.y)*(l1.start.x-l2.start.x)) / D; - double uB = ((l1.end.x-l1.start.x)*(l1.start.y-l2.start.y) - (l1.end.y-l1.start.y)*(l1.start.x-l2.start.x)) / D; + double uA = ((l2.end.x - l2.start.x) * (l1.start.y - l2.start.y) - (l2.end.y - l2.start.y) * (l1.start.x - l2.start.x)) / D; + double uB = ((l1.end.x - l1.start.x) * (l1.start.y - l2.start.y) - (l1.end.y - l1.start.y) * (l1.start.x - l2.start.x)) / D; return uA >= 0 && uA <= 1 && uB >= 0 && uB <= 1; } @@ -1283,7 +1333,7 @@ namespace olc::utils::geom2d if (rn < 0.f || rn > 1.f || sn < 0.f || sn > 1.f) return {}; // Intersection not within line segment - return { l1.start + rn * l1.vector()}; + return { l1.start + rn * l1.vector() }; } // intersects(r,l) @@ -1402,7 +1452,7 @@ namespace olc::utils::geom2d template inline constexpr bool contains(const circle& c, const rect& r) { - return contains(c, r.pos) + return contains(c, r.pos) && contains(c, olc::v_2d{ r.pos.x + r.size.x, r.pos.y }) && contains(c, olc::v_2d{ r.pos.x, r.pos.y + r.size.y }) && contains(c, r.pos + r.size); @@ -1413,9 +1463,9 @@ namespace olc::utils::geom2d template inline constexpr bool contains(const triangle& t, const rect& r) { - return contains(t, r.pos) + return contains(t, r.pos) && contains(t, r.pos + r.size) - && contains(t, olc::v_2d{ r.pos.x + r.size.x,r.pos.y }) + && contains(t, olc::v_2d{ r.pos.x + r.size.x, r.pos.y }) && contains(t, olc::v_2d{ r.pos.x, r.pos.y + r.size.y }); } @@ -1486,7 +1536,7 @@ namespace olc::utils::geom2d template inline std::vector> intersects(const line& l, const rect& r) { - return intersects(r,l); + return intersects(r, l); } // intersects(r,r) @@ -1582,7 +1632,8 @@ namespace olc::utils::geom2d template inline constexpr bool contains(const circle& c1, const circle& c2) { - return (c1.pos - c2.pos).mag2() <= (c1.radius - c2.radius) * (c1.radius - c2.radius); + return (std::sqrt(std::pow(c2.pos.x - c1.pos.x, 2) + std::pow(c2.pos.y - c1.pos.y, 2)) + c2.radius) <= c1.radius; + } // contains(t,c) @@ -1667,13 +1718,13 @@ namespace olc::utils::geom2d inline std::vector> intersects(const circle& c1, const circle& c2) { if (c1.pos == c2.pos) return {}; // circles are either within one another so cannot intersect, or are - // identical so share all points which there's no good way to represent in return value. + // identical so share all points which there's no good way to represent in return value. v_2d between = c2.pos - c1.pos; float dist2 = between.mag2(); float radiusSum = c1.radius + c2.radius; - if (dist2 > radiusSum*radiusSum) return {}; // circles are too far apart to be touching. + if (dist2 > radiusSum * radiusSum) return {}; // circles are too far apart to be touching. if (contains(c1, c2) || contains(c2, c1)) return {}; // one circle is inside of the other, they can't be intersecting. - if (dist2 == radiusSum) return {c1.pos + between.norm() * c1.radius}; // circles are touching at exactly 1 point + if (dist2 == radiusSum) return { c1.pos + between.norm() * c1.radius }; // circles are touching at exactly 1 point // otherwise they're touching at 2 points. // // ______ ________ @@ -1699,10 +1750,10 @@ namespace olc::utils::geom2d // x is ccDist and h is halfChord. // float dist = std::sqrt(dist2); - float ccDist = (dist2 + c1.radius * c1.radius - c2.radius * c2.radius)/(2*dist); + float ccDist = (dist2 + c1.radius * c1.radius - c2.radius * c2.radius) / (2 * dist); v_2d chordCenter = c1.pos + between.norm() * ccDist; v_2d halfChord = between.norm().perp() * std::sqrt(c1.radius * c1.radius - ccDist * ccDist); - return {chordCenter + halfChord, chordCenter - halfChord}; + return { chordCenter + halfChord, chordCenter - halfChord }; } // intersects(t,c) @@ -1884,14 +1935,14 @@ namespace olc::utils::geom2d return circle(p, 0); } - + // envelope_c(l) // Return circle that fully encapsulates a line template inline constexpr circle envelope_c(const line& l) { - return {l.upoint(0.5),l.vector().mag()/2}; + return { l.upoint(0.5),l.vector().mag() / 2 }; } // envelope_c(r) @@ -1920,22 +1971,22 @@ namespace olc::utils::geom2d double D = 2 * (t.pos[0].x * (t.pos[1].y - t.pos[2].y) + t.pos[1].x * (t.pos[2].y - t.pos[0].y) + t.pos[2].x * (t.pos[0].y - t.pos[1].y)); circumcenter.x = T1(double( - (t.pos[0].x * t.pos[0].x + t.pos[0].y * t.pos[0].y) * (t.pos[1].y - t.pos[2].y) + - (t.pos[1].x * t.pos[1].x + t.pos[1].y * t.pos[1].y) * (t.pos[2].y - t.pos[0].y) + + (t.pos[0].x * t.pos[0].x + t.pos[0].y * t.pos[0].y) * (t.pos[1].y - t.pos[2].y) + + (t.pos[1].x * t.pos[1].x + t.pos[1].y * t.pos[1].y) * (t.pos[2].y - t.pos[0].y) + (t.pos[2].x * t.pos[2].x + t.pos[2].y * t.pos[2].y) * (t.pos[0].y - t.pos[1].y) - ) / D); + ) / D); circumcenter.y = T1(double( - (t.pos[0].x * t.pos[0].x + t.pos[0].y * t.pos[0].y) * (t.pos[2].x - t.pos[1].x) + + (t.pos[0].x * t.pos[0].x + t.pos[0].y * t.pos[0].y) * (t.pos[2].x - t.pos[1].x) + (t.pos[1].x * t.pos[1].x + t.pos[1].y * t.pos[1].y) * (t.pos[0].x - t.pos[2].x) + (t.pos[2].x * t.pos[2].x + t.pos[2].y * t.pos[2].y) * (t.pos[1].x - t.pos[0].x) - ) / D); + ) / D); double r = 0; for (auto& point : t.pos) { r = std::max(r, double(std::hypot(circumcenter.x - point.x, circumcenter.y - point.y))); } - return {circumcenter, T1(r)}; + return { circumcenter, T1(r) }; } @@ -1958,11 +2009,11 @@ namespace olc::utils::geom2d template inline constexpr rect envelope_r(const line& l) { - T1 min_x=std::min(l.start.x,l.end.x); - T1 min_y=std::min(l.start.y,l.end.y); - T1 size_x=std::abs(l.start.x-l.end.x); - T1 size_y=std::abs(l.start.y-l.end.y); - return {{min_x,min_y},{size_x,size_y}}; + T1 min_x = std::min(l.start.x, l.end.x); + T1 min_y = std::min(l.start.y, l.end.y); + T1 size_x = std::abs(l.start.x - l.end.x); + T1 size_y = std::abs(l.start.y - l.end.y); + return { {min_x,min_y},{size_x,size_y} }; } // envelope_r(r) @@ -1977,7 +2028,7 @@ namespace olc::utils::geom2d // Return rectangle that fully encapsulates a circle template inline constexpr rect envelope_r(const circle& c) - { + { return rect(c.pos - v_2d{c.radius, c.radius}, { c.radius * 2, c.radius * 2 }); } @@ -1991,13 +2042,13 @@ namespace olc::utils::geom2d return rect(vMin, vMax - vMin); } - template + template inline constexpr auto bounding_box(T&& t) { return envelope_r(std::forward(t)); } - template + template inline constexpr auto bounding_circle(T&& t) { return envelope_c(std::forward(t)); @@ -2082,7 +2133,7 @@ namespace olc::utils::geom2d olc::v_2d vClosest; for (const auto& vContact : vAllIntersections) { - double dDistance = (vContact - c.pos).mag2(); + double dDistance = (vContact - q.origin).mag2(); if (dDistance < dClosest) { dClosest = dDistance; @@ -2098,8 +2149,37 @@ namespace olc::utils::geom2d template inline std::optional> project(const circle& c, const rect& r, const ray& q) { - // TODO: - return std::nullopt; + const auto s1 = project(c, r.top(), q); + const auto s2 = project(c, r.bottom(), q); + const auto s3 = project(c, r.left(), q); + const auto s4 = project(c, r.right(), q); + + std::vector> vAllIntersections; + if (s1.has_value()) vAllIntersections.push_back(s1.value()); + if (s2.has_value()) vAllIntersections.push_back(s2.value()); + if (s3.has_value()) vAllIntersections.push_back(s3.value()); + if (s4.has_value()) vAllIntersections.push_back(s4.value()); + + if (vAllIntersections.size() == 0) + { + // No intersections at all, so + return std::nullopt; + } + + // Find closest + double dClosest = std::numeric_limits::max(); + olc::v_2d vClosest; + for (const auto& vContact : vAllIntersections) + { + double dDistance = (vContact - q.origin).mag2(); + if (dDistance < dClosest) + { + dClosest = dDistance; + vClosest = vContact; + } + } + + return vClosest; } // project(c,t) @@ -2107,8 +2187,35 @@ namespace olc::utils::geom2d template inline std::optional> project(const circle& c, const triangle& t, const ray& q) { - // TODO: - return std::nullopt; + const auto s1 = project(c, t.side(0), q); + const auto s2 = project(c, t.side(1), q); + const auto s3 = project(c, t.side(2), q); + + std::vector> vAllIntersections; + if (s1.has_value()) vAllIntersections.push_back(s1.value()); + if (s2.has_value()) vAllIntersections.push_back(s2.value()); + if (s3.has_value()) vAllIntersections.push_back(s3.value()); + + if (vAllIntersections.size() == 0) + { + // No intersections at all, so + return std::nullopt; + } + + // Find closest + double dClosest = std::numeric_limits::max(); + olc::v_2d vClosest; + for (const auto& vContact : vAllIntersections) + { + double dDistance = (vContact - q.origin).mag2(); + if (dDistance < dClosest) + { + dClosest = dDistance; + vClosest = vContact; + } + } + + return vClosest; } @@ -2141,6 +2248,19 @@ namespace olc::utils::geom2d return {}; // Intersection, but behind a rays origin, so not really an intersection in context } + // intersects(q,p) + // return intersection point (if it exists) of a ray and a point + template + inline std::vector> intersects(const ray& q, const v_2d& p) + { + const line l = { q.origin, q.origin + q.direction }; + + if (std::abs(l.side(p)) < epsilon) + return { p }; // Intersection + else + return {}; + } + // intersects(q,l) // return intersection point (if it exists) of a ray and a line segment template @@ -2167,9 +2287,180 @@ namespace olc::utils::geom2d return { q.origin + q.direction * t1 }; // Intersection, both rays positive else return {}; // Intersection, but behind a rays origin, or outside line segment bounds. - // so not really an intersection in context + // so not really an intersection in context } + // collision(q,l) + // optionally returns collision point and collision normal of ray and a line segment, if it collides + template + inline std::optional, olc::v_2d>> collision(const ray& q, const line& l) + { + const auto vIntersection = intersects(q, l); + if (vIntersection.size() > 0) + { + return { {vIntersection[0], l.vector().perp().norm() * l.side(q.origin)} }; + } + + return std::nullopt; + } + + // reflect(q,l) + // optionally returns a ray reflected off a line segement if collision occurs + template + inline std::optional> reflect(const ray& q, const line& l) + { + const auto vCollision = collision(q, l); + if (vCollision.has_value()) + { + return { ray{vCollision.value().first, q.direction.reflect(vCollision.value().second)} }; + } + + return std::nullopt; + } + + // reflect(q,p) + // optionally returns a ray reflected off a point if collision occurs + template + inline std::optional> reflect(const ray& q, const olc::v_2d& p) + { + // TODO: + return std::nullopt; + } + + // collision(q,r) + // optionally returns collision point and collision normal of ray and a line segment, if it collides + template + inline std::optional, olc::v_2d>> collision(const ray& q, const rect& r) + { + olc::v_2d vClosestIntersection; + olc::v_2d vIntersectionNormal; + double dClosestDistance2 = std::numeric_limits::max(); + bool bCollide = false; + + for (size_t i = 0; i < r.side_count(); i++) + { + auto v = intersects(q, r.side(i)); + if (v.size() > 0) + { + bCollide = true; + double d = (v[0] - q.origin).mag2(); + if (d < dClosestDistance2) + { + dClosestDistance2 = d; + vClosestIntersection = v[0]; + vIntersectionNormal = r.side(i).vector().perp().norm(); + } + } + } + + if (bCollide) + { + return { {vClosestIntersection, vIntersectionNormal} }; + } + + return std::nullopt; + } + + // reflect(q,r) + // optionally returns a ray reflected off a rectangle if collision occurs + template + inline std::optional> reflect(const ray& q, const rect& r) + { + const auto vCollision = collision(q, r); + if (vCollision.has_value()) + { + return { ray{vCollision.value().first, q.direction.reflect(vCollision.value().second)} }; + } + + return std::nullopt; + } + + // collision(q,c) + // optionally returns collision point and collision normal of ray and a circle, if it collides + template + inline std::optional, olc::v_2d>> collision(const ray& q, const circle& c) + { + const auto vIntersection = intersects(q, c); + if (vIntersection.size() > 0) + { + return { {vIntersection[0], (vIntersection[0] - c.pos).norm()} }; + } + + return std::nullopt; + } + + // reflect(q,c) + // optionally returns a ray reflected off a circle if collision occurs + template + inline std::optional> reflect(const ray& q, const circle& c) + { + const auto vCollision = collision(q, c); + if (vCollision.has_value()) + { + return { ray{vCollision.value().first, q.direction.reflect(vCollision.value().second)} }; + } + + return std::nullopt; + } + + // collision(q,r) + // optionally returns collision point and collision normal of ray and a triangle, if it collides + template + inline std::optional, olc::v_2d>> collision(const ray& q, const triangle& t) + { + olc::v_2d vClosestIntersection; + olc::v_2d vIntersectionNormal; + double dClosestDistance2 = std::numeric_limits::max(); + bool bCollide = false; + + for (size_t i = 0; i < t.side_count(); i++) + { + auto v = intersects(q, t.side(i)); + if (v.size() > 0) + { + bCollide = true; + double d = (v[0] - q.origin).mag2(); + if (d < dClosestDistance2) + { + dClosestDistance2 = d; + vClosestIntersection = v[0]; + vIntersectionNormal = t.side(i).vector().perp().norm(); + } + } + } + + if (bCollide) + { + return { {vClosestIntersection, vIntersectionNormal} }; + } + + return std::nullopt; + } + + // reflect(q,t) + // optionally returns a ray reflected off a triangle if collision occurs + template + inline std::optional> reflect(const ray& q, const triangle& t) + { + const auto vCollision = collision(q, t); + if (vCollision.has_value()) + { + return { ray{vCollision.value().first, q.direction.reflect(vCollision.value().second)} }; + } + + return std::nullopt; + } + + // reflect(q,r) + // can't reflect a ray of a ray + template + inline std::optional> reflect(const ray& q1, const ray& q2) + { + // Can't reflect! + return std::nullopt; + } + + // intersects(q,c) // Get intersection points where a ray intersects a circle template @@ -2196,7 +2487,8 @@ namespace olc::utils::geom2d if (s2 < 0) return { q.origin + q.direction * s1 }; - return { q.origin + q.direction * std::min(s1, s2) }; + const auto [min_s, max_s] = std::minmax(s1, s2); + return { q.origin + q.direction * min_s, q.origin + q.direction * max_s }; } } @@ -2232,3 +2524,5 @@ namespace olc::utils::geom2d return internal::filter_duplicate_points(intersections); } } + +#endif // PGE_VER diff --git a/utilities/olcUTIL_QuadTree.h b/utilities/olcUTIL_QuadTree.h index 2a52a6dd..5713066b 100644 --- a/utilities/olcUTIL_QuadTree.h +++ b/utilities/olcUTIL_QuadTree.h @@ -1,5 +1,5 @@ /* - OneLoneCoder - QuadTree v1.01 + OneLoneCoder - QuadTree v1.02 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A Dynamic Quad-Tree implementation to store objects in a 2D space with a fast retrieval. @@ -54,6 +54,8 @@ Changes ~~~~~~~ v1.01: Bug fix clear() function + v1.02: File Restructure + +Added insertion return iterator */ @@ -73,17 +75,16 @@ #pragma once -#include "olcPixelGameEngine.h" -#include "olcUTIL_Geometry2D.h" - - +#include namespace olc::utils { template struct QuadTreeItemLocation { + // Pointer to Top-Level Container typename std::list, T>>* container = nullptr; + // Iterator that points to item in Top-Level Container typename std::list, T>>::iterator iterator; }; @@ -202,7 +203,7 @@ namespace olc::utils { clear(); m_rect = rArea; - olc::v2d_generic vChildSize = m_rect.size / CTYPE(2); + olc::v_2d vChildSize = m_rect.size / CTYPE(2); m_rChild = { geom2d::rect(m_rect.pos, vChildSize), @@ -265,7 +266,7 @@ namespace olc::utils } // Inserts an item into the quadtree - void insert(const T& item, const geom2d::rect& itemsize) + typename IQuadtreeContainer::iterator insert(const T& item, const geom2d::rect& itemsize) { QuadTreeItem newItem; newItem.item = item; @@ -275,6 +276,8 @@ namespace olc::utils // Pointer/Area of item is stored in geom2d::rect tree m_allItems.back().pItem = root.insert(std::prev(m_allItems.end()), itemsize); + + return std::prev(m_allItems.end()); } // Returns a std::list of pointers to items within the search area From 27ef0f8b888672a20b5b3da12392c2b6e935ba9f Mon Sep 17 00:00:00 2001 From: Javidx9 <25419386+OneLoneCoder@users.noreply.github.com> Date: Mon, 2 Sep 2024 20:35:46 +0100 Subject: [PATCH 3/3] Point to local geometry2d by default --- utilities/olcUTIL_Animate2D.h | 2 +- utilities/olcUTIL_QuadTree.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/utilities/olcUTIL_Animate2D.h b/utilities/olcUTIL_Animate2D.h index 39bf839d..a78415d7 100644 --- a/utilities/olcUTIL_Animate2D.h +++ b/utilities/olcUTIL_Animate2D.h @@ -58,7 +58,7 @@ #pragma once -#include +#include "utilities/olcUTIL_Geometry2D.h" #include "olcPixelGameEngine.h" #include diff --git a/utilities/olcUTIL_QuadTree.h b/utilities/olcUTIL_QuadTree.h index 5713066b..5593ce0b 100644 --- a/utilities/olcUTIL_QuadTree.h +++ b/utilities/olcUTIL_QuadTree.h @@ -75,7 +75,7 @@ #pragma once -#include +#include "utilities/olcUTIL_Geometry2D.h" namespace olc::utils {