Lightshadow
Español English

Cómo se construye el grafo de rutas

El método por el que Lightshadow convierte datos de OpenStreetMap en el grafo sobre el que calcula rutas peatonales. Es una descripción técnica del código que lo hace, no una explicación del producto.

Para qué es esta página

Las calles de Lightshadow proceden de OpenStreetMap, una base de datos publicada bajo la Open Database License (ODbL). Cuando alguien extrae una parte de esa base de datos, la filtra y la transforma en otra cosa — aquí, un grafo de rutas — la licencia llama al resultado «base de datos derivada», y a lo que se muestra al público a partir de ella (las rutas de la aplicación) «obra producida».

La licencia dice que quien hace pública una obra producida a partir de una base de datos derivada tiene que ofrecer a quien la recibe, gratis por internet y en forma legible por máquina, una de dos cosas: o bien la base derivada entera, o bien un fichero con todas las alteraciones hechas a la base original, o el método por el que se hicieron — la licencia pone «un algoritmo» como ejemplo — incluido cualquier contenido añadido. Esa es la sección 4.6 de la ODbL, y las dos opciones son sus apartados (a) y (b). Esta página es la opción (b): describe el método completo, con los filtros, las etiquetas y las constantes exactas que usa el código. El aviso de atribución que la sección 4.3 exige en la propia obra está en la aplicación, en la pantalla «Licencias», y al pie de esta página.

1. Qué se descarga de OpenStreetMap, y cómo

Se pide a la Overpass API el conjunto de vías (way) de la ciudad cuya etiqueta highway tiene uno de estos dieciocho valores:

residential  living_street  pedestrian  footway  path  steps
service  unclassified  tertiary  tertiary_link  secondary  secondary_link
primary  primary_link  cycleway  track  bridleway  corridor

La lista es la constante HIGHWAY_WALK del motor de rutas y es la misma que decide, más adelante, qué vías son transitables a pie. La consulta, tal como se envía por cada bloque de la ciudad, es:

[out:json][timeout:180];
way["highway"~"^(residential|living_street|…|corridor)$"](S,W,N,E);
out geom;

La caja de la ciudad se divide en bloques de 0,02° de lado (unos 2 km) y se pide cada bloque por separado, con una pausa de 4 s entre peticiones, probando tres espejos de Overpass por orden. out geom devuelve, con cada vía, las coordenadas de sus nodos; una vía cuya lista de nodos y cuya geometría no tienen la misma longitud (una vía recortada por el borde del bloque) se descarta. Solo se piden vías: no se descargan nodos sueltos ni relaciones, así que un paso de peatones cartografiado como nodo (highway=crossing sobre un nodo) no está en los datos.

packages/api/tools/fetch_full_ways.py (consulta, bloques, espejos); packages/api/tools/build_ways.py (artefacto).

Qué etiquetas se conservan

De cada vía se guardan su identificador OSM, la lista de identificadores de nodo, las coordenadas y estas diez etiquetas; el resto se descarta:

highway  foot  access  bicycle  name  name:ca  name:es  footway  crossing  bridge

El resultado se escribe en un fichero comprimido (valencia_ways.json.gz) que va incluido con el servicio. El servicio nunca consulta OpenStreetMap en vivo: todo lo que sabe de las calles está en ese fichero.

2. Cómo las vías se convierten en grafo

  1. Filtro de transitabilidad. Se descarta una vía si su highway no está en la lista anterior, si lleva access=private o si lleva foot=no. (En el modo bicicleta, que la aplicación no ofrece, la lista es otra y se descarta bicycle=no.)
  2. Proyección. Las coordenadas se pasan a metros con una proyección equirectangular centrada en la ciudad.
  3. Partición en aristas. Se cuenta cuántas vías usan cada nodo. Cada vía se corta en los nodos que comparte con otra vía (y en su último nodo): cada trozo es una arista del grafo y sus dos extremos, nodos. Un trozo de menos de 0,5 m se descarta. El nodo del grafo conserva el identificador de nodo de OSM.
  4. Componente principal. Se etiquetan las componentes conexas y se recuerda la mayor. Al buscar el nodo más cercano a un punto de origen o destino solo se miran los nodos de esa componente, para que una isla desconectada nunca reciba una ruta.

Cada arista guarda: sus dos nodos, la polilínea en metros y en grados, su longitud, una fracción de sol (que no procede de OSM, véase §3) y una marca on_deck (§3). Además el servicio anota, por arista, la vía OSM de la que salió — su nombre (name, y name:es para la forma castellana) y su clase highway — para poder nombrar cada tramo en las indicaciones.

packages/engine/sombra_engine/routing.py — _is_usable, build_graph, _label_components, nearest_node; packages/engine/sombra_engine/geo.py — Projection.

Medido sobre el artefacto de València que se sirve hoy

magnitudvalor
vías descargadas67.152 (clases presentes: 17 de 18; no hay bridleway en la caja)
vías transitables66.308 (554 descartadas por access=private, 290 más por foot=no)
nodos / aristas108.622 / 158.896, 6.372,4 km de arista

Vías: contadas en packages/api/data/valencia_ways.json.gz (descarga del 30 de septiembre de 2026) con el filtro de routing._is_usable. Nodos, aristas y kilómetros: la construcción del grafo de ese mismo artefacto, 30 de septiembre de 2026.

3. Qué se deriva por arista

Fracción de sol

No viene de OSM: se calcula aparte, en cada petición de ruta. Esta página describe únicamente cómo se obtiene el grafo a partir de OpenStreetMap.

Lado de la calle

Las aristas se dividen en dos clases por su etiqueta highway. Si la vía es una calzada (residential, living_street, service, unclassified, tertiary, tertiary_link, secondary, secondary_link, primary, primary_link, road), tiene dos aceras y el buscador de rutas elige lado. Si la vía es ya la superficie peatonal (footway, path, steps, pedestrian, cycleway, track, corridor, bridleway), no hay lado que elegir.

Dónde se puede cruzar

Solo se cambia de acera en un nodo donde OSM cartografía un paso de peatones, y el cambio cuesta 12 m equivalentes; en ningún otro nodo se cruza. Un nodo cuenta como paso si pertenece a una vía con footway=crossing o con cualquier valor de crossing=*; las dos etiquetas se comprueban porque en este artefacto 9.384 vías llevan crossing=* frente a 8.481 con footway=crossing. Como solo se descargaron vías, los pasos cartografiados como nodo no cuentan (§1).

Tableros de puente (on_deck)

El motor marca una arista como «sobre tablero» si su vía lleva bridge=* con cualquier valor salvo no, abandoned, dismantled, razed, demolished. En el artefacto que se sirve hoy, 876 vías llevan un valor así.

routing.py — on_bridge, route; sombra_api/artefacts.py — CARRIAGEWAY_CLASSES, _is_crossing_way, _derive_crossing_nodes; sombra_api/config.py — CROSSING_PENALTY_M 12.

4. Fecha de los datos

El artefacto de vías guarda en su cabecera la fecha de la descarga (fetched_utc), la herramienta que la hizo, el número de bloques, la caja resultante y la lista de clases highway realmente presentes, calculada a partir del contenido y no escrita a mano. Para València, el artefacto que se sirve hoy:

fetched_utc2026-09-30T10:55:36Z
fetched_bypackages/api/tools/fetch_full_ways.py
chunk_files125
bbox−0,4441 39,2635 → −0,2757 39,5821
way_count67.152

Qué fecha es esa exactamente. fetched_utc es la hora de modificación del bloque de caché más reciente, es decir, el momento de la descarga. La respuesta de Overpass trae también la marca de tiempo de la propia base de datos de OSM (osm3s.timestamp_osm_base), pero la caché guarda solo los elementos, no esa cabecera, así que la fecha de estado de la base de datos de OSM no queda registrada; la descarga es su cota superior. Es una carencia conocida del método.

build_ways.py — fetched_utc = mtime del bloque más reciente; fetch_full_ways.py — la caché guarda r.json()["elements"].

Créditos y licencia

  • Datos de calles © los colaboradores de OpenStreetMap, disponibles bajo la Open Database License (ODbL) — openstreetmap.org/copyright. El grafo de rutas descrito aquí es una base de datos derivada de OpenStreetMap, y esta página es el método de derivación que la sección 4.6(b) de la ODbL pide publicar.