stc
Loading...
Searching...
No Matches
Math.hpp
Go to the documentation of this file.
1
29#pragma once
30
31#include <cmath>
32#include <concepts>
33#include <stdexcept>
34
35/*
36 * TODO:
37 * * Check if it makes more sense to do triangle checks rather than raw rect checks. This might also be more
38 * generalisable?
39 */
40namespace stc::math {
41
45template <typename T, typename IT>
46concept VectorType2D = requires (const T& val) {
47 { val.x } -> std::convertible_to<IT>;
48 { val.y } -> std::convertible_to<IT>;
49};
50
51template <typename VT, typename IT>
52concept VectorType3D = requires (const VT& val) {
53 { val.x } -> std::convertible_to<IT>;
54 { val.y } -> std::convertible_to<IT>;
55 { val.z } -> std::convertible_to<IT>;
56};
57
58template <typename IT>
59concept SignedNumber = requires {
60 std::is_signed_v<IT>;
61};
62
68template <typename T>
69inline T square(const T& val){
70 return val * val;
71}
72
78namespace g2d {
79
83template <typename IT, VectorType2D<IT> VT>
84inline bool isCounterClockwise(const VT& a, const VT& b, const VT& c) {
85 return (c.y - a.y) * (b.x - a.x) > (b.y - a.y) * (c.x - a.x);
86}
87
94template <SignedNumber IT, VectorType2D<IT> VT>
96 const VT& point,
97 const VT& lineStart,
98 const VT& lineEnd
99) {
100 // TODO: is this just the dot product? Can it be replaced with
101 // 0 <= dot(AB,AM) <= dot(AB,AB) && 0 <= dot(BC,BM) <= dot(BC,BC)
102 // for any real-world benefit?
103 return (lineEnd.x - lineStart.x) * (point.y - lineStart.y)
104 - (point.x - lineStart.x) * (lineEnd.y - lineStart.y);
105}
106
113template <typename IT, VectorType2D<IT> VT>
114 requires std::equality_comparable_with<VT, VT>
116 const VT& l1Start,
117 const VT& l1End,
118 const VT& l2Start,
119 const VT& l2End
120) {
121 return (isCounterClockwise<IT, VT>(l1Start, l2Start, l2End) != isCounterClockwise<IT, VT>(l1End, l2Start, l2End)
122 && isCounterClockwise<IT, VT>(l1Start, l1End, l2Start) != isCounterClockwise<IT, VT>(l1Start, l1End, l2End)
123 )
124 || isPointOnLeftOfEdge<IT, VT>(l1Start, l2Start, l2End) == 0
125 || isPointOnLeftOfEdge<IT, VT>(l1End, l2Start, l2End) == 0;
126}
127
146template <typename IT, VectorType2D<IT> VT>
148 const VT& lineStart,
149 const VT& lineEnd,
150
151 const VT& rectCornerA,
152 const VT& rectCornerB,
153 const VT& rectCornerC,
154 const VT& rectCornerD
155) {
156 return lineIntersectsLineInclusive<IT, VT>(
157 lineStart, lineEnd,
158 rectCornerA, rectCornerB
159 ) || lineIntersectsLineInclusive<IT, VT>(
160 lineStart, lineEnd,
161 rectCornerB, rectCornerC
162 ) || lineIntersectsLineInclusive<IT, VT>(
163 lineStart, lineEnd,
164 rectCornerC, rectCornerD
165 ) || lineIntersectsLineInclusive<IT, VT>(
166 lineStart, lineEnd,
167 rectCornerD, rectCornerA
168 );
169}
170
185template <SignedNumber IT, VectorType2D<IT> VT>
187 const VT& point,
188
189 const VT& rectCornerA,
190 const VT& rectCornerB,
191 const VT& rectCornerC,
192 const VT& rectCornerD
193) {
194 return
195 isPointOnLeftOfEdge<IT, VT>(
196 point, rectCornerA, rectCornerB
197 ) > 0
198 && isPointOnLeftOfEdge<IT, VT>(
199 point, rectCornerB, rectCornerC
200 ) > 0
201 && isPointOnLeftOfEdge<IT, VT>(
202 point, rectCornerC, rectCornerD
203 ) > 0
204 && isPointOnLeftOfEdge<IT, VT>(
205 point, rectCornerD, rectCornerA
206 ) > 0;
207}
208
209
224template <SignedNumber IT, VectorType2D<IT> VT>
226 const VT& point,
227
228 const VT& rectCornerA,
229 const VT& rectCornerB,
230 const VT& rectCornerC,
231 const VT& rectCornerD
232) {
233 return
234 isPointOnLeftOfEdge<IT, VT>(
235 point, rectCornerA, rectCornerB
236 ) >= 0
237 && isPointOnLeftOfEdge<IT, VT>(
238 point, rectCornerB, rectCornerC
239 ) >= 0
240 && isPointOnLeftOfEdge<IT, VT>(
241 point, rectCornerC, rectCornerD
242 ) >= 0
243 && isPointOnLeftOfEdge<IT, VT>(
244 point, rectCornerD, rectCornerA
245 ) >= 0;
246}
247
248
255template <typename IT, VectorType2D<IT> VT>
257 const VT& point,
258
259 const VT& startPosition,
260 const VT& endPosition
261) {
262 auto right = std::max(startPosition.x, endPosition.x);
263 auto left = std::min(startPosition.x, endPosition.x);
264 auto bottom = std::min(startPosition.y, endPosition.y);
265 auto top = std::max(startPosition.y, endPosition.y);
266
267 return left <= point.x && point.x <= right
268 && bottom <= point.y && point.y <= top;
269}
270
277template <SignedNumber IT, VectorType2D<IT> VT>
279 const VT& lineStart,
280 const VT& lineEnd,
281
282 const VT& rectStart,
283 const VT& rectEnd
284) {
285 auto right = std::max(rectStart.x, rectEnd.x);
286 auto left = std::min(rectStart.x, rectEnd.x);
287 auto bottom = std::min(rectStart.y, rectEnd.y);
288 auto top = std::max(rectStart.y, rectEnd.y);
289
290 if (lineStart.x == lineEnd.x) {
291 // Vertical line
292 if (lineStart.x > right || lineStart.x < left) {
293 return false;
294 }
295
296 auto minY = std::min(lineStart.y, lineEnd.y);
297 auto maxY = std::max(lineStart.y, lineEnd.y);
298
299 if (
300 (minY > top && maxY > top)
301 || (minY < bottom && maxY < bottom)
302 ) {
303 return false;
304 }
305 return true;
306 } else if (lineStart.y == lineEnd.y) {
307 // Horizontal line
308 if (lineStart.y > top || lineStart.y < bottom) {
309 return false;
310 }
311
312 auto minX = std::min(lineStart.x, lineEnd.x);
313 auto maxX = std::max(lineStart.x, lineEnd.x);
314
315 if (
316 (minX > right && maxX > right)
317 || (minX < left && maxX < left)
318 ) {
319 return false;
320 }
321 return true;
322 } else {
323 throw std::runtime_error("Diagonal lines are not yet implemented");
324 }
325}
326
333template <SignedNumber IT, VectorType2D<IT> VT>
335 const VT& lineStart,
336 const VT& lineEnd,
337
338 const VT& rectStart,
339 const VT& rectEnd
340) {
341 auto right = std::max(rectStart.x, rectEnd.x);
342 auto left = std::min(rectStart.x, rectEnd.x);
343 auto bottom = std::min(rectStart.y, rectEnd.y);
344 auto top = std::max(rectStart.y, rectEnd.y);
345
346 if (lineStart.x == lineEnd.x) {
347 // Vertical line
348 if (lineStart.x >= right || lineStart.x <= left) {
349 return false;
350 }
351
352 auto minY = std::min(lineStart.y, lineEnd.y);
353 auto maxY = std::max(lineStart.y, lineEnd.y);
354
355 if (
356 (minY >= top && maxY >= top)
357 || (minY <= bottom && maxY <= bottom)
358 ) {
359 return false;
360 }
361 return true;
362 } else if (lineStart.y == lineEnd.y) {
363 // Horizontal line
364 if (lineStart.y >= top || lineStart.y <= bottom) {
365 return false;
366 }
367
368 auto minX = std::min(lineStart.x, lineEnd.x);
369 auto maxX = std::max(lineStart.x, lineEnd.x);
370
371 if (
372 (minX >= right && maxX >= right)
373 || (minX <= left && maxX <= left)
374 ) {
375 return false;
376 }
377 return true;
378 } else {
379 throw std::runtime_error("Diagonal lines are not yet implemented");
380 }
381}
382
383}
384
385}
Definition Math.hpp:59
Definition Math.hpp:46
Definition Math.hpp:52
bool isCounterClockwise(const VT &a, const VT &b, const VT &c)
Definition Math.hpp:84
IT isPointOnLeftOfEdge(const VT &point, const VT &lineStart, const VT &lineEnd)
Definition Math.hpp:95
bool rectangleContainsPointExclusive(const VT &point, const VT &rectCornerA, const VT &rectCornerB, const VT &rectCornerC, const VT &rectCornerD)
Definition Math.hpp:186
bool rectangleContainsPointInclusive(const VT &point, const VT &rectCornerA, const VT &rectCornerB, const VT &rectCornerC, const VT &rectCornerD)
Definition Math.hpp:225
bool lineIntersectsLineInclusive(const VT &l1Start, const VT &l1End, const VT &l2Start, const VT &l2End)
Definition Math.hpp:115
bool lineIntersectsRectangleExclusive(const VT &lineStart, const VT &lineEnd, const VT &rectStart, const VT &rectEnd)
Definition Math.hpp:334
bool lineIntersectsRectangleInclusive(const VT &lineStart, const VT &lineEnd, const VT &rectCornerA, const VT &rectCornerB, const VT &rectCornerC, const VT &rectCornerD)
Definition Math.hpp:147
Definition Math.hpp:40
T square(const T &val)
Definition Math.hpp:69