24 [[nodiscard]]
bool contains(
double p)
const noexcept
26 return p >=
min && p <=
max;
31 return min <= other.max &&
max >= other.min;
34 [[nodiscard]]
double width() const noexcept {
return max -
min; }
36 [[nodiscard]]
double center() const noexcept {
return (
min +
max) * 0.5; }
45 return { .
min =
min - margin, .max =
max + margin };
67 [[nodiscard]]
bool contains(glm::vec2 p)
const noexcept
69 return p.x >=
min.x && p.x <=
max.x
70 && p.y >=
min.y && p.y <=
max.y;
75 return min.x <= other.max.x &&
max.x >= other.min.x
76 &&
min.y <= other.max.y &&
max.y >= other.min.y;
79 [[nodiscard]]
float width() const noexcept {
return max.x -
min.x; }
80 [[nodiscard]]
float height() const noexcept {
return max.y -
min.y; }
82 [[nodiscard]] glm::vec2
center() const noexcept {
return (
min +
max) * 0.5F; }
91 return { .
min =
min - glm::vec2(margin), .max =
max + glm::vec2(margin) };
109 float x,
float y,
float w,
float h,
110 uint32_t win_w, uint32_t win_h)
noexcept
112 auto nx = [&](
float px) {
113 return (
px /
static_cast<float>(win_w)) * 2.0F - 1.0F;
115 auto ny = [&](
float py) {
116 return 1.0F - (
py /
static_cast<float>(win_h)) * 2.0F;
118 return { .
min = glm::vec2(nx(x), ny(y +
h)), .max = glm::vec2(nx(x + w), ny(y)) };
127 glm::vec2 ndc_position, glm::vec2 ndc_scale)
noexcept
129 glm::vec2 half = ndc_scale * 0.5F;
130 return { .
min = ndc_position - half, .max = ndc_position + half };
151 [[nodiscard]]
bool contains(
const glm::vec3& p)
const noexcept
163 glm::vec3 oc = ray.origin -
center;
164 float b = glm::dot(oc, ray.direction);
166 const float discriminant =
b *
b - c;
167 if (discriminant < 0.0F)
169 return -
b + std::sqrt(discriminant) >= 0.0F;
192 [[nodiscard]]
bool contains(
const glm::vec3& p)
const noexcept
194 return p.x >=
min.x && p.x <=
max.x
195 && p.y >=
min.y && p.y <=
max.y
196 && p.z >=
min.z && p.z <=
max.z;
201 return min.x <= other.max.x &&
max.x >= other.min.x
202 &&
min.y <= other.max.y &&
max.y >= other.min.y
203 &&
min.z <= other.max.z &&
max.z >= other.min.z;
206 [[nodiscard]] glm::vec3
center() const noexcept {
return (
min +
max) * 0.5F; }
217 return { .
min =
min - glm::vec3(margin), .max =
max + glm::vec3(margin) };
227 return { .
min = c - half, .max = c + half };
236 return { .
min = s.center - glm::vec3(s.radius),
237 .max = s.center + glm::vec3(s.radius) };
252[[nodiscard]]
inline std::function<bool(glm::vec2)>
256 return [center, r2](glm::vec2 p) {
257 glm::vec2 d = p - center;
258 return d.x * d.x + d.y * d.y <= r2;
271[[nodiscard]]
inline std::function<bool(glm::vec2)>
274 std::vector<glm::vec2> verts(vertices.begin(), vertices.end());
275 return [verts = std::move(verts)](glm::vec2 p) {
277 size_t n = verts.size();
278 for (
size_t i = 0; i < n; ++i) {
279 glm::vec2
a = verts[i];
280 glm::vec2
b = verts[(i + 1) % n];
283 float cross = (
b.x -
a.x) * (p.y -
a.y)
284 - (
b.y -
a.y) * (p.x -
a.x);
290 float cross = (
b.x -
a.x) * (p.y -
a.y)
291 - (
b.y -
a.y) * (p.x -
a.x);
311[[nodiscard]]
inline std::function<bool(glm::vec2)>
314 std::vector<glm::vec2> pts(
points.begin(),
points.end());
315 float t2 = half_thickness * half_thickness;
316 return [pts = std::move(pts), t2](glm::vec2 p) {
317 for (
size_t i = 0; i + 1 < pts.size(); ++i) {
318 glm::vec2
a = pts[i];
319 glm::vec2
b = pts[i + 1];
320 glm::vec2 ab =
b -
a;
321 float len2 = glm::dot(ab, ab);
324 glm::vec2 ap = p -
a;
325 d2 = glm::dot(ap, ap);
327 float t = glm::clamp(glm::dot(p -
a, ab) / len2, 0.0F, 1.0F);
328 glm::vec2 proj =
a + t * ab;
329 glm::vec2 diff = p - proj;
330 d2 = glm::dot(diff, diff);
352[[nodiscard]]
inline std::function<bool(glm::vec3)>
356 return [center, r2](
const glm::vec3& p) {
357 glm::vec3 d = p - center;
358 return glm::dot(d, d) <= r2;
372[[nodiscard]]
inline std::function<bool(glm::vec3)>
375 std::vector<std::pair<glm::vec3, float>> ps(planes.begin(), planes.end());
376 return [ps = std::move(ps)](
const glm::vec3& p) {
377 return std::ranges::all_of(
379 [&p](
const auto& plane) {
380 const auto& [n, d] = plane;
381 return glm::dot(n, p) >= d;
398[[nodiscard]]
inline std::function<bool(glm::vec3)>
400 std::span<const glm::vec2> footprint,
404 std::vector<glm::vec2> verts(footprint.begin(), footprint.end());
405 return [verts = std::move(verts), y_min, y_max](
const glm::vec3& p) {
406 if (p.y < y_min || p.y > y_max)
408 glm::vec2
q { p.x, p.z };
410 const size_t n = verts.size();
411 for (
size_t i = 0; i < n; ++i) {
412 glm::vec2
a = verts[i];
413 glm::vec2
b = verts[(i + 1) % n];
416 float cross = (
b.x -
a.x) * (
q.y -
a.y)
417 - (
b.y -
a.y) * (
q.x -
a.x);
423 float cross = (
b.x -
a.x) * (
q.y -
a.y)
424 - (
b.y -
a.y) * (
q.x -
a.x);
441[[nodiscard]]
inline std::function<bool(glm::vec2)>
443 std::function<
bool(glm::vec2)>
a,
444 std::function<
bool(glm::vec2)>
b)
446 return [
a = std::move(
a),
b = std::move(
b)](glm::vec2 p) {
454[[nodiscard]]
inline std::function<bool(glm::vec2)>
456 std::function<
bool(glm::vec2)>
a,
457 std::function<
bool(glm::vec2)>
b)
459 return [
a = std::move(
a),
b = std::move(
b)](glm::vec2 p) {
468[[nodiscard]]
inline std::function<bool(glm::vec2)>
470 std::function<
bool(glm::vec2)>
a,
471 std::function<
bool(glm::vec2)>
b)
473 return [
a = std::move(
a),
b = std::move(
b)](glm::vec2 p) {
474 return a(p) && !
b(p);
502[[nodiscard]]
inline std::function<bool(glm::vec3)>
504 std::function<
bool(glm::vec3)>
a,
505 std::function<
bool(glm::vec3)>
b)
507 return [
a = std::move(
a),
b = std::move(
b)](
const glm::vec3& p) {
515[[nodiscard]]
inline std::function<bool(glm::vec3)>
517 std::function<
bool(glm::vec3)>
a,
518 std::function<
bool(glm::vec3)>
b)
520 return [
a = std::move(
a),
b = std::move(
b)](
const glm::vec3& p) {
528[[nodiscard]]
inline std::function<bool(glm::vec3)>
530 std::function<
bool(glm::vec3)>
a,
531 std::function<
bool(glm::vec3)>
b)
533 return [
a = std::move(
a),
b = std::move(
b)](
const glm::vec3& p) {
534 return a(p) && !
b(p);
583 const glm::vec2 c = anchor.
center();
586 return { .min = { c.x - w * 0.5F, c.y -
h * 0.5F },
587 .max = { c.x + w * 0.5F, c.y +
h * 0.5F } };
600 x1 = anchor.min.x + w;
603 x0 = anchor.max.x - w;
612 ?
AABB2D { .
min = { x0, anchor.min.y - gap -
h }, .max = { x1, anchor.min.y - gap } }
613 :
AABB2D { .
min = { x0, anchor.max.y + gap }, .max = { x1, anchor.max.y + gap +
h } };
624 y0 = anchor.max.y -
h;
629 y1 = anchor.min.y +
h;
637 ?
AABB2D { .
min = { anchor.max.x + gap, y0 }, .max = { anchor.max.x + gap + w, y1 } }
638 :
AABB2D { .
min = { anchor.min.x - gap - w, y0 }, .max = { anchor.min.x - gap, y1 } };
654 { t.bounds() } -> std::convertible_to<AABB2D>;
658template <HasBounds T>
665template <HasBounds A>
667 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.
double center() const noexcept
double width() const noexcept
AABB1D translated(double offset) const noexcept
bool overlaps(const AABB1D &other) const noexcept
AABB1D expanded(double margin) const noexcept
bool contains(double p) const noexcept
Closed interval on a scalar axis.
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.