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

使用H3与OpenLayers生成墨卡托投影六边形地图时±180°存在间隙

H3 + OpenLayers 墨卡托投影下±180°经度处六边形间隙问题解决

我在使用H3与OpenLayers生成墨卡托投影的六边形地图时,发现±180°经度位置存在间隙。

问题代码

const createHex = (lat: any, lng: any) => {
    const cell = latLngToCell(lng, lat, 1);
    const coords = cellToBoundary(cell).map((c) => [c[1], c[0]]);
    const polygon = new Polygon([coords]);

    const feature = new Feature(polygon);
    vectorSource.addFeature(feature);
};

const map = new Map({
    target: 'map',
    layers: [
        new TileLayer({
            source: new TileJSON({
                url: 'https://api.maptiler.com/maps/satellite/256/tiles.json?key=yFxxWLuQf6QipClqNF0n',
                crossOrigin: 'anonymous'
            })
        })
    ],
    view: new View({
        center: [0, 0],
        zoom: 2,
        projection: 'EPSG:4326'
    })
});

map.on('click', (e) => {
    createHex(e.coordinate[0], e.coordinate[1]);
});

问题截图

问题截图

解决方案

问题根源有两点:一是H3函数参数顺序错误,二是跨±180°经线的多边形未被正确处理,导致OpenLayers渲染时出现间隙。修复步骤如下:

  1. 纠正H3参数顺序:H3的latLngToCell函数参数为(纬度, 经度, 分辨率),原代码传反了经纬度,导致六边形位置计算错误。
  2. 拆分跨日界线的多边形:编写工具函数检测并拆分跨±180°的多边形,将其分为东、西两部分,确保OpenLayers能正确渲染。

修复后的代码

// 拆分跨±180°经线的多边形
const splitCrossAntimeridianPolygon = (coords: number[][]) => {
    let hasCross = coords.some(coord => Math.abs(coord[0]) > 180);
    if (!hasCross) return [coords];

    const westCoords: number[][] = [];
    const eastCoords: number[][] = [];

    coords.forEach((coord, idx) => {
        const lng = coord[0];
        const prevCoord = coords[idx === 0 ? coords.length - 1 : idx - 1];
        const prevLng = prevCoord[0];

        if (lng > 180) {
            westCoords.push([lng - 360, coord[1]]);
            eastCoords.push([lng, coord[1]]);
        } else if (lng < -180) {
            westCoords.push([lng, coord[1]]);
            eastCoords.push([lng + 360, coord[1]]);
        } else {
            // 处理跨线的情况,添加180/-180分割点
            if ((prevLng > 180 && lng < 180) || (prevLng < -180 && lng > -180)) {
                westCoords.push([-180, coord[1]]);
                eastCoords.push([180, coord[1]]);
            }
            westCoords.push(coord);
            eastCoords.push(coord);
        }
    });

    // 闭合多边形
    westCoords.push(westCoords[0]);
    eastCoords.push(eastCoords[0]);

    return [westCoords, eastCoords];
};

const createHex = (lat: number, lng: number) => {
    // 纠正H3参数顺序:纬度在前,经度在后
    const cell = latLngToCell(lat, lng, 1);
    // H3返回的边界格式为[经度, 纬度],直接适配OpenLayers的EPSG:4326格式
    const coords = cellToBoundary(cell);
    // 处理跨线多边形
    const polygonCoordsList = splitCrossAntimeridianPolygon(coords);

    polygonCoordsList.forEach(polygonCoords => {
        const polygon = new Polygon([polygonCoords]);
        const feature = new Feature(polygon);
        vectorSource.addFeature(feature);
    });
};

// 地图初始化代码保持不变
const map = new Map({
    target: 'map',
    layers: [
        new TileLayer({
            source: new TileJSON({
                url: 'https://api.maptiler.com/maps/satellite/256/tiles.json?key=yFxxWLuQf6QipClqNF0n',
                crossOrigin: 'anonymous'
            })
        })
    ],
    view: new View({
        center: [0, 0],
        zoom: 2,
        projection: 'EPSG:4326'
    })
});

map.on('click', (e) => {
    // OpenLayers的coordinate格式是[经度, 纬度],修正传参顺序
    createHex(e.coordinate[1], e.coordinate[0]);
});

额外说明:原代码中createHex的调用参数也传反了——OpenLayers的e.coordinate是[经度, 纬度],需把纬度(e.coordinate[1])传给createHex第一个参数,经度(e.coordinate[0])传给第二个参数,这也是之前位置错误的原因之一。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.14 00:04:58