129 lines
7.1 KiB
Markdown
129 lines
7.1 KiB
Markdown
# Arma raster tiles
|
|
|
|
Servidor estático de tiles raster XYZ para os mapas de Arma 3 fornecidos como KML/KMZ `GroundOverlay`. Todas as fontes compõem uma camada mundial única: não existe identificador de mapa na URL.
|
|
|
|
## Arquitetura
|
|
|
|
`tile-builder` lê `source/` recursivamente, extrai KMZs somente em diretórios temporários, lê cada `GroundOverlay`, localiza a imagem local indicada por `Icon/href` e a reprojeta para Web Mercator (EPSG:3857). Para `LatLonBox` com `rotation`, os quatro cantos são girados no sentido anti-horário em torno do centro antes do warp GDAL; o raster final recebe alfa para conservar transparência e recortar as bordas rotacionadas.
|
|
|
|
Cada overlay gera tiles temporários por `gdal2tiles --xyz`. O builder os compõe com alfa em uma única pirâmide. Uma área menor tem prioridade e é desenhada por cima; se as áreas forem iguais, vence primeiro o caminho relativo em ordem alfabética e depois o índice do `GroundOverlay`. A área é calculada a partir do polígono rotacionado em EPSG:3857.
|
|
|
|
O resultado físico é publicado diretamente na pasta local `tiles/`:
|
|
|
|
```text
|
|
tiles/{z}/{x}/{y}.png
|
|
tiles/metadata.json
|
|
```
|
|
|
|
O Nginx aceita exclusivamente a rota pública abaixo e faz a tradução interna. Não publique nem use a ordem de armazenamento diretamente.
|
|
|
|
```text
|
|
https://arma_tiles.valmo.dev/tiles/{x}/{y}/{z}
|
|
https://arma_tiles.valmo.dev/tiles/18342/12417/15
|
|
```
|
|
|
|
Mesmo sem `.png` na URL, a resposta é `Content-Type: image/png` e inclui `Access-Control-Allow-Origin: *`, permitindo uso direto pelo MapLibre em outra origem. Sem provider configurado, coordenadas sem cobertura retornam `tiles/empty.png`; com provider configurado, são encaminhadas ao callback e armazenadas no cache local do Nginx.
|
|
|
|
## Provider de callback e MapLibre
|
|
|
|
Copie `.env.example` para `.env` e, se quiser uma camada base, defina um template HTTPS XYZ:
|
|
|
|
```dotenv
|
|
CALLBACK_PROVIDER=https://tiles.seu-provider.example/{z}/{x}/{y}.png
|
|
```
|
|
|
|
O template é validado antes de qualquer leitura/processamento de fonte. Ele precisa usar `https`, não pode ter query, credenciais ou IP privado, e deve conter exatamente um `{z}`, `{x}` e `{y}` no caminho. Deixe a variável vazia ou ausente para usar o `empty.png` branco.
|
|
|
|
Para que o provider apareça tanto onde não há mapa Arma quanto nas bordas transparentes de uma tile parcialmente coberta, use a camada base local abaixo da camada Arma:
|
|
|
|
```js
|
|
sources: {
|
|
providerBase: {
|
|
type: "raster",
|
|
tiles: ["http://localhost:9000/base/{x}/{y}/{z}"],
|
|
tileSize: 256,
|
|
scheme: "xyz"
|
|
},
|
|
arma: {
|
|
type: "raster",
|
|
tiles: ["http://localhost:9000/tiles/{x}/{y}/{z}"],
|
|
tileSize: 256,
|
|
scheme: "xyz",
|
|
minzoom: 0,
|
|
maxzoom: 17
|
|
}
|
|
},
|
|
layers: [
|
|
{ id: "provider-base", type: "raster", source: "providerBase" },
|
|
{ id: "arma", type: "raster", source: "arma" }
|
|
]
|
|
```
|
|
|
|
`/base/{x}/{y}/{z}` e o fallback de `/tiles/` consultam o callback sob demanda e compartilham um cache local persistente. Exiba a atribuição e cumpra os termos definidos pelo provider escolhido.
|
|
|
|
## Entradas
|
|
|
|
Coloque `.kmz` e `.kml` em `source/`, inclusive em subpastas. Um KMZ deve conter um KML (o builder prefere `doc.kml`) e a imagem local referenciada pelo KML. KMLs soltos podem referenciar imagens dentro da mesma árvore de `source/`.
|
|
|
|
Os arquivos de entrada nunca são modificados ou removidos. Erros por arquivo são registrados em `tiles/metadata.json` e não bloqueiam as demais fontes. Links HTTP(S), caminhos absolutos e `gx:LatLonQuad` não fazem parte desta primeira versão; use `LatLonBox` e imagens locais.
|
|
|
|
## Zoom e configuração
|
|
|
|
O máximo automático de cada overlay é calculado a partir da maior resolução reprojetada em metros por pixel. O builder escolhe o maior zoom cuja resolução de tile ainda não é mais detalhada que a fonte, evitando ampliação de pixels.
|
|
|
|
O mínimo automático é `0`: os níveis amplos custam pouco e tornam mapas isolados encontráveis a partir da visão mundial. Cada fonte para no próprio máximo nativo, evitando ampliar pixels no servidor. Para permitir zoom visual adicional, configure o MapLibre com `maxZoom` alto e mantenha o `maxzoom` da source no máximo nativo; o MapLibre amplia a última tile disponível. Se nenhuma fonte cobrir a coordenada, o servidor usa o callback configurado ou o `empty.png` branco.
|
|
|
|
`config/maps.json` permite overrides globais e por caminho relativo a `source/`:
|
|
|
|
```json
|
|
{
|
|
"global": { "minzoom": null, "maxzoom": null },
|
|
"sources": {
|
|
"Altis.kmz": { "minzoom": 8, "maxzoom": 16 },
|
|
"subpasta/exemplo.kml": { "maxzoom": 14 }
|
|
}
|
|
}
|
|
```
|
|
|
|
Use inteiro entre 0 e 22 ou `null`. A precedência é fonte, global, cálculo automático. Um `maxzoom` explícito acima do máximo automático é permitido e ficará marcado em `metadata.json`, pois solicita ampliação conscientemente.
|
|
|
|
## Geração local
|
|
|
|
Dependências locais: Python 3, Pillow, GDAL com `gdal_translate`, `gdalwarp`, `gdalinfo` e `gdal2tiles.py`.
|
|
|
|
```bash
|
|
./scripts/build-tiles.sh
|
|
./scripts/build-tiles.sh --source-filter Altis.kmz
|
|
```
|
|
|
|
O cache em `cache/` usa SHA-256 da fonte. Entradas inalteradas reutilizam os GeoTIFFs reprojetados. Para garantir a composição e a prioridade corretas, a v1 recompõe a pirâmide final inteira em staging a cada build; apenas a reprojeção das fontes inalteradas é reutilizada. Ao fim do build, a pasta local `tiles/` é substituída pelo resultado completo, após a geração de `metadata.json`.
|
|
|
|
## Docker Compose e Coolify
|
|
|
|
Para desenvolvimento local:
|
|
|
|
```bash
|
|
docker compose up --build
|
|
```
|
|
|
|
O Nginx ficará disponível em `http://localhost:${HTTP_PORT:-9000}`. O Compose executa primeiro o builder e monta a pasta `tiles/` como somente leitura no Nginx.
|
|
|
|
No Coolify, mantenha as entradas fora do Git e crie uma pasta/volume persistente no host. Defina `ARMA_TILES_SOURCE_DIR` para esse caminho; ele será montado como `/app/source` somente leitura. O volume nomeado `arma_tiles_data` preserva o cache entre deploys; a pasta `tiles/` do projeto é o volume de saída publicado tanto pelo builder quanto pelo Nginx. Configure o domínio `arma_tiles.valmo.dev` e TLS no proxy do Coolify, apontando para a porta 80 do serviço `tiles`.
|
|
|
|
Para limitar paralelismo do GDAL, configure `GDAL2TILES_PROCESSES` (o padrão é `1`). As respostas de tile têm cache público de um dia e `stale-while-revalidate` de sete dias, além de ETag.
|
|
|
|
## Validação
|
|
|
|
```bash
|
|
python3 tests/test_build_tiles.py
|
|
./scripts/smoke-test.sh
|
|
```
|
|
|
|
O teste de fumaça processa `Altis.kmz`, verifica `tiles/metadata.json` e um PNG, sobe o Nginx e consulta uma tile pela ordem pública `{x}/{y}/{z}` para confirmar `200`, `image/png` e CORS. O callback é opcional e não é exercitado pelo teste local.
|
|
|
|
## Limitações conhecidas
|
|
|
|
- Não há watcher: após adicionar ou alterar uma entrada, execute o builder ou faça um novo deploy.
|
|
- A composição final ainda é uma reconstrução global; a estrutura de cache permite uma futura invalidação apenas dos tiles afetados.
|
|
- Esta versão não baixa imagens externas, não suporta `gx:LatLonQuad`, não trata overlays que cruzam o antimeridiano e não inclui DEM, hillshade, vetores, MBTiles, frontend, autenticação ou banco de dados.
|