From 78c94773a9ad3a59060eed1a35f027e9cde85be1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sven=20M=C3=BCller?= Date: Mon, 5 Feb 2024 14:48:01 +0100 Subject: [PATCH] Added implementation for closest(ray, point) --- TEST_Geometry2D.cpp | 7 +++++++ olcUTIL_Geometry2D.h | 48 +++++++++++++++++++++++++++++++++++++++++--- 2 files changed, 52 insertions(+), 3 deletions(-) diff --git a/TEST_Geometry2D.cpp b/TEST_Geometry2D.cpp index fbdb6ee..dad774b 100644 --- a/TEST_Geometry2D.cpp +++ b/TEST_Geometry2D.cpp @@ -377,6 +377,13 @@ class Test_Geometry2D : public olc::PixelGameEngine // Laser beam ray ray_laser{ {10.0f, 300.0f}, {1.0f, 0.0f} }; + + // Display a light-blue point for testing the closest-function between the ray ray_laser and + // the point mouse_position + olc::vf2d mouse_position = GetMousePos(); + auto closest_between_ray_and_point = closest(ray_laser, mouse_position); + olc::PixelGameEngine::FillCircle(closest_between_ray_and_point, 2, olc::Pixel(50, 200, 255)); + bool ray_stop = false; int nBounces = 100; size_t last_hit_index = -1; diff --git a/olcUTIL_Geometry2D.h b/olcUTIL_Geometry2D.h index cedf02a..1793d54 100644 --- a/olcUTIL_Geometry2D.h +++ b/olcUTIL_Geometry2D.h @@ -173,7 +173,7 @@ | | | | | | | ---------+--------------+--------------+--------------+--------------+--------------+--------------+ RAY | | | | | | | - | | | | | | | + | closest | | | | | | | | collision | collision | collision | collision | collision* | | | intersects | intersects | intersects | intersects | intersects | | | reflect | reflect | reflect | reflect | reflect* | @@ -882,8 +882,50 @@ namespace olc::utils::geom2d template inline olc::v_2d closest(const ray& r, const olc::v_2d& p) { - // TODO: implement - return p; + // We can divide the 2d space with a vector perpendicular to the rays direction into two half-spaces. + // These will be use to differentiate between two cases. + olc::v_2d perpendicular_ray_direction = { -r.direction.y, r.direction.x }; + olc::v_2d ray_origin_to_p = p - r.origin; + bool behind_ray_origin = perpendicular_ray_direction.x * ray_origin_to_p.y + - perpendicular_ray_direction.y * ray_origin_to_p.x >= 0; + + + if (behind_ray_origin) + { + // Case 1: If p lies in the half-space where the direction of the ray does not fall into, + // then the closest point on the ray to point p will always be the origin of the ray. + // This case also includes all points lying on a line, + // which is both perpendicular to the rays direction as well as going through the rays origin. + return r.origin; + } + else + { + // Case 2: If the point p lies in the half-space where the direction of the ray is contained, + // then the closest point on the ray r to point p is the projection of p onto the r. + T1 relative_p_position = r.direction.x * ray_origin_to_p.y + - r.direction.y * ray_origin_to_p.x; + + // The point lies directly on the ray and can thus be returned as closest point. + if (relative_p_position == 0) + { + return p; + } + + // Determine the direction we have to shoot the projection ray in, based on whether the point p is to the + // left or right of ray r's direction. + olc::v_2d project_ray_direction = relative_p_position > 0 ? + -perpendicular_ray_direction : + perpendicular_ray_direction; + + // Find the closest point on ray r from point p using the ray intersection between r and the constructed + // projection_ray. + ray projection_ray = { p, project_ray_direction }; + auto intersections = intersects(r, projection_ray); + + // Given the case we are handling here, there will always be exactly one intersection, so it is safe to + // access the first element of the insertions vector. + return intersections[0]; + } }