Class ClusterCellGrid
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
-
objectClusterCellGrid
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
Count
Clusters indexed by the last Build(IReadOnlyList<MarkerCluster>, double).
public int Count { get; }
Property Value
LastQueryCellsVisited
Cells the most recent Query(IReadOnlyList<MarkerCluster>, in MercatorBounds, List<int>) tried, occupied or not.
public int LastQueryCellsVisited { get; }
Property Value
OccupiedCellCount
Occupied cells after the last Build(IReadOnlyList<MarkerCluster>, double).
public int OccupiedCellCount { get; }
Property Value
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
clustersIReadOnlyList<MarkerCluster>cellSizedoubleGrid 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
clustersIReadOnlyList<MarkerCluster>The same list Build(IReadOnlyList<MarkerCluster>, double) was called with - positions are re-read from it, not cached.
boundsMercatorBoundsQuery rect in the same unwrapped normalized mercator frame the clusters were built in. A non-finite bound answers nothing.
resultsList<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()