Table of Contents

Class ClusterCellGrid

Namespace
LansMap.Core.Markers

Static, build-once spatial index over a cluster list's centroids: every occupied cell's members sit in one contiguous run of a shared array, found by binary search instead of a hash probe.

public sealed class ClusterCellGrid
Inheritance
object
ClusterCellGrid

Remarks

Meant for a level that is built once and queried many times, never mutated in place: there is no Add, Remove, or UpdatePosition. Build(IReadOnlyList<MarkerCluster>, double) replaces the whole grid from a fresh cluster list; Query(IReadOnlyList<MarkerCluster>, in MercatorBounds, List<int>) re-reads each candidate's position from that same list rather than storing a copy, which is why both methods take it as a parameter.

Cell keying matches MarkerSpatialIndex: a cell is floor(position / cellSize) on each axis, packed into one long. Query(IReadOnlyList<MarkerCluster>, in MercatorBounds, List<int>) visits the rect's cells in the same order (y outer, x inner) and, within a cell, in ascending cluster index - the order Build(IReadOnlyList<MarkerCluster>, double) fills them in - so results are deterministic across two builds of identical input.

Ground centroids only: a coarser-level cluster is always built at altitude 0, so there is no raised-marker fallback list to carry.

Not thread safe. Query(IReadOnlyList<MarkerCluster>, in MercatorBounds, List<int>) allocates nothing; Build(IReadOnlyList<MarkerCluster>, double) grows its internal arrays as needed and never shrinks them until Release().

Properties

CellSize

The grid cell size passed to the last Build(IReadOnlyList<MarkerCluster>, double).

public double CellSize { get; }

Property Value

double

Count

Clusters indexed by the last Build(IReadOnlyList<MarkerCluster>, double).

public int Count { get; }

Property Value

int

LastQueryCellsVisited

Cells the most recent Query(IReadOnlyList<MarkerCluster>, in MercatorBounds, List<int>) tried, occupied or not.

public int LastQueryCellsVisited { get; }

Property Value

int

OccupiedCellCount

Occupied cells after the last Build(IReadOnlyList<MarkerCluster>, double).

public int OccupiedCellCount { get; }

Property Value

int

Methods

Build(IReadOnlyList<MarkerCluster>, double)

Rebuilds the grid from clusters' current positions. Replaces whatever this instance held before; there is no incremental update.

public void Build(IReadOnlyList<MarkerCluster> clusters, double cellSize)

Parameters

clusters IReadOnlyList<MarkerCluster>

Clusters to index, read by MercX/MercY.

cellSize double

Grid cell width and height in normalized mercator units. Must be positive and finite.

Query(IReadOnlyList<MarkerCluster>, in MercatorBounds, List<int>)

Fills results (cleared first) with every cluster from the last Build(IReadOnlyList<MarkerCluster>, double) whose position falls inside bounds. Only cells the rect touches are visited.

public void Query(IReadOnlyList<MarkerCluster> clusters, in MercatorBounds bounds, List<int> results)

Parameters

clusters IReadOnlyList<MarkerCluster>

The same list Build(IReadOnlyList<MarkerCluster>, double) was called with - positions are re-read from it, not cached.

bounds MercatorBounds

Query rect in the same unwrapped normalized mercator frame the clusters were built in. A non-finite bound answers nothing.

results List<int>

Caller-owned output list; cleared first.

Release()

Drops every stored cluster and frees the internal arrays, so an instance that will not be reused for a while does not hold onto its last build's memory.

public void Release()