1// tGeometry.h 
2// 
3// Idealized geometric shapes. These include triangles, circles, boxes, spheres, rays, lines, planes, cylinders, 
4// capsules, frustums, and ellipses. When the shape primitives have a number in their name, it refers to the space the 
5// shape is in, not the dimensionality of the shape itself. eg. A tCircle3 is a (2D) circle in R3 while a tCircle2 is a 
6// 2D circle in R2. For shapes that are in R3 we drop the 3 because the R3 primitives are more general. 
7// 
8// Copyright (c) 2006, 2016, 2019 Tristan Grimmer. 
9// Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby 
10// granted, provided that the above copyright notice and this permission notice appear in all copies. 
11// 
12// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL 
13// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, 
14// INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN 
15// AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR 
16// PERFORMANCE OF THIS SOFTWARE. 
17 
18#pragma once 
19#include "Math/tVector2.h" 
20#include "Math/tVector3.h" 
21#include "Math/tVector4.h" 
22#include "Math/tMatrix2.h" 
23#include "Math/tMatrix4.h" 
24namespace tMath 
25
26 
27 
28// Edges are simply line segments with two end points. The tEdge data structure is just a set of 2 indexes into any 
29// sort of vertex array. It is therefore dimension-agnostic and can be used for edges in R2 and R3. 
30struct tEdge 
31
32 tEdge() { } 
33 tEdge(const tEdge& s) { for (int i = 0; i < 2; i++) Index[i] = s.Index[i]; } 
34 bool operator==(const tEdge& e) const { return (Index[0] == e.Index[0]) && (Index[1] == e.Index[1]); } 
35 bool operator!=(const tEdge& e) const { return (Index[0] != e.Index[0]) || (Index[1] != e.Index[1]); } 
36 tEdge& operator=(const tEdge& e) { Index[0] = e.Index[0]; Index[1] = e.Index[1]; return *this; } 
37 int Index[2]; 
38}; 
39 
40 
41// A triangular face. It has 3 vertices and 3 edges. It may be degenerate. The tTriFace data structure is just a set of 
42// 3 indexes into any sort of vertex array. It is therefore dimension-agnostic and can be used for tris in R2 and R3. 
43struct tTriFace 
44
45 tTriFace() { } 
46 tTriFace(const tTriFace& s) { for (int i = 0; i < 3; i++) Index[i] = s.Index[i]; } 
47 bool operator==(const tTriFace& f) const { return (Index[0] == f.Index[0]) && (Index[1] == f.Index[1]) && (Index[2] == f.Index[2]); } 
48 bool operator!=(const tTriFace& f) const { return (Index[0] != f.Index[0]) || (Index[1] != f.Index[1]) || (Index[2] != f.Index[2]); } 
49 tTriFace& operator=(const tTriFace& f) { Index[0] = f.Index[0]; Index[1] = f.Index[1]; Index[2] = f.Index[2]; return *this; } 
50 int Index[3]; 
51}; 
52typedef tTriFace tTri; // A short synonym for a triangular face. 
53 
54 
55// The same as a tTriFace but using only 16 bit indices. 
56struct tTriFaceShort 
57
58 tTriFaceShort() { } 
59 tTriFaceShort(const tTriFaceShort& s) { for (int v = 0; v < 3; v++) Index[v] = s.Index[v]; } 
60 bool operator==(const tTriFaceShort& f) const { return (Index[0] == f.Index[0]) && (Index[1] == f.Index[1]) && (Index[2] == f.Index[2]); } 
61 bool operator!=(const tTriFaceShort& f) const { return (Index[0] != f.Index[0]) || (Index[1] != f.Index[1]) || (Index[2] != f.Index[2]); } 
62 tTriFaceShort& operator=(const tTriFaceShort& f) { Index[0] = f.Index[0]; Index[1] = f.Index[1]; Index[2] = f.Index[2]; return *this; } 
63 uint16 Index[3]; 
64}; 
65typedef tTriFaceShort tTriShort; // A short synonym for a short triangular face. 
66 
67 
68// A quad face. It has 4 vertices and 4 edges. It may be degenerate. The tQuadFace data structure is just a set of 
69// 4 indexes into any sort of vertex array. It is therefore dimension-agnostic and can be used for quads in R2 and R3. 
70struct tQuadFace 
71
72 tQuadFace() { } 
73 tQuadFace(const tQuadFace& s) { for (int i = 0; i < 4; i++) Index[i] = s.Index[i]; } 
74 bool operator==(const tQuadFace& f) const { return (Index[0] == f.Index[0]) && (Index[1] == f.Index[1]) && (Index[2] == f.Index[2]) && (Index[3] == f.Index[3]); } 
75 bool operator!=(const tQuadFace& f) const { return (Index[0] != f.Index[0]) || (Index[1] != f.Index[1]) || (Index[2] != f.Index[2]) || (Index[3] != f.Index[3]); } 
76 tQuadFace& operator=(const tQuadFace& f) { Index[0] = f.Index[0]; Index[1] = f.Index[1]; Index[2] = f.Index[2]; Index[3] = f.Index[3]; return *this; } 
77 int Index[4]; 
78}; 
79typedef tQuadFace tQuad; // A short synonym for a quadrilateral face. 
80 
81 
82// The same as a tQuadFace but using only 16 bit indices. 
83struct tQuadFaceShort 
84
85 tQuadFaceShort() { } 
86 tQuadFaceShort(const tQuadFaceShort& s) { for (int i = 0; i < 4; i++) Index[i] = s.Index[i]; } 
87 bool operator==(const tQuadFaceShort& f) const { return (Index[0] == f.Index[0]) && (Index[1] == f.Index[1]) && (Index[2] == f.Index[2]) && (Index[3] == f.Index[3]); } 
88 bool operator!=(const tQuadFaceShort& f) const { return (Index[0] != f.Index[0]) || (Index[1] != f.Index[1]) || (Index[2] != f.Index[2]) || (Index[3] != f.Index[3]); } 
89 tQuadFaceShort& operator=(const tQuadFaceShort& f) { Index[0] = f.Index[0]; Index[1] = f.Index[1]; Index[2] = f.Index[2]; Index[3] = f.Index[3]; return *this; } 
90 uint16 Index[4]; 
91}; 
92typedef tQuadFace tQuad; // A short synonym for a quadrilateral face. 
93 
94 
95// A line segment goes from point A to point B. Ends are included. The 2 means in R2. 
96struct tLineSeg2 
97
98 tLineSeg2() { } 
99 tLineSeg2(float x0, float y0, float x1, float y1) { A.Set(x0, y0); B.Set(x1, y1); } 
100 tLineSeg2(const tVector2& a, const tVector2& b) : A(a), B(b) { } 
101 tLineSeg2(const tLineSeg2& s) : A(s.A), B(s.B) { } 
102 tVector2 A, B
103}; 
104 
105 
106// A line goes through point A and point B. 
107struct tLine2 
108
109 tLine2() { } 
110 tLine2(float x0, float y0, float x1, float y1) { A.Set(x0, y0); B.Set(x1, y1); } 
111 tLine2(const tVector2& a, const tVector2& b) : A(a), B(b) { } 
112 tLine2(const tLineSeg2& s) : A(s.A), B(s.B) { } 
113 tLine2(const tLine2& s) : A(s.A), B(s.B) { } 
114 tVector2 A, B
115}; 
116 
117 
118// A ray from Start in (normalized) direction Dir. 
119struct tRay2 
120
121 tRay2() { } 
122 tVector2 Start
123 tVector2 Dir; // Normalized. 
124}; 
125 
126 
127// An axis aligned rectangle in R2. 
128struct tARect2 
129
130 enum Side 
131
132 Side_None = 0x00000000
133 Side_Left = 0x00000001
134 Side_Right = 0x00000002
135 Side_Bottom = 0x00000004
136 Side_Top = 0x00000008 
137 }; 
138 
139 tARect2() { Clear(); } 
140 tARect2(const tARect2& src) { Set(src); } 
141 tARect2(const tVector2& origin, float sideLength) { Set(origin, sideLength); } 
142 tARect2(const tVector2& min, float width, float height) { Set(min, width, height); } 
143 tARect2(const tVector2& min, const tVector2& max) { Set(min, max); } 
144 tARect2(float minx, float miny, float maxx, float maxy) { Set(minx, miny, maxx, maxy); } 
145 
146 void Set(const tARect2& src) { Min.Set(src.Min); Max.Set(src.Max); } 
147 void Set(const tVector2& origin, float sideLength) { Min.Set(origin.x - sideLength/2.0f, origin.y - sideLength/2.0f); Max.Set(origin.x + sideLength/2.0f, origin.y + sideLength/2.0f); } 
148 void Set(const tVector2& min, float width, float height) { Min.Set(min); Max.Set(min.x + width, min.y + height); } 
149 void Set(const tVector2& min, const tVector2& max) { Min.Set(min); Max.Set(max); } 
150 void Set(float minx, float miny, float maxx, float maxy) { Min.Set(minx, miny); Max.Set(maxx, maxy); } 
151 
152 void AddPoint(const tVector2&); 
153 void Expand(float e) { Min.x -= e; Min.y -= e; Max.x += e; Max.y += e; } 
154 void Clear() { Min = tVector2(PosInfinity, PosInfinity); Max = tVector2(NegInfinity, NegInfinity); } 
155 void Empty() { Clear(); } 
156 
157 // Boundary included. 
158 bool IsPointInside(const tVector2& point) const { return ((point.x >= Min.x) && (point.x <= Max.x) && (point.y >= Min.y) && (point.y <= Max.y)); } 
159  
160 // The boundary is included. Positive margin values increase the rectangle size. 
161 bool IsPointInside(const tVector2& point, float margin) const { return ((point.x >= Min.x-margin) && (point.x <= Max.x+margin) && (point.y >= Min.y-margin) && (point.y <= Max.y+margin)); } 
162 
163 // Similar to above except you can control which boundary sides are included. With default bias values this 
164 // function includes the 2 minimum boundary lines and does not include the 2 maximum lines. This is useful for 
165 // situations such as spatial partitioning where a single point must not be inside multiple adjacent boxes. 
166 bool IsPointInsideBias 
167
168 const tVector2& point
169 tIntervalBias biasX = tIntervalBias::Low
170 tIntervalBias biasY = tIntervalBias::Low 
171 ) const
172 
173 // Transforms Min and Max vectors and builds the new box from them. 
174 void Transform(const tMatrix2& xform); 
175 
176 tVector2 ComputeCenter() const { return (Min + Max)/2.0f; } 
177 tVector2 ComputeExtents() const { return (Max - Min)/2.0f; } 
178 bool Overlaps(const tARect2&) const
179 
180 tVector2 Min
181 tVector2 Max
182}; 
183typedef tARect2 tRect2
184 
185 
186struct tORect2 
187
188 tORect2() : Center(0.0f, 0.0f), Extents(0.0f, 0.0f) { Axes[0].Set(1.0f, 0.0f); Axes[1].Set(0.0f, 1.0f); } 
189 bool IsInside(const tVector2& point) const
190 tVector2 Center
191 tVector2 Axes[2]; 
192 tVector2 Extents
193}; 
194 
195 
196struct tCircle2 
197
198 tCircle2() { } 
199 float Area() const { return Pi * Radius * Radius; } 
200 float Radius
201 tVector2 Center
202}; 
203 
204 
205// An ellipse in R2. The ellipse equation is: (x-a)^2 / r1^2 + (y-b)^2 / r2^2 = 1 where (a, b) is the center location, 
206// r1 is the x 'radius', and r2 is the y 'radius'. 
207struct tEllipse2 
208
209 tEllipse2() { } 
210 float Area() const { return Pi * RadiusX * RadiusY; } 
211 
212 float RadiusX, RadiusY
213 tVector2 Center
214}; 
215 
216 
217// Primitives in 3D space. 
218 
219 
220// A line segment has the same members as a line, but only goes from A to B (inclusive). 
221struct tLineSeg 
222
223 tLineSeg() { } 
224 tLineSeg(const tVector3& a, const tVector3& b) : A(a), B(b) { } 
225 tLineSeg(const tLineSeg& src) : A(src.A), B(src.B) { } 
226 tVector3 A, B
227}; 
228 
229 
230// A ray from Start in normalized direction Dir. 
231struct tRay 
232
233 tRay() { } 
234 tRay(const tVector3& start, const tVector3& dir) : Start(start), Dir(dir) { } 
235 tRay(const tLineSeg& s) { Set(s); } 
236 void Set(const tVector3& start, const tVector3& dir) { Start = start; Dir = dir; } 
237 void Set(const tLineSeg& s) { Start = s.A; Dir = s.B - s.A; Dir.NormalizeSafe(); } 
238 
239 tVector3 Start
240 tVector3 Dir
241}; 
242 
243 
244// Goes through A and B and extends infinitely. 
245struct tLine 
246
247 tLine() { } 
248 tLine(const tRay& ray) { Set(ray); } 
249 tLine(const tLineSeg& seg) { Set(seg); } 
250 void Set(const tRay& ray) { A = ray.Start; B = ray.Start + ray.Dir; } 
251 void Set(const tLineSeg& seg) { A = seg.A; B = seg.B; } 
252  
253 tVector3 A, B
254}; 
255 
256 
257// A cylinder. Represented as a line segment with a radius. 
258struct tCylinder 
259
260 tCylinder() { } 
261 tCylinder(const tVector3& a, const tVector3& b, float radius) : Radius(radius), A(a), B(b) { } 
262 tCylinder(const tLineSeg& s, float radius) : Radius(radius), A(s.A), B(s.B) { } 
263 
264 float Radius
265 tVector3 A, B
266}; 
267 
268 
269// A capsule is just a cylinder with hemispherical ends. It uses the same representation as a tCylinder. The only 
270// difference is in how the state varialble are interpreted. For a capsule, the ends parts also have a radius. 
271typedef tCylinder tCapsule
272 
273 
274struct tTriangle 
275
276 tTriangle() { } 
277 tTriangle(const tVector3& a, const tVector3& b, const tVector3& c) : A(a), B(b), C(c) { } 
278 
279 tVector3 A, B, C
280}; 
281 
282 
283// This is an axis-aligned box in R3. 
284struct tABox 
285
286 tABox() : Min(PosInfinity, PosInfinity, PosInfinity), Max(NegInfinity, NegInfinity, NegInfinity) { } 
287 tABox(const tABox& src) : Min(src.Min), Max(src.Max) { } 
288 tABox(const tVector3& min, float width, float height, float depth) : Min(min), Max(min.x + width, min.y + height, min.z + depth) { } 
289 tABox(const tVector3& min, const tVector3& max) : Min(min), Max(max) { } 
290 tABox(float minx, float miny, float minz, float maxx, float maxy, float maxz) : Min(minx, miny, minz), Max(maxx, maxy, maxz) { } 
291 
292 void AddPoint(const tVector3&); 
293 void Expand(float e) { Min.x -= e; Min.y -= e; Min.z -= e; Max.x += e; Max.y += e; Max.z += e; } 
294 void Empty() { Min = tVector3(PosInfinity, PosInfinity, PosInfinity); Max = tVector3(NegInfinity, NegInfinity, NegInfinity); } 
295 void Transform(const tMatrix4& xform); // Affine and projection transforms supported. 
296 
297 // Boundary included. 
298 bool IsPointInside(const tVector3& point) const { return ((point.x >= Min.x) && (point.x <= Max.x) && (point.y >= Min.y) && (point.y <= Max.y) && (point.z >= Min.z) && (point.z <= Max.z)); } 
299 
300 // The boundary is included. Positive margin values increase the rectangle size. 
301 bool IsPointInside(const tVector3& point, float margin) const { return ((point.x >= Min.x-margin) && (point.x <= Max.x+margin) && (point.y >= Min.y-margin) && (point.y <= Max.y+margin) && (point.z >= Min.z-margin) && (point.z <= Max.z+margin)); } 
302 
303 // Similar to above except you can control which boundary planes are included. With default bias values this 
304 // function includes the 3 minimum boundary planes and does not include the 3 maximum planes. This is useful for 
305 // situations such as spatial partitioning where a single point must not be inside multiple adjacent boxes. 
306 bool IsPointInsideBias 
307
308 const tVector3& point
309 tIntervalBias biasX = tIntervalBias::Low
310 tIntervalBias biasY = tIntervalBias::Low
311 tIntervalBias biasZ = tIntervalBias::Low 
312 ) const
313 
314 tVector3 ComputeCenter() const { return (Min + Max)/2.0f; } 
315 tVector3 ComputeExtents() const { return (Max - Min)/2.0f; } 
316 bool Overlaps(const tABox&) const { tAssert(!"Not implemented yet."); return false; } 
317 
318 tVector3 Min
319 tVector3 Max
320}; 
321typedef tABox tBox
322typedef tABox tAABB
323 
324 
325// @todo The oriented box is mostly unimplemented. 
326struct tOBox 
327
328 tOBox() : Center(0.0f, 0.0f, 0.0f), Extents(0.0f, 0.0f, 0.0f) { Axes[0].Set(1.0f, 0.0f, 0.0f); Axes[1].Set(0.0f, 1.0f, 0.0f); Axes[2].Set(0.0f, 0.0f, 1.0f); } 
329 bool IsInside(const tVector3& point) const
330 
331 tVector3 Center
332 tVector3 Axes[3]; 
333 tVector3 Extents
334}; 
335typedef tOBox tOBB
336 
337 
338struct tCircle 
339
340 tCircle() { } 
341 float Area() const { return Pi * Radius * Radius; } 
342 
343 float Radius
344 tVector3 Center
345 tVector3 Normal
346}; 
347 
348 
349struct tSphere 
350
351 tSphere() { } 
352 tSphere(const tVector3& center, float radius) : Center(center), Radius(radius) { } 
353 void Set(const tVector3& center, float radius) { Center = center; Radius = radius; } 
354 
355 tVector3 Center
356 float Radius
357}; 
358 
359 
360// A tPlane essentially represents the plane equation ax + by + cz + d = 0 using two member variables: Normal and 
361// Distance. These two values act as the coefficients of the plane equation with a = Normal.x, b = Normal.y, 
362// c = Normal.z, and d = Distance. 
363struct tPlane 
364
365public
366 tPlane() { } 
367 tPlane(float a, float b, float c, float d = 0.0f) { Set(a, b, c, d); } 
368 tPlane(const tVector3& normal, float d = 0.0f) { Set(normal, d); } 
369 tPlane(const tVector4& v) { Set(v); } 
370 tPlane(const tVector3& normal, const tVector3& p) { Set(normal, p); } 
371 tPlane(const tVector3& p1, const tVector3& p2, const tVector3& p3) { Set(p1, p2, p3); } 
372 
373 void Set(float a, float b, float c, float d) { Normal.Set(a, b, c); Distance = d; } 
374 void Set(const tVector3& normal, float d) { Normal = normal; Distance = d; } 
375 void Set(const tVector4& v) { Normal = tVector3(v); Distance = v.w; } 
376 void Set(const tVector3& normal, const tVector3& p) { Normal = normal; Distance = -(normal*p); } 
377 void Set(const tVector3& p1, const tVector3& p2, const tVector3& p3) { tVector3 v1 = p2 - p1; tVector3 v2 = p3 - p1; Normal = v1 % v2; Distance = -Normal * p3; } 
378 
379 // Makes Normal length 1. When this is done the Distance member will be how far away the plane is from the origin in 
380 // the direction of Normal. The Distance /= length in the implementation is CORRECT. 
381 void Normalize() { float l = Normal.Length(); Normal /= l; Distance /= l; } 
382 
383 // If the plane is normalized this returns the shortest distance from 'point' to the plane. Normalized or not, if 
384 // the result is < 0 then the point is in the negative half-space, > 0 for positive half-space, and 0 on the plane. 
385 float GetDistance(const tVector3& point) const { return Normal.x*point.x + Normal.y*point.y + Normal.z*point.z + Distance; } 
386 
387 // Computes two unit vectors for the plane that form an orthogonal basis. The plane d-value is irrelevant and the 
388 // plane may be considered to go through the origin. The plane does not need to be normalized before calling. 
389 void ComputeOrthogonalBasisVectors(tVector3& u, tVector3& v) const
390 
391 // The Normal is a vector perpendicular to the surface of the plane. 
392 tVector3 Normal
393 
394 // the Distance only represents the distance to the plane if the plane is normalized. If it is not normalized, this 
395 // is MOT a multiplier to get the normal to the plane because ax+by+cz+d=0 is the same plane as kax+kby+kcz+kd=0. 
396 // Distance (d) more as the offset of the point (a,b,c) from the origin. They grow and shrink together. 
397 float Distance
398}; 
399 
400 
401class tFrustum 
402
403public
404 tFrustum() { } 
405 tFrustum(const tMatrix4& m) { Set(m); } 
406 tFrustum(const tPlane p[6]) { Set(p); } 
407 tFrustum(const tVector4 v[6]) { Set(v); } 
408 
409 void Set(const tMatrix4&); 
410 void Set(const tPlane[6]); 
411 void Set(const tVector4[6]); 
412 
413 // Use to index into the Planes array. 
414 enum Plane 
415
416 Plane_Right
417 Plane_Left
418 Plane_Top
419 Plane_Bottom
420 Plane_Near
421 Plane_Far
422 Plane_NumPlanes 
423 }; 
424 
425 // Normals are interior-facing. The near distance (mNear.mDist) will be the negative of the far. 
426 tPlane Planes[int(Plane_NumPlanes)]; 
427}; 
428 
429 
430// This function finds a small sphere that encloses the supplied points. The algorithm is 'stable' in that continuous 
431// changes in source positions do not result in discontinuities in the output sphere. Runs in expected O(n) time and 
432// finds the smallest, or rather something close to the smallest, sphere that encloses them all. If numpoints is <= 0 
433// or points is nullptr returns false and does not modify the sphere. For numPoints = 1 returns a sphere with the 
434// center at the point and radius minRadius. This also happens if all points have identical positions. 
435// 
436// Uses the Bouncing Bubble solution to the minimal enclosing ball problem. See 
437// "https://en.wikipedia.org/wiki/Bounding_sphere#Bouncing_Bubble". The minRadius must not be too close to zero or 
438// the algorithm will not work. The minRadius is forced to be >= Epsilon if too small a value is passed in. The 
439// implementation is based on Andres Hernandez's code as shown here: 
440// http://stackoverflow.com/questions/17331203/bouncing-bubble-algorithm-for-smallest-enclosing-sphere which is 
441// based on a paper by Tian Bo. 
442bool tComputeSmallEnclosingSphere(tSphere& result, const tVector3* points, int numPoints, float minRadius = 0.00001); 
443 
444// This is an older unstable function for computing a minimal bounding sphere. It is based on Graphics Gems vol II. 
445// Runs fast but is an approximation only. For a precise answer we should use the algorithm found here: 
446// http://www.geometrictools.com/LibFoundation/Containment/Containment.html which is based on the Emo Welzl algorithm 
447// that has an expected O(n) running time and is generally much faster than the Megiddo algorithm that guarantees O(n). 
448// A possible benefit of this unstable implementation is no minimum radius. Performance and result quality have not been 
449// tested. 
450bool tComputeSmallEnclosingSphere_Unstable(tSphere& result, const tVector3* points, int numPoints); 
451float tDistanceToLine(const tVector3& point, const tLine&); 
452 
453// @todo Extend the use of tIntersectResult to the 3D tests. 
454enum class tIntersectResult 
455
456 None, // No intersection. 
457 Parallel
458 Point, // Intersects at a single point. 
459 Segment, // Intersects along a line segment. 
460 Coincident // Primitives overlap. 
461}; 
462 
463// Intersections. These functions determine if various primitives intersect or not. If the function has the word 'test' 
464// in it, only that determination is made. If the function has the word 'find' in it, the location of intersection is 
465// also computed and returned. 'Find' functions are slower. The functions are named using the convention: 
466// tIntersectTestPrim1Prim2(...) and tIntersectFindPrim1Prim2(...). 
467 
468// Finds the intersection point between 2 2D lines. 
469tIntersectResult tIntersectFindLineLine(const tLine2&, const tLine2&, tVector2& intersection); 
470 
471// The segment intersection functions are currently not mathematically consistent since 'coincident' is returned if 
472// the segments lie on the same line even if they do not intersect. What should be returned in this case is either 
473// 'None' or, if they overlap, a line segment for the overlap region. 
474tIntersectResult tIntersectFindSegSeg(const tLineSeg2&, const tLineSeg2&, tVector2& intersection); 
475tIntersectResult tIntersectFindRaySeg(const tRay2&, const tLineSeg2&, tVector2& intersection); 
476 
477// Returns the number of intersection points found. Only 0, 1, or 2 will ever be returned. You may only read that many 
478// results from the 'intersection' array. If the ray is lined up with one of the rectangle edges there will not be any 
479// results for that edge but you will still receive results for the adjacent edges and the function will still return 
480// 0, 1, or 2. If sides is supplied, it is filled with the tARect2 Side bitfields. 
481int tIntersectFindRayRect(const tRay2&, const tARect2&, tVector2 intersection[2], uint32* sides = nullptr); 
482 
483// The tRay.Dir argument must be normalized. This function modifies t such that the intersection point is given by 
484// tRay.Start + tRay.Dir*t. t holds the closer of the two possible intersections and is always positive. Returns false 
485// if there was no intersection, true otherwise. 
486bool tIntersectFindRaySphere(float& t, const tRay&, const tSphere&); 
487bool tIntersectTestLineSegSphere(const tLineSeg&, const tSphere&); 
488 
489bool tIntersectTestCapsulePoint(const tCapsule&, const tVector3&); 
490 
491// This function requires that ray start from the center of the ellipse. The ellipse's center is ignored and so is the 
492// ray's start. The result 't' is set to how much the ray's dir needs to by multiplied by to land on the ellipse. 
493bool tIntersectFindRayEllipse(float& t, const tRay2&, const tEllipse2&); 
494 
495// This test assumes that the triangle faces one direction. An anticlockwise winding of the verts allows the right-hand 
496// rule to be used in determining the direction of the triangle's normal -- assuming a right-handed coordinate system. 
497bool tIntersectTestRayTriangle(const tRay&, const tTriangle&); 
498 
499// Returns true if the sphere is partly or completely inside the volume of the view frustum. 
500bool tIntersectTestFrustumSphere(const tFrustum&, const tSphere&); 
501 
502// @todo Not implemented. 
503bool tIntersectTestTriangleTriangle(const tTriangle&, const tTriangle&); 
504 
505// @todo Not implemented. 
506bool IntersectFindTriangleTriangle(tLineSeg& intersection, const tTriangle&, const tTriangle&); 
507 
508 
509
510 
511 
512// Implementation below this line. 
513 
514 
515inline void tMath::tARect2::AddPoint(const tVector2& p
516
517 Max.x = tMax(p.x, Max.x); 
518 Max.y = tMax(p.y, Max.y); 
519 Min.x = tMin(p.x, Min.x); 
520 Min.y = tMin(p.y, Min.y); 
521
522 
523 
524inline void tMath::tARect2::Transform(const tMatrix2& t
525
526 // Transform the four rectangle points to the new space and grow a new rectangle around them. 
527 tARect2 rect
528 rect.AddPoint(t * tVector2(Min.x, Min.y)); 
529 rect.AddPoint(t * tVector2(Max.x, Min.y)); 
530 rect.AddPoint(t * tVector2(Min.x, Max.y)); 
531 rect.AddPoint(t * tVector2(Max.x, Max.y)); 
532 *this = rect
533
534 
535 
536inline bool tMath::tARect2::Overlaps(const tARect2& rect) const 
537
538 tVector2 diff = rect.ComputeCenter() - ComputeCenter(); 
539 tVector2 extents = rect.ComputeExtents() + ComputeExtents(); 
540 if ((tAbs(diff.x) <= extents.x) && (tAbs(diff.y) <= extents.y)) 
541 return true
542 
543 return false
544
545 
546 
547inline bool tMath::tARect2::IsPointInsideBias(const tVector2& point, tIntervalBias biasX, tIntervalBias biasY) const 
548
549 std::function<bool(float,float)> lessX = tBiasLess(biasX); 
550 std::function<bool(float,float)> grtrX = tBiasGreater(biasX); 
551 bool inX = grtrX(point.x, Min.x) && lessX(point.x, Max.x); 
552 
553 std::function<bool(float,float)> lessY = tBiasLess(biasY); 
554 std::function<bool(float,float)> grtrY = tBiasGreater(biasY); 
555 bool inY = grtrY(point.y, Min.y) && lessY(point.y, Max.y); 
556 
557 return inX && inY
558
559 
560 
561inline void tMath::tABox::AddPoint(const tVector3& p
562
563 Max.x = tMax(p.x, Max.x); 
564 Max.y = tMax(p.y, Max.y); 
565 Max.z = tMax(p.z, Max.z); 
566 
567 Min.x = tMin(p.x, Min.x); 
568 Min.y = tMin(p.y, Min.y); 
569 Min.z = tMin(p.z, Min.z); 
570
571 
572 
573inline bool tMath::tABox::IsPointInsideBias(const tVector3& point, tIntervalBias biasX, tIntervalBias biasY, tIntervalBias biasZ) const 
574
575 std::function<bool(float,float)> lessX = tBiasLess(biasX); 
576 std::function<bool(float,float)> grtrX = tBiasGreater(biasX); 
577 bool inX = grtrX(point.x, Min.x) && lessX(point.x, Max.x); 
578 
579 std::function<bool(float,float)> lessY = tBiasLess(biasY); 
580 std::function<bool(float,float)> grtrY = tBiasGreater(biasY); 
581 bool inY = grtrY(point.y, Min.y) && lessY(point.y, Max.y); 
582 
583 std::function<bool(float,float)> lessZ = tBiasLess(biasZ); 
584 std::function<bool(float,float)> grtrZ = tBiasGreater(biasZ); 
585 bool inZ = grtrZ(point.z, Min.z) && lessZ(point.z, Max.z); 
586 
587 return inX && inY && inZ
588
589 
590 
591inline void tMath::tFrustum::Set(const tPlane planes[6]) 
592
593 for (int p = 0; p < 6; p++) 
594 Planes[p] = planes[p]; 
595
596 
597 
598inline void tMath::tFrustum::Set(const tVector4 planes[6]) 
599
600 for (int p = 0; p < 6; p++) 
601 Planes[p] = tPlane(planes[p]); 
602
603 
604 
605inline bool tMath::tIntersectTestCapsulePoint(const tCapsule& c, const tVector3& p
606
607 return tMath::tIntersectTestLineSegSphere 
608
609 tLineSeg(c.A, c.B), 
610 tSphere(p, c.Radius
611 ); 
612
613