Python绘制闪电轨迹
本来想生成一个闪电轨迹的图像,思路是取两点,坐标塞进列表,计算距离,如果大于指定值就计算这两点的中点并旦在一定范围内偏移(范国与两点距离有关),然后把中点坐标赛回列表。循环执行直到列表中所有相邻点的距离小于指定值,然后遍历列表生成粒子。闪电轨迹本身就是有棱有角的,不能太平滑,也不能有奇怪的凸起。
写了个代码发现生成的不太像,倒像是一个国家的边境线了。
其中17 18行的代码是用来做随机偏移的,可以调整这4个参数以及35行的终止距离。
import matplotlib.pyplot as plt
import random
def generate_lightning(start_point, end_point, max_distance):
points =
while True:
all_within_max_distance = True
new_points = []
for i in range(len(points) - 1):
p1 = points
p2 = points
distance = ((p2 - p1) ** 2 + (p2 - p1) ** 2) ** 0.5
if distance > max_distance:
all_within_max_distance = False
midpoint = ((p1 + p2) / 2, (p1 + p2) / 2)
offset_x = random.uniform(-distance / 12, distance / 4)
offset_y = random.uniform(-distance / 6, distance / 6)
new_midpoint = (midpoint + offset_x, midpoint + offset_y)
new_points.extend()
else:
new_points.append(p1)
new_points.append(points[-1])
points = new_points
if all_within_max_distance:
break
return points
# 设置起始点和终点坐标以及最大距离
start_point = (0, 0)
end_point = (100, 100)
max_distance = 8
# 生成闪电轨迹的点列表
lightning_points = generate_lightning(start_point, end_point, max_distance)
# 绘制闪电
x_coords, y_coords = zip(*lightning_points)
plt.plot(x_coords, y_coords, 'b-')
# 设置图形的坐标轴范围等
plt.xlim(min(x_coords) - 1, max(x_coords) + 1)
plt.ylim(min(y_coords) - 1, max(y_coords) + 1)
# 显示图形
plt.show() import matplotlib.pyplot as plt
import random
def generate_lightning(start_point, end_point, max_distance):
points =
while True:
all_within_max_distance = True
new_points = []
for i in range(len(points) - 1):
p1 = points
p2 = points
# 修正距离计算公式
distance = ((p2 - p1) ** 2 + (p2 - p1) ** 2) ** 0.5
if distance > max_distance:
all_within_max_distance = False
midpoint = ((p1 + p2) / 2, (p1 + p2) / 2)
offset_x = random.uniform(-distance / 5, distance / 5)
offset_y = random.uniform(-distance / 5, distance / 5)
new_midpoint = (midpoint + offset_x, midpoint + offset_y)
new_points.extend()
else:
new_points.append(p1)
new_points.append(points[-1])
points = new_points
if all_within_max_distance:
break
return points
def add_forks(main_points, max_distance, num_forks, depth=1):
fork_list = []
for _ in range(num_forks):
# 随机选择一个主闪电上的点作为分叉的起点
point_on_main = random.choice(main_points)
# 随机生成一个偏移的分叉终点
x_offset = random.uniform(-20, 20)
y_offset = random.uniform(-20, 20)
fork_end_point = (point_on_main + x_offset, point_on_main + y_offset)
# 生成分叉闪电
fork_points = generate_lightning(point_on_main, fork_end_point, max_distance)
fork_list.append(fork_points)
# 如果需要递归生成次级分叉
if depth > 1:
sub_forks = add_forks(fork_points, max_distance, random.randint(1, 2), depth - 1)
fork_list.extend(sub_forks)
return fork_list
# 设置起始点和终点坐标以及最大距离
start_point = (50, 100)
end_point = (50, 0)
max_distance = 2
# 生成主闪电轨迹
main_lightning = generate_lightning(start_point, end_point, max_distance)
# 生成分叉
num_forks = 4# 分叉数量
fork_depth = 2# 分叉层级
forks = add_forks(main_lightning, max_distance, num_forks, fork_depth)
# 绘制闪电
plt.figure(figsize=(8, 12))
plt.style.use('dark_background')# 设置黑色背景
# 绘制主闪电
x_main, y_main = zip(*main_lightning)
plt.plot(x_main, y_main, color='black', linewidth=1.5, alpha=0.9, label="Main Lightning")
# 绘制分叉
for fork in forks:
x_fork, y_fork = zip(*fork)
plt.plot(x_fork, y_fork, color='black', linewidth=1, alpha=0.6)
# 动态调整坐标范围
x_all = for p in main_lightning] + for fork in forks for p in fork]
y_all = for p in main_lightning] + for fork in forks for p in fork]
plt.xlim(min(x_all) - 10, max(x_all) + 10)
plt.ylim(min(y_all) - 10, max(y_all) + 10)
# 设置图形
plt.axis('off')# 关闭坐标轴显示
plt.legend()
plt.show(block=True)# 强制显示图形
用ai优化了一下,更像了
import matplotlib.pyplot as plt
import random
import numpy as np
def generate_lightning(start_point, end_point, max_distance):
points =
while True:
all_within_max_distance = True
new_points = []
for i in range(len(points) - 1):
p1 = points
p2 = points
distance = ((p2 - p1) ** 2 + (p2 - p1) ** 2) ** 0.5
if distance > max_distance:
all_within_max_distance = False
midpoint = ((p1 + p2) / 2, (p1 + p2) / 2)
offset_x = random.uniform(-distance / 5, distance / 5)
offset_y = random.uniform(-distance / 5, distance / 5)
new_midpoint = (midpoint + offset_x, midpoint + offset_y)
new_points.extend()
else:
new_points.append(p1)
new_points.append(points[-1])
points = new_points
if all_within_max_distance:
break
return points
def add_forks(main_points, max_distance, num_forks, depth=1):
fork_list = []
for _ in range(num_forks):
point_on_main = random.choice(main_points)
x_offset = random.uniform(-20, 20)
y_offset = random.uniform(-20, 20)
fork_end_point = (point_on_main + x_offset, point_on_main + y_offset)
fork_points = generate_lightning(point_on_main, fork_end_point, max_distance)
fork_list.append(fork_points)
if depth > 1:
sub_forks = add_forks(fork_points, max_distance, random.randint(1, 2), depth - 1)
fork_list.extend(sub_forks)
return fork_list
# 设置起始点和终点坐标以及最大距离
start_point = (50, 100)
end_point = (50, 0)
max_distance = 2
# 生成主闪电轨迹
main_lightning = generate_lightning(start_point, end_point, max_distance)
# 生成分叉
num_forks = 4
fork_depth = 2
forks = add_forks(main_lightning, max_distance, num_forks, fork_depth)
# 绘制闪电
plt.figure(figsize=(8, 12))
plt.style.use('dark_background')
# 计算主闪电的线宽变化
n_points = len(main_lightning)
linewidths_main = np.linspace(3, 0.5, n_points - 1)
# 绘制主闪电
for i in range(n_points - 1):
x_main = , main_lightning]
y_main = , main_lightning]
plt.plot(x_main, y_main, color='blue', linewidth=linewidths_main, alpha=0.9)
# 计算分叉的线宽变化
for fork in forks:
n_fork_points = len(fork)
linewidths_fork = np.linspace(1.5, 0.3, n_fork_points - 1)
for i in range(n_fork_points - 1):
x_fork = , fork]
y_fork = , fork]
plt.plot(x_fork, y_fork, color='blue', linewidth=linewidths_fork, alpha=0.6)
# 动态调整坐标范围
x_all = for p in main_lightning] + for fork in forks for p in fork]
y_all = for p in main_lightning] + for fork in forks for p in fork]
plt.xlim(min(x_all) - 10, max(x_all) + 10)
plt.ylim(min(y_all) - 10, max(y_all) + 10)
plt.axis('off')
plt.legend()
plt.show(block=True)
本帖最后由 vincent327 于 2024-11-19 15:04 编辑
哈哈哈 挺好玩的 用你的代码 然后让Cursor使用composer润色了下 成这样了!
import matplotlib.pyplot as plt
import random
import numpy as np
from matplotlib.colors import LinearSegmentedColormap
def generate_lightning(start_point, end_point, max_distance):
"""
生成闪电的主要路径
参数:
start_point: 起始点坐标 (x, y)
end_point: 终点坐标 (x, y)
max_distance: 两点之间的最大允许距离
返回:
points: 闪电路径的所有点坐标列表
"""
points =
while True:
all_within_max_distance = True
new_points = []
for i in range(len(points) - 1):
p1 = points
p2 = points
# 计算两点之间的距离
distance = ((p2 - p1) ** 2 + (p2 - p1) ** 2) ** 0.5
if distance > max_distance:
all_within_max_distance = False
# 计算中点
midpoint = ((p1 + p2) / 2, (p1 + p2) / 2)
# 添加随机偏移,使闪电更自然
offset_x = random.uniform(-distance / 4, distance / 4)
offset_y = random.uniform(-distance / 4, distance / 4)
new_midpoint = (midpoint + offset_x, midpoint + offset_y)
new_points.extend()
else:
new_points.append(p1)
new_points.append(points[-1])
points = new_points
if all_within_max_distance:
break
return points
def add_forks(main_points, max_distance, num_forks, depth=1):
"""
为主闪电添加分叉
参数:
main_points: 主闪电路径的点列表
max_distance: 两点之间的最大允许距离
num_forks: 分叉数量
depth: 递归深度,控制子分叉的生成
返回:
fork_list: 所有分叉的点坐标列表
"""
fork_list = []
for _ in range(num_forks):
# 选择主干上的点作为分叉起点(避开起始部分)
available_points = main_points
point_on_main = random.choice(available_points)
# 生成分叉的终点
x_offset = random.uniform(-15, 15)
y_offset = random.uniform(-15, 0)# 只向下分叉
fork_end_point = (point_on_main + x_offset, point_on_main + y_offset)
# 生成分叉路径
fork_points = generate_lightning(point_on_main, fork_end_point, max_distance)
fork_list.append(fork_points)
# 递归生成子分叉
if depth > 1:
sub_forks = add_forks(fork_points, max_distance, random.randint(1, 1), depth - 1)
fork_list.extend(sub_forks)
return fork_list
# 定义闪电的颜色渐变
colors = [(0.1, 0.1, 0.3), (0.4, 0.4, 1), (0.7, 0.7, 1), (1, 1, 1)]
n_bins = 100
cmap = LinearSegmentedColormap.from_list('custom_lightning', colors, N=n_bins)
# 设置闪电的基本参数
start_point = (0, 150)# 起始点
end_point = (0, 0) # 终点
max_distance = 2 # 最大分段距离
# 生成主闪电路径
main_lightning = generate_lightning(start_point, end_point, max_distance)
# 设置分叉参数并生成分叉
num_forks = 4 # 分叉数量
fork_depth = 2 # 分叉深度
forks = add_forks(main_lightning, max_distance, num_forks, fork_depth)
# 创建图形
plt.figure(figsize=(10, 15))
plt.style.use('dark_background')# 使用深色背景
# 创建背景渐变效果
x = np.linspace(-50, 50, 100)
y = np.linspace(-10, 160, 170)
X, Y = np.meshgrid(x, y)
Z = np.exp(-(X**2 + (Y-80)**2)/3000)# 创建光晕效果
plt.imshow(Z, extent=[-50, 50, -10, 160], cmap='gray', alpha=0.3)
def plot_with_glow(x, y, color, linewidth, alpha):
"""
绘制带发光效果的线条
参数:
x, y: 线条的坐标
color: 线条颜色
linewidth: 线条宽度
alpha: 透明度
"""
for glow_width, glow_alpha in [(linewidth*3, 0.1), (linewidth*2, 0.2), (linewidth, alpha)]:
plt.plot(x, y, color=color, linewidth=glow_width, alpha=glow_alpha)
# 绘制主闪电
n_points = len(main_lightning)
linewidths_main = np.linspace(4, 1, n_points - 1)# 渐变的线条宽度
for i in range(n_points - 1):
x_main = , main_lightning]
y_main = , main_lightning]
color = cmap(random.uniform(0.7, 1.0))# 随机选择颜色
plot_with_glow(x_main, y_main, color, linewidths_main, 0.9)
# 绘制分叉
for fork in forks:
n_fork_points = len(fork)
linewidths_fork = np.linspace(2, 0.5, n_fork_points - 1)# 分叉的线条宽度
for i in range(n_fork_points - 1):
x_fork = , fork]
y_fork = , fork]
color = cmap(random.uniform(0.5, 0.9))# 随机选择颜色
plot_with_glow(x_fork, y_fork, color, linewidths_fork, 0.7)
# 调整显示范围
x_all = for p in main_lightning] + for fork in forks for p in fork]
y_all = for p in main_lightning] + for fork in forks for p in fork]
margin = 20
plt.xlim(min(x_all) - margin, max(x_all) + margin)
plt.ylim(min(y_all) - margin, max(y_all) + margin)
# 关闭坐标轴显示
plt.axis('off')
# 显示图形
plt.show() 太酷了,弄了个闪电出来 上传个图,看看效果 go4399 发表于 2024-11-16 16:43
上传个图,看看效果
试试效果
没安装库的先安装:
python -m pip install matplotlib-i https://mirrors.aliyun.com/pypi/simple/
运行效果大概就是这样,实际原理就是简单的生成一段随机路径模仿闪电轨迹;楼主可以精进一点,比如闪电加上分支,颜色等 Open74 发表于 2024-11-16 18:01
运行效果大概就是这样,实际原理就是简单的生成一段随机路径模仿闪电轨迹;楼主可以精进一点,比如闪电加上 ...
要做成一个动态图,让轨迹从上往下快速形成才能模拟出闪电。最好再加上雨天背景图和雷声音频。 hjxhjxjx 发表于 2024-11-16 17:58
试试效果
没安装库的先安装:
python -m pip install matplotlib-i https:// ...
我觉得这个轨迹还是有点奇怪,要再调参数 Open74 发表于 2024-11-16 18:01
运行效果大概就是这样,实际原理就是简单的生成一段随机路径模仿闪电轨迹;楼主可以精进一点,比如闪电加上 ...
分支的话在生成的轨迹上取一点,在空白的地方取一点再用一下写好的函数生成一条轨迹就行了 mebyan 发表于 2024-11-16 18:27
要做成一个动态图,让轨迹从上往下快速形成才能模拟出闪电。最好再加上雨天背景图和雷声音频。
我只是在研究模拟出合理的轨迹图不是闪电的过程 向你学习!