0
0

电子围栏

This commit is contained in:
2025-09-11 10:54:56 +08:00
parent 6bc1d5b20b
commit b8af6b511c
23 changed files with 1544 additions and 4 deletions

View File

@ -0,0 +1,24 @@
package com.fuyuanshen.equipment.utils.map;
/**
* @author: 默苍璃
* @date: 2025-09-1110:27
*/
public class Coordinate {
private double lat;
private double lng;
// 构造函数
public Coordinate() {}
public Coordinate(double lat, double lng) {
this.lat = lat;
this.lng = lng;
}
// getter和setter方法
public double getLat() { return lat; }
public void setLat(double lat) { this.lat = lat; }
public double getLng() { return lng; }
public void setLng(double lng) { this.lng = lng; }
}

View File

@ -0,0 +1,135 @@
package com.fuyuanshen.equipment.utils.map;
import java.util.List;
/**
* @author: 默苍璃
* @date: 2025-09-1110:13
*/
public class GeoFenceChecker {
/**
* 点是否在围栏内
*
* @param pointLat 点的纬度
* @param pointLng 点的经度
* @param fenceType 围栏类型0 POLYGON 或 1 CIRCLE
* @param coordinates 围栏坐标点列表
* @param radius 圆形围栏半径仅对CIRCLE类型有效
* @return true表示在围栏内false表示在围栏外
*/
public static boolean isPointInFence(double pointLat, double pointLng,
Integer fenceType,
List<Coordinate> coordinates,
Long radius) {
if (fenceType == 0) {
return isPointInPolygon(pointLat, pointLng, coordinates);
} else if (fenceType == 1) {
if (coordinates == null || coordinates.isEmpty() || radius == null) {
return false;
}
// 圆形围栏只有一个坐标点(圆心)
Coordinate center = coordinates.get(0);
return isPointInCircle(pointLat, pointLng, center.lat, center.lng, radius);
}
return false;
}
/**
* 使用射线投射算法判断点是否在多边形内
*
* @param pointLat 点的纬度
* @param pointLng 点的经度
* @param polygon 多边形顶点坐标列表
* @return true表示在多边形内false表示在多边形外
*/
public static boolean isPointInPolygon(double pointLat, double pointLng,
List<Coordinate> polygon) {
if (polygon == null || polygon.size() < 3) {
return false;
}
int intersectCount = 0;
int vertexCount = polygon.size();
// 遍历多边形的每条边
for (int i = 0; i < vertexCount; i++) {
Coordinate p1 = polygon.get(i);
Coordinate p2 = polygon.get((i + 1) % vertexCount);
// 检查点是否在边的y范围内
if (p1.lat != p2.lat &&
(pointLat >= Math.min(p1.lat, p2.lat)) &&
(pointLat < Math.max(p1.lat, p2.lat))) {
// 计算边与从点发出的水平射线的交点经度
double intersectLng = (pointLat - p1.lat) * (p2.lng - p1.lng) / (p2.lat - p1.lat) + p1.lng;
// 如果交点在点的右侧则计数加1
if (pointLng < intersectLng) {
intersectCount++;
}
}
}
// 奇数个交点表示点在多边形内
return intersectCount % 2 == 1;
}
/**
* 判断点是否在圆形内
*
* @param pointLat 点的纬度
* @param pointLng 点的经度
* @param centerLat 圆心纬度
* @param centerLng 圆心经度
* @param radius 半径(米)
* @return true表示在圆内false表示在圆外
*/
public static boolean isPointInCircle(double pointLat, double pointLng,
double centerLat, double centerLng,
Long radius) {
double distance = calculateDistance(pointLat, pointLng, centerLat, centerLng);
return distance <= radius;
}
/**
* 计算两点间距离使用Haversine公式
*
* @param lat1 点1纬度
* @param lng1 点1经度
* @param lat2 点2纬度
* @param lng2 点2经度
* @return 距离(米)
*/
public static double calculateDistance(double lat1, double lng1, double lat2, double lng2) {
final double EARTH_RADIUS = 6371000; // 地球半径(米)
double dLat = Math.toRadians(lat2 - lat1);
double dLng = Math.toRadians(lng2 - lng1);
double a = Math.sin(dLat / 2) * Math.sin(dLat / 2) +
Math.cos(Math.toRadians(lat1)) * Math.cos(Math.toRadians(lat2)) *
Math.sin(dLng / 2) * Math.sin(dLng / 2);
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
return EARTH_RADIUS * c;
}
/**
* 坐标点类
*/
public static class Coordinate {
public double lat;
public double lng;
public Coordinate() {
}
public Coordinate(double lat, double lng) {
this.lat = lat;
this.lng = lng;
}
}
}