python/hitl/run_sim.py
@@ -339,14 +339,27 @@
        self.view.sceneMouseMoved.connect(self._update_mouse_pos)
        left_layout.addWidget(self.view, stretch=1)
        # Bottom bar for map controls
        bottom_bar = QtWidgets.QWidget()
        bottom_layout = QtWidgets.QHBoxLayout(bottom_bar)
        bottom_layout.setContentsMargins(0, 4, 0, 0)
        self.follow_checkbox = QtWidgets.QCheckBox("自动跟随车辆")
        self.follow_checkbox.setChecked(True)
        self.follow_checkbox.toggled.connect(self._on_follow_toggled)
        left_layout.addWidget(self.follow_checkbox, alignment=QtCore.Qt.AlignLeft)
        bottom_layout.addWidget(self.follow_checkbox)
        self.clear_trail_btn = QtWidgets.QPushButton("清除轨迹")
        self.clear_trail_btn.clicked.connect(self._clear_trail)
        bottom_layout.addWidget(self.clear_trail_btn)
        bottom_layout.addStretch(1)
        self.mouse_pos_label = QtWidgets.QLabel("E: 0.00  N: 0.00")
        self.mouse_pos_label.setStyleSheet("color:#222; background:rgba(255,255,255,190); padding:2px 6px; border-radius:4px;")
        left_layout.addWidget(self.mouse_pos_label, alignment=QtCore.Qt.AlignRight)
        bottom_layout.addWidget(self.mouse_pos_label)
        left_layout.addWidget(bottom_bar)
        layout.addWidget(left_panel, stretch=3)
@@ -402,9 +415,11 @@
        self.origin_text = QtWidgets.QLineEdit(default_origin_short)
        self.origin_text.setPlaceholderText("3949.9120,N,11616.8544,E[,alt]")
        self.origin_btn = QtWidgets.QPushButton("更新原点")
        self.copy_origin_btn = QtWidgets.QPushButton("复制宏定义") # 新增按钮
        grid.addWidget(QtWidgets.QLabel("坐标 (lat,N,lon,E):"), 0, 0, 1, 2)
        grid.addWidget(self.origin_text, 0, 2, 1, 2)
        grid.addWidget(self.origin_btn, 0, 4)
        grid.addWidget(self.copy_origin_btn, 0, 5) # 添加到布局
        labels = ["E (m)", "N (m)", "U (m)", "Heading (deg)"]
        self.pos_spin: List[QtWidgets.QDoubleSpinBox] = []
@@ -428,12 +443,13 @@
        status_layout = QtWidgets.QVBoxLayout(status_group)
        self.info_label = QtWidgets.QLabel("等待数据...")
        self.info_label.setAlignment(QtCore.Qt.AlignTop | QtCore.Qt.AlignLeft)
        self.info_label.setStyleSheet("font-family: Consolas, 'Courier New'; font-size: 12px;")
        self.info_label.setStyleSheet("font-family: Consolas, 'Courier New'; font-size: 14px;")
        info_scroll = QtWidgets.QScrollArea()
        info_scroll.setWidgetResizable(True)
        info_scroll.setWidget(self.info_label)
        info_scroll.setMinimumHeight(500)  # 进一步增加最小高度
        status_layout.addWidget(info_scroll)
        right_layout.addWidget(status_group, stretch=1)
        right_layout.addWidget(status_group, stretch=4)  # 进一步增加布局权重,从2增加到4
        # Stack table
        stack_group = QtWidgets.QGroupBox("堆栈监测")
@@ -484,6 +500,7 @@
        self.path_load_btn.clicked.connect(self._load_path_from_text)
        self.path_export_btn.clicked.connect(self._export_path_to_mcu)
        self.origin_btn.clicked.connect(self._update_origin)
        self.copy_origin_btn.clicked.connect(self._copy_origin_macro) # 绑定事件
        self.reset_pose_btn.clicked.connect(self._reset_position)
        self.port_refresh_btn.clicked.connect(self._refresh_serial_ports)
        self.serial_toggle_btn.clicked.connect(self._toggle_serial)
@@ -492,6 +509,55 @@
        self._set_controls_enabled(False)
        self._update_serial_ui()
    def _copy_origin_macro(self):
        text = self.origin_text.text().strip()
        if not text:
            QtWidgets.QMessageBox.warning(self, "复制", "原点输入框为空")
            return
        # 格式: lat_val,N,lon_val,E,alt
        # 例如: 3949.9120,N,11616.8544,E,47.5
        parts = [p.strip() for p in text.split(",")]
        if len(parts) < 4:
            QtWidgets.QMessageBox.warning(self, "复制", "原点格式错误,需至少包含经纬度")
            return
        try:
            # 解析 DDMM.MMMM 格式转 DD.DDDD
            # 纬度
            lat_raw = parts[0]
            lat_deg_int = int(float(lat_raw) / 100)
            lat_min = float(lat_raw) % 100
            lat_dd = lat_deg_int + lat_min / 60.0
            if parts[1].upper() == 'S':
                lat_dd = -lat_dd
            # 经度
            lon_raw = parts[2]
            lon_deg_int = int(float(lon_raw) / 100)
            lon_min = float(lon_raw) % 100
            lon_dd = lon_deg_int + lon_min / 60.0
            if parts[3].upper() == 'W':
                lon_dd = -lon_dd
            # 高度
            alt = "0.0"
            if len(parts) >= 5:
                alt = parts[4]
            macro = (
                f"#define MC_CFG_ORIGIN_LAT_DEG            ({lat_dd:.6f})\n"
                f"#define MC_CFG_ORIGIN_LON_DEG            ({lon_dd:.6f})\n"
                f"#define MC_CFG_ORIGIN_ALT_M              ({alt})"
            )
            clipboard = QtWidgets.QApplication.clipboard()
            clipboard.setText(macro)
            QtWidgets.QMessageBox.information(self, "复制", "已复制宏定义到剪贴板!")
        except ValueError as e:
            QtWidgets.QMessageBox.warning(self, "复制", f"数值解析错误: {e}")
    def _handle_user_pan(self):
        if self._auto_follow:
            self.follow_checkbox.blockSignals(True)
@@ -504,6 +570,12 @@
        if checked and self.pose_status:
            self.view.centerOn(self.pose_status.east, -self.pose_status.north)
    def _clear_trail(self):
        """清除地图上的轨迹点"""
        self.trail_points = []
        # Update scene to remove trail
        self._update_scene()
    def _update_mouse_pos(self, east: float, scene_y: float):
        north = -scene_y
        self.mouse_pos_label.setText(f"E: {east: .2f}  N: {north: .2f}")
@@ -722,6 +794,7 @@
            (height if height > 0 else 1.0) + pad_y * 2.0,
        )
        self.scene.setSceneRect(scene_rect)
        self.view.fitInView(scene_rect, QtCore.Qt.KeepAspectRatio)
    def _append_log(self, text: str):
        self.log_view.appendPlainText(text)