1、抽稀

通俗点讲,直接举个栗子吧:我们知道运动轨迹实际上是由很多个经纬度坐标连接而成。那么我们是否需要将所有运动时记录下来的经纬度坐标都用来绘制轨迹呢?其实是没必要的,很多数据其实是多余的,实际上将这些多余的数据剔除仍然能保证轨迹曲线形状大致不变,而且还能让曲线更平滑更节省存储空间,类似这样的过程我们就称之为抽稀。抽稀的算法很多,这里将介绍一种经典的算法:道格拉斯-普克(Douglas-Peuker)算法。

2、道格拉斯-普克(Douglas-Peuker)算法

还是举个栗子吧,假设在平面坐标系上有一条由N个坐标点组成的曲线,已设定一个阈值epsilon。

(1)首先,将起始点与结束点用直线连接, 再找出到该直线的距离最大,同时又大于阈值epsilon的点并记录下该点的位置(这里暂且称其为最大阈值点),如图所示:

(2)接着,以该点为分界点,将整条曲线分割成两段(这里暂且称之为左曲线和右曲线),将这两段曲线想象成独立的曲线然后重复操作(1),找出两边的最大阈值点,如图所示:

(3)最后,重复操作(2)(1)直至再也找不到最大阈值点为止,然后将所有最大阈值点按顺序连接起来便可以得到一条更简化的,更平滑的,与原曲线十分近似的曲线,如图所示:

3、如何实现?

OK,终于到代码登场了,不废话,上代码:

Point类:

public class Point {

double x;

double y;

public Point(int x, int y) {

this.x = x;

this.y = y;

System.out.print("(" + x + "," + y + ") ");

}

public static Point instance(int x, int y) {

return new Point(x, y);

}

}

DouglasPeuckerUtil 类:

public class DouglasPeuckerUtil {

public static void main(String[] args) {

System.out.print("原始坐标:");

List points = new ArrayList<>();

List result = new ArrayList<>();

points.add(Point.instance(1, 1));

points.add(Point.instance(2, 2));

points.add(Point.instance(3, 4));

points.add(Point.instance(4, 1));

points.add(Point.instance(5, 0));

points.add(Point.instance(6, 3));

points.add(Point.instance(7, 5));

points.add(Point.instance(8, 2));

points.add(Point.instance(9, 1));

points.add(Point.instance(10, 6));

System.out.println("");

System.out

.println("=====================================================================");

System.out.print("抽稀坐标:");

result = DouglasPeucker(points, 1);

for (Point p : result) {

System.out.print("(" + p.x + "," + p.y + ") ");

}

}

public static List DouglasPeucker(List points, int epsilon) {

// 找到最大阈值点,即操作(1)

double maxH = 0;

int index = 0;

int end = points.size();

for (int i = 1; i < end - 1; i++) {

double h = H(points.get(i), points.get(0), points.get(end - 1));

if (h > maxH) {

maxH = h;

index = i;

}

}

// 如果存在最大阈值点,就进行递归遍历出所有最大阈值点

List result = new ArrayList<>();

if (maxH > epsilon) {

List leftPoints = new ArrayList<>();// 左曲线

List 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 leftResult = new ArrayList<>();

List 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;

}

/**

* 计算点到直线的距离

*

* @param p

* @param s

* @param e

* @return

*/

public static double H(Point p, Point s, Point e) {

double AB = distance(s, e);

double CB = distance(p, s);

double CA = distance(p, e);

double S = helen(CB, CA, AB);

double H = 2 * S / AB;

return H;

}

/**

* 计算两点之间的距离

*

* @param p1

* @param p2

* @return

*/

public static double distance(Point p1, Point p2) {

double x1 = p1.x;

double y1 = p1.y;

double x2 = p2.x;

double y2 = p2.y;

double xy = Math.sqrt((x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2));

return xy;

}

/**

* 海伦公式,已知三边求三角形面积

*

* @param cB

* @param cA

* @param aB

* @return 面积

*/

public static double helen(double CB, double CA, double AB) {

double p = (CB + CA + AB) / 2;

double S = Math.sqrt(p * (p - CB) * (p - CA) * (p - AB));

return S;

}

输出结果:

OK,平面坐标上的Douglas-Peuker算法已经基本实现了!但是如果换成经纬度呢?其实不用担心,地图API一般都会提供计算两个经纬度坐标之间距离的函数,所以万变不离其宗,思路还是一样的,大胆点,代码啪啪啪的敲起来吧!

4、参考示例

MySQL抽稀_Android GPS定位轨迹抽稀之道格拉斯-普克(Douglas-Peuker)算法详解相关推荐

  1. GPS定位轨迹抽稀之道格拉斯-普克(Douglas-Peuker)算法详解

    目录 1. 抽稀 2. 原理 3. 具体思路 4. 代码示例 道格拉斯-普克算法是我们常用的一种轨迹点的抽稀算法,抽稀出来的点可以尽可能的维持原先轨迹点的大体轮廓,剔除一些非必要的点 2. 原理 假设 ...

  2. 2021-03-20 GPS抽稀之道格拉斯-普克(Douglas-Peuker)算法

    GPS抽稀之道格拉斯-普克(Douglas-Peuker)算法 道格拉斯-普克算法是我们常用的一种轨迹点的抽稀算法,抽稀出来的点可以尽可能的维持原先轨迹点的大体轮廓,剔除一些非必要的点. 道格拉斯-普 ...

  3. Android Arcgis 优化--------道格拉斯-普克抽稀算法

    最近偶然接触到抽稀相关的算法.发现道格拉斯抽稀算法很适合目前项目某一个功能优化.所以我抽空看了一下,也写了针对经纬度路径点抽稀的工具类.下面我们先看看该算法的介绍. 介绍 道格拉斯-普克算法(Doug ...

  4. 【Java代码】道格拉斯-普克 Douglas-Peucker 抽稀算法(算法流程图解+使用JDK8方法实现+详细注解源码)

    1.算法说明   道格拉斯-普克算法 Douglas-Peucker Algorithm 简称 D-P 算法,亦称为拉默-道格拉斯-普克算法.迭代适应点算法.分裂与合并算法,是将曲线近似表示为一系列点 ...

  5. 道格拉斯-普克算法(经纬度或坐标点抽稀)

    起因 最近在做一个车联网项目,有一个场景是车辆定时上报当前所在经纬度等位置信息上报给平台,平台通过web页面在高德地图上展示车辆行驶路径. 由于车辆上报规则是每隔4s上报一次,一个小时也就是900个点 ...

  6. 道格拉斯-普克 抽稀算法

    道格拉斯-普克抽稀算法,是用来对大量冗余的图形数据点进行压缩以提取必要的数据点.该算法实现抽稀的过程是:先将一条曲线首尾点虚连一条直线,求其余各点到该直线的距离,取其最大者与规定的临界值相比较,若小于 ...

  7. 道格拉斯-普克抽稀算法

    道格拉斯-普克抽稀算法,是用来对大量冗余的图形数据点进行压缩以提取必要的数据点.该算法实现抽稀的过程是:先将一条曲线首尾点虚连一条直线,求其余各点到该直线的距离,取其最大者与规定的临界值相比较,若小于 ...

  8. 【Python】道格拉斯-普克抽稀算法

    常用的地图点压缩 1.算法应用 道格拉斯-普克抽稀算法,是用来对大量冗余的图形数据点进行压缩以提取必要的数据点. 2.算法步骤 对每一条曲线的首末点虚连一条直线,求所有点与直线的距离, 并找出最大距离 ...

  9. mysql数据库BKA算法详解

    BKA算法详解 Batched Key Access理解了 MRR 性能提升的原理,我们就能理解 MySQL 在 5.6 版本后开始引入的 BatchedKey Access(BKA) 算法了.这个 ...

  10. Apollo6.0代码Lattice算法详解——Part5: 生成横纵向轨迹

    Apollo6.0代码Lattice算法详解--Part5: 生成横纵向轨迹 0.前置知识 1.涉及主要函数 2.函数关系 3.部分函数代码详解 3.1 lattice_planner.cc中代码部分 ...

最新文章

  1. 【智力题】国际象棋问题
  2. Vue-cli代理解决跨域问题
  3. 获取this_带你彻底弄清JavaScript的关键字this
  4. php学习之路五(表单验证)
  5. HTML-CSS背景渐进色
  6. pc安装linux内核,PC/104平台嵌入式Linux系统核心定制方法
  7. 黑马程序员—java基础总结1
  8. C++之‘malloc’ was not declared in this scope和invalid conversion from ‘void*’ to ‘char*’
  9. 见识过世界的强大,才能拥有掌握世界的力量
  10. Python基础:搭建开发环境(1)
  11. 三菱q系列特殊继电器一览表_2020山西三菱Q系列PLC模块回收购销
  12. Weblogic部署
  13. 使用Java生成验证码
  14. 教你快速录制gif动图
  15. cass坡度土方计算案例_CASS软件中方格网法计算土方量的原理及误差分析
  16. maya制作玻璃材质
  17. 【数据结构】循环队列的front,rear指针以及队列满的条件、计算队列长度
  18. echarts 桑基图 添加标志线问题
  19. html input hiden,input hidden属性
  20. 解决MySQL CPU占用100%的经验总结 转

热门文章

  1. 使用ASP.NET MVC构建HTML5离线web应用程序
  2. M study summarize
  3. violate原理,java内存模型,可见性,cache二级内存模型
  4. 在删除 maven 聚合工程里面的一个子项目的时候,启动项目报错:XXXpom.xml does not exist
  5. 手动配置 hibernate 项目
  6. 统计某个路径下的总文件个数,及总行数(不含空行)
  7. hdu 2037 这个夏天不AC (java)
  8. GoldenGate新增表
  9. Visual Studio 2013无法打开IIS Express Web的解决办法
  10. shell之脚本片断