consumer-app/utils/coordinate.js

169 lines
5.5 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/**
* 判断经纬度是否超出中国境内(优化版:更精准的边界范围)
*/
function isLocationOutOfChina(latitude, longitude) {
// 先校验参数有效性
if (typeof latitude !== 'number' || typeof longitude !== 'number' || isNaN(latitude) || isNaN(longitude)) {
return true;
}
// 优化后的中国经纬度范围(覆盖大部分核心区域,减少南海误判)
if (longitude < 72.004 || longitude > 137.8347 || latitude < 3.86 || latitude > 53.55) {
return true;
}
return false;
}
/**
* 将WGS-84(国际标准)转为GCJ-02(火星坐标):
*/
function transformFromWGSToGCJ(latitude, longitude) {
// 新增参数校验
if (typeof latitude !== 'number' || typeof longitude !== 'number' || isNaN(latitude) || isNaN(longitude)) {
throw new Error('输入的经纬度必须为有效数字');
}
// 修正:初始化为数字类型
let lat = latitude;
let lon = longitude;
const ee = 0.00669342162296594323;
const a = 6378245.0;
const pi = Math.PI; // 复用内置PI提升精度
if (!isLocationOutOfChina(latitude, longitude)) {
const adjustLat = transformLatWithXY(longitude - 105.0, latitude - 35.0);
const adjustLon = transformLonWithXY(longitude - 105.0, latitude - 35.0);
const radLat = latitude / 180.0 * pi;
let magic = Math.sin(radLat);
magic = 1 - ee * magic * magic;
const sqrtMagic = Math.sqrt(magic);
lat = latitude + (adjustLat * 180.0) / ((a * (1 - ee)) / (magic * sqrtMagic) * pi);
lon = longitude + (adjustLon * 180.0) / (a / sqrtMagic * Math.cos(radLat) * pi);
}
return { latitude: lat, longitude: lon };
}
/**
* 将GCJ-02(火星坐标)转为百度坐标:
*/
function transformFromGCJToBaidu(latitude, longitude) {
// 参数校验
if (typeof latitude !== 'number' || typeof longitude !== 'number' || isNaN(latitude) || isNaN(longitude)) {
throw new Error('输入的经纬度必须为有效数字');
}
const xPi = Math.PI * 3000.0 / 180.0;
const z = Math.sqrt(longitude * longitude + latitude * latitude) + 0.00002 * Math.sin(latitude * xPi);
const theta = Math.atan2(latitude, longitude) + 0.000003 * Math.cos(longitude * xPi);
const a_latitude = z * Math.sin(theta) + 0.006;
const a_longitude = z * Math.cos(theta) + 0.0065;
return { latitude: a_latitude, longitude: a_longitude };
}
/**
* 将百度坐标转为GCJ-02(火星坐标):
*/
function transformFromBaiduToGCJ(latitude, longitude) {
// 参数校验
if (typeof latitude !== 'number' || typeof longitude !== 'number' || isNaN(latitude) || isNaN(longitude)) {
throw new Error('输入的经纬度必须为有效数字');
}
const xPi = Math.PI * 3000.0 / 180.0;
const x = longitude - 0.0065;
const y = latitude - 0.006;
const z = Math.sqrt(x * x + y * y) - 0.00002 * Math.sin(y * xPi);
const theta = Math.atan2(y, x) - 0.000003 * Math.cos(x * xPi);
const a_latitude = z * Math.sin(theta);
const a_longitude = z * Math.cos(theta);
return { latitude: a_latitude, longitude: a_longitude };
}
/**
* 将GCJ-02(火星坐标)转为WGS-84:
*/
function transformFromGCJToWGS(latitude, longitude) {
// 参数校验
if (typeof latitude !== 'number' || typeof longitude !== 'number' || isNaN(latitude) || isNaN(longitude)) {
throw new Error('输入的经纬度必须为有效数字');
}
const threshold = 0.00001; // 约1米精度
const maxIteration = 30;
let iteration = 0;
// 初始边界
let minLat = latitude - 0.5;
let maxLat = latitude + 0.5;
let minLng = longitude - 0.5;
let maxLng = longitude + 0.5;
let delta = 1;
while (iteration < maxIteration && delta > threshold) {
iteration++;
const midLat = (minLat + maxLat) / 2;
const midLng = (minLng + maxLng) / 2;
const midPoint = transformFromWGSToGCJ(midLat, midLng);
delta = Math.abs(midPoint.latitude - latitude) + Math.abs(midPoint.longitude - longitude);
// 二分法缩小范围
if (midPoint.latitude > latitude) {
maxLat = midLat;
} else {
minLat = midLat;
}
if (midPoint.longitude > longitude) {
maxLng = midLng;
} else {
minLng = midLng;
}
}
return { latitude: (minLat + maxLat) / 2, longitude: (minLng + maxLng) / 2 };
}
/**
* 判断点是否在矩形范围内
*/
function isContains(point, p1, p2) {
if (!point || !p1 || !p2) return false;
return (point.latitude >= Math.min(p1.latitude, p2.latitude)
&& point.latitude <= Math.max(p1.latitude, p2.latitude)
&& point.longitude >= Math.min(p1.longitude, p2.longitude)
&& point.longitude <= Math.max(p1.longitude, p2.longitude));
}
/**
* 纬度偏移计算
*/
function transformLatWithXY(x, y) {
const pi = Math.PI;
let lat = -100.0 + 2.0 * x + 3.0 * y + 0.2 * y * y + 0.1 * x * y + 0.2 * Math.sqrt(Math.abs(x));
lat += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
lat += (20.0 * Math.sin(y * pi) + 40.0 * Math.sin(y / 3.0 * pi)) * 2.0 / 3.0;
lat += (160.0 * Math.sin(y / 12.0 * pi) + 320 * Math.sin(y * pi / 30.0)) * 2.0 / 3.0;
return lat;
}
/**
* 经度偏移计算
*/
function transformLonWithXY(x, y) {
const pi = Math.PI;
let lon = 300.0 + x + 2.0 * y + 0.1 * x * x + 0.1 * x * y + 0.1 * Math.sqrt(Math.abs(x));
lon += (20.0 * Math.sin(6.0 * x * pi) + 20.0 * Math.sin(2.0 * x * pi)) * 2.0 / 3.0;
lon += (20.0 * Math.sin(x * pi) + 40.0 * Math.sin(x / 3.0 * pi)) * 2.0 / 3.0;
lon += (150.0 * Math.sin(x / 12.0 * pi) + 300.0 * Math.sin(x / 30.0 * pi)) * 2.0 / 3.0;
return lon;
}
export {
isLocationOutOfChina,
transformFromWGSToGCJ,
transformFromGCJToBaidu,
transformFromBaiduToGCJ,
transformFromGCJToWGS
};