Commit 7541df44 authored by Philip Trettner's avatar Philip Trettner
Browse files

WIP: introspect

parent 7f98aa5f
......@@ -55,6 +55,8 @@
#define TG_FORCE_SEMICOLON static_assert(true)
#define TG_IMPL_STRINGIFY(expr) #expr
#define TG_STRINGIFY(expr) TG_IMPL_STRINGIFY(expr)
// =========
// operations and classes
......@@ -493,6 +495,20 @@
template <int D, class T> \
type(dir<D, T> const&)->type<D, T> // enforce ;
#define TG_IMPL_COMP_INTROSPECT(type) \
template <class I, int D, class ScalarT> \
constexpr void introspect(I&& i, type<D, ScalarT>& v) \
{ \
i(v.TG_IMPL_MEMBER(type, 0), TG_STRINGIFY(TG_IMPL_MEMBER(type, 0))); \
if constexpr (D >= 2) \
i(v.TG_IMPL_MEMBER(type, 1), TG_STRINGIFY(TG_IMPL_MEMBER(type, 1))); \
if constexpr (D >= 3) \
i(v.TG_IMPL_MEMBER(type, 2), TG_STRINGIFY(TG_IMPL_MEMBER(type, 2))); \
if constexpr (D >= 4) \
i(v.TG_IMPL_MEMBER(type, 3), TG_STRINGIFY(TG_IMPL_MEMBER(type, 3))); \
} \
TG_FORCE_SEMICOLON
#define TG_IMPL_DEFINE_TRAIT(trait, result_type, default_val) \
template <class T> \
......
......@@ -298,5 +298,28 @@ using size_t_for = decltype(helper_size_t<N, Alignment>());
/// Bug report: https://developercommunity.visualstudio.com/content/problem/800899/false-positive-for-c2975-on-alias-template-fixed-w.html
template <class T, size_t N>
using compact_size_t_typed = size_t_for<N, alignof(T)>;
// adapted from https://stackoverflow.com/questions/23999573/convert-a-number-to-a-string-literal-with-constexpr
template <unsigned... digits>
struct digits_to_string_literal
{
static const char value[];
};
template <unsigned... digits>
constexpr char digits_to_string_literal<digits...>::value[] = {('0' + digits)..., 0};
template <unsigned rem, unsigned... digits>
struct number_to_string_literal_t : number_to_string_literal_t<rem / 10, rem % 10, digits...>
{
};
template <unsigned... digits>
struct number_to_string_literal_t<0, digits...> : digits_to_string_literal<digits...>
{
};
template <unsigned num>
inline constexpr char const* number_to_string_literal = number_to_string_literal_t<num>::value;
}
} // namespace tg
......@@ -8,6 +8,7 @@
#include <typed-geometry/functions/basic/constants.hh>
#include <typed-geometry/functions/basic/data_ptr.hh>
#include <typed-geometry/functions/basic/hash.hh>
#include <typed-geometry/functions/basic/limits.hh>
#include <typed-geometry/functions/basic/minmax.hh>
#include <typed-geometry/functions/basic/mix.hh>
......
#pragma once
#include <typed-geometry/tg-lean.hh>
namespace tg
{
namespace detail
{
struct hash_inspector
{
size_t hash = 0x987654321;
template <class T, class... Args>
constexpr void operator()(T const& v, Args&&...)
{
add(v);
}
private:
constexpr void hash_combine(size_t v) { hash = hash * 6364136223846793005ULL + v + 0xda3e39cb94b95bdbULL; }
constexpr void add(bool v) { hash_combine(size_t(v)); }
constexpr void add(i8 v) { hash_combine(size_t(v)); }
constexpr void add(i16 v) { hash_combine(size_t(v)); }
constexpr void add(i32 v) { hash_combine(size_t(v)); }
constexpr void add(i64 v) { hash_combine(size_t(v)); }
constexpr void add(u8 v) { hash_combine(size_t(v)); }
constexpr void add(u16 v) { hash_combine(size_t(v)); }
constexpr void add(u32 v) { hash_combine(size_t(v)); }
constexpr void add(u64 v) { hash_combine(size_t(v)); }
constexpr void add(f32 v) { hash_combine(v == 0 ? 0 : bit_cast<u32>(v)); }
constexpr void add(f64 v) { hash_combine(v == 0 ? 0 : bit_cast<u64>(v)); }
template <class T>
constexpr void add(T const& v)
{
introspect(*this, const_cast<T&>(v)); // v will not be changed
}
};
}
// universal hasher for tg types
struct hash
{
template <class T>
constexpr size_t operator()(T const& v) const noexcept
{
detail::hash_inspector hi;
hi(v);
return hi.hash;
}
};
template <class T>
constexpr size_t make_hash(T const& v) noexcept
{
return hash{}(v);
}
}
......@@ -29,26 +29,26 @@ template <class ScalarT>
return s.width * s.height;
}
template <class ScalarT>
[[nodiscard]] constexpr ScalarT area(aabb<2, ScalarT> const& b)
template <class ScalarT, class TraitsT>
[[nodiscard]] constexpr ScalarT area(aabb<2, ScalarT, TraitsT> const& b)
{
return area(size<2, ScalarT>(b.max - b.min));
}
template <class ScalarT>
[[nodiscard]] constexpr ScalarT area(aabb<3, ScalarT> const& b)
template <class ScalarT, class TraitsT>
[[nodiscard]] constexpr ScalarT area(aabb<3, ScalarT, TraitsT> const& b)
{
auto s = size<3, ScalarT>(b.max - b.min);
return 2 * (s.width * s.height + s.width * s.depth + s.height * s.depth);
}
template <class ScalarT>
[[nodiscard]] constexpr ScalarT area(box<2, ScalarT> const& b)
template <class ScalarT, int D, class TraitsT>
[[nodiscard]] constexpr ScalarT area(box<2, ScalarT, D, TraitsT> const& b)
{
return 4 * sqrt(length_sqr(b.half_extents[0]) * length_sqr(b.half_extents[1]));
}
template <class ScalarT>
[[nodiscard]] constexpr ScalarT area(box<3, ScalarT> const& b)
template <class ScalarT, class TraitsT>
[[nodiscard]] constexpr ScalarT area(box<3, ScalarT, 3, TraitsT> const& b)
{
auto w = length(b.half_extents[0]);
auto h = length(b.half_extents[1]);
......@@ -74,14 +74,14 @@ template <class ScalarT>
return length(cross(b.pos1 - b.pos0, b.pos2 - b.pos0)) * fractional_result<ScalarT>(0.5);
}
template <class ScalarT>
[[nodiscard]] constexpr fractional_result<ScalarT> area(sphere<2, ScalarT> const& b)
template <class ScalarT, int D, class TraitsT>
[[nodiscard]] constexpr fractional_result<ScalarT> area(sphere<2, ScalarT, D, TraitsT> const& b)
{
return tg::pi_scalar<fractional_result<ScalarT>> * tg::pow2(b.radius);
}
template <class ScalarT>
[[nodiscard]] constexpr fractional_result<ScalarT> area(sphere<3, ScalarT> const& b)
template <class ScalarT, class TraitsT>
[[nodiscard]] constexpr fractional_result<ScalarT> area(sphere<3, ScalarT, 3, TraitsT> const& b)
{
return (4 * tg::pi_scalar<fractional_result<ScalarT>>)*tg::pow2(b.radius);
}
......
......@@ -38,13 +38,13 @@ template <int D, class ScalarT>
{
return normalize(s.pos1 - s.pos0);
}
template <int D, class ScalarT>
[[nodiscard]] constexpr dir<D, ScalarT> direction(cylinder<D, ScalarT> const& c)
template <int D, class ScalarT, class TraitsT>
[[nodiscard]] constexpr dir<D, ScalarT> direction(cylinder<D, ScalarT, TraitsT> const& c)
{
return direction(c.axis);
}
template <int D, class ScalarT>
[[nodiscard]] constexpr dir<D, ScalarT> direction(capsule<D, ScalarT> const& c)
template <int D, class ScalarT, class TraitsT>
[[nodiscard]] constexpr dir<D, ScalarT> direction(capsule<D, ScalarT, TraitsT> const& c)
{
return direction(c.axis);
}
......
......@@ -253,7 +253,7 @@ template <int D, class ScalarT>
// ray - tube
template <class ScalarT>
[[nodiscard]] constexpr ray_hits<2, ScalarT> intersection_parameter_no_caps(ray<3, ScalarT> const& r, cylinder<3, ScalarT> const& c)
[[nodiscard]] constexpr ray_hits<2, ScalarT> intersection_parameter(ray<3, ScalarT> const& r, cylinder_boundary_no_caps<3, ScalarT> const& c)
{
auto cdir = direction(c);
auto cosA = dot(cdir, r.dir);
......@@ -364,7 +364,7 @@ template <class ScalarT>
[[nodiscard]] constexpr optional<ScalarT> closest_intersection_parameter(ray<3, ScalarT> const& r, cylinder<3, ScalarT> const& c)
{
auto const dir = direction(c);
auto const t_cyl = closest_intersection_parameter_no_caps(r, cylinder<3, ScalarT>(c.axis, c.radius));
auto const t_cyl = closest_intersection_parameter(r, cylinder_boundary_no_caps<3, ScalarT>(c.axis, c.radius));
auto const t_cap0 = intersection_parameter(r, sphere<2, ScalarT, 3>(c.axis.pos0, c.radius, dir));
auto const t_cap1 = intersection_parameter(r, sphere<2, ScalarT, 3>(c.axis.pos1, c.radius, dir));
......@@ -441,7 +441,7 @@ template <class ScalarT>
// returns intersection points of two circles in 2D
// for now does not work if circles are identical (result would be a circle2 again)
template <class ScalarT>
[[nodiscard]] constexpr optional<array<pos<2, ScalarT>, 2>> intersection(sphere_boundary<2, ScalarT> const& a, sphere_boundary<2, ScalarT> const& b)
[[nodiscard]] constexpr optional<pair<pos<2, ScalarT>, pos<2, ScalarT>>> intersection(sphere_boundary<2, ScalarT> const& a, sphere_boundary<2, ScalarT> const& b)
{
if (a.center == b.center && a.radius == b.radius)
return {}; // degenerate case
......@@ -474,7 +474,7 @@ template <class ScalarT>
auto p_above = p_between + h_by_d * a_to_b_swap;
auto p_below = p_between - h_by_d * a_to_b_swap;
return array<pos<2, ScalarT>, 2>{p_above, p_below};
return pair{p_above, p_below};
}
......
......@@ -155,7 +155,7 @@ template <int D, class ScalarT>
}
template <int D, class ScalarT>
[[nodiscard]] constexpr pos<D, ScalarT> project_to_boundary(pos<D, ScalarT> const& p, sphere<D, ScalarT> const& sp)
[[nodiscard]] constexpr pos<D, ScalarT> project(pos<D, ScalarT> const& p, sphere_boundary<D, ScalarT> const& sp)
{
auto dir_to_p = tg::normalize_safe(p - sp.center);
if (is_zero_vector(dir_to_p))
......@@ -179,7 +179,7 @@ template <class ScalarT>
}
template <class ScalarT>
[[nodiscard]] constexpr pos<3, ScalarT> project_to_boundary(pos<3, ScalarT> const& p, sphere<2, ScalarT, 3> const& c)
[[nodiscard]] constexpr pos<3, ScalarT> project(pos<3, ScalarT> const& p, sphere_boundary<2, ScalarT, 3> const& c)
{
auto hp = project(p, plane<3, ScalarT>(c.normal, c.center));
......@@ -209,7 +209,7 @@ template <class ScalarT>
}
template <class ScalarT>
[[nodiscard]] constexpr pos<3, ScalarT> project_to_boundary(pos<3, ScalarT> const& p, hemisphere<3, ScalarT> const& h) // boundary, including caps
[[nodiscard]] constexpr pos<3, ScalarT> project(pos<3, ScalarT> const& p, hemisphere_boundary<3, ScalarT> const& h)
{
auto closestOnFlat = project(p, sphere<2, ScalarT, 3>(h.center, h.radius, h.normal));
......@@ -240,7 +240,7 @@ template <class ScalarT>
}
template <class ScalarT>
[[nodiscard]] constexpr pos<2, ScalarT> project_to_boundary(pos<2, ScalarT> const& p, hemisphere<2, ScalarT> const& h) // boundary, including caps
[[nodiscard]] constexpr pos<2, ScalarT> project(pos<2, ScalarT> const& p, hemisphere_boundary<2, ScalarT> const& h) // boundary, including caps
{
auto v = perpendicular(h.normal) * h.radius;
auto closestOnFlat = project(p, segment<2, ScalarT>(h.center - v, h.center + v));
......@@ -271,20 +271,7 @@ template <class ScalarT>
}
template <class ScalarT>
[[nodiscard]] constexpr pos<3, ScalarT> project_no_caps(pos<3, ScalarT> const& p, cylinder<3, ScalarT> const& t) // same as project(cylinder) for the internal case
{
auto lp = project(p, line<3, ScalarT>(t.axis.pos0, normalize(t.axis.pos1 - t.axis.pos0)));
auto sp = project(lp, t.axis);
auto dir = p - lp;
auto l = length(dir);
if (l > t.radius)
dir *= t.radius / l;
return sp + dir;
}
template <class ScalarT>
[[nodiscard]] constexpr pos<3, ScalarT> project_to_boundary_no_caps(pos<3, ScalarT> const& p, cylinder<3, ScalarT> const& t)
[[nodiscard]] constexpr pos<3, ScalarT> project(pos<3, ScalarT> const& p, cylinder_boundary_no_caps<3, ScalarT> const& t)
{
auto lp = project(p, line<3, ScalarT>(t.axis.pos0, normalize(t.axis.pos1 - t.axis.pos0)));
auto sp = project(lp, t.axis);
......@@ -296,7 +283,7 @@ template <class ScalarT>
}
template <class ScalarT>
[[nodiscard]] constexpr pos<3, ScalarT> project_to_boundary(pos<3, ScalarT> const& p, cylinder<3, ScalarT> const& c) // boundary, including caps
[[nodiscard]] constexpr pos<3, ScalarT> project(pos<3, ScalarT> const& p, cylinder_boundary<3, ScalarT> const& c) // boundary, including caps
{
auto dir = direction(c);
......@@ -345,7 +332,7 @@ template <class ScalarT>
return project(p, cylinder<3, ScalarT>(c.axis, c.radius));
}
template <class ScalarT>
[[nodiscard]] constexpr pos<3, ScalarT> project_to_boundary(pos<3, ScalarT> const& p, capsule<3, ScalarT> const& c) // boundary, including caps
[[nodiscard]] constexpr pos<3, ScalarT> project(pos<3, ScalarT> const& p, capsule_boundary<3, ScalarT> const& c) // boundary, including caps
{
auto t = coordinates(c.axis, p);
......
......@@ -2,316 +2,140 @@
#include <functional>
#include <typed-geometry/tg-lean.hh>
namespace tg
{
namespace detail
{
inline size_t hash_combine(size_t a, size_t b) { return a * 6364136223846793005ULL + b + 0xda3e39cb94b95bdbULL; }
inline size_t hash_combine(size_t a, size_t b, size_t c) { return hash_combine(hash_combine(a, b), c); }
inline size_t hash_combine(size_t a, size_t b, size_t c, size_t d) { return hash_combine(hash_combine(a, b), hash_combine(c, d)); }
template <class T>
size_t hash(T const& a)
{
return std::hash<T>{}(a);
}
template <class T>
size_t hash(T const& a, T const& b)
{
return hash_combine(std::hash<T>{}(a), std::hash<T>{}(b));
}
template <class T>
size_t hash(T const& a, T const& b, T const& c)
{
return hash_combine(std::hash<T>{}(a), std::hash<T>{}(b), std::hash<T>{}(c));
}
template <class T>
size_t hash(T const& a, T const& b, T const& c, T const& d)
{
return hash_combine(std::hash<T>{}(a), std::hash<T>{}(b), std::hash<T>{}(c), std::hash<T>{}(d));
}
} // namespace detail
} // namespace tg
#include <typed-geometry/functions/basic/hash.hh>
namespace std
{
// -- scalars
template <class T>
struct hash<tg::angle_t<T>>
struct hash<tg::angle_t<T>> : tg::hash
{
std::size_t operator()(tg::angle_t<T> const& v) const noexcept { return tg::detail::hash(v.radians()); }
};
// -- comp
template <class ScalarT>
struct hash<tg::comp<1, ScalarT>>
template <class T>
struct hash<tg::interval<T>> : tg::hash
{
std::size_t operator()(tg::comp<1, ScalarT> const& v) const noexcept { return tg::detail::hash(v.x); }
};
template <class ScalarT>
struct hash<tg::comp<2, ScalarT>>
template <class T>
struct hash<tg::fwd_diff<T>> : tg::hash
{
std::size_t operator()(tg::comp<2, ScalarT> const& v) const noexcept { return tg::detail::hash(v.x, v.y); }
};
template <class ScalarT>
struct hash<tg::comp<3, ScalarT>>
template <int w>
struct hash<tg::fixed_int<w>> : tg::hash
{
std::size_t operator()(tg::comp<3, ScalarT> const& v) const noexcept { return tg::detail::hash(v.x, v.y, v.z); }
};
template <class ScalarT>
struct hash<tg::comp<4, ScalarT>>
template <int w>
struct hash<tg::fixed_uint<w>> : tg::hash
{
std::size_t operator()(tg::comp<4, ScalarT> const& v) const noexcept { return tg::detail::hash(v.x, v.y, v.z, v.w); }
};
// -- vec
template <class ScalarT>
struct hash<tg::vec<1, ScalarT>>
// -- comp-likes
template <int D, class ScalarT>
struct hash<tg::comp<D, ScalarT>> : tg::hash
{
std::size_t operator()(tg::vec<1, ScalarT> const& v) const noexcept { return tg::detail::hash(v.x); }
};
template <class ScalarT>
struct hash<tg::vec<2, ScalarT>>
template <int D, class ScalarT>
struct hash<tg::vec<D, ScalarT>> : tg::hash
{
std::size_t operator()(tg::vec<2, ScalarT> const& v) const noexcept { return tg::detail::hash(v.x, v.y); }
};
template <class ScalarT>
struct hash<tg::vec<3, ScalarT>>
{
std::size_t operator()(tg::vec<3, ScalarT> const& v) const noexcept { return tg::detail::hash(v.x, v.y, v.z); }
};
template <class ScalarT>
struct hash<tg::vec<4, ScalarT>>
template <int D, class ScalarT>
struct hash<tg::dir<D, ScalarT>> : tg::hash
{
std::size_t operator()(tg::vec<4, ScalarT> const& v) const noexcept { return tg::detail::hash(v.x, v.y, v.z, v.w); }
};
// -- dir
template <class ScalarT>
struct hash<tg::dir<1, ScalarT>>
template <int D, class ScalarT>
struct hash<tg::pos<D, ScalarT>> : tg::hash
{
std::size_t operator()(tg::dir<1, ScalarT> const& v) const noexcept { return tg::detail::hash(v.x); }
};
template <class ScalarT>
struct hash<tg::dir<2, ScalarT>>
template <int D, class ScalarT>
struct hash<tg::size<D, ScalarT>> : tg::hash
{
std::size_t operator()(tg::dir<2, ScalarT> const& v) const noexcept { return tg::detail::hash(v.x, v.y); }
};
template <class ScalarT>
struct hash<tg::dir<3, ScalarT>>
template <int D, class ScalarT>
struct hash<tg::color<D, ScalarT>> : tg::hash
{
std::size_t operator()(tg::dir<3, ScalarT> const& v) const noexcept { return tg::detail::hash(v.x, v.y, v.z); }
};
template <class ScalarT>
struct hash<tg::dir<4, ScalarT>>
struct hash<tg::quaternion<ScalarT>> : tg::hash
{
std::size_t operator()(tg::dir<4, ScalarT> const& v) const noexcept { return tg::detail::hash(v.x, v.y, v.z, v.w); }
};
// -- pos
template <class ScalarT>
struct hash<tg::pos<1, ScalarT>>
template <int D, class ScalarT>
struct hash<tg::quadric<D, ScalarT>> : tg::hash
{
std::size_t operator()(tg::pos<1, ScalarT> const& v) const noexcept { return tg::detail::hash(v.x); }
};
template <class ScalarT>
struct hash<tg::pos<2, ScalarT>>
{
std::size_t operator()(tg::pos<2, ScalarT> const& v) const noexcept { return tg::detail::hash(v.x, v.y); }
};
template <class ScalarT>
struct hash<tg::pos<3, ScalarT>>
{
std::size_t operator()(tg::pos<3, ScalarT> const& v) const noexcept { return tg::detail::hash(v.x, v.y, v.z); }
};
template <class ScalarT>
struct hash<tg::pos<4, ScalarT>>
template <int C, int R, class ScalarT>
struct hash<tg::mat<C, R, ScalarT>> : tg::hash
{
std::size_t operator()(tg::pos<4, ScalarT> const& v) const noexcept { return tg::detail::hash(v.x, v.y, v.z, v.w); }
};
// -- size
template <class ScalarT>
struct hash<tg::size<1, ScalarT>>
{
std::size_t operator()(tg::size<1, ScalarT> const& v) const noexcept { return tg::detail::hash(v.width); }
};
template <class ScalarT>
struct hash<tg::size<2, ScalarT>>
{
std::size_t operator()(tg::size<2, ScalarT> const& v) const noexcept { return tg::detail::hash(v.width, v.height); }
};
template <class ScalarT>
struct hash<tg::size<3, ScalarT>>
{
std::size_t operator()(tg::size<3, ScalarT> const& v) const noexcept { return tg::detail::hash(v.width, v.height, v.depth); }
};
template <class ScalarT>
struct hash<tg::size<4, ScalarT>>
{
std::size_t operator()(tg::size<4, ScalarT> const& v) const noexcept { return tg::detail::hash(v.width, v.height, v.depth, v.w); }
};
// TODO: f8 and f16
// -- color
template <class ScalarT>
struct hash<tg::color<3, ScalarT>>
// -- objects
template <int D, class ScalarT>
struct hash<tg::line<D, ScalarT>> : tg::hash
{
std::size_t operator()(tg::color<3, ScalarT> const& v) const noexcept { return tg::detail::hash(v.r, v.g, v.b); }
};
template <class ScalarT>
struct hash<tg::color<4, ScalarT>>
template <int D, class ScalarT>
struct hash<tg::ray<D, ScalarT>> : tg::hash
{
std::size_t operator()(tg::color<4, ScalarT> const& v) const noexcept { return tg::detail::hash(v.r, v.g, v.b, v.a); }
};
// -- quat
template <class ScalarT>
struct hash<tg::quaternion<ScalarT>>
template <int D, class ScalarT>
struct hash<tg::segment<D, ScalarT>> : tg::hash
{
std::size_t operator()(tg::quaternion<ScalarT> const& v) const noexcept { return tg::detail::hash(v.x, v.y, v.z, v.w); }
};
// -- mat
template <int R, class ScalarT>
struct hash<tg::mat<1, R, ScalarT>>
template <int D, class ScalarT>
struct hash<tg::triangle<D, ScalarT>> : tg::hash
{
std::size_t operator()(tg::mat<1, R, ScalarT> const& v) const noexcept { return tg::detail::hash(v[0]); }
};
template <int R, class ScalarT>
struct hash<tg::mat<2, R, ScalarT>>
template <int D, class ScalarT>
struct hash<tg::quad<D, ScalarT>> : tg::hash
{
std::size_t operator()(tg::mat<2, R, ScalarT> const& v) const noexcept { return tg::detail::hash(v[0], v[1]); }
};
template <int R, class ScalarT>
struct hash<tg::mat<3, R, ScalarT>>
template <int D, class ScalarT>
struct hash<tg::plane<D, ScalarT>> : tg::hash
{
std::size_t operator()(tg::mat<3, R, ScalarT> const& v) const noexcept { return tg::detail::hash(v[0], v[1], v[2]); }
};
template <int R, class ScalarT>
struct hash<tg::mat<4, R, ScalarT>>
template <int D, class ScalarT>
struct hash<tg::halfspace<D, ScalarT>> : tg::hash
{
std::size_t operator()(tg::mat<4, R, ScalarT> const& v) const noexcept { return tg::detail::hash(v[0], v[1], v[2], v[3]); }
};
// -- fixed_uint