Raytracer
Loading...
Searching...
No Matches
VecN.hpp
1#include <cmath>
2#include <cstddef>
3#include <iostream>
4#include "exceptions/Range.hpp"
5#include <type_traits>
6
7#ifndef __VEC_N_HPP__
8 #define __VEC_N_HPP__
9
10namespace Raytracer::Utils
11{
12 inline double degreesToRadians(double degrees)
13 {
14 return degrees * M_PI / 180.0;
15 }
16
17 inline double randomDouble()
18 {
19 return rand() / (RAND_MAX + 1.0);
20 }
21
22 inline double randomDouble(double min, double max)
23 {
24 return min + (max - min) * randomDouble();
25 }
26
27 inline int randomInt(int min, int max)
28 {
29 return static_cast<int>(randomDouble(min, max + 1));
30 }
31
32 template <typename T>
33 concept isNumerical = requires(T) { std::is_arithmetic_v<T>; };
34
35 template <typename T>
36 concept isPositive = requires(T t) { t > 0; };
37
38 template <isNumerical T, std::size_t N>
39 requires isPositive<T> && (N > 1)
40 class VecN {
41 public:
42 T e[N];
43
44 VecN() : e{0, 0, 0}
45 {
46 }
47
48 VecN(T e0, T e1, T e2)
49 {
50 static_assert(
51 N == 3, "VecN(T e0, T e1, T e2) is only valid for N == 3");
52 e[0] = e0;
53 e[1] = e1;
54 e[2] = e2;
55 }
56
57 T x() const
58 {
59 return e[0];
60 }
61
62 T y() const
63 {
64 static_assert(N == 3, "y() is only valid for >= VecN<2>");
65 return e[1];
66 }
67
68 T z() const
69 {
70 static_assert(N == 3, "z() is only valid for VecN<3>");
71 return e[2];
72 }
73
74 VecN operator-() const
75 {
76 VecN v;
77 for (std::size_t i = 0; i < N; i++) {
78 v.e[i] = -e[i];
79 }
80
81 return v;
82 }
83
84 T operator[](std::size_t i) const
85 {
86 if (i >= N) {
87 throw Exceptions::RangeException("Index out of bounds");
88 }
89 return e[i];
90 }
91
92 T &operator[](std::size_t i)
93 {
94 if (i >= N) {
95 throw Exceptions::RangeException("Index out of bounds");
96 }
97 return e[i];
98 }
99
100 VecN &operator+=(const VecN &v)
101 {
102 for (std::size_t i = 0; i < N; i++) {
103 e[i] += v.e[i];
104 }
105
106 return *this;
107 }
108
109 VecN &operator*=(double t)
110 {
111 for (std::size_t i = 0; i < N; i++) {
112 e[i] *= t;
113 }
114
115 return *this;
116 }
117
118 VecN &operator/=(double t)
119 {
120 return *this *= 1 / t;
121 }
122
123 double length() const
124 {
125 return std::sqrt(lengthSquared());
126 }
127
128 double lengthSquared() const
129 {
130 double sum = 0;
131 for (std::size_t i = 0; i < N; i++) {
132 sum += e[i] * e[i];
133 }
134
135 return sum;
136 }
137
138 bool nearZero() const
139 {
140 static constexpr double s = 1e-8;
141 for (std::size_t i = 0; i < N; i++) {
142 if (std::fabs(e[i]) > s) {
143 return false;
144 }
145 }
146
147 return true;
148 }
149
150 static VecN random()
151 {
152 VecN result;
153 for (std::size_t i = 0; i < N; i++) {
154 result[i] = randomDouble();
155 }
156
157 return result;
158 }
159
160 static VecN random(double min, double max)
161 {
162 VecN result;
163 for (std::size_t i = 0; i < N; i++) {
164 result[i] = randomDouble(min, max);
165 }
166
167 return result;
168 }
169
170 VecN &normalize()
171 {
172 return *this /= length();
173 }
174 };
175
176 using Vec3 = VecN<double, 3>;
177 using Point3 = Vec3;
178 using Color = Vec3;
179
180 template <typename T, std::size_t N>
181 std::ostream &operator<<(std::ostream &out, const VecN<T, N> &v)
182 {
183 for (std::size_t i = 0; i < N; i++) {
184 out << v[i];
185 if (i != N - 1) {
186 out << " ";
187 }
188 }
189 return out;
190 }
191
192 template <typename T, std::size_t N>
193 VecN<T, N> operator+(const VecN<T, N> &u, const VecN<T, N> &v)
194 {
195 VecN<T, N> result;
196 for (std::size_t i = 0; i < N; i++) {
197 result.e[i] = u.e[i] + v.e[i];
198 }
199 return result;
200 }
201
202 template <typename T, std::size_t N>
203 VecN<T, N> operator-(const VecN<T, N> &u, const VecN<T, N> &v)
204 {
205 VecN<T, N> result;
206 for (std::size_t i = 0; i < N; i++) {
207 result.e[i] = u.e[i] - v.e[i];
208 }
209 return result;
210 }
211
212 template <typename T, std::size_t N>
213 VecN<T, N> operator*(const VecN<T, N> &u, const VecN<T, N> &v)
214 {
215 VecN<T, N> result;
216 for (std::size_t i = 0; i < N; i++) {
217 result.e[i] = u.e[i] * v.e[i];
218 }
219 return result;
220 }
221
222 template <typename T, std::size_t N>
223 VecN<T, N> operator*(double t, const VecN<T, N> &v)
224 {
225 VecN<T, N> result;
226 for (std::size_t i = 0; i < N; i++) {
227 result.e[i] = t * v.e[i];
228 }
229 return result;
230 }
231
232 template <typename T, std::size_t N>
233 VecN<T, N> operator*(const VecN<T, N> &v, double t)
234 {
235 return t * v;
236 }
237
238 template <typename T, std::size_t N>
239 VecN<T, N> operator/(const VecN<T, N> &v, double t)
240 {
241 return (1 / t) * v;
242 }
243
244 template <typename T, std::size_t N>
245 T dot(const VecN<T, N> &u, const VecN<T, N> &v)
246 {
247 T sum = 0;
248 for (std::size_t i = 0; i < N; i++) {
249 sum += u.e[i] * v.e[i];
250 }
251
252 return sum;
253 }
254
255 template <typename T, std::size_t N>
256 VecN<T, N> cross(const VecN<T, N> &u, const VecN<T, N> &v)
257 {
258 static_assert(N == 3, "cross() is only valid for VecN<3>");
259
260 VecN<T, N> result;
261 result[0] = u.e[1] * v.e[2] - u.e[2] * v.e[1];
262 result[1] = u.e[2] * v.e[0] - u.e[0] * v.e[2];
263 result[2] = u.e[0] * v.e[1] - u.e[1] * v.e[0];
264
265 return result;
266 }
267
268 template <typename T, std::size_t N>
269 VecN<T, N> unitVector(const VecN<T, N> &v)
270 {
271 return v / v.length();
272 }
273
274 template <typename T, std::size_t N> VecN<T, N> randomInUnitSphere()
275 {
276 while (true) {
277 VecN<T, N> vec = VecN<T, N>::random(-1, 1);
278
279 if (vec.lengthSquared() >= 1) {
280 continue;
281 }
282
283 return vec;
284 }
285 }
286
287 template <typename T, std::size_t N> VecN<T, N> randomUnitVector()
288 {
289 return unitVector(randomInUnitSphere<T, N>());
290 }
291
292 template <typename T, std::size_t N>
293 VecN<T, N> randomInHemisphere(const VecN<T, N> &normal)
294 {
295 VecN<T, N> inUnitSphere = randomInUnitSphere<T, N>();
296
297 if (dot(inUnitSphere, normal) > 0.0) {
298 return inUnitSphere;
299 } else {
300 return -inUnitSphere;
301 }
302 }
303
304 template <typename T, std::size_t N>
305 VecN<T, N> reflect(const VecN<T, N> &v, const VecN<T, N> &n)
306 {
307 return v - 2 * dot(v, n) * n;
308 }
309
310 template <typename T, std::size_t N>
311 VecN<T, N> refract(
312 const VecN<T, N> &uv, const VecN<T, N> &n, double etaiOverEtat)
313 {
314 double cosTheta = std::fmin(dot(-uv, n), 1.0);
315 VecN<T, N> rayOutPerp = etaiOverEtat * (uv + cosTheta * n);
316 VecN<T, N> rayOutParallel =
317 -std::sqrt(std::fabs(1.0 - rayOutPerp.lengthSquared())) * n;
318 return rayOutPerp + rayOutParallel;
319 }
320
321 template <typename T, std::size_t N> VecN<T, N> randomInUnitDisk()
322 {
323 while (true) {
324 VecN<T, N> p =
325 VecN<T, N>(randomDouble(-1, 1), randomDouble(-1, 1), 0);
326 if (p.lengthSquared() >= 1) {
327 continue;
328 }
329
330 return p;
331 }
332 }
333} // namespace Raytracer::Utils
334
335#endif /* __VEC_N_HPP__ */
Definition VecN.hpp:40
Definition VecN.hpp:33
Definition VecN.hpp:36