使用Python生成带20W有色立方体的矢量瓦片 MVT用于在Mapbox中加载的完整流程

一、环境安装

复制代码
pip install mapbox-vector-tile[proj] shapely mercantile

mapbox-vector-tile--- MVT encode/decode(依赖 protobuf + shapely)

shapely--- 构造 Polygon 几何

mercantile--- 经纬度 ↔ 瓦片 xyz 换算

二、核心思路

在指定经纬度范围内随机生成 20W 个小矩形 Polygon

每个要素附带随机 color(0--255 整数三元组或 CSS 色值)

用 mercantile计算目标 zoom 下各瓦片包围盒,按瓦片分组

对每个瓦片内的要素,将 WGS84 坐标量化到 tile 局部坐标 (0--4096)​ 后调用 mapbox_vector_tile.encode()

写出 {z}/{x}/{y}.mvt

⚠️ 单张 MVT 建议 ≤ 数万要素,20W 需分散到多个 z=14~16 的瓦片中。

三、完整示例代码

复制代码
import os
import random
import math
import mercantile
from shapely.geometry import Polygon
import mapbox_vector_tile

# ── 参数 ──────────────────────────────────────────────
NUM_FEATURES   = 200_000        # 20万个"立方体"(小方块)
ZOOM           = 14             # 切片层级
TILE_EXTENT    = 4096           # MVT标准范围
CENTER_LNG, CENTER_LAT = 116.39, 39.90   # 北京附近
RADIUS_DEG     = 0.15           # 约16km
BOX_SIZE_DEG   = 0.0003         # 每个小方块大小
OUTPUT_DIR     = "./mvt_output"
LAYER_NAME     = "colored_boxes"
# ────────────────────────────────────────────────────────

os.makedirs(OUTPUT_DIR, exist_ok=True)

# ① 随机生成 (minx, miny, maxx, maxy) 的矩形 + 随机颜色
features_world = []
for fid in range(NUM_FEATURES):
    cx = CENTER_LNG + random.uniform(-RADIUS_DEG, RADIUS_DEG)
    cy = CENTER_LAT + random.uniform(-RADIUS_DEG, RADIUS_DEG)
    half = BOX_SIZE_DEG / 2
    poly = Polygon([
        (cx - half, cy - half),
        (cx - half, cy + half),
        (cx + half, cy + half),
        (cx + half, cy - half),
        (cx - half, cy - half),
    ])
    r = random.randint(0, 255)
    g = random.randint(0, 255)
    b = random.randint(0, 255)
    features_world.append({
        "poly": poly,
        "props": {"id": fid, "r": r, "g": g, "b": b,
                  "color": f"#{r:02x}{g:02x}{b:02x}"}
    })

# ② 按瓦片分组
tile_bins = {}
for feat in features_world:
    centroid = feat["poly"].centroid
    t = mercantile.tile(centroid.x, centroid.y, ZOOM)
    tile_bins.setdefault(t, []).append(feat)

# ③ 逐瓦片编码
MVT_EXTENT = TILE_EXTENT
for (tx, ty, tz), feats in tile_bins.items():
    if not feats:
        continue

    # 瓦片WGS84边界 → 量化用
    tb = mercantile.bounds(tx, ty, tz)
    bbox = (tb.west, tb.south, tb.east, tb.north)  # minx, miny, maxx, maxy

    layer_features = []
    for feat in feats:
        # 用 WKT + quantize_bounds 让编码器自动做坐标变换
        layer_features.append({
            "geometry": feat["poly"].wkt,
            "properties": feat["props"]
        })

    pbf = mapbox_vector_tile.encode(
        [{
            "name": LAYER_NAME,
            "features": layer_features
        }],
        default_options={
            "quantize_bounds": bbox,
            "extents": MVT_EXTENT,
            "y_coord_down": False   # MVT规范Y轴向下,encoder内部处理
        }
    )

    z_dir = os.path.join(OUTPUT_DIR, str(tz))
    x_dir = os.path.join(z_dir, str(tx))
    os.makedirs(x_dir, exist_ok=True)
    with open(os.path.join(x_dir, f"{ty}.mvt"), "wb") as f:
        f.write(pbf)

    print(f"✓ tile {tz}/{tx}/{ty} → {len(feats)} features, {len(pbf)} bytes")

print("Done! 输出目录:", OUTPUT_DIR)

四、前端渲染

复制代码
<style>html,body,#map{margin:0;padding:0;width:100%;height:100%}</style>
<div id="map"></div>

<script src="https://api.mapbox.com/mapbox-gl-js/v3.2.0/mapbox-gl.js"></script>
<link href="https://api.mapbox.com/mapbox-gl-js/v3.2.0/mapbox-gl.css" rel="stylesheet"/>

<script>
mapboxgl.accessToken = "accessToken";

const map = new mapboxgl.Map({
  container: 'map',
  style: 'mapbox://styles/mapbox/standard', // ✅ 关键
  center: [116.39, 39.90],
  zoom: 14
});

map.on('style.load', () => {
  map.addSource('coloredBoxes', {
    type: 'vector',
    tiles: ['./mvt_output/{z}/{x}/{y}.mvt'],
    minzoom: 14,
    maxzoom: 15
  });

  map.addLayer({
    id: 'colored-boxes-fill',
    type: 'fill',
    source: 'coloredBoxes',
    'source-layer': 'colored_boxes',
    slot: 'middle',
    paint: {
      'fill-color': ['get', 'color'],
      'fill-opacity': 0.85
    }
  });
});
</script>
相关推荐
丷丩4 天前
MapLibre GL JS第41课:向地图添加图标
前端·javascript·mapbox·maplibre gl js
丷丩8 天前
MapLibre GL JS第36课:一个Source配置多个图层样式
javascript·gis·map·mapbox·maplibre gl js
丷丩9 天前
MapLibre GL JS第38课:根据缩放级别改变建筑颜色
javascript·map·mapbox·maplibre gl js
丷丩11 天前
MapLibre GL JS第35课:显示带地形高程(三维地形)的卫星影像
javascript·gis·map·mapbox·maplibre gl js
丷丩12 天前
MapLibre GL JS第25课:添加栅格瓦片源
开发语言·javascript·gis·mapbox·maplibre gl js
丷丩13 天前
MapLibre GL JS第27课:添加COG栅格源
javascript·map·mapbox·maplibre gl js
丷丩13 天前
MapLibre GL JS第29课:添加Canvas源
javascript·gis·map·mapbox·maplibre gl js
丷丩13 天前
MapLibre GL JS第21课:绘制GeoJSON点图标、注记
前端·javascript·gis·mapbox·maplibre gl js
丷丩13 天前
MapLibre GL JS第20课:更新GeoJSON多边形
前端·javascript·gis·mapbox·maplibre gl js