Java编程实现轨迹压缩算法开放窗口实例代码
程序员文章站
2023-12-13 19:32:16
轨迹压缩算法
场景描述
给定一个gps数据记录文件,每条记录包含经度和维度两个坐标字段,根据距离阈值压缩记录,将过滤后的所有记录的经纬度坐标构成一条轨迹
算法描述...
轨迹压缩算法
场景描述
给定一个gps数据记录文件,每条记录包含经度和维度两个坐标字段,根据距离阈值压缩记录,将过滤后的所有记录的经纬度坐标构成一条轨迹
算法描述
这种算法的用处还是相当广泛的。
轨迹压缩算法分为两大类,分别是无损压缩和有损压缩,无损压缩算法主要包括哈夫曼编码,有损压缩算法又分为批处理方式和在线数据压缩方式,其中批处理方式又包括dp(douglas-peucker)算法、td-tr(top-down time-ratio)算法和bellman算法,在线数据压缩方式又包括滑动窗口、开放窗口、基于安全区域的方法等。
大家也可参考这篇文章:《java编程实现轨迹压缩之douglas-peucker算法详细代码》
代码实现
import java.awt.color; import java.awt.graphics; import java.awt.point; import java.awt.toolkit; import java.io.bufferedreader; import java.io.file; import java.io.fileinputstream; import java.io.inputstreamreader; import java.io.randomaccessfile; import java.text.decimalformat; import java.util.arraylist; import java.util.iterator; import javax.swing.jframe; import javax.swing.jpanel; public class trajectorycom { public static void main(string[] args) throws exception{ //阈值定义 double maxdistanceerror = 30; /* * 文件读取 * */ //存放从文件读取的位置点的信息列表 arraylist<enpoint> enplist = new arraylist<enpoint>(); //源数据文件的地址 建立文件对象 //这里是需要更改的地方 改你源文件的存放地址 记住如果地址中含"\",记得再加一个"\",原因"\"是转义符号 //这里可以写成c:/users/administrator/desktop/11.6/2007-10-14-gps.log file sourcefile = new file("./2007-10-14-gps.log"); //调用文件读取函数 读取文件数据 enplist = getenpointfromfile(sourcefile); //这里是测试 有没有读到里面 看看列表里的数据个数 交作业的时候记得注释掉 system.out.println(enplist.size()); /* * 数据处理 * 方法:开放窗口轨迹压缩法 * */ //存放目标点的集合 arraylist<enpoint> repointlist = new arraylist<enpoint>(); repointlist = openwindowtra(enplist,maxdistanceerror); system.out.println(repointlist.size()); /* * 写入目标文件 * */ file targetfile = new file("./2007-10-14-gpsresult.log"); writetestpointtofile(targetfile,repointlist); /* * 压缩率计算 */ double cpl = (double)repointlist.size() / (double)enplist.size() * 100; decimalformat df = new decimalformat("0.000000"); system.out.println("压缩率:"+ df.format(cpl) + "%"); /* * 计算平均距离误差 * */ double avediserr = getmeandisterror(enplist,repointlist); system.out.println(avediserr); /* * 画线形成对比图 * */ //generateimage(enplist,repointlist); } /* * 从提供的文件信息里提取位置点 * 并将每个点的坐标数值调用转换函数存到列表里 * 函数返回一个 存放所有位置点 的集合 */ public static arraylist<enpoint> getenpointfromfile(file fgps)throws exception{ arraylist<enpoint> pgpsarray = new arraylist<enpoint>(); if(fgps.exists()&&fgps.isfile()){ inputstreamreader read = new inputstreamreader(new fileinputstream(fgps)); //输入流初始化 bufferedreader breader = new bufferedreader(read); //缓存读取初始化 string str; string[] strgps; int i = 0; while((str = breader.readline())!=null){ //每次读一行 strgps = str.split(" "); enpoint p = new enpoint(); p.id = i; i++; p.pe = (dftodu(strgps[3])); p.pn = (dftodu(strgps[5])); pgpsarray.add(p); } breader.close(); } return pgpsarray; } /** * 函数功能:将原始经纬度坐标数据转换成度 * 获取的经纬度数据为一个字符串 */ public static double dftodu(string str){ int indexd = str.indexof('.'); //获取 . 字符所在的位置 string strm = str.substring(0,indexd-2); //整数部分 string strn = str.substring(indexd-2); //小数部分 double d = double.parsedouble(strm)+double.parsedouble(strn)/60; return d; } /* * 开放窗口方法实现 * 返回一个压缩后的位置列表 * 列表每条数据存放id、点的坐标 * * 算法描述: * 初始点和浮动点计算出投影点,判断投影点和轨迹点的距离与阈值 若存在距离大于阈值 * 则初始点放入targetlist,浮动点向前检索一点作为新的初始点,新的初始点向后检索第二个作为新的浮动点 这里存在判断 即新的初始点位置+1是不是等于列表长度 这里决定了浮动点的选取 * 如此处理至终点 * */ public static arraylist<enpoint> openwindowtra(arraylist<enpoint> sourcelist,double maxdis){ arraylist<enpoint> targetlist = new arraylist<enpoint>(); //定义初始点位置 最开始初始点位置为0 int startpoint = 0; //定义浮动点位置 最开始初始点位置2 int floatpoint = 2; //定义当前轨迹点位置 最开始初始点位置为1 int nowpoint = 1; int len = sourcelist.size(); //存放所有窗口内的点的信息集合 arraylist<enpoint> listpoint = new arraylist<enpoint>(); listpoint.add(sourcelist.get(nowpoint)); //浮动点位置决定循环 while(true){ //标志 用来控制判断是否进行窗口内轨迹点更新 boolean flag = false; //计算并判断窗口内所有点和投影点的距离是否大于阈值 for (enpoint point:listpoint){ double disoftwo = getdistance(sourcelist.get(startpoint),sourcelist.get(floatpoint),point); if(disoftwo >= 30){ flag = true; break; } } if(flag){ //窗口内点距离都大于阈值 //初始点加到目标列表 targetlist.add(sourcelist.get(startpoint)); //初始点变化 startpoint = floatpoint - 1; //浮动点变化 floatpoint += 1; if(floatpoint >= len){ targetlist.add(sourcelist.get(floatpoint-1)); break; } //窗口内点变化 listpoint.clear(); //system.out.println(listpoint.size()); listpoint.add(sourcelist.get(startpoint+1)); } else{ //距离小于阈值的情况 //初始点不变 //当前窗口集合加入当前浮动点 listpoint.add(sourcelist.get(floatpoint)); //浮动点后移一位 floatpoint += 1; //如果浮动点是终点 且当前窗口点距离都小于阈值 就直接忽略窗口点 直接将终点加入目标点集合 if(floatpoint >= len){ targetlist.add(sourcelist.get(startpoint)); targetlist.add(sourcelist.get(floatpoint-1)); break; } } flag = false; } return targetlist; } /*计算投影点到轨迹点的距离 * 入口是初始点a、浮动点b、当前轨迹点c * 三角形面积公式 */ public static double getdistance(enpoint a,enpoint b,enpoint c){ double distance = 0; double a = math.abs(geodist(a,b)); double b = math.abs(geodist(b,c)); double c = math.abs(geodist(a,c)); double p = (a + b + c)/2.0; double s = math.sqrt(p * (p-a) * (p-b) * (p-c)); distance = s * 2.0 / a; return distance; } /* * arraylist 拷贝函数 * */ /*提供的函数 * 其中计算距离的函数 经过改造得到下面的距离计算方法 * 具体是怎么计算距离的 我也没研究了 * */ public static double geodist(enpoint pa,enpoint pb){ double radlat1 = rad(pa.pn); double radlat2 = rad(pb.pn); double delta_lon = rad(pb.pe - pa.pe); double top_1 = math.cos(radlat2) * math.sin(delta_lon); double top_2 = math.cos(radlat1) * math.sin(radlat2) - math.sin(radlat1) * math.cos(radlat2) * math.cos(delta_lon); double top = math.sqrt(top_1 * top_1 + top_2 * top_2); double bottom = math.sin(radlat1) * math.sin(radlat2) + math.cos(radlat1) * math.cos(radlat2) * math.cos(delta_lon); double delta_sigma = math.atan2(top, bottom); double distance = delta_sigma * 6378137.0; return distance; } public static double rad(double d){ return d * math.pi / 180.0; } /* * 将压缩后的位置点信息写入到文件中 * */ public static void writetestpointtofile(file outgpsfile,arraylist<enpoint> pgpspointfilter)throws exception{ iterator<enpoint> ifilter = pgpspointfilter.iterator(); randomaccessfile rfilter = new randomaccessfile(outgpsfile,"rw"); while(ifilter.hasnext()){ enpoint p = ifilter.next(); string sfilter = p.getresultstring(); byte[] bfilter = sfilter.getbytes(); rfilter.write(bfilter); } rfilter.close(); } /** * 函数功能:求平均距离误差 * 返回平均距离 */ public static double getmeandisterror(arraylist<enpoint> pgpsarray,arraylist<enpoint> pgpsarrayre){ double sumdist = 0.0; for (int i=1;i<pgpsarrayre.size();i++){ double="" end="pgpsarrayre.get(i).id;" int="" j="start+1;j<end;j++){" meandist="sumdist/(pgpsarray.size());" pre="" return="" start="pgpsarrayre.get(i-1).id;" sumdist=""><pre class="brush:java;">import java.text.decimalformat; public class enpoint implements comparable<enpoint>{ public int id; //点id public double pe; //经度 public double pn; //维度 public enpoint(){ } //空构造函数 public string tostring(){ return this.id+"#"+this.pn+","+this.pe; } public string getresultstring(){ decimalformat df = new decimalformat("0.000000"); return this.id+"#"+df.format(this.pe)+","+df.format(this.pn)+" \n"; } @override public int compareto(enpoint other) { if(this.id<other.id) else="" return="" this.id="">other.id) return 1; else return 0; } }
总结
以上就是本文关于java编程实现轨迹压缩算法开放窗口实例代码的全部内容,希望对大家有所帮助。如有不足之处,欢迎留言指出。