# lddl/horizon architecture

> Architecture diagram of the GitHub repository lddl/horizon, generated by GitDiagram from its file tree, README and a sample of source files (last updated 2026-09-27). It is an AI-made overview: check details against the source.

- Interactive diagram: https://gitdiagram.com/lddl/horizon
- Repository: https://github.com/lddl/horizon

## Overview

Horizon turns prepared OpenStreetMap road-graph CSVs into a queryable routing and map-matching service. At startup, the server loads the graph and spatial edge data; clients then submit GPS traces or route/isochrone requests through REST, with gRPC available as an optional API. Map matching searches for nearby road candidates and evaluates likely paths; routing and isochrone operations use the graph to produce results. The README documents these capabilities, while only selected implementation excerpts were available, so uncertain internal call links are omitted.

Main entry points: [`map_matcher.go`](https://github.com/lddl/horizon/blob/master/map_matcher.go) (Map matcher), [`map_engine.go`](https://github.com/lddl/horizon/blob/master/map_engine.go) (Map engine), [`cmd/horizon/main.go`](https://github.com/lddl/horizon/blob/master/cmd/horizon/main.go) (Server startup), [`rpc/service.go`](https://github.com/lddl/horizon/blob/master/rpc/service.go) (gRPC service)

## Diagram (Mermaid)

```mermaid
flowchart TD

subgraph group_ingest["Graph loading"]
  node_csv["Prepared graph CSVs"]
  node_engine["Map engine<br/>[map_engine.go]"]
  node_lookup["CSV column lookup<br/>[csv_lookup.go]"]
  node_cost["Edge cost resolution<br/>[cost_resolver.go]"]
end

subgraph group_core["Routing core"]
  node_graph["Road graph<br/>[edge_graph.go]"]
  node_ch["CH query graph"]
  node_spatial[("Spatial edge index<br/>[storage.go]")]
  node_geometry["Road geometry<br/>[edge.go]"]
  node_isoengine["Isochrone computation"]
end

subgraph group_api["Service APIs"]
  node_main["Server startup<br/>[main.go]"]
  node_restmatch["REST map match<br/>[map_match.go]"]
  node_restshort["REST shortest path<br/>[shortest_path.go]"]
  node_restiso["REST isochrones<br/>[isochrones.go]"]
  node_rpc["gRPC service<br/>[service.go]"]
  node_rpcmatch["gRPC map match<br/>[map_match.go]"]
  node_rpcshort["gRPC shortest path<br/>[shortest_path.go]"]
  node_rpciso["gRPC isochrones<br/>[isochrones.go]"]
end

subgraph group_match["Map matching"]
  node_matcher["Map matcher<br/>[map_matcher.go]"]
  node_gps["GPS measurements<br/>[gps_measurement.go]"]
  node_candidate["Road candidates<br/>[candidates.go]"]
  node_hmm["HMM probabilities"]
  node_matchresult["Match results"]
end

node_actor(("API client"))

node_csv -->|"loads"| node_engine
node_engine -->|"reads headers"| node_lookup
node_engine -->|"resolves costs"| node_cost
node_engine -->|"builds graph"| node_graph
node_engine -->|"indexes edges"| node_spatial
node_engine -->|"loads geometry"| node_geometry
node_actor -->|"posts trace"| node_restmatch
node_actor -->|"requests route"| node_restshort
node_actor -->|"requests area"| node_restiso
node_main -->|"loads graph"| node_engine
node_main -->|"registers handler"| node_restmatch
node_main -->|"registers handler"| node_restshort
node_main -->|"registers handler"| node_restiso
node_restmatch -->|"runs matching"| node_matcher
node_matcher -->|"uses observations"| node_gps
node_matcher -->|"searches nearby"| node_spatial
node_matcher -->|"generates candidates"| node_candidate
node_matcher -->|"scores paths"| node_hmm
node_matcher -->|"returns matches"| node_matchresult
node_restshort -->|"queries route"| node_matcher
node_restiso -->|"queries area"| node_matcher
node_matcher -->|"queries graph"| node_graph
node_graph -->|"uses CH routing"| node_ch
node_matcher -->|"computes isochrones"| node_isoengine
node_main -.->|"optionally starts"| node_rpc
node_rpc -->|"dispatches RPC"| node_rpcmatch
node_rpc -->|"dispatches RPC"| node_rpcshort
node_rpc -->|"dispatches RPC"| node_rpciso
node_rpcmatch -->|"runs matching"| node_matcher
node_rpcshort -->|"queries route"| node_matcher
node_rpciso -->|"queries area"| node_matcher

click node_engine "https://github.com/lddl/horizon/blob/master/map_engine.go"
click node_lookup "https://github.com/lddl/horizon/blob/master/csv_lookup.go"
click node_cost "https://github.com/lddl/horizon/blob/master/cost_resolver.go"
click node_graph "https://github.com/lddl/horizon/blob/master/edge_graph.go"
click node_spatial "https://github.com/lddl/horizon/blob/master/spatial/storage.go"
click node_geometry "https://github.com/lddl/horizon/blob/master/spatial/edge.go"
click node_matcher "https://github.com/lddl/horizon/blob/master/map_matcher.go"
click node_gps "https://github.com/lddl/horizon/blob/master/gps_measurement.go"
click node_candidate "https://github.com/lddl/horizon/blob/master/candidates.go"
click node_hmm "https://github.com/lddl/horizon/blob/master/hmm_probabilities.go"
click node_matchresult "https://github.com/lddl/horizon/blob/master/map_matcher_result.go"
click node_main "https://github.com/lddl/horizon/blob/master/cmd/horizon/main.go"
click node_restmatch "https://github.com/lddl/horizon/blob/master/rest/map_match.go"
click node_restshort "https://github.com/lddl/horizon/blob/master/rest/shortest_path.go"
click node_restiso "https://github.com/lddl/horizon/blob/master/rest/isochrones.go"
click node_rpc "https://github.com/lddl/horizon/blob/master/rpc/service.go"
click node_rpcmatch "https://github.com/lddl/horizon/blob/master/rpc/map_match.go"
click node_rpcshort "https://github.com/lddl/horizon/blob/master/rpc/shortest_path.go"
click node_rpciso "https://github.com/lddl/horizon/blob/master/rpc/isochrones.go"
click node_isoengine "https://github.com/lddl/horizon/blob/master/isochrones_wrapper.go"

classDef toneNeutral fill:#f8fafc,stroke:#334155,stroke-width:1.5px,color:#0f172a
classDef toneBlue fill:#dbeafe,stroke:#2563eb,stroke-width:1.5px,color:#172554
classDef toneAmber fill:#fef3c7,stroke:#d97706,stroke-width:1.5px,color:#78350f
classDef toneMint fill:#dcfce7,stroke:#16a34a,stroke-width:1.5px,color:#14532d
classDef toneRose fill:#ffe4e6,stroke:#e11d48,stroke-width:1.5px,color:#881337
classDef toneIndigo fill:#e0e7ff,stroke:#4f46e5,stroke-width:1.5px,color:#312e81
classDef toneTeal fill:#ccfbf1,stroke:#0f766e,stroke-width:1.5px,color:#134e4a
class node_csv,node_engine,node_lookup,node_cost,node_actor toneBlue
class node_graph,node_ch,node_spatial,node_geometry,node_isoengine toneAmber
class node_main,node_restmatch,node_restshort,node_restiso,node_rpc,node_rpcmatch,node_rpcshort,node_rpciso toneMint
class node_matcher,node_gps,node_candidate,node_hmm,node_matchresult toneRose
```

## Components

### Graph loading

- **Prepared graph CSVs**
- [Map engine](https://github.com/lddl/horizon/blob/master/map_engine.go): `map_engine.go`
- [CSV column lookup](https://github.com/lddl/horizon/blob/master/csv_lookup.go): `csv_lookup.go`
- [Edge cost resolution](https://github.com/lddl/horizon/blob/master/cost_resolver.go): `cost_resolver.go`

### Routing core

- [Road graph](https://github.com/lddl/horizon/blob/master/edge_graph.go): `edge_graph.go`
- **CH query graph**
- [Spatial edge index](https://github.com/lddl/horizon/blob/master/spatial/storage.go): `spatial/storage.go`
- [Road geometry](https://github.com/lddl/horizon/blob/master/spatial/edge.go): `spatial/edge.go`
- [Isochrone computation](https://github.com/lddl/horizon/blob/master/isochrones_wrapper.go): `isochrones_wrapper.go`

### Service APIs

- [Server startup](https://github.com/lddl/horizon/blob/master/cmd/horizon/main.go): `cmd/horizon/main.go`
- [REST map match](https://github.com/lddl/horizon/blob/master/rest/map_match.go): `rest/map_match.go`
- [REST shortest path](https://github.com/lddl/horizon/blob/master/rest/shortest_path.go): `rest/shortest_path.go`
- [REST isochrones](https://github.com/lddl/horizon/blob/master/rest/isochrones.go): `rest/isochrones.go`
- [gRPC service](https://github.com/lddl/horizon/blob/master/rpc/service.go): `rpc/service.go`
- [gRPC map match](https://github.com/lddl/horizon/blob/master/rpc/map_match.go): `rpc/map_match.go`
- [gRPC shortest path](https://github.com/lddl/horizon/blob/master/rpc/shortest_path.go): `rpc/shortest_path.go`
- [gRPC isochrones](https://github.com/lddl/horizon/blob/master/rpc/isochrones.go): `rpc/isochrones.go`

### Map matching

- [Map matcher](https://github.com/lddl/horizon/blob/master/map_matcher.go): `map_matcher.go`
- [GPS measurements](https://github.com/lddl/horizon/blob/master/gps_measurement.go): `gps_measurement.go`
- [Road candidates](https://github.com/lddl/horizon/blob/master/candidates.go): `candidates.go`
- [HMM probabilities](https://github.com/lddl/horizon/blob/master/hmm_probabilities.go): `hmm_probabilities.go`
- [Match results](https://github.com/lddl/horizon/blob/master/map_matcher_result.go): `map_matcher_result.go`

### Other components

- **API client**

## Connections

- Prepared graph CSVs → Map engine: loads
- Map engine → CSV column lookup: reads headers
- Map engine → Edge cost resolution: resolves costs
- Map engine → Road graph: builds graph
- Map engine → Spatial edge index: indexes edges
- Map engine → Road geometry: loads geometry
- API client → REST map match: posts trace
- API client → REST shortest path: requests route
- API client → REST isochrones: requests area
- Server startup → Map engine: loads graph
- Server startup → REST map match: registers handler
- Server startup → REST shortest path: registers handler
- Server startup → REST isochrones: registers handler
- REST map match → Map matcher: runs matching
- Map matcher → GPS measurements: uses observations
- Map matcher → Spatial edge index: searches nearby
- Map matcher → Road candidates: generates candidates
- Map matcher → HMM probabilities: scores paths
- Map matcher → Match results: returns matches
- REST shortest path → Map matcher: queries route
- REST isochrones → Map matcher: queries area
- Map matcher → Road graph: queries graph
- Road graph → CH query graph: uses CH routing
- Map matcher → Isochrone computation: computes isochrones
- Server startup → gRPC service: optionally starts
- gRPC service → gRPC map match: dispatches RPC
- gRPC service → gRPC shortest path: dispatches RPC
- gRPC service → gRPC isochrones: dispatches RPC
- gRPC map match → Map matcher: runs matching
- gRPC shortest path → Map matcher: queries route
- gRPC isochrones → Map matcher: queries area
