4#include "exceptions/Range.hpp"
10namespace Raytracer::Utils
12 inline double degreesToRadians(
double degrees)
14 return degrees * M_PI / 180.0;
17 inline double randomDouble()
19 return rand() / (RAND_MAX + 1.0);
22 inline double randomDouble(
double min,
double max)
24 return min + (max - min) * randomDouble();
27 inline int randomInt(
int min,
int max)
29 return static_cast<int>(randomDouble(min, max + 1));
33 concept isNumerical =
requires(T) { std::is_arithmetic_v<T>; };
38 template <isNumerical T, std::
size_t N>
48 VecN(T e0, T e1, T e2)
51 N == 3,
"VecN(T e0, T e1, T e2) is only valid for N == 3");
64 static_assert(N == 3,
"y() is only valid for >= VecN<2>");
70 static_assert(N == 3,
"z() is only valid for VecN<3>");
74 VecN operator-()
const
77 for (std::size_t i = 0; i < N; i++) {
84 T operator[](std::size_t i)
const
92 T &operator[](std::size_t i)
102 for (std::size_t i = 0; i < N; i++) {
109 VecN &operator*=(
double t)
111 for (std::size_t i = 0; i < N; i++) {
118 VecN &operator/=(
double t)
120 return *
this *= 1 / t;
123 double length()
const
125 return std::sqrt(lengthSquared());
128 double lengthSquared()
const
131 for (std::size_t i = 0; i < N; i++) {
138 bool nearZero()
const
140 static constexpr double s = 1e-8;
141 for (std::size_t i = 0; i < N; i++) {
142 if (std::fabs(e[i]) > s) {
153 for (std::size_t i = 0; i < N; i++) {
154 result[i] = randomDouble();
160 static VecN random(
double min,
double max)
163 for (std::size_t i = 0; i < N; i++) {
164 result[i] = randomDouble(min, max);
172 return *
this /= length();
180 template <
typename T, std::
size_t N>
181 std::ostream &operator<<(std::ostream &out,
const VecN<T, N> &v)
183 for (std::size_t i = 0; i < N; i++) {
192 template <
typename T, std::
size_t N>
193 VecN<T, N> operator+(
const VecN<T, N> &u,
const VecN<T, N> &v)
196 for (std::size_t i = 0; i < N; i++) {
197 result.e[i] = u.e[i] + v.e[i];
202 template <
typename T, std::
size_t N>
203 VecN<T, N> operator-(
const VecN<T, N> &u,
const VecN<T, N> &v)
206 for (std::size_t i = 0; i < N; i++) {
207 result.e[i] = u.e[i] - v.e[i];
212 template <
typename T, std::
size_t N>
213 VecN<T, N> operator*(
const VecN<T, N> &u,
const VecN<T, N> &v)
216 for (std::size_t i = 0; i < N; i++) {
217 result.e[i] = u.e[i] * v.e[i];
222 template <
typename T, std::
size_t N>
223 VecN<T, N> operator*(
double t,
const VecN<T, N> &v)
226 for (std::size_t i = 0; i < N; i++) {
227 result.e[i] = t * v.e[i];
232 template <
typename T, std::
size_t N>
233 VecN<T, N> operator*(
const VecN<T, N> &v,
double t)
238 template <
typename T, std::
size_t N>
239 VecN<T, N> operator/(
const VecN<T, N> &v,
double t)
244 template <
typename T, std::
size_t N>
245 T dot(
const VecN<T, N> &u,
const VecN<T, N> &v)
248 for (std::size_t i = 0; i < N; i++) {
249 sum += u.e[i] * v.e[i];
255 template <
typename T, std::
size_t N>
256 VecN<T, N> cross(
const VecN<T, N> &u,
const VecN<T, N> &v)
258 static_assert(N == 3,
"cross() is only valid for VecN<3>");
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];
268 template <
typename T, std::
size_t N>
269 VecN<T, N> unitVector(
const VecN<T, N> &v)
271 return v / v.length();
274 template <
typename T, std::
size_t N> VecN<T, N> randomInUnitSphere()
277 VecN<T, N> vec = VecN<T, N>::random(-1, 1);
279 if (vec.lengthSquared() >= 1) {
287 template <
typename T, std::
size_t N> VecN<T, N> randomUnitVector()
289 return unitVector(randomInUnitSphere<T, N>());
292 template <
typename T, std::
size_t N>
293 VecN<T, N> randomInHemisphere(
const VecN<T, N> &normal)
295 VecN<T, N> inUnitSphere = randomInUnitSphere<T, N>();
297 if (dot(inUnitSphere, normal) > 0.0) {
300 return -inUnitSphere;
304 template <
typename T, std::
size_t N>
305 VecN<T, N> reflect(
const VecN<T, N> &v,
const VecN<T, N> &n)
307 return v - 2 * dot(v, n) * n;
310 template <
typename T, std::
size_t N>
312 const VecN<T, N> &uv,
const VecN<T, N> &n,
double etaiOverEtat)
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;
321 template <
typename T, std::
size_t N> VecN<T, N> randomInUnitDisk()
325 VecN<T, N>(randomDouble(-1, 1), randomDouble(-1, 1), 0);
326 if (p.lengthSquared() >= 1) {