#pragma once #include "diffvg.h" #include #include template struct TVector2 { DEVICE TVector2() {} template DEVICE TVector2(T2 x, T2 y) : x(T(x)), y(T(y)) {} template DEVICE TVector2(const TVector2 &v) : x(T(v.x)), y(T(v.y)) {} DEVICE T& operator[](int i) { return *(&x + i); } DEVICE T operator[](int i) const { return *(&x + i); } T x, y; }; template struct TVector3 { DEVICE TVector3() {} template DEVICE TVector3(T2 x, T2 y, T2 z) : x(T(x)), y(T(y)), z(T(z)) {} template DEVICE TVector3(const TVector3 &v) : x(T(v.x)), y(T(v.y)), z(T(v.z)) {} DEVICE T& operator[](int i) { return *(&x + i); } DEVICE T operator[](int i) const { return *(&x + i); } T x, y, z; }; template struct TVector4 { DEVICE TVector4() {} template DEVICE TVector4(T2 x, T2 y, T2 z, T2 w) : x(T(x)), y(T(y)), z(T(z)), w(T(w)) {} template DEVICE TVector4(const TVector4 &v) : x(T(v.x)), y(T(v.y)), z(T(v.z)), w(T(v.w)) {} DEVICE T& operator[](int i) { return *(&x + i); } DEVICE T operator[](int i) const { return *(&x + i); } T x, y, z, w; }; using Vector2f = TVector2; using Vector2d = TVector2; using Vector2i = TVector2; using Vector2 = TVector2; using Vector3i = TVector3; using Vector3f = TVector3; using Vector3d = TVector3; using Vector3 = TVector3; using Vector4f = TVector4; using Vector4d = TVector4; using Vector4 = TVector4; template DEVICE inline auto operator+(const TVector2 &v0, const TVector2 &v1) -> TVector2 { return TVector2{ v0[0] + v1[0], v0[1] + v1[1]}; } template DEVICE inline auto operator+(const T0 &v0, const TVector2 &v1) -> TVector2 { return TVector2{v0 + v1[0], v0 + v1[1]}; } template DEVICE inline auto operator+(const T0 &v0, const TVector3 &v1) -> TVector3 { return TVector3{ v0 + v1[0], v0 + v1[1], v0 + v1[2]}; } template DEVICE inline auto operator+(const TVector2 &v0, const T1 &v1) -> TVector2 { return TVector2{ v0[0] + v1, v0[1] + v1}; } template DEVICE inline auto operator+(const TVector3 &v0, const T1 &v1) -> TVector3 { return TVector3{ v0[0] + v1, v0[1] + v1, v0[2] + v1}; } template DEVICE inline auto operator+(const TVector3 &v0, const TVector3 &v1) -> TVector3 { return TVector3{ v0[0] + v1[0], v0[1] + v1[1], v0[2] + v1[2]}; } template DEVICE inline auto operator+(const TVector4 &v0, const TVector4 &v1) -> TVector4 { return TVector4{ v0[0] + v1[0], v0[1] + v1[1], v0[2] + v1[2], v0[3] + v1[3]}; } template DEVICE inline auto operator+=(TVector2 &v0, const TVector2 &v1) -> TVector2& { v0[0] += v1[0]; v0[1] += v1[1]; return v0; } template DEVICE inline auto operator+=(TVector3 &v0, const TVector3 &v1) -> TVector3& { v0[0] += v1[0]; v0[1] += v1[1]; v0[2] += v1[2]; return v0; } template DEVICE inline auto operator+=(TVector3 &v0, const T1 &v1) -> TVector3& { v0[0] += v1; v0[1] += v1; v0[2] += v1; return v0; } template DEVICE inline auto operator+=(TVector4 &v0, const TVector4 &v1) -> TVector4& { v0[0] += v1[0]; v0[1] += v1[1]; v0[2] += v1[2]; v0[3] += v1[3]; return v0; } template DEVICE inline auto operator+=(TVector4 &v0, const T1 &v1) -> TVector4& { v0[0] += v1; v0[1] += v1; v0[2] += v1; v0[3] += v1; return v0; } template DEVICE inline auto operator-(const T0 &v0, const TVector2 &v1) -> TVector2 { return TVector2{v0 - v1[0], v0 - v1[1]}; } template DEVICE inline auto operator-(const T0 &v0, const TVector3 &v1) -> TVector2 { return TVector3{v0 - v1[0], v0 - v1[1], v0 - v1[2]}; } template DEVICE inline auto operator-(const TVector2 &v0, const T1 &v1) -> TVector2 { return TVector2{v0[0] - v1, v0[1] - v1}; } template DEVICE inline auto operator-(const TVector3 &v0, const T1 &v1) -> TVector3 { return TVector3{v0[0] - v1, v0[1] - v1, v0[2] - v1}; } template DEVICE inline auto operator-(const TVector2 &v0, const TVector2 &v1) -> TVector2 { return TVector2{ v0[0] - v1[0], v0[1] - v1[1]}; } template DEVICE inline auto operator-(const TVector2 &v) -> TVector2 { return TVector2{-v[0], -v[1]}; } template DEVICE inline auto operator-(const TVector3 &v) -> TVector3 { return TVector3{-v[0], -v[1], -v[2]}; } template DEVICE inline auto operator-(const TVector3 &v0, const TVector3 &v1) -> TVector3 { return TVector3{ v0[0] - v1[0], v0[1] - v1[1], v0[2] - v1[2]}; } template DEVICE inline auto operator-(const TVector4 &v0, const TVector4 &v1) -> TVector4 { return TVector4{ v0[0] - v1[0], v0[1] - v1[1], v0[2] - v1[2], v0[3] - v1[3]}; } template DEVICE inline auto operator-=(TVector2 &v0, const TVector2 &v1) -> TVector2& { v0[0] -= v1[0]; v0[1] -= v1[1]; return v0; } template DEVICE inline auto operator-=(TVector3 &v0, const TVector3 &v1) -> TVector3& { v0[0] -= v1[0]; v0[1] -= v1[1]; v0[2] -= v1[2]; return v0; } template DEVICE inline auto operator*(const TVector2 &v0, const TVector2 &v1) -> TVector2 { return TVector2{ v0[0] * v1[0], v0[1] * v1[1]}; } template DEVICE inline auto operator*(const TVector2 &v0, const T1 &s) -> TVector2 { return TVector2{ v0[0] * s, v0[1] * s}; } template DEVICE inline auto operator*(const T0 &s, const TVector2 &v0) -> TVector2 { return TVector2{s * v0[0], s * v0[1]}; } template DEVICE inline auto operator*=(TVector2 &v0, const T1 &s) -> TVector2& { v0[0] *= s; v0[1] *= s; return v0; } template DEVICE inline auto operator*(const TVector3 &v0, const T1 &s) -> TVector3 { return TVector3{ v0[0] * s, v0[1] * s, v0[2] * s}; } template DEVICE inline auto operator*(const T0 &s, const TVector3 &v0) -> TVector3 { return TVector3{ s * v0[0], s * v0[1], s * v0[2]}; } template DEVICE inline auto operator*=(TVector3 &v0, const T1 &s) -> TVector3& { v0[0] *= s; v0[1] *= s; v0[2] *= s; return v0; } template DEVICE inline auto operator*=(TVector4 &v0, const T1 &s) -> TVector4& { v0[0] *= s; v0[1] *= s; v0[2] *= s; v0[3] *= s; return v0; } template DEVICE inline auto operator*(const TVector3 &v0, const TVector3 &v1) -> TVector3 { return TVector3{ v0[0] * v1[0], v0[1] * v1[1], v0[2] * v1[2]}; } template DEVICE inline auto operator*(const TVector4 &v0, const T1 &s) -> TVector4 { return TVector4{ v0[0] * s, v0[1] * s, v0[2] * s, v0[3] * s}; } template DEVICE inline auto operator*(const T0 &s, const TVector4 &v0) -> TVector4 { return TVector4{ s * v0[0], s * v0[1], s * v0[2], s * v0[3]}; } template DEVICE inline auto operator*(const TVector4 &v0, const TVector4 &v1) -> TVector4 { return TVector4{ v0[0] * v1[0], v0[1] * v1[1], v0[2] * v1[2], v0[3] * v1[3]}; } template DEVICE inline auto operator/(const TVector2 &v0, const T1 &s) -> TVector2 { auto inv_s = 1.f / s; return v0 * inv_s; } template DEVICE inline auto operator/(const TVector3 &v0, const T1 &s) -> TVector3 { auto inv_s = 1.f / s; return v0 * inv_s; } template DEVICE inline auto operator/(const TVector4 &v0, const T1 &s) -> TVector4 { auto inv_s = 1.f / s; return v0 * inv_s; } template DEVICE inline auto operator/(const T0 &s, const TVector3 &v1) -> TVector3 { return TVector3{ s / v1[0], s / v1[2], s / v1[2]}; } template DEVICE inline auto operator/(const TVector3 &v0, const TVector3 &v1) -> TVector3 { return TVector3{ v0[0] / v1[0], v0[1] / v1[2], v0[2] / v1[2]}; } template DEVICE inline auto operator/(const TVector2 &v0, const TVector2 &v1) -> TVector2 { return TVector2{ v0[0] / v1[0], v0[1] / v1[1]}; } template DEVICE inline auto operator/=(TVector3 &v0, const T1 &s) -> TVector3& { auto inv_s = 1.f / s; v0[0] *= inv_s; v0[1] *= inv_s; v0[2] *= inv_s; return v0; } template DEVICE inline auto operator/=(TVector4 &v0, const T1 &s) -> TVector4& { auto inv_s = 1.f / s; v0[0] *= inv_s; v0[1] *= inv_s; v0[2] *= inv_s; v0[3] *= inv_s; return v0; } template DEVICE inline bool operator==(const TVector2 &v0, const TVector2 &v1) { return v0.x == v1.x && v0.y == v1.y; } template DEVICE inline bool operator==(const TVector3 &v0, const TVector3 &v1) { return v0.x == v1.x && v0.y == v1.y && v0.z == v1.z; } template DEVICE inline bool operator!=(const TVector3 &v0, const TVector3 &v1) { return v0.x != v1.x || v0.y != v1.y || v0.z != v1.z; } template DEVICE inline TVector2 get_normal(const TVector2 &v) { return TVector2{v.y, -v.x}; } template DEVICE inline T length_squared(const TVector2 &v0) { return square(v0[0]) + square(v0[1]); } template DEVICE inline TVector2 d_length_squared(const TVector2 &v0, const T &d_l_sq) { //l_sq = square(v0[0]) + square(v0[1]) return 2 * d_l_sq * v0; } template DEVICE inline T length(const TVector2 &v0) { return sqrt(length_squared(v0)); } template DEVICE inline TVector2 d_length(const TVector2 &v0, const T &d_l) { auto l_sq = length_squared(v0); auto l = sqrt(l_sq); auto d_l_sq = 0.5f * d_l / l; return d_length_squared(v0, T(d_l_sq)); } template DEVICE inline T length_squared(const TVector3 &v0) { return square(v0[0]) + square(v0[1]) + square(v0[2]); } template DEVICE inline TVector3 d_length_squared(const TVector3 &v0, const T &d_l_sq) { //l_sq = square(v0[0]) + square(v0[1]) + square(v0[2]) return 2 * d_l_sq * v0; } template DEVICE inline T length(const TVector3 &v0) { return sqrt(length_squared(v0)); } template DEVICE inline TVector3 d_length(const TVector3 &v0, const T &d_l) { auto l_sq = length_squared(v0); auto l = sqrt(l_sq); auto d_l_sq = 0.5f * d_l / l; return d_length_squared(v0, d_l_sq); } template DEVICE inline auto distance_squared(const TVector2 &v0, const TVector2 &v1) -> decltype(length_squared(v1 - v0)) { return length_squared(v1 - v0); } template DEVICE inline auto distance_squared(const TVector3 &v0, const TVector3 &v1) -> decltype(length_squared(v1 - v0)) { return length_squared(v1 - v0); } template DEVICE inline auto distance(const TVector2 &v0, const TVector2 &v1) -> decltype(length(v1 - v0)) { return length(v1 - v0); } template DEVICE inline void d_distance(const TVector2 &v0, const TVector2 &v1, const T &d_output, TVector2 &d_v0, TVector2 &d_v1) { auto d_v1_v0 = d_length(v1 - v0, d_output); d_v0 -= d_v1_v0; d_v1 += d_v1_v0; } template DEVICE inline auto distance(const TVector3 &v0, const TVector3 &v1) -> decltype(length(v1 - v0)) { return length(v1 - v0); } template DEVICE inline void d_distance(const TVector3 &v0, const TVector3 &v1, const T &d_output, TVector3 &d_v0, TVector3 &d_v1) { auto d_v1_v0 = d_length(v1 - v0, d_output); d_v0 -= d_v1_v0; d_v1 += d_v1_v0; } template DEVICE inline TVector2 normalize(const TVector2 &v0) { return v0 / length(v0); } template DEVICE inline TVector2 d_normalize(const TVector2 &v0, const TVector2 &d_n) { auto l = length(v0); auto n = v0 / l; auto d_v0 = d_n / l; auto d_l = -dot(d_n, n) / l; // l = length(v0) d_v0 += d_length(v0, d_l); return d_v0; } template DEVICE inline TVector3 normalize(const TVector3 &v0) { return v0 / length(v0); } template DEVICE inline TVector3 d_normalize(const TVector3 &v0, const TVector3 &d_n) { auto l = length(v0); auto n = v0 / l; auto d_v0 = d_n / l; auto d_l = -dot(d_n, n) / l; // l = length(v0) d_v0 += d_length(v0, d_l); return d_v0; } template DEVICE inline auto dot(const TVector2 &v0, const TVector2 &v1) -> decltype(v0[0] * v1[0]) { return v0[0] * v1[0] + v0[1] * v1[1]; } template DEVICE inline auto dot(const TVector3 &v0, const TVector3 &v1) -> decltype(v0[0] * v1[0]) { return v0[0] * v1[0] + v0[1] * v1[1] + v0[2] * v1[2]; } template DEVICE inline auto dot(const TVector4 &v0, const TVector4 &v1) -> decltype(v0[0] * v1[0]) { return v0[0] * v1[0] + v0[1] * v1[1] + v0[2] * v1[2] + v0[3] * v1[3]; } template DEVICE inline auto cross(const TVector3 &v0, const TVector3 &v1) -> TVector3 { return TVector3{ v0[1] * v1[2] - v0[2] * v1[1], v0[2] * v1[0] - v0[0] * v1[2], v0[0] * v1[1] - v0[1] * v1[0]}; } template DEVICE inline void d_cross(const TVector3 &v0, const TVector3 &v1, const TVector3 &d_output, TVector3 &d_v0, TVector3 &d_v1) { d_v0 += cross(v1, d_output); d_v1 += cross(d_output, v0); } template DEVICE inline T luminance(const TVector3 &v) { return 0.212671f * v[0] + 0.715160f * v[1] + 0.072169f * v[2]; } template DEVICE inline T sum(const T &v) { return v; } template DEVICE inline T sum(const TVector2 &v) { return v[0] + v[1]; } template DEVICE inline T sum(const TVector3 &v) { return v[0] + v[1] + v[2]; } template DEVICE inline T sum(const TVector4 &v) { return v[0] + v[1] + v[2] + v[3]; } template DEVICE void coordinate_system(const TVector3 &n, TVector3 &x, TVector3 &y) { if (n[2] < -1.f + 1e-6f) { x = TVector3{T(0), T(-1), T(0)}; y = TVector3{T(-1), T(0), T(0)}; } else { auto a = 1.f / (1.f + n[2]); auto b = -n[0] * n[1] * a; x = TVector3{1.f - square(n[0]) * a, b, -n[0]}; y = TVector3{b, 1.f - square(n[1]) * a, -n[1]}; } } template DEVICE void d_coordinate_system(const TVector3 &n, const TVector3 &d_x, const TVector3 &d_y, TVector3 &d_n) { if (n[2] < -1.f + 1e-6f) { //x = TVector3{T(0), T(-1), T(0)}; //y = TVector3{T(-1), T(0), T(0)}; // don't need to do anything } else { auto a = 1.f / (1.f + n[2]); // auto b = -n[0] * n[1] * a; // x = TVector3{1.f - square(n[0]) * a, b, -n[0]} d_n[0] -= 2.f * n[0] * d_x[0] * a; auto d_a = -square(n[0]) * d_x[0]; auto d_b = d_x[1]; d_n[0] -= d_x[2]; // y = TVector3{b, 1.f - square(n[1]) * a, -n[1]} d_b += d_y[0]; d_n[1] -= 2.f * d_y[1] * n[1] * a; d_a -= d_y[1] * square(n[1]); d_n[1] -= d_y[2]; // b = -n[0] * n[1] * a d_n[0] -= d_b * n[1] * a; d_n[1] -= d_b * n[0] * a; d_a -= d_b * n[0] * n[1]; // a = 1 / (1 + n[2]) d_n[2] -= d_a * a / (1 + n[2]); } } DEVICE inline bool isfinite(const Vector2 &v) { return isfinite(v.x) && isfinite(v.y); } DEVICE inline bool isfinite(const Vector3 &v) { return isfinite(v.x) && isfinite(v.y) && isfinite(v.z); } DEVICE inline bool isfinite(const Vector4 &v) { return isfinite(v.x) && isfinite(v.y) && isfinite(v.z) && isfinite(v.w); } DEVICE inline bool is_zero(const Vector3 &v) { return v.x == 0 && v.y == 0 && v.z == 0; } template inline std::ostream& operator<<(std::ostream &os, const TVector2 &v) { return os << "(" << v[0] << ", " << v[1] << ")"; } template inline std::ostream& operator<<(std::ostream &os, const TVector3 &v) { return os << "(" << v[0] << ", " << v[1] << ", " << v[2] << ")"; } template inline std::ostream& operator<<(std::ostream &os, const TVector4 &v) { return os << "(" << v[0] << ", " << v[1] << ", " << v[2] << ", " << v[3] << ")"; } DEVICE inline float det(const Vector2f &a, const Vector2f &b) { return a.x*b.y-b.x*a.y; } DEVICE inline Vector2f quadratic_closest_pt_approx(const Vector2f &b0, const Vector2f &b1, const Vector2f &b2, float *t_ = nullptr) { // From http://w3.impa.br/~diego/publications/NehHop08.pdf float a=det(b0,b2), b=2*det(b1,b0), d=2*det(b2,b1); float f=b*d-a*a; Vector2f d21=b2-b1, d10=b1-b0, d20=b2-b0; Vector2f gf=2*(b*d21+d*d10+a*d20); gf=Vector2f(gf.y,-gf.x); Vector2f pp=-f*gf/dot(gf,gf); Vector2f d0p=b0-pp; float ap=det(d0p,d20), bp=2*det(d10,d0p); float t=clamp((ap+bp)/(2*a+b+d),0.f,1.f); float tt = 1 - t; if (t_ != nullptr) { *t_ = t; } return (tt*tt)*b0 + (2*tt*t)*b1 + (t*t)*b2; } DEVICE inline Vector2f quadratic_closest_pt_approx(const Vector2f &b0, const Vector2f &b1, const Vector2f &b2, const Vector2f &pt, float *t = nullptr) { // Approximate closest point to a quadratic curve return quadratic_closest_pt_approx(b0 - pt, b1 - pt, b2 - pt, t) + pt; }