Java編程實現(xiàn)軌跡壓縮算法開放窗口實例代碼
軌跡壓縮算法
場景描述
給定一個GPS數(shù)據(jù)記錄文件,每條記錄包含經(jīng)度和維度兩個坐標字段,根據(jù)距離閾值壓縮記錄,將過濾后的所有記錄的經(jīng)緯度坐標構(gòu)成一條軌跡
算法描述
這種算法的用處還是相當廣泛的。
軌跡壓縮算法分為兩大類,分別是無損壓縮和有損壓縮,無損壓縮算法主要包括哈夫曼編碼,有損壓縮算法又分為批處理方式和在線數(shù)據(jù)壓縮方式,其中批處理方式又包括DP(Douglas-Peucker)算法、TD-TR(Top-Down Time-Ratio)算法和Bellman算法,在線數(shù)據(jù)壓縮方式又包括滑動窗口、開放窗口、基于安全區(qū)域的方法等。
大家也可參考這篇文章:《Java編程實現(xiàn)軌跡壓縮之Douglas-Peucker算法詳細代碼》
代碼實現(xiàn)
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>();
//源數(shù)據(jù)文件的地址 建立文件對象
//這里是需要更改的地方 改你源文件的存放地址 記住如果地址中含"\",記得再加一個"\",原因"\"是轉(zhuǎn)義符號
//這里可以寫成C:/Users/Administrator/Desktop/11.6/2007-10-14-GPS.log
File sourceFile = new File("./2007-10-14-GPS.log");
//調(diào)用文件讀取函數(shù) 讀取文件數(shù)據(jù)
ENPList = getENPointFromFile(sourceFile);
//這里是測試 有沒有讀到里面 看看列表里的數(shù)據(jù)個數(shù) 交作業(yè)的時候記得注釋掉
System.out.println(ENPList.size());
/*
* 數(shù)據(jù)處理
* 方法:開放窗口軌跡壓縮法
* */
//存放目標點的集合
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);
}
/*
* 從提供的文件信息里提取位置點
* 并將每個點的坐標數(shù)值調(diào)用轉(zhuǎn)換函數(shù)存到列表里
* 函數(shù)返回一個 存放所有位置點 的集合
*/
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;
}
/**
* 函數(shù)功能:將原始經(jīng)緯度坐標數(shù)據(jù)轉(zhuǎn)換成度
* 獲取的經(jīng)緯度數(shù)據(jù)為一個字符串
*/
public static double dfTodu(String str){
int indexD = str.indexOf('.');
//獲取 . 字符所在的位置
String strM = str.substring(0,indexD-2);
//整數(shù)部分
String strN = str.substring(indexD-2);
//小數(shù)部分
double d = double.parsedouble(strM)+double.parsedouble(strN)/60;
return d;
}
/*
* 開放窗口方法實現(xiàn)
* 返回一個壓縮后的位置列表
* 列表每條數(shù)據(jù)存放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();
//存放所有窗口內(nèi)的點的信息集合
ArrayList<enpoint> listPoint = new ArrayList<enpoint>();
listPoint.add(sourceList.get(nowPoint));
//浮動點位置決定循環(huán)
while(true){
//標志 用來控制判斷是否進行窗口內(nèi)軌跡點更新
Boolean flag = false;
//計算并判斷窗口內(nèi)所有點和投影點的距離是否大于閾值
for (ENPoint point:listPoint){
double disOfTwo = getDistance(sourceList.get(startPoint),sourceList.get(floatPoint),point);
if(disOfTwo >= 30){
flag = true;
break;
}
}
if(flag){
//窗口內(nèi)點距離都大于閾值
//初始點加到目標列表
targetList.add(sourceList.get(startPoint));
//初始點變化
startPoint = floatPoint - 1;
//浮動點變化
floatPoint += 1;
if(floatPoint >= len){
targetList.add(sourceList.get(floatPoint-1));
break;
}
//窗口內(nèi)點變化
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 拷貝函數(shù)
* */
/*提供的函數(shù)
* 其中計算距離的函數(shù) 經(jīng)過改造得到下面的距離計算方法
* 具體是怎么計算距離的 我也沒研究了
* */
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();
}
/**
* 函數(shù)功能:求平均距離誤差
* 返回平均距離
*/
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;
//經(jīng)度
public double pn;
//維度
public ENPoint(){
}
//空構(gòu)造函數(shù)
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;
}
}
總結(jié)
以上就是本文關(guān)于Java編程實現(xiàn)軌跡壓縮算法開放窗口實例代碼的全部內(nèi)容,希望對大家有所幫助。如有不足之處,歡迎留言指出。
上一篇:Java編程實現(xiàn)springMVC簡單登錄實例
欄 目:Java編程
本文標題:Java編程實現(xiàn)軌跡壓縮算法開放窗口實例代碼
本文地址:http://www.jygsgssxh.com/a1/Javabiancheng/8410.html
您可能感興趣的文章
- 01-10Java咖啡館(1)——嘆咖啡
- 01-10Java Socket編程(三) 服務(wù)器Sockets
- 01-10Java進階:Struts多模塊的技巧
- 01-10Java Socket編程(一) Socket傳輸模式
- 01-10Java Socket編程(二) Java面向連接的類
- 01-10Java運行時多態(tài)性的實現(xiàn)
- 01-10Java經(jīng)驗點滴:處理沒有被捕獲的異常
- 01-10Java Socket編程(四) 重復和并發(fā)服務(wù)器
- 01-10Java中的浮點數(shù)分析
- 01-10面向?qū)ο缶幊?Java中的抽象數(shù)據(jù)類型


閱讀排行
本欄相關(guān)
- 01-10Java咖啡館(1)——嘆咖啡
- 01-10JVM的垃圾回收機制詳解和調(diào)優(yōu)
- 01-10Java Socket編程(三) 服務(wù)器Sockets
- 01-10Java進階:Struts多模塊的技巧
- 01-10J2SE 1.5版本的新特性一覽
- 01-10Java Socket編程(一) Socket傳輸模式
- 01-10Java運行時多態(tài)性的實現(xiàn)
- 01-10Java Socket編程(二) Java面向連接的類
- 01-10Java Socket編程(四) 重復和并發(fā)服務(wù)
- 01-10Java經(jīng)驗點滴:處理沒有被捕獲的異常
隨機閱讀
- 08-05dedecms(織夢)副欄目數(shù)量限制代碼修改
- 01-10SublimeText編譯C開發(fā)環(huán)境設(shè)置
- 08-05DEDE織夢data目錄下的sessions文件夾有什
- 01-11Mac OSX 打開原生自帶讀寫NTFS功能(圖文
- 01-10C#中split用法實例總結(jié)
- 01-10使用C語言求解撲克牌的順子及n個骰子
- 01-10delphi制作wav文件的方法
- 08-05織夢dedecms什么時候用欄目交叉功能?
- 04-02jquery與jsp,用jquery
- 01-11ajax實現(xiàn)頁面的局部加載


