feat: 添加 EGM 计算动画可视化功能
在 web 界面中实现 EGM 计算过程的动画展示,包括地线保护弧、导线暴露弧和地面线的动态绘制。重构 main.py 以支持可选的动画参数传递,并新增 Animation.vue 组件和 WebAnimation 类实现前后端交互。
This commit is contained in:
126
webview_app.py
126
webview_app.py
@@ -23,6 +23,126 @@ from core import Parameter
|
||||
from main import parameter_display, run_egm
|
||||
|
||||
|
||||
class WebAnimation:
|
||||
"""
|
||||
Web 动画类,将 Python 端的 Animation 调用映射到前端 JavaScript
|
||||
对应 Animation.vue 的功能
|
||||
"""
|
||||
|
||||
def __init__(self, window=None):
|
||||
self._window = window
|
||||
self._disable = True # 默认禁用
|
||||
|
||||
def set_window(self, window):
|
||||
"""设置窗口对象"""
|
||||
self._window = window
|
||||
|
||||
def enable(self, enabled: bool):
|
||||
"""
|
||||
启用/禁用动画
|
||||
对应 animation.py 的 enable 方法和 Animation.vue 的 enable 方法
|
||||
"""
|
||||
self._disable = not enabled
|
||||
if self._window:
|
||||
js_code = f'if(window.animationApi){{window.animationApi.enable({str(enabled).lower()})}}'
|
||||
self._window.evaluate_js(js_code)
|
||||
|
||||
def init_fig(self):
|
||||
"""初始化画布"""
|
||||
if self._disable or not self._window:
|
||||
return
|
||||
js_code = 'if(window.animationApi){window.animationApi.initFig()}'
|
||||
self._window.evaluate_js(js_code)
|
||||
|
||||
def add_rs(self, rs: float, rs_x: float, rs_y: float):
|
||||
"""
|
||||
添加地线保护弧(RS 圆)
|
||||
对应 animation.py 的 add_rs 方法
|
||||
"""
|
||||
if self._disable or not self._window:
|
||||
return
|
||||
js_code = f'if(window.animationApi){{window.animationApi.addRs({rs}, {rs_x}, {rs_y})}}'
|
||||
self._window.evaluate_js(js_code)
|
||||
|
||||
def add_rc(self, rc: float, rc_x: float, rc_y: float):
|
||||
"""
|
||||
添加导线暴露弧(RC 圆)
|
||||
对应 animation.py 的 add_rc 方法
|
||||
"""
|
||||
if self._disable or not self._window:
|
||||
return
|
||||
js_code = f'if(window.animationApi){{window.animationApi.addRc({rc}, {rc_x}, {rc_y})}}'
|
||||
self._window.evaluate_js(js_code)
|
||||
|
||||
def add_rg_line(self, line_func):
|
||||
"""
|
||||
添加地面线(RG 线)
|
||||
对应 animation.py 的 add_rg_line 方法
|
||||
|
||||
Args:
|
||||
line_func: 一个函数,接收 x 返回 y
|
||||
"""
|
||||
if self._disable or not self._window:
|
||||
return
|
||||
# 生成线上的点,传递给前端
|
||||
# 由于无法直接传递函数,我们预先计算一些点
|
||||
import numpy as np
|
||||
x_points = np.linspace(0, 300, 50)
|
||||
y_points = [line_func(x) for x in x_points]
|
||||
points = list(zip(x_points.tolist(), y_points))
|
||||
|
||||
js_code = f'''
|
||||
if(window.animationApi){{
|
||||
window.animationApi.addRgLine({json.dumps(points)})
|
||||
}}
|
||||
'''
|
||||
self._window.evaluate_js(js_code)
|
||||
|
||||
def add_expose_area(
|
||||
self,
|
||||
rc_x: float,
|
||||
rc_y: float,
|
||||
intersection_x1: float,
|
||||
intersection_y1: float,
|
||||
intersection_x2: float,
|
||||
intersection_y2: float
|
||||
):
|
||||
"""
|
||||
添加暴露弧区域(两条红线)
|
||||
对应 animation.py 的 add_expose_area 方法
|
||||
"""
|
||||
if self._disable or not self._window:
|
||||
return
|
||||
js_code = f'''if(window.animationApi){{
|
||||
window.animationApi.addExposeArea(
|
||||
{rc_x}, {rc_y},
|
||||
{intersection_x1}, {intersection_y1},
|
||||
{intersection_x2}, {intersection_y2}
|
||||
)
|
||||
}}'''
|
||||
self._window.evaluate_js(js_code)
|
||||
|
||||
def clear(self):
|
||||
"""清除画布"""
|
||||
if self._disable or not self._window:
|
||||
return
|
||||
js_code = 'if(window.animationApi){window.animationApi.clear()}'
|
||||
self._window.evaluate_js(js_code)
|
||||
|
||||
def pause(self):
|
||||
"""
|
||||
暂停并刷新
|
||||
对应 animation.py 的 pause 方法
|
||||
"""
|
||||
if self._disable or not self._window:
|
||||
return
|
||||
js_code = 'if(window.animationApi){window.animationApi.pause()}'
|
||||
self._window.evaluate_js(js_code)
|
||||
# 添加延迟以便动画可见
|
||||
import time
|
||||
time.sleep(0.1) # 增加延迟,让用户看清动画
|
||||
|
||||
|
||||
class WebHandler:
|
||||
"""Web日志处理器"""
|
||||
def __init__(self, callback=None):
|
||||
@@ -86,6 +206,7 @@ class EGMWebApp:
|
||||
self._loguru_handler_id = None
|
||||
self._log_queue: queue.Queue = queue.Queue()
|
||||
self._running = False
|
||||
self.animation = WebAnimation() # Web 动画实例
|
||||
|
||||
def _process_log_queue(self):
|
||||
"""处理日志队列,在主线程中定时调用"""
|
||||
@@ -220,8 +341,8 @@ class EGMWebApp:
|
||||
|
||||
logger.info("开始执行 EGM 计算...")
|
||||
|
||||
# 调用 main.py 的核心计算函数
|
||||
result = run_egm(para)
|
||||
# 调用 main.py 的核心计算函数,传递 animation 对象
|
||||
result = run_egm(para, self.animation)
|
||||
|
||||
self.add_log("info", "EGM 计算完成")
|
||||
|
||||
@@ -467,6 +588,7 @@ def start_webview():
|
||||
|
||||
# 将窗口对象传递给 API
|
||||
api.window = window
|
||||
api.animation.set_window(window)
|
||||
|
||||
# 启动
|
||||
logger.info("启动 EGM Web 界面...")
|
||||
|
||||
Reference in New Issue
Block a user