Class ClusterCentroidGrid
Grid spatial index over densely numbered ground points, backed entirely by flat pooled arrays: an open-addressed cell table, one shared bucket arena, and per-id side arrays. Serves the cluster build's two internal grids, where ids are consecutive from zero and no point has altitude.
public sealed class ClusterCentroidGrid
- Inheritance
-
objectClusterCentroidGrid
Remarks
Same query contract as MarkerSpatialIndex minus the altitude fallback: Query(in MercatorBounds, List<int>) visits only the cells a rect touches, filters each candidate against the rect exactly, and appends survivors in cell-scan order (y outer, x inner) and, within a cell, in bucket order. Add appends to a bucket, Remove swaps the bucket's last entry into the freed slot, and UpdatePosition(int, double, double) is a remove followed by an add - the identical ordering rules MarkerSpatialIndex follows, so the two produce the same result sequence for the same operation sequence, ties included.
Nothing here allocates per cell or per point once the arrays have grown to a workload's size: ResetForReuse(double) rewinds the arena and the table instead of releasing them, so a caller that runs many passes through one instance pays the growth once. Ids must be small non-negative integers - the side arrays are indexed by id, so a sparse id space costs memory proportional to the largest id, not to the number of points.
Not thread safe. Cell size is set by ResetForReuse(double) and is a world-mercator distance.
Constructors
ClusterCentroidGrid(double, int)
public ClusterCentroidGrid(double cellSize, int initialCapacity = 64)
Parameters
cellSizedoubleGrid cell width and height in normalized mercator units. Must be positive and finite.
initialCapacityintPoint count to preallocate for. A sizing hint only; the grid grows correctly from a smaller one.
Fields
DefaultCapacity
Point count to preallocate when constructing a new grid.
public const int DefaultCapacity = 64
Field Value
Properties
CellSize
The current grid cell size in normalized mercator units.
public double CellSize { get; }
Property Value
Count
Points currently in the grid.
public int Count { get; }
Property Value
LastQueryCellsVisited
Cells the most recent Query(in MercatorBounds, List<int>) stepped over, occupied or not. Exists so a caller or a test can verify the query bounded its work to the rect instead of walking the grid.
public int LastQueryCellsVisited { get; }
Property Value
OccupiedCellCount
Cells holding at least one point right now. Cells emptied by a removal are not counted.
public int OccupiedCellCount { get; }
Property Value
Methods
Add(int, double, double)
Starts tracking a point at x,y
in normalized mercator units.
public void Add(int id, double x, double y)
Parameters
idintCaller-chosen identity, used directly as an array index, so it must be non-negative and should be dense.
xdoubleNormalized mercator x.
ydoubleNormalized mercator y.
Exceptions
- ArgumentOutOfRangeException
idis negative.- InvalidOperationException
idis already tracked.
Query(in MercatorBounds, List<int>)
Fills results (cleared first) with every tracked
point inside bounds, visiting only the cells the
rect touches.
public void Query(in MercatorBounds bounds, List<int> results)
Parameters
boundsMercatorBoundsQuery rect in the same unwrapped normalized mercator frame the points were added in. A non-finite bound returns nothing rather than flooring an unspecified cast into an unbounded cell range.
resultsList<int>Caller-owned output list; cleared first.
Remove(int)
Stops tracking a point. Idempotent: an id that is not tracked is ignored.
public void Remove(int id)
Parameters
idint
ResetForReuse(double)
Drops every point and rebases CellSize, so one instance can serve an unrelated pass without releasing the arrays it already grew.
public void ResetForReuse(double cellSize)
Parameters
cellSizedouble
Remarks
Destructive: every id this grid was tracking stops being findable, with no notification. Intended for a grid a single caller owns end to end and repopulates before its next use.
UpdatePosition(int, double, double)
Moves a tracked point, re-bucketing it if that changes its cell. A stale id - not currently tracked - is ignored rather than an error.
public void UpdatePosition(int id, double x, double y)