25 { v.position } -> std::convertible_to<glm::vec3>;
42template <PositionCarrying T>
43[[nodiscard]] glm::vec3
centroid(std::span<T> pts)
noexcept
46 return glm::vec3(0.0F);
48 for (
const auto& p : pts)
49 acc +=
static_cast<glm::vec3
>(p.position);
50 return acc /
static_cast<float>(pts.size());
68template <PositionCarrying T, std::invocable<const T&> WeightFn>
69 requires std::convertible_to<std::invoke_result_t<WeightFn, const T&>,
float>
73 return glm::vec3(0.0F);
76 for (
const auto& p : pts) {
77 const auto w =
static_cast<float>(std::invoke(
weight, p));
78 acc +=
static_cast<glm::vec3
>(p.position) * w;
81 return total > 0.0F ? acc /
total : glm::vec3(0.0F);
103 std::invocable<const T&> PosFn,
104 std::invocable<const T&> WeightFn>
105 requires std::convertible_to<std::invoke_result_t<PosFn, const T&>, glm::vec3>
106 && std::convertible_to<std::invoke_result_t<WeightFn, const T&>,
float>
107[[nodiscard]] glm::vec3
centroid(std::span<T> pts, PosFn pos, WeightFn
weight)
noexcept
110 return glm::vec3(0.0F);
113 for (
const auto& p : pts) {
114 const auto w =
static_cast<float>(std::invoke(
weight, p));
115 acc +=
static_cast<glm::vec3
>(std::invoke(pos, p)) * w;
118 return total > 0.0F ? acc /
total : glm::vec3(0.0F);
127[[nodiscard]]
inline glm::vec3
centroid(std::span<const glm::vec3> pts)
noexcept
130 return glm::vec3(0.0F);
132 for (
const auto& p : pts)
134 return acc /
static_cast<float>(pts.size());
148 std::span<const std::byte> bytes,
151 size_t index)
noexcept
153 if (stride <
offset +
sizeof(glm::vec3)
154 ||
index * stride +
offset +
sizeof(glm::vec3) > bytes.size())
157 std::memcpy(&p, bytes.data() +
index * stride +
offset,
sizeof(glm::vec3));
175 std::span<const std::byte> bytes,
177 size_t offset = 0) noexcept
179 if (stride <
offset +
sizeof(glm::vec3))
180 return glm::vec3(0.0F);
181 const size_t count = bytes.size() / stride;
183 return glm::vec3(0.0F);
185 for (
size_t i = 0; i <
count; ++i)
187 return acc /
static_cast<float>(
count);
205 std::span<const std::byte> bytes,
208 std::span<const uint32_t>
indices)
noexcept
212 for (
size_t t = 0; t + 2 <
indices.size(); t += 3) {
218 const float area = 0.5F * glm::length(glm::cross(*
b - *
a, *c - *
a));
219 acc += (*
a + *
b + *c) * (area / 3.0F);
239template <PositionCarrying T>
243 return AABB3D { .
min = glm::vec3(0.0F), .max = glm::vec3(0.0F) };
244 constexpr float inf = std::numeric_limits<float>::max();
245 AABB3D box { .
min = glm::vec3(inf), .max = glm::vec3(-inf) };
246 for (
const auto& p : pts) {
247 const glm::vec3
q =
static_cast<glm::vec3
>(p.position);
248 box.min = glm::min(box.min,
q);
249 box.max = glm::max(box.max,
q);
263[[nodiscard]]
inline AABB3D aabb(std::span<const glm::vec3> pts)
noexcept
266 return AABB3D { .
min = glm::vec3(0.0F), .max = glm::vec3(0.0F) };
267 constexpr float inf = std::numeric_limits<float>::max();
268 AABB3D box { .
min = glm::vec3(inf), .max = glm::vec3(-inf) };
269 for (
const auto& p : pts) {
270 box.min = glm::min(box.min, p);
271 box.max = glm::max(box.max, p);
std::vector< uint32_t > indices
Satisfied by any type exposing a position field convertible to glm::vec3.
std::optional< glm::vec3 > position_at(std::span< const std::byte > bytes, size_t stride, size_t offset, size_t index) noexcept
Position of one record in interleaved vertex bytes.
glm::vec2 centroid(const Memory::HistoryBuffer< glm::vec2 > &history, size_t window) noexcept
Mean position across a window.
glm::vec3 surface_centroid(std::span< const std::byte > bytes, size_t stride, size_t offset, std::span< const uint32_t > indices) noexcept
Area-weighted centroid of the triangles of an indexed mesh.
AABB3D aabb(std::span< T > pts) noexcept
Axis-aligned bounding box of a PositionCarrying span.
Axis-aligned bounding box in 3D world space.