bd

package Building;

import java.util.*;
import java.lang.Math;

// 建筑类
class Building {
String id;
String name;
double latitude; // 纬度
double longitude; // 经度
double height; // 建筑高度(米)
int floors; // 楼层数

public Building(String id, String name, double lat, double lon, double height, int floors) {
this.id = id;
this.name = name;
this.latitude = lat;
this.longitude = lon;
this.height = height;
this.floors = floors;
}
}

// 小区类
class ResidentialArea {
String id;
String name;
List<Building> buildings;
double centerLat;
double centerLon;

public ResidentialArea(String id, String name, double centerLat, double centerLon) {
this.id = id;
this.name = name;
this.centerLat = centerLat;
this.centerLon = centerLon;
this.buildings = new ArrayList<>();
}

public void addBuilding(Building building) {
buildings.add(building);
}
}

// 视线分析结果
class VisibilityResult {
Building sourceBuilding;
Building targetBuilding;
boolean isVisible;
double obstructionAngle; // 遮挡角度
double distance; // 距离

public VisibilityResult(Building source, Building target, boolean visible,
double angle, double distance) {
this.sourceBuilding = source;
this.targetBuilding = target;
this.isVisible = visible;
this.obstructionAngle = angle;
this.distance = distance;
}
}


package Building;

import java.util.*;
;

public class BuildingOcclusionAnalyzer {

private static final double EARTH_RADIUS = 6371000; // 地球半径(米)

/**
* 分析小区内所有建筑的相互遮挡关系
*/
public static Map<String, List<VisibilityResult>> analyzeOcclusion(ResidentialArea area) {
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<>();

for (int j = 0; j < buildings.size(); j++) {
if (i == j) continue; // 跳过自身

Building target = buildings.get(j);
boolean isVisible = checkVisibility(source, target, buildings);
double distance = calculateDistance(source.latitude, source.longitude,
target.latitude, target.longitude);
double obstructionAngle = calculateObstructionAngle(source, target);

sourceResults.add(new VisibilityResult(source, target, isVisible,
obstructionAngle, distance));
}

results.put(source.id, sourceResults);
}

return results;
}

/**
* 检查源建筑是否能看见目标建筑
*/
public static boolean checkVisibility(Building source, Building target, List<Building> allBuildings) {
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);

// 检查中间是否有遮挡建筑
for (Building obstacle : allBuildings) {
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 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 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 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 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 double calculateObstructionAngle(Building source, Building target) {
double elevation = calculateElevationAngle(source, target);
return Math.toDegrees(elevation);
}

/**
* 计算两点之间的距离(米)
*/
public static double calculateDistance(double lat1, double lon1, double lat2, double lon2) {
double lat1Rad = Math.toRadians(lat1);
double lon1Rad = Math.toRadians(lon1);
double lat2Rad = Math.toRadians(lat2);
double lon2Rad = Math.toRadians(lon2);

double dLat = lat2Rad - lat1Rad;
double dLon = lon2Rad - lon1Rad;

double a = Math.sin(dLat/2) * Math.sin(dLat/2) +
Math.cos(lat1Rad) * Math.cos(lat2Rad) *
Math.sin(dLon/2) * Math.sin(dLon/2);

double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a));

return EARTH_RADIUS * c;
}

/**
* 计算方位角
*/
public static double calculateAzimuth(double lat1, double lon1, double lat2, double lon2) {
double lat1Rad = Math.toRadians(lat1);
double lon1Rad = Math.toRadians(lon1);
double lat2Rad = Math.toRadians(lat2);
double lon2Rad = Math.toRadians(lon2);

double dLon = lon2Rad - lon1Rad;

double y = Math.sin(dLon) * Math.cos(lat2Rad);
double x = Math.cos(lat1Rad) * Math.sin(lat2Rad) -
Math.sin(lat1Rad) * Math.cos(lat2Rad) * Math.cos(dLon);

double azimuthRad = Math.atan2(y, x);
double azimuthDeg = Math.toDegrees(azimuthRad);
return (azimuthDeg + 360) % 360;
}
}

package Building;
import java.util.*;
public class OcclusionAnalysisExample {

public static void main(String[] args) {
// 创建小区
ResidentialArea area = new ResidentialArea("RA001", "阳光小区", 39.9087, 116.3975);

// 添加建筑物
area.addBuilding(new Building("B001", "1号楼", 39.9087, 116.3975, 60.0, 20));
area.addBuilding(new Building("B002", "2号楼", 39.9090, 116.3980, 45.0, 15));
area.addBuilding(new Building("B003", "3号楼", 39.9085, 116.3970, 75.0, 25));
area.addBuilding(new Building("B004", "4号楼", 39.9092, 116.3968, 30.0, 10));
area.addBuilding(new Building("B005", "5号楼", 39.9083, 116.3982, 90.0, 30));

// 分析遮挡关系
Map<String, List<VisibilityResult>> results = BuildingOcclusionAnalyzer.analyzeOcclusion(area);

// 输出结果
System.out.println("=== 小区建筑遮挡分析结果 ===");
for (Map.Entry<String, List<VisibilityResult>> entry : results.entrySet()) {
Building source = null;
for (Building b : area.buildings) {
if (b.id.equals(entry.getKey())) {
source = b;
break;
}
}

System.out.println("\n" + source.name + " 的视野分析:");

for (VisibilityResult result : entry.getValue()) {
String status = result.isVisible ? "可见" : "被遮挡";
System.out.printf(" → %s: %s (距离: %.1fm, 仰角: %.1f°)%n",
result.targetBuilding.name, status, result.distance, result.obstructionAngle);
}
}

// 生成遮挡统计
generateOcclusionStatistics(area, results);
}

private static void generateOcclusionStatistics(ResidentialArea area,
Map<String, List<VisibilityResult>> results) {
System.out.println("\n=== 遮挡统计 ===");

for (Building building : area.buildings) {
List<VisibilityResult> buildingResults = results.get(building.id);
long visibleCount = buildingResults.stream().filter(r -> r.isVisible).count();
long totalCount = buildingResults.size();

System.out.printf("%s: 可见 %d/%d 栋建筑 (%.1f%%)%n",
building.name, visibleCount, totalCount, (visibleCount * 100.0 / totalCount));
}
}
}



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);
}
}














posted @ 2025-08-28 23:23  good白  阅读(11)  评论(0)    收藏  举报