rendered paste body# -*- coding: utf-8 -*-"""从一条山脊到一整片大陆.ipynbAutomatically generated by Colab.Original file is located at https://colab.research.google.com/drive/1Huc6gsj8JWXMhVpzBvpS9RDTmPrmqp5f"""import numpy as npimport matplotlib.pyplot as pltfrom matplotlib.colors import LinearSegmentedColormapfrom mpl_toolkits.mplot3d import Axes3Ddef diamond_square(iterations=8, initial_displacement=1.0, decay=0.55, seed=7): """ 用钻石—正方形算法生成二维山地。 iterations: 迭代次数。最终网格大小为 (2^iterations + 1) × (2^iterations + 1) initial_displacement: 第一次迭代时的随机偏移幅度 decay: 每轮迭代后,随机偏移缩小的比例 seed: 随机种子。相同种子会生成相同的山脉 """ rng = np.random.default_rng(seed) size = 2 ** iterations + 1 terrain = np.zeros((size, size)) # 给平面的四个角设置初始高度 terrain[0, 0] = rng.uniform(-0.2, 0.2) terrain[0, -1] = rng.uniform(-0.2, 0.2) terrain[-1, 0] = rng.uniform(-0.2, 0.2) terrain[-1, -1] = rng.uniform(-0.2, 0.2) step = size - 1 displacement = initial_displacement while step > 1: half = step // 2 # ------------------------- # 第一步:正方形步骤 # ------------------------- # 找到每个正方形的中心点, # 取四个角高度的平均值,再加入随机偏移 for y in range(half, size - 1, step): for x in range(half, size - 1, step): top_left = terrain[y - half, x - half] top_right = terrain[y - half, x + half] bottom_left = terrain[y + half, x - half] bottom_right = terrain[y + half, x + half] average = ( top_left + top_right + bottom_left + bottom_right ) / 4 terrain[y, x] = average + rng.uniform( -displacement, displacement ) # ------------------------- # 第二步:钻石步骤 # ------------------------- # 找到每个菱形的中心点, # 取周围已有点的平均值,再加入随机偏移 for y in range(0, size, half): start_x = half if (y // half) % 2 == 0 else 0 for x in range(start_x, size, step): neighbors = [] if y - half >= 0: neighbors.append(terrain[y - half, x]) if y + half < size: neighbors.append(terrain[y + half, x]) if x - half >= 0: neighbors.append(terrain[y, x - half]) if x + half < size: neighbors.append(terrain[y, x + half]) average = np.mean(neighbors) terrain[y, x] = average + rng.uniform( -displacement, displacement ) # 网格尺度缩小 step //= 2 # 随着尺度变小,随机偏移也逐渐减小 displacement *= decay # 把高度归一化到 0~1 terrain -= terrain.min() terrain /= terrain.max() return terrain# 生成二维山地terrain = diamond_square( iterations=8, initial_displacement=1.0, decay=0.55, seed=7)# 自定义地形颜色:# 深蓝—浅蓝—绿色—棕色—白色terrain_colors = LinearSegmentedColormap.from_list( "terrain_colors", [ (0.00, "#264653"), (0.18, "#4f8a8b"), (0.32, "#84a98c"), (0.55, "#52734d"), (0.72, "#8b6f47"), (0.88, "#b8a88a"), (1.00, "#f5f5f5") ])# 建立平面坐标size = terrain.shape[0]x = np.linspace(0, 1, size)y = np.linspace(0, 1, size)X, Y = np.meshgrid(x, y)# 为了让山峰更加明显,对高度稍作非线性处理Z = terrain ** 1.35# 绘制三维山脉fig = plt.figure(figsize=(14, 9))ax = fig.add_subplot(111, projection="3d")surface = ax.plot_surface( X, Y, Z, cmap=terrain_colors, linewidth=0, antialiased=True, rcount=180, ccount=180)ax.view_init(elev=42, azim=-125)# 调整纵向比例,使山脉更有立体感ax.set_box_aspect((1, 1, 0.38))ax.set_axis_off()ax.set_title( "Diamond-Square Fractal Mountain", fontsize=18, pad=10)plt.tight_layout()plt.show()