| 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 | } |