1 | //************************************ bs::framework - Copyright 2018 Marko Pintera **************************************// |
2 | //*********** Licensed under the MIT license. See LICENSE.md for full terms. This notice is not to be removed. ***********// |
3 | #include "Math/BsSphere.h" |
4 | #include "Math/BsRay.h" |
5 | #include "Math/BsPlane.h" |
6 | #include "Math/BsAABox.h" |
7 | #include "Math/BsMath.h" |
8 | |
9 | namespace bs |
10 | { |
11 | void Sphere::merge(const Sphere& rhs) |
12 | { |
13 | Vector3 newCenter = (mCenter + rhs.mCenter) * 0.5f; |
14 | |
15 | float newRadiusA = newCenter.distance(mCenter) + getRadius(); |
16 | float newRadiusB = newCenter.distance(rhs.mCenter) + rhs.getRadius(); |
17 | |
18 | mCenter = newCenter; |
19 | mRadius = std::max(newRadiusA, newRadiusB); |
20 | } |
21 | |
22 | void Sphere::merge(const Vector3& point) |
23 | { |
24 | float dist = point.distance(mCenter); |
25 | mRadius = std::max(mRadius, dist); |
26 | } |
27 | |
28 | void Sphere::transform(const Matrix4& matrix) |
29 | { |
30 | float lengthSqrd[3]; |
31 | for(UINT32 i = 0; i < 3; i++) |
32 | { |
33 | Vector3 column = matrix.getColumn(i); |
34 | lengthSqrd[i] = column.dot(column); |
35 | } |
36 | |
37 | float maxLengthSqrd = std::max(lengthSqrd[0], std::max(lengthSqrd[1], lengthSqrd[2])); |
38 | |
39 | mCenter = matrix.multiplyAffine(mCenter); |
40 | mRadius *= sqrt(maxLengthSqrd); |
41 | } |
42 | |
43 | bool Sphere::contains(const Vector3& v) const |
44 | { |
45 | return ((v - mCenter).squaredLength() <= Math::sqr(mRadius)); |
46 | } |
47 | |
48 | bool Sphere::intersects(const Sphere& s) const |
49 | { |
50 | return (s.mCenter - mCenter).squaredLength() <= |
51 | Math::sqr(s.mRadius + mRadius); |
52 | } |
53 | |
54 | std::pair<bool, float> Sphere::intersects(const Ray& ray, bool discardInside) const |
55 | { |
56 | const Vector3& raydir = ray.getDirection(); |
57 | const Vector3& rayorig = ray.getOrigin() - getCenter(); |
58 | float radius = getRadius(); |
59 | |
60 | // Check origin inside first |
61 | if (rayorig.squaredLength() <= radius*radius && discardInside) |
62 | { |
63 | return std::pair<bool, float>(true, 0.0f); |
64 | } |
65 | |
66 | // t = (-b +/- sqrt(b*b + 4ac)) / 2a |
67 | float a = raydir.dot(raydir); |
68 | float b = 2 * rayorig.dot(raydir); |
69 | float c = rayorig.dot(rayorig) - radius*radius; |
70 | |
71 | // Determinant |
72 | float d = (b*b) - (4 * a * c); |
73 | if (d < 0) |
74 | { |
75 | // No intersection |
76 | return std::pair<bool, float>(false, 0.0f); |
77 | } |
78 | else |
79 | { |
80 | // If d == 0 there is one intersection, if d > 0 there are 2. |
81 | // We only return the first one. |
82 | |
83 | float t = ( -b - Math::sqrt(d) ) / (2 * a); |
84 | if (t < 0) |
85 | t = ( -b + Math::sqrt(d) ) / (2 * a); |
86 | |
87 | return std::pair<bool, float>(true, t); |
88 | } |
89 | } |
90 | |
91 | bool Sphere::intersects(const Plane& plane) const |
92 | { |
93 | return (Math::abs(plane.getDistance(getCenter())) <= getRadius()); |
94 | } |
95 | |
96 | bool Sphere::intersects(const AABox& box) const |
97 | { |
98 | return box.intersects(*this); |
99 | } |
100 | } |