25 [[nodiscard]]
bool contains(glm::vec2 p)
const noexcept
27 return p.x >=
min.x && p.x <=
max.x
28 && p.y >=
min.y && p.y <=
max.y;
33 return min.x <= other.max.x &&
max.x >= other.min.x
34 &&
min.y <= other.max.y &&
max.y >= other.min.y;
37 [[nodiscard]]
float width() const noexcept {
return max.x -
min.x; }
38 [[nodiscard]]
float height() const noexcept {
return max.y -
min.y; }
40 [[nodiscard]] glm::vec2
center() const noexcept {
return (
min +
max) * 0.5F; }
49 return { .
min =
min - glm::vec2(margin), .max =
max + glm::vec2(margin) };
67 float x,
float y,
float w,
float h,
68 uint32_t win_w, uint32_t win_h)
noexcept
70 auto nx = [&](
float px) {
71 return (px /
static_cast<float>(win_w)) * 2.0F - 1.0F;
73 auto ny = [&](
float py) {
74 return 1.0F - (py /
static_cast<float>(win_h)) * 2.0F;
76 return { .
min = glm::vec2(nx(x), ny(y +
h)), .max = glm::vec2(nx(x + w), ny(y)) };
85 glm::vec2 ndc_position, glm::vec2 ndc_scale)
noexcept
87 glm::vec2 half = ndc_scale * 0.5F;
88 return { .
min = ndc_position - half, .max = ndc_position + half };
109 [[nodiscard]]
bool contains(
const glm::vec3& p)
const noexcept
121 glm::vec3 oc = ray.origin -
center;
122 float b = glm::dot(oc, ray.direction);
124 return b *
b - c >= 0.0F;
147 [[nodiscard]]
bool contains(
const glm::vec3& p)
const noexcept
149 return p.x >=
min.x && p.x <=
max.x
150 && p.y >=
min.y && p.y <=
max.y
151 && p.z >=
min.z && p.z <=
max.z;
156 return min.x <= other.max.x &&
max.x >= other.min.x
157 &&
min.y <= other.max.y &&
max.y >= other.min.y
158 &&
min.z <= other.max.z &&
max.z >= other.min.z;
161 [[nodiscard]] glm::vec3
center() const noexcept {
return (
min +
max) * 0.5F; }
172 return { .
min =
min - glm::vec3(margin), .max =
max + glm::vec3(margin) };
182 return { .
min = c - half, .max = c + half };
191 return { .
min = s.center - glm::vec3(s.radius),
192 .max = s.center + glm::vec3(s.radius) };
207[[nodiscard]]
inline std::function<bool(glm::vec2)>
211 return [center, r2](glm::vec2 p) {
212 glm::vec2 d = p - center;
213 return d.x * d.x + d.y * d.y <= r2;
226[[nodiscard]]
inline std::function<bool(glm::vec2)>
229 std::vector<glm::vec2> verts(vertices.begin(), vertices.end());
230 return [verts = std::move(verts)](glm::vec2 p) {
232 size_t n = verts.size();
233 for (
size_t i = 0; i < n; ++i) {
234 glm::vec2
a = verts[i];
235 glm::vec2
b = verts[(i + 1) % n];
238 float cross = (
b.x -
a.x) * (p.y -
a.y)
239 - (
b.y -
a.y) * (p.x -
a.x);
245 float cross = (
b.x -
a.x) * (p.y -
a.y)
246 - (
b.y -
a.y) * (p.x -
a.x);
266[[nodiscard]]
inline std::function<bool(glm::vec2)>
269 std::vector<glm::vec2> pts(
points.begin(),
points.end());
270 float t2 = half_thickness * half_thickness;
271 return [pts = std::move(pts), t2](glm::vec2 p) {
272 for (
size_t i = 0; i + 1 < pts.size(); ++i) {
273 glm::vec2
a = pts[i];
274 glm::vec2
b = pts[i + 1];
275 glm::vec2 ab =
b -
a;
276 float len2 = glm::dot(ab, ab);
279 glm::vec2 ap = p -
a;
280 d2 = glm::dot(ap, ap);
282 float t = glm::clamp(glm::dot(p -
a, ab) / len2, 0.0F, 1.0F);
283 glm::vec2 proj =
a + t * ab;
284 glm::vec2 diff = p - proj;
285 d2 = glm::dot(diff, diff);
307[[nodiscard]]
inline std::function<bool(glm::vec3)>
311 return [center, r2](
const glm::vec3& p) {
312 glm::vec3 d = p - center;
313 return glm::dot(d, d) <= r2;
327[[nodiscard]]
inline std::function<bool(glm::vec3)>
330 std::vector<std::pair<glm::vec3, float>> ps(planes.begin(), planes.end());
331 return [ps = std::move(ps)](
const glm::vec3& p) {
332 return std::ranges::all_of(
334 [&p](
const auto& plane) {
335 const auto& [n, d] = plane;
336 return glm::dot(n, p) >= d;
353[[nodiscard]]
inline std::function<bool(glm::vec3)>
355 std::span<const glm::vec2> footprint,
359 std::vector<glm::vec2> verts(footprint.begin(), footprint.end());
360 return [verts = std::move(verts), y_min, y_max](
const glm::vec3& p) {
361 if (p.y < y_min || p.y > y_max)
363 glm::vec2
q { p.x, p.z };
365 const size_t n = verts.size();
366 for (
size_t i = 0; i < n; ++i) {
367 glm::vec2
a = verts[i];
368 glm::vec2
b = verts[(i + 1) % n];
371 float cross = (
b.x -
a.x) * (
q.y -
a.y)
372 - (
b.y -
a.y) * (
q.x -
a.x);
378 float cross = (
b.x -
a.x) * (
q.y -
a.y)
379 - (
b.y -
a.y) * (
q.x -
a.x);
396[[nodiscard]]
inline std::function<bool(glm::vec2)>
398 std::function<
bool(glm::vec2)>
a,
399 std::function<
bool(glm::vec2)>
b)
401 return [
a = std::move(
a),
b = std::move(
b)](glm::vec2 p) {
409[[nodiscard]]
inline std::function<bool(glm::vec2)>
411 std::function<
bool(glm::vec2)>
a,
412 std::function<
bool(glm::vec2)>
b)
414 return [
a = std::move(
a),
b = std::move(
b)](glm::vec2 p) {
423[[nodiscard]]
inline std::function<bool(glm::vec2)>
425 std::function<
bool(glm::vec2)>
a,
426 std::function<
bool(glm::vec2)>
b)
428 return [
a = std::move(
a),
b = std::move(
b)](glm::vec2 p) {
429 return a(p) && !
b(p);
457[[nodiscard]]
inline std::function<bool(glm::vec3)>
459 std::function<
bool(glm::vec3)>
a,
460 std::function<
bool(glm::vec3)>
b)
462 return [
a = std::move(
a),
b = std::move(
b)](
const glm::vec3& p) {
470[[nodiscard]]
inline std::function<bool(glm::vec3)>
472 std::function<
bool(glm::vec3)>
a,
473 std::function<
bool(glm::vec3)>
b)
475 return [
a = std::move(
a),
b = std::move(
b)](
const glm::vec3& p) {
483[[nodiscard]]
inline std::function<bool(glm::vec3)>
485 std::function<
bool(glm::vec3)>
a,
486 std::function<
bool(glm::vec3)>
b)
488 return [
a = std::move(
a),
b = std::move(
b)](
const glm::vec3& p) {
489 return a(p) && !
b(p);
538 const glm::vec2 c = anchor.
center();
541 return { .min = { c.x - w * 0.5F, c.y -
h * 0.5F },
542 .max = { c.x + w * 0.5F, c.y +
h * 0.5F } };
555 x1 = anchor.min.x + w;
558 x0 = anchor.max.x - w;
567 ?
AABB2D { .
min = { x0, anchor.min.y - gap -
h }, .max = { x1, anchor.min.y - gap } }
568 :
AABB2D { .
min = { x0, anchor.max.y + gap }, .max = { x1, anchor.max.y + gap +
h } };
579 y0 = anchor.max.y -
h;
584 y1 = anchor.min.y +
h;
592 ?
AABB2D { .
min = { anchor.max.x + gap, y0 }, .max = { anchor.max.x + gap + w, y1 } }
593 :
AABB2D { .
min = { anchor.min.x - gap - w, y0 }, .max = { anchor.min.x - gap, y1 } };
609 { t.bounds() } -> std::convertible_to<AABB2D>;
613template <HasBounds T>
620template <HasBounds A>
622 const A& anchor,
Side side,
float w,
float h,
std::vector< glm::vec2 > * points
Any type carrying a spatial footprint usable as a placement anchor.
Align
Cross-axis alignment of a placed region against its anchor.
std::function< bool(glm::vec3)> convex_region(std::span< const std::pair< glm::vec3, float > > planes)
Containment test for a convex volume defined by inward-facing half-planes.
std::function< bool(glm::vec2)> intersect_bounds(std::function< bool(glm::vec2)> a, std::function< bool(glm::vec2)> b)
Intersection of two containment tests.
std::function< bool(glm::vec2)> polygon_bounds(std::span< const glm::vec2 > vertices)
Containment test for a convex or concave polygon.
std::function< bool(glm::vec3)> extruded_polygon_region(std::span< const glm::vec2 > footprint, float y_min, float y_max)
Containment test for a vertically extruded 2D polygon.
std::function< bool(glm::vec2)> subtract_bounds(std::function< bool(glm::vec2)> a, std::function< bool(glm::vec2)> b)
Difference of two containment tests.
glm::uvec2 ndc_size_to_pixels(const AABB2D ®ion, uint32_t width, uint32_t height)
Convert an NDC AABB's extent to integer pixel dimensions.
AABB2D place(AABB2D anchor, Side side, float w, float h, float gap=0.F, Align align=Align::Center) noexcept
Compute a region of size (w, h) positioned relative to anchor.
Side
Direction of a placed region relative to its anchor.
std::function< bool(glm::vec2)> stroke_bounds(std::span< const glm::vec2 > points, float half_thickness)
Containment test for a polyline with a uniform half-thickness.
std::function< bool(glm::vec2)> circular_bounds(glm::vec2 center, float radius) noexcept
Containment test for a circle.
std::function< bool(glm::vec2)> union_bounds(std::function< bool(glm::vec2)> a, std::function< bool(glm::vec2)> b)
Union of two containment tests.
AABB2D bounds_of(const T &obj)
Extract the anchor region from any HasBounds object.
static AABB2D from_pixel(float x, float y, float w, float h, uint32_t win_w, uint32_t win_h) noexcept
Construct from pixel-space top-left rect, converted to NDC.
static AABB2D from_ndc(glm::vec2 center, glm::vec2 half) noexcept
float height() const noexcept
AABB2D expanded(float margin) const noexcept
bool overlaps(const AABB2D &other) const noexcept
bool contains(glm::vec2 p) const noexcept
AABB2D translated(glm::vec2 offset) const noexcept
glm::vec2 center() const noexcept
float width() const noexcept
static AABB2D from_buffer_transform(glm::vec2 ndc_position, glm::vec2 ndc_scale) noexcept
Construct from a TextureBuffer NDC position and scale.
Axis-aligned bounding rectangle in a 2D coordinate space.
glm::vec3 center() const noexcept
bool contains(const glm::vec3 &p) const noexcept
bool overlaps(const AABB3D &other) const noexcept
glm::vec3 half_extent() const noexcept
static AABB3D from_sphere(const BoundingSphere &s) noexcept
Construct the tightest AABB enclosing a BoundingSphere.
static AABB3D from_center(const glm::vec3 &c, const glm::vec3 &half) noexcept
Construct from a center point and half-extents.
AABB3D translated(const glm::vec3 &offset) const noexcept
AABB3D expanded(float margin) const noexcept
glm::vec3 extent() const noexcept
Axis-aligned bounding box in 3D world space.
bool overlaps_ray(const Ray &ray) const noexcept
Returns true if the ray passes through or originates inside the sphere.
bool contains(const glm::vec3 &p) const noexcept
Spherical fast-reject hint in world space.
Origin and normalized direction in world space.