diff --git a/.idea/wire_controlsystem.iml b/.idea/wire_controlsystem.iml index 8b8c395..4a631ed 100644 --- a/.idea/wire_controlsystem.iml +++ b/.idea/wire_controlsystem.iml @@ -2,7 +2,7 @@ - + diff --git a/UI/test.py b/UI/test.py index 81166e2..9e2ed6f 100644 --- a/UI/test.py +++ b/UI/test.py @@ -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) diff --git a/UI/ui.py b/UI/ui.py index 16fec2c..10c6e43 100644 --- a/UI/ui.py +++ b/UI/ui.py @@ -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): diff --git a/UI/ui_3d.py b/UI/ui_3d.py new file mode 100644 index 0000000..ffc6b6e --- /dev/null +++ b/UI/ui_3d.py @@ -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-60cm,Y/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-60cm,Y/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() + diff --git a/readme.md b/readme.md index 31bd38a..3b89d97 100644 --- a/readme.md +++ b/readme.md @@ -12,3 +12,5 @@ sudo chmod 666 /dev/ttyACM0 # python版本 3.9 + +