Commits (214)
......@@ -3,6 +3,8 @@ project(TypedGeometry)
option(TG_EXPORT_LITERALS "if true, spills tg::literals into the global namespace (i.e. 180_deg works out of the box)" ON)
option(TG_ENABLE_ASSERTIONS "if true, enables assertions (also in RelWithDebInfo)" ON)
option(TG_ENABLE_INTERNAL_ASSERTIONS "if true, enables internally used assertions (requires TG_ENABLE_ASSERTIONS)" ON)
option(TG_ENABLE_CONTRACTS "if true, enables contract assertions (requires TG_ENABLE_ASSERTIONS)" ON)
# ===============================================
# Create target
......@@ -15,18 +17,23 @@ file(GLOB_RECURSE SOURCES
source_group(TREE ${CMAKE_CURRENT_SOURCE_DIR} FILES ${SOURCES})
add_library(typed-geometry STATIC ${SOURCES})
set_property(TARGET typed-geometry PROPERTY POSITION_INDEPENDENT_CODE ON)
target_include_directories(typed-geometry PUBLIC "src")
if (CMAKE_CXX_STANDARD GREATER_EQUAL 17)
target_compile_definitions(typed-geometry PUBLIC TG_SUPPORT_CXX17)
endif()
if (TG_ENABLE_ASSERTIONS)
target_compile_definitions(typed-geometry PUBLIC $<$<CONFIG:DEBUG>:TG_ENABLE_ASSERTIONS>)
target_compile_definitions(typed-geometry PUBLIC $<$<CONFIG:RELWITHDEBINFO>:TG_ENABLE_ASSERTIONS>)
endif()
if (TG_ENABLE_INTERNAL_ASSERTIONS)
target_compile_definitions(typed-geometry PUBLIC TG_ENABLE_INTERNAL_ASSERTIONS)
endif()
if (TG_ENABLE_CONTRACTS)
target_compile_definitions(typed-geometry PUBLIC TG_ENABLE_CONTRACTS)
endif()
if (TG_EXPORT_LITERALS)
target_compile_definitions(typed-geometry PUBLIC TG_EXPORT_LITERALS)
endif()
......@@ -30,7 +30,17 @@ std::map<p, int> v_cnts; // std::less
std::unordered_map<p, int> v_cnts; // std::hash
```
Most functionality is implemented as free functions, overloaded by type and with consistent vocabulary:
Most functionality is implemented as free functions, overloaded by type and with consistent vocabulary.
### Object Types
Basically all `tg` provided types are _regular_, i.e. have value semantics like `int` or `vector`.
The following categories exist:
* _POD_ types like `vec` and most fixed-size objects
* dynamically sized non-_POD_ values like `polygon` (similar to `vector`)
* _transparent_ types like `vec` where `.x` is part of the interface
* _opaque_ types like `angle` and `quadric` where the representation is implementation detail
### Vectors
......
#include <typed-geometry/detail/assert.hh>
#include <typed-geometry/common/assert.hh>
#include <cstdio>
#include <cstdlib>
......@@ -30,7 +30,4 @@ void tg::detail::assertion_failed(assertion_info const& info)
default_assertion_handler(info);
}
void tg::set_assertion_handler(void (*handler)(detail::assertion_info const&))
{
s_current_handler = handler;
}
void tg::set_assertion_handler(void (*handler)(detail::assertion_info const&)) { s_current_handler = handler; }
......@@ -14,13 +14,25 @@
// compile flags
// TG_ENABLE_ASSERTIONS enables assertions
#if !defined(TG_ENABLE_ASSERTIONS)
#ifndef TG_ENABLE_ASSERTIONS
#define TG_ASSERT(condition) TG_UNUSED(bool((condition)))
#else
#define TG_ASSERT(condition) \
(TG_LIKELY((condition)) ? void(0) : ::tg::detail::assertion_failed({#condition, TG_PRETTY_FUNC, __FILE__, __LINE__})) // force ;
#endif
#ifndef TG_ENABLE_CONTRACTS
#define TG_CONTRACT(condition) TG_UNUSED(bool((condition)))
#else
#define TG_CONTRACT(condition) TG_ASSERT(condition && "contract violation")
#endif
#ifndef TG_ENABLE_INTERNAL_ASSERTIONS
#define TG_INTERNAL_ASSERT(condition) TG_UNUSED(bool((condition)))
#else
#define TG_INTERNAL_ASSERT(condition) TG_ASSERT(condition)
#endif
namespace tg
{
namespace detail
......
......@@ -2,17 +2,24 @@
#include <cmath>
#include "../types/angle.hh"
#include "errors.hh"
#include "macros.hh"
#include <typed-geometry/types/angle.hh>
#include <typed-geometry/detail/errors.hh>
#include <typed-geometry/detail/macros.hh>
namespace tg
{
template <class T>
constexpr angle<T> tau = angle<T>::from_radians(static_cast<T>(6.28318530717958647693));
constexpr angle_t<T> tau = angle_t<T>::from_radians(static_cast<T>(6.28318530717958647693));
template <class T>
constexpr angle_t<T> pi = angle_t<T>::from_radians(static_cast<T>(3.14159265358979323846));
template <class T>
constexpr T tau_scalar = static_cast<T>(6.28318530717958647693);
template <class T>
constexpr angle<T> pi = angle<T>::from_radians(static_cast<T>(3.14159265358979323846));
constexpr T pi_scalar = static_cast<T>(3.14159265358979323846);
template <class T>
constexpr T nan = NAN;
......
#pragma once
#include "../types/scalar.hh"
#include <typed-geometry/types/scalar.hh>
namespace tg
{
......@@ -31,11 +31,28 @@ struct limits<i32>
static constexpr i32 min() { return i32(-2147483647 - 1); }
static constexpr i32 max() { return i32(2147483647); }
};
#ifdef _MSC_VER
template <>
struct limits<i64>
struct limits<long>
{
static constexpr i64 min() { return i64(-9223372036854775807LL - 1); }
static constexpr i64 max() { return i64(9223372036854775807LL); }
static_assert(sizeof(long) == 4, "unsupported arch");
static constexpr long min() { return long(-2147483647 - 1); }
static constexpr long max() { return long(2147483647); }
};
#else
template <>
struct limits<long>
{
static_assert(sizeof(long) == 8, "unsupported arch");
static constexpr long min() { return long(-9223372036854775807LL - 1); }
static constexpr long max() { return long(9223372036854775807LL); }
};
#endif
template <>
struct limits<long long>
{
static constexpr long long min() { return i64(-9223372036854775807LL - 1); }
static constexpr long long max() { return i64(9223372036854775807LL); }
};
template <>
......@@ -56,11 +73,28 @@ struct limits<u32>
static constexpr u32 min() { return u32(0); }
static constexpr u32 max() { return u32(4294967295); }
};
#ifdef _MSC_VER
template <>
struct limits<unsigned long>
{
static_assert(sizeof(unsigned long) == 4, "unsupported arch");
static constexpr unsigned long min() { return u32(0); }
static constexpr unsigned long max() { return u32(4294967295); }
};
#else
template <>
struct limits<unsigned long>
{
static_assert(sizeof(unsigned long) == 8, "unsupported arch");
static constexpr unsigned long min() { return u64(0); }
static constexpr unsigned long max() { return u64(18446744073709551615uLL); }
};
#endif
template <>
struct limits<u64>
struct limits<unsigned long long>
{
static constexpr u64 min() { return u64(0); }
static constexpr u64 max() { return u64(18446744073709551615uLL); }
static constexpr unsigned long long min() { return u64(0); }
static constexpr unsigned long long max() { return u64(18446744073709551615uLL); }
};
template <>
......
#pragma once
#include "../types/scalar.hh"
#include "functions/minmax.hh"
#include <typed-geometry/types/scalar.hh>
#include <typed-geometry/functions/minmax.hh>
/**
* Provides random generators:
......@@ -38,7 +39,7 @@ public:
}
template <class Rng>
constexpr void seed(Rng& rd)
constexpr auto seed(Rng& rd) -> decltype(u64(rd()), void())
{
m_seed = u64(rd()) << 31 | u64(rd());
}
......@@ -80,7 +81,7 @@ public:
}
template <class Rng>
constexpr void seed(Rng& rd)
constexpr auto seed(Rng& rd) -> decltype(u64(rd()), void())
{
m_seed = u64(rd()) << 31 | u64(rd());
}
......@@ -123,7 +124,7 @@ public:
}
template <class Rng>
constexpr void seed(Rng& rd)
constexpr auto seed(Rng& rd) -> decltype(u64(rd()), void())
{
u64 s0 = u64(rd()) << 31 | u64(rd());
u64 s1 = u64(rd()) << 31 | u64(rd());
......
......@@ -2,11 +2,11 @@
#include <cmath>
#include "../../detail/scalar_traits.hh"
#include "../../types/angle.hh"
#include "../../types/scalar.hh"
#include "../constants.hh"
#include "../utility.hh"
#include <typed-geometry/common/constants.hh>
#include <typed-geometry/detail/scalar_traits.hh>
#include <typed-geometry/detail/utility.hh>
#include <typed-geometry/types/angle.hh>
#include <typed-geometry/types/scalar.hh>
// TODO:
// - proper f8, f16
......@@ -93,7 +93,7 @@ TG_NODISCARD inline f32 abs(f32 v) { return std::abs(v); }
TG_NODISCARD inline f64 abs(f64 v) { return std::abs(v); }
template <class T>
TG_NODISCARD angle<T> abs(angle<T> a)
TG_NODISCARD angle_t<T> abs(angle_t<T> a)
{
return radians(abs(a.radians()));
}
......@@ -116,23 +116,41 @@ TG_NODISCARD inline i64 iround(f64 v) { return v >= 0 ? i64(v + 0.5) : i64(v - 0
TG_NODISCARD inline f32 fract(f32 v) { return v - floor(v); }
TG_NODISCARD inline f64 fract(f64 v) { return v - floor(v); }
template <class T, class = enable_if<is_scalar<T>>>
TG_NODISCARD constexpr T min(T const& a, T const& b)
template <class A, class B>
TG_NODISCARD constexpr auto min(A&& a, B&& b) -> decltype(a < b ? a : b)
{
return a < b ? a : b;
}
template <class T, class = enable_if<is_scalar<T>>>
TG_NODISCARD constexpr T max(T const& a, T const& b)
template <class A, class B>
TG_NODISCARD constexpr auto max(A&& a, B&& b) -> decltype(a < b ? b : a)
{
return a < b ? b : a;
}
template <class T, class = enable_if<is_scalar<T>>>
TG_NODISCARD constexpr T clamp(T const& a, T const& min_value, T const& max_value)
template <class A, class B, class C>
TG_NODISCARD constexpr auto clamp(A const& a, B const& min_value, C const& max_value) -> decltype(min(max(a, min_value), max_value))
{
return min(max(a, min_value), max_value);
}
template <class T>
TG_NODISCARD constexpr T saturate(T const& a)
{
return clamp(a, T(0), T(1));
}
template <class T, class = enable_if<is_scalar<T>>>
TG_NODISCARD constexpr T sign(T const& v)
{
// TODO: optimize?
// if constexpr (!is_unsigned_integer<T>)
if (v < T(0))
return T(-1);
if (v > T(0))
return T(1);
return T(0);
}
// ==================================================================
// Powers
......@@ -141,26 +159,26 @@ TG_NODISCARD inline f32 pow(f32 b, i32 e) { return f32(std::pow(b, e)); }
TG_NODISCARD inline f64 pow(f64 b, f64 e) { return std::pow(b, e); }
TG_NODISCARD inline f64 pow(f64 b, i32 e) { return std::pow(b, e); }
template <class T, class = enable_if<has_multiplication<T>>>
TG_NODISCARD constexpr T pow2(T const& v)
template <class T>
TG_NODISCARD constexpr auto pow2(T const& v) -> decltype(v * v)
{
return v * v;
}
template <class T, class = enable_if<has_multiplication<T>>>
TG_NODISCARD constexpr T pow3(T const& v)
template <class T>
TG_NODISCARD constexpr auto pow3(T const& v) -> decltype(v * v * v)
{
return v * v * v;
}
template <class T, class = enable_if<has_multiplication<T>>>
TG_NODISCARD constexpr T pow4(T const& v)
template <class T>
TG_NODISCARD constexpr auto pow4(T const& v) -> decltype((v * v) * (v * v))
{
auto v2 = v * v;
auto const v2 = v * v;
return v2 * v2;
}
template <class T, class = enable_if<has_multiplication<T>>>
TG_NODISCARD constexpr T pow5(T const& v)
template <class T>
TG_NODISCARD constexpr auto pow5(T const& v) -> decltype((v * v) * (v * v) * v)
{
auto v2 = v * v;
auto const v2 = v * v;
return v2 * v2 * v;
}
......@@ -191,22 +209,26 @@ TG_NODISCARD inline f64 log10(f64 v) { return std::log10(v); }
// ==================================================================
// Trigonometry
TG_NODISCARD inline f32 sin(angle<f32> v) { return std::sin(v.radians()); }
TG_NODISCARD inline f64 sin(angle<f64> v) { return std::sin(v.radians()); }
TG_NODISCARD inline f32 cos(angle<f32> v) { return std::cos(v.radians()); }
TG_NODISCARD inline f64 cos(angle<f64> v) { return std::cos(v.radians()); }
TG_NODISCARD inline f32 tan(angle<f32> v) { return std::tan(v.radians()); }
TG_NODISCARD inline f64 tan(angle<f64> v) { return std::tan(v.radians()); }
TG_NODISCARD inline f32 sin(angle_t<f32> v) { return std::sin(v.radians()); }
TG_NODISCARD inline f64 sin(angle_t<f64> v) { return std::sin(v.radians()); }
TG_NODISCARD inline f32 cos(angle_t<f32> v) { return std::cos(v.radians()); }
TG_NODISCARD inline f64 cos(angle_t<f64> v) { return std::cos(v.radians()); }
TG_NODISCARD inline f32 tan(angle_t<f32> v) { return std::tan(v.radians()); }
TG_NODISCARD inline f64 tan(angle_t<f64> v) { return std::tan(v.radians()); }
// TODO: use SSE intrinsic to compute both directly
TG_NODISCARD inline pair<f32, f32> sin_cos(angle_t<f32> v) { return {sin(v), cos(v)}; }
TG_NODISCARD inline pair<f64, f64> sin_cos(angle_t<f64> v) { return {sin(v), cos(v)}; }
TG_NODISCARD inline angle<f32> asin(f32 v) { return radians(std::asin(v)); }
TG_NODISCARD inline angle<f64> asin(f64 v) { return radians(std::asin(v)); }
TG_NODISCARD inline angle<f32> acos(f32 v) { return radians(std::acos(v)); }
TG_NODISCARD inline angle<f64> acos(f64 v) { return radians(std::acos(v)); }
TG_NODISCARD inline angle<f32> atan(f32 v) { return radians(std::atan(v)); }
TG_NODISCARD inline angle<f64> atan(f64 v) { return radians(std::atan(v)); }
TG_NODISCARD inline angle_t<f32> asin(f32 v) { return radians(std::asin(v)); }
TG_NODISCARD inline angle_t<f64> asin(f64 v) { return radians(std::asin(v)); }
TG_NODISCARD inline angle_t<f32> acos(f32 v) { return radians(std::acos(v)); }
TG_NODISCARD inline angle_t<f64> acos(f64 v) { return radians(std::acos(v)); }
TG_NODISCARD inline angle_t<f32> atan(f32 v) { return radians(std::atan(v)); }
TG_NODISCARD inline angle_t<f64> atan(f64 v) { return radians(std::atan(v)); }
TG_NODISCARD inline angle<f32> atan2(f32 y, f32 x) { return radians(std::atan2(y, x)); }
TG_NODISCARD inline angle<f64> atan2(f64 y, f64 x) { return radians(std::atan2(y, x)); }
TG_NODISCARD inline angle_t<f32> atan2(f32 y, f32 x) { return radians(std::atan2(y, x)); }
TG_NODISCARD inline angle_t<f64> atan2(f64 y, f64 x) { return radians(std::atan2(y, x)); }
TG_NODISCARD inline f32 sinh(f32 v) { return std::sinh(v); }
TG_NODISCARD inline f64 sinh(f64 v) { return std::sinh(v); }
......@@ -222,4 +244,37 @@ TG_NODISCARD inline f64 acosh(f64 v) { return std::acosh(v); }
TG_NODISCARD inline f32 atanh(f32 v) { return std::atanh(v); }
TG_NODISCARD inline f64 atanh(f64 v) { return std::atanh(v); }
// ==================================================================
// other GLSL
TG_NODISCARD constexpr f32 smoothstep(f32 edge0, f32 edge1, f32 x)
{
auto t = clamp((x - edge0) / (edge1 - edge0), f32(0), f32(1));
return t * t * (f32(3) - f32(2) * t);
}
TG_NODISCARD constexpr f64 smoothstep(f64 edge0, f64 edge1, f64 x)
{
auto t = clamp((x - edge0) / (edge1 - edge0), f64(0), f64(1));
return t * t * (f64(3) - f64(2) * t);
}
// ==================================================================
// other Math
// greatest common divisor
// TODO: how does it work for negative numbers?
template <class T, class = enable_if<is_integer<T>>>
T gcd(T a, T b)
{
return b ? gcd(b, a % b) : a;
}
// least common multiple
// CAREFUL: a * b is an intermediate and might overflow
template <class T, class = enable_if<is_integer<T>>>
T lcm(T a, T b)
{
return a * b / gcd(a, b);
}
} // namespace tg
#pragma once
#include "utility.hh"
#include <typed-geometry/types/fwd.hh>
namespace tg
{
namespace detail
{
template <class Obj>
struct comp_size
{
static constexpr int value = -1;
};
template <int N, class T>
struct comp_size<T[N]>
{
static constexpr int value = N;
};
template <int D, class T>
struct comp_size<vec<D, T>>
{
static constexpr int value = D;
};
template <int D, class T>
struct comp_size<dir<D, T>>
{
static constexpr int value = D;
};
template <int D, class T>
struct comp_size<pos<D, T>>
{
static constexpr int value = D;
};
template <int D, class T>
struct comp_size<size<D, T>>
{
static constexpr int value = D;
};
template <int D, class T>
struct comp_size<color<D, T>>
{
static constexpr int value = D;
};
template <int D, class T>
struct comp_size<comp<D, T>>
{
static constexpr int value = D;
};
template <class Obj, class ScalarT>
auto test_comp_convertible(Obj* obj) -> decltype(ScalarT((*obj)[0]), true_type{});
template <class Obj, class ScalarT>
auto test_comp_convertible(...) -> false_type;
template <class Obj, class = enable_if<comp_size<Obj>::value != -1>>
constexpr int impl_get_dynamic_comp_size(Obj const&, priority_tag<2>)
{
return comp_size<Obj>::value;
}
template <class Obj>
constexpr auto impl_get_dynamic_comp_size(Obj const& v, priority_tag<1>) -> decltype(int(v.size()))
{
return int(v.size());
}
template <class Obj>
constexpr auto impl_get_dynamic_comp_size(Obj const& v, priority_tag<0>) -> decltype(int(v.length()))
{
return int(v.length());
}
template <class Obj>
constexpr int get_dynamic_comp_size(Obj const& v)
{
return impl_get_dynamic_comp_size(v, priority_tag<2>{});
}
template <class Obj, class ScalarT>
constexpr ScalarT comp_get(Obj const& v, unsigned char idx, int size, ScalarT fill)
{
return idx < size ? ScalarT(v[idx]) : fill;
}
}
template <class Obj, class ScalarT>
constexpr bool is_comp_convertible = decltype(detail::test_comp_convertible<Obj, ScalarT>(nullptr))::value;
template <class Obj>
constexpr bool is_comp_dynamic_size = detail::comp_size<Obj>::value < 0;
template <class Obj, int D, class ScalarT>
constexpr bool is_comp_like = is_comp_convertible<Obj, ScalarT> && (is_comp_dynamic_size<Obj> || detail::comp_size<Obj>::value >= D);
}
#pragma once
#include "../types/vec.hh"
#include <typed-geometry/types/vec.hh>
namespace tg
{
......
#pragma once
#include <typed-geometry/common/assert.hh>
#include <typed-geometry/types/dir.hh>
#include <typed-geometry/types/pos.hh>
#include <typed-geometry/types/size.hh>
#include <typed-geometry/types/vec.hh>
#include <typed-geometry/types/objects/box.hh>
#include <typed-geometry/types/objects/halfspace.hh>
#include <typed-geometry/types/objects/hyperplane.hh>
#include <typed-geometry/types/objects/line.hh>
#include <typed-geometry/detail/operators/ops_pos.hh>
#include <typed-geometry/functions/dot.hh>
// Header for all constructors that depend on functions
namespace tg
{
template <class ScalarT>
constexpr dir<1, ScalarT>::dir(ScalarT x) : x(x)
{
TG_CONTRACT(dot(*this, *this) <= ScalarT(1.001) && "dirs must be normalized");
}
template <class ScalarT>
constexpr dir<2, ScalarT>::dir(ScalarT x, ScalarT y) : x(x), y(y)
{
TG_CONTRACT(dot(*this, *this) <= ScalarT(1.001) && "dirs must be normalized");
}
template <class ScalarT>
constexpr dir<3, ScalarT>::dir(ScalarT x, ScalarT y, ScalarT z) : x(x), y(y), z(z)
{
TG_CONTRACT(dot(*this, *this) <= ScalarT(1.001) && "dirs must be normalized");
}
template <class ScalarT>
constexpr dir<4, ScalarT>::dir(ScalarT x, ScalarT y, ScalarT z, ScalarT w) : x(x), y(y), z(z), w(w)
{
TG_CONTRACT(dot(*this, *this) <= ScalarT(1.001) && "dirs must be normalized");
}
template <class ScalarT>
constexpr dir<1, ScalarT>::dir(vec<1, ScalarT> const& v) : x(v.x)
{
TG_CONTRACT(dot(*this, *this) <= ScalarT(1.001) && "dirs must be normalized");
}
template <class ScalarT>
constexpr dir<2, ScalarT>::dir(vec<2, ScalarT> const& v) : x(v.x), y(v.y)
{
TG_CONTRACT(dot(*this, *this) <= ScalarT(1.001) && "dirs must be normalized");
}
template <class ScalarT>
constexpr dir<3, ScalarT>::dir(vec<3, ScalarT> const& v) : x(v.x), y(v.y), z(v.z)
{
TG_CONTRACT(dot(*this, *this) <= ScalarT(1.001) && "dirs must be normalized");
}
template <class ScalarT>
constexpr dir<4, ScalarT>::dir(vec<4, ScalarT> const& v) : x(v.x), y(v.y), z(v.z), w(v.w)
{
TG_CONTRACT(dot(*this, *this) <= ScalarT(1.001) && "dirs must be normalized");
}
template <int D, class ScalarT>
constexpr box<D, ScalarT>::box(aabb<D, ScalarT> const& b)
{
static_assert(is_floating_point<ScalarT>, "cannot be guaranteed for integers");
auto half_e = (b.max - b.min) / ScalarT(2);
center = b.min + half_e;
for (auto i = 0; i < D; ++i)
{
auto v = vec_t();
v[i] = ScalarT(1);
half_extents[i] = v * half_e[i];
}
}
template <int D, class ScalarT>
constexpr hyperplane<D, ScalarT>::hyperplane(dir_t n, pos_t p) : normal(n), dis(dot(vec<D, ScalarT>(p), n))
{
}
template <int D, class ScalarT>
constexpr halfspace<D, ScalarT>::halfspace(dir_t n, pos_t p) : normal(n), dis(dot(vec<D, ScalarT>(p), n))
{
}
template <int D, class ScalarT>
constexpr line<D, ScalarT> line<D, ScalarT>::from_points(pos_t a, pos_t b)
{
return line(a, normalize(b - a));
}
}
#pragma once
#include <typed-geometry/types/objects/hyperplane.hh>
#include <typed-geometry/detail/functions/dot.hh>
// Header for all constructors that depend on functions
namespace tg
{
template <int D, class ScalarT>
constexpr hyperplane<D, ScalarT>::hyperplane(vec_t n, pos_t p) : n(n), d(dot(p, n))
{
}
}
#pragma once
#include "functions/aabb.hh"
#include "functions/area.hh"
#include "functions/centroid.hh"
#include "functions/closest_points.hh"
#include "functions/contains.hh"
#include "functions/coordinates.hh"
#include "functions/cross.hh"
#include "functions/data_ptr.hh"
#include "functions/determinant.hh"
#include "functions/diag.hh"
#include "functions/direction.hh"
#include "functions/distance.hh"
#include "functions/dot.hh"
#include "functions/interpolate.hh"
#include "functions/inverse.hh"
#include "functions/length.hh"
#include "functions/math.hh"
#include "functions/minmax.hh"
#include "functions/mix.hh"
#include "functions/normal.hh"
#include "functions/normalize.hh"
#include "functions/outer_product.hh"
#include "functions/project.hh"
#include "functions/rasterize.hh"
#include "functions/rotation.hh"
#include "functions/scaling.hh"
#include "functions/submatrix.hh"
#include "functions/subvector.hh"
#include "functions/tangent.hh"
#include "functions/translation.hh"
#include "functions/uniform.hh"
#include "functions/volume.hh"
#include "functions/intersection.hh"
#include <typed-geometry/functions/aabb.hh>
#include <typed-geometry/functions/angle.hh>
#include <typed-geometry/functions/area.hh>
#include <typed-geometry/functions/centroid.hh>
#include <typed-geometry/functions/closest_points.hh>
#include <typed-geometry/functions/contains.hh>
#include <typed-geometry/functions/coordinates.hh>
#include <typed-geometry/functions/cross.hh>
#include <typed-geometry/functions/data_ptr.hh>
#include <typed-geometry/functions/determinant.hh>
#include <typed-geometry/functions/diag.hh>
#include <typed-geometry/functions/direction.hh>
#include <typed-geometry/functions/distance.hh>
#include <typed-geometry/functions/dot.hh>
#include <typed-geometry/functions/gaussian.hh>
#include <typed-geometry/functions/interpolate.hh>
#include <typed-geometry/functions/intersection.hh>
#include <typed-geometry/functions/inverse.hh>
#include <typed-geometry/functions/length.hh>
#include <typed-geometry/functions/look_at.hh>
#include <typed-geometry/functions/math.hh>
#include <typed-geometry/functions/minmax.hh>
#include <typed-geometry/functions/mix.hh>
#include <typed-geometry/functions/norm.hh>
#include <typed-geometry/functions/normal.hh>
#include <typed-geometry/functions/normalize.hh>
#include <typed-geometry/functions/outer_product.hh>
#include <typed-geometry/functions/perimeter.hh>
#include <typed-geometry/functions/perpendicular.hh>
#include <typed-geometry/functions/perspective.hh>
#include <typed-geometry/functions/project.hh>
#include <typed-geometry/functions/random_choice.hh>
#include <typed-geometry/functions/rasterize.hh>
#include <typed-geometry/functions/reflect.hh>
#include <typed-geometry/functions/refract.hh>
#include <typed-geometry/functions/rotation.hh>
#include <typed-geometry/functions/scaling.hh>
#include <typed-geometry/functions/size.hh>
#include <typed-geometry/functions/smoothstep.hh>
#include <typed-geometry/functions/statistics.hh>
#include <typed-geometry/functions/submatrix.hh>
#include <typed-geometry/functions/subvector.hh>
#include <typed-geometry/functions/tangent.hh>
#include <typed-geometry/functions/translation.hh>
#include <typed-geometry/functions/uniform.hh>
#include <typed-geometry/functions/volume.hh>
#pragma once
#include "../../types/objects/box.hh"
#include "../../types/objects/triangle.hh"
namespace tg
{
template <int D, class ScalarT>
TG_NODISCARD constexpr box<D, ScalarT> aabb(pos<D, ScalarT> const& v)
{
return {v, v};
}
template <int D, class ScalarT>
TG_NODISCARD constexpr box<D, ScalarT> aabb(box<D, ScalarT> const& b)
{
return b;
}
template <int D, class ScalarT>
TG_NODISCARD constexpr box<D, ScalarT> aabb(triangle<D, ScalarT> const& t)
{
return aabb(t.v0, t.v1, t.v2);
}
template <class PrimA, class PrimB, class... PrimsT>
TG_NODISCARD constexpr auto aabb(PrimA const& pa, PrimB const& pb, PrimsT const&... prims) -> decltype(aabb(pa))
{
auto ba = aabb(pa);
auto bb = aabb(pb);
static_assert(is_same<decltype(ba), decltype(bb)>, "all arguments must have the same aabb box type");
auto b = decltype(ba)(min(ba.min, bb.min), max(ba.max, bb.max));
return aabb(b, prims...);
}
} // namespace tg
#pragma once
#include "../../types/objects/box.hh"
#include "../../types/objects/triangle.hh"
#include "../../types/pos.hh"
#include "../../types/size.hh"
#include "../../types/vec.hh"
#include "../operators/ops_vec.hh"
#include "../scalar_traits.hh"
#include "../scalars/scalar_math.hh"
namespace tg
{
template <class ScalarT>
TG_NODISCARD constexpr squared_result<ScalarT> area(size<2, ScalarT> const& s)
{
return s.width * s.height;
}
template <class ScalarT>
TG_NODISCARD constexpr squared_result<ScalarT> area(box<2, ScalarT> const& b)
{
return area(size<2, ScalarT>(b.max - b.min));
}
template <class ScalarT>
TG_NODISCARD constexpr fractional_result<ScalarT> signed_area(triangle<2, ScalarT> const& b)
{
return cross(b.v1 - b.v0, b.v2 - b.v0) * fractional_result<ScalarT>(0.5);
}
template <class ScalarT>
TG_NODISCARD constexpr fractional_result<ScalarT> area(triangle<2, ScalarT> const& b)
{
return abs(signed_area(b));
}
template <class ScalarT>
TG_NODISCARD constexpr fractional_result<ScalarT> area(triangle<3, ScalarT> const& b)
{
return length(cross(b.v1 - b.v0, b.v2 - b.v0)) * fractional_result<ScalarT>(0.5);
}
} // namespace tg
#pragma once
#include "../../types/vec.hh"
#include "../scalar_traits.hh"
namespace tg
{
template <class ScalarT>
TG_NODISCARD constexpr vec<3, squared_result<ScalarT>> cross(vec<3, ScalarT> const& a, vec<3, ScalarT> const& b)
{
vec<3, ScalarT> r;
r.x = a.y * squared_result<ScalarT>(b.z) - a.z * squared_result<ScalarT>(b.y);
r.y = a.z * squared_result<ScalarT>(b.x) - a.x * squared_result<ScalarT>(b.z);
r.z = a.x * squared_result<ScalarT>(b.y) - a.y * squared_result<ScalarT>(b.x);
return r;
}
template <class ScalarT>
TG_NODISCARD constexpr squared_result<ScalarT> cross(vec<2, ScalarT> const& a, vec<2, ScalarT> const& b)
{
return a.x * squared_result<ScalarT>(b.y) - a.y * squared_result<ScalarT>(b.x);
}
} // namespace tg
#pragma once
#include "closest_points.hh"
#include "normalize.hh"
namespace tg
{
// Default implementation:
template <class A, class B>
TG_NODISCARD constexpr auto direction(A const& a, B const& b) -> decltype(normalize_safe(closest_points(a, b).second - closest_points(a, b).first))
{
auto cp = closest_points(a, b);
return normalize_safe(cp.second - cp.first);
}
} // namespace tg
#pragma once
#include "../../types/objects/line.hh"
#include "../../types/objects/plane.hh"
#include "../../types/objects/segment.hh"
#include "../../types/pos.hh"
#include "../../types/vec.hh"
#include "../operators/ops_pos.hh"
#include "../operators/ops_vec.hh"
#include "../scalars/scalar_math.hh"
#include "../special_values.hh"
#include "../tg_traits.hh"
#include "closest_points.hh"
namespace tg
{
// Base case for distance2 of point/point
template <int D, class ScalarA, class ScalarB>
TG_NODISCARD constexpr auto distance2(pos<D, ScalarA> const& a, pos<D, ScalarB> const& b) -> decltype(length2(a - b))
{
return length2(a - b);
}
// Default implementation of distance as sqrt(distance2)
template <class A, class B>
TG_NODISCARD constexpr auto distance(A const& a, B const& b) -> decltype(sqrt(distance2(a, b)))
{
return sqrt(distance2(a, b));
}
// Default implementation of distance2 as distance2(ca, cb) for closest points ca and cb
template <class A, class B>
TG_NODISCARD constexpr auto distance2(A const& a, B const& b) -> decltype(length2(closest_points(a, b).first - closest_points(a, b).second))
{
auto cp = closest_points(a, b);
return length2(cp.first - cp.second);
}
// Convience for distance to (0,0,0)
template <class Obj>
TG_NODISCARD constexpr auto distance_to_origin(Obj const& o) -> decltype(distance(o, pos_type_for<Obj>::zero))
{
return distance(o, pos_type_for<Obj>::zero);
}
template <class Obj>
TG_NODISCARD constexpr auto distance2_to_origin(Obj const& o) -> decltype(distance(o, pos_type_for<Obj>::zero))
{
return distance2(o, pos_type_for<Obj>::zero);
}
// =========== Object Implementations ===========
// signed distance is positive if p lies above pl, 0 if it lies on the plane and negative if below pl
template <class ScalarT>
TG_NODISCARD constexpr fractional_result<ScalarT> signed_distance(pos<3, ScalarT> const& p, plane const& pl)
{
return dot(p - zero<pos<3, ScalarT>>(), pl.n) - pl.d;
}
template <class ScalarT>
TG_NODISCARD constexpr fractional_result<ScalarT> distance(pos<3, ScalarT> const& p, plane const& pl)
{
return abs(signed_distance(p, pl));
}
} // namespace tg
#pragma once
#include "../../types/vec.hh"
#include "../scalar_traits.hh"
namespace tg
{
template <class ScalarT>
TG_NODISCARD constexpr squared_result<ScalarT> dot(vec<1, ScalarT> const& a, vec<1, ScalarT> const& b)
{
return a.x * squared_result<ScalarT>(b.x);
}
template <class ScalarT>
TG_NODISCARD constexpr squared_result<ScalarT> dot(vec<2, ScalarT> const& a, vec<2, ScalarT> const& b)
{
return a.x * squared_result<ScalarT>(b.x) + //
a.y * squared_result<ScalarT>(b.y);
}
template <class ScalarT>
TG_NODISCARD constexpr squared_result<ScalarT> dot(vec<3, ScalarT> const& a, vec<3, ScalarT> const& b)
{
return a.x * squared_result<ScalarT>(b.x) + //
a.y * squared_result<ScalarT>(b.y) + //
a.z * squared_result<ScalarT>(b.z);
}
template <class ScalarT>
TG_NODISCARD constexpr squared_result<ScalarT> dot(vec<4, ScalarT> const& a, vec<4, ScalarT> const& b)
{
return a.x * squared_result<ScalarT>(b.x) + //
a.y * squared_result<ScalarT>(b.y) + //
a.z * squared_result<ScalarT>(b.z) + //
a.w * squared_result<ScalarT>(b.w);
}
} // namespace tg
#pragma once
#include "../../types/objects/circle.hh"
#include "../../types/objects/hyperplane.hh"
#include "../../types/objects/ray.hh"
#include "../../types/objects/sphere.hh"
#include "../../types/objects/triangle.hh"
#include "contains.hh"
#include "dot.hh"
#include "normal.hh"
// family of intersection functions:
// intersects(a, b) -> bool iff any point lies in a and in b
// intersection(a, b) -> ??? returns an object describing the intersection
// related function:
// closest_hit(ray, b) -> optional<pos>
namespace tg
{
template <class A, class B>
struct intersection_result;
template <int D, class ScalarT>
struct intersection_result<ray<3, ScalarT>, hyperplane<D, ScalarT>>
{
bool empty;
tg::pos<D, ScalarT> pos;
};
template <class ScalarT>
struct intersection_result<ray<3, ScalarT>, triangle<3, ScalarT>>
{
bool empty;
tg::pos<3, ScalarT> pos;
};
template <class ScalarT>
struct intersection_result<sphere<3, ScalarT>, sphere<3, ScalarT>>
{
bool empty;
tg::circle<3, ScalarT> circle;
};
// returns whether two objects intersect
template <class A, class B>
TG_NODISCARD constexpr auto intersects(A const& a, B const& b) -> decltype(!intersection(a, b).empty)
{
return !intersection(a, b).empty;
}
// returns intersection point of ray and hyperplane
template <int D, class ScalarT>
TG_NODISCARD constexpr auto intersection(ray<D, ScalarT> const& r, hyperplane<D, ScalarT> const& p)
-> intersection_result<ray<D, ScalarT>, hyperplane<D, ScalarT>>
{
// if plane normal and raydirection are parallel there is no intersection
auto dotND = dot(p.n, r.dir);
if (dotND == 0)
return {true, {}};
auto t = -(dot(p.n, vec<D, ScalarT>(r.pos)) + p.d) / dotND;
// check whether plane lies behind ray
if (t < 0)
return {true, {}};
auto result = r.pos + r.dir * t;
// non-empty intersection
return {false, result};
}
// returns intersection point of ray and triangle
template <class ScalarT>
TG_NODISCARD constexpr auto intersection(ray<3, ScalarT> const& r, triangle<3, ScalarT> const& t)
-> intersection_result<tg::ray<3, ScalarT>, tg::triangle<3, ScalarT>>
{
auto p = hyperplane<3, ScalarT>(normal(t), t.v0);
auto result = intersection(r, p);
// check whether potential intersection point indeed lies on the triangle
if (!contains(t, result.pos))
return {true, {}};
// non-empty intersection
return result;
}
// returns intersection circle of sphere and sphere (normal points from a to b)
template <class ScalarT>
TG_NODISCARD constexpr auto intersection(sphere<3, ScalarT> const& a, sphere<3, ScalarT> const& b)
-> intersection_result<sphere<3, ScalarT>, sphere<3, ScalarT>>
{
auto d2 = distance2(a.center, b.center);
auto d = tg::sqrt(d2);
// no intersection
if (d > a.radius + b.radius)
return {true, {}};
// radius and centers of larger sphere (ls) and smaller sphere (ss)
auto lsr = a.radius;
auto ssr = b.radius;
auto lsc = a.center;
auto ssc = b.center;
if (b.radius > a.radius)
{
// TODO: tg::swap?
lsr = b.radius;
ssr = a.radius;
lsc = b.center;
ssc = a.center;
}
if (d + ssr < lsr)
{
// Smaller sphere inside larger one and not touching it
return {true, {}};
}
// squared radii of a and b
auto ar2 = a.radius * a.radius;
auto br2 = b.radius * b.radius;
auto t = ScalarT(0.5) + (ar2 - br2) / (ScalarT(2) * d2);
// position and radius of intersection circle
auto ipos = a.center + t * (b.center - a.center);
auto irad = sqrt(ar2 - t * t * d2);
// non-empty intersection (circle)
return {false, {ipos, irad, (b.center - a.center) / d}};
}
} // namespace tg