You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Leaflet.js结合Sentinel Hub WMS:多边形裁剪卫星瓦片的优化方案咨询

可行解决方案

方案1:服务端预定义AOI(推荐)

直接在Sentinel Hub后台配置目标多边形作为AOI并关联到你的图层:

  • 登录Sentinel Hub Dashboard,找到你的NDVI图层
  • 在图层设置中添加自定义AOI,导入你的多边形GeoJSON数据
  • 后续Leaflet的WMS请求无需携带GEOMETRY参数,Sentinel Hub会自动仅返回AOI范围内的瓦片

该方案彻底规避了URI过长问题,同时由服务端高效处理裁剪,减少无效请求量。修改代码时只需移除bounds参数(或保留作为辅助限制),直接使用配置好AOI的图层ID即可:

const layer = L.tileLayer.wms(baseUrl, {
  attribution:
    '&copy; <a href="http://www.sentinel-hub.com/" target="_blank">Sentinel Hub</a>',
  tileSize: 256,
  maxcc: 20,
  layers: layerId,
  time: timeRange,
  gain: "0.3",
  gamma: "0.8",
  upsampling: "BICUBIC",
  opacity: 0.8,
  maxNativeZoom: 25,
  minNativeZoom: 12,
  minZoom: 0,
  maxZoom: 30,
  transparent: "true",
  format: "image/png",
  crs: L.CRS.EPSG4326,
  // 移除bounds参数,或保留作为额外范围限制
});

方案2:前端瓦片裁剪(无需修改服务端)

利用Leaflet的Canvas API对每个加载的WMS瓦片进行客户端裁剪,仅保留多边形范围内的内容:

  1. 先将你的多边形转换为Leaflet的L.Polygon对象
  2. 扩展L.TileLayer.WMS,重写createTile方法实现裁剪逻辑

示例代码:

// 从landsData生成裁剪用的多边形集合
const clipPolygons = landsData.map(land => 
  L.polygon(land.lpisGeojson.geometry.coordinates[0])
);

// 自定义裁剪WMS图层
class ClippedWmsLayer extends L.TileLayer.WMS {
  createTile(coords, done) {
    const tile = super.createTile(coords, done);
    tile.onload = () => {
      const canvas = document.createElement('canvas');
      const ctx = canvas.getContext('2d');
      canvas.width = tile.width;
      canvas.height = tile.height;

      // 获取当前瓦片的地理边界
      const tileBounds = this._tileCoordsToBounds(coords);
      // 将多边形转换为瓦片坐标系下的路径并设置裁剪区域
      ctx.beginPath();
      clipPolygons.forEach(poly => {
        const latLngs = poly.getLatLngs()[0];
        latLngs.forEach((latLng, idx) => {
          const tileRelativePoint = this._map.latLngToContainerPoint(latLng)
            .subtract(this._map.latLngToContainerPoint(tileBounds.getNorthWest()));
          idx === 0 ? ctx.moveTo(tileRelativePoint.x, tileRelativePoint.y) 
                   : ctx.lineTo(tileRelativePoint.x, tileRelativePoint.y);
        });
        ctx.closePath();
      });
      ctx.clip();
      // 绘制裁剪后的瓦片
      ctx.drawImage(tile, 0, 0);
      // 替换原瓦片为Canvas元素
      tile.replaceWith(canvas);
    };
    return tile;
  }
}

// 使用自定义图层替代原L.tileLayer.wms
const layer = new ClippedWmsLayer(baseUrl, {
  // 保留原有的WMS参数
  bounds: bounds,
});

注意:若多边形数量多或结构复杂,前端裁剪可能存在性能损耗,更适合中小规模AOI场景。

方案3:简化多边形+POST请求传递GEOMETRY

如果需要动态传递AOI:

  1. 用Turf.js简化多边形,减少坐标点数量(平衡精度与URI长度):
import * as turf from '@turf/turf';

// 简化每个多边形,tolerance值可根据需求调整
const simplifiedLands = landsData.map(land => {
  return turf.simplify(land.lpisGeojson, { tolerance: 0.001, highQuality: true });
});
  1. 扩展Leaflet的WMS图层,使用POST请求传递GEOMETRY参数(规避GET请求的URI长度限制):
class PostWmsLayer extends L.TileLayer.WMS {
  getTileUrl(coords) {
    const params = {...this.wmsParams};
    // 添加上当前瓦片的边界参数
    params.bbox = this._tileCoordsToBounds(coords).toBBoxString();
    params.width = this.options.tileSize;
    params.height = this.options.tileSize;
    // 添加简化后的几何参数(多多边形可合并为MultiPolygon)
    params.geometry = JSON.stringify(simplifiedLands[0].geometry);

    return { params, url: this._url };
  }

  createTile(coords, done) {
    const tile = document.createElement('img');
    tile.crossOrigin = '';

    const { url, params } = this.getTileUrl(coords);
    // 发送POST请求获取瓦片
    fetch(url, {
      method: 'POST',
      headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
      body: new URLSearchParams(params)
    })
    .then(res => res.blob())
    .then(blob => {
      tile.src = URL.createObjectURL(blob);
      done(null, tile);
    })
    .catch(err => done(err, tile));

    return tile;
  }
}

方案4:GeoJSON遮罩层(快速临时方案)

用与地图底色一致的GeoJSON层覆盖在WMS层上方,仅露出目标多边形区域:

// 创建覆盖整个地图范围的遮罩多边形
const mapBounds = map.getBounds();
const maskPolygon = L.polygon([
  [mapBounds.getNorthWest().lat, mapBounds.getNorthWest().lng],
  [mapBounds.getNorthEast().lat, mapBounds.getNorthEast().lng],
  [mapBounds.getSouthEast().lat, mapBounds.getSouthEast().lng],
  [mapBounds.getSouthWest().lat, mapBounds.getSouthWest().lng],
], {
  fillColor: '#ffffff', // 匹配你的地图底色
  fillOpacity: 1,
  weight: 0
});

// 使用Leaflet.ClipPolygon插件用目标多边形裁剪遮罩层
maskPolygon.clipTo(clipPolygons);

// 图层顺序:WMS层在底层,遮罩层在上方
sateliteLayer.value.addLayer(layer);
sateliteLayer.value.addLayer(maskPolygon);

该方案实现简单,但仅为视觉遮挡,WMS仍会加载整个bounds内的瓦片,适合快速验证需求场景。


内容的提问来源于stack exchange,提问作者Radek Homola

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.30 00:37:03