src/geometry.cpp

changeset 71
198d25fe4e21
parent 64
f99d52b1646b
child 115
ed884a2fb009
--- 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()}
+	};
+}

mercurial