Skip to content

Commit 1da4d20

Browse files
committed
add Redo
1 parent 176b9a7 commit 1da4d20

11 files changed

+390
-250
lines changed

.gitignore

+4-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
1-
/__pycache__
1+
/__pycache__
2+
/build
3+
/*.egg-info
4+
/pyfmm-gui/__pycache__

README.md

+25-4
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,38 @@
77

88
## 安装
99

10-
1、安装[PyFMM](https://github.com/Dengda98/PyFMM).
10+
1、安装[***PyFMM***](https://github.com/Dengda98/PyFMM).
1111

1212
2、安装PyQt5
1313
```bash
1414
conda install pyqt -c conda-forge
1515
```
1616

17-
3、
17+
3、安装本程序
18+
有两个选择:
19+
+ **不提前下载程序包**
20+
21+
要求你当前环境中有git工具。这样可直接运行
22+
```bash
23+
# vx.x.x指代Release中的版本号,建议下载最新稳定版本
24+
pip install -v git+https://github.com/Dengda98/[email protected]
25+
```
26+
27+
28+
+ **提前下载好程序包**
29+
30+
**建议在[Release](https://github.com/Dengda98/PyFMM-GUI/releases)中下载最新稳定版本**,不推荐clone,不推荐直接下载主分支。在下载解压后,在程序根目录下运行
31+
```bash
32+
pip install -v .
33+
```
34+
35+
这样可安装到你的虚拟环境中。
36+
1837

1938
## 使用
2039

2140
```bash
22-
python pyfmm-gui.py
23-
```
41+
python -m pyfmm-gui.main
42+
```
43+
44+
功能按钮很简单,基本“所见即所得”。其中`Update Velocity`下的文本框是个Python脚本窗口,可以自定义FMM网格范围(`xmax, ymax`,最小值均为0)、划分数(`nx, ny`),以及2D速度数组`vel2d`。设置好后,点击`Update Velocity`即可计算。

pyfmm-gui/__init__.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
from ._version import __version__

pyfmm-gui/_version.py

+1
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
__version__ = "0.1"

pyfmm-gui/main.py

+136
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,136 @@
1+
"""
2+
:file: main.py
3+
:author: Zhu Dengda ([email protected])
4+
:date: 2024-11
5+
6+
PyFMM二维模型下的交互界面,基于PyQt5开发
7+
8+
"""
9+
10+
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QWidget
11+
from PyQt5 import QtCore, QtGui, QtWidgets
12+
from PyQt5 import uic
13+
import matplotlib as mpl
14+
from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas
15+
import matplotlib.pyplot as plt
16+
import numpy as np
17+
import os, sys
18+
from scipy.ndimage import gaussian_filter
19+
20+
from .subwidget import MatplotlibWidget
21+
from .utils import try_except_decorator
22+
23+
24+
class MainWindow(QMainWindow):
25+
def __init__(self):
26+
super().__init__()
27+
uic.loadUi(os.path.join(os.path.dirname(__file__), "main.ui"), self) # 加载 UI 文件
28+
29+
30+
self.mplwidget = MatplotlibWidget(self)
31+
32+
self.mplwidget.canvas.setCursor(QtGui.QCursor(QtCore.Qt.CrossCursor))
33+
self.mplwidget.canvas.setMouseTracking(True)
34+
# 将 Canvas 嵌入到 layout 中
35+
self.verticalLayout_mpl.addWidget(self.mplwidget.canvas)
36+
37+
# 绑定更新按钮
38+
self.updateSrcLocButton.clicked.connect(self.update_plot)
39+
self.clearRcvButton.clicked.connect(self.clear_rcv)
40+
self.updateVelButton.clicked.connect(self.update_velocity)
41+
self.redoButton.clicked.connect(self.redo_rcv)
42+
43+
# 定义参数
44+
self.plot_param = {}
45+
self.update_srcloc()
46+
self.clear_rcv()
47+
48+
self.update_velocity()
49+
50+
def update_srcloc(self):
51+
self.plot_param['srcloc'] = [float(self.lineEdit_srcX.text()), float(self.lineEdit_srcY.text())]
52+
53+
def clear_rcv(self):
54+
self.textBrowser_rcv.clear()
55+
self.textBrowser_rcv.append(f"{'X':>8s} {'Y':>8s} {'T':>6s}")
56+
for _ in range(len(self.mplwidget.plot_handle['rays'])):
57+
h = self.mplwidget.plot_handle['rays'].pop()
58+
h.remove()
59+
h = self.mplwidget.plot_handle['rcvdots'].pop()
60+
h.remove()
61+
62+
self.mplwidget.canvas_redraw()
63+
64+
def redo_rcv(self):
65+
self.delete_textBrowser_rcv_last_line()
66+
if len(self.mplwidget.plot_handle['rays']) == 0:
67+
return
68+
69+
h = self.mplwidget.plot_handle['rays'].pop()
70+
h.remove()
71+
h = self.mplwidget.plot_handle['rcvdots'].pop()
72+
h.remove()
73+
self.mplwidget.canvas_redraw()
74+
75+
def delete_textBrowser_rcv_last_line(self):
76+
# 获取当前文本内容
77+
content = self.textBrowser_rcv.toPlainText()
78+
79+
# 按行分割文本
80+
lines = content.split('\n')
81+
82+
# 删除最后一行,保留X,Y,T,如果有内容的话
83+
if len(lines) > 1:
84+
lines.pop()
85+
86+
# 更新 QTextBrowser 内容
87+
# self.textBrowser_rcv.setPlainText('\n'.join(lines))
88+
self.textBrowser_rcv.setPlainText("")
89+
for line in lines:
90+
self.textBrowser_rcv.append(line)
91+
92+
@try_except_decorator("statusBar")
93+
def update_velocity(self, *args):
94+
namespace = {"np":np}
95+
exec(self.textEdit_vel.toPlainText(), namespace)
96+
97+
self.plot_param['xarr'] = np.linspace(0, namespace['xmax'], namespace['nx']).copy()
98+
self.plot_param['yarr'] = np.linspace(0, namespace['ymax'], namespace['ny']).copy()
99+
vel2d = namespace['vel2d'].copy()
100+
vel2d[vel2d < 0.0] = 0.1
101+
102+
self.plot_param['vel2d'] = vel2d
103+
104+
self.clear_rcv()
105+
self.mplwidget.plot_velocity(self.plot_param['xarr'], self.plot_param['yarr'], self.plot_param['vel2d'])
106+
self.update_plot()
107+
108+
def update_plot(self):
109+
# 读入参数
110+
self.update_srcloc()
111+
112+
self.clear_rcv()
113+
114+
# 衡量范围
115+
if self.plot_param['srcloc'][0] > self.plot_param['xarr'][-1] or \
116+
self.plot_param['srcloc'][0] < self.plot_param['xarr'][0] or \
117+
self.plot_param['srcloc'][1] > self.plot_param['yarr'][-1] or \
118+
self.plot_param['srcloc'][1] < self.plot_param['yarr'][0]:
119+
120+
self.statusBar().showMessage(f"source location out of bound!", 3000)
121+
return
122+
123+
self.statusBar().showMessage(f"Fast Marcing ......")
124+
QApplication.processEvents() # 强制刷新事件循环
125+
# 调用 canvas 的 plot 方法刷新绘图
126+
self.mplwidget.plot(
127+
self.plot_param['srcloc'],
128+
self.plot_param['xarr'], self.plot_param['yarr'], self.plot_param['vel2d'])
129+
self.statusBar().showMessage(f"Done.", 1000)
130+
131+
132+
if __name__ == '__main__':
133+
app = QApplication(sys.argv)
134+
window = MainWindow()
135+
window.show()
136+
sys.exit(app.exec_())

main.ui renamed to pyfmm-gui/main.ui

+50-17
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,12 @@
2929
<property name="mouseTracking">
3030
<bool>false</bool>
3131
</property>
32-
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="2,6">
32+
<layout class="QVBoxLayout" name="verticalLayout_4" stretch="2,7">
33+
<property name="bottomMargin">
34+
<number>0</number>
35+
</property>
3336
<item>
34-
<layout class="QHBoxLayout" name="horizontalLayout" stretch="3,12,3">
37+
<layout class="QHBoxLayout" name="horizontalLayout_2" stretch="2,11,3">
3538
<item>
3639
<layout class="QVBoxLayout" name="verticalLayout" stretch="1,3">
3740
<property name="bottomMargin">
@@ -178,6 +181,7 @@
178181
&lt;html&gt;&lt;head&gt;&lt;meta name=&quot;qrichtext&quot; content=&quot;1&quot; /&gt;&lt;style type=&quot;text/css&quot;&gt;
179182
p, li { white-space: pre-wrap; }
180183
&lt;/style&gt;&lt;/head&gt;&lt;body style=&quot; font-family:'Comic Sans MS'; font-size:12pt; font-weight:400; font-style:normal;&quot;&gt;
184+
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt;# define xmax, ymax, nx, ny, vel2d&lt;/span&gt;&lt;/p&gt;
181185
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt;from scipy.ndimage import gaussian_filter&lt;/span&gt;&lt;/p&gt;
182186
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt;xmax, nx = 100, 500&lt;/span&gt;&lt;/p&gt;
183187
&lt;p style=&quot; margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;&quot;&gt;&lt;span style=&quot; font-size:11pt;&quot;&gt;ymax, ny = 50, 250&lt;/span&gt;&lt;/p&gt;
@@ -191,23 +195,52 @@ p, li { white-space: pre-wrap; }
191195
<item>
192196
<layout class="QVBoxLayout" name="verticalLayout_2">
193197
<item>
194-
<widget class="QPushButton" name="clearRcvButton">
195-
<property name="sizePolicy">
196-
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
197-
<horstretch>0</horstretch>
198-
<verstretch>0</verstretch>
199-
</sizepolicy>
200-
</property>
201-
<property name="font">
202-
<font>
203-
<family>Times New Roman</family>
204-
<pointsize>13</pointsize>
205-
</font>
198+
<layout class="QHBoxLayout" name="horizontalLayout" stretch="6,2">
199+
<property name="spacing">
200+
<number>3</number>
206201
</property>
207-
<property name="text">
208-
<string>Clear Receivers</string>
202+
<property name="sizeConstraint">
203+
<enum>QLayout::SetNoConstraint</enum>
209204
</property>
210-
</widget>
205+
<item>
206+
<widget class="QPushButton" name="clearRcvButton">
207+
<property name="sizePolicy">
208+
<sizepolicy hsizetype="Ignored" vsizetype="Expanding">
209+
<horstretch>0</horstretch>
210+
<verstretch>0</verstretch>
211+
</sizepolicy>
212+
</property>
213+
<property name="font">
214+
<font>
215+
<family>Times New Roman</family>
216+
<pointsize>13</pointsize>
217+
</font>
218+
</property>
219+
<property name="text">
220+
<string>Clear Receivers</string>
221+
</property>
222+
</widget>
223+
</item>
224+
<item>
225+
<widget class="QPushButton" name="redoButton">
226+
<property name="sizePolicy">
227+
<sizepolicy hsizetype="Ignored" vsizetype="Expanding">
228+
<horstretch>0</horstretch>
229+
<verstretch>0</verstretch>
230+
</sizepolicy>
231+
</property>
232+
<property name="font">
233+
<font>
234+
<family>Times New Roman</family>
235+
<pointsize>13</pointsize>
236+
</font>
237+
</property>
238+
<property name="text">
239+
<string>Redo</string>
240+
</property>
241+
</widget>
242+
</item>
243+
</layout>
211244
</item>
212245
<item>
213246
<widget class="QTextBrowser" name="textBrowser_rcv"/>

0 commit comments

Comments
 (0)