package org.sxkj.common.geo.utils;
|
|
import org.sxkj.common.geo.entity.Feature;
|
import org.sxkj.common.geo.entity.FlyAreaParam;
|
import org.sxkj.common.geo.entity.GeoJson;
|
import com.fasterxml.jackson.databind.DeserializationFeature;
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
import org.sxkj.common.geo.entity.PointPOJO;
|
|
import java.io.File;
|
import java.io.IOException;
|
import java.util.*;
|
|
/**
|
* 空间计算工具类
|
*/
|
public class GeoUtils {
|
/**
|
* 默认地球半径
|
*/
|
private static double EARTH_RADIUS = 6371000;//赤道半径(单位m)
|
|
/**
|
* 转化为弧度(rad)
|
*/
|
private static double rad(double d) {
|
return d * Math.PI / 180.0;
|
}
|
|
|
/**
|
* 计算中心经纬度与目标经纬度的距离(米)
|
*
|
* @param centerLon 中心精度
|
* @param centerLat 中心纬度
|
* @param targetLon 需要计算的精度
|
* @param targetLat 需要计算的纬度
|
* @return 米
|
*/
|
public static double distance(double centerLon, double centerLat, double targetLon, double targetLat) {
|
|
double jl_jd = 102834.74258026089786013677476285;// 每经度单位米;
|
double jl_wd = 111712.69150641055729984301412873;// 每纬度单位米;
|
double b = Math.abs((centerLat - targetLat) * jl_jd);
|
double a = Math.abs((centerLon - targetLon) * jl_wd);
|
return Math.sqrt((a * a + b * b));
|
}
|
|
/**
|
* 根据多个点计算中心点
|
* @param list
|
* @return
|
*/
|
public static PointPOJO getCenterPoint(List<PointPOJO> list) {
|
|
int total = list.size();
|
double X = 0, Y = 0, Z = 0;
|
|
for (int i = 0; i < list.size(); i++) {
|
PointPOJO point = list.get(i);
|
double lat, lon, x, y, z;
|
lon = point.getLon() * Math.PI / 180;
|
lat = point.getLat() * Math.PI / 180;
|
x = Math.cos(lat) * Math.cos(lon);
|
y = Math.cos(lat) * Math.sin(lon);
|
z = Math.sin(lat);
|
X += x;
|
Y += y;
|
Z += z;
|
}
|
|
|
X = X / total;
|
Y = Y / total;
|
Z = Z / total;
|
double Lon = Math.atan2(Y, X);
|
double Hyp = Math.sqrt(X * X + Y * Y);
|
double Lat = Math.atan2(Z, Hyp);
|
|
PointPOJO centerPoint = new PointPOJO();
|
centerPoint.setLon( Lon * 180 / Math.PI);
|
centerPoint.setLat(Lat * 180 / Math.PI);
|
return centerPoint;
|
}
|
|
/**
|
* 获取点区域并按从近到远排序
|
* @param flyAreaParam
|
* @return
|
*/
|
public static List<PointPOJO> caculatePointList(FlyAreaParam flyAreaParam){
|
List<List<PointPOJO>> areaList = flyAreaParam.getAreaList();
|
PointPOJO dockPoint = flyAreaParam.getDockPoint();
|
Double radius = flyAreaParam.getRadius();
|
|
List<PointPOJO> centerPointList = new ArrayList<>();
|
|
//根据区域获取中心点
|
areaList.forEach(area -> {
|
PointPOJO centerPoint = GeoUtils.getCenterPoint(area);
|
centerPointList.add(centerPoint);
|
});
|
|
//巡逻目标集合
|
List<PointPOJO> targetList = new ArrayList<>();
|
//获取所有中心点之后,
|
centerPointList.forEach(centerPoint -> {
|
//判断各个中心点和机场点的距离
|
double distance = GeoUtils.distance(dockPoint.getLon(), dockPoint.getLat(), centerPoint.getLon(), centerPoint.getLat());
|
|
//当距离小于半径时,添加到目标集合中
|
if (distance <= radius) {
|
centerPoint.setDistance(distance);
|
targetList.add(centerPoint);
|
}
|
});
|
|
//按距离从近到远排序
|
targetList.sort(Comparator.comparing(PointPOJO::getDistance));
|
return targetList;
|
}
|
|
/**
|
* 根据geojson获取点区域并按从近到远排序
|
* @param geoJson
|
* @return
|
*/
|
public static List<PointPOJO> caculatePointList(GeoJson geoJson,PointPOJO dockPoint,Double radius){
|
List<Feature> features = geoJson.getFeatures();
|
|
List<List<PointPOJO>> areaList = new ArrayList<>();
|
|
features.forEach(feature -> {
|
List<PointPOJO> list = new ArrayList<>();
|
List<List<Double>> coordinates = feature.getGeometry().getCoordinates().get(0);
|
|
coordinates.forEach(coordinate ->{
|
PointPOJO pointPOJO = new PointPOJO();
|
|
pointPOJO.setLon(coordinate.get(0));
|
pointPOJO.setLat(coordinate.get(1));
|
|
list.add(pointPOJO);
|
});
|
areaList.add(list);
|
});
|
|
FlyAreaParam flyAreaParam = new FlyAreaParam();
|
|
flyAreaParam.setDockPoint(dockPoint);
|
flyAreaParam.setRadius(radius);
|
flyAreaParam.setAreaList(areaList);
|
|
List<PointPOJO> pointPOJOS = caculatePointList(flyAreaParam);
|
|
return pointPOJOS;
|
}
|
|
/**
|
* 读取json文件
|
* @param path
|
* @return
|
*/
|
public static GeoJson readJsonFile(String path){
|
|
try {
|
File file = new File(path);
|
ObjectMapper objectMapper = new ObjectMapper();
|
|
objectMapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false);
|
|
return objectMapper.readValue(file, GeoJson.class);
|
} catch (IOException e) {
|
e.printStackTrace();
|
return null;
|
}
|
|
}
|
|
|
/**
|
* 根据起点经纬度、方向和距离计算目标点经纬度
|
*
|
* @param lat1 起点纬度(单位:度)
|
* @param lon1 起点经度(单位:度)
|
* @param bearing 方向角(单位:度,正北为0度,顺时针增加)
|
* lat1:起点纬度(单位:度)。
|
*
|
* lon1:起点经度(单位:度)。
|
*
|
* bearing:方向角(单位:度,正北为0度,顺时针增加)。
|
*
|
* distance:距离(单位:米)
|
* @param distance 距离(单位:米)
|
* @return 目标点的经纬度数组,格式为 [纬度, 经度]
|
*/
|
public static PointPOJO calculateDestination(double lat1, double lon1, double bearing, double distance) {
|
// 将经纬度从度数转换为弧度
|
double lat1Rad = Math.toRadians(lat1);
|
double lon1Rad = Math.toRadians(lon1);
|
|
// 将方向角从度数转换为弧度
|
double bearingRad = Math.toRadians(bearing);
|
|
// 计算目标点纬度
|
double lat2Rad = Math.asin(Math.sin(lat1Rad) * Math.cos(distance / EARTH_RADIUS) +
|
Math.cos(lat1Rad) * Math.sin(distance / EARTH_RADIUS) * Math.cos(bearingRad));
|
|
// 计算目标点经度
|
double lon2Rad = lon1Rad + Math.atan2(
|
Math.sin(bearingRad) * Math.sin(distance / EARTH_RADIUS) * Math.cos(lat1Rad),
|
Math.cos(distance / EARTH_RADIUS) - Math.sin(lat1Rad) * Math.sin(lat2Rad));
|
|
// 将结果从弧度转换回度数
|
double lat2 = Math.toDegrees(lat2Rad);
|
double lon2 = Math.toDegrees(lon2Rad);
|
PointPOJO pointPOJO=new PointPOJO();
|
pointPOJO.setLat(lat2);
|
pointPOJO.setLon(lon2);
|
return pointPOJO;
|
}
|
|
|
/**
|
* 方向与角度的关系
|
*/
|
public static final Map<String, Double> DIRECTION_ANGLES = new HashMap<>();
|
|
static {
|
DIRECTION_ANGLES.put("北", 0.0);
|
DIRECTION_ANGLES.put("东北", 45.0);
|
DIRECTION_ANGLES.put("东", 90.0);
|
DIRECTION_ANGLES.put("东南", 135.0);
|
DIRECTION_ANGLES.put("南", 180.0);
|
DIRECTION_ANGLES.put("西南", 225.0);
|
DIRECTION_ANGLES.put("西", 270.0);
|
DIRECTION_ANGLES.put("西北", 315.0);
|
}
|
|
|
|
}
|