添加了3D线条显示效果

This commit is contained in:
2026-01-07 18:11:27 +08:00
parent cc4bdbb965
commit bbfcd63503
5 changed files with 261 additions and 55 deletions

View File

@ -2,7 +2,7 @@
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="jdk" jdkName="damiao" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="PyDocumentationSettings">

View File

@ -14,6 +14,7 @@ from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
QTableWidget, QTableWidgetItem)
from PySide6.QtCore import QTimer, Qt, Signal, Slot
from PySide6.QtGui import (QFont, QPalette, QColor)
from ui_3d import Target3DWidgetA, Target3DWidgetB
class LengthMotorController(QMainWindow):
@ -166,7 +167,7 @@ class LengthMotorController(QMainWindow):
self.table_line_a.setItem(row, 2, QTableWidgetItem(str(params[1])))
self.table_line_a.setItem(row, 3, QTableWidgetItem(str(params[2])))
self.table_line_a.setItem(row, 4, QTableWidgetItem(str(params[3])))
self.table_line_a.setFixedHeight(220)
self.table_line_a.setFixedHeight(280)
self.table_line_a.setEditTriggers(QTableWidget.NoEditTriggers)
self.table_line_a.setSelectionBehavior(QTableWidget.SelectRows)
self.table_line_a.selectRow(0)
@ -185,7 +186,7 @@ class LengthMotorController(QMainWindow):
self.table_line_b.setItem(row, 2, QTableWidgetItem(str(params[1])))
self.table_line_b.setItem(row, 3, QTableWidgetItem(str(params[2])))
self.table_line_b.setItem(row, 4, QTableWidgetItem(str(params[3])))
self.table_line_b.setFixedHeight(220)
self.table_line_b.setFixedHeight(260)
self.table_line_b.setEditTriggers(QTableWidget.NoEditTriggers)
self.table_line_b.setSelectionBehavior(QTableWidget.SelectRows)
self.table_line_b.selectRow(0)
@ -384,26 +385,21 @@ class LengthMotorController(QMainWindow):
def _create_3d_placeholder(self, parent_layout):
"""3D效果显示占位区缩小留白"""
display_group = QGroupBox("线条3D效果显示(后续接口)")
display_group = QGroupBox("线条3D效果显示")
display_group.setFont(self.font1)
display_layout = QVBoxLayout(display_group)
display_layout.setContentsMargins(20, 20, 20, 20)
placeholder_text = QTextEdit()
placeholder_text.setReadOnly(True)
placeholder_text.setMaximumHeight(180) # 进一步缩小高度
placeholder_text.setText("""3D接口说明
1. 后续集成3D模块如Qt3DExtras
2. 参数a→半径参数b→长度参数c/d→颜色
3. 保存参数触发record_data_signal更新3D""")
placeholder_text.setFont(QFont("Microsoft YaHei", 10))
# 实例化ui_3d.py中的Target3DWidget
self.ui_3d_widget = Target3DWidgetA() # 创建3D绘图控件实例
self.ui_3d_widget.setMaximumSize(500, 330)
test_btn = QPushButton("测试参数传递")
test_btn.setFont(self.font2)
test_btn.setFixedWidth(150)
test_btn.clicked.connect(self._test_3d_param_pass)
display_layout.addWidget(placeholder_text)
display_layout.addWidget(self.ui_3d_widget)
display_layout.addWidget(test_btn, alignment=Qt.AlignCenter)
parent_layout.addWidget(display_group)

View File

@ -11,9 +11,10 @@ import time
from PySide6.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
QHBoxLayout, QLabel, QPushButton,
QGroupBox, QMessageBox, QComboBox, QTextEdit,
QTableWidget, QTableWidgetItem) # 新增表格组件
QTableWidget, QTableWidgetItem)
from PySide6.QtCore import QTimer, Qt, Signal, Slot
from PySide6.QtGui import (QFont, QPalette, QColor)
from ui_3d import Target3DWidgetA, Target3DWidgetB
class LengthMotorController(QMainWindow):
@ -27,9 +28,8 @@ class LengthMotorController(QMainWindow):
self.setWindowTitle("线条长度标记与电机位置控制系统")
self.setMinimumSize(1200, 700)
self.font1 = QFont("Microsoft YaHei", 12)
self.font1 = QFont("Microsoft YaHei", 14)
self.font2 = QFont("Microsoft YaHei", 12)
self.recorded_data = []
# 线条A参数
self.line_a_params = {
@ -67,14 +67,14 @@ class LengthMotorController(QMainWindow):
# 1. 顶部标题(替代原实时时间)
self._create_title(main_layout)
# 2. 下方左右分栏:左侧线条选择区(表格),右侧参数+3D
# 2. 下方左右分栏:左侧线条选择区,右侧(实时时间 + 参数 + 3D
bottom_h_layout = QHBoxLayout()
bottom_h_layout.setSpacing(20)
# 左侧:线条选择区(表格形式
# 左侧:线条选择区(表格)
self._create_line_select_table(bottom_h_layout)
# 右侧:参数设置 + 3D显示区
# 右侧:实时时间 + 参数设置 + 3D显示区
self._create_right_area(bottom_h_layout)
main_layout.addLayout(bottom_h_layout)
@ -146,7 +146,7 @@ class LengthMotorController(QMainWindow):
parent_layout.addWidget(title_label)
def _create_line_select_table(self, parent_layout):
"""左侧线条选择区(表格形式显示线条A/B的参数"""
"""左侧线条选择区(表格)"""
line_select_group = QGroupBox("线条选择(参数预览)")
line_select_group.setFont(self.font1)
line_select_group.setMinimumWidth(self.width() * 0.5)
@ -159,19 +159,18 @@ class LengthMotorController(QMainWindow):
a_label.setFont(self.font2)
self.table_line_a = QTableWidget()
self.table_line_a.setRowCount(len(self.line_a_params))
self.table_line_a.setColumnCount(5) # 类型 + a/b/c/d
self.table_line_a.setColumnCount(5)
self.table_line_a.setHorizontalHeaderLabels(["类型", "参数a", "参数b", "参数c", "参数d"])
# 填充线条A数据
for row, (type_name, params) in enumerate(self.line_a_params.items()):
self.table_line_a.setItem(row, 0, QTableWidgetItem(type_name))
self.table_line_a.setItem(row, 1, QTableWidgetItem(str(params[0])))
self.table_line_a.setItem(row, 2, QTableWidgetItem(str(params[1])))
self.table_line_a.setItem(row, 3, QTableWidgetItem(str(params[2])))
self.table_line_a.setItem(row, 4, QTableWidgetItem(str(params[3])))
self.table_line_a.setFixedHeight(220)
self.table_line_a.setEditTriggers(QTableWidget.NoEditTriggers) # 禁止编辑
self.table_line_a.setSelectionBehavior(QTableWidget.SelectRows) # 按行选择
self.table_line_a.selectRow(0) # 默认选中第一行
self.table_line_a.setFixedHeight(280)
self.table_line_a.setEditTriggers(QTableWidget.NoEditTriggers)
self.table_line_a.setSelectionBehavior(QTableWidget.SelectRows)
self.table_line_a.selectRow(0)
self.table_line_a.itemSelectionChanged.connect(self._on_line_a_select)
# 线条B表格
@ -181,14 +180,13 @@ class LengthMotorController(QMainWindow):
self.table_line_b.setRowCount(len(self.line_b_params))
self.table_line_b.setColumnCount(5)
self.table_line_b.setHorizontalHeaderLabels(["类型", "参数a", "参数b", "参数c", "参数d"])
# 填充线条B数据
for row, (type_name, params) in enumerate(self.line_b_params.items()):
self.table_line_b.setItem(row, 0, QTableWidgetItem(type_name))
self.table_line_b.setItem(row, 1, QTableWidgetItem(str(params[0])))
self.table_line_b.setItem(row, 2, QTableWidgetItem(str(params[1])))
self.table_line_b.setItem(row, 3, QTableWidgetItem(str(params[2])))
self.table_line_b.setItem(row, 4, QTableWidgetItem(str(params[3])))
self.table_line_b.setFixedHeight(220)
self.table_line_b.setFixedHeight(260)
self.table_line_b.setEditTriggers(QTableWidget.NoEditTriggers)
self.table_line_b.setSelectionBehavior(QTableWidget.SelectRows)
self.table_line_b.selectRow(0)
@ -207,33 +205,32 @@ class LengthMotorController(QMainWindow):
import_layout.addWidget(import_a_btn)
import_layout.addWidget(import_b_btn)
# 布局
select_layout.addWidget(a_label)
select_layout.addWidget(self.table_line_a)
select_layout.addWidget(b_label)
select_layout.addWidget(self.table_line_b)
select_layout.addLayout(import_layout)
select_layout.addStretch() # 填充高度
select_layout.addStretch()
parent_layout.addWidget(line_select_group)
def _on_line_a_select(self):
"""线条A表格选中行变化时,记录选中类型"""
selected_rows = self.table_line_a.selectionModel().selectedRows()
"""线条A表格选中行变化"""
selected_rows = self.table_line_a.selectedItems()
if selected_rows:
# 获取选中行的第一列(类型列)文本
row = selected_rows[0].row()
self.selected_line_a = self.table_line_a.item(row, 0).text()
def _on_line_b_select(self):
"""线条B表格选中行变化时,记录选中类型"""
selected_rows = self.table_line_b.selectionModel().selectedRows()
"""线条B表格选中行变化"""
selected_rows = self.table_line_b.selectedItems()
if selected_rows:
row = selected_rows[0].row()
self.selected_line_b = self.table_line_b.item(row, 0).text()
def _create_right_area(self, parent_layout):
"""右侧区域:参数设置 + 3D显示"""
"""右侧区域:实时时间 → 线条类型设置 3D显示"""
right_v_layout = QVBoxLayout()
right_v_layout.setSpacing(20)
@ -301,7 +298,7 @@ class LengthMotorController(QMainWindow):
param_d_list.append(d_str)
param_d_list = sorted(list(set(param_d_list)), key=lambda x: int(x))
# 4个参数下拉框(横向布局)
# 4个参数下拉框
param_layout = QHBoxLayout()
param_layout.setSpacing(20)
@ -361,15 +358,15 @@ class LengthMotorController(QMainWindow):
button_layout = QHBoxLayout()
self.save_btn = QPushButton("保存设置")
self.save_btn.setFont(self.font2)
self.save_btn.setFixedSize(140, 45) # 宽140px高45px
self.save_btn.setFixedSize(140, 45)
self.clear_btn = QPushButton("清空选择")
self.clear_btn.setFont(self.font2)
self.clear_btn.setFixedSize(140, 45) # 宽140px高45px
self.clear_btn.setFixedSize(140, 45)
self.export_btn = QPushButton("导出记录")
self.export_btn.setFont(self.font2)
self.export_btn.setFixedSize(140, 45) # 宽140px高45px
self.export_btn.setFixedSize(140, 45)
button_layout.addStretch()
button_layout.addWidget(self.save_btn)
@ -381,33 +378,28 @@ class LengthMotorController(QMainWindow):
control_layout.addLayout(button_layout)
right_v_layout.addWidget(control_group)
# 2. 3D效果显示占位区
# 3. 3D效果显示占位区
self._create_3d_placeholder(right_v_layout)
parent_layout.addLayout(right_v_layout)
def _create_3d_placeholder(self, parent_layout):
"""3D效果显示占位区缩小"""
display_group = QGroupBox("线条3D效果显示(后续接口)")
"""3D效果显示占位区缩小留白"""
display_group = QGroupBox("线条3D效果显示")
display_group.setFont(self.font1)
display_layout = QVBoxLayout(display_group)
display_layout.setContentsMargins(20, 20, 20, 20)
placeholder_text = QTextEdit()
placeholder_text.setReadOnly(True)
placeholder_text.setMaximumHeight(180)
placeholder_text.setText("""3D接口说明
1. 后续集成3D模块如Qt3DExtras
2. 参数a→半径参数b→长度参数c/d→颜色
3. 保存参数触发record_data_signal更新3D""")
placeholder_text.setFont(QFont("Microsoft YaHei", 10))
# 实例化ui_3d.py中的Target3DWidget
self.ui_3d_widget = Target3DWidgetA() # 创建3D绘图控件实例
self.ui_3d_widget.setMaximumSize(500, 330)
test_btn = QPushButton("测试参数传递")
test_btn.setFont(self.font2)
test_btn.setFixedWidth(150)
test_btn.clicked.connect(self._test_3d_param_pass)
display_layout.addWidget(placeholder_text)
display_layout.addWidget(self.ui_3d_widget)
display_layout.addWidget(test_btn, alignment=Qt.AlignCenter)
parent_layout.addWidget(display_group)
@ -457,10 +449,10 @@ class LengthMotorController(QMainWindow):
d_str = f"{d:.0f}" # 参数d是整数25/26/28等
"""设置参数到下拉框"""
self.combo_a.setCurrentText(a_str)
self.combo_b.setCurrentText(b_str)
self.combo_c.setCurrentText(c_str)
self.combo_d.setCurrentText(d_str)
self.combo_a.setCurrentText(str(a))
self.combo_b.setCurrentText(str(b))
self.combo_c.setCurrentText(str(c))
self.combo_d.setCurrentText(str(d))
@Slot()
def _save_settings(self):

216
UI/ui_3d.py Normal file
View File

@ -0,0 +1,216 @@
#!/usr/bin/env python
# -*- coding: utf-8 -*-
'''
# @Time : 2026/1/7 10:41
# @Author : reenrr
# @File : 3D.py
# @Desc : 界面上的线条3D显示
'''
from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QVBoxLayout
from matplotlib.backends.backend_qtagg import FigureCanvasQTAgg as FigureCanvas
import matplotlib.pyplot as plt
import sys
# 线条类型A
class Target3DWidgetA(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.init_3d_plot()
self.setLayout(QVBoxLayout())
self.layout().addWidget(self.canvas)
def init_3d_plot(self):
# 3D画布
self.fig = plt.figure(figsize=(15, 6))
self.canvas = FigureCanvas(self.fig)
self.ax = self.fig.add_subplot(111, projection='3d')
# 绘制3D形状
self.draw_target_shape()
# 添加标注
self.add_annotations()
# ========== 核心修改X/Y/Z轴统一为1cm单位 ==========
self.ax.set_xlabel('X')
self.ax.set_ylabel('Y')
self.ax.set_zlabel('Z')
# 1. 轴范围X轴设为0-60cmY/Z设为0-5cm
self.ax.set_xlim(0, 60)
self.ax.set_ylim(0, 5)
self.ax.set_zlim(0, 5)
# 2. 刻度间隔统一为1cm
self.ax.set_xticks(range(0, 61, 5)) # X轴每5cm标一次刻度避免太密集
self.ax.set_yticks(range(0, 6, 1)) # Y轴每1cm标一次刻度
self.ax.set_zticks(range(0, 6, 1)) # Z轴每1cm标一次刻度
# 调整视角适配X轴1cm刻度
self.ax.view_init(elev=20, azim=60)
def draw_target_shape(self):
"""绘制3D结构"""
vertices = [
# 底部截面Z=0平面
(0, 3, 0), (50, 3, 0),
(50, 3, 0), (50, 0, 0),
# 中间截面Z=0.5平面)
(0, 0.5, 0.5), (0, 3, 0.5),
(0, 3, 0.5), (50, 3, 0.5),
(50, 3, 0.5), (50, 0.5, 0.5),
(50, 0.5, 0.5), (0, 0.5, 0.5),
# 顶部界面Z=2平面
(0, 0, 2), (0, 0.5, 2),
(0, 0.5, 2), (50, 0.5, 2),
(50, 0.5, 2), (50, 0, 2),
(50, 0, 2), (0, 0, 2),
# z方向的连线
(0, 3, 0.5), (0, 3, 0),
(50, 3, 0.5), (50, 3, 0),
(0, 0.5, 2), (0, 0.5, 0.5),
(50, 0.5, 2), (50, 0.5, 0.5),
(50, 0, 2), (50, 0, 0),
]
# 绘制所有棱边
for i in range(0, len(vertices), 2):
x = [vertices[i][0], vertices[i + 1][0]]
y = [vertices[i][1], vertices[i + 1][1]]
z = [vertices[i][2], vertices[i + 1][2]]
self.ax.plot(x, y, z, color='black', linewidth=2)
def add_annotations(self):
"""标注位置适配X轴1cm单位"""
annotations = [
("a", 50, 0, 1, 'red'),
("b", 50, 1, 0, 'green'),
("c", 50, 3, 0.25, 'blue'),
("d", 25, 2, 0, 'magenta')
]
for text, x, y, z, color in annotations:
self.ax.text(x, y, z, text, fontsize=14, color=color, weight='bold')
# 线条类型B
class Target3DWidgetB(QWidget):
def __init__(self, parent=None):
super().__init__(parent)
self.init_3d_plot()
self.setLayout(QVBoxLayout())
self.layout().addWidget(self.canvas)
def init_3d_plot(self):
# 3D画布
self.fig = plt.figure(figsize=(15, 6))
self.canvas = FigureCanvas(self.fig)
self.ax = self.fig.add_subplot(111, projection='3d')
# 绘制3D形状
self.draw_target_shape()
# 添加标注
self.add_annotations()
# ========== 核心修改X/Y/Z轴统一为1cm单位 ==========
self.ax.set_xlabel('X')
self.ax.set_ylabel('Y')
self.ax.set_zlabel('Z')
# 1. 轴范围X轴设为0-60cmY/Z设为0-5cm
self.ax.set_xlim(0, 60)
self.ax.set_ylim(0, 5)
self.ax.set_zlim(0, 5)
# 2. 刻度间隔统一为1cm
self.ax.set_xticks(range(0, 61, 5)) # X轴每5cm标一次刻度避免太密集
self.ax.set_yticks(range(0, 6, 1)) # Y轴每1cm标一次刻度
self.ax.set_zticks(range(0, 6, 1)) # Z轴每1cm标一次刻度
# 调整视角适配X轴1cm刻度
self.ax.view_init(elev=20, azim=60)
def draw_target_shape(self):
"""绘制3D结构"""
vertices = [
# 底部截面Z=0平面
(0, 3, 0), (50, 3, 0),
(50, 3, 0), (50, 0, 0),
# 中间截面Z=0.5平面)
(0, 0.5, 0.5), (0, 2.5, 0.5),
(50, 2.5, 0.5), (50, 0.5, 0.5),
(50, 0.5, 0.5), (0, 0.5, 0.5),
# 中间截面Z=1平面
(0, 2.5, 1),(0, 3, 1),
(0, 3, 1), (50, 3, 1),
(50, 3, 1), (50, 2.5, 1),
(50, 2.5, 1), (0, 2.5, 1),
# 顶部界面Z=2平面
(0, 0, 2), (0, 0.5, 2),
(0, 0.5, 2), (50, 0.5, 2),
(50, 0.5, 2), (50, 0, 2),
(50, 0, 2), (0, 0, 2),
# z方向的连线
(0, 3, 1), (0, 3, 0),
(50, 3, 1), (50, 3, 0),
(0, 0.5, 2), (0, 0.5, 0.5),
(50, 0.5, 2), (50, 0.5, 0.5),
(50, 0, 2), (50, 0, 0),
(0, 2.5, 1),(0, 2.5, 0.5),
(50, 2.5, 1),(50, 2.5, 0.5)
]
# 绘制所有棱边
for i in range(0, len(vertices), 2):
x = [vertices[i][0], vertices[i + 1][0]]
y = [vertices[i][1], vertices[i + 1][1]]
z = [vertices[i][2], vertices[i + 1][2]]
self.ax.plot(x, y, z, color='black', linewidth=2)
def add_annotations(self):
"""标注位置适配X轴1cm单位"""
annotations = [
("a", 50, 0, 1, 'red'),
("b", 50, 1, 0, 'green'),
("c", 50, 3, 0.5, 'blue'),
("d", 25, 2, 0, 'magenta')
]
for text, x, y, z, color in annotations:
self.ax.text(x, y, z, text, fontsize=14, color=color, weight='bold')
class MainWindowA(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("3D视图X/Y/Z单位1cm")
self.setGeometry(100, 100, 1200, 700) # 加宽窗口适配X轴1cm刻度
self.setCentralWidget(Target3DWidgetA())
class MainWindowB(QMainWindow):
def __init__(self):
super().__init__()
self.setWindowTitle("3D视图X/Y/Z单位1cm")
self.setGeometry(100, 100, 1200, 700) # 加宽窗口适配X轴1cm刻度
self.setCentralWidget(Target3DWidgetB())
def ui_3d_a():
app = QApplication(sys.argv)
window = MainWindowA()
window.show()
sys.exit(app.exec())
def ui_3d_b():
app = QApplication(sys.argv)
window = MainWindowB()
window.show()
sys.exit(app.exec())
# ----------测试接口----------
if __name__ == '__main__':
ui_3d_a()
# ui_3d_b()

View File

@ -12,3 +12,5 @@ sudo chmod 666 /dev/ttyACM0
# python版本
3.9