GPS道格拉斯轨迹抽稀算法【经纬度轨迹纠偏】直接拷贝使用!!!

方法算的,和高德算的,大概相差了几十米不等,应该可以满足大多数人的需求,要是你要更精确地话,那还是问问高德的客服吧,这事帮不了你了~~【注意,更新了一个方法,在最后,可以比较着看】

/**
 * 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;
    }

猜你喜欢

转载自blog.csdn.net/fengyeNom1/article/details/113736460
今日推荐