代码实现了多种风格地图(wildcluster
、street
、market
、random
)的生成以及可视化功能。地图生成过程包括初始化地图、设置起点和终点、添加特定元素(如种子点、道路、建筑、货架、障碍物等),并确保起点和终点之间可达,最后通过matplotlib
库将生成的地图可视化。
import numpy as np
import random
import matplotlib.pyplot as plt
from collections import deque
import math
from scipy.spatial import distance
from shapely.geometry import LineString
# wildcluster 风格地图生成
# 检查从起点出发可达的区域,并将无法到达的区域设置为障碍物(使用广度优先搜索 BFS)
def mark_or_check_reachability(map_array, start, end, mark_unreachable=False):
h, w = map_array.shape
visited = np.zeros((h, w), dtype=bool)
queue = deque([start])
directions = [(-1, 0), (1, 0), (0, -1), (0, 1), (-1, -1), (-1, 1), (1, -1), (1, 1)]
while queue:
x, y = queue.popleft()
if (x, y) == end:
if not mark_unreachable:
return True
if visited[y, x]:
continue
visited[y, x] = True
for dx, dy in directions:
nx, ny = x + dx, y + dy
if 0 <= nx < w and 0 <= ny < h and not visited[ny, nx] and map_array[ny, nx] != 0:
queue.append((nx, ny))
if mark_unreachable:
# 将无法到达的区域设置为障碍物
for y in range(h):
for x in range(w):
if not visited[y, x] and map_array[y, x] == 255:
map_array[y, x] = 0
# 检查终点是否可达
if not visited[end[1], end[0]]:
return None
return map_array
else:
return False
def generate_wildcluster_map(w, h, density):
density_config = {
'sparse': (0.01, 0.4),
'normal': (0.02, 0.5),
'dense': (0.03, 0.6)
}
seed_ratio, p = density_config[density]
n_seeds = int(w * h * seed_ratio)
attempts = 0
while attempts < 50:
# 初始化地图,全为255(表示空地)
basemap = np.full((h, w), 255, dtype=np.uint8)
# 随机生成起点和终点
end_point = (random.randint(0, w-1), random.randint(0, 2))
start_point = (random.randint(0, w-1), random.randint(h-3, h-1))
basemap[end_point[1], end_point[0]] = 200 # 终点蓝色
basemap[start_point[1], start_point[0]] = 100 # 起点绿色
# 生成种子点
seeds = set()
while len(seeds) < n_seeds:
sx, sy = random.randint(0, w-1), random.randint(0, h-1)
if (abs(sx - start_point[0]) > 5 or abs(sy - start_point[1]) > 5) and \
(abs(sx - end_point[0]) > 5 or abs(sy - end_point[1]) > 5):
seeds.add((sx, sy))
# 扩展种子点
for sx, sy in seeds:
basemap[sy, sx] = 0
expansion_radius = random.randint(1, 3)
for dx in range(-expansion_radius, expansion_radius + 1):
for dy in range(-expansion_radius, expansion_radius + 1):
nx, ny = sx + dx, sy + dy
if 0 <= nx < w and 0 <= ny < h and random.random() > p and basemap[ny, nx] == 255:
basemap[ny, nx] = 0
# 将从起点出发无法到达的区域填成障碍物
basemap = mark_or_check_reachability(basemap, start_point, end_point, mark_unreachable=True)
# 如果地图有效则返回
if basemap is not None:
return basemap, start_point, end_point
attempts += 1
raise RuntimeError(