NRF SDK 0.9

Reading and acting

Understand positions and topology

Join a position to its track, convert distances and handle partial networks without inventing a route.

A track, a fraction and a direction

After game.snapshot(), use observation.track(id) and platform(id) for already indexed joins. To frequently look up nodes or track metrics, build your indexes once from nodes and trackMetrics in that same batch. A Position contains trackId, fraction and direction. The fraction runs from 0 to 1 from the track origin; direction +1 or −1 describes traversal and does not change that origin.

JVM class: index metrics once per capture
package wiki.trackpositions

import fr.nimby.sdk.Observation
import fr.nimby.sdk.Position
import fr.nimby.sdk.TrackDirection
import fr.nimby.sdk.TrackId

class TrackPositions(snapshot: Observation) {
    private val metrics = snapshot.trackMetrics?.associateBy { it.trackId }

    fun atMetres(track: TrackId, offsetM: Double, direction: TrackDirection): Position? {
        val metric = metrics?.get(track.value) ?: return null
        if (!offsetM.isFinite() || offsetM !in 0.0..metric.lengthM) return null
        return metric.positionAtMetres(offsetM, direction)
    }
}

Create TrackPositions with the returned Observation, then call atMetres for the required tracks. This example function returns null when the metric is missing or the distance lies outside the track; it avoids a linear search for every position. Replace the index when adopting a new snapshot.

ConversionContract
metric.offsetM(fraction)Distance from the origin, with a finite fraction in [0, 1].
metric.fraction(offsetM)Finite distance between 0 and lengthM; no extrapolation.
metric.distanceM(a, b)Positive distance on this same track, with no route selection.
metric.positionAtMetres(m, direction)Locally calculated position; this result does not authorise construction.

Handle missing relationships

A capture may not supply every relationship. A missing node link does not prove there is a buffer stop. A junction describes connections and directions, not a train’s reserved route. Traversals must detect cycles, branches and missing references, with a distance or segment-count limit.

DataInterpretation
TrackUsageAn interval on a track associated with a train. Intervals may overlap; their order does not form a path.
reservations / occupationsnull: table unavailable. A supplied table describes reservations and physical occupation separately.
selectedPathObserved path for the selected train in a full capture; do not infer it from sorted reservations.
PlatformConnects a platform track to a station; not every track is a platform.

The specialised game.trains.snapshot does not request the full network. Its track or occupation tables therefore cannot establish that the map is empty. In a Native tool, start from context.network() and the tool API topology helpers to avoid reimplementing those traversals.