top of page

Obtenção de Tiles MVT de WebSites para Lat/Lon e DXF

De forma bem objetiva, a ideia é capturar, direto de um site com webmapping, os limites de um polígono de interesse para um estudo e convertê-los em DXF. Em outras palavras, queremos converter Tiles MVT para DXF em Latitude e Longitude.

Tiles MVT: Captura via Network


Pressione F12 no navegador e, na aba Network das DevTools, devemos localizar as requisições para os arquivos .mvt, normalmente estruturados no formato de tiles:

.../tiles/z/x/y.mvt

Esses arquivos são compactos e leves, contendo vetores (pontos, linhas e polígonos) codificados em um grid local.

Você precisará primeiro gravar o log, clicando no botão exibido na figura abaixo.


Clique para gravar o log.
Clique para gravar o log.
Deixe gravando.
Deixe gravando.

No centro você verá esse botão de Reload page. Clique nele para atualizar a página.

Atualizando a página.
Atualizando a página.

Mantenha o filtro Fetch/XHR ativado e repare que surgirá uma lista de requisições de tiles. Cada vez que você aplicar um zoom no mapa, essa lista será incrementada.

Lista de requisições.
Lista de requisições.

Quando alcançar o nível de zoom desejado, os últimos itens da lista serão os arquivos MVT correspondentes. Queremos o polígono em rosa. Clique no arquivo MVT mais recente.

Lista final de arquivos MVT.
Lista final de arquivos MVT.

Observe que a URL requisitada terá esse padrão:

.../tiles/z/x/y.mvt
Padrão .../tiles/z/x/y.mvt da URL requisitada.
Padrão .../tiles/z/x/y.mvt da URL requisitada.

Na imagem acima, vemos que z = 13, x = 3299 e y = 4284. Ao clicar duas vezes no arquivo, ele será baixado. Para facilitar o uso, renomeie-o para:

z_x_y.mvt

Conversão para JSON


O arquivo MVT é um formato binário compacto, usado para armazenar dados vetoriais em tiles. Para poder visualizar ou trabalhar com suas informações de forma legível, você pode convertê-lo para JSON utilizando um script em Python. Essa conversão permite acessar as geometrias e atributos contidos no tile de maneira estruturada e fácil de manipular.


Use o script abaixo:

import mapbox_vector_tile
import json

# ====== CONFIGURAÇÃO ======
input_mvt_file = "13_3299_4284.mvt"
output_json_file = "13_3299_4284_decoded.json"

# ====== LER E DECODIFICAR ======
with open(input_mvt_file, 'rb') as f:
    tile_data = f.read()

decoded = mapbox_vector_tile.decode(tile_data)

# ====== SALVAR EM JSON ======
with open(output_json_file, 'w', encoding='utf-8') as out:
    json.dump(decoded, out, ensure_ascii=False, indent=2)

print(f"Arquivo salvo como {output_json_file}")

No nosso caso, o arquivo JSON obtido foi:

{
  "default": {
    "extent": 4096,
    "version": 2,
    "features": [
      {
        "geometry": {
          "type": "Polygon",
          "coordinates": [
            [
              [
                4316,
                4352
              ],
              [
                4334,
                4333
              ],
              [
                4352,
                4323
              ],
              [
                4352,
                -256
              ],
              [
                -256,
                -256
              ],
              [
                -256,
                4352
              ],
              [
                4316,
                4352
              ]
            ]
          ]
        },
        "properties": {
          "id": "770dd4dc-9ad5-44b3-b921-87f18e1b6177",
          "grouping": "cities",
          "name": "Cabo de Santo Agostinho"
        },
        "id": 0,
        "type": "Feature"
      }
    ],
    "type": "FeatureCollection"
  }
}

Observe de cara que não é o arquivo que queremos, uma vez que possui poucos vértices e suas propriedades não atendem ao que procuramos. Vamos examinar com mais cuidado a lista de requisições.


A estrutura das pastas costuma seguir uma lógica importante para organizar os dados nos mapas online, então o polígono que buscamos deve estar em um diretório específico. No nosso caso, queremos uma unidade de conservação. Ao verificar melhor os últimos itens da lista, identificamos um arquivo cuja URL indica que ele corresponde ao dado desejado.

.../uc/tiles/13/3300/4283.mvt
.../uc/tiles/13/3300/4283.mvt
.../uc/tiles/13/3300/4283.mvt

Após a conversão, perceba agora que este é o arquivo que estávamos procurando.

...
        "properties": {
          "name": "APA Estuarina dos Rios Jaboatão e Pirapama",
          "sphere": "Estadual",
          "category": "Área de proteção ambiental",
          "id": "0074cbee-5555-4507-b1e6-e8358b3367e7",
          "law": "Lei nº 9931/86"
        },
        "id": 0,
        "type": "Feature"
      }
    ],
    "type": "FeatureCollection"
  }
}

Finalmente: Tiles MVT para DXF


Antes de prosseguir, entenda o Sistema de Tiles Web Mercator.


Execute este script para converter o arquivo JSON em DXF. Verifique atentamente os valores das variáveis de entrada, especialmente tile_z, tile_x e tile_y.


import ezdxf
import json
import math

# ====== CONFIGURAÇÃO ======
input_json_file = "13_3300_4283_decoded.json"
output_dxf_file = "13_3300_4283_decoded_latlon_export.dxf"

tile_z = 13
tile_x = 3300

# Escolha aqui o Y do servidor
tile_y_xyz = 4283

tile_y = tile_y_xyz

extent = 4096

# ====== FUNÇÃO ======
def mvt_to_latlon(px, py, z, x_tile, y_tile, extent):
    # Flip local dentro do tile
    py_flipped = extent - py

    n = 2.0 ** z
    x_norm = (x_tile + (px / extent)) / n
    y_norm = (y_tile + (py_flipped / extent)) / n

    lon = x_norm * 360.0 - 180.0
    lat_rad = math.atan(math.sinh(math.pi * (1 - 2 * y_norm)))
    lat = math.degrees(lat_rad)
    return lon, lat

# ====== LEITURA ======
with open(input_json_file, 'r', encoding='utf-8') as f:
    data = json.load(f)

if 'features' in data:
    features = data['features']
elif 'default' in data and 'features' in data['default']:
    features = data['default']['features']
else:
    raise KeyError("Não encontrei campo 'features' no JSON!")

# ====== CRIA DXF ======
doc = ezdxf.new('R2000')
msp = doc.modelspace()

layer_counter = 1

for feature in features:
    geom_type = feature['geometry']['type']
    coords = feature['geometry']['coordinates']

    if geom_type == 'Polygon':
        polygons = [coords]
    elif geom_type == 'MultiPolygon':
        polygons = coords
    else:
        continue

    for poly in polygons:
        for ring in poly:
            converted_ring = [
                mvt_to_latlon(pt[0], pt[1], tile_z, tile_x, tile_y, extent)
                for pt in ring
            ]
            layer_name = f"OUTER_SHAPE_{layer_counter}"
            if layer_name not in doc.layers:
                doc.layers.add(name=layer_name)
            msp.add_lwpolyline(converted_ring, close=True, dxfattribs={'layer': layer_name})
            layer_counter += 1

doc.saveas(output_dxf_file)
print(f"DXF gerado com sucesso: {output_dxf_file}")

Vale lembrar que o resultado pode ser apenas parcial. Por isso, será necessário localizar as outras partes que forem do seu interesse.


Parte do polígono que desejamos em DXF convertidos para Latitude e Longitude.
Parte do polígono que desejamos em DXF convertidos para Latitude e Longitude.

Assim, finalizamos mais um conteúdo! Compartilhe com seus amigos!


Comentários


Posts relacionados...

Design azul abstrato
Design azul abstrato
Design azul abstrato
Design azul abstrato
Design azul abstrato
Design azul abstrato
Design azul abstrato
Design azul abstrato
Design azul abstrato
Design azul abstrato
Design azul abstrato
Design azul abstrato
Design azul abstrato
Design azul abstrato
Design azul abstrato
Design azul abstrato
bottom of page