import type { EditorDocument } from "../editor/types.js"; import type { Waypoint } from "./pathFollow.js"; /** A junction where lane spans meet. */ export interface LaneNode { id: string; at: Waypoint; } /** One directed lane span to resolve into the graph. */ export interface LaneEdgeConfig { id: string; /** World-space centerline, in travel order. */ points: readonly Waypoint[]; /** Junction ids; omitted endpoints are joined geometrically by {@link LaneGraphConfig.joinRadius}. */ from?: string; to?: string; /** Speed limit in world units per second. */ speed?: number; width?: number; /** Ids of the parallel lanes on either side, used for lane changes. */ left?: string; right?: string; /** Arc positions, in metres, of parking spots on this lane. */ parking?: readonly number[]; /** Allowed as a traffic spawn point. */ entry?: boolean; /** Allowed as a traffic removal point. */ exit?: boolean; } /** Signal timing for one intersection; phases list the in-lanes each green window serves. */ export interface LaneSignalProgram { greenSeconds: number; yellowSeconds: number; /** Red-for-all interval between phases. Default 0. */ allRedSeconds?: number; /** * In-lane ids served by each green phase, in cycle order. Omitted lets the traffic runtime derive * them: one green per line of travel, so opposite approaches share a window. */ phases?: readonly (readonly string[])[]; } /** How an intersection resolves which approach may enter next. */ export type LaneRightOfWay = "signal" | "priority"; /** Right-of-way and signal timing for one authored crossing. */ export interface LaneIntersectionConfig { node: string; /** Default `"priority"` (first come, first served) unless a signal program is given. */ kind?: LaneRightOfWay; signal?: LaneSignalProgram; /** Metres before the lane end where a car holds at the stop line. Default 6. */ stopLine?: number; /** Seconds the signal cycle is shifted, to unsynchronize a street of intersections. Default 0. */ offsetSeconds?: number; } /** A resolved lane span: centerline, arc lengths, limit and adjacency. */ export interface LaneSpan { id: string; from: string; to: string; points: readonly Waypoint[]; /** Per-segment lengths; one fewer than `points`. */ segmentLengths: readonly number[]; length: number; speed: number; width: number; left: string | null; right: string | null; parking: readonly number[]; entry: boolean; exit: boolean; } /** A resolved crossing: the lanes that feed it, the lanes that leave it, and its right-of-way. */ export interface LaneIntersection { node: string; at: Waypoint; kind: LaneRightOfWay; inLanes: readonly string[]; outLanes: readonly string[]; stopLine: number; signal: LaneSignalProgram | null; offsetSeconds: number; } /** A parking spot projected onto one lane at an arc position. */ export interface LaneSpot { id: string; lane: string; /** Arc, in metres, along the lane where a car stands parked. */ arc: number; } /** World pose of a lane at an arc position. */ export interface LanePose { laneId: string; arc: number; position: Waypoint; /** Yaw of travel, matching engine `rotationY`. */ heading: number; } /** The authored lane graph: junctions, directed spans, crossings and parking spots. */ export interface LaneGraphConfig { /** Junction positions; lanes may name them in `from`/`to` instead of joining by geometry. */ nodes?: readonly LaneNode[]; lanes: readonly LaneEdgeConfig[]; intersections?: readonly LaneIntersectionConfig[]; spots?: readonly LaneSpot[]; /** Distance within which two lane endpoints are the same junction. Default 3. */ joinRadius?: number; } /** * Authored lane topology: junctions, directed spans with speed limits and arc lengths, crossings with * their right-of-way, and parking spots. Positions come from the spans themselves, so a traffic * runtime never re-derives geometry or runs a path search per vehicle. */ export interface LaneGraph { node(id: string): LaneNode | null; lane(id: string): LaneSpan | null; laneIds(): readonly string[]; nodeIds(): readonly string[]; outLanes(nodeId: string): readonly string[]; inLanes(nodeId: string): readonly string[]; intersection(nodeId: string): LaneIntersection | null; intersections(): readonly LaneIntersection[]; spots(): readonly LaneSpot[]; spot(id: string): LaneSpot | null; /** Lanes a car may spawn on: an authored entry, or a lane whose start has no inbound traffic. */ entries(): readonly string[]; /** Lanes that leave the graph: an authored exit, or a lane that ends where nothing continues. */ exits(): readonly string[]; /** World pose at `arc` metres, shifted `lateral` metres to the driver's left. */ pose(laneId: string, arc: number, lateral?: number): LanePose | null; /** Arc on `laneId` nearest a world XZ point, clamped to the span. */ project(laneId: string, x: number, z: number): number; /** Travel heading at `arc` along a lane, in radians. */ heading(laneId: string, arc: number): number; } /** * Write the world pose at `arc` along a lane into a caller-owned record — the allocation-free form * {@link LaneGraph.pose} wraps, for a runtime that poses hundreds of cars per tick. * @internal */ export declare function lanePoseInto(lane: LaneSpan, arc: number, lateral: number, out: { x: number; y: number; z: number; heading: number; }): void; /** * Read handle over the graph resolved once at construction. The build mutates its working set; this * object never changes, so a save system rebuilds it from the scene document instead of serializing it. * * @capability lane-graph directed lane topology with junctions, signals and parking for vehicle traffic */ export declare function createLaneGraph(config: LaneGraphConfig): LaneGraph; /** How the document reader recognizes authored lane content. */ export interface LaneGraphDocumentOptions { /** Path kinds authored as one directed lane each. Default `["traffic_lane"]`. */ laneKinds?: readonly string[]; /** Path kinds authored as a two-way road centerline, expanded into a lane per direction. Default `["road"]`. */ roadKinds?: readonly string[]; /** Marker kinds that carry an intersection's right-of-way in `meta`. Default `["traffic_intersection"]`. */ intersectionKinds?: readonly string[]; /** Marker kinds that place a parking spot. Default `["traffic_parking"]`. */ parkingKinds?: readonly string[]; /** Distance within which lane endpoints and markers join a junction. Default 3. */ joinRadius?: number; /** Speed limit, in world units per second, by authored `meta.level`. */ speedByLevel?: Readonly>; /** Speed limit for a path with no recognized level. Default 13. */ defaultSpeed?: number; } /** * Read a lane graph out of an authored scene document. `traffic_lane` paths are one directed lane each; * `road` paths (the editor's street bake) become a lane per direction, offset onto their own side of * the road; `traffic_intersection` markers carry a signal program and right-of-way in `meta`; * `traffic_parking` markers place parking spots. Runtime positions come from the paths, so editing a * road moves its traffic instead of leaving a duplicate lane behind. * * @capability lane-graph-from-scene read an authored lane graph, signals and parking out of the scene document */ export declare function laneGraphFromDocument(doc: Pick, options?: LaneGraphDocumentOptions): LaneGraph;