|
| 1 | +--- |
| 2 | +sidebar_position: 2 |
| 3 | +--- |
| 4 | + |
| 5 | +# Converter Pipeline |
| 6 | + |
| 7 | +This page describes the end-to-end conversion flow for `osi3.GroundTruth → foxglove.SceneUpdate`, the primary converter. For general information about message converters, see the [Lichtblick message converter guide](https://lichtblick-suite.github.io/docs/guides/create-message-converter). |
| 8 | + |
| 9 | +## Pipeline stages |
| 10 | + |
| 11 | +### 1. Configuration |
| 12 | + |
| 13 | +The converter reads panel settings from `event.topicConfig` (typed as `GroundTruthPanelSettings`). If no config is provided, it falls back to `DEFAULT_CONFIG`. |
| 14 | + |
| 15 | +A **config signature** (JSON-stringified config) is computed. If the signature differs from the previous frame, all caches are invalidated. |
| 16 | + |
| 17 | +### 2. Host vehicle resolution |
| 18 | + |
| 19 | +The host vehicle is identified by `message.host_vehicle_id.value`. If absent, a fallback from the SensorView wrapper is used. Warnings are emitted via `emitAlert()` for: |
| 20 | + |
| 21 | +- Missing host vehicle ID (both sources) |
| 22 | +- Host vehicle ID not found in `moving_object` array |
| 23 | +- Divergence between GroundTruth and SensorView host vehicle IDs |
| 24 | + |
| 25 | +### 3. Frame cache check |
| 26 | + |
| 27 | +If caching is enabled, the converter checks a `WeakMap<GroundTruth, entities>` keyed by config signature. If the exact same message object was already converted with the same config, the cached result is returned immediately. |
| 28 | + |
| 29 | +### 4. Deletion detection |
| 30 | + |
| 31 | +For each entity type, the converter compares current-frame entity IDs against a stored `Set<number>` from the previous frame. Missing IDs generate `SceneEntityDeletion` entries with the current timestamp. |
| 32 | + |
| 33 | +### 5. Entity building |
| 34 | + |
| 35 | +Entities are built by feature modules in this order: |
| 36 | + |
| 37 | +| Step | Feature | Condition | Builder | |
| 38 | +|------|---------|-----------|---------| |
| 39 | +| 1 | Moving objects | Always | `buildMovingObjectEntity()` | |
| 40 | +| 2 | Stationary objects | Always | `buildStationaryObjectEntity()` | |
| 41 | +| 3 | Traffic signs | Always | `buildTrafficSignEntity()` | |
| 42 | +| 4 | Traffic lights | Always | `buildTrafficLightEntity()` | |
| 43 | +| 5 | Road markings | Always (STOP only) | `buildRoadMarkingEntity()` | |
| 44 | +| 6 | Lane boundaries | `showPhysicalLanes` | `buildLaneBoundaryEntity()` | |
| 45 | +| 7 | Lanes | `showPhysicalLanes` | `buildLaneEntity()` | |
| 46 | +| 8 | Logical lane boundaries | `showLogicalLanes` | `buildLogicalLaneBoundaryEntity()` | |
| 47 | +| 9 | Logical lanes | `showLogicalLanes` | `buildLogicalLaneEntity()` | |
| 48 | +| 10 | Reference lines | `showReferenceLines` | `buildReferenceLineEntity()` | |
| 49 | + |
| 50 | +### 6. Geometry cache reuse |
| 51 | + |
| 52 | +Lane and boundary entities are expensive to rebuild. The converter uses geometry-aware caching: |
| 53 | + |
| 54 | +``` |
| 55 | +Compute hash of lane_boundary IDs |
| 56 | + → If cached, reuse lane boundary entities (skip rebuild) |
| 57 | + → If boundaries unchanged, check lane cache too |
| 58 | + → Same logic for logical lanes/boundaries |
| 59 | +``` |
| 60 | + |
| 61 | +See [Caching](caching.md) for details. |
| 62 | + |
| 63 | +### 7. State update |
| 64 | + |
| 65 | +After building entities: |
| 66 | + |
| 67 | +- Update `previousXyzIds` sets for next frame's deletion detection |
| 68 | +- Store current config and config signature |
| 69 | +- Populate frame cache and geometry caches |
| 70 | + |
| 71 | +### 8. Return |
| 72 | + |
| 73 | +```typescript |
| 74 | +{ |
| 75 | + deletions: SceneEntityDeletion[], // Entities removed since last frame |
| 76 | + entities: SceneEntity[] // All current-frame entities |
| 77 | +} |
| 78 | +``` |
| 79 | + |
| 80 | +## Error handling |
| 81 | + |
| 82 | +The entire conversion is wrapped in `try/catch`. On failure: |
| 83 | + |
| 84 | +- Error is logged to `console.error` |
| 85 | +- An alert is emitted with `severity: "error"` |
| 86 | +- An empty `SceneUpdate` (no entities) is returned — deletions are still applied |
| 87 | +- Exceptions never propagate to the Lichtblick runtime |
| 88 | + |
| 89 | +## Feature builder pattern |
| 90 | + |
| 91 | +Each feature module exports: |
| 92 | + |
| 93 | +- `build*Entity()` — Creates a `PartialSceneEntity` with Foxglove primitives (cubes, models, triangles, arrows) |
| 94 | +- `build*Metadata()` — Creates `KeyValuePair[]` metadata for panel displays |
| 95 | + |
| 96 | +Builders receive the OSI entity cast as `DeepRequired<T>` (from `ts-essentials`), which satisfies TypeScript but does **not** validate field presence at runtime. |
0 commit comments