红莲R-LotusX 2024-12-16 14:10 采纳率: 20%
浏览 51
已结题

js进行WGS-84和GCJ-02间的互相转换有误差该如何解决

使用如下方法进行WGS-84和GCJ-02间的互相转换,但是转换后再转回来有误差,该如何解决


const PI = 3.14159265358979323846;
const A = 6378245.0; // 长半轴
const EE = 0.00669342162296594323; // 偏心率平方

// WGS-84 转 GCJ-02
function wgs84ToGcj02(lon, lat) {
    if (outOfChina(lat, lon)) {
        return [lat, lon]; // 如果坐标在中国以外,直接返回
    }
    let dLat = transformLat(lon - 105.0, lat - 35.0);
    let dLon = transformLon(lon - 105.0, lat - 35.0);
    let radLat = lat / 180.0 * PI;
    let magic = Math.sin(radLat);
    magic = 1 - EE * magic * magic;
    let sqrtMagic = Math.sqrt(magic);
    dLat = (dLat * 180.0) / ((A * (1 - EE)) / (magic * sqrtMagic) * PI);
    dLon = (dLon * 180.0) / (A / sqrtMagic * Math.cos(radLat) * PI);
    const gcjLat = lat + dLat;
    const gcjLon = lon + dLon;
    return [gcjLon, gcjLat];
}

// GCJ-02 转 WGS-84
function gcj02ToWgs84(lon, lat) {
    if (outOfChina(lat, lon)) {
        return [lat, lon]; // 如果坐标在中国以外,直接返回
    }
    let dLat = transformLat(lon - 105.0, lat - 35.0);
    let dLon = transformLon(lon - 105.0, lat - 35.0);
    let radLat = lat / 180.0 * PI;
    let magic = Math.sin(radLat);
    magic = 1 - EE * magic * magic;
    let sqrtMagic = Math.sqrt(magic);
    dLat = (dLat * 180.0) / ((A * (1 - EE)) / (magic * sqrtMagic) * PI);
    dLon = (dLon * 180.0) / (A / sqrtMagic * Math.cos(radLat) * PI);
    const wgsLat = lat - dLat;
    const wgsLon = lon - dLon;
    return [wgsLon, wgsLat];
}

// 判断是否在中国范围外
function outOfChina(lat, lon) {
    return lon < 72.004 || lon > 137.8347 || lat < 0.8293 || lat > 55.8271;
}

// 经度转换
function transformLon(x, y) {
    let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
    ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
    ret += (20.0 * Math.sin(x * PI) + 40.0 * Math.sin(x / 3.0 * PI)) * 2.0 / 3.0;
    ret += (150.0 * Math.sin(x / 12.0 * PI) + 300.0 * Math.sin(x / 30.0 * PI)) * 2.0 / 3.0;
    return ret;
}

// 纬度转换
function transformLat(x, y) {
    let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
    ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
    ret += (20.0 * Math.sin(y * PI) + 40.0 * Math.sin(y / 3.0 * PI)) * 2.0 / 3.0;
    ret += (160.0 * Math.sin(y / 12.0 * PI) + 320 * Math.sin(y * PI / 30.0)) * 2.0 / 3.0;
    return ret;
}

export default {
  wgs84ToGcj02,
  gcj02ToWgs84
}
// // 示例用法
// const wgsLat = 39.913818; // 北京WGS-84纬度
// const wgsLon = 116.363625; // 北京WGS-84经度

// // WGS-84 -> GCJ-02
// const [gcjLat, gcjLon] = wgs84ToGcj02(wgsLat, wgsLon);

// console.log(`WGS-84 -> GCJ-02: 纬度 = ${gcjLat}, 经度 = ${gcjLon}`);

// // GCJ-02 -> WGS-84
// const [wgsBackLat, wgsBackLon] = gcj02ToWgs84(gcjLat, gcjLon);
// console.log(`GCJ-02 -> WGS-84: 纬度 = ${wgsBackLat}, 经度 = ${wgsBackLon}`);
  • 写回答

1条回答 默认 最新

  • 道友老李 JWE233286一种基于机器视觉的水表指针读数识别及修正的方法 专利发明者 2024-12-16 14:13
    关注
    让【道友老李】来帮你解答,本回答参考通义千问qwen-plus编写,并整理提供,如果还有疑问可以点击头像关注,评论或留言
    ### 问题描述

    在进行WGS-84和GCJ-02之间的互相转换时,发现转换后再转回来存在误差。这是因为GCJ-02坐标系是基于WGS-84坐标系进行偏移后的结果,而这种偏移是非线性的,因此在进行反向转换时可能会产生误差。

    解决方案

    为了减少或消除这种误差,可以采取以下几种方法:

    1. 迭代法:通过多次迭代逐步逼近原始坐标。
    2. 优化算法:使用更精确的数学模型来计算偏移量。
    3. 校正因子:根据已知的误差分布,引入校正因子进行补偿。

    迭代法实现

    迭代法是一种常见的方法,通过多次转换逐步减小误差。以下是使用迭代法的示例代码:

    const PI = 3.14159265358979323846;
    const A = 6378245.0; // 长半轴
    const EE = 0.00669342162296594323; // 偏心率平方
    
    // WGS-84 转 GCJ-02
    function wgs84ToGcj02(lon, lat) {
        if (outOfChina(lat, lon)) {
            return [lon, lat]; // 如果坐标在中国以外,直接返回
        }
        let dLat = transformLat(lon - 105.0, lat - 35.0);
        let dLon = transformLon(lon - 105.0, lat - 35.0);
        let radLat = lat / 180.0 * PI;
        let magic = Math.sin(radLat);
        magic = 1 - EE * magic * magic;
        let sqrtMagic = Math.sqrt(magic);
        dLat = (dLat * 180.0) / ((A * (1 - EE)) / (magic * sqrtMagic) * PI);
        dLon = (dLon * 180.0) / (A / sqrtMagic * Math.cos(radLat) * PI);
        const gcjLat = lat + dLat;
        const gcjLon = lon + dLon;
        return [gcjLon, gcjLat];
    }
    
    // GCJ-02 转 WGS-84
    function gcj02ToWgs84(lon, lat, iterations = 10) {
        if (outOfChina(lat, lon)) {
            return [lon, lat]; // 如果坐标在中国以外,直接返回
        }
        let delta = 0.01;
        let threshold = 0.000000001;
        let wgsLat = lat;
        let wgsLon = lon;
    
        for (let i = 0; i < iterations; i++) {
            let [gcjLon, gcjLat] = wgs84ToGcj02(wgsLon, wgsLat);
            let dLat = lat - gcjLat;
            let dLon = lon - gcjLon;
            if (Math.abs(dLat) < threshold && Math.abs(dLon) < threshold) {
                break;
            }
            wgsLat += dLat;
            wgsLon += dLon;
        }
    
        return [wgsLon, wgsLat];
    }
    
    // 判断是否在中国范围外
    function outOfChina(lat, lon) {
        return lon < 72.004 || lon > 137.8347 || lat < 0.8293 || lat > 55.8271;
    }
    
    // 经度转换
    function transformLon(x, y) {
        let ret = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(x * PI) + 40.0 * Math.sin(x / 3.0 * PI)) * 2.0 / 3.0;
        ret += (150.0 * Math.sin(x / 12.0 * PI) + 300.0 * Math.sin(x / 30.0 * PI)) * 2.0 / 3.0;
        return ret;
    }
    
    // 纬度转换
    function transformLat(x, y) {
        let ret = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
        ret += (20.0 * Math.sin(6.0 * x * PI) + 20.0 * Math.sin(2.0 * x * PI)) * 2.0 / 3.0;
        ret += (20.0 * Math.sin(y * PI) + 40.0 * Math.sin(y / 3.0 * PI)) * 2.0 / 3.0;
        ret += (160.0 * Math.sin(y / 12.0 * PI) + 320 * Math.sin(y * PI / 30.0)) * 2.0 / 3.0;
        return ret;
    }
    
    // 示例用法
    const wgsLat = 39.913818; // 北京WGS-84纬度
    const wgsLon = 116.363625; // 北京WGS-84经度
    
    // WGS-84 -> GCJ-02
    const [gcjLat, gcjLon] = wgs84ToGcj02(wgsLon, wgsLat);
    console.log(`WGS-84 -> GCJ-02: 纬度 = ${gcjLat}, 经度 = ${gcjLon}`);
    
    // GCJ-02 -> WGS-84
    const [wgsBackLat, wgsBackLon] = gcj02ToWgs84(gcjLon, gcjLat);
    console.log(`GCJ-02 -> WGS-84: 纬度 = ${wgsBackLat}, 经度 = ${wgsBackLon}`);
    

    说明

    1. 迭代法gcj02ToWgs84函数中引入了迭代次数iterations和阈值threshold,通过多次迭代逐步减小误差。
    2. 阈值:当两次转换的误差小于阈值时,停止迭代,以提高效率。
    3. 示例用法:展示了如何使用这些函数进行坐标转换,并输出结果。

    通过上述方法,可以显著减少转换过程中的误差,提高坐标的准确性。

    本回答被题主选为最佳回答 , 对您是否有帮助呢?
    评论

报告相同问题?

问题事件

  • 系统已结题 12月24日
  • 已采纳回答 12月16日
  • 创建了问题 12月16日