import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
public class TrajectorySimplification {
// 轨迹点类
static class Point {
double x, y;
Point(double x, double y) {
this.x = x;
this.y = y;
}
@Override
public String toString() {
return "Point{" +
"x=" + x +
", y=" + y +
'}';
}
}
// 计算点到线段的垂直距离
private static double perpendicularDistance(Point p, Point start, Point end) {
double dx = end.x - start.x;
double dy = end.y - start.y;
double mag = Math.hypot(dx, dy);
if (mag > 0.0) {
dx /= mag;
dy /= mag;
}
double pvx = p.x - start.x;
double pvy = p.y - start.y;
double pvdot = dx * pvx + dy * pvy;
double ax = pvx - pvdot * dx;
double ay = pvy - pvdot * dy;
return Math.hypot(ax, ay);
}
// 道格拉斯-普克算法
public static List<Point> douglasPeucker(List<Point> points, double epsilon) {
if (points == null || points.size() < 3) {
return points;
}
int startIndex = 0;
int endIndex = points.size() - 1;
List<Point> result = new ArrayList<>();
result.add(points.get(startIndex));
result.add(points.get(endIndex));
douglasPeuckerRecursive(points, startIndex, endIndex, epsilon, result);
// 按照原始顺序排序
Collections.sort(result, Comparator.comparingDouble(p -> p.x));
return result;
}
private static void douglasPeuckerRecursive(List<Point> points, int startIndex, int endIndex, double epsilon, List<Point> result) {
double maxDistance = 0.0;
int index = 0;
for (int i = startIndex + 1; i < endIndex; i++) {
double distance = perpendicularDistance(points.get(i), points.get(startIndex), points.get(endIndex));
if (distance > maxDistance) {
maxDistance = distance;
index = i;
}
}
if (maxDistance > epsilon) {
result.add(points.get(index));
douglasPeuckerRecursive(points, startIndex, index, epsilon, result);
douglasPeuckerRecursive(points, index, endIndex, epsilon, result);
}
}
public static void main(String[] args) {
List<Point> points = new ArrayList<>();
points.add(new Point(0, 0));
points.add(new Point(1, 0.1));
points.add(new Point(2, -0.1));
points.add(new Point(3, 5));
points.add(new Point(4, 6));
points.add(new Point(5, 7));
points.add(new Point(6, 8.1));
points.add(new Point(7, 9));
points.add(new Point(8, 9));
points.add(new Point(9, 9));
// 经纬度数据点数比较多的情况下,epsilon 设置0.006,根据自己的业务去动态调整
double epsilon = 1.0;
List<Point> simplifiedPoints = douglasPeucker(points, epsilon);
System.out.println("Original Points:");
for (Point point : points) {
System.out.println(point);
}
System.out.println("\nSimplified Points:");
for (Point point : simplifiedPoints) {
System.out.println(point);
}
}
}
代码解释
- Point类: 定义一个简单的点类,包含x和y坐标。
- perpendicularDistance方法: 计算一个点到一条线段的垂直距离。
- douglasPeucker方法: 实现道格拉斯-普克算法,接受一个点列表和一个阈值epsilon,返回简化后的点列表。
- douglasPeuckerRecursive方法: 递归实现轨迹简化的核心算法。
- main方法: 示例代码,展示如何使用上述方法进行复杂巡检轨迹的抽稀。
使用说明
- 输入: 轨迹点列表和阈值epsilon。
- 输出: 简化后的轨迹点列表。
你可以调整epsilon的值来控制简化的程度。较大的epsilon值会删除更多的点,而较小的epsilon值会保留更多的点。
示例输出
运行上述代码后,你将看到原始点列表和简化后的点列表。简化后的点列表将包含较少的点,但仍然保留了轨迹的大致形状。