Files
MER-2.2_2601/mer_uniapp/pages/activity/utils/geoUtil.js

148 lines
4.7 KiB
JavaScript
Raw Normal View History

// +----------------------------------------------------------------------
// | CRMEB [ CRMEB赋能开发者助力企业发展 ]
// +----------------------------------------------------------------------
// | Copyright (c) 2016~2026 https://www.crmeb.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed CRMEB并不是自由软件未经许可不能去掉CRMEB相关版权
// +----------------------------------------------------------------------
// | Author: CRMEB Team <admin@crmeb.com>
// +----------------------------------------------------------------------
/**
* 地理围栏工具类
* 提供根据经纬度判断是否在多边形范围内的功能
*/
const geoUtil = {
/**
* 判断点是否在多边形内部射线法
* @param {Object} point 待判断的点 {lng: 经度, lat: 纬度}
* @param {Array} polygon 多边形顶点数组 [{lng: 经度1, lat: 纬度1}, {lng: 经度2, lat: 纬度2}, ...]
* @returns {Boolean} 是否在多边形内部
*/
isPointInPolygon: function(point, polygon) {
if (!point || !polygon || !Array.isArray(polygon) || polygon.length < 3) {
return false;
}
let inside = false;
const x = point.lng;
const y = point.lat;
// 射线法实现
for (let i = 0, j = polygon.length - 1; i < polygon.length; j = i++) {
const xi = polygon[i].lng;
const yi = polygon[i].lat;
const xj = polygon[j].lng;
const yj = polygon[j].lat;
// 判断点是否在多边形的边上
if (this.isPointOnLine(point, {lng: xi, lat: yi}, {lng: xj, lat: yj})) {
return true;
}
// 判断点是否与多边形边界相交
const intersect = ((yi > y) !== (yj > y)) &&
(x < (xj - xi) * (y - yi) / (yj - yi) + xi);
if (intersect) {
inside = !inside;
}
}
return inside;
},
/**
* 判断点是否在线段上
* @param {Object} point 待判断的点
* @param {Object} lineStart 线段起点
* @param {Object} lineEnd 线段终点
* @returns {Boolean} 是否在线段上
*/
isPointOnLine: function(point, lineStart, lineEnd) {
// 计算点到线段的距离
const distance = this.pointToLineDistance(point, lineStart, lineEnd);
// 如果距离非常小接近0且点在线段的包围盒内则认为点在线段上
return distance < 0.000001 &&
point.lng >= Math.min(lineStart.lng, lineEnd.lng) &&
point.lng <= Math.max(lineStart.lng, lineEnd.lng) &&
point.lat >= Math.min(lineStart.lat, lineEnd.lat) &&
point.lat <= Math.max(lineStart.lat, lineEnd.lat);
},
/**
* 计算点到线段的距离
* @param {Object} point
* @param {Object} lineStart 线段起点
* @param {Object} lineEnd 线段终点
* @returns {Number} 距离
*/
pointToLineDistance: function(point, lineStart, lineEnd) {
const A = point.lng - lineStart.lng;
const B = point.lat - lineStart.lat;
const C = lineEnd.lng - lineStart.lng;
const D = lineEnd.lat - lineStart.lat;
const dot = A * C + B * D;
const lenSq = C * C + D * D;
let param = -1;
if (lenSq !== 0) {
param = dot / lenSq;
}
let xx, yy;
if (param < 0) {
xx = lineStart.lng;
yy = lineStart.lat;
} else if (param > 1) {
xx = lineEnd.lng;
yy = lineEnd.lat;
} else {
xx = lineStart.lng + param * C;
yy = lineStart.lat + param * D;
}
const dx = point.lng - xx;
const dy = point.lat - yy;
// 这里返回的是欧几里得距离,在实际地理应用中可能需要转换为实际距离(如米)
return Math.sqrt(dx * dx + dy * dy);
},
/**
* 计算两个经纬度点之间的距离Haversine公式
* @param {Object} point1 第一个点
* @param {Object} point2 第二个点
* @returns {Number} 两点之间的距离单位
*/
getDistance: function(point1, point2) {
const R = 6371000; // 地球半径(米)
const φ1 = this.toRadians(point1.lat);
const φ2 = this.toRadians(point2.lat);
const Δφ = this.toRadians(point2.lat - point1.lat);
const Δλ = this.toRadians(point2.lng - point1.lng);
const a = Math.sin(Δφ / 2) * Math.sin(Δφ / 2) +
Math.cos(φ1) * Math.cos(φ2) *
Math.sin(Δλ / 2) * Math.sin(Δλ / 2);
const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
const distance = R * c; // 距离(米)
return distance;
},
/**
* 角度转弧度
* @param {Number} degrees 角度
* @returns {Number} 弧度
*/
toRadians: function(degrees) {
return degrees * (Math.PI / 180);
}
};
export default geoUtil;