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/BsPlane.h"
4#include "Math/BsMatrix3.h"
5#include "Math/BsAABox.h"
6#include "Math/BsSphere.h"
7#include "Math/BsRay.h"
8#include "Math/BsMath.h"
9
10namespace bs
11{
12 Plane::Plane(const Vector3& normal, float d)
13 :normal(normal), d(d)
14 { }
15
16 Plane::Plane(float a, float b, float c, float _d)
17 :normal(a, b, c), d(_d)
18 { }
19
20 Plane::Plane(const Vector3& normal, const Vector3& point)
21 :normal(normal), d(normal.dot(point))
22 { }
23
24 Plane::Plane(const Vector3& point0, const Vector3& point1, const Vector3& point2)
25 {
26 Vector3 kEdge1 = point1 - point0;
27 Vector3 kEdge2 = point2 - point0;
28 normal = kEdge1.cross(kEdge2);
29 normal.normalize();
30 d = normal.dot(point0);
31 }
32
33 float Plane::getDistance(const Vector3& point) const
34 {
35 return normal.dot(point) - d;
36 }
37
38 Plane::Side Plane::getSide(const Vector3& point, float epsilon) const
39 {
40 float dist = getDistance(point);
41
42 if (dist > epsilon)
43 return Plane::POSITIVE_SIDE;
44
45 if (dist < -epsilon)
46 return Plane::NEGATIVE_SIDE;
47
48 return Plane::NO_SIDE;
49 }
50
51 Plane::Side Plane::getSide(const AABox& box) const
52 {
53 // Calculate the distance between box centre and the plane
54 float dist = getDistance(box.getCenter());
55
56 // Calculate the maximize allows absolute distance for
57 // the distance between box centre and plane
58 Vector3 halfSize = box.getHalfSize();
59 float maxAbsDist = Math::abs(normal.x * halfSize.x) + Math::abs(normal.y * halfSize.y) + Math::abs(normal.z * halfSize.z);
60
61 if (dist < -maxAbsDist)
62 return Plane::NEGATIVE_SIDE;
63
64 if (dist > +maxAbsDist)
65 return Plane::POSITIVE_SIDE;
66
67 return Plane::BOTH_SIDE;
68 }
69
70 Plane::Side Plane::getSide(const Sphere& sphere) const
71 {
72 // Calculate the distance between box centre and the plane
73 float dist = getDistance(sphere.getCenter());
74 float radius = sphere.getRadius();
75
76 if (dist < -radius)
77 return Plane::NEGATIVE_SIDE;
78
79 if (dist > +radius)
80 return Plane::POSITIVE_SIDE;
81
82 return Plane::BOTH_SIDE;
83 }
84
85 Vector3 Plane::projectVector(const Vector3& point) const
86 {
87 // We know plane normal is unit length, so use simple method
88 Matrix3 xform;
89 xform[0][0] = 1.0f - normal.x * normal.x;
90 xform[0][1] = -normal.x * normal.y;
91 xform[0][2] = -normal.x * normal.z;
92 xform[1][0] = -normal.y * normal.x;
93 xform[1][1] = 1.0f - normal.y * normal.y;
94 xform[1][2] = -normal.y * normal.z;
95 xform[2][0] = -normal.z * normal.x;
96 xform[2][1] = -normal.z * normal.y;
97 xform[2][2] = 1.0f - normal.z * normal.z;
98 return xform.multiply(point);
99
100 }
101
102 float Plane::normalize()
103 {
104 float fLength = normal.length();
105
106 // Will also work for zero-sized vectors, but will change nothing
107 if (fLength > 1e-08f)
108 {
109 float fInvLength = 1.0f / fLength;
110 normal *= fInvLength;
111 d *= fInvLength;
112 }
113
114 return fLength;
115 }
116
117 bool Plane::intersects(const AABox& box) const
118 {
119 return box.intersects(*this);
120 }
121
122 bool Plane::intersects(const Sphere& sphere) const
123 {
124 return sphere.intersects(*this);
125 }
126
127 std::pair<bool, float> Plane::intersects(const Ray& ray) const
128 {
129 float denom = normal.dot(ray.getDirection());
130 if (Math::abs(denom) < std::numeric_limits<float>::epsilon())
131 {
132 // Parallel
133 return std::pair<bool, float>(false, 0.0f);
134 }
135 else
136 {
137 float nom = normal.dot(ray.getOrigin()) - d;
138 float t = -(nom/denom);
139 return std::pair<bool, float>(t >= 0.0f, t);
140 }
141 }
142}
143