package bianjie;
|
|
import java.util.ArrayList;
|
import java.util.List;
|
|
import zhuye.Coordinate;
|
|
public class bianjieguihua2 {
|
/**
|
* 自动处理Coordinate列表并生成优化后的边界坐标(无需传入间隔和角度阈值)
|
*
|
* @param coordinates Coordinate对象列表
|
* @param baseStation 基准站坐标,格式:"纬度,N/S,经度,E/W" 例如:"2324.194945,N,11330.938547,E"
|
* @return 优化后的边界坐标字符串,格式:"X0,Y0;X1,Y1;X2,Y2;..."
|
*/
|
public static String processCoordinateListAuto(String baseStation) {
|
List<Coordinate> coordinates =Coordinate.coordinates;
|
try {
|
// 检查输入数据
|
if (coordinates == null || coordinates.isEmpty()) {
|
throw new IllegalArgumentException("坐标列表不能为空");
|
}
|
|
if (baseStation == null || baseStation.trim().isEmpty()) {
|
throw new IllegalArgumentException("基站坐标不能为空");
|
}
|
|
// 解析基准站坐标
|
String[] baseParts = baseStation.split(",");
|
if (baseParts.length != 4) {
|
throw new IllegalArgumentException("基准站坐标格式错误,应为: 纬度,N/S,经度,E/W");
|
}
|
|
double baseLat = parseDMToDecimal(baseParts[0], baseParts[1]);
|
double baseLon = parseDMToDecimal(baseParts[2], baseParts[3]);
|
|
// 将Coordinate列表转换为局部坐标系坐标
|
List<BoundaryAlgorithm.Coordinate> localCoordinates =
|
convertToLocalCoordinates(coordinates, baseLat, baseLon);
|
|
// 三角形小区域特殊处理,避免过度插值导致点数扩增
|
if (localCoordinates.size() == 3) {
|
double triangleArea = calculatePolygonArea(localCoordinates);
|
double trianglePerimeter = calculatePerimeter(localCoordinates);
|
|
System.out.println("检测到三角形边界,面积=" + String.format("%.2f", triangleArea) +
|
"m², 周长=" + String.format("%.2f", trianglePerimeter) + "m");
|
|
if (triangleArea < 100.0 || trianglePerimeter < 30.0) {
|
System.out.println("小三角形,跳过插值优化");
|
BoundaryAlgorithm.Coordinate firstPoint = localCoordinates.get(0);
|
List<BoundaryAlgorithm.Coordinate> trianglePoints = new ArrayList<>(localCoordinates);
|
trianglePoints.add(new BoundaryAlgorithm.Coordinate(
|
firstPoint.x,
|
firstPoint.y,
|
firstPoint.lat,
|
firstPoint.lon));
|
return convertBoundaryPointsToString(trianglePoints);
|
}
|
}
|
|
// 创建算法实例
|
BoundaryAlgorithm algorithm = new BoundaryAlgorithm();
|
|
// 自动场景分析(增强版,使用高程数据)
|
BoundaryAlgorithm.SceneAnalysis sceneAnalysis = analyzeSceneFromCoordinates(localCoordinates, coordinates);
|
System.out.println("自动场景分析结果:");
|
System.out.println(sceneAnalysis.toString());
|
|
// 根据场景分析结果获取参数
|
BoundaryAlgorithm.BoundaryParameters params =
|
algorithm.getParametersForPreset(sceneAnalysis.suggestedPreset);
|
|
System.out.println("自动选择的参数: 间隔=" + params.interval + "米, 角度阈值=" +
|
params.angleThreshold + "度");
|
|
// 使用优化算法处理边界
|
List<BoundaryAlgorithm.Coordinate> optimizedPoints =
|
algorithm.optimizeBoundaryPointsAdvanced(localCoordinates, params);
|
|
// 质量评估
|
BoundaryAlgorithm.BoundaryQuality boundaryQuality =
|
algorithm.evaluateBoundaryQuality(optimizedPoints);
|
|
System.out.println("边界质量评估结果:");
|
System.out.println(boundaryQuality.toString());
|
|
// 转换为输出字符串格式
|
return convertBoundaryPointsToString(optimizedPoints);
|
|
} catch (Exception e) {
|
throw new RuntimeException("自动处理坐标列表时发生错误: " + e.getMessage(), e);
|
}
|
}
|
|
/**
|
* 基于坐标列表进行场景分析(增强版,使用高程数据)
|
*/
|
private static BoundaryAlgorithm.SceneAnalysis analyzeSceneFromCoordinates(
|
List<BoundaryAlgorithm.Coordinate> localCoords, List<Coordinate> originalCoords) {
|
|
BoundaryAlgorithm.SceneAnalysis analysis = new BoundaryAlgorithm.SceneAnalysis();
|
|
if (localCoords.size() < 3) {
|
analysis.suggestedPreset = "复杂小区域";
|
return analysis;
|
}
|
|
// 计算基本统计信息
|
calculateBasicStatisticsFromCoordinates(localCoords, analysis);
|
|
// 计算边界复杂度
|
calculateBoundaryComplexityFromCoordinates(localCoords, analysis);
|
|
// 计算高程变化(使用原始坐标的高程数据)
|
calculateElevationStatistics(originalCoords, analysis);
|
|
// 自动选择预设场景(增强版,考虑高程因素)
|
selectPresetAutomaticallyFromCoordinates(analysis);
|
|
return analysis;
|
}
|
|
/**
|
* 从坐标计算基本统计信息
|
*/
|
private static void calculateBasicStatisticsFromCoordinates(
|
List<BoundaryAlgorithm.Coordinate> points, BoundaryAlgorithm.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);
|
} else {
|
analysis.avgSpeed = 0;
|
}
|
}
|
|
/**
|
* 计算高程统计信息
|
*/
|
private static void calculateElevationStatistics(List<Coordinate> coordinates,
|
BoundaryAlgorithm.SceneAnalysis analysis) {
|
if (coordinates == null || coordinates.isEmpty()) {
|
analysis.elevationRange = 0;
|
return;
|
}
|
|
double minElevation = Double.MAX_VALUE;
|
double maxElevation = Double.MIN_VALUE;
|
|
for (Coordinate coord : coordinates) {
|
double elevation = coord.getElevation();
|
if (elevation < minElevation) minElevation = elevation;
|
if (elevation > maxElevation) maxElevation = elevation;
|
}
|
|
analysis.elevationRange = maxElevation - minElevation;
|
|
// 计算平均高程
|
double sumElevation = 0;
|
for (Coordinate coord : coordinates) {
|
sumElevation += coord.getElevation();
|
}
|
double avgElevation = sumElevation / coordinates.size();
|
|
System.out.println("高程统计: 范围=" + String.format("%.2f", analysis.elevationRange) +
|
"米, 平均=" + String.format("%.2f", avgElevation) + "米");
|
}
|
|
/**
|
* 从坐标计算边界复杂度
|
*/
|
private static void calculateBoundaryComplexityFromCoordinates(
|
List<BoundaryAlgorithm.Coordinate> points, BoundaryAlgorithm.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 static void selectPresetAutomaticallyFromCoordinates(BoundaryAlgorithm.SceneAnalysis analysis) {
|
// 决策逻辑基于多个因素
|
double areaWeight = 0.4;
|
double complexityWeight = 0.3;
|
double elevationWeight = 0.3; // 增加高程权重
|
|
// 计算综合得分
|
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 / 20.0); // 20米变化为基准
|
score += elevationScore * elevationWeight;
|
|
// 根据得分选择预设
|
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);
|
}
|
|
/**
|
* 计算两点间距离
|
*/
|
private static double calculateDistance(BoundaryAlgorithm.Coordinate p1, BoundaryAlgorithm.Coordinate p2) {
|
double dx = p2.x - p1.x;
|
double dy = p2.y - p1.y;
|
return Math.sqrt(dx * dx + dy * dy);
|
}
|
|
/**
|
* 计算角度变化
|
*/
|
private static double calculateAngleChange(BoundaryAlgorithm.Coordinate prev,
|
BoundaryAlgorithm.Coordinate current,
|
BoundaryAlgorithm.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;
|
}
|
|
/**
|
* 计算多边形面积
|
*/
|
private static double calculatePolygonArea(List<BoundaryAlgorithm.Coordinate> points) {
|
if (points.size() < 3) return 0.0;
|
|
double area = 0.0;
|
int n = points.size();
|
|
for (int i = 0; i < n; i++) {
|
BoundaryAlgorithm.Coordinate current = points.get(i);
|
BoundaryAlgorithm.Coordinate next = points.get((i + 1) % n);
|
area += (current.x * next.y - next.x * current.y);
|
}
|
|
return Math.abs(area) / 2.0;
|
}
|
|
private static double calculatePerimeter(List<BoundaryAlgorithm.Coordinate> points) {
|
if (points == null || points.size() != 3) {
|
return 0.0;
|
}
|
double d1 = calculateDistance(points.get(0), points.get(1));
|
double d2 = calculateDistance(points.get(1), points.get(2));
|
double d3 = calculateDistance(points.get(2), points.get(0));
|
return d1 + d2 + d3;
|
}
|
|
// ============ 其他方法保持不变 ============
|
|
/**
|
* 将度分格式坐标转换为十进制度格式
|
*/
|
private static double parseDMToDecimal(String dmCoord, String direction) {
|
try {
|
if (dmCoord == null || dmCoord.isEmpty()) {
|
return 0;
|
}
|
|
int dotIndex = dmCoord.indexOf('.');
|
if (dotIndex < 2) {
|
return 0;
|
}
|
|
// 提取度部分和分部分
|
int degrees = Integer.parseInt(dmCoord.substring(0, dotIndex - 2));
|
double minutes = Double.parseDouble(dmCoord.substring(dotIndex - 2));
|
|
// 转换为十进制度
|
double decimal = degrees + minutes / 60.0;
|
|
// 根据方向调整正负
|
if ("S".equals(direction) || "W".equals(direction)) {
|
decimal = -decimal;
|
}
|
|
return decimal;
|
|
} catch (Exception e) {
|
throw new IllegalArgumentException("度分坐标解析错误: " + dmCoord, e);
|
}
|
}
|
|
/**
|
* 将Coordinate列表转换为局部坐标系坐标
|
*/
|
private static List<BoundaryAlgorithm.Coordinate> convertToLocalCoordinates(
|
List<Coordinate> coordinates, double baseLat, double baseLon) {
|
|
List<BoundaryAlgorithm.Coordinate> localCoords = new ArrayList<>();
|
|
for (Coordinate coord : coordinates) {
|
try {
|
// 解析度分格式坐标为十进制度
|
double lat = parseDMToDecimal(coord.getLatitude(), coord.getLatDirection());
|
double lon = parseDMToDecimal(coord.getLongitude(), coord.getLonDirection());
|
|
// 转换为局部坐标系
|
BoundaryAlgorithm.Coordinate localCoord =
|
convertToLocalCoordinate(lat, lon, baseLat, baseLon);
|
|
localCoords.add(localCoord);
|
|
} catch (Exception e) {
|
System.err.println("坐标转换失败: " + coord + ", 错误: " + e.getMessage());
|
}
|
}
|
|
return localCoords;
|
}
|
|
/**
|
* 将经纬度坐标转换为局部坐标系
|
*/
|
private static BoundaryAlgorithm.Coordinate convertToLocalCoordinate(
|
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);
|
|
return new BoundaryAlgorithm.Coordinate(eastDistance, northDistance, lat, lon);
|
}
|
|
/**
|
* 将边界点列表转换为字符串格式
|
*/
|
private static String convertBoundaryPointsToString(List<BoundaryAlgorithm.Coordinate> points) {
|
if (points == null || points.isEmpty()) {
|
return "";
|
}
|
|
StringBuilder coordinatesBuilder = new StringBuilder();
|
for (int i = 0; i < points.size(); i++) {
|
BoundaryAlgorithm.Coordinate point = points.get(i);
|
coordinatesBuilder.append(String.format("%.2f,%.2f", point.x, point.y));
|
if (i < points.size() - 1) {
|
coordinatesBuilder.append(";");
|
}
|
}
|
|
return coordinatesBuilder.toString();
|
}
|
|
// // ============ 测试方法 ============
|
//
|
// /**
|
// * 测试方法
|
// */
|
// public static void main(String[] args) {
|
// try {
|
// // 创建测试Coordinate列表(包含高程数据)
|
// int count = Coordinate.loadFromGNGGAFile();
|
// List<Coordinate> coordinateList=Coordinate.coordinates;
|
//
|
// // 设置基准站坐标
|
// String baseStation = "3949.91202005,N,11616.85440851,E";
|
//
|
// // 调用自动处理方法
|
// String result = bianjieguihua2.processCoordinateListAuto(coordinateList, baseStation);
|
//
|
// System.out.println("自动处理的边界点坐标结果: " + result);
|
//
|
// } catch (Exception e) {
|
// System.err.println("处理失败: " + e.getMessage());
|
// e.printStackTrace();
|
// }
|
// }
|
}
|