Back to sparse_spatial_hash

Documentation

API reference and core concepts for sparse_spatial_hash.

API Documentation

The sparse_spatial_hash library provides a high-performance spatial indexing data structure for C++20. It divides space into a grid of cells and uses a hash map to store only occupied cells, making it memory-efficient for large, sparse worlds.

Core Classes

grid_config<N>

Configuration structure for spatial grids.

Field Type Description
cell_size std::array<float, N> Size of each cell in each dimension
world_size std::array<float, N> Total world size in each dimension
topology_type topology Boundary behavior (bounded, toroidal, infinite)
grid_config<3> cfg{
    .cell_size = {10.0f, 10.0f, 10.0f},
    .world_size = {1000.0f, 1000.0f, 1000.0f},
    .topology_type = topology::bounded
};

sparse_spatial_hash<Entity, N>

The main grid class for spatial indexing.

Template Parameters:

Parameter Description
Entity Your entity type (e.g., Particle, GameObject)
N Number of dimensions (typically 2 or 3)
Float Floating-point type (default: float)
Index Index type (default: std::size_t)
Hash Cell hash function (default: cell_hash<N>)
Allocator Allocator type (default: std::allocator)

position_accessor<Entity, N>

Trait for extracting position from your entity type.

template<>
struct spatial::position_accessor<Particle, 3> {
    static float get(const Particle& p, std::size_t dim) {
        switch(dim) {
            case 0: return p.x;
            case 1: return p.y;
            case 2: return p.z;
            default: return 0.0f;
        }
    }
};

Note: If your entity stores position as std::array<float, N>, the default implementation works automatically.

Topology Types

Type Behavior Use Case
topology::bounded Coordinates clamped to [0, world_size] Rooms, arenas, bounded worlds
topology::toroidal Coordinates wrap around (periodic) N-body simulations, Pac-Man-style worlds
topology::infinite No bounds checking, grid grows Procedural worlds, expanding universes

Core Operations

Building the Grid

Method Complexity Description
rebuild(entities) O(n) Full rebuild from entity container
update(entities) O(k) Incremental update (k = entities that changed cells)
clear() O(1) Remove all entities

Querying

Method Description
query_radius(r, x, y, z) Returns indices of entities in cells intersecting query sphere
query_cell(cx, cy, cz) Returns indices of entities in specific cell
for_each_pair(entities, radius, callback) Invokes callback for all pairs within radius

Important: query_radius returns candidates - entities in cells that intersect the query sphere. Always filter by exact distance for precision:

auto candidates = grid.query_radius(radius, x, y, z);
for (auto idx : candidates) {
    float dist = compute_distance(entities[idx], query_point);
    if (dist < radius) {
        // True neighbor
    }
}

Statistics

Method Description
entity_count() Total entities in grid
cell_count() Number of occupied cells
stats() Returns grid_stats with detailed metrics
auto stats = grid.stats();
// stats.occupied_cells
// stats.avg_entities_per_cell
// stats.occupancy_ratio
// stats.max_entities_in_cell

Performance Characteristics

Operation Complexity Typical Performance
Build O(n) 14.7M entities/second
Incremental Update O(k) 29.2M entities/second
Query Radius O(cells × entities/cell) Sub-microsecond for typical queries
For Each Pair O(n × avg_neighbors) Optimized for collision detection

Memory Usage

  • Sparse storage: Only occupied cells use memory
  • Typical: 100MB for 10M particles in 10000³ world
  • Comparison: 60,000× less memory than equivalent dense grid

Full Reference

For complete API documentation with all method signatures and complexity guarantees: