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 | |
10 | namespace 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 | |