From f890dd944811b082f06e44e51367d38f81c8cac8 Mon Sep 17 00:00:00 2001 From: hacklab Date: Sat, 8 Aug 2026 22:24:17 +0200 Subject: [PATCH] =?UTF-8?q?Multi-pa=C3=ADs,=20idiomas,=20seguridad,=20inst?= =?UTF-8?q?aladores=20y=20documentaci=C3=B3n?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Seguridad - Escapado de todo lo que viene de datos de terceros antes de ir al HTML, incluidos los tooltips de Leaflet. Los nombres de municipio salen de OpenStreetMap, que cualquiera puede editar: sin escapar, era una vía de inyección de código en el navegador de quien abriera el visor. Multi-país - El país pasa a ser un parámetro (REGION). Catálogo de 27 regiones entre Europa y el norte de África, declarando por país qué datos existen de verdad. - Una malla por país y no una continental: Europa entera a 100 m son mil millones de celdas y unos 73 GB solo en capas ráster. - Proyección equiárea propia para las regiones de fuera de Europa, donde EPSG:3035 deforma. Interfaz - Idiomas: castellano, inglés, francés y portugués, con selector persistente. - Modo Mapa: el país entero sobre satélite, topográfico u OSM. - Enlaces a mapas externos en la barra inferior, siempre visibles. - Botón de ver de cerca también en la cabecera de la ficha. - Fuera la distancia desde Madrid, que centralizaba algo de uso general. Portabilidad - install.sh e install.ps1 para Linux/macOS y Windows; requirements.txt. - Sin rutas absolutas en el código. Documentación - Ocho páginas en docs/ para la wiki: instalación, uso, añadir un país, metodología, seguridad, fuentes y publicación. --- README.md | 36 ++-- abrir.ps1 | 6 + docs/Anadir-un-pais.md | 56 ++++++ docs/Fuentes-y-licencias.md | 28 +++ docs/Home.md | 34 ++++ docs/Instalacion.md | 60 ++++++ docs/Metodologia.md | 80 ++++++++ docs/Publicar.md | 48 +++++ docs/Seguridad.md | 40 ++++ docs/Uso-del-visor.md | 56 ++++++ install.ps1 | 57 ++++++ install.sh | 50 +++++ out/informe.html | 51 +---- out/visor.html | 364 ++++++++++++++++++++++++++---------- requirements.txt | 8 + src/build_viewer.py | 364 ++++++++++++++++++++++++++---------- src/config.py | 27 ++- src/dl_dem.sh | 3 +- src/regions.py | 191 +++++++++++++++++++ src/report.py | 5 +- src/score.py | 2 - src/stars.py | 2 - 22 files changed, 1288 insertions(+), 280 deletions(-) create mode 100644 abrir.ps1 create mode 100644 docs/Anadir-un-pais.md create mode 100644 docs/Fuentes-y-licencias.md create mode 100644 docs/Home.md create mode 100644 docs/Instalacion.md create mode 100644 docs/Metodologia.md create mode 100644 docs/Publicar.md create mode 100644 docs/Seguridad.md create mode 100644 docs/Uso-del-visor.md create mode 100644 install.ps1 create mode 100755 install.sh create mode 100644 requirements.txt create mode 100644 src/regions.py diff --git a/README.md b/README.md index e36b989..98ae4c0 100644 --- a/README.md +++ b/README.md @@ -9,13 +9,11 @@ explorarlas sobre relieve, ortofoto y catastro. ![vista del visor](docs/visor.png) +Documentación completa en la [wiki](../../wiki) y en `docs/`. + ## Cómo usarlo -**En el navegador, sin instalar nada** — si está publicado en GitLab Pages: -`https://.gitlab.io//`. Funciona igual en Windows, Android y -Linux. - -**En local**, tras clonar: +**Sin instalar nada**, tras clonar: ```bash xdg-open out/visor.html # Linux @@ -64,18 +62,32 @@ perfecto al que no se puede llegar no salga con cuatro estrellas. Los candidatos se eligen cogiendo el mejor punto de cada bloque de 20 km y exigiendo después 10 km de separación entre los elegidos. -## Reproducirlo +## Otros países -Hacen falta ~25 GB de disco y un par de horas. Los datos de partida no están en -el repositorio: se descargan solos. +El país es un parámetro. Hay 27 declarados entre Europa y el norte de África, +pero **solo España está calculada**: el resto hay que procesarlo. ```bash -python3 -m venv .venv -./.venv/bin/pip install numpy scipy rasterio osmium shapely pyproj requests pillow -make all +./.venv/bin/python src/regions.py # ver el catálogo +REGION=pt make all # procesar Portugal ``` -O paso a paso, ver el `Makefile`. +Una malla por país, no una continental: Europa entera a 100 m son mil millones +de celdas, 73 GB solo en capas ráster. Ver [Añadir un país](docs/Anadir-un-pais.md). + +Ojo con lo que hay disponible en cada sitio: en el norte de África **no hay +fuente libre de espacios protegidos**, así que el filtro legal no se aplica y +hay que conseguir la cartografía del país aparte. + +## Reproducirlo + +Hacen falta ~25 GB de disco por país y un par de horas. + +```bash +./install.sh # Linux y macOS +.\install.ps1 # Windows (PowerShell) +make all +``` ## Lo que este análisis no sabe diff --git a/abrir.ps1 b/abrir.ps1 new file mode 100644 index 0000000..f32b72d --- /dev/null +++ b/abrir.ps1 @@ -0,0 +1,6 @@ +# Abre el visor en el navegador por defecto (Windows). +$ErrorActionPreference = "Stop" +Set-Location -Path $PSScriptRoot +$f = if ($args[0] -eq "informe") { "out\informe.html" } else { "out\visor.html" } +if (-not (Test-Path $f)) { Write-Host "No encuentro $f" -ForegroundColor Red; exit 1 } +Start-Process (Resolve-Path $f) diff --git a/docs/Anadir-un-pais.md b/docs/Anadir-un-pais.md new file mode 100644 index 0000000..7a791b8 --- /dev/null +++ b/docs/Anadir-un-pais.md @@ -0,0 +1,56 @@ +# Añadir un país + +El país es un parámetro. Se elige con la variable `REGION`. + +```bash +./.venv/bin/python src/regions.py # ver el catálogo +REGION=pt make all # procesar Portugal entero +``` + +Los resultados van a `out/pt/` y los intermedios a `data/interim/pt/`. España, +que es la región por defecto, publica en `out/` para no romper rutas. + +## Por qué una malla por país y no un mapa continental + +Europa entera a 100 m son mil millones de celdas: **4 GB por capa** y unos +**73 GB** para las dieciocho capas del modelo, más de lo que cabe en memoria de +una vez. El norte de África añade otros 61 GB. Por país el problema es tratable +y además se puede paralelizar. + +## Lo que hay que mirar antes + +`src/regions.py` declara, por país, qué datos existen de verdad: + +| Campo | Qué significa | +|---|---| +| `protected='eea'` | Hay Red Natura 2000 y designaciones nacionales de la Agencia Europea de Medio Ambiente. El filtro legal funciona | +| `protected=None` | **No hay fuente libre equivalente.** El filtro legal no se aplica. Pasa en todo el norte de África: hay que conseguir la cartografía del país antes de fiarse de un resultado | +| `ortho='pnoa'` | Ortofoto nacional descargable. Solo España | +| `ortho=None` | Sin foto aérea incrustada. En el visor queda el mapa deslizante, que sí funciona en todas partes | + +## Proyección + +Europa usa EPSG:3035 (equiárea europea). Para el norte de África se construye +una proyección equiárea centrada en el propio país, porque 3035 deforma fuera de +Europa. Está en `regions.crs_for()`. + +## Añadir un país que no esté + +En `src/regions.py`: + +```python +"si": dict(name="Eslovenia", bbox=(13.3, 45.4, 16.6, 46.9), + osm=["europe/slovenia"], + neighbours=["europe/croatia", "europe/austria", "europe/italy"], + protected="eea", ortho=None), +``` + +- `bbox` en lon/lat con algo de margen. +- `osm` y `neighbours`, rutas de [Geofabrik](https://download.geofabrik.de). +- **Los vecinos importan.** Sin ellos, la franja fronteriza sale falsamente + vacía: el extracto está recortado por la frontera y al otro lado no hay + edificios en los datos aunque sí los haya en el terreno. + +## Coste aproximado + +Por país mediano: 2-6 GB de descarga, ~25 GB de disco temporal y un par de horas. diff --git a/docs/Fuentes-y-licencias.md b/docs/Fuentes-y-licencias.md new file mode 100644 index 0000000..34e2a91 --- /dev/null +++ b/docs/Fuentes-y-licencias.md @@ -0,0 +1,28 @@ +# Fuentes y licencias + +| Dato | Fuente | Licencia | +|---|---|---| +| Edificios, viales, agua, arbolado, roca, límites administrativos | [OpenStreetMap](https://www.openstreetmap.org/copyright) vía Geofabrik | ODbL | +| Red Natura 2000 y designaciones nacionales | Agencia Europea de Medio Ambiente / MITECO | Reutilización con atribución | +| Ortofotos PNOA (solo España) | [Instituto Geográfico Nacional](https://www.ign.es) | CC BY 4.0 | +| Cartografía catastral (solo España) | [Dirección General del Catastro](https://www.sedecatastro.gob.es) | Reutilización con atribución | +| Modelo de elevaciones | Copernicus DEM GLO-90 | Copernicus | +| Clima | [WorldClim 2.1](https://www.worldclim.org) | CC BY-SA 4.0 | +| Mapa deslizante | [Leaflet](https://leafletjs.com) 1.9.4 | BSD-2 | + +El código, MIT. Los datos mantienen la licencia de su fuente: si redistribuyes +resultados, **arrastra las atribuciones**. + +## Servicios que consulta el visor en vivo + +Solo en los modos Mapa y Ver de cerca, y solo si los activas: + +- `www.ign.es` — ortofoto PNOA y mapa topográfico +- `ovc.catastro.meh.es` — parcelas catastrales +- `geoserver.iepnb.es` — Red Natura 2000 y espacios protegidos +- `tile.openstreetmap.org` — mapa base de OSM + +Son servicios públicos con condiciones de uso razonable. El visor pide teselas +solo de lo que estás mirando; no descarga en bloque. + +El modo Relieve y todos los datos del modelo funcionan **sin conexión**. diff --git a/docs/Home.md b/docs/Home.md new file mode 100644 index 0000000..c52667b --- /dev/null +++ b/docs/Home.md @@ -0,0 +1,34 @@ +# EXPLORER + +Localiza los puntos de un país más alejados de cualquier rastro de gente **a los +que además se puede llegar** con un vehículo, y los valora de 1 a 5 estrellas. + +Barre el territorio celda a celda sobre una malla de 100 m usando datos abiertos, +descarta lo que no es viable (espacios protegidos, zonas militares, sin acceso, +demasiada pendiente) y puntúa lo que queda en seis criterios. + +## Empezar + +| Quiero… | Ir a | +|---|---| +| Solo mirar los resultados | [Uso del visor](Uso-del-visor) | +| Instalarlo en mi máquina | [Instalación](Instalacion) | +| Procesar otro país | [Añadir un país](Anadir-un-pais) | +| Entender cómo se calcula | [Metodología](Metodologia) | +| Saber qué datos usa | [Fuentes y licencias](Fuentes-y-licencias) | +| Publicarlo para más gente | [Publicar](Publicar) | + +## Estado + +Ahora mismo hay **un solo país procesado, España**, con 355 localizaciones. +El resto del catálogo (27 países entre Europa y el norte de África) está +declarado y el código los soporta, pero **sus datos no están calculados**: hay +que ejecutar el pipeline para cada uno. Ver [Añadir un país](Anadir-un-pais). + +## Aviso + +Esto localiza sitios despoblados; no es permiso para nada. Casi todo el terreno +es privado, muchas zonas tienen restricciones de acceso por incendios, y celebrar +una concentración sin autorización tiene consecuencias administrativas y, si +prende algo, penales. Comprueba propiedad, figura de protección y época del año +antes de moverte. diff --git a/docs/Instalacion.md b/docs/Instalacion.md new file mode 100644 index 0000000..31fad7a --- /dev/null +++ b/docs/Instalacion.md @@ -0,0 +1,60 @@ +# Instalación + +## Para solo mirar los resultados: nada + +El visor es un HTML. Clona el repositorio y ábrelo: + +| Sistema | Orden | +|---|---| +| Linux | `xdg-open out/visor.html` o `./abrir.sh` | +| Windows | doble clic en `out\visor.html`, o `.\abrir.ps1` | +| macOS | `open out/visor.html` | +| Android / iPhone | ver [Publicar](Publicar) | + +No hace falta servidor, ni Python, ni conexión. + +**Ojo:** `visor.html` necesita la carpeta `out/ortho/` a su lado, que es donde +están las fotos aéreas. Si mueves el HTML solo, se quedan sin cargar. + +### Si al abrirlo se abre un editor de texto + +Le pasa a quien tiene los `.html` asociados a un editor, algo habitual si +programas. `xdg-open` respeta esa asociación, no el navegador por defecto. +Usa `./abrir.sh`, que llama al navegador directamente, o arrástralo a una +ventana del navegador. + +## Para reconstruir los datos + +Hacen falta Python 3.9+, unos 25 GB de disco por país y un par de horas. + +### Linux / macOS + +```bash +./install.sh +``` + +Si falta el módulo `venv`: `sudo apt install python3-venv` en Debian/Ubuntu. + +### Windows + +```powershell +Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass +.\install.ps1 +``` + +Si no tienes Python: `winget install Python.Python.3.12`, marcando +*Add Python to PATH*. + +### Qué instala + +Solo paquetes de Python, dentro de `.venv/`, sin tocar el sistema: +`numpy`, `scipy`, `rasterio`, `osmium`, `shapely`, `pyproj`, `requests`, +`pillow`. Todos traen binarios precompilados para Linux, Windows y macOS, así +que **no hace falta compilar GDAL ni nada parecido**. + +## Comprobar que funciona + +```bash +./.venv/bin/python src/regions.py # lista los países disponibles +./.venv/bin/python src/revisar.py # comprueba la coherencia del resultado +``` diff --git a/docs/Metodologia.md b/docs/Metodologia.md new file mode 100644 index 0000000..7a3e97d --- /dev/null +++ b/docs/Metodologia.md @@ -0,0 +1,80 @@ +# Metodología + +Malla de 100 m en proyección equiárea, así que una distancia euclídea en la +malla es una distancia real en el terreno. + +## 1. Se descarta + +Una celda queda fuera, por buena que sea, si cumple alguna: + +| Condición | Por qué | +|---|---| +| En espacio protegido oficial, o a menos de 300 m del borde | Los parques se trazaron rodeando lo más vacío, y el modelo tendía a pegarse al límite, donde hay zona periférica y vigilancia | +| En zona militar o sobre agua | Obvio | +| A menos de 2 km de un edificio | Por debajo te oyen desde casa | +| A menos de 400 m de una carretera | Te ve cada coche que pasa | +| A más de 800 m de un vial | No metes un equipo más lejos | +| Más de 10° de pendiente | Ni se monta ni se aparca | + +En España sobreviven 47.519 km², el 9,5 % del país. + +## 2. Manda el sonido + +Se estima el nivel que llega a la casa más cercana con propagación real: + +``` +SPL = 130 − 20·log₁₀(d) − 0,5·d/1000 − atenuación_arbolado − apantallamiento +``` + +Divergencia esférica desde 130 dB a 1 m (equipo grande), absorción atmosférica +en frecuencias bajas (0,5 dB/km, que es lo que viaja), hasta 6 dB de absorción +por arbolado y hasta 12 dB de apantallamiento si estás en una hondonada. + +Se exige **≤ 45 dB**, el límite nocturno típico en suelo rural. Es el filtro que +de verdad corta: de 47.519 km² quedan **505 km²** en toda España. El cuello de +botella no es la soledad, es el sonido. + +## 3. Se puntúa + +| Criterio | Peso | Qué mide | +|---|---|---| +| Sonido | 30 % | Los dB del apartado anterior | +| Soledad | 22 % | Lejanía de edificios, carreteras y núcleos; densidad construida en 5 km | +| Acceso | 18 % | Pista en condiciones cerca (OSM distingue firme y grado), llano, sin pedregal | +| Agua | 12 % | Río, arroyo o fuente entre 120 y 900 m | +| Arbolado | 10 % | Entre 20 y 65 % de cobertura: sombra y pantalla sin ser impenetrable | +| Clima | 8 % | Máxima del mes más cálido y mínima del más frío, corregidas por altitud | + +Las estrellas salen de la media ponderada **penalizada por el eslabón más +débil**: un sitio perfecto al que no se puede llegar no es de cuatro estrellas. + +## 4. Se reparten + +Se divide el país en bloques de 20 km, se coge el mejor punto elegible de cada +bloque y después se exige 10 km de separación entre los elegidos. Sin ese +segundo paso salen pares casi duplicados: dos bloques vecinos pueden elegir cada +uno una celda pegada a su frontera común. + +## Trampas que costaron sangre + +- **La frontera.** El extracto de un país está recortado por su frontera, así + que al otro lado no hay edificios en los datos aunque sí en el terreno. Sin + añadir los países vecinos, toda la raya sale falsamente vacía. +- **La rejilla no está alineada con la latitud.** En EPSG:3035 baja más al sur + que la ventana de análisis, y colaba Melilla, cuyos edificios sí se habían + filtrado. Salía como el punto más aislado del país con 74,6 km. El máximo real + son 9,8 km. +- **Los protegidos de OpenStreetMap cubren el 15 %; los oficiales, el 29 %.** + Con los buenos, 33 de los 60 candidatos de la primera versión estaban dentro + de espacio protegido. +- **Sin distancia a carretera en la puntuación**, el modelo colocaba puntos de + cinco estrellas sobre el propio asfalto. + +## Lo que no sabe + +- **No ve vallas ni propiedad.** Es la mayor diferencia con la realidad de campo. + Por eso el visor lleva la capa de catastro. +- **El modelo acústico es de manual.** Una inversión térmica nocturna o el viento + a favor llevan el bajo mucho más lejos. +- **Ignora la estación.** Riesgo de incendio de junio a septiembre. +- **Distancia en línea recta, no tiempo de coche.** diff --git a/docs/Publicar.md b/docs/Publicar.md new file mode 100644 index 0000000..9dc677f --- /dev/null +++ b/docs/Publicar.md @@ -0,0 +1,48 @@ +# Publicar + +## Este repositorio está en Gitea + +**Gitea no tiene Pages integrado**, a diferencia de GitLab. Opciones: + +### Clonar y abrir (lo más simple) + +```bash +git clone https://gitea.laenre.net/hacklab/EXPLORER.git +cd EXPLORER +xdg-open out/visor.html +``` + +Funciona en Linux, Windows y macOS sin instalar nada. + +### Servirlo con cualquier servidor estático + +```bash +cd out && python3 -m http.server 8000 +``` + +Y abrir `http://localhost:8000/visor.html`. Así también funciona desde el móvil +si estás en la misma red: `http://IP-DEL-ORDENADOR:8000/visor.html`. + +Para dejarlo en un dominio, cualquier nginx/Apache sirviendo `out/` vale. No hay +backend. + +### GitLab Pages, si lo espejas + +El repositorio trae un `.gitlab-ci.yml` listo. Si creas un espejo en gitlab.com, +publica solo con hacer push y queda en +`https://USUARIO.gitlab.io/PROYECTO/`. Ese es el camino más cómodo para que lo +use gente desde el móvil sin descargar nada. + +## Móvil + +El visor se adapta a pantalla estrecha: el mapa arriba, los controles debajo y la +ficha a pantalla completa. Probado a 412 px de ancho. + +Lo que **no** está probado en un móvil real es el gesto de pellizcar para hacer +zoom en el modo Relieve, que usa eventos de puntero propios. En los modos Mapa y +Ver de cerca el zoom lo gestiona Leaflet y no hay problema. + +## Tamaño + +El repositorio son unos 18 MB: `visor.html` 3,9 MB, `informe.html` 1,8 MB y +8,4 MB de fotos aéreas. Los 22 GB de datos de partida no se versionan. diff --git a/docs/Seguridad.md b/docs/Seguridad.md new file mode 100644 index 0000000..1ba3919 --- /dev/null +++ b/docs/Seguridad.md @@ -0,0 +1,40 @@ +# Seguridad y privacidad + +## Qué NO hace el visor + +- No pide permisos del navegador. No usa geolocalización. +- No manda datos a ningún sitio. No tiene analítica, ni cookies, ni rastreo. +- Lo único que guarda es el idioma elegido, en `localStorage`. +- No carga código de ningún CDN: Leaflet va incrustado en el fichero. + +## Qué SÍ sale de tu máquina + +En los modos Mapa y Ver de cerca, el navegador pide teselas a los servidores de +la lista de [Fuentes](Fuentes-y-licencias). Esos servidores ven tu IP y **la zona +que estás mirando**, como con cualquier mapa web. Si eso te importa, quédate en +el modo Relieve, que es completamente local. + +Los enlaces de la barra inferior abren servicios de terceros (Google, Mapillary, +Catastro) con las coordenadas en la URL. Solo se abren si pulsas. + +## Escapado de contenido + +Los nombres de municipio y de espacio protegido vienen de OpenStreetMap y de +ficheros oficiales, o sea de terceros: **cualquiera puede editar el nombre de un +municipio en OSM**. Todo lo que sale de los datos y acaba en el HTML pasa por +escapado antes, incluidos los tooltips del mapa. Sin eso, alguien podría inyectar +código editando un topónimo. + +## Al reconstruir los datos + +- Todas las descargas van por HTTPS con verificación de certificado. +- Los servidores del ministerio español sirven la cadena TLS incompleta. El + proyecto **no desactiva la verificación**: descarga el certificado intermedio + oficial de la FNMT y valida la cadena entera contra la raíz del sistema. +- El repositorio no contiene credenciales. `data/` está en `.gitignore`. + +## Si lo publicas + +El visor es HTML estático, sin backend, así que la superficie de ataque es la de +cualquier página estática. Sírvelo por HTTPS y añade cabeceras +`Content-Security-Policy` si tu servidor lo permite. diff --git a/docs/Uso-del-visor.md b/docs/Uso-del-visor.md new file mode 100644 index 0000000..38ce78c --- /dev/null +++ b/docs/Uso-del-visor.md @@ -0,0 +1,56 @@ +# Uso del visor + +## Los tres modos + +Arriba a la izquierda: + +- **Relieve** — el país entero sobre relieve sombreado, generado a partir del + modelo de elevaciones. Funciona sin conexión. Encima puedes activar la capa de + aislamiento y la de espacios protegidos. +- **Mapa** — el país entero sobre mapa real: satélite, topográfico u + OpenStreetMap. Necesita conexión. +- **Ver de cerca** — lo mismo, centrado en la localización elegida. + +## Capas + +En los modos Mapa y Ver de cerca: + +| Fondo | Qué aporta | +|---|---| +| Satélite | Ortofoto. Ves la explanada, los árboles y por dónde entra la pista | +| Topográfico | Curvas de nivel, cotas, arroyos, topónimos | +| OpenStreetMap | Caminos y nombres | + +| Encima | Qué aporta | +|---|---| +| Parcelas del catastro | De quién es la finca y dónde acaba. **Lo más útil**: el modelo ve la pista, no el candado | +| Red Natura 2000 | Límites oficiales en vivo | +| Espacios protegidos | Figuras nacionales | +| Otras localizaciones | El resto de puntos, para ver alternativas cerca | + +## Filtros + +Estrellas mínimas, región, y mínimos por criterio (sonido, agua, arbolado, +acceso). La lista y el mapa se actualizan a la vez. + +## La ficha + +Al pulsar una localización: + +- **Vista aérea** — foto real del sitio, 640 m de lado. Púlsala para ir al mapa. +- **Relieve 3D** — el terreno 9,6 km alrededor. Arrastra para girarlo y ver si + estás en una hondonada. +- **Los seis criterios** con su puntuación. +- **Los datos**: dB que llegan a la casa más cercana, distancias, arbolado, + pendiente, temperaturas. +- **Aviso** del espacio protegido más cercano. + +## Los enlaces de abajo + +Bajo el mapa, para la localización elegida: Satélite, Street View, Mapillary, +OSM, Catastro y Cómo llegar. + +## Idioma + +Selector arriba a la izquierda: castellano, inglés, francés y portugués. Se +recuerda entre visitas. Los nombres de municipio no se traducen, vienen del país. diff --git a/install.ps1 b/install.ps1 new file mode 100644 index 0000000..0810a4e --- /dev/null +++ b/install.ps1 @@ -0,0 +1,57 @@ +# Instalador para Windows (PowerShell). +# +# Solo hace falta para RECONSTRUIR los datos. Para USAR el visor no se instala +# nada: se abre out\visor.html haciendo doble clic. +# +# Si Windows bloquea el script: +# Set-ExecutionPolicy -Scope Process -ExecutionPolicy Bypass +# .\install.ps1 + +$ErrorActionPreference = "Stop" +Set-Location -Path $PSScriptRoot + +Write-Host "== RAVE SCOUT / EXPLORER ==" -ForegroundColor Cyan + +# --- python --- +$py = $null +foreach ($c in @("py -3", "python", "python3")) { + try { + $exe, $arg = $c.Split(" ", 2) + $v = & $exe $arg -c "import sys;print(sys.version_info>=(3,9))" 2>$null + if ($v -eq "True") { $py = $c; break } + } catch { } +} +if (-not $py) { + Write-Host "Falta Python 3.9 o superior." -ForegroundColor Red + Write-Host " Descarga: https://www.python.org/downloads/" + Write-Host " O bien: winget install Python.Python.3.12" + Write-Host " Marca 'Add Python to PATH' durante la instalacion." + exit 1 +} +$exe, $arg = $py.Split(" ", 2) +Write-Host ("Python: " + (& $exe $arg -V)) + +# --- entorno --- +if (-not (Test-Path ".venv")) { & $exe $arg -m venv .venv } +& ".\.venv\Scripts\python.exe" -m pip -q install --upgrade pip +Write-Host "Instalando dependencias..." +& ".\.venv\Scripts\python.exe" -m pip -q install -r requirements.txt + +# --- comprobacion --- +$chk = @" +import importlib, sys +faltan = [m for m in ('numpy','scipy','rasterio','osmium','shapely','pyproj', + 'requests','PIL') if not importlib.util.find_spec(m)] +if faltan: + print('FALTAN: ' + ', '.join(faltan)); sys.exit(1) +print('Dependencias correctas.') +"@ +$chk | & ".\.venv\Scripts\python.exe" - +if ($LASTEXITCODE -ne 0) { exit 1 } + +Write-Host "" +Write-Host "Listo." -ForegroundColor Green +Write-Host " Abrir el visor: .\abrir.ps1" +Write-Host " Ver paises: .\.venv\Scripts\python.exe src\regions.py" +Write-Host " Reconstruir Espana: .\.venv\Scripts\python.exe src\stars.py" +Write-Host " Otro pais: `$env:REGION='pt'; .\.venv\Scripts\python.exe src\stars.py" diff --git a/install.sh b/install.sh new file mode 100755 index 0000000..a741fa4 --- /dev/null +++ b/install.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +# Instalador para Linux y macOS. +# +# Solo hace falta para RECONSTRUIR los datos. Para USAR el visor no se instala +# nada: se abre out/visor.html en cualquier navegador. +set -euo pipefail +cd "$(dirname "${BASH_SOURCE[0]}")" + +echo "== RAVE SCOUT / EXPLORER ==" + +# --- python --- +PY="" +for c in python3.12 python3.11 python3.10 python3; do + if command -v "$c" >/dev/null 2>&1; then + v=$("$c" -c 'import sys;print(sys.version_info>=(3,9))' 2>/dev/null || echo False) + [ "$v" = "True" ] && { PY="$c"; break; } + fi +done +[ -n "$PY" ] || { echo "Falta Python 3.9 o superior."; echo \ + " Debian/Ubuntu: sudo apt install python3 python3-venv"; \ + echo " Fedora: sudo dnf install python3"; \ + echo " macOS: brew install python"; exit 1; } +echo "Python: $($PY -V)" + +if ! "$PY" -c "import venv" >/dev/null 2>&1; then + echo "Falta el módulo venv. En Debian/Ubuntu: sudo apt install python3-venv"; exit 1 +fi + +# --- entorno --- +[ -d .venv ] || "$PY" -m venv .venv +./.venv/bin/pip -q install --upgrade pip +echo "Instalando dependencias…" +./.venv/bin/pip -q install -r requirements.txt + +# --- comprobación --- +./.venv/bin/python - <<'EOF' +import importlib, sys +faltan = [m for m in ("numpy","scipy","rasterio","osmium","shapely","pyproj", + "requests","PIL") if not importlib.util.find_spec(m)] +if faltan: + print("FALTAN:", ", ".join(faltan)); sys.exit(1) +print("Dependencias correctas.") +EOF + +echo +echo "Listo." +echo " Abrir el visor: ./abrir.sh" +echo " Ver países: ./.venv/bin/python src/regions.py" +echo " Reconstruir España: make all" +echo " Otro país: REGION=pt make all" diff --git a/out/informe.html b/out/informe.html index 30a044d..4966bea 100644 --- a/out/informe.html +++ b/out/informe.html @@ -278,7 +278,7 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp #valorcoordenadasmunicipiocomunidad dBcasa kmpista magua kmárbol % - prot kmMadrid kmver + prot kmver @@ -293,7 +293,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 0,1 33 3,1 -174.9 sat sv @@ -309,7 +308,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 2,1 65 4,6 -156.5 sat sv @@ -325,7 +323,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 1,3 61 1,1 -168.6 sat sv @@ -341,7 +338,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 1,8 59 1,7 -198.0 sat sv @@ -357,7 +353,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 0,4 51 3,9 -190.0 sat sv @@ -373,7 +368,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 2,7 83 0,4 -122.1 sat sv @@ -389,7 +383,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 4,6 74 3,2 -168.6 sat sv @@ -405,7 +398,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 4,1 68 0,5 -254.0 sat sv @@ -421,7 +413,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 0,1 17 4,7 -388.2 sat sv @@ -437,7 +428,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 1,2 31 0,4 -139.5 sat sv @@ -453,7 +443,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 1,8 70 12,9 -119.9 sat sv @@ -469,7 +458,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 1,8 73 3,0 -209.9 sat sv @@ -485,7 +473,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 1,7 0 0,3 -264.9 sat sv @@ -501,7 +488,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 1,4 62 3,1 -158.3 sat sv @@ -517,7 +503,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 2,4 52 3,3 -149.3 sat sv @@ -533,7 +518,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 0,1 32 1,5 -309.5 sat sv @@ -549,7 +533,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 2,1 69 0,7 -138.5 sat sv @@ -565,7 +548,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 0,1 35 1,7 -87.8 sat sv @@ -581,7 +563,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 0,1 88 2,7 -267.6 sat sv @@ -597,7 +578,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 2,6 70 3,4 -153.6 sat sv @@ -613,7 +593,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 2,6 12 6,0 -180.5 sat sv @@ -629,7 +608,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 0,7 20 1,5 -272.5 sat sv @@ -645,7 +623,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 1,1 100 1,0 -211.3 sat sv @@ -661,7 +638,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 3,1 63 4,5 -228.3 sat sv @@ -677,7 +653,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 4,4 45 4,0 -191.5 sat sv @@ -693,7 +668,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 1,8 30 3,6 -185.2 sat sv @@ -709,7 +683,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 0,1 71 0,8 -129.2 sat sv @@ -725,7 +698,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 1,0 64 2,9 -319.1 sat sv @@ -741,7 +713,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 2,3 85 8,1 -164.7 sat sv @@ -757,7 +728,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 5,7 92 0,9 -165.4 sat sv @@ -773,7 +743,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 0,5 80 1,1 -220.3 sat sv @@ -789,7 +758,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 0,2 65 4,3 -266.0 sat sv @@ -805,7 +773,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 3,4 69 6,5 -316.8 sat sv @@ -821,7 +788,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 3,3 36 1,0 -303.0 sat sv @@ -837,7 +803,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 1,2 90 13,7 -295.9 sat sv @@ -853,7 +818,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 0,9 0 0,6 -403.2 sat sv @@ -869,7 +833,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 2,3 0 7,0 -378.9 sat sv @@ -885,7 +848,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 5,9 73 1,9 -346.1 sat sv @@ -901,7 +863,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 0,8 10 2,1 -141.0 sat sv @@ -917,7 +878,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 0,5 27 6,3 -333.9 sat sv @@ -933,7 +893,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 0,1 47 0,8 -121.5 sat sv @@ -949,7 +908,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 0,1 87 1,0 -280.4 sat sv @@ -965,7 +923,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 2,4 51 0,5 -231.4 sat sv @@ -981,7 +938,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 0,2 61 2,7 -350.0 sat sv @@ -997,7 +953,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 4,5 35 2,5 -147.0 sat sv @@ -1013,7 +968,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 2,1 74 1,2 -176.9 sat sv @@ -1029,7 +983,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp 2,3 66 0,7 -153.2 sat sv @@ -1059,8 +1012,6 @@ code.inline { font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monosp riesgo extremo de incendio de junio a septiembre, con restricciones de acceso y responsabilidad penal si algo prende. El mismo punto no es el mismo sitio en marzo que en agosto. -
  • Distancia en línea recta, no tiempo de coche

    La columna de Madrid es - euclídea. Por carretera y luego pista, el tiempo real puede ser el doble.
  • diff --git a/out/visor.html b/out/visor.html index 4504944..188dc2f 100644 --- a/out/visor.html +++ b/out/visor.html @@ -686,7 +686,10 @@ button,input,select{font:inherit;color:inherit} border-right:1px solid var(--line);display:flex;flex-direction:column;height:100vh} #side header{padding:16px 18px 12px;border-bottom:1px solid var(--line)} #side h1{margin:0;font-size:15px;letter-spacing:.02em} -#side .sub{color:var(--muted);font-size:11.5px;margin-top:3px} +#side .sub{color:var(--muted);font-size:11.5px;margin-top:3px;display:flex; + justify-content:space-between;align-items:center;gap:8px} +#lang{width:auto;padding:2px 5px;font-size:11px;background:var(--panel2); + border:1px solid var(--line);border-radius:4px;color:var(--ink2);cursor:pointer} .filters{padding:14px 18px;display:flex;flex-direction:column;gap:13px; border-bottom:1px solid var(--line)} .f-row{display:flex;flex-direction:column;gap:6px} @@ -726,12 +729,30 @@ select{width:100%;background:var(--panel2);border:1px solid var(--line); border-radius:5px;padding:6px 11px;font-size:12px;cursor:pointer;color:var(--ink2)} .toolbar button[aria-pressed=true]{background:var(--accent);border-color:var(--accent); color:#08131f;font-weight:600} -.legend{position:absolute;bottom:12px;left:12px;background:rgba(21,26,33,.93); - border:1px solid var(--line);border-radius:5px;padding:9px 12px;font-size:11px; - display:flex;gap:13px;align-items:center;z-index:5} +/* Barra inferior: leyenda a la izquierda y, a su derecha, los enlaces a mapas + externos de la localización elegida. Antes había que abrir la ficha y bajar + hasta el final para encontrarlos. */ +.bottombar{position:absolute;bottom:12px;left:12px;right:12px;z-index:5; + display:flex;gap:10px;align-items:center;justify-content:space-between; + flex-wrap:wrap;pointer-events:none} +.bottombar>*{pointer-events:auto} +.legend{background:rgba(21,26,33,.93);border:1px solid var(--line); + border-radius:5px;padding:9px 12px;font-size:11px;display:flex;gap:13px; + align-items:center} .legend i{width:9px;height:9px;border-radius:50%;display:inline-block;margin-right:4px} -.hint{position:absolute;bottom:12px;right:12px;color:var(--muted);font-size:11px; - background:rgba(21,26,33,.9);padding:5px 9px;border-radius:4px;z-index:5} +.maplinks{background:rgba(21,26,33,.93);border:1px solid var(--line); + border-radius:5px;padding:5px 6px;display:flex;gap:4px;align-items:center; + flex-wrap:wrap;max-width:100%} +.maplinks a{display:flex;flex-direction:column;gap:0;padding:5px 9px; + border-radius:4px;text-decoration:none;line-height:1.2;white-space:nowrap} +.maplinks a b{color:var(--accent);font-size:11.5px;font-weight:600} +.maplinks a span{color:var(--muted);font-size:9.5px} +.maplinks a:hover{background:#1d2836} +.ml-sel{padding:5px 10px 5px 6px;border-right:1px solid var(--line); + margin-right:3px;font-size:11px;color:var(--ink2);white-space:nowrap; + display:flex;flex-direction:column;line-height:1.25} +.ml-sel b{font-size:11.5px;color:var(--ink)} +.ml-hint{color:var(--muted);font-size:11px;padding:6px 9px} /* ---------- mapa de cerca (Leaflet) ---------- */ #leaf{position:absolute;top:0;left:0;width:100%;height:100%;display:none; @@ -739,6 +760,8 @@ select{width:100%;background:var(--panel2);border:1px solid var(--line); body.cerca #map{display:none} body.cerca #leaf{display:block} body.cerca .legend{display:none} +/* los conmutadores del relieve solo tienen sentido en su propio modo */ +body.cerca .only-esp{display:none} #layers{position:absolute;top:52px;left:12px;z-index:6;width:186px; background:rgba(21,26,33,.95);border:1px solid var(--line);border-radius:6px; padding:9px 11px;display:none;flex-direction:column;gap:8px;font-size:12px} @@ -776,6 +799,7 @@ body.cerca.sinsel #nosel{display:block} .d-head h2{margin:0 26px 0 0;font-size:16px} .d-head .loc{color:var(--muted);font-size:12px;margin-top:2px} .d-head .stars{font-size:16px;margin-top:7px;letter-spacing:1px} +.d-head .btn-cerca{margin-top:11px} #close{position:absolute;top:13px;right:14px;background:none;border:0; color:var(--muted);font-size:20px;cursor:pointer;line-height:1;padding:2px 5px} #close:hover{color:var(--ink)} @@ -854,13 +878,16 @@ body.cerca.sinsel #nosel{display:block}