Files
osmWorkflow/docs/v2x-cesium-preview.md

6.5 KiB

Live V2X Cesium Preview

The Cesium preview displays live V2X operational data on a compiled native intersection. The package manifest, native road geometry, and traffic signals remain independent of the service. Vehicle entities and their trace lines are created only from authenticated V2X streams; generated routes and traffic simulation are never rendered as a substitute.

Configuration

Add a non-sensitive v2xPreview object to the area configuration:

{
  "v2xPreview": {
    "enabled": true,
    "apiBaseUrl": "/api",
    "wsBaseUrl": "/websocket",
    "crossCode": "420100023333"
  }
}

apiBaseUrl and wsBaseUrl should normally be relative, same-origin paths. The deployment server proxies them to the V2X REST and WebSocket services. Do not commit a private upstream address, an account, a token, or an AMap key. crossCode is deployment configuration for the selected intersection. It is never shown or editable in the browser login panel.

Optional phase binding overrides

traffic-signals.json carries no V2X phase number, so live phases are bound to native signal heads geometrically (see Phase Binding below). Three optional keys tune or replace that binding:

Key Default Purpose
maxDistanceMeters 30 Stop-line proximity tolerance.
maxHeadingDeltaDegrees 45 Approach heading tolerance.
phaseSignalMap none Explicit {"<phaseNo>": ["<nodeKey>", …]}; bypasses geometry for the listed phases.

Use phaseSignalMap when the V2X link geometry cannot be matched — the V2X panel reports how many phases bound and how many did not.

The page always starts at the login gate. After authentication it resolves the current intersection with the same source-dashboard rule: request the HD-map cross list and cross-device configuration list, prefer a configured cross, then use the first available HD-map cross. Only after that resolution succeeds does it issue the operational REST requests or open signal, OBU, and target-vehicle WebSockets.

The browser sends POST {apiBaseUrl}/facilities/api/sys/login with userName and an MD5-hashed password, matching the source V2X dashboard. It holds the returned token in sessionStorage only, sends it as the raw Authorization header for REST calls, and uses it as the authorization parameter for the signal WebSocket. Closing the tab clears the session token.

Data Sources

After sign-in the preview reads the selected intersection's links, pole configuration, bound devices, and device configuration, and subscribes to /network/ws/network/signal for phase updates. It also subscribes to /network/ws/network/obuPosition and /network/ws/network/targetPosition for the only vehicle and vehicle-line sources. Failures are shown in the V2X panel; the static Cesium scene stays available and the vehicle layer stays empty.

All three sockets mirror the source dashboard's connection behaviour: a {"heartBeat":"ping"} frame every 30 s, automatic reconnect with backoff, and the subscription frame replayed on every reconnect. Without the heartbeat the service drops the connection and the scene silently empties after a minute.

Subscription frames match the dashboard exactly:

Socket Frame on every (re)connect
signal {"junctionId":"<crossCode>"}
obuPosition {"bounds":"<four GCJ-02 corners>"}, or an empty frame when the camera rectangle is unavailable (no viewport filter)
targetPosition {"deviceId":"<ids>"}, or {"deviceId":null} when no targets are configured

Phase Binding

The runtime traffic-signal document has no V2X phaseNo, so phases are bound to native signal heads by geometry: the V2X link's last segment ends at the stop line, and each native signal records its own stop-line point and heading. The generator in scripts/lib/traffic-signals.js derives mast = travel - 90 and face = travel + 180 from the approach travel direction, so the travel heading is recovered as faceHeadingDegrees + 180.

One link may bind several heads on the same approach, and several links may share one phase; both are unions, so a phase lights every approach it drives. Unbound phases are counted in the panel — override them with phaseSignalMap.

Vehicle Lifecycle

Vehicles follow the dashboard's rules: the push interval (0 falls back to 500 ms) sets the animation duration, a vehicle not updated within interval * 1.5 is hidden, and hidden entries stay as reusable slots rather than being removed. The OBU data hook calls its model car_obu.glb, but the dashboard's final CrossCars template renders 11.glb; the preview uses that final rendering contract. Targets use ${type}${subType}.glb. The dashboard vehicle assets are packaged under _preview/v2x-vehicles/. Valid live vehicles are lifted clear of the road, remain at least 28 screen pixels in overview, and the first live push focuses the camera near the vehicle group.

Coordinate Contract

Data Coordinate system Preview handling
Native package placement and traffic signals WGS84 and local ENU Existing Cesium contract; unchanged.
V2X dashboard road/link/device data GCJ-02 Converted once to WGS84 immediately before Cesium entity creation.
High德 reference GeoJSON GCJ-02 Compiler calibration input only; never loaded by this preview.

Do not convert native WGS84 data again, and do not pass V2X GCJ-02 coordinates directly to Cesium. Either error produces a visible intersection offset.

Proxy Requirements

Use an HTTPS reverse proxy which forwards the configured REST prefix and supports WebSocket upgrade for the configured WS prefix. For development or a simple host without Nginx, use the repository's proxy static server instead of python3 -m http.server:

V2X_UPSTREAM=http://<v2x-api-host>:<port>/dashboardApi \
V2X_WS_UPSTREAM=http://<v2x-ws-host>:<port>/dashboardWebsocket \
  npm run serve:v2x-preview -- --root outputs/fengshu-er-road --host 0.0.0.0 --port 7862

It rewrites /api/* and /websocket/* before proxying, matching the source dashboard's Vite proxy. The upstream address stays an environment value, not a browser configuration or committed area file. The generated preview is static, so direct cross-origin calls are likely to fail CORS or expose an internal origin.

Rollback

v2xPreview.enabled defaults to false; set it to true for a selected area. Set it back to false and regenerate the preview. The generated page omits the V2X panel; published package contents remain unchanged.