Querying entities
Between ingests you can query the engine's in-memory state directly — no events required. Queries come in two shapes: membership lookups that filter entities by the zones they are currently inside, and spatial queries that find entities by their distance from a point.
Membership queries
By zone
engine.entitiesInZone(zoneId: string): EntityState[]
Returns every entity whose logical zone membership currently includes zoneId. Entities are included only after the zone's dwell threshold has been met (if one is configured).
import { GeoEngine } from '@jamesholcombe/geo-stream'
const engine = new GeoEngine()
engine.registerZone('warehouse', {
type: 'Polygon',
coordinates: [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]]],
})
engine.ingest([
{ id: 'truck-1', x: 5, y: 5, tMs: Date.now() },
{ id: 'truck-2', x: 50, y: 50, tMs: Date.now() },
])
const inWarehouse = engine.entitiesInZone('warehouse')
// [{ id: 'truck-1', x: 5, y: 5, t_ms: ..., speed: undefined, heading: undefined }]
By circle
engine.entitiesInCircle(circleId: string): EntityState[]
Returns every entity currently inside the named circle (i.e., those for which an approach event has fired and no recede has followed).
engine.registerCircle('loading-bay', 0, 0, 5)
engine.ingest([{ id: 'van-1', x: 3, y: 0, tMs: Date.now() }])
const atBay = engine.entitiesInCircle('loading-bay')
// [{ id: 'van-1', ... }]
Spatial queries
Spatial queries search by Euclidean distance from a point. Results always include a distance field and are sorted nearest-first.
type EntityWithDistance = EntityState & { distance: number }
All entities within a radius
engine.entitiesNearPoint(x: number, y: number, radius: number): EntityWithDistance[]
Returns every known entity within radius of (x, y), sorted by distance ascending. Entities with no known position (i.e., never ingested) are excluded.
const nearby = engine.entitiesNearPoint(10, 10, 50)
for (const entity of nearby) {
console.log(entity.id, entity.distance.toFixed(1))
}
k-nearest entities
engine.nearestToPoint(x: number, y: number, k: number): EntityWithDistance[]
Returns the k closest entities to (x, y), sorted by distance ascending. Useful for dispatch — find the nearest available resource without scanning the full fleet.
const nearest3 = engine.nearestToPoint(10, 10, 3)
// nearest3[0] is closest, nearest3[2] is furthest of the three
Examples
Fleet dispatch — find the nearest driver
import { GeoEngine } from '@jamesholcombe/geo-stream'
const engine = new GeoEngine()
// Ingest the latest position for every active driver
engine.ingest([
{ id: 'driver-1', x: 12.1, y: 8.4, tMs: Date.now() },
{ id: 'driver-2', x: 3.2, y: 14.7, tMs: Date.now() },
{ id: 'driver-3', x: 27.5, y: 2.1, tMs: Date.now() },
{ id: 'driver-4', x: 9.9, y: 11.3, tMs: Date.now() },
])
// Pickup request arrives at (10, 10) — find the 3 closest drivers
const pickup = { x: 10, y: 10 }
const candidates = engine.nearestToPoint(pickup.x, pickup.y, 3)
for (const driver of candidates) {
console.log(`${driver.id}: ${driver.distance.toFixed(2)} units away`)
}
// driver-4: 1.34 units away
// driver-1: 2.69 units away
// driver-2: 9.56 units away
Depot occupancy dashboard
import { GeoEngine } from '@jamesholcombe/geo-stream'
const engine = new GeoEngine()
engine.registerZone('depot-a', {
type: 'Polygon',
coordinates: [[[0, 0], [10, 0], [10, 10], [0, 10], [0, 0]]],
})
engine.registerZone('depot-b', {
type: 'Polygon',
coordinates: [[[20, 0], [30, 0], [30, 10], [20, 10], [20, 0]]],
})
// Refresh on any new ingest batch
function depotSummary() {
return {
'depot-a': engine.entitiesInZone('depot-a').map(e => e.id),
'depot-b': engine.entitiesInZone('depot-b').map(e => e.id),
}
}
engine.ingest([
{ id: 'truck-1', x: 5, y: 5, tMs: Date.now() },
{ id: 'truck-2', x: 25, y: 5, tMs: Date.now() },
])
console.log(depotSummary())
// { 'depot-a': ['truck-1'], 'depot-b': ['truck-2'] }
Performance
All five query methods scan the full set of known entities in O(N). For fleets of up to tens of thousands of entities this is fast enough to call synchronously after each ingest batch. There is no separate index to maintain — the engine's in-memory state is the source of truth.