方法算的,和高德算的,大概相差了几十米不等,应该可以满足大多数人的需求,要是你要更精确地话,那还是问问高德的客服吧,这事帮不了你了~~【注意,更新了一个方法,在最后,可以比较着看】
/**
* Create by Mazhanzhu on 2021/2/2
* 两点之间距离计算
*/
public class MapDistance {
public static final String TAG = "MapDistance";
private double DEF_PI = 3.14159265359; // PI
private double DEF_2PI = 6.28318530712; // 2*PI
private double DEF_PI180 = 0.01745329252; // PI/180.0
private double DEF_R = 6370693.5; // radius of earth
public static final int WARNDIS = 125;//警告距离,时速150公里情况下,3秒距离为125米
private MapDistance() {
}
private static MapDistance instance;
public static synchronized MapDistance getInstance() {
if (instance == null) {
instance = new MapDistance();
}
return instance;
}
/**
* 返回为m,适合短距离测量
*
* @param lon1
* @param lat1
* @param lon2
* @param lat2
* @return
*/
public double getShortDistance(double lon1, double lat1, double lon2, double lat2) {
double ew1, ns1, ew2, ns2;
double dx, dy, dew;
double distance;
// 角度转换为弧度
ew1 = lon1 * DEF_PI180;
ns1 = lat1 * DEF_PI180;
ew2 = lon2 * DEF_PI180;
ns2 = lat2 * DEF_PI180;
// 经度差
dew = ew1 - ew2;
// 若跨东经和西经180 度,进行调整
if (dew > DEF_PI)
dew = DEF_2PI - dew;
else if (dew < -DEF_PI)
dew = DEF_2PI + dew;
dx = DEF_R * Math.cos(ns1) * dew; // 东西方向长度(在纬度圈上的投影长度)
dy = DEF_R * (ns1 - ns2); // 南北方向长度(在经度圈上的投影长度)
// 勾股定理求斜边长
distance = Math.sqrt(dx * dx + dy * dy);
return distance;
}
/**
* 返回为m,适合长距离测量
*
* @param lon1
* @param lat1
* @param lon2
* @param lat2
* @return
*/
public double getLongDistance(double lon1, double lat1, double lon2, double lat2) {
double ew1, ns1, ew2, ns2;
double distance;
// 角度转换为弧度
ew1 = lon1 * DEF_PI180;
ns1 = lat1 * DEF_PI180;
ew2 = lon2 * DEF_PI180;
ns2 = lat2 * DEF_PI180;
// 求大圆劣弧与球心所夹的角(弧度)
distance = Math.sin(ns1) * Math.sin(ns2) + Math.cos(ns1) * Math.cos(ns2)
* Math.cos(ew1 - ew2);
// 调整到[-1..1]范围内,避免溢出
if (distance > 1.0)
distance = 1.0;
else if (distance < -1.0)
distance = -1.0;
// 求大圆劣弧长度
distance = DEF_R * Math.acos(distance);
return distance;
}
public void getReaLKM(double allKm, List<Bean_OwnPointData> allList, Date_Mz dateMz) {
ArrayList<Bean_OwnPointData> queryAll = new ArrayList<>();
if (allList.size() > 3) {
List<Bean_OwnPointData> dataList = DouglasPeucker(allList, 1);
Log_Ma.e(TAG, "道格拉斯轨迹抽稀算法:" + queryAll.size() + "/" + new Gson().toJson(queryAll));
if (dataList.size() > 0) {
queryAll.addAll(dataList);
} else {
queryAll.addAll(allList);
}
} else {
queryAll.addAll(allList);
}
double allm = 0.0;
double sum;
if (queryAll.size() == 0) {
dateMz.success(allKm);
} else {
List<TraceLocation> points = new ArrayList<>();
for (int i = 0; i < queryAll.size(); i++) {
TraceLocation traceLocation = new TraceLocation(queryAll.get(i).getLatitude(), queryAll.get(i).getLongitude(),
queryAll.get(i).getSpeed(), queryAll.get(i).getBearing(), queryAll.get(i).getTime());
points.add(traceLocation);
if (i > 0) {
Bean_OwnPointData item1 = queryAll.get(i);
Bean_OwnPointData item2 = queryAll.get(i - 1);
double mDistance = MapDistance.getInstance().getShortDistance(
item1.getLongitude(), item1.getLatitude(),
item2.getLongitude(), item2.getLatitude());
Log_Ma.e(TAG, "距离" + mDistance);
allm = DoubleUtil.sum(allm, mDistance);
}
}
double div = DoubleUtil.div(allm, 1000, 2);
String format = new DecimalFormat(".00").format(div);
sum = DoubleUtil.sum(allKm, Double.parseDouble(format));
Log_Ma.e(TAG, "距离 总的数据" + allm);
dateMz.success(sum);
}
}
public interface Date_Mz {
void success(double mzzSUM);
}
/**
* GPS道格拉斯轨迹抽稀算法
*
* @param points 传入点的集合
* @param epsilon 位置点太近动态画在图上不是很明显,可以设置点之间距离大于为5米才添加到集合中,这里可以加入点抽稀算法
* @return
*/
private List<Bean_OwnPointData> DouglasPeucker(List<Bean_OwnPointData> points, int epsilon) {
double maxH = 0;
int index = 0;
int end = points.size();
for (int i = 1; i < end - 1; i++) {
double h = H(points.get(0), points.get(i), points.get(end - 1));
if (h > maxH) {
maxH = h;
index = i;
}
}
List<Bean_OwnPointData> result = new ArrayList<>();
if (maxH > epsilon) {
List<Bean_OwnPointData> leftPoints = new ArrayList<>();//左曲线
List<Bean_OwnPointData> rightPoints = new ArrayList<>();//右曲线
//分别保存左曲线和右曲线的坐标点
for (int i = 0; i < end; i++) {
if (i <= index) {
leftPoints.add(points.get(i));
if (i == index) {
rightPoints.add(points.get(i));
}
} else {
rightPoints.add(points.get(i));
}
}
List<Bean_OwnPointData> leftResult = new ArrayList<>();
List<Bean_OwnPointData> rightResult = new ArrayList<>();
leftResult = DouglasPeucker(leftPoints, epsilon);
rightResult = DouglasPeucker(rightPoints, epsilon);
rightResult.remove(0);//移除重复的点
leftResult.addAll(rightResult);
result = leftResult;
} else {
result.add(points.get(0));
result.add(points.get(end - 1));
}
return result;
}
public double H(Bean_OwnPointData A, Bean_OwnPointData B, Bean_OwnPointData C) {
double c = getShortDistance(A.getLongitude(), A.getLatitude(), B.getLongitude(), B.getLatitude());
double b = getShortDistance(A.getLongitude(), A.getLatitude(), C.getLongitude(), C.getLatitude());
double a = getShortDistance(C.getLongitude(), C.getLatitude(), B.getLongitude(), C.getLatitude());
double S = helen(a, b, c);
double H = 2 * S / c;
return H;
}
public double helen(double a, double b, double c) {
double p = (a + b + c) / 2;
double S = Math.sqrt(p * (p - a) * (p - b) * (p - c));
return S;
}
}
里面用到的一个Bean类,也给你们吧
public class Bean_OwnPointData {
@PrimaryKey(AssignType.AUTO_INCREMENT)
long id;
private String routeId;
private double latitude = 0.0; // 纬度 39°54′27
private double longitude = 0.0; // 经度 116°23′17
private float speed;
private float bearing;
private long time;
private String IntOut;//1 圈内 2圈外
/**
* @param longitude 125.310531
* @param latitude 43.82308
*/
public Bean_OwnPointData(double longitude, double latitude) {
this.latitude = latitude;
this.longitude = longitude;
}
public Bean_OwnPointData() {
}
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getRouteId() {
return routeId == null ? "" : routeId;
}
public void setRouteId(String routeId) {
this.routeId = routeId;
}
public double getLatitude() {
return latitude;
}
public void setLatitude(double latitude) {
this.latitude = latitude;
}
public double getLongitude() {
return longitude;
}
public void setLongitude(double longitude) {
this.longitude = longitude;
}
public float getSpeed() {
return speed;
}
public void setSpeed(float speed) {
this.speed = speed;
}
public float getBearing() {
return bearing;
}
public void setBearing(float bearing) {
this.bearing = bearing;
}
public long getTime() {
return time;
}
public void setTime(long time) {
this.time = time;
}
public String getIntOut() {
return IntOut == null ? "" : IntOut;
}
public void setIntOut(String intOut) {
IntOut = intOut;
}
}
废话不多说,不逼逼,完事了,大家散吧~该吃中午饭了~
更新了一个方法,原来的抽吸太严重了【可以比较着先看】
/**
* GPS道格拉斯轨迹抽稀算法【更新了一个方法,原来的抽吸太严重了】
*
* @param points 传入点的集合
* @param epsilon 位置点太近动态画在图上不是很明显,可以设置点之间距离大于为5米才添加到集合中,这里可以加入点抽稀算法
* @return
*/
private List<Bean_OwnPointData> DouglasPeucker(List<Bean_OwnPointData> points, int epsilon) {
List<Bean_OwnPointData> result = new ArrayList<>();
//fixme 方法一
result.add(points.get(0));
int mBeiNum = 1;
for (int i = 1; i < points.size(); i++) {
double distance = getLongDistance(
points.get(i).getLongitude(), points.get(i).getLatitude(),
points.get(i - mBeiNum).getLongitude(), points.get(i - mBeiNum).getLatitude());
if (distance > WARNDIS * mBeiNum) {
mBeiNum++;
continue;
} else {
mBeiNum = 1;
result.add(points.get(i));
}
}
//fixme 方法二
/*double maxH = 0;
int index = 0;
for (int i = 1; i < points.size() - 1; i++) {
double h = H(points.get(0), points.get(i), points.get(points.size() - 1));
if (h > maxH) {
maxH = h;
index = i;
}
}
if (maxH > epsilon) {
List<Bean_OwnPointData> leftPoints = new ArrayList<>();//左曲线
List<Bean_OwnPointData> rightPoints = new ArrayList<>();//右曲线
//分别保存左曲线和右曲线的坐标点
for (int i = 0; i < points.size(); i++) {
if (i <= index) {
leftPoints.add(points.get(i));
if (i == index) {
rightPoints.add(points.get(i));
}
} else {
rightPoints.add(points.get(i));
}
}
List<Bean_OwnPointData> leftResult = new ArrayList<>();
List<Bean_OwnPointData> rightResult = new ArrayList<>();
leftResult = DouglasPeucker(leftPoints, epsilon);
rightResult = DouglasPeucker(rightPoints, epsilon);
rightResult.remove(0);//移除重复的点
leftResult.addAll(rightResult);
result = leftResult;
} else {
result.add(points.get(0));
result.add(points.get(points.size() - 1));
}*/
return result;
}