icer233 发表于 2024-11-16 15:45

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()

lyzxx 发表于 2024-11-16 23:34

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)# 强制显示图形

LiCan857 发表于 2024-11-19 09:14

用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:01

本帖最后由 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()

Wisdom_xiaogui 发表于 2024-11-16 16:38

太酷了,弄了个闪电出来

go4399 发表于 2024-11-16 16:43

上传个图,看看效果

hjxhjxjx 发表于 2024-11-16 17:58

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

试试效果
没安装库的先安装:
python -m pip install matplotlib-i https://mirrors.aliyun.com/pypi/simple/

Open74 发表于 2024-11-16 18:01

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

mebyan 发表于 2024-11-16 18:27

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

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

icer233 发表于 2024-11-16 18:32

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

我觉得这个轨迹还是有点奇怪,要再调参数

icer233 发表于 2024-11-16 18:38

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

分支的话在生成的轨迹上取一点,在空白的地方取一点再用一下写好的函数生成一条轨迹就行了

icer233 发表于 2024-11-16 18:39

mebyan 发表于 2024-11-16 18:27
要做成一个动态图,让轨迹从上往下快速形成才能模拟出闪电。最好再加上雨天背景图和雷声音频。

我只是在研究模拟出合理的轨迹图不是闪电的过程

ruanxiaoqi 发表于 2024-11-16 19:34

向你学习!
页: [1] 2 3 4 5
查看完整版本: Python绘制闪电轨迹