package bianjie;
|
import java.util.ArrayList;
|
import java.util.List;
|
|
public class BoundaryAlgorithm {
|
|
public static class Coordinate {
|
public double x; // 东方向坐标 (米)
|
public double y; // 北方向坐标 (米)
|
public double lat; // 纬度
|
public double lon; // 经度
|
|
public Coordinate(double x, double y, double lat, double lon) {
|
this.x = x;
|
this.y = y;
|
this.lat = lat;
|
this.lon = lon;
|
}
|
|
@Override
|
public String toString() {
|
return String.format("(%.2f, %.2f)", x, y);
|
}
|
|
@Override
|
public boolean equals(Object obj) {
|
if (this == obj) return true;
|
if (obj == null || getClass() != obj.getClass()) return false;
|
Coordinate that = (Coordinate) obj;
|
return Math.abs(this.x - that.x) < 0.001 &&
|
Math.abs(this.y - that.y) < 0.001;
|
}
|
|
public Coordinate copy() {
|
return new Coordinate(x, y, lat, lon);
|
}
|
}
|
|
// 边界质量评估类
|
public static class BoundaryQuality {
|
public boolean isClosed;
|
public double closureError;
|
public int selfIntersectionCount;
|
public double smoothness;
|
public double area;
|
public int pointCount;
|
|
@Override
|
public String toString() {
|
return String.format(
|
"边界质量评估:\n" +
|
"是否闭合: %s\n" +
|
"闭合误差: %.3f米\n" +
|
"自相交点数: %d\n" +
|
"平均角度变化: %.2f度\n" +
|
"面积: %.2f平方米\n" +
|
"边界点数: %d",
|
isClosed ? "是" : "否", closureError, selfIntersectionCount,
|
smoothness, area, pointCount
|
);
|
}
|
}
|
|
// 边界参数类
|
public static class BoundaryParameters {
|
public final double interval; // 米
|
public final double angleThreshold; // 度
|
public final double simplificationTolerance; // 米
|
|
public BoundaryParameters(double interval, double angleThreshold, double simplificationTolerance) {
|
this.interval = interval;
|
this.angleThreshold = angleThreshold;
|
this.simplificationTolerance = simplificationTolerance;
|
}
|
|
// 预设参数
|
public static final BoundaryParameters LARGE_FLAT =
|
new BoundaryParameters(2.0, 10.0, 0.5);
|
public static final BoundaryParameters COMPLEX_SMALL =
|
new BoundaryParameters(0.5, 5.0, 0.2);
|
public static final BoundaryParameters DEFAULT =
|
new BoundaryParameters(1.0, 8.0, 0.3);
|
}
|
|
// 场景分析类
|
public static class SceneAnalysis {
|
public double totalDistance; // 总行走距离
|
public double area; // 估算面积
|
public double complexity; // 边界复杂度 (0-1)
|
public double elevationRange; // 高程变化范围
|
public double avgSpeed; // 平均行走速度
|
public String suggestedPreset; // 建议的预设场景
|
|
@Override
|
public String toString() {
|
return String.format(
|
"场景分析结果:\n" +
|
" 总距离: %.1f米\n" +
|
" 估算面积: %.1f平方米\n" +
|
" 边界复杂度: %.2f\n" +
|
" 高程变化: %.1f米\n" +
|
" 平均速度: %.1f米/秒\n" +
|
" 建议场景: %s",
|
totalDistance, area, complexity, elevationRange, avgSpeed, suggestedPreset
|
);
|
}
|
}
|
|
// 处理边界数据的主要方法(增强版)
|
public List<Coordinate> processBoundaryData(String gnggaData, double baseLat, double baseLon,
|
double interval, double angleThreshold) {
|
return processBoundaryDataAdvanced(gnggaData, baseLat, baseLon,
|
new BoundaryParameters(interval, angleThreshold, interval/2));
|
}
|
|
// 高级处理边界数据方法
|
public List<Coordinate> processBoundaryDataAdvanced(String gnggaData, double baseLat, double baseLon,
|
BoundaryParameters params) {
|
System.out.println("开始处理边界数据...");
|
System.out.println("基准站坐标: " + baseLat + ", " + baseLon);
|
System.out.println("参数: 间隔=" + params.interval + "米, 角度阈值=" + params.angleThreshold + "度");
|
|
// 1. 解析GNGGA数据
|
List<Coordinate> rawPoints = parseGNGGA(gnggaData, baseLat, baseLon);
|
System.out.println("解析到原始点: " + rawPoints.size() + " 个");
|
|
if (rawPoints.size() < 3) {
|
System.out.println("数据点不足,无法形成边界");
|
return new ArrayList<>();
|
}
|
|
// 2. 过滤和平滑数据
|
List<Coordinate> filteredPoints = filterAndSmoothPoints(rawPoints);
|
System.out.println("过滤后点: " + filteredPoints.size() + " 个");
|
|
// 3. 高级边界点优化
|
List<Coordinate> optimizedPoints = optimizeBoundaryPointsAdvanced(filteredPoints, params);
|
System.out.println("优化后边界点: " + optimizedPoints.size() + " 个");
|
|
// 4. 边界质量评估
|
BoundaryQuality quality = evaluateBoundaryQuality(optimizedPoints);
|
System.out.println(quality.toString());
|
|
return optimizedPoints;
|
}
|
|
// 分析GNGGA数据并自动选择场景
|
public SceneAnalysis analyzeGNGGAData(String gnggaData, double baseLat, double baseLon) {
|
SceneAnalysis analysis = new SceneAnalysis();
|
|
// 1. 解析GNGGA数据获取原始点
|
List<Coordinate> rawPoints = parseGNGGA(gnggaData, baseLat, baseLon);
|
if (rawPoints.size() < 3) {
|
analysis.suggestedPreset = "复杂小区域";
|
return analysis;
|
}
|
|
// 2. 计算基本统计信息
|
calculateBasicStatistics(rawPoints, analysis);
|
|
// 3. 计算边界复杂度
|
calculateBoundaryComplexity(rawPoints, analysis);
|
|
// 4. 分析高程变化
|
analyzeElevationData(gnggaData, analysis);
|
|
// 5. 自动选择预设场景
|
selectPresetAutomatically(analysis);
|
|
System.out.println(analysis.toString());
|
return analysis;
|
}
|
|
// 计算基本统计信息
|
private void calculateBasicStatistics(List<Coordinate> points, SceneAnalysis analysis) {
|
// 计算总距离
|
analysis.totalDistance = 0;
|
for (int i = 1; i < points.size(); i++) {
|
analysis.totalDistance += calculateDistance(points.get(i-1), points.get(i));
|
}
|
|
// 计算面积
|
analysis.area = calculatePolygonArea(points);
|
|
// 计算平均速度 (假设时间间隔为1秒)
|
if (points.size() > 1) {
|
analysis.avgSpeed = analysis.totalDistance / (points.size() - 1);
|
}
|
}
|
|
// 计算边界复杂度
|
private void calculateBoundaryComplexity(List<Coordinate> points, SceneAnalysis analysis) {
|
if (points.size() < 3) {
|
analysis.complexity = 0;
|
return;
|
}
|
|
double totalAngleChange = 0;
|
int angleCount = 0;
|
|
for (int i = 1; i < points.size() - 1; i++) {
|
double angleChange = Math.abs(calculateAngleChange(
|
points.get(i-1), points.get(i), points.get(i+1)
|
));
|
totalAngleChange += angleChange;
|
angleCount++;
|
}
|
|
// 复杂度基于角度变化和边界长度
|
double avgAngleChange = angleCount > 0 ? totalAngleChange / angleCount : 0;
|
|
// 标准化复杂度 (0-1范围)
|
analysis.complexity = Math.min(1.0, avgAngleChange / 45.0); // 45度作为高复杂度阈值
|
}
|
|
// 分析高程数据
|
private void analyzeElevationData(String gnggaData, SceneAnalysis analysis) {
|
double minElevation = Double.MAX_VALUE;
|
double maxElevation = Double.MIN_VALUE;
|
int elevationCount = 0;
|
|
String[] records = gnggaData.split("\\$GNGGA");
|
for (String record : records) {
|
try {
|
String trimmedRecord = record.trim();
|
if (trimmedRecord.isEmpty()) continue;
|
|
if (!trimmedRecord.startsWith(",")) {
|
trimmedRecord = "," + trimmedRecord;
|
}
|
|
String[] fields = trimmedRecord.split(",");
|
if (fields.length >= 10) {
|
// 第10个字段是海拔高度
|
String elevationStr = fields[9];
|
if (!elevationStr.isEmpty()) {
|
double elevation = Double.parseDouble(elevationStr);
|
minElevation = Math.min(minElevation, elevation);
|
maxElevation = Math.max(maxElevation, elevation);
|
elevationCount++;
|
}
|
}
|
} catch (Exception e) {
|
// 忽略解析错误
|
}
|
}
|
|
if (elevationCount > 0) {
|
analysis.elevationRange = maxElevation - minElevation;
|
} else {
|
analysis.elevationRange = 0;
|
}
|
}
|
|
// 自动选择预设场景
|
private void selectPresetAutomatically(SceneAnalysis analysis) {
|
// 决策逻辑基于多个因素
|
double areaWeight = 0.4;
|
double complexityWeight = 0.3;
|
double elevationWeight = 0.2;
|
double speedWeight = 0.1;
|
|
// 计算综合得分
|
double score = 0;
|
|
// 面积因素:面积越大,越适合大间隔
|
double areaScore = Math.min(1.0, analysis.area / 1000.0); // 1000平方米为基准
|
score += areaScore * areaWeight;
|
|
// 复杂度因素:复杂度越高,越需要小间隔
|
double complexityScore = analysis.complexity;
|
score += complexityScore * complexityWeight;
|
|
// 高程因素:高程变化越大,越需要精细处理
|
double elevationScore = Math.min(1.0, analysis.elevationRange / 10.0); // 10米变化为基准
|
score += elevationScore * elevationWeight;
|
|
// 速度因素:速度变化大可能表示复杂地形
|
double speedScore = Math.min(1.0, analysis.avgSpeed / 2.0); // 2米/秒为基准
|
score += speedScore * speedWeight;
|
|
// 根据得分选择预设
|
if (score < 0.3) {
|
analysis.suggestedPreset = "平坦大区域";
|
} else if (score < 0.6) {
|
analysis.suggestedPreset = "常规区域";
|
} else {
|
analysis.suggestedPreset = "复杂小区域";
|
}
|
|
System.out.println("自动场景选择得分: " + String.format("%.2f", score) + " -> " + analysis.suggestedPreset);
|
}
|
|
// 根据场景名称获取参数
|
public BoundaryParameters getParametersForPreset(String presetName) {
|
switch (presetName) {
|
case "平坦大区域":
|
return BoundaryParameters.LARGE_FLAT;
|
case "复杂小区域":
|
return BoundaryParameters.COMPLEX_SMALL;
|
case "常规区域":
|
default:
|
return BoundaryParameters.DEFAULT;
|
}
|
}
|
|
// 解析GNGGA格式数据
|
private List<Coordinate> parseGNGGA(String gnggaData, double baseLat, double baseLon) {
|
List<Coordinate> points = new ArrayList<>();
|
if (gnggaData == null || gnggaData.trim().isEmpty()) {
|
return points;
|
}
|
|
String[] records = gnggaData.split("\\$GNGGA");
|
System.out.println("找到GNGGA记录: " + (records.length - 1) + " 条");
|
|
for (String record : records) {
|
try {
|
String trimmedRecord = record.trim();
|
if (trimmedRecord.isEmpty()) continue;
|
|
if (!trimmedRecord.startsWith(",")) {
|
trimmedRecord = "," + trimmedRecord;
|
}
|
|
String[] fields = trimmedRecord.split(",");
|
if (fields.length < 7) {
|
System.out.println("记录字段不足: " + trimmedRecord);
|
continue;
|
}
|
|
// 检查定位状态
|
int fixStatus;
|
try {
|
fixStatus = Integer.parseInt(fields[6]);
|
} catch (NumberFormatException e) {
|
System.out.println("定位状态格式错误: " + fields[6]);
|
continue;
|
}
|
|
if (fixStatus != 4) {
|
System.out.println("跳过非高精度定位点,状态: " + fixStatus);
|
continue;
|
}
|
|
// 解析纬度和经度
|
String latStr = fields[2];
|
double latitude = parseCoordinate(latStr, fields[3]);
|
String lonStr = fields[4];
|
double longitude = parseCoordinate(lonStr, fields[5]);
|
// 转换为相对于基准站的坐标
|
Coordinate coord = convertToLocalCoordinates(latitude, longitude, baseLat, baseLon);
|
points.add(coord);
|
|
} catch (Exception e) {
|
System.err.println("解析GNGGA数据失败: " + record + ", 错误: " + e.getMessage());
|
}
|
}
|
|
return points;
|
}
|
|
// 解析坐标字符串 (DDMM.MMMMM 格式)
|
private double parseCoordinate(String coordStr, String direction) {
|
try {
|
if (coordStr == null || coordStr.isEmpty()) {
|
return 0;
|
}
|
|
int dotIndex = coordStr.indexOf('.');
|
if (dotIndex < 2) {
|
return 0;
|
}
|
|
int degrees = Integer.parseInt(coordStr.substring(0, dotIndex - 2));
|
double minutes = Double.parseDouble(coordStr.substring(dotIndex - 2));
|
|
double decimal = degrees + minutes / 60.0;
|
|
if ("S".equals(direction) || "W".equals(direction)) {
|
decimal = -decimal;
|
}
|
|
return decimal;
|
} catch (Exception e) {
|
System.err.println("坐标解析错误: " + coordStr);
|
return 0;
|
}
|
}
|
|
// 转换为局部坐标系
|
private Coordinate convertToLocalCoordinates(double lat, double lon, double baseLat, double baseLon) {
|
double earthRadius = 6371000;
|
|
double deltaLat = lat - baseLat;
|
double northDistance = deltaLat * Math.PI / 180.0 * earthRadius;
|
|
double deltaLon = lon - baseLon;
|
double eastDistance = deltaLon * Math.PI / 180.0 * earthRadius * Math.cos(baseLat * Math.PI / 180.0);
|
Coordinate coord = new Coordinate(eastDistance, northDistance, lat, lon);
|
|
return coord;
|
}
|
|
// 过滤和平滑数据点
|
private List<Coordinate> filterAndSmoothPoints(List<Coordinate> points) {
|
if (points.size() < 3) return points;
|
|
List<Coordinate> filtered = new ArrayList<>();
|
|
// 1. 速度过滤 - 移除移动过快的点(可能是噪声)
|
filtered.add(points.get(0)); // 总是保留第一个点
|
|
for (int i = 1; i < points.size(); i++) {
|
double speed = calculateDistance(points.get(i-1), points.get(i));
|
if (speed < 5.0) { // 最大合理速度为5米/秒
|
filtered.add(points.get(i));
|
} else {
|
System.out.println("移除高速点: 速度=" + speed + "米/秒");
|
}
|
}
|
|
// 2. 简单平滑滤波
|
List<Coordinate> smoothed = movingAverageFilter(filtered, 3);
|
|
return smoothed;
|
}
|
|
// 移动平均滤波
|
private List<Coordinate> movingAverageFilter(List<Coordinate> points, int windowSize) {
|
if (points.size() <= windowSize) return points;
|
|
List<Coordinate> smoothed = new ArrayList<>();
|
|
for (int i = 0; i < points.size(); i++) {
|
double sumX = 0, sumY = 0;
|
int count = 0;
|
|
for (int j = Math.max(0, i - windowSize/2);
|
j <= Math.min(points.size() - 1, i + windowSize/2); j++) {
|
sumX += points.get(j).x;
|
sumY += points.get(j).y;
|
count++;
|
}
|
|
Coordinate smoothedPoint = new Coordinate(
|
sumX / count, sumY / count,
|
points.get(i).lat, points.get(i).lon
|
);
|
smoothed.add(smoothedPoint);
|
}
|
|
return smoothed;
|
}
|
|
// 高级边界点优化算法
|
List<Coordinate> optimizeBoundaryPointsAdvanced(List<Coordinate> points,
|
BoundaryParameters params) {
|
if (points.size() < 3) return points;
|
|
List<Coordinate> optimized = new ArrayList<>();
|
|
// 1. 首先进行道格拉斯-普克算法简化
|
List<Coordinate> simplified = douglasPeuckerSimplification(points, params.simplificationTolerance);
|
System.out.println("道格拉斯-普克简化后: " + simplified.size() + " 个点");
|
|
// 2. 基于距离和角度的进一步优化
|
optimized.add(simplified.get(0));
|
Coordinate lastAdded = simplified.get(0);
|
|
for (int i = 1; i < simplified.size(); i++) {
|
Coordinate current = simplified.get(i);
|
Coordinate next = (i < simplified.size() - 1) ? simplified.get(i + 1) : simplified.get(0);
|
|
double distance = calculateDistance(lastAdded, current);
|
double angleChange = calculateAngleChange(lastAdded, current, next);
|
|
// 动态调整阈值
|
double dynamicInterval = adjustIntervalByCurvature(params.interval, angleChange);
|
|
if (distance >= dynamicInterval || Math.abs(angleChange) > params.angleThreshold) {
|
optimized.add(current);
|
lastAdded = current;
|
}
|
}
|
|
// 确保闭合
|
if (!optimized.get(0).equals(optimized.get(optimized.size() - 1))) {
|
Coordinate first = optimized.get(0);
|
Coordinate last = optimized.get(optimized.size() - 1);
|
double closingDistance = calculateDistance(first, last);
|
|
if (closingDistance > params.interval) {
|
// 如果首尾距离较远,添加中间点
|
List<Coordinate> interpolated = interpolateBoundary(
|
List.of(last, first), params.interval
|
);
|
optimized.addAll(interpolated.subList(1, interpolated.size() - 1));
|
}
|
optimized.add(first);
|
}
|
|
return optimized;
|
}
|
|
// 道格拉斯-普克算法
|
private List<Coordinate> douglasPeuckerSimplification(List<Coordinate> points, double epsilon) {
|
if (points.size() < 3) return points;
|
|
// 找到最大距离点
|
double maxDistance = 0;
|
int index = 0;
|
Coordinate start = points.get(0);
|
Coordinate end = points.get(points.size() - 1);
|
|
for (int i = 1; i < points.size() - 1; i++) {
|
double distance = perpendicularDistance(points.get(i), start, end);
|
if (distance > maxDistance) {
|
maxDistance = distance;
|
index = i;
|
}
|
}
|
|
List<Coordinate> result = new ArrayList<>();
|
if (maxDistance > epsilon) {
|
// 递归简化
|
List<Coordinate> firstPart = douglasPeuckerSimplification(
|
points.subList(0, index + 1), epsilon);
|
List<Coordinate> secondPart = douglasPeuckerSimplification(
|
points.subList(index, points.size()), epsilon);
|
|
result.addAll(firstPart.subList(0, firstPart.size() - 1));
|
result.addAll(secondPart);
|
} else {
|
result.add(start);
|
result.add(end);
|
}
|
|
return result;
|
}
|
|
// 计算垂直距离
|
private double perpendicularDistance(Coordinate point, Coordinate lineStart, Coordinate lineEnd) {
|
double area = Math.abs(
|
(lineEnd.y - lineStart.y) * point.x -
|
(lineEnd.x - lineStart.x) * point.y +
|
lineEnd.x * lineStart.y - lineEnd.y * lineStart.x
|
);
|
double lineLength = calculateDistance(lineStart, lineEnd);
|
return lineLength > 0 ? area / lineLength : 0;
|
}
|
|
// 根据曲率动态调整间隔
|
private double adjustIntervalByCurvature(double baseInterval, double angleChange) {
|
double curvatureFactor = Math.max(0.3, Math.min(2.0, 1.0 - Math.abs(angleChange) / 90.0));
|
return baseInterval * curvatureFactor;
|
}
|
|
// 边界插值
|
public List<Coordinate> interpolateBoundary(List<Coordinate> boundary, double maxGap) {
|
List<Coordinate> interpolated = new ArrayList<>();
|
|
for (int i = 0; i < boundary.size(); i++) {
|
interpolated.add(boundary.get(i));
|
|
Coordinate current = boundary.get(i);
|
Coordinate next = boundary.get((i + 1) % boundary.size());
|
double distance = calculateDistance(current, next);
|
|
if (distance > maxGap) {
|
int segments = (int) Math.ceil(distance / maxGap);
|
for (int j = 1; j < segments; j++) {
|
double ratio = (double) j / segments;
|
Coordinate interpolatedPoint = interpolate(current, next, ratio);
|
interpolated.add(interpolatedPoint);
|
}
|
}
|
}
|
|
return interpolated;
|
}
|
|
// 线性插值
|
private Coordinate interpolate(Coordinate p1, Coordinate p2, double ratio) {
|
double x = p1.x + (p2.x - p1.x) * ratio;
|
double y = p1.y + (p2.y - p1.y) * ratio;
|
double lat = p1.lat + (p2.lat - p1.lat) * ratio;
|
double lon = p1.lon + (p2.lon - p1.lon) * ratio;
|
return new Coordinate(x, y, lat, lon);
|
}
|
|
// 边界质量评估
|
public BoundaryQuality evaluateBoundaryQuality(List<Coordinate> boundary) {
|
BoundaryQuality quality = new BoundaryQuality();
|
|
if (boundary.size() < 3) {
|
return quality;
|
}
|
|
// 检查闭合
|
Coordinate first = boundary.get(0);
|
Coordinate last = boundary.get(boundary.size() - 1);
|
quality.isClosed = calculateDistance(first, last) < 1.0;
|
quality.closureError = calculateDistance(first, last);
|
|
// 检查自相交
|
quality.selfIntersectionCount = countSelfIntersections(boundary);
|
|
// 计算平滑度
|
quality.smoothness = calculateBoundarySmoothness(boundary);
|
|
// 计算面积
|
quality.area = calculatePolygonArea(boundary);
|
quality.pointCount = boundary.size();
|
|
return quality;
|
}
|
|
// 计算边界平滑度
|
private double calculateBoundarySmoothness(List<Coordinate> boundary) {
|
double totalAngleChange = 0;
|
int count = 0;
|
|
for (int i = 1; i < boundary.size() - 1; i++) {
|
double angleChange = calculateAngleChange(
|
boundary.get(i-1), boundary.get(i), boundary.get(i+1)
|
);
|
totalAngleChange += Math.abs(angleChange);
|
count++;
|
}
|
|
return count > 0 ? totalAngleChange / count : 0;
|
}
|
|
// 计算自相交数量
|
private int countSelfIntersections(List<Coordinate> boundary) {
|
int intersections = 0;
|
int n = boundary.size();
|
|
for (int i = 0; i < n; i++) {
|
Coordinate a1 = boundary.get(i);
|
Coordinate a2 = boundary.get((i + 1) % n);
|
|
for (int j = i + 2; j < n; j++) {
|
Coordinate b1 = boundary.get(j);
|
Coordinate b2 = boundary.get((j + 1) % n);
|
|
if (doLinesIntersect(a1, a2, b1, b2)) {
|
intersections++;
|
}
|
}
|
}
|
|
return intersections;
|
}
|
|
// 检查两线段是否相交
|
private boolean doLinesIntersect(Coordinate a1, Coordinate a2, Coordinate b1, Coordinate b2) {
|
double denominator = ((b2.y - b1.y) * (a2.x - a1.x) - (b2.x - b1.x) * (a2.y - a1.y));
|
|
if (denominator == 0) return false; // 平行
|
|
double ua = ((b2.x - b1.x) * (a1.y - b1.y) - (b2.y - b1.y) * (a1.x - b1.x)) / denominator;
|
double ub = ((a2.x - a1.x) * (a1.y - b1.y) - (a2.y - a1.y) * (a1.x - b1.x)) / denominator;
|
|
return ua >= 0 && ua <= 1 && ub >= 0 && ub <= 1;
|
}
|
|
// 计算两点间距离
|
private double calculateDistance(Coordinate p1, Coordinate p2) {
|
double dx = p2.x - p1.x;
|
double dy = p2.y - p1.y;
|
return Math.sqrt(dx * dx + dy * dy);
|
}
|
|
// 计算角度变化
|
private double calculateAngleChange(Coordinate prev, Coordinate current, Coordinate next) {
|
double angle1 = Math.atan2(current.y - prev.y, current.x - prev.x);
|
double angle2 = Math.atan2(next.y - current.y, next.x - current.x);
|
|
double angleChange = Math.toDegrees(angle2 - angle1);
|
|
// 规范化角度到 [-180, 180]
|
while (angleChange > 180) angleChange -= 360;
|
while (angleChange < -180) angleChange += 360;
|
|
return angleChange;
|
}
|
|
// 计算多边形面积
|
public double calculatePolygonArea(List<Coordinate> points) {
|
if (points.size() < 3) return 0.0;
|
|
double area = 0.0;
|
int n = points.size();
|
|
for (int i = 0; i < n; i++) {
|
Coordinate current = points.get(i);
|
Coordinate next = points.get((i + 1) % n);
|
area += (current.x * next.y - next.x * current.y);
|
}
|
|
return Math.abs(area) / 2.0;
|
}
|
|
// 边界编辑功能
|
public List<Coordinate> editBoundary(List<Coordinate> boundary, int pointIndex, Coordinate newPosition) {
|
if (pointIndex < 0 || pointIndex >= boundary.size()) {
|
return boundary;
|
}
|
|
List<Coordinate> edited = new ArrayList<>();
|
for (int i = 0; i < boundary.size(); i++) {
|
if (i == pointIndex) {
|
edited.add(newPosition);
|
} else {
|
edited.add(boundary.get(i).copy());
|
}
|
}
|
|
// 自动平滑编辑点周围的区域
|
return smoothLocalArea(edited, pointIndex, 2);
|
}
|
|
// 平滑局部区域
|
private List<Coordinate> smoothLocalArea(List<Coordinate> boundary, int centerIndex, int radius) {
|
List<Coordinate> smoothed = new ArrayList<>(boundary);
|
int n = boundary.size();
|
|
for (int i = Math.max(0, centerIndex - radius);
|
i <= Math.min(n - 1, centerIndex + radius); i++) {
|
if (i == 0 || i == n - 1) continue; // 不移动首尾点
|
|
double sumX = 0, sumY = 0;
|
int count = 0;
|
|
for (int j = Math.max(0, i - 1); j <= Math.min(n - 1, i + 1); j++) {
|
sumX += boundary.get(j).x;
|
sumY += boundary.get(j).y;
|
count++;
|
}
|
|
Coordinate smoothedPoint = new Coordinate(
|
sumX / count, sumY / count,
|
boundary.get(i).lat, boundary.get(i).lon
|
);
|
smoothed.set(i, smoothedPoint);
|
}
|
|
return smoothed;
|
}
|
}
|