--- a/src/geometry.cpp Fri Mar 06 20:13:10 2020 +0200 +++ b/src/geometry.cpp Fri Mar 06 21:53:30 2020 +0200 @@ -2,23 +2,15 @@ #include "geometry.h" /** - * @brief Computes a line from two points - * @param point_1 - * @param point_2 - * @return line - */ -geom::Line geom::lineFromPoints(const glm::vec3& point_1, const glm::vec3 point_2) -{ - return {point_2 - point_1, point_1}; -} - -/** * @brief Computes line-plane intersection * @param line * @param plane * @return point of intersection. Does not return a value if the line is in parallel to the plane. */ -std::optional<glm::vec3> geom::linePlaneIntersection(const geom::Line& line, const geom::Plane& plane, const float epsilon) +std::optional<glm::vec3> geom::linePlaneIntersection( + const geom::Line<3>& line, + const geom::Plane& plane, + const float epsilon) { const float denominator = glm::dot(line.direction, plane.normal); if (std::abs(denominator) < epsilon) @@ -82,3 +74,123 @@ }; return glm::vec3{component(matrix, 0), component(matrix, 1), component(matrix, 2)}; } + +std::optional<glm::vec2> geom::lineLineIntersection(const Line<2>& line_1, const Line<2>& line_2) +{ + const float denominator = (line_1.direction.x * line_2.direction.y) - (line_1.direction.y * line_2.direction.x); + constexpr float epsilon = 1e-6f; + if (std::abs(denominator) < epsilon) + { + return {}; + } + else + { + const glm::vec2 p1 = line_1.anchor + line_1.direction; + const glm::vec2& p2 = line_1.anchor; + const glm::vec2 p3 = line_2.anchor + line_2.direction; + const glm::vec2& p4 = line_2.anchor; + const float a = glm::determinant(glm::mat2{{p1.x, p2.x}, {p1.y, p2.y}}); + const float b = glm::determinant(glm::mat2{{p3.x, p4.x}, {p3.y, p4.y}}); + const float c_x = glm::determinant(glm::mat2{{p1.x, p2.x}, {1, 1}}); + const float c_y = glm::determinant(glm::mat2{{p1.y, p2.y}, {1, 1}}); + const float d_x = glm::determinant(glm::mat2{{p3.x, p4.x}, {1, 1}}); + const float d_y = glm::determinant(glm::mat2{{p3.y, p4.y}, {1, 1}}); + const float x = glm::determinant(glm::mat2{{a, b}, {c_x, d_x}}); + const float y = glm::determinant(glm::mat2{{a, b}, {c_y, d_y}}); + return glm::vec2{x / denominator, y / denominator}; + } +} + +std::optional<glm::vec2> geom::rayLineSegmentIntersection(const Ray<2>& ray, const LineSegment2D& line) +{ + std::optional<glm::vec2> result = lineLineIntersection(rayToLine(ray), lineFromPoints(line.points[0], line.points[1])); + if (result.has_value()) + { + const float d1 = glm::dot(*result - ray.anchor, ray.direction); + if (d1 < 0) + { + result.reset(); + } + else + { + const float d2 = glm::dot(*result - line.points[0], *result - line.points[1]); + if (d2 > 0) + { + result.reset(); + } + } + } + return result; +} + +std::optional<geom::PointOnRectagle> geom::rayRectangleIntersection(const Ray<2>& ray, const QRectF& rectangle) +{ + std::optional<glm::vec2> position; + std::optional<PointOnRectagle> result; + // Try top + position = rayLineSegmentIntersection(ray, top(rectangle)); + if (position.has_value()) + { + result = {*position, RectangleSide::Top}; + } + else + { + // Try bottom + position = rayLineSegmentIntersection(ray, bottom(rectangle)); + if (position.has_value()) + { + result = {*position, RectangleSide::Bottom}; + } + else + { + // Try left + position = rayLineSegmentIntersection(ray, left(rectangle)); + if (position.has_value()) + { + result = {*position, RectangleSide::Left}; + } + else + { + // Try right + position = rayLineSegmentIntersection(ray, right(rectangle)); + if (position.has_value()) + { + result = {*position, RectangleSide::Right}; + } + } + } + } + return result; +} + +geom::LineSegment2D geom::top(const QRectF& rectangle) +{ + return { + glm::vec2{rectangle.left(), rectangle.top()}, + glm::vec2{rectangle.right(), rectangle.top()} + }; +} + +geom::LineSegment2D geom::bottom(const QRectF& rectangle) +{ + return { + glm::vec2{rectangle.left(), rectangle.bottom()}, + glm::vec2{rectangle.right(), rectangle.bottom()} + }; +} + +geom::LineSegment2D geom::left(const QRectF& rectangle) +{ + return { + glm::vec2{rectangle.left(), rectangle.top()}, + glm::vec2{rectangle.left(), rectangle.bottom()} + }; +} + +geom::LineSegment2D geom::right(const QRectF& rectangle) +{ + return { + glm::vec2{rectangle.right(), rectangle.top()}, + glm::vec2{rectangle.right(), rectangle.bottom()} + }; +}