1 /*
2  * Copyright (c) 2024 Huawei Device Co., Ltd.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #ifndef API_BASE_MATH_VECTOR_UTIL_H
17 #define API_BASE_MATH_VECTOR_UTIL_H
18 
19 #include <base/math/mathf.h>
20 #include <base/math/vector.h>
21 #include <base/namespace.h>
22 
BASE_BEGIN_NAMESPACE()23 BASE_BEGIN_NAMESPACE()
24 namespace Math {
25 /** \addtogroup group_math_vectorutil
26  *  @{
27  */
28 // Vector2
29 /** Dot product of two vector2's */
30 static inline constexpr float Dot(const Vec2& lhs, const Vec2& rhs)
31 {
32     return (lhs.x * rhs.x) + (lhs.y * rhs.y);
33 }
34 
35 /** Cross product of two vector2's */
36 static inline constexpr float Cross(const Vec2& lhs, const Vec2& rhs)
37 {
38     return lhs.x * rhs.y - lhs.y * rhs.x;
39 }
40 
41 /** Linearly interpolate between two vector2's */
42 static inline constexpr Vec2 Lerp(Vec2 v1, Vec2 v2, float t)
43 {
44     t = Math::clamp01(t);
45     return Vec2(v1.x + (v2.x - v1.x) * t, v1.y + (v2.y - v1.y) * t);
46 }
47 
48 /** Return squared magnitude of two vector2's */
49 static inline constexpr float SqrMagnitude(const Vec2& vec)
50 {
51     return vec.x * vec.x + vec.y * vec.y;
52 }
53 
54 /** Return magnitude of two vector2's */
55 static inline float Magnitude(const Vec2& vec)
56 {
57     return Math::sqrt(vec.x * vec.x + vec.y * vec.y);
58 }
59 
60 /** Return distance between vector2's */
61 static inline float distance(const Vec2& v0, const Vec2& v1)
62 {
63     return Magnitude(v1 - v0);
64 }
65 
66 /** Return two component min of vector2's */
67 static constexpr inline Vec2 min(const Vec2& lhs, const Vec2& rhs)
68 {
69     return Vec2(min(lhs.x, rhs.x), min(lhs.y, rhs.y));
70 }
71 
72 /** Return two component max of vector2's */
73 static constexpr inline Vec2 max(const Vec2& lhs, const Vec2& rhs)
74 {
75     return Vec2(max(lhs.x, rhs.x), max(lhs.y, rhs.y));
76 }
77 
78 /** Return normalized vector2 (if magnitude is not larger than epsilon, returns zero vector) */
79 static inline Vec2 Normalize(const Vec2& value)
80 {
81     const float mag = Magnitude(value);
82     if (mag > Math::EPSILON)
83         return value / mag;
84     else
85         return Vec2(0.0f, 0.0f);
86 }
87 
88 /** Return vector2 perpendicular to input in clock-wise direction */
89 static inline Vec2 PerpendicularCW(const Vec2& value)
90 {
91     return Vec2(-value.y, value.x);
92 }
93 
94 /** Return vector2 perpendicular to input in counter clock-wise direction */
95 static inline Vec2 PerpendicularCCW(const Vec2& value)
96 {
97     return Vec2(value.y, -value.x);
98 }
99 
100 /** Return vector2 rotated clock wise by angle radians (Y down)*/
101 static inline Vec2 RotateCW(const Vec2& value, float angle)
102 {
103     const float s = Math::sin(angle);
104     const float c = Math::cos(angle);
105     return Vec2(value.x * c - value.y * s, value.y * c + value.x * s);
106 }
107 
108 /** Return vector2 rotated counter clock wise by angle radians (Y down) */
109 static inline Vec2 RotateCCW(const Vec2& value, float angle)
110 {
111     const float s = Math::sin(angle);
112     const float c = Math::cos(angle);
113     return Vec2(value.x * c + value.y * s, value.y * c - value.x * s);
114 }
115 
116 /** Return intersection of two Vec2 start points and direction vectors. Returns boolean flag indicating if the vectors
117  * intersect. */
118 static inline Vec2 Intersect(
119     const Vec2& aStart, const Vec2& aDir, const Vec2& bStart, const Vec2& bDir, bool infinite, bool& intersected)
120 {
121     const auto denominator = Cross(aDir, bDir);
122 
123     if (Math::abs(denominator) < BASE_EPSILON) {
124         // The lines are parallel
125         intersected = false;
126         return {};
127     }
128 
129     // Solve the intersection positions
130     const auto originDist = bStart - aStart;
131     const auto uNumerator = Cross(originDist, aDir);
132     const auto u = uNumerator / denominator;
133     const auto t = Cross(originDist, bDir) / denominator;
134 
135     if (!infinite && (t < 0 || t > 1 || u < 0 || u > 1)) {
136         // The intersection lies outside of the line segments
137         intersected = false;
138         return {};
139     }
140 
141     intersected = true;
142 
143     // Calculate the intersection point
144     return aStart + aDir * t;
145 }
146 
147 // Vector3
148 /** Dot product of two vector3's */
149 static inline constexpr float Dot(const Vec3& lhs, const Vec3& rhs)
150 {
151     return (lhs.x * rhs.x) + (lhs.y * rhs.y) + (lhs.z * rhs.z);
152 }
153 
154 /** Cross product of two vector3's */
155 static inline constexpr Vec3 Cross(const Vec3& lhs, const Vec3& rhs)
156 {
157     return Vec3(lhs.y * rhs.z - lhs.z * rhs.y, lhs.z * rhs.x - lhs.x * rhs.z, lhs.x * rhs.y - lhs.y * rhs.x);
158 }
159 
160 /** Linearly interpolate between v1 and v2 vector3's by value t */
161 static inline constexpr Vec3 Lerp(const Vec3& v1, const Vec3& v2, float t)
162 {
163     t = Math::clamp01(t);
164     return Vec3(v1.x + (v2.x - v1.x) * t, v1.y + (v2.y - v1.y) * t, v1.z + (v2.z - v1.z) * t);
165 }
166 
167 /** Return squared magnitude of vector3's */
168 static inline constexpr float SqrMagnitude(const Vec3& vec)
169 {
170     return vec.x * vec.x + vec.y * vec.y + vec.z * vec.z;
171 }
172 
173 /** Return magnitude of vector3's */
174 static inline float Magnitude(const Vec3& vec)
175 {
176     return Math::sqrt(vec.x * vec.x + vec.y * vec.y + vec.z * vec.z);
177 }
178 
179 /** Return squared distance of two vector3's */
180 static inline float Distance2(const Vec3& v0, const Vec3& v1)
181 {
182     return SqrMagnitude(v1 - v0);
183 }
184 
185 /** Return normalized vector3 (if magnitude is not larger than epsilon, returns zero vector) */
186 static inline Vec3 Normalize(const Vec3& value)
187 {
188     const float mag = Magnitude(value);
189     if (mag > Math::EPSILON) {
190         return value / mag;
191     } else {
192         return Vec3(0.0f, 0.0f, 0.0f);
193     }
194 }
195 
196 /** Return three component min of vector3's */
197 static constexpr inline Vec3 min(const Vec3& lhs, const Vec3& rhs)
198 {
199     return Vec3(min(lhs.x, rhs.x), min(lhs.y, rhs.y), min(lhs.z, rhs.z));
200 }
201 
202 /** Return three component max of vector3's */
203 static constexpr inline Vec3 max(const Vec3& lhs, const Vec3& rhs)
204 {
205     return Vec3(max(lhs.x, rhs.x), max(lhs.y, rhs.y), max(lhs.z, rhs.z));
206 }
207 
208 /** Return scaled value of vector3 */
209 static inline Vec3 Scale(Vec3 const& v, float desiredLength)
210 {
211     return v * desiredLength / Magnitude(v);
212 }
213 
214 /** Combine vector3's which have been multiplied with scalar (a * ascl) + (b * bscl) */
215 static inline constexpr Vec3 Combine(Vec3 const& a, Vec3 const& b, float ascl, float bscl)
216 {
217     return (a * ascl) + (b * bscl);
218 }
219 
220 // Vector4
221 /** Return squared magnitude of vector4 */
222 static inline constexpr float SqrMagnitude(const Vec4& vec)
223 {
224     return vec.x * vec.x + vec.y * vec.y + vec.z * vec.z + vec.w * vec.w;
225 }
226 
227 /** Linearly interpolate between v1 and v2 vector4's by value t */
228 static inline constexpr Vec4 Lerp(const Vec4& v1, const Vec4& v2, float t)
229 {
230     t = Math::clamp01(t);
231     return Vec4(v1.x + (v2.x - v1.x) * t, v1.y + (v2.y - v1.y) * t, v1.z + (v2.z - v1.z) * t, v1.w + (v2.w - v1.w) * t);
232 }
233 
234 /** @} */
235 } // namespace Math
236 BASE_END_NAMESPACE()
237 
238 #endif // API_BASE_MATH_VECTOR_UTIL_H
239