Java编程实现轨迹压缩算法开放窗口实例代码
轨迹压缩算法
场景描述
给定一个GPS数据记录文件,每条记录包含经度和维度两个坐标字段,根据距离阈值压缩记录,将过滤后的所有记录的经纬度坐标构成一条轨迹
算法描述
这种算法的用处还是相当广泛的。
轨迹压缩算法分为两大类,分别是无损压缩和有损压缩,无损压缩算法主要包括哈夫曼编码,有损压缩算法又分为批处理方式和在线数据压缩方式,其中批处理方式又包括DP(Douglas-Peucker)算法、TD-TR(Top-DownTime-Ratio)算法和Bellman算法,在线数据压缩方式又包括滑动窗口、开放窗口、基于安全区域的方法等。
大家也可参考这篇文章:《Java编程实现轨迹压缩之Douglas-Peucker算法详细代码》
代码实现
importjava.awt.Color; importjava.awt.Graphics; importjava.awt.Point; importjava.awt.Toolkit; importjava.io.BufferedReader; importjava.io.File; importjava.io.FileInputStream; importjava.io.InputStreamReader; importjava.io.RandomAccessFile; importjava.text.DecimalFormat; importjava.util.ArrayList; importjava.util.Iterator; importjavax.swing.JFrame; importjavax.swing.JPanel; publicclassTrajectoryCom{ publicstaticvoidmain(String[]args)throwsException{ //阈值定义 doublemaxDistanceError=30; /* *文件读取 **/ //存放从文件读取的位置点的信息列表 ArrayListENPList=newArrayList (); //源数据文件的地址建立文件对象 //这里是需要更改的地方改你源文件的存放地址记住如果地址中含"\",记得再加一个"\",原因"\"是转义符号 //这里可以写成C:/Users/Administrator/Desktop/11.6/2007-10-14-GPS.log FilesourceFile=newFile("./2007-10-14-GPS.log"); //调用文件读取函数读取文件数据 ENPList=getENPointFromFile(sourceFile); //这里是测试有没有读到里面看看列表里的数据个数交作业的时候记得注释掉 System.out.println(ENPList.size()); /* *数据处理 *方法:开放窗口轨迹压缩法 **/ //存放目标点的集合 ArrayList rePointList=newArrayList (); rePointList=openWindowTra(ENPList,maxDistanceError); System.out.println(rePointList.size()); /* *写入目标文件 **/ FiletargetFile=newFile("./2007-10-14-GPSResult.log"); writeTestPointToFile(targetFile,rePointList); /* *压缩率计算 */ doublecpL=(double)rePointList.size()/(double)ENPList.size()*100; DecimalFormatdf=newDecimalFormat("0.000000"); System.out.println("压缩率:"+df.format(cpL)+"%"); /* *计算平均距离误差 **/ doubleaveDisErr=getMeanDistError(ENPList,rePointList); System.out.println(aveDisErr); /* *画线形成对比图 **/ //generateImage(ENPList,rePointList); } /* *从提供的文件信息里提取位置点 *并将每个点的坐标数值调用转换函数存到列表里 *函数返回一个存放所有位置点的集合 */ publicstaticArrayList getENPointFromFile(FilefGPS)throwsException{ ArrayList pGPSArray=newArrayList (); if(fGPS.exists()&&fGPS.isFile()){ InputStreamReaderread=newInputStreamReader(newFileInputStream(fGPS)); //输入流初始化 BufferedReaderbReader=newBufferedReader(read); //缓存读取初始化 Stringstr; String[]strGPS; inti=0; while((str=bReader.readLine())!=null){ //每次读一行 strGPS=str.split(""); ENPointp=newENPoint(); p.id=i; i++; p.pe=(dfTodu(strGPS[3])); p.pn=(dfTodu(strGPS[5])); pGPSArray.add(p); } bReader.close(); } returnpGPSArray; } /** *函数功能:将原始经纬度坐标数据转换成度 *获取的经纬度数据为一个字符串 */ publicstaticdoubledfTodu(Stringstr){ intindexD=str.indexOf('.'); //获取.字符所在的位置 StringstrM=str.substring(0,indexD-2); //整数部分 StringstrN=str.substring(indexD-2); //小数部分 doubled=double.parsedouble(strM)+double.parsedouble(strN)/60; returnd; } /* *开放窗口方法实现 *返回一个压缩后的位置列表 *列表每条数据存放ID、点的坐标 * *算法描述: *初始点和浮动点计算出投影点,判断投影点和轨迹点的距离与阈值若存在距离大于阈值 *则初始点放入targetList,浮动点向前检索一点作为新的初始点,新的初始点向后检索第二个作为新的浮动点这里存在判断即新的初始点位置+1是不是等于列表长度这里决定了浮动点的选取 *如此处理至终点 **/ publicstaticArrayList openWindowTra(ArrayList sourceList,doublemaxDis){ ArrayList targetList=newArrayList (); //定义初始点位置最开始初始点位置为0 intstartPoint=0; //定义浮动点位置最开始初始点位置2 intfloatPoint=2; //定义当前轨迹点位置最开始初始点位置为1 intnowPoint=1; intlen=sourceList.size(); //存放所有窗口内的点的信息集合 ArrayList listPoint=newArrayList (); listPoint.add(sourceList.get(nowPoint)); //浮动点位置决定循环 while(true){ //标志用来控制判断是否进行窗口内轨迹点更新 Booleanflag=false; //计算并判断窗口内所有点和投影点的距离是否大于阈值 for(ENPointpoint:listPoint){ doubledisOfTwo=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; } returntargetList; } /*计算投影点到轨迹点的距离 *入口是初始点A、浮动点B、当前轨迹点C *三角形面积公式 */ publicstaticdoublegetDistance(ENPointA,ENPointB,ENPointC){ doubledistance=0; doublea=Math.abs(geoDist(A,B)); doubleb=Math.abs(geoDist(B,C)); doublec=Math.abs(geoDist(A,C)); doublep=(a+b+c)/2.0; doubles=Math.sqrt(p*(p-a)*(p-b)*(p-c)); distance=s*2.0/a; returndistance; } /* *ArrayList拷贝函数 **/ /*提供的函数 *其中计算距离的函数经过改造得到下面的距离计算方法 *具体是怎么计算距离的我也没研究了 **/ publicstaticdoublegeoDist(ENPointpA,ENPointpB){ doubleradLat1=Rad(pA.pn); doubleradLat2=Rad(pB.pn); doubledelta_lon=Rad(pB.pe-pA.pe); doubletop_1=Math.cos(radLat2)*Math.sin(delta_lon); doubletop_2=Math.cos(radLat1)*Math.sin(radLat2)-Math.sin(radLat1)*Math.cos(radLat2)*Math.cos(delta_lon); doubletop=Math.sqrt(top_1*top_1+top_2*top_2); doublebottom=Math.sin(radLat1)*Math.sin(radLat2)+Math.cos(radLat1)*Math.cos(radLat2)*Math.cos(delta_lon); doubledelta_sigma=Math.atan2(top,bottom); doubledistance=delta_sigma*6378137.0; returndistance; } publicstaticdoubleRad(doubled){ returnd*Math.PI/180.0; } /* *将压缩后的位置点信息写入到文件中 **/ publicstaticvoidwriteTestPointToFile(FileoutGPSFile,ArrayList pGPSPointFilter)throwsException{ Iterator iFilter=pGPSPointFilter.iterator(); RandomAccessFilerFilter=newRandomAccessFile(outGPSFile,"rw"); while(iFilter.hasNext()){ ENPointp=iFilter.next(); StringsFilter=p.getResultString(); byte[]bFilter=sFilter.getBytes(); rFilter.write(bFilter); } rFilter.close(); } /** *函数功能:求平均距离误差 *返回平均距离 */ publicstaticdoublegetMeanDistError(ArrayList pGPSArray,ArrayList pGPSArrayRe){ doublesumDist=0.0; for(inti=1;i importjava.text.DecimalFormat; publicclassENPointimplementsComparable { publicintid; //点ID publicdoublepe; //经度 publicdoublepn; //维度 publicENPoint(){ } //空构造函数 publicStringtoString(){ returnthis.id+"#"+this.pn+","+this.pe; } publicStringgetResultString(){ DecimalFormatdf=newDecimalFormat("0.000000"); returnthis.id+"#"+df.format(this.pe)+","+df.format(this.pn)+"\n"; } @Override publicintcompareTo(ENPointother){ if(this.id other.id)return1;else return0; } }
总结
以上就是本文关于Java编程实现轨迹压缩算法开放窗口实例代码的全部内容,希望对大家有所帮助。如有不足之处,欢迎留言指出。