Python绘制闪电轨迹

查看 92|回复 12
作者:icer233   
本来想生成一个闪电轨迹的图像,思路是取两点,坐标塞进列表,计算距离,如果大于指定值就计算这两点的中点并旦在一定范围内偏移(范国与两点距离有关),然后把中点坐标赛回列表。循环执行直到列表中所有相邻点的距离小于指定值,然后遍历列表生成粒子。
闪电轨迹本身就是有棱有角的,不能太平滑,也不能有奇怪的凸起。
写了个代码发现生成的不太像,倒像是一个国家的边境线了。
其中17 18行的代码是用来做随机偏移的,可以调整这4个参数以及35行的终止距离。
[Python] 纯文本查看 复制代码import matplotlib.pyplot as plt
import random
def generate_lightning(start_point, end_point, max_distance):
    points = [start_point, end_point]
    while True:
        all_within_max_distance = True
        new_points = []
        for i in range(len(points) - 1):
            p1 = points[i]
            p2 = points[i + 1]
            distance = ((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2) ** 0.5
            if distance > max_distance:
                all_within_max_distance = False
                midpoint = ((p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2)
                offset_x = random.uniform(-distance / 12, distance / 4)
                offset_y = random.uniform(-distance / 6, distance / 6)
                new_midpoint = (midpoint[0] + offset_x, midpoint[1] + offset_y)
                new_points.extend([p1, new_midpoint])
            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()

闪电, 轨迹

lyzxx   

[Python] 纯文本查看 复制代码import matplotlib.pyplot as plt
import random
def generate_lightning(start_point, end_point, max_distance):
    points = [start_point, end_point]
    while True:
        all_within_max_distance = True
        new_points = []
        for i in range(len(points) - 1):
            p1 = points[i]
            p2 = points[i + 1]
            # 修正距离计算公式
            distance = ((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2) ** 0.5
            if distance > max_distance:
                all_within_max_distance = False
                midpoint = ((p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2)
                offset_x = random.uniform(-distance / 5, distance / 5)
                offset_y = random.uniform(-distance / 5, distance / 5)
                new_midpoint = (midpoint[0] + offset_x, midpoint[1] + offset_y)
                new_points.extend([p1, new_midpoint])
            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[0] + x_offset, point_on_main[1] + 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 = [p[0] for p in main_lightning] + [p[0] for fork in forks for p in fork]
y_all = [p[1] for p in main_lightning] + [p[1] 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)  # 强制显示图形
LiCan857   

用ai优化了一下,更像了
[Python] 纯文本查看 复制代码import matplotlib.pyplot as plt
import random
import numpy as np
def generate_lightning(start_point, end_point, max_distance):
    points = [start_point, end_point]
    while True:
        all_within_max_distance = True
        new_points = []
        for i in range(len(points) - 1):
            p1 = points[i]
            p2 = points[i + 1]
            distance = ((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2) ** 0.5
            if distance > max_distance:
                all_within_max_distance = False
                midpoint = ((p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2)
                offset_x = random.uniform(-distance / 5, distance / 5)
                offset_y = random.uniform(-distance / 5, distance / 5)
                new_midpoint = (midpoint[0] + offset_x, midpoint[1] + offset_y)
                new_points.extend([p1, new_midpoint])
            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[0] + x_offset, point_on_main[1] + 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[i][0], main_lightning[i + 1][0]]
    y_main = [main_lightning[i][1], main_lightning[i + 1][1]]
    plt.plot(x_main, y_main, color='blue', linewidth=linewidths_main[i], 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[i][0], fork[i + 1][0]]
        y_fork = [fork[i][1], fork[i + 1][1]]
        plt.plot(x_fork, y_fork, color='blue', linewidth=linewidths_fork[i], alpha=0.6)
# 动态调整坐标范围
x_all = [p[0] for p in main_lightning] + [p[0] for fork in forks for p in fork]
y_all = [p[1] for p in main_lightning] + [p[1] 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   

哈哈哈 挺好玩的 用你的代码 然后让Cursor使用composer润色了下 成这样了!
[Python] 纯文本查看 复制代码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 = [start_point, end_point]
    while True:
        all_within_max_distance = True
        new_points = []
        for i in range(len(points) - 1):
            p1 = points[i]
            p2 = points[i + 1]
            # 计算两点之间的距离
            distance = ((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2) ** 0.5
            if distance > max_distance:
                all_within_max_distance = False
                # 计算中点
                midpoint = ((p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2)
                # 添加随机偏移,使闪电更自然
                offset_x = random.uniform(-distance / 4, distance / 4)
                offset_y = random.uniform(-distance / 4, distance / 4)
                new_midpoint = (midpoint[0] + offset_x, midpoint[1] + offset_y)
                new_points.extend([p1, new_midpoint])
            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[len(main_points)//4:]
        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[0] + x_offset, point_on_main[1] + 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[i][0], main_lightning[i + 1][0]]
    y_main = [main_lightning[i][1], main_lightning[i + 1][1]]
    color = cmap(random.uniform(0.7, 1.0))  # 随机选择颜色
    plot_with_glow(x_main, y_main, color, linewidths_main[i], 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[i][0], fork[i + 1][0]]
        y_fork = [fork[i][1], fork[i + 1][1]]
        color = cmap(random.uniform(0.5, 0.9))  # 随机选择颜色
        plot_with_glow(x_fork, y_fork, color, linewidths_fork[i], 0.7)
# 调整显示范围
x_all = [p[0] for p in main_lightning] + [p[0] for fork in forks for p in fork]
y_all = [p[1] for p in main_lightning] + [p[1] 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()
Wisdom_xiaogui   

太酷了,弄了个闪电出来
go4399   

上传个图,看看效果
hjxhjxjx   


go4399 发表于 2024-11-16 16:43
上传个图,看看效果

试试效果


QQ截图20241116175645.jpg (35.89 KB, 下载次数: 0)
下载附件
2024-11-16 17:57 上传



QQ截图20241116175620.jpg (36.48 KB, 下载次数: 0)
下载附件
2024-11-16 17:57 上传

没安装库的先安装:
[Bash shell] 纯文本查看 复制代码python -m pip install matplotlib  -i https://mirrors.aliyun.com/pypi/simple/
Open74   

运行效果大概就是这样,实际原理就是简单的生成一段随机路径模仿闪电轨迹;楼主可以精进一点,比如闪电加上分支,颜色等
mebyan   


Open74 发表于 2024-11-16 18:01
运行效果大概就是这样,实际原理就是简单的生成一段随机路径模仿闪电轨迹;楼主可以精进一点,比如闪电加上 ...

要做成一个动态图,让轨迹从上往下快速形成才能模拟出闪电。最好再加上雨天背景图和雷声音频。
icer233
OP
  


hjxhjxjx 发表于 2024-11-16 17:58
试试效果
没安装库的先安装:
[mw_shl_code=bash,true]python -m pip install matplotlib  -i https:// ...

我觉得这个轨迹还是有点奇怪,要再调参数
您需要登录后才可以回帖 登录 | 立即注册

返回顶部