tiramisu/spatial

Spatial partitioning data structures for efficient spatial queries.

Provides octree and Collider (Box and Sphere) for:

Quick Example

import tiramisu/spatial

// Create octree for world bounds
let world_bounds = spatial.box(
  min: vec3.Vec3(-100.0, -100.0, -100.0),
  max: vec3.Vec3(100.0, 100.0, 100.0),
)
let tree = spatial.octree_new(bounds: world_bounds, capacity: 8)

// Insert enemies
let tree = spatial.octree_insert(tree, enemy_pos, enemy_id)

// Find enemies near player
let nearby = spatial.octree_query_radius(tree, player_pos, radius: 10.0)

Types

Collision volume for spatial queries and collision detection.

pub opaque type Collider

Octree node for spatial partitioning Divides 3D space into 8 octants recursively Note: Octrees always use Box bounds (not Sphere)

pub opaque type Octree(a)

Values

pub fn collider_box(
  min min: vec3.Vec3(Float),
  max max: vec3.Vec3(Float),
) -> Collider

Create a box collider from min and max points.

Example

let bounds = spatial.collider_box(
  min: vec3.Vec3(-1.0, -1.0, -1.0),
  max: vec3.Vec3(1.0, 1.0, 1.0),
)
pub fn collider_box_from_center(
  center: vec3.Vec3(Float),
  half_extents: vec3.Vec3(Float),
) -> Collider

Create a box collider from center and half-extents.

Example

let bounds = spatial.box_from_center(
  center: vec3.Vec3(0.0, 5.0, 0.0),
  half_extents: vec3.Vec3(2.0, 1.0, 2.0),
)
pub fn collider_center(collider: Collider) -> vec3.Vec3(Float)

Get the center of a collider.

pub fn collider_contains_point(
  collider: Collider,
  point: vec3.Vec3(Float),
) -> Bool

Check if a point is inside a collider.

Works for both Box and Sphere colliders.

pub fn collider_from_transform(
  collider: Collider,
  transform: transform.Transform,
) -> Collider

Create a new collider from a local-space collider and a transform.

For Box: Computes a new axis-aligned bounding box that encompasses all 8 corners after rotation, translation, and scaling.

For Sphere: Transforms the center and scales the radius by the maximum scale component (since spheres remain spherical under uniform scaling).

Example

// Local space box
let local_box = spatial.box(
  min: vec3.Vec3(-1.0, -1.0, -1.0),
  max: vec3.Vec3(1.0, 1.0, 1.0),
)

// Rotated 45 degrees around Y axis
let transform = transform.identity
  |> transform.with_position(vec3.Vec3(5.0, 0.0, 0.0))
  |> transform.with_euler_rotation(vec3.Vec3(0.0, 0.785, 0.0))

// Get world-space collider
let world_box = spatial.collider_from_transform(local_box, transform)
pub fn collider_intersects(a: Collider, b: Collider) -> Bool

Check if two colliders intersect.

Handles Box-Box, Sphere-Sphere, and Box-Sphere collisions.

pub fn collider_size(collider: Collider) -> vec3.Vec3(Float)

Get the size (dimensions) of a box collider.

For spheres, returns the diameter as a uniform Vec3.

pub fn collider_sphere(
  center center: vec3.Vec3(Float),
  radius radius: Float,
) -> Collider

Create a sphere collider from center and radius.

Example

let bounds = spatial.sphere(
  center: vec3.Vec3(0.0, 0.0, 0.0),
  radius: 2.5,
)
pub fn octree_bounds(tree: Octree(a)) -> Collider

Get the bounds of the octree

pub fn octree_count(tree: Octree(a)) -> Int

Count total items in the octree

pub fn octree_insert(
  tree: Octree(a),
  position: vec3.Vec3(Float),
  item: a,
) -> Octree(a)

Insert an item at a position into the octree

pub fn octree_new(bounds: Collider, capacity: Int) -> Octree(a)

Create a new empty octree.

Note: Octrees require Box colliders (not Sphere).

Parameters

  • bounds: The spatial region this octree covers (must be a Box)
  • capacity: Maximum items per node before subdividing (typically 8-16)

Example

let bounds = spatial.box(
  min: vec3.Vec3(-100.0, -100.0, -100.0),
  max: vec3.Vec3(100.0, 100.0, 100.0),
)
let tree = spatial.octree_new(bounds, capacity: 8)
pub fn octree_query(
  tree: Octree(a),
  query_bounds: Collider,
) -> List(#(vec3.Vec3(Float), a))

Query all items within a collider region

pub fn octree_query_all(
  tree: Octree(a),
) -> List(#(vec3.Vec3(Float), a))

Query all items in the octree (useful for iteration)

pub fn octree_query_radius(
  tree: Octree(a),
  center: vec3.Vec3(Float),
  radius: Float,
) -> List(#(vec3.Vec3(Float), a))

Query all items within a radius of a point

Search Document