Files
MER-2.2_2601/mer_uniapp/pages/activity/utils/geoUtil.js
2026-03-08 20:07:52 +08:00

148 lines
4.7 KiB
JavaScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// +----------------------------------------------------------------------
// | 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;