feat: 添加 EGM 计算动画可视化功能

在 web 界面中实现 EGM 计算过程的动画展示,包括地线保护弧、导线暴露弧和地面线的动态绘制。重构 main.py 以支持可选的动画参数传递,并新增 Animation.vue 组件和 WebAnimation 类实现前后端交互。
This commit is contained in:
dmy
2026-03-03 15:58:57 +08:00
parent cee451914a
commit a65ce23cee
5 changed files with 409 additions and 18 deletions

36
main.py
View File

@@ -6,7 +6,6 @@ import tomli
from loguru import logger
from core import *
import timeit
from animation import Animation
# 打印参数
@@ -62,11 +61,12 @@ def read_parameter(toml_file_path) -> Parameter:
return para
def run_egm(para: Parameter) -> dict:
def run_egm(para: Parameter, animation=None) -> dict:
"""
执行 EGM 计算的核心函数,可被外部调用。
Args:
para: 参数对象,包含所有计算所需的参数。
animation: 可选的动画对象,用于可视化。需要实现 add_rs, add_rc, add_rg_line, add_expose_area, pause 方法。
Returns:
计算结果字典。
"""
@@ -104,9 +104,10 @@ def run_egm(para: Parameter) -> dict:
ng = func_ng(td, para.ng)
avr_n_sf = 0 # 考虑电压的影响计算的跳闸率
ground_angels = para.ground_angels
# 初始化动画
animate = Animation()
animate.enable(False)
# 动画对象:如果传入了 animation 则使用,否则不启用动画
animate = animation
if animate:
animate.enable(True) # 启用动画
# animate.show()
for ground_angel in ground_angels:
logger.info(f"地面倾角{ground_angel/math.pi*180:.3f}°")
@@ -179,14 +180,17 @@ def run_egm(para: Parameter) -> dict:
): # 雷电流
logger.info(f"尝试计算电流为{i_bar:.2f}")
rs = rs_fun(i_bar)
animate.add_rs(rs, rs_x, rs_y)
if animate:
animate.add_rs(rs, rs_x, rs_y)
rc = rc_fun(i_bar, u_ph)
animate.add_rc(rc, rc_x, rc_y)
if animate:
animate.add_rc(rc, rc_x, rc_y)
rg = rg_fun(i_bar, rc_y, u_ph, typ=rg_type)
rg_line_func = None
if rg_type == "g":
rg_line_func = rg_line_function_factory(rg, ground_angel)
animate.add_rg_line(rg_line_func)
if animate:
animate.add_rg_line(rg_line_func)
rs_rc_circle_intersection = solve_circle_intersection(
rs, rc, rs_x, rs_y, rc_x, rc_y
)
@@ -219,12 +223,13 @@ def run_egm(para: Parameter) -> dict:
"上面的导地线无法保护下面的导地线,检查设置参数。"
)
continue
animate.add_expose_area(
rc_x,
rc_y,
*rs_rc_circle_intersection,
*circle_rc_or_rg_line_intersection,
)
if animate:
animate.add_expose_area(
rc_x,
rc_y,
*rs_rc_circle_intersection,
*circle_rc_or_rg_line_intersection,
)
cad = Draw()
cad.draw(
i_min,
@@ -298,7 +303,8 @@ def run_egm(para: Parameter) -> dict:
logger.info(f"电流为{i_bar}kA时暴露弧已经完全被屏蔽")
exposed_curve_shielded = True
break
animate.pause()
if animate:
animate.pause()
# 判断是否导线已经被完全保护
if abs(i_max - _max_i) < 1e-5:
logger.info("无法找到最大电流,可能是杆塔较高。")