#pragma once #include "config/types.h" #include "maths.h" #include #include #include #include template class Ray { public: #ifndef __cpp_aggregate_paren_init Ray(PositionType start, Direction3D direction) : start {start}, direction {direction} { } #endif PositionType start; Direction3D direction; [[nodiscard]] PositionType::value_type distanceToLine(const PositionType & p1, const PositionType & e1) const { // https://en.wikipedia.org/wiki/Skew_lines const RelativePosition3D diff = p1 - e1; const auto d1 = glm::normalize(diff); const auto n = crossProduct(d1, direction); const auto n2 = crossProduct(direction, n); const auto c1 = p1 + PositionType((glm::dot(RelativePosition3D(start - p1), n2) / glm::dot(d1, n2)) * d1); const auto difflength = glm::length(diff); if (glm::length(RelativePosition3D(c1 - p1)) > difflength || glm::length(RelativePosition3D(c1 - e1)) > difflength) { return std::numeric_limits::infinity(); } return static_cast(glm::abs(glm::dot(n, RelativePosition3D(p1 - start)))); } [[nodiscard]] bool passesCloseToEdges(const std::span positions, const PositionType::value_type distance) const { return std::adjacent_find(positions.begin(), positions.end(), [this, distance](const auto & a, const auto & b) { return distanceToLine(a, b) <= distance; }) != positions.end(); } bool intersectPlane(const PositionType orig, const Direction3D norm, RelativeDistance & distance) const { if constexpr (std::is_floating_point_v) { return glm::intersectRayPlane(start, direction, orig, norm, distance) && distance >= 0.F; } else { const RelativePosition3D origr = orig - start; return glm::intersectRayPlane({}, direction, origr, norm, distance) && distance >= 0.F; } } bool intersectTriangle(const PositionType t0, const PositionType t1, const PositionType t2, BaryPosition & bary, RelativeDistance & distance) const { if constexpr (std::is_floating_point_v) { return glm::intersectRayTriangle(start, direction, t0, t1, t2, bary, distance) && distance >= 0.F; } else { const RelativePosition3D t0r = t0 - start, t1r = t1 - start, t2r = t2 - start; return glm::intersectRayTriangle({}, direction, t0r, t1r, t2r, bary, distance) && distance >= 0.F; } } bool intersectSphere(const PositionType centre, const PositionType::value_type size, PositionType & position, Normal3D & normal) const { if constexpr (std::is_floating_point_v) { return glm::intersectRaySphere(start, direction, centre, size, position, normal); } else { const RelativePosition3D cr = centre - start; RelativePosition3D positionF {}; const auto r = glm::intersectRaySphere( {}, direction, cr, static_cast(size), positionF, normal); position = GlobalPosition3D(positionF) + start; return r; } } }; class RayFactory { public: template static Ray fromPoints(PositionType start, PositionType p) { return {start, glm::normalize(p - start)}; } };