目录
1. 抽稀
2. 原理
3. 具体思路
4. 代码示例
道格拉斯-普克算法是我们常用的一种轨迹点的抽稀算法,抽稀出来的点可以尽可能的维持原先轨迹点的大体轮廓,剔除一些非必要的点
2. 原理
假设在平面坐标系上有一条由N个坐标点组成的曲线,已设定一个阈值epsilon。
(1)首先,将起始点与结束点用直线连接, 再找出到该直线的距离最大,同时又大于阈值epsilon的点并记录下该点的位置(这里暂且称其为最大阈值点),如图所示:
(2)接着,以该点为分界点,将整条曲线分割成两段(这里暂且称之为左曲线和右曲线),将这两段曲线想象成独立的曲线然后重复操作(1),找出两边的最大阈值点,如图所示:
(3)最后,重复操作(2)(1)直至再也找不到最大阈值点为止,然后将所有最大阈值点按顺序连接起来便可以得到一条更简化的,更平滑的,与原曲线十分近似的曲线,如图所示:
3. 具体思路
对每一条曲线的首末点虚连一条直线,求所有点与直线的距离,并找出最大距离值dmax ,用dmax与限差D相比:若dmax < D ,这条曲线上的中间点所有舍去;若dmax ≥D ,保留dmax 相应的坐标点,并以该点为界,把曲线分为两部分,对这两部分反复使用该方法。控制限差值的大小可以控制抽稀的粒度。
4. 代码示例
public class GpsData {
private int index;
public GpsData(){
}
/**
* 纬度
*/
private double latitudeEx;
/**
* 经度
*/
private double longitudeEx;
public double getLatitudeEx() {
return latitudeEx;
}
public void setLatitudeEx(double latitudeEx) {
this.latitudeEx = latitudeEx;
}
public double getLongitudeEx() {
return longitudeEx;
}
public void setLongitudeEx(double longitudeEx) {
this.longitudeEx = longitudeEx;
}
public int getIndex() {
return index;
}
public void setIndex(int index) {
this.index = index;
}
}
public class Douglas extends JFrame {
/**
* 存储采样点数据链表
*/
public static List<GpsData > points = new ArrayList<GpsData >();
/**
* 控制数据经度压缩的极差
*/
private static final double D = 0.0001;
/**
* 对矢量曲线进行压缩
*
* @param from 曲线的起始点
* @param to 曲线的终止点
*/
public static void compress(GpsData from, GpsData to) {
/**
* 压缩算法的开关
*/
boolean switchvalue = false;
/**
* 由起始点和终止点构成直线方程一般式的系数
*/
double fromLat = Double.valueOf(from.getLatitudeEx());
double fromLng = Double.valueOf(from.getLongitudeEx());
double toLat = Double.valueOf(to.getLatitudeEx());
double toLng = Double.valueOf(to.getLongitudeEx());
double A = (fromLat - toLat)
/ Math.sqrt(Math.pow((fromLat - toLat), 2)+ Math.pow((fromLng - toLng), 2));
/**
* 由起始点和终止点构成直线方程一般式的系数
*/
double B = (toLng - fromLng)
/ Math.sqrt(Math.pow((fromLat - toLat), 2)
+ Math.pow((fromLng - toLng), 2));
/**
* 由起始点和终止点构成直线方程一般式的系数
*/
double C = (fromLng * toLat - toLng * fromLat)
/ Math.sqrt(Math.pow((fromLat - toLat), 2)
+ Math.pow((fromLng - toLng), 2));
double d = 0;
double dmax = 0;
int m = points.indexOf(from);
int n = points.indexOf(to);
if (n == m + 1){ return;}
GpsData middle = null;
List<Double> distance = new ArrayList<>();
for (int i = m + 1; i < n; i++) {
double blng = Double.valueOf(points.get(i).getLongitudeEx());
double blat = Double.valueOf(points.get(i).getLatitudeEx());
d = Math.abs(A * (blng) + B * (blat) + C) / Math.sqrt(Math.pow(A, 2) + Math.pow(B, 2));
distance.add(d);
}
dmax = distance.get(0);
for (int j = 1; j < distance.size(); j++) {
if (distance.get(j) > dmax){
dmax = distance.get(j);
}
}
if (dmax > D) {
switchvalue = true;
} else{
switchvalue = false;
}
if (!switchvalue) {
//删除Points(m,n)内的坐标
for (int i = m + 1; i < n; i++) {
points.get(i).setIndex(-1);
}
} else {
for (int i = m + 1; i < n; i++) {
double blng = Double.valueOf(points.get(i).getLongitudeEx());
double blat = Double.valueOf(points.get(i).getLatitudeEx());
if ((Math.abs(A * (blng) + B
* (blat) + C)
/ Math.sqrt(Math.pow(A, 2) + Math.pow(B, 2)) == dmax)){
middle = points.get(i);
}
}
compress(from, middle);
compress(middle, to);
}
}
public static List<GpsData > douglasData(List<GpsData> source) {
points = source;
System.out.println("压缩前:");
for (int i = 0; i < points.size(); i++) {
GpsData p = points.get(i);
System.out.print("[" + p.getLongitudeEx() + "," + p.getLatitudeEx() + "],");
}
if(!CollectionUtils.isEmpty(points)){
compress(points.get(0), points.get(points.size() - 1));
}
System.out.println("\n压缩后:");
List<GpsData > list = new ArrayList<>();
for (int i = 0; i < points.size(); i++) {
GpsData p = points.get(i);
if (p.getIndex()>-1) {
list.add(p);
System.out.println("[" + p.getLongitudeEx() + "," + p.getLatitudeEx() + "],");
}
}
return list;
}
public static void main(String[] args) {
List<GpsData> list = new ArrayList<>();
GpsData data=null;
String[] $points = new String []{"117.212448,39.133785", "117.212669,39.133667", "117.213165,39.133297", "117.213203,39.13327", "117.213554,39.133099", "117.213669,39.13295", "117.213921,39.132462", "117.214088,39.132126", "117.214142,39.131962", "117.214188,39.13176", "117.214233,39.131397", "117.21418,39.13055", "117.214279,39.130459", "117.214539,39.130375", "117.214874,39.130188", "117.216881,39.128716", "117.217598,39.127995", "117.217972,39.12759", "117.218338,39.127178", "117.218407,39.127071", "117.218567,39.126911", "117.219704,39.125702", "117.219795,39.12561", "117.220284,39.125114", "117.220619,39.124802", "117.221046,39.124348", "117.221138,39.124245", "117.221268,39.124092", "117.222321,39.122955", "117.222824,39.122406", "117.222916,39.122311", "117.223663,39.121544", "117.2239,39.121452", "117.224113,39.12159", "117.224251,39.121677", "117.225136,39.122208", "117.225281,39.122292", "117.225319,39.122311", "117.226273,39.122875", "117.226685,39.123127", "117.227371,39.12352", "117.227806,39.123779", "117.228477,39.124134", "117.228531,39.124161", "117.228531,39.124161", "117.228668,39.124187", "117.228897,39.124325", "117.229767,39.12479", "117.230927,39.12545", "117.231186,39.12561", "117.231659,39.125908", "117.231834,39.126026", "117.232018,39.126186", "117.232185,39.126362", "117.232353,39.126583", "117.232658,39.126972", "117.232658,39.126972", "117.233124,39.12748", "117.233253,39.127609", "117.233368,39.127689", "117.233513,39.127762", "117.233665,39.127823", "117.233734,39.127846", "117.233833,39.127865", "117.233994,39.127888", "117.234138,39.127892", "117.234329,39.127884", "117.234612,39.127838", "117.234955,39.127754", "117.235252,39.12767", "117.236282,39.12738", "117.237137,39.127129", "117.237671,39.126961", "117.237953,39.126949", "117.238213,39.126865", "117.238472,39.126793", "117.2397,39.126434", "117.242233,39.125698", "117.243538,39.12532", "117.243645,39.125298",};
System.out.println("抽稀前---------------"+$points.length);
for(int i=0;i<$points.length;i++){
data= new GpsData();
data.setLongitudeEx(Double.valueOf($points[i].split(",")[0]));
data.setLatitudeEx(Double.valueOf($points[i].split(",")[1]));
list.add(data);
}
List<GpsData> gpsDataList= douglasData(list);
System.out.println("---------------"+gpsDataList.size());
System.out.println(gpsDataList.toString());
}
}