您好,登錄后才能下訂單哦!
這篇文章主要介紹了Java編程如何實現軌跡壓縮算法開放窗口,具有一定借鑒價值,感興趣的朋友可以參考下,希望大家閱讀完這篇文章之后大有收獲,下面讓小編帶著大家一起了解一下。
軌跡壓縮算法
場景描述
給定一個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編程如何實現軌跡壓縮算法開放窗口”這篇文章對大家有幫助,同時也希望大家多多支持億速云,關注億速云行業資訊頻道,更多相關知識等著你來學習!
免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。