package com.xiaopeng.pushMessage.utils;
|
|
import com.alibaba.fastjson2.JSON;
|
import com.alibaba.fastjson2.JSONArray;
|
import com.alibaba.fastjson2.JSONObject;
|
import com.xiaopeng.api.dto.operation.LonLatDto;
|
import lombok.extern.slf4j.Slf4j;
|
import org.gavaghan.geodesy.Ellipsoid;
|
import org.gavaghan.geodesy.GeodeticCalculator;
|
import org.gavaghan.geodesy.GeodeticCurve;
|
import org.gavaghan.geodesy.GlobalCoordinates;
|
import org.springframework.data.geo.Point;
|
|
import java.util.*;
|
import java.util.concurrent.*;
|
|
|
@Slf4j
|
public class MapMatchingUtil {
|
|
|
|
|
/**
|
* 获取剩余导航数据
|
* @param polyline
|
* @param longitude
|
* @param latitude
|
* @return
|
*/
|
public static Map<String, List<LonLatDto>> getRemainingNavigation(List<LonLatDto> polyline, Double longitude, Double latitude){
|
//导航数据只有一个点的情况
|
Map<String, List<LonLatDto>> map = new HashMap<>();
|
if(polyline.size() == 1){
|
LonLatDto lonLatDto = polyline.get(0);
|
GlobalCoordinates source1 = new GlobalCoordinates(lonLatDto.getLatitude(), lonLatDto.getLongitude());
|
GlobalCoordinates target1 = new GlobalCoordinates(latitude, longitude);
|
GeodeticCurve geoCurve1 = new GeodeticCalculator().calculateGeodeticCurve(Ellipsoid.WGS84, source1, target1);
|
double distance =geoCurve1.getEllipsoidalDistance();
|
//判断距离小于5米,则可以返回空数据
|
if(5 >= distance){
|
map.put("unserved", new ArrayList<>());
|
map.put("served", new ArrayList<>());
|
return map;
|
}
|
//大于5米的情况,将车子当前位置添加进结果中
|
map.put("unserved", polyline);
|
map.put("served", new ArrayList<>());
|
return map;
|
}
|
//多个点位的情况,需要找出当前点位处于那两个点位之间,然后截取掉超出的部分轨迹
|
return getRecentlyPoint(polyline, longitude, latitude);
|
}
|
|
|
/**
|
* 判断点位在轨迹线路中的点位之间
|
* 返回截取后的剩余轨迹
|
* @param polyline
|
* @param longitude
|
* @param latitude
|
* @return
|
*/
|
public static Map<String, List<LonLatDto>> getRecentlyPoint(List<LonLatDto> polyline, Double longitude, Double latitude){
|
Map<String, List<LonLatDto>> map = new HashMap<>();
|
for (int i = 0; i < polyline.size(); i++) {
|
if(i == polyline.size() - 1){
|
break;
|
}
|
LonLatDto lonLatDto1 = polyline.get(i);
|
|
//车辆到第一个点位的距离
|
GlobalCoordinates source1 = new GlobalCoordinates(lonLatDto1.getLatitude(), lonLatDto1.getLongitude());
|
GlobalCoordinates target1 = new GlobalCoordinates(latitude, longitude);
|
GeodeticCurve geoCurve1 = new GeodeticCalculator().calculateGeodeticCurve(Ellipsoid.WGS84, source1, target1);
|
double distance1 =geoCurve1.getEllipsoidalDistance();
|
|
//车辆到第二个点位的距离
|
LonLatDto lonLatDto2 = polyline.get(i + 1);
|
GlobalCoordinates source2 = new GlobalCoordinates(lonLatDto2.getLatitude(), lonLatDto2.getLongitude());
|
GlobalCoordinates target2 = new GlobalCoordinates(latitude, longitude);
|
GeodeticCurve geoCurve2 = new GeodeticCalculator().calculateGeodeticCurve(Ellipsoid.WGS84, source2, target2);
|
double distance2 =geoCurve2.getEllipsoidalDistance();
|
|
//第一个点位到第二个点位的距离
|
GlobalCoordinates source3 = new GlobalCoordinates(lonLatDto1.getLatitude(), lonLatDto1.getLongitude());
|
GlobalCoordinates target3 = new GlobalCoordinates(lonLatDto2.getLatitude(), lonLatDto2.getLongitude());
|
GeodeticCurve geoCurve3 = new GeodeticCalculator().calculateGeodeticCurve(Ellipsoid.WGS84, source3, target3);
|
double distance3 =geoCurve3.getEllipsoidalDistance();
|
|
//车辆位置在第二个点位的前面
|
//这种情况需要从第二个点位开始截取,最终剩余的轨迹从第三个点位开始
|
if(distance1 > distance2 && distance1 > distance3){
|
//继续向前找,找车辆处于那一段点位中间
|
continue;
|
}
|
//车辆位置在两点之间的情况
|
//车辆位置到上一个点的距离+车辆位置到下一个点的距离 = 上一个点到下一个点的距离
|
//车辆位置到上一个点的距离+车辆位置到下一个点的距离 <= 上一个点到下一个点的距离 + 5米的漂移量
|
if ((distance1 + distance2) == distance3 || (distance1 + distance2) <= distance3 + 5) {
|
//剩余未服务的点位
|
List<LonLatDto> unserved = new ArrayList<>(polyline.subList(i + 1, polyline.size()));
|
List<LonLatDto> served = new ArrayList<>(polyline.subList(0, i + 1));
|
map.put("unserved", unserved);
|
map.put("served", served);
|
|
System.err.println("车辆在两点之间,从第二个开始截取 : " + i);
|
return map;
|
}
|
}
|
//所有数据遍历完后任然没有合适的数据则返回原始数据
|
map.put("unserved", polyline);
|
map.put("served", new ArrayList<>());
|
return map;
|
}
|
|
|
|
public static Map<String, List<LonLatDto>> getRemainingNavigationByAngle(List<LonLatDto> polyline, Double longitude, Double latitude){
|
//导航数据只有一个点的情况
|
Map<String, List<LonLatDto>> map = new HashMap<>();
|
if(polyline.size() < 3){
|
map.put("unserved", new ArrayList<>());
|
map.put("served", polyline);
|
return map;
|
}
|
|
for (int i = 0; i < polyline.size(); i++) {
|
if(i+1 == polyline.size()){
|
break;
|
}
|
LonLatDto centerPoint = polyline.get(i);
|
LonLatDto nextPoint = polyline.get(i+1);
|
|
|
// 定义三个点
|
// Point A
|
double[] pointA = {nextPoint.getLongitude(), nextPoint.getLatitude()};
|
// Point B: 中间点
|
double[] pointB = {centerPoint.getLongitude(), centerPoint.getLatitude()};
|
// Point C
|
double[] pointC = {longitude, latitude};
|
//正向夹角
|
double angle = calculateAngle(pointA, pointB, pointC);
|
// 定义三个点
|
// Point A
|
double[] pointA1 = {centerPoint.getLongitude(), centerPoint.getLatitude()};
|
// Point B: 中间点
|
double[] pointB1 = {nextPoint.getLongitude(), nextPoint.getLatitude()};
|
// Point C
|
double[] pointC1 = {longitude, latitude};
|
//反向夹角
|
double angle1 = calculateAngle(pointA1, pointB1, pointC1);
|
//正向夹角和反向夹角都小于90度,则认为车辆在两点之间
|
if(90 >= angle && 90 >= angle1){
|
double lon = centerPoint.getLongitude();
|
double lat = centerPoint.getLatitude();
|
if(angle < angle1){
|
lon = nextPoint.getLongitude();
|
lat = nextPoint.getLatitude();
|
}
|
//计算距离,定位偏移10米内
|
GlobalCoordinates source3 = new GlobalCoordinates(lat, lon);
|
GlobalCoordinates target3 = new GlobalCoordinates(latitude, longitude);
|
GeodeticCurve geoCurve3 = new GeodeticCalculator().calculateGeodeticCurve(Ellipsoid.WGS84, source3, target3);
|
double distance3 =geoCurve3.getEllipsoidalDistance();
|
if(distance3 > 10){
|
continue;
|
}
|
map.put("unserved", polyline.subList(i, polyline.size()));
|
map.put("served", polyline.subList(0, i));
|
System.err.println("车辆在两点之间,点位夹角 : " + angle + " " + i);
|
return map;
|
}
|
}
|
map.put("unserved", polyline);
|
map.put("served", new ArrayList<>());
|
return map;
|
|
}
|
|
|
/**
|
* 计算两个点位之间的夹角
|
* @param a 起始点
|
* @param m 中点
|
* @param b 终点
|
* @return
|
*/
|
public static double calculateAngle(double a_x, double a_y, double m_x, double m_y, double b_x, double b_y) {
|
// 获取从A到M和从B到M的向量
|
double[] vectorAM = new double[]{a_x - m_x, a_y - m_y};
|
double[] vectorBM = new double[]{b_x - m_x, b_y - m_y};
|
|
// 计算两个向量的点积
|
double dotProduct = vectorAM[0] * vectorBM[0] + vectorAM[1] * vectorBM[1];
|
|
// 计算两个向量的模(长度)
|
double magnitudeAM = Math.sqrt(vectorAM[0] * vectorAM[0] + vectorAM[1] * vectorAM[1]);
|
double magnitudeBM = Math.sqrt(vectorBM[0] * vectorBM[0] + vectorBM[1] * vectorBM[1]);
|
|
// 计算夹角的余弦值
|
double cosTheta = dotProduct / (magnitudeAM * magnitudeBM);
|
|
// 计算夹角(弧度)并转换为度
|
double angleInRadians = Math.acos(cosTheta);
|
double angleInDegrees = Math.toDegrees(angleInRadians);
|
|
return angleInDegrees;
|
}
|
|
// public static void main(String[] args) {
|
// // 计算坐标差
|
// double x1 = 113.3843844686235;
|
//
|
// double y1 = 23.155130575839845;
|
//
|
// double x2 = 113.3836848841087;
|
//
|
// double y2 = 23.155180919552134;
|
//
|
// double x3 = 113.38368194444445;
|
//
|
// double y3 = 23.15508361111111;
|
//
|
// //计算三条边
|
//
|
// double a = Math.sqrt((x2 - x3) * (x2 - x3) + (y2 - y3) * (y2- y3));
|
//
|
// double b = Math.sqrt((x1 - x3) * (x1 - x3) + (y1 - y3) * (y1 - y3));
|
//
|
// double c = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));
|
//
|
// //计算三个角
|
//
|
// double A = Math.toDegrees(Math.acos((a * a - b * b - c * c) / (-2 * b * c)));
|
//
|
// double B = Math.toDegrees(Math.acos((b * b - a * a - c * c) / (-2 * a * c)));
|
//
|
// double C = Math.toDegrees(Math.acos((c * c - a * a - b * b) / (-2 * a * b)));
|
//
|
// //显示结果,保留小数点后两位
|
//
|
// System.out.println("The three angles are " +
|
//
|
// Math.round(A * 100) / 100.0 + " " +
|
//
|
// Math.round(B * 100) / 100.0 + " " +
|
//
|
// Math.round(C * 100) / 100.0);
|
// }
|
|
public static void main(String[] args) {
|
String json = "[{\n" +
|
"\t\"latitude\": 23.155130575839845,\n" +
|
"\t\"longitude\": 113.3843844686235\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.155210151679693,\n" +
|
"\t\"longitude\": 113.38426593724698\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.155289727519538,\n" +
|
"\t\"longitude\": 113.38414740587048\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.15529,\n" +
|
"\t\"longitude\": 113.384147\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.155362958389055,\n" +
|
"\t\"longitude\": 113.38402358903004\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.155435916778114,\n" +
|
"\t\"longitude\": 113.38390017806007\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.15550887516717,\n" +
|
"\t\"longitude\": 113.3837767670901\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.155581833556226,\n" +
|
"\t\"longitude\": 113.38365335612013\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.155585,\n" +
|
"\t\"longitude\": 113.383648\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.155542,\n" +
|
"\t\"longitude\": 113.383621\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.155312,\n" +
|
"\t\"longitude\": 113.383648\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.155180919552134,\n" +
|
"\t\"longitude\": 113.3836848841087\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.155081,\n" +
|
"\t\"longitude\": 113.383713\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.15495796304221,\n" +
|
"\t\"longitude\": 113.38377424506344\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.154856,\n" +
|
"\t\"longitude\": 113.383825\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.154741004509642,\n" +
|
"\t\"longitude\": 113.38390239240225\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.154626009019285,\n" +
|
"\t\"longitude\": 113.38397978480451\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.154593,\n" +
|
"\t\"longitude\": 113.384002\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.154488868635756,\n" +
|
"\t\"longitude\": 113.3840956684042\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.15438473727151,\n" +
|
"\t\"longitude\": 113.3841893368084\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.153869,\n" +
|
"\t\"longitude\": 113.384732\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.153783434325412,\n" +
|
"\t\"longitude\": 113.38484554532484\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.153697868650823,\n" +
|
"\t\"longitude\": 113.38495909064967\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.153612302976235,\n" +
|
"\t\"longitude\": 113.3850726359745\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.153606,\n" +
|
"\t\"longitude\": 113.385081\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.15352802191651,\n" +
|
"\t\"longitude\": 113.38520076538181\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.153450043833022,\n" +
|
"\t\"longitude\": 113.38532053076364\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.153397,\n" +
|
"\t\"longitude\": 113.385402\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.15332878835048,\n" +
|
"\t\"longitude\": 113.38552854437049\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.15326057670096,\n" +
|
"\t\"longitude\": 113.38565508874098\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.153252,\n" +
|
"\t\"longitude\": 113.385671\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.153190501345524,\n" +
|
"\t\"longitude\": 113.3858015058656\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.15312900269105,\n" +
|
"\t\"longitude\": 113.38593201173121\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.15308,\n" +
|
"\t\"longitude\": 113.386036\n" +
|
"}, {\n" +
|
"\t\"latitude\": 23.15306,\n" +
|
"\t\"longitude\": 113.386128\n" +
|
"}]";
|
List<LonLatDto> polyline = JSON.parseArray(json, LonLatDto.class);
|
String xcgj = "[{\"longitude\":113.38358194444445,\"latitude\":23.15508361111111}]";
|
List<LonLatDto> lonLatDtos = JSON.parseArray(xcgj, LonLatDto.class);
|
for (LonLatDto lonLatDto : lonLatDtos) {
|
Map<String, List<LonLatDto>> remainingNavigation = getRemainingNavigation(polyline, lonLatDto.getLongitude(), lonLatDto.getLatitude());
|
List<LonLatDto> unserved = remainingNavigation.get("unserved");
|
List<LonLatDto> served = remainingNavigation.get("served");
|
System.err.println(JSON.toJSONString(served));
|
polyline = unserved;
|
|
}
|
System.err.println("------------------------------------");
|
|
polyline = JSON.parseArray(json, LonLatDto.class);
|
for (LonLatDto lonLatDto : lonLatDtos) {
|
Map<String, List<LonLatDto>> remainingNavigation = getRemainingNavigationByAngle(polyline, lonLatDto.getLongitude(), lonLatDto.getLatitude());
|
List<LonLatDto> unserved = remainingNavigation.get("unserved");
|
List<LonLatDto> served = remainingNavigation.get("served");
|
System.err.println(JSON.toJSONString(served));
|
polyline = unserved;
|
|
}
|
|
|
|
|
// JSONArray objects = JSON.parseArray("[{\n" +
|
// "\t\"latitude\": 23.155130575839845,\n" +
|
// "\t\"longitude\": 113.3843844686235\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.155210151679693,\n" +
|
// "\t\"longitude\": 113.38426593724698\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.155289727519538,\n" +
|
// "\t\"longitude\": 113.38414740587048\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.15529,\n" +
|
// "\t\"longitude\": 113.384147\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.155362958389055,\n" +
|
// "\t\"longitude\": 113.38402358903004\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.155435916778114,\n" +
|
// "\t\"longitude\": 113.38390017806007\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.15550887516717,\n" +
|
// "\t\"longitude\": 113.3837767670901\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.155581833556226,\n" +
|
// "\t\"longitude\": 113.38365335612013\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.155585,\n" +
|
// "\t\"longitude\": 113.383648\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.155542,\n" +
|
// "\t\"longitude\": 113.383621\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.155312,\n" +
|
// "\t\"longitude\": 113.383648\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.155180919552134,\n" +
|
// "\t\"longitude\": 113.3836848841087\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.155081,\n" +
|
// "\t\"longitude\": 113.383713\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.15495796304221,\n" +
|
// "\t\"longitude\": 113.38377424506344\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.154856,\n" +
|
// "\t\"longitude\": 113.383825\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.154741004509642,\n" +
|
// "\t\"longitude\": 113.38390239240225\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.154626009019285,\n" +
|
// "\t\"longitude\": 113.38397978480451\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.154593,\n" +
|
// "\t\"longitude\": 113.384002\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.154488868635756,\n" +
|
// "\t\"longitude\": 113.3840956684042\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.15438473727151,\n" +
|
// "\t\"longitude\": 113.3841893368084\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.153869,\n" +
|
// "\t\"longitude\": 113.384732\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.153783434325412,\n" +
|
// "\t\"longitude\": 113.38484554532484\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.153697868650823,\n" +
|
// "\t\"longitude\": 113.38495909064967\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.153612302976235,\n" +
|
// "\t\"longitude\": 113.3850726359745\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.153606,\n" +
|
// "\t\"longitude\": 113.385081\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.15352802191651,\n" +
|
// "\t\"longitude\": 113.38520076538181\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.153450043833022,\n" +
|
// "\t\"longitude\": 113.38532053076364\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.153397,\n" +
|
// "\t\"longitude\": 113.385402\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.15332878835048,\n" +
|
// "\t\"longitude\": 113.38552854437049\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.15326057670096,\n" +
|
// "\t\"longitude\": 113.38565508874098\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.153252,\n" +
|
// "\t\"longitude\": 113.385671\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.153190501345524,\n" +
|
// "\t\"longitude\": 113.3858015058656\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.15312900269105,\n" +
|
// "\t\"longitude\": 113.38593201173121\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.15308,\n" +
|
// "\t\"longitude\": 113.386036\n" +
|
// "}, {\n" +
|
// "\t\"latitude\": 23.15306,\n" +
|
// "\t\"longitude\": 113.386128\n" +
|
// "}]");
|
// String str = "[";
|
// for (int i = 0; i < objects.size(); i++) {
|
// JSONObject jsonObject = objects.getJSONObject(i);
|
// str += "[" + jsonObject.getDouble("longitude") + "," + jsonObject.getDouble("latitude") + "],";
|
// }
|
// System.err.println(str + "]");
|
}
|
|
|
|
private static final double EARTH_RADIUS_KM = 6371.0; // 地球平均半径 (公里)
|
|
/**
|
* 计算由三个经纬度点构成的夹角
|
*
|
* @param pointA 经纬度点 A (格式: {经度, 纬度})
|
* @param pointB 经纬度点 B (格式: {经度, 纬度}) - 此点为夹角的顶点
|
* @param pointC 经纬度点 C (格式: {经度, 纬度})
|
* @return 夹角 ABC 的大小,单位为度
|
*/
|
public static double calculateAngle(double[] pointA, double[] pointB, double[] pointC) {
|
// 1. 将经纬度(度)转换为弧度
|
double lat1 = Math.toRadians(pointA[1]);
|
double lon1 = Math.toRadians(pointA[0]);
|
double lat2 = Math.toRadians(pointB[1]);
|
double lon2 = Math.toRadians(pointB[0]);
|
double lat3 = Math.toRadians(pointC[1]);
|
double lon3 = Math.toRadians(pointC[0]);
|
|
// 2. 计算各点对之间的中心角 (angular distance)
|
double angularDist_AB = haversineDistanceInRadians(lat1, lon1, lat2, lon2);
|
double angularDist_BC = haversineDistanceInRadians(lat2, lon2, lat3, lon3);
|
double angularDist_AC = haversineDistanceInRadians(lat1, lon1, lat3, lon3);
|
|
// 3. 使用球面余弦定律计算夹角 B (angle at point B)
|
// cos(B) = (cos(b) - cos(c) * cos(a)) / (sin(c) * sin(a))
|
// 其中 a 是 BC 的中心角, b 是 AC 的中心角, c 是 AB 的中心角
|
double cos_angle_B = (
|
Math.cos(angularDist_AC) -
|
Math.cos(angularDist_AB) * Math.cos(angularDist_BC)
|
) / (
|
Math.sin(angularDist_AB) * Math.sin(angularDist_BC)
|
);
|
|
// 4. 防止由于浮点数精度问题导致的无效输入 (例如 cos_angle_B > 1 或 < -1)
|
cos_angle_B = Math.max(-1.0, Math.min(1.0, cos_angle_B));
|
|
// 5. 计算夹角 B 并转换为度
|
double angle_B_rad = Math.acos(cos_angle_B);
|
double angle_B_deg = Math.toDegrees(angle_B_rad);
|
|
return angle_B_deg;
|
}
|
|
/**
|
* 使用 Haversine 公式计算两个经纬度点之间的中心角 (弧度)
|
* 此函数计算的是球心角,不是地面距离
|
*/
|
private static double haversineDistanceInRadians(double lat1, double lon1, double lat2, double lon2) {
|
double delta_lat = lat2 - lat1;
|
double delta_lon = lon2 - lon1;
|
|
double a = Math.sin(delta_lat / 2) * Math.sin(delta_lat / 2) +
|
Math.cos(lat1) * Math.cos(lat2) *
|
Math.sin(delta_lon / 2) * Math.sin(delta_lon / 2);
|
|
double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1 - a));
|
|
return c; // 返回中心角 (弧度)
|
}
|
|
// --- 示例 ---
|
// public static void main(String[] args) {
|
// // 定义三个点
|
// // Point A: 北京天安门广场附近
|
// double[] pointA = {113.3836848841087,23.155180919552134};
|
// // Point B: 北京某个中间点
|
// double[] pointB = {113.383713,23.155081};
|
// // Point C: 北京另一个方向的点
|
// double[] pointC = {113.38368194444445,23.15508361111111};
|
//
|
// double angle = calculateAngle(pointA, pointB, pointC);
|
//
|
// System.out.printf("由点 A(%f, %f), B(%f, %f), C(%f, %f) 构成的夹角 ABC 为: %.2f 度%n",
|
// pointA[0], pointA[1], pointB[0], pointB[1], pointC[0], pointC[1], angle);
|
// }
|
}
|