Java编程实现轨迹压缩算法开放窗口实例代码
作者:wzw_ice 发布时间:2021-12-03 09:54:07
标签: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;
}
}
来源:https://www.2cto.com/kf/201711/700920.html


猜你喜欢
- 一直对invoke和begininvoke的使用和概念比较混乱,这两天看了些资料,对这两个的用法和原理有了些新的认识和理解。 首先
- android通过google API获取天气信息public class WeatherActivity extends Activity
- 一、文件上传概述实现Web开发中的文件上传功能,需要两步操作:1、在Web页面中添加上传输入项 <form
- 一、实现效果本篇文章实现了简单的图片轮播,初始化3张资源图片,初始化3秒更换一次图片背景,轮换播放。二、知识点Thread线程start()
- 研究背景 我們在搞新的配置中心Nacos的時候,为了获取新的配置中心的配置文件中配置的 dat
- 这个类(我的是Activity中)继承SensorEventListener接口先获取传感器对象,再获取传感器对象的类型//获取传感器管理对
- 本文实例讲述了java GUI编程之布局控制器(Layout)。分享给大家供大家参考,具体如下:布局控制器,是用来系统自动分配各个compo
- 一、业务说明对应APP业务中的成员有两类,一是服务人员,二是被服务人员, 主要实现功能, 对APP中的服务人员位置进行时时定位, 然后通过被
- 我们知道,spring boot自动配置功能可以根据不同情况来决定spring配置应该用哪个,不应该用哪个,举个例子:Spring的Jdbc
- 在上一篇博文《C/C++ Qt TreeWidget 单层树形组件应用》中给大家演示了如何使用TreeWidget组件创建单层树形结构,并给
- #简易版1、客户发送请求经过 DisPatcherServlet 核心过滤器2、DisPatcherServlet 核心控制器在去找一个或多
- java掩码 private static String nameMask(String name) throws Exception {
- using System;using System.Collections.Generic;using System.Drawing;usi
- 概述常用的弹窗有菜单,或者Dialog,但更加人性化和可自定义的还是PopupWindow如果只是展示列表数据或者弹窗列表选择,直接使用Li
- Author:jeffreyDate:2019-04-08一、开发环境:1、mysql - 5.72、navicat(mysql客户端管理工
- 1. String对象不可改变的特性下图显示了如下代码运行的过程:String s = "abcd"; s = s.co
- 不同的浏览器会把cookie文件保存在不同的地方以下是C# WebBrowser控件cookies的存放路径C:\Users\{你的帐号名}
- 最近做了一个文件上传、下载、与在线打开文件的功能,刚开始对文件上传的界面中含有其它表单(例如输入框、密码等)在上传的过程中遇到了许多问题,下
- 1、什么是OpenCVSharp 为了解决在Csharp下编写OpenCV程序的问题,我做过比较深入的研究,并且实现了高效可用的
- 本文主要包括以下几个方面:编码基本知识,java,系统软件,url,工具软件等。 在下面的描述中,将以&