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

起因

最近在做一个车联网项目,有一个场景是车辆定时上报当前所在经纬度等位置信息上报给平台,平台通过web页面在高德地图上展示车辆行驶路径。

由于车辆上报规则是每隔4s上报一次,一个小时也就是900个点,一天也就是21600个点,如果是10辆车就是216000个点,那如果是100辆车,甚至是10000辆车对于数据库存储来说会是一个灾难,对于渲染地图,过多的点,也减少页面的流畅度。

考虑到车辆直线行驶的时候,只需要记录第一个点和最后一个点即可,期间的点位都是没有必要的,如果拐弯的话,只需要记录一两个拐弯的点即可,这样就可以减少点数,进而减少存储或者绘图压力。

有没有一种合适的算法解决此问题呢,遂查阅资料,了解到一个算法----道格拉斯-普克算法

介绍

道格拉斯-普克算法 (Douglas–Peucker algorithm,亦称为拉默-道格拉斯-普克算法、迭代适应点算法、分裂与合并算法)是将曲线近似表示为一系列点,并减少点的数量的一种算法。它的优点是具有平移和旋转不变性,给定曲线与阈值后,抽样结果一定。—摘自百度百科

道格拉斯图解
如果有8个点,如上图(1),抽稀步骤如下:

  1. 在曲线首尾两点间虚连一条直线,求出其余各点到该直线的距离,如右图(1)。
  2. 选到点到直线距离的最大者与阈值相比较,若大于阈值,则记录该点,否则将直线两端点间各点全部舍去,如右图(2),记录第4个点,然后根据地4个点,将点分成两段1-4,4-8
  3. 然后分别对1-4,4-8重复第1、2步操作,迭代操作,即仍选距离最大者与阈值比较,依次取舍,直到无点可舍去,最后得到满足给定精度限差的曲线点坐标,如图(3)、(4)依次保留第6点、第7点,舍去其他点,即完成线的化简。

结合步骤,这里有两点数学知识,一是两点确定一条直线方程,二是求点到直线的距离。

点到直线的距离公式如下

点到直线的距离公式

PHP代码

	/**
     * 点到直线的距离
     * @param $a float
     * @param $b float
     * @param $c float
     * @param $xy string 点坐标例如 "2,2"
     * @return number
     */
    public function getDistanceFromPointToLine($a, $b, $c, $xy)
    {
   
   
        $x = explode(",", $xy)[0];
        $y = explode(",", $xy)[1];
        return abs(($a * $x + $b * $y + $c) / sqrt($a * $a + $b * $b));
    }

    /**
     * 根据两个点求直线方程 ax+by+c=0
     * @param $xy1 string 点1,例如"1,1"
     * @param $xy2 string 点2,例如"2,2"
     * @return array
     */
    public function getLineByPoint($xy1, $xy2)
    {
   
   
        $x1 = explode(",", $xy1)[0];//第一个点的横坐标
        $y1 = explode(",", $xy1)[1];//第一个点的纵坐标
        $x2 = explode(",", $xy2)[
根据您提供的引用内容,道格拉斯-普克算法是一种将曲线近似表示为一系列点,并减少点的数量的算法。如果您想在Java中使用道格拉斯-普克算法,可以考虑使用以下工具包: 1. JTS Topology Suite:JTS是一个Java库,提供了一套用于处理地理空间数据的工具。它包含了道格拉斯-普克算法的实现,可以用于经纬度路径点。您可以通过以下代码示例来使用JTS Topology Suite进行: ```java import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.GeometryFactory; import org.locationtech.jts.simplify.DouglasPeuckerSimplifier; public class DouglasPeuckerExample { public static void main(String[] args) { // 输入的经纬度路径点 Coordinate[] inputPoints = new Coordinate[] { new Coordinate(0, 0), new Coordinate(1, 1), new Coordinate(2, 2), new Coordinate(3, 3), new Coordinate(4, 4) }; // 创建GeometryFactory对象 GeometryFactory geometryFactory = new GeometryFactory(); // 创建LineString对象 org.locationtech.jts.geom.LineString lineString = geometryFactory.createLineString(inputPoints); // 使用Douglas-Peucker算法进行 double tolerance = 0.5; // 的容差值 DouglasPeuckerSimplifier simplifier = new DouglasPeuckerSimplifier(lineString); simplifier.setDistanceTolerance(tolerance); org.locationtech.jts.geom.LineString simplifiedLineString = (org.locationtech.jts.geom.LineString) simplifier.getResultGeometry(); // 输出后的经纬度路径点 Coordinate[] simplifiedPoints = simplifiedLineString.getCoordinates(); for (Coordinate point : simplifiedPoints) { System.out.println("Latitude: " + point.x + ", Longitude: " + point.y); } } } ``` 2. GeoTools:GeoTools是一个开源的Java库,用于处理地理空间数据。它提供了许多空间分析和地理信息系统功能,包括道格拉斯-普克算法的实现。您可以使用以下代码示例来使用GeoTools进行: ```java import org.geotools.geometry.jts.JTSFactoryFinder; import org.geotools.simplify.DouglasPeuckerSimplifier; import org.locationtech.jts.geom.Coordinate; import org.locationtech.jts.geom.Geometry; import org.locationtech.jts.geom.GeometryFactory; public class DouglasPeuckerExample { public static void main(String[] args) { // 输入的经纬度路径点 Coordinate[] inputPoints = new Coordinate[] { new Coordinate(0, 0), new Coordinate(1, 1), new Coordinate(2, 2), new Coordinate(3, 3), new Coordinate(4, 4) }; // 创建GeometryFactory对象 GeometryFactory geometryFactory = JTSFactoryFinder.getGeometryFactory(); // 创建LineString对象 Geometry lineString = geometryFactory.createLineString(inputPoints); // 使用Douglas-Peucker算法进行 double tolerance = 0.5; // 的容差值 DouglasPeuckerSimplifier simplifier = new DouglasPeuckerSimplifier(lineString); simplifier.setDistanceTolerance(tolerance); Geometry simplifiedGeometry = simplifier.getResultGeometry(); // 输出后的经纬度路径点 Coordinate[] simplifiedPoints = simplifiedGeometry.getCoordinates(); for (Coordinate point : simplifiedPoints) { System.out.println("Latitude: " + point.x + ", Longitude: " + point.y); } } } ``` 请注意,以上示例代码仅为演示如何使用Java工具包实现道格拉斯-普克算法进行。您可以根据自己的需求进行调整和扩展。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值