TazGraph Project v0.1.0
Loading...
Searching...
No Matches
AABB.h
1#pragma once
2
3#include "../../pch.h"
4
5#include "./SelectionFrustum.h"
6constexpr float LINE_THRESHOLD = 5.0f;
7template<typename RectType>
8inline bool checkCollision(const RectType& recA, const RectType& recB) {
9 static_assert(std::is_same<RectType, SDL_Rect>::value || std::is_same<RectType, SDL_FRect>::value,
10 "checkCollision: RectType must be either SDL_Rect or SDL_FRect");
11
12 if (recA.x >= recB.x + recB.w || recA.x + recA.w <= recB.x ||
13 recA.y >= recB.y + recB.h || recA.y + recA.h <= recB.y) {
14 return false; // no collision
15 }
16 return true;
17}
18
19inline bool checkCollision(const SDL_Rect& recA, const SDL_FRect& recB) {
20 SDL_FRect convertedA = { static_cast<float>(recA.x), static_cast<float>(recA.y),
21 static_cast<float>(recA.w), static_cast<float>(recA.h) };
22 return checkCollision(convertedA, recB);
23}
24
25inline bool checkCollision(const SDL_FRect& recA, const SDL_Rect& recB) {
26 return checkCollision(recB, recA);
27}
28
29inline bool checkCollision3D(const glm::vec3& centerA, const glm::vec3& halfSizeA,
30 const glm::vec3& centerB, const glm::vec3& halfSizeB,
31 float padding = 0.0f) {
32
33 glm::vec3 paddedHalfSizeA = halfSizeA + glm::vec3(padding);
34 glm::vec3 paddedHalfSizeB = halfSizeB + glm::vec3(padding);
35
36
37 return !(centerA.x + paddedHalfSizeA.x <= centerB.x - paddedHalfSizeB.x ||
38 centerA.x - paddedHalfSizeA.x >= centerB.x + paddedHalfSizeB.x ||
39 centerA.y + paddedHalfSizeA.y <= centerB.y - paddedHalfSizeB.y ||
40 centerA.y - paddedHalfSizeA.y >= centerB.y + paddedHalfSizeB.y ||
41 centerA.z + paddedHalfSizeA.z <= centerB.z - paddedHalfSizeB.z ||
42 centerA.z - paddedHalfSizeA.z >= centerB.z + paddedHalfSizeB.z);
43}
44
45inline float pointLineDistance(glm::vec2 point, glm::vec2 lineStartPoint, glm::vec2 lineEndPoint) {
46 float num = std::abs((lineEndPoint.y - lineStartPoint.y) * point.x - (lineEndPoint.x - lineStartPoint.x) * point.y + lineEndPoint.x * lineStartPoint.y - lineEndPoint.y * lineStartPoint.x);
47 float den = std::sqrt((lineEndPoint.y - lineStartPoint.y) * (lineEndPoint.y - lineStartPoint.y) + (lineEndPoint.x - lineStartPoint.x) * (lineEndPoint.x - lineStartPoint.x));
48 return num / den;
49}
50
51inline bool rayIntersectsRectangle(const glm::vec3& rayOrigin, const glm::vec3& rayDirection,
52 const glm::vec3& planePoint, const glm::vec3& planeNormal,
53 float xMin, float xMax, float yMin, float yMax) {
54 // Step 1: Check if the ray intersects the plane
55 float denom = glm::dot(planeNormal, rayDirection);
56
57 // If denom == 0, the ray is parallel to the plane
58 if (std::abs(denom) < 1e-6) {
59 return false; // No intersection
60 }
61
62 // Calculate t
63 float t = glm::dot(planeNormal, planePoint - rayOrigin) / denom;
64
65 // If t < 0, the intersection is behind the ray origin
66 if (t < 0) {
67 return false;
68 }
69
70 // Calculate the intersection point
71 glm::vec3 intersectionPoint = rayOrigin + t * rayDirection;
72
73 // Step 2: Check if the intersection point lies within the rectangle bounds
74 if (intersectionPoint.x >= xMin && intersectionPoint.x <= xMax &&
75 intersectionPoint.y >= yMin && intersectionPoint.y <= yMax) {
76 return true; // Intersection point is within the rectangle
77 }
78
79 return false; // Intersection point is outside the rectangle
80}
81
82
83inline bool rayIntersectsSphere(
84 const glm::vec3& rayOrigin,
85 const glm::vec3& rayDirection,
86 const glm::vec3& sphereCenter,
87 float radius,
88 glm::vec3& t
89) {
90 glm::vec3 oc = rayOrigin - sphereCenter;
91
92 float A = glm::dot(rayDirection, rayDirection);
93 float B = 2.0f * glm::dot(oc, rayDirection);
94 float C = glm::dot(oc, oc) - radius * radius;
95
96 float discriminant = B * B - 4 * A * C;
97
98 if (discriminant < 0) {
99 return false; // No intersection
100 }
101
102 // Compute the closest valid t value
103 float sqrtDiscriminant = sqrt(discriminant);
104 float t0 = (-B - sqrtDiscriminant) / (2.0f * A);
105 float t1 = (-B + sqrtDiscriminant) / (2.0f * A);
106
107 if (t0 >= 0) {
108 t = rayOrigin + t0 * rayDirection; // Closest intersection point
109 return true;
110 }
111 else if (t1 >= 0) {
112 t = rayOrigin + t1 * rayDirection; // Intersection behind the ray origin
113 return true;
114 }
115
116 return false;
117}
118
119inline bool sphereIntersectsBox(
120 const glm::vec3& sphereCenter, float sphereRadius,
121 const glm::vec3& boxMin, const glm::vec3& boxMax,
122 glm::vec3& intersectionPoint)
123{
124 glm::vec3 closestPoint = glm::clamp(sphereCenter, boxMin, boxMax);
125
126 intersectionPoint = closestPoint;
127
128 glm::vec3 diff = closestPoint - sphereCenter;
129 float distanceSquared = glm::dot(diff, diff);
130
131 return distanceSquared <= (sphereRadius * sphereRadius);
132}
133
134inline bool rayIntersectsBox(
135 const glm::vec3& rayOrigin,
136 const glm::vec3& rayDirection,
137 const glm::vec3& boxMin,
138 const glm::vec3& boxMax,
139 glm::vec3& intersectionPoint,
140 float* tOut = nullptr
141) {
142 float tMin = 0.0f;
143 float tMax = std::numeric_limits<float>::max();
144
145 // Test each axis slab
146 for (int i = 0; i < 3; i++) {
147 if (abs(rayDirection[i]) < 1e-8f) {
148 // Ray is parallel to slab, check if origin is inside
149 if (rayOrigin[i] < boxMin[i] || rayOrigin[i] > boxMax[i]) {
150 return false;
151 }
152 }
153 else {
154 // Compute intersection t values for near and far plane
155 float invD = 1.0f / rayDirection[i];
156 float t1 = (boxMin[i] - rayOrigin[i]) * invD;
157 float t2 = (boxMax[i] - rayOrigin[i]) * invD;
158
159 // Ensure t1 is the near plane
160 if (t1 > t2) std::swap(t1, t2);
161
162 // Update tMin and tMax
163 tMin = std::max(tMin, t1);
164 tMax = std::min(tMax, t2);
165
166 // Early exit if no overlap
167 if (tMin > tMax) {
168 return false;
169 }
170 }
171 }
172
173 // If tMax < 0, box is behind ray
174 if (tMax < 0) {
175 return false;
176 }
177
178 // tMin is the intersection distance
179 float t = (tMin >= 0) ? tMin : tMax;
180 intersectionPoint = rayOrigin + t * rayDirection;
181
182 if (tOut) {
183 *tOut = t;
184 }
185
186 return true;
187}
188
189
190
191inline bool rayIntersectsLineSegment(
192 const glm::vec3& rayOrigin,
193 const glm::vec3& rayDirection,
194 const glm::vec3& segmentStart,
195 const glm::vec3& segmentEnd,
196 glm::vec3& intersectionPoint,
197 float* tOut = nullptr
198) {
199 glm::vec3 lineVec = segmentEnd - segmentStart;
200 glm::vec3 w = rayOrigin - segmentStart;
201
202 float a = glm::dot(rayDirection, rayDirection);
203 float b = glm::dot(rayDirection, lineVec);
204 float c = glm::dot(lineVec, lineVec);
205 float d = glm::dot(rayDirection, w);
206 float e = glm::dot(lineVec, w);
207
208 float denom = a * c - b * b;
209
210 if (abs(denom) < 1e-6f) {
211 return false; // Lines are parallel
212 }
213
214 float s = (b * e - c * d) / denom;
215 float t = (a * e - b * d) / denom;
216
217 // Clamp t to line segment bounds
218 t = glm::clamp(t, 0.0f, 1.0f);
219
220 // Check if ray parameter is positive
221 if (s < 0) {
222 return false;
223 }
224
225 glm::vec3 pointOnRay = rayOrigin + s * rayDirection;
226 glm::vec3 pointOnSegment = segmentStart + t * lineVec;
227
228 float distance = glm::distance(pointOnRay, pointOnSegment);
229
230 if (distance <= LINE_THRESHOLD) {
231 intersectionPoint = pointOnSegment;
232 if (tOut) {
233 *tOut = distance;
234 }
235
236 return true;
237 }
238
239 return false;
240}
241
242inline bool checkCircleLineCollision(glm::vec2 center, int circleRadius, glm::vec2 lineStartPoint, glm::vec2 lineEndPoint) {
243 float dist = pointLineDistance(center, lineStartPoint, lineEndPoint);
244
245 if (dist <= circleRadius) {
246 float dx = lineEndPoint.x - lineStartPoint.x;
247 float dy = lineEndPoint.y - lineStartPoint.y;
248 float t = ((center.x - lineStartPoint.x) * dx + (center.y - lineStartPoint.y) * dy) / (dx * dx + dy * dy);
249
250 t = std::max(0.0f, std::min(1.0f, t));
251
252 float closestX = lineStartPoint.x + t * dx;
253 float closestY = lineStartPoint.y + t * dy;
254
255 float distanceToCircle = std::sqrt((closestX - center.x) * (closestX - center.x) +
256 (closestY - center.y) * (closestY - center.y));
257 return distanceToCircle <= circleRadius;
258 }
259
260 return false;
261}
262
263inline bool isPointInFrustum(const glm::vec3& point, const SelectionFrustum& frustum) {
264 for (int i = 0; i < 6; i++) {
265 float distance = glm::dot(glm::vec3(frustum.planes[i]), point) + frustum.planes[i].w;
266 if (distance < 0) {
267 return false; // Point is outside this plane
268 }
269 }
270 return true;
271}
Definition SelectionFrustum.h:5