7 * @brief Computes line-plane intersection |
7 * @brief Computes line-plane intersection |
8 * @param line |
8 * @param line |
9 * @param plane |
9 * @param plane |
10 * @return point of intersection. Does not return a value if the line is in parallel to the plane. |
10 * @return point of intersection. Does not return a value if the line is in parallel to the plane. |
11 */ |
11 */ |
12 std::optional<glm::vec3> geom::linePlaneIntersection( |
12 std::optional<glm::vec3> linePlaneIntersection( |
13 const geom::Line<3>& line, |
13 const Line<3>& line, |
14 const geom::Plane& plane, |
14 const Plane& plane, |
15 const float epsilon) |
15 const float epsilon) |
16 { |
16 { |
17 const float denominator = glm::dot(line.direction, plane.normal); |
17 const float denominator = glm::dot(line.direction, plane.normal); |
18 if (std::abs(denominator) < epsilon) |
18 if (std::abs(denominator) < epsilon) |
19 { |
19 { |
29 /** |
29 /** |
30 * @brief Computes the plane of a triangle |
30 * @brief Computes the plane of a triangle |
31 * @param triangle |
31 * @param triangle |
32 * @return plane |
32 * @return plane |
33 */ |
33 */ |
34 geom::Plane geom::planeFromTriangle(const geom::Triangle& triangle) |
34 Plane planeFromTriangle(const Triangle& triangle) |
35 { |
35 { |
36 return geom::Plane{normalVector(triangle), triangle.p1}; |
36 return Plane{normalVector(triangle), triangle.p1}; |
37 } |
37 } |
38 |
38 |
39 /** |
39 /** |
40 * @brief Computes the normal vector of a triangle |
40 * @brief Computes the normal vector of a triangle |
41 * @param triangle |
41 * @param triangle |
42 * @return normal vector |
42 * @return normal vector |
43 */ |
43 */ |
44 glm::vec3 geom::normalVector(const geom::Triangle& triangle) |
44 glm::vec3 normalVector(const Triangle& triangle) |
45 { |
45 { |
46 return glm::normalize( |
46 return glm::normalize( |
47 glm::cross( |
47 glm::cross( |
48 triangle.p2 - triangle.p1, |
48 triangle.p2 - triangle.p1, |
49 triangle.p3 - triangle.p1)); |
49 triangle.p3 - triangle.p1)); |
53 * @brief Extracts the scaling component of the specified matrix into a vector and returns both the scaling |
53 * @brief Extracts the scaling component of the specified matrix into a vector and returns both the scaling |
54 * components as well as the unscaled matrix. |
54 * components as well as the unscaled matrix. |
55 * @param matrix Matrix to compute |
55 * @param matrix Matrix to compute |
56 * @return scaling vector and unscaled matrix |
56 * @return scaling vector and unscaled matrix |
57 */ |
57 */ |
58 geom::ScalingExtract geom::extractScaling(const glm::mat4& matrix) |
58 ScalingExtract extractScaling(const glm::mat4& matrix) |
59 { |
59 { |
60 geom::ScalingExtract result; |
60 ScalingExtract result; |
61 result.scaling = geom::scalingVector(matrix); |
61 result.scaling = scalingVector(matrix); |
62 result.unscaled = glm::scale(matrix, 1.0f / result.scaling); |
62 result.unscaled = glm::scale(matrix, 1.0f / result.scaling); |
63 return result; |
63 return result; |
64 } |
64 } |
65 |
65 |
66 /** |
66 /** |
67 * @brief Computes the scaling vector, which contains the scaling of the specified matrix |
67 * @brief Computes the scaling vector, which contains the scaling of the specified matrix |
68 * @param matrix |
68 * @param matrix |
69 * @return scaling vector |
69 * @return scaling vector |
70 */ |
70 */ |
71 glm::vec3 geom::scalingVector(const glm::mat4 matrix) |
71 glm::vec3 scalingVector(const glm::mat4 matrix) |
72 { |
72 { |
73 auto component = [](const glm::mat4& matrix, const int i) -> float |
73 auto component = [](const glm::mat4& matrix, const int i) -> float |
74 { |
74 { |
75 return std::hypot(std::hypot(matrix[i][0], matrix[i][1]), matrix[i][2]); |
75 return std::hypot(std::hypot(matrix[i][0], matrix[i][1]), matrix[i][2]); |
76 }; |
76 }; |
77 return glm::vec3{component(matrix, 0), component(matrix, 1), component(matrix, 2)}; |
77 return glm::vec3{component(matrix, 0), component(matrix, 1), component(matrix, 2)}; |
78 } |
78 } |
79 |
79 |
80 std::optional<glm::vec2> geom::lineLineIntersection(const Line<2>& line_1, const Line<2>& line_2) |
80 std::optional<glm::vec2> lineLineIntersection(const Line<2>& line_1, const Line<2>& line_2) |
81 { |
81 { |
82 const float denominator = (line_1.direction.x * line_2.direction.y) - (line_1.direction.y * line_2.direction.x); |
82 const float denominator = (line_1.direction.x * line_2.direction.y) - (line_1.direction.y * line_2.direction.x); |
83 constexpr float epsilon = 1e-6f; |
83 constexpr float epsilon = 1e-6f; |
84 if (std::abs(denominator) < epsilon) |
84 if (std::abs(denominator) < epsilon) |
85 { |
85 { |
101 const float y = glm::determinant(glm::mat2{{a, b}, {c_y, d_y}}); |
101 const float y = glm::determinant(glm::mat2{{a, b}, {c_y, d_y}}); |
102 return glm::vec2{x / denominator, y / denominator}; |
102 return glm::vec2{x / denominator, y / denominator}; |
103 } |
103 } |
104 } |
104 } |
105 |
105 |
106 std::optional<glm::vec2> geom::rayLineSegmentIntersection(const Ray<2>& ray, const LineSegment2D& line) |
106 std::optional<glm::vec2> rayLineSegmentIntersection(const Ray<2>& ray, const LineSegment2D& line) |
107 { |
107 { |
108 std::optional<glm::vec2> result = lineLineIntersection( |
108 std::optional<glm::vec2> result = lineLineIntersection( |
109 rayToLine(ray), |
109 rayToLine(ray), |
110 lineFromPoints(line.p1, line.p2)); |
110 lineFromPoints(line.p1, line.p2)); |
111 if (result.has_value()) |
111 if (result.has_value()) |
125 } |
125 } |
126 } |
126 } |
127 return result; |
127 return result; |
128 } |
128 } |
129 |
129 |
130 std::optional<geom::PointOnRectagle> geom::rayRectangleIntersection(const Ray<2>& ray, const QRectF& rectangle) |
130 std::optional<PointOnRectagle> rayRectangleIntersection(const Ray<2>& ray, const QRectF& rectangle) |
131 { |
131 { |
132 std::optional<glm::vec2> position; |
132 std::optional<glm::vec2> position; |
133 std::optional<PointOnRectagle> result; |
133 std::optional<PointOnRectagle> result; |
134 // Try top |
134 // Try top |
135 position = rayLineSegmentIntersection(ray, top(rectangle)); |
135 position = rayLineSegmentIntersection(ray, top(rectangle)); |
165 } |
165 } |
166 } |
166 } |
167 return result; |
167 return result; |
168 } |
168 } |
169 |
169 |
170 geom::LineSegment2D geom::top(const QRectF& rectangle) |
170 LineSegment2D top(const QRectF& rectangle) |
171 { |
171 { |
172 return { |
172 return { |
173 glm::vec2{rectangle.left(), rectangle.top()}, |
173 glm::vec2{rectangle.left(), rectangle.top()}, |
174 glm::vec2{rectangle.right(), rectangle.top()} |
174 glm::vec2{rectangle.right(), rectangle.top()} |
175 }; |
175 }; |
176 } |
176 } |
177 |
177 |
178 geom::LineSegment2D geom::bottom(const QRectF& rectangle) |
178 LineSegment2D bottom(const QRectF& rectangle) |
179 { |
179 { |
180 return { |
180 return { |
181 glm::vec2{rectangle.left(), rectangle.bottom()}, |
181 glm::vec2{rectangle.left(), rectangle.bottom()}, |
182 glm::vec2{rectangle.right(), rectangle.bottom()} |
182 glm::vec2{rectangle.right(), rectangle.bottom()} |
183 }; |
183 }; |
184 } |
184 } |
185 |
185 |
186 geom::LineSegment2D geom::left(const QRectF& rectangle) |
186 LineSegment2D left(const QRectF& rectangle) |
187 { |
187 { |
188 return { |
188 return { |
189 glm::vec2{rectangle.left(), rectangle.top()}, |
189 glm::vec2{rectangle.left(), rectangle.top()}, |
190 glm::vec2{rectangle.left(), rectangle.bottom()} |
190 glm::vec2{rectangle.left(), rectangle.bottom()} |
191 }; |
191 }; |
192 } |
192 } |
193 |
193 |
194 geom::LineSegment2D geom::right(const QRectF& rectangle) |
194 LineSegment2D right(const QRectF& rectangle) |
195 { |
195 { |
196 return { |
196 return { |
197 glm::vec2{rectangle.right(), rectangle.top()}, |
197 glm::vec2{rectangle.right(), rectangle.top()}, |
198 glm::vec2{rectangle.right(), rectangle.bottom()} |
198 glm::vec2{rectangle.right(), rectangle.bottom()} |
199 }; |
199 }; |
200 } |
200 } |
201 |
201 |
202 bool geom::isConvex(const std::vector<glm::vec3>& polygon) |
202 bool isConvex(const std::vector<glm::vec3>& polygon) |
203 { |
203 { |
204 const int n = polygon.size(); |
204 const int n = polygon.size(); |
205 auto polygonRing = iter::ring(polygon, n); |
205 auto polygonRing = iter::ring(polygon, n); |
206 std::vector<glm::vec3> crosses; |
206 std::vector<glm::vec3> crosses; |
207 crosses.resize(n); |
207 crosses.resize(n); |
240 * @brief computes the point on a Bezier curve |
240 * @brief computes the point on a Bezier curve |
241 * @param curve |
241 * @param curve |
242 * @param t scalar between 0 and 1, with t=0 being P0 and t=1 being P3 |
242 * @param t scalar between 0 and 1, with t=0 being P0 and t=1 being P3 |
243 * @return point on curve |
243 * @return point on curve |
244 */ |
244 */ |
245 glm::vec3 geom::pointOnCurve(const BezierCurve &curve, float t) |
245 glm::vec3 pointOnCurve(const BezierCurve &curve, float t) |
246 { |
246 { |
247 // clamp t as rounding errors might make it slightly out of bounds |
247 // clamp t as rounding errors might make it slightly out of bounds |
248 t = std::clamp(t, 0.0f, 1.0f); |
248 t = std::clamp(t, 0.0f, 1.0f); |
249 const float t_2 = t * t; |
249 const float t_2 = t * t; |
250 const float t_3 = t * t * t; |
250 const float t_3 = t * t * t; |
260 * @brief computes the derivative of a point on a Bezier curve |
260 * @brief computes the derivative of a point on a Bezier curve |
261 * @param curve |
261 * @param curve |
262 * @param t scalar between 0 and 1, with t=0 being P0 and t=1 being P3 |
262 * @param t scalar between 0 and 1, with t=0 being P0 and t=1 being P3 |
263 * @return point on curve |
263 * @return point on curve |
264 */ |
264 */ |
265 glm::vec3 geom::derivativeOnCurve(const BezierCurve &curve, float t) |
265 glm::vec3 derivativeOnCurve(const BezierCurve &curve, float t) |
266 { |
266 { |
267 // clamp t as rounding errors might make it slightly out of bounds |
267 // clamp t as rounding errors might make it slightly out of bounds |
268 t = std::clamp(t, 0.0f, 1.0f); |
268 t = std::clamp(t, 0.0f, 1.0f); |
269 const float t_2 = t * t; |
269 const float t_2 = t * t; |
270 const float coeffs[4] = { |
270 const float coeffs[4] = { |