package Building;
import java.util.*;
public class OptimizedOcclusionAnalyzer extends BuildingOcclusionAnalyzer {
/**
* 使用空间索引优化遮挡分析
*/
public static Map<String, List<VisibilityResult>> analyzeOcclusionOptimized(ResidentialArea area) {
// 构建空间索引(按经纬度网格划分)
Map<String, List<Building>> spatialIndex = createSpatialIndex(area.buildings);
Map<String, List<VisibilityResult>> results = new HashMap<>();
List<Building> buildings = area.buildings;
for (int i = 0; i < buildings.size(); i++) {
Building source = buildings.get(i);
List<VisibilityResult> sourceResults = new ArrayList<>();
// 只检查附近网格中的建筑
List<Building> nearbyBuildings = getNearbyBuildings(source, spatialIndex, area.buildings);
for (Building target : nearbyBuildings) {
if (source.id.equals(target.id)) continue;
boolean isVisible = checkVisibilityOptimized(source, target, nearbyBuildings, spatialIndex);
double distance = calculateDistance(source.latitude, source.longitude,
target.latitude, target.longitude);
double obstructionAngle = BuildingOcclusionAnalyzer.calculateObstructionAngle(source, target);
sourceResults.add(new VisibilityResult(source, target, isVisible,
obstructionAngle, distance));
}
results.put(source.id, sourceResults);
}
return results;
}
public static Map<String, List<Building>> createSpatialIndex(List<Building> buildings) {
Map<String, List<Building>> index = new HashMap<>();
double gridSize = 0.001; // 网格大小(约100米)
for (Building building : buildings) {
int gridX = (int)(building.longitude / gridSize);
int gridY = (int)(building.latitude / gridSize);
String gridKey = gridX + "," + gridY;
index.computeIfAbsent(gridKey, k -> new ArrayList<>()).add(building);
}
return index;
}
private static List<Building> getNearbyBuildings(Building source,
Map<String, List<Building>> spatialIndex,
List<Building> allBuildings) {
// 返回源建筑周围3x3网格内的所有建筑
// 简化实现:返回所有建筑(实际应根据距离过滤)
return allBuildings;
}
/**
* 计算仰角(弧度)
*/
private static double calculateElevationAngle(Building source, Building target) {
double distance = calculateDistance(source.latitude, source.longitude,
target.latitude, target.longitude);
double heightDifference = target.height - source.height;
return Math.atan2(heightDifference, distance);
}
/**
* 优化版的视线检查方法(使用空间索引)
*/
public static boolean checkVisibilityOptimized(Building source, Building target,
List<Building> nearbyBuildings,
Map<String, List<Building>> spatialIndex) {
double sourceLat = source.latitude;
double sourceLon = source.longitude;
double targetLat = target.latitude;
double targetLon = target.longitude;
// 计算视线角度
double azimuth = calculateAzimuth(sourceLat, sourceLon, targetLat, targetLon);
double elevation = calculateElevationAngle(source, target);
// 获取视线路径上的网格区域
Set<String> sightLineGrids = getSightLineGrids(sourceLat, sourceLon, targetLat, targetLon, 0.001);
// 只检查视线路径上的建筑
List<Building> potentialObstacles = new ArrayList<>();
for (String gridKey : sightLineGrids) {
List<Building> gridBuildings = spatialIndex.get(gridKey);
if (gridBuildings != null) {
potentialObstacles.addAll(gridBuildings);
}
}
// 进一步过滤:只检查在源建筑和目标建筑之间的建筑
potentialObstacles = filterBuildingsBetween(source, target, potentialObstacles);
// 检查遮挡
for (Building obstacle : potentialObstacles) {
if (obstacle.id.equals(source.id) || obstacle.id.equals(target.id)) {
continue;
}
if (isBuildingInSightLine(source, target, obstacle)) {
double obstacleElevation = calculateElevationAngle(source, obstacle);
// 如果障碍物的仰角大于目标仰角,则遮挡
if (obstacleElevation > elevation) {
return false;
}
}
}
return true;
}
private static double pointToLineDistance(double[] linePoint1, double[] linePoint2, double[] point) {
double x0 = point[0], y0 = point[1];
double x1 = linePoint1[0], y1 = linePoint1[1];
double x2 = linePoint2[0], y2 = linePoint2[1];
double A = x0 - x1;
double B = y0 - y1;
double C = x2 - x1;
double D = y2 - y1;
double dot = A * C + B * D;
double len_sq = C * C + D * D;
double param = (len_sq != 0) ? dot / len_sq : -1;
double xx, yy;
if (param < 0) {
xx = x1;
yy = y1;
} else if (param > 1) {
xx = x2;
yy = y2;
} else {
xx = x1 + param * C;
yy = y1 + param * D;
}
double dx = x0 - xx;
double dy = y0 - yy;
return Math.sqrt(dx * dx + dy * dy);
}
/**
* 计算点到线段的距离
*/
private static double distanceToLineSegment(double lineLat1, double lineLon1,
double lineLat2, double lineLon2,
double pointLat, double pointLon) {
// 将经纬度转换为平面坐标(简化处理,适用于小范围)
double[] p1 = {lineLon1, lineLat1};
double[] p2 = {lineLon2, lineLat2};
double[] p = {pointLon, pointLat};
return pointToLineDistance(p1, p2, p);
}
/**
* 判断建筑是否在视线路径上
*/
private static boolean isBuildingInSightLine(Building source, Building target, Building obstacle) {
double sourceLat = source.latitude;
double sourceLon = source.longitude;
double targetLat = target.latitude;
double targetLon = target.longitude;
double obstacleLat = obstacle.latitude;
double obstacleLon = obstacle.longitude;
// 计算障碍物到视线的距离
double distanceToLine = distanceToLineSegment(
sourceLat, sourceLon, targetLat, targetLon, obstacleLat, obstacleLon);
// 如果距离小于建筑宽度的一半(假设建筑宽度约50米),则认为在视线路径上
return distanceToLine < 25;
}
/**
* 获取视线路径经过的网格区域
*/
private static Set<String> getSightLineGrids(double lat1, double lon1,
double lat2, double lon2,
double gridSize) {
Set<String> grids = new HashSet<>();
// Bresenham算法在网格空间中的实现
int x1 = (int)(lon1 / gridSize);
int y1 = (int)(lat1 / gridSize);
int x2 = (int)(lon2 / gridSize);
int y2 = (int)(lat2 / gridSize);
int dx = Math.abs(x2 - x1);
int dy = Math.abs(y2 - y1);
int sx = (x1 < x2) ? 1 : -1;
int sy = (y1 < y2) ? 1 : -1;
int err = dx - dy;
while (true) {
grids.add(x1 + "," + y1);
if (x1 == x2 && y1 == y2) break;
int e2 = 2 * err;
if (e2 > -dy) {
err -= dy;
x1 += sx;
}
if (e2 < dx) {
err += dx;
y1 += sy;
}
}
return grids;
}
/**
* 过滤出在源建筑和目标建筑之间的建筑
*/
private static List<Building> filterBuildingsBetween(Building source, Building target,
List<Building> buildings) {
List<Building> filtered = new ArrayList<>();
double minLat = Math.min(source.latitude, target.latitude);
double maxLat = Math.max(source.latitude, target.latitude);
double minLon = Math.min(source.longitude, target.longitude);
double maxLon = Math.max(source.longitude, target.longitude);
for (Building building : buildings) {
if (building.latitude >= minLat && building.latitude <= maxLat &&
building.longitude >= minLon && building.longitude <= maxLon) {
filtered.add(building);
}
}
return filtered;
}
/**
* 更精确的建筑在视线路径上判断
*/
private static boolean isBuildingInSightLinePrecise(Building source, Building target, Building obstacle) {
double sourceLat = source.latitude;
double sourceLon = source.longitude;
double targetLat = target.latitude;
double targetLon = target.longitude;
double obstacleLat = obstacle.latitude;
double obstacleLon = obstacle.longitude;
// 计算障碍物到视线的垂直距离
double distanceToLine = distanceToLineSegment(
sourceLat, sourceLon, targetLat, targetLon, obstacleLat, obstacleLon);
// 计算建筑的大致宽度(基于楼层数估算)
double buildingWidth = estimateBuildingWidth(obstacle);
// 如果距离小于建筑宽度,则认为在视线路径上
return distanceToLine < buildingWidth / 2;
}
/**
* 估算建筑宽度(米)
*/
private static double estimateBuildingWidth(Building building) {
// 假设每层楼约100平方米,建筑近似为正方形
double areaPerFloor = 100; // 平方米
double sideLength = Math.sqrt(areaPerFloor * building.floors);
return sideLength;
}
}
package Building;
import java.util.*;
public class PerformanceComparison {
public static void main(String[] args) {
// 创建测试数据(100栋建筑)
List<Building> testBuildings = generateTestBuildings(100);
ResidentialArea testArea = new ResidentialArea("TEST", "测试小区", 39.9087, 116.3975);
testBuildings.forEach(testArea::addBuilding);
// 构建空间索引
Map<String, List<Building>> spatialIndex = OptimizedOcclusionAnalyzer.createSpatialIndex(testBuildings);
// 性能测试:原始方法 vs 优化方法
Building testSource = testBuildings.get(0);
Building testTarget = testBuildings.get(50);
// 原始方法
long startTime = System.nanoTime();
boolean result1 = BuildingOcclusionAnalyzer.checkVisibility(
testSource, testTarget, testBuildings);
long time1 = System.nanoTime() - startTime;
// 优化方法
startTime = System.nanoTime();
boolean result2 = OptimizedOcclusionAnalyzer.checkVisibilityOptimized(
testSource, testTarget, testBuildings, spatialIndex);
long time2 = System.nanoTime() - startTime;
System.out.println("性能对比结果:");
System.out.printf("原始方法: %.3f ms, 结果: %b%n", time1 / 1_000_000.0, result1);
System.out.printf("优化方法: %.3f ms, 结果: %b%n", time2 / 1_000_000.0, result2);
System.out.printf("性能提升: %.1f 倍%n", (double)time1 / time2);
// 批量测试
testBatchPerformance(testArea, spatialIndex);
}
private static List<Building> generateTestBuildings(int count) {
List<Building> buildings = new ArrayList<>();
Random random = new Random();
double centerLat = 39.9087;
double centerLon = 116.3975;
double range = 0.01; // 约1公里范围
for (int i = 0; i < count; i++) {
double lat = centerLat + (random.nextDouble() - 0.5) * range;
double lon = centerLon + (random.nextDouble() - 0.5) * range;
double height = 30 + random.nextDouble() * 70; // 30-100米
int floors = 10 + random.nextInt(20); // 10-30层
buildings.add(new Building("B" + i, "建筑" + i, lat, lon, height, floors));
}
return buildings;
}
private static void testBatchPerformance(ResidentialArea area,
Map<String, List<Building>> spatialIndex) {
List<Building> buildings = area.buildings;
// 测试1000次视线检查
long startTime = System.nanoTime();
for (int i = 0; i < 1000; i++) {
Building source = buildings.get(i % buildings.size());
Building target = buildings.get((i + 10) % buildings.size());
BuildingOcclusionAnalyzer.checkVisibility(source, target, buildings);
}
long timeOriginal = System.nanoTime() - startTime;
startTime = System.nanoTime();
for (int i = 0; i < 1000; i++) {
Building source = buildings.get(i % buildings.size());
Building target = buildings.get((i + 10) % buildings.size());
OptimizedOcclusionAnalyzer.checkVisibilityOptimized(source, target, buildings, spatialIndex);
}
long timeOptimized = System.nanoTime() - startTime;
System.out.println("\n批量性能测试 (1000次视线检查):");
System.out.printf("原始方法总时间: %.3f ms%n", timeOriginal / 1_000_000.0);
System.out.printf("优化方法总时间: %.3f ms%n", timeOptimized / 1_000_000.0);
System.out.printf("批量性能提升: %.1f 倍%n", (double)timeOriginal / timeOptimized);
}
}