使用 Python 实现随机中点位移法生成逼真的裂隙面
使用 Python 实现随机中点位移法生成逼真的裂隙面
裂隙面在地质学、岩石力学、计算机图形学等领域有着广泛的应用。它们的随机性和分形特性使得模拟真实裂隙面成为一项重要的研究课题。本文将通过 Python ,结合经典的 随机中点位移法( Random Midpoint Displacement , RMD ),逐步创建一个二维的随机裂隙面,并详细解析每一步代码的实现过程。
先看下效果图:
一、随机中点位移法简介
1. 什么是随机中点位移法?
随机中点位移法是一种简单且高效的分形生成算法。它的基本思想是从一个大尺度开始,通过不断细化网格,并在每次细化时为中间点添加随机扰动,从而生成具有大尺度结构和小尺度细节的表面。
这一方法的特点是:
2. 应用领域
二、 Python 代码实现
让我们直接进入代码部分,并通过逐行详解,帮助你全面掌握随机中点位移法的实现。
1. 导入必要的库
import numpy as np
import matplotlib.pyplot as plt
numpy
:用于处理多维数组和数学计算。我们将借助它来创建二维数组并进行随机数生成。matplotlib.pyplot
:用于可视化生成的裂隙面。这是 Python 中非常强大的绘图库。2. 函数定义:随机中点位移法核心逻辑
def midpoint_displacement_2d(size, roughness, seed=None):
"""
使用随机中点位移法生成二维粗糙裂隙面。
参数:
- size: 裂隙面的网格尺寸(必须是2的幂次方+1,例如65, 129, 257等)。
- roughness: 粗糙度参数,控制表面的起伏程度。
- seed: 随机数种子,用于生成可重复的结果。
返回值:
- surface: 生成的二维裂隙面。
"""
函数说明
size
:二维数组的大小,必须为 2^n + 1
(如 129 , 257 等)。这种结构使网格能够在每次迭代中被整齐地细分。roughness
:粗糙度参数,控制生成裂隙面的起伏程度。值越大,表面越粗糙;值越小,表面越平滑。seed
:随机数种子,用于确保生成的结果是可重复的。指定种子后,每次运行都会生成相同的裂隙面。3. 设置随机数种子
if seed is not None:
np.random.seed(seed)
解释
seed
值,那么我们使用 np.random.seed(seed)
设置随机数生成器的种子。4. 初始化二维裂隙面
surface = np.zeros((size, size))
np.zeros((size, size))
:创建一个大小为 (size, size)
的二维数组,初始值全为 0 。5. 初始化网格的四个顶点
surface[0, 0] = np.random.uniform(-1, 1)
surface[0, -1] = np.random.uniform(-1, 1)
surface[-1, 0] = np.random.uniform(-1, 1)
surface[-1, -1] = np.random.uniform(-1, 1)
解释
[-1, 1]
。6. 初始化步长
step_size = size - 1
解释
size - 1
。7. 开始迭代生成裂隙面
while step_size > 1:
half_step = step_size // 2
解释
while
循环,直到步长小于或等于 1 。half_step = step_size // 2
,用于在网格的中点和边界点之间插值。8. 钻石步( Diamond Step )
for x in range(0, size - 1, step_size):
for y in range(0, size - 1, step_size):
avg = (
surface[x, y]
+ surface[x + step_size, y]
+ surface[x, y + step_size]
+ surface[x + step_size, y + step_size]
) / 4
surface[x + half_step, y + half_step] = avg + np.random.uniform(-1, 1) * roughness
说明
avg
:计算当前网格四个顶点的平均值。np.random.uniform(-1, 1) * roughness
:添加一个随机扰动,其幅度由 roughness
控制。surface[x + half_step, y + half_step]
。9. 方形步( Square Step )
for x in range(0, size - 1, half_step):
for y in range((x + half_step) % step_size, size - 1, step_size):
avg = 0
count = 0
if x - half_step >= 0:
avg += surface[x - half_step, y]
count += 1
if x + half_step < size:
avg += surface[x + half_step, y]
count += 1
if y - half_step >= 0:
avg += surface[x, y - half_step]
count += 1
if y + half_step < size:
avg += surface[x, y + half_step]
count += 1
surface[x, y] = avg / count + np.random.uniform(-1, 1) * roughness
说明
10. 更新步长和粗糙度
step_size //= 2
roughness /= 2
说明
11. 返回最终结果
return surface
说明
12. 调用函数并可视化结果
size = 129
roughness = 1.0
seed = 42
surface = midpoint_displacement_2d(size, roughness, seed)
plt.figure(figsize=(10, 8))
plt.imshow(surface, cmap='terrain', origin='upper')
plt.colorbar(label="Height")
plt.title("Random Midpoint Displacement Surface")
plt.xlabel("X-axis")
plt.ylabel("Y-axis")
plt.show()
说明
–
size=129
:网格大小为 129 × 129 。–
roughness=1.0
:初始粗糙度。–
seed=42
:随机种子,用于生成可复现的结果。matplotlib
绘制结果:–
imshow
:展示二维裂隙面。–
cmap='terrain'
:用地形色彩映射模拟裂隙表面。三、完整代码
import numpy as np
import matplotlib.pyplot as plt
def midpoint_displacement_2d(size, roughness, seed=None):
"""
使用随机中点位移法生成二维粗糙裂隙面。
参数:
- size: 裂隙面的网格尺寸(必须是2的幂次方+1,例如65, 129, 257等)。
- roughness: 粗糙度参数,控制表面的起伏程度。
- seed: 随机数种子,用于生成可重复的结果。
返回值:
- surface: 生成的二维裂隙面。
"""
if seed is not None:
np.random.seed(seed)
# 初始化一个二维数组,并将四个顶点随机赋值
surface = np.zeros((size, size))
surface[0, 0] = np.random.uniform(-1, 1)
surface[0, -1] = np.random.uniform(-1, 1)
surface[-1, 0] = np.random.uniform(-1, 1)
surface[-1, -1] = np.random.uniform(-1, 1)
step_size = size - 1 # 初始步长
while step_size > 1:
half_step = step_size // 2
# 钻石步:计算中点值
for x in range(0, size - 1, step_size):
for y in range(0, size - 1, step_size):
avg = (
surface[x, y]
+ surface[x + step_size, y]
+ surface[x, y + step_size]
+ surface[x + step_size, y + step_size]
) / 4
surface[x + half_step, y + half_step] = avg + np.random.uniform(-1, 1) * roughness
# 方形步:计算边点值
for x in range(0, size - 1, half_step):
for y in range((x + half_step) % step_size, size - 1, step_size):
avg = 0
count = 0
if x - half_step >= 0:
avg += surface[x - half_step, y]
count += 1
if x + half_step < size:
avg += surface[x + half_step, y]
count += 1
if y - half_step >= 0:
avg += surface[x, y - half_step]
count += 1
if y + half_step < size:
avg += surface[x, y + half_step]
count += 1
surface[x, y] = avg / count + np.random.uniform(-1, 1) * roughness
# 缩小步长,并降低粗糙度比例
step_size //= 2
roughness /= 2
return surface
# 参数设置
size = 129 # 网格尺寸(2^n + 1,例如65, 129, 257)
roughness = 1.0 # 粗糙度系数
seed = 42 # 随机种子(可选)
# 生成裂隙面
surface = midpoint_displacement_2d(size, roughness, seed)
# 绘制裂隙面
plt.figure(figsize=(10, 8))
plt.imshow(surface, cmap='terrain', origin='upper')
plt.colorbar(label="Height")
plt.title("Random Midpoint Displacement Surface")
plt.xlabel("X-axis")
plt.ylabel("Y-axis")
plt.show()
四、结果展示与分析
运行上述代码后,你将看到一个二维裂隙面,具有随机的高低起伏,形似真实的自然裂隙。裂隙面的粗糙度参数和网格分辨率可以根据需要调整,以满足不同的应用场景。
五、扩展与应用
1. 三维裂隙面生成
将此方法扩展到三维数组,可以生成更加复杂的三维裂隙网络。
2. 工程领域应用
模拟裂隙对流体流动的影响,分析裂隙面在接触力学中的作用。
3. 性能优化
使用并行计算或 GPU 加速,可以快速生成高分辨率的裂隙面。
作者:挣扎的蓝藻