# QT GUI 添加自定义路径功能 - 修改指南

## 概述

本指南将教你如何在现有的 QT GUI (`qt_gui_demo.cpp`) 中添加自定义路径选择功能。

## 修改步骤

### 步骤 1: 添加必要的头文件

在文件开头添加以下头文件（第16行之后）：

```cpp
#include <QFileDialog>
#include <QMessageBox>
```

### 步骤 2: 在 Path Type 下拉框中添加选项

找到 `path_combo_` 的初始化部分（约第275-279行），修改为：

```cpp
path_combo_ = new QComboBox(this);
path_combo_->addItem("Circle Arc");
path_combo_->addItem("Straight Line");
path_combo_->addItem("S-Curve");
path_combo_->addItem("Load from CSV");      // 新增
path_combo_->addItem("Custom Spline");       // 新增
```

### 步骤 3: 添加按钮和路径信息标签

在 path_combo_ 初始化后，添加以下代码（约第280行）：

```cpp
control_layout->addLayout(path_layout);

// 添加自定义路径按钮
QHBoxLayout* custom_btn_layout = new QHBoxLayout();

QPushButton* load_csv_btn = new QPushButton("Browse CSV...", this);
connect(load_csv_btn, &QPushButton::clicked, [this]() {
    QString filename = QFileDialog::getOpenFileName(
        this, "Open CSV Path File", "", "CSV Files (*.csv)");
    if (!filename.isEmpty()) {
        if (custom_path_.loadFromCSV(filename.toStdString(), true)) {
            custom_path_loaded_ = true;
            QMessageBox::information(this, "Success", 
                QString("Loaded %1 points from CSV!").arg(
                    custom_path_.getPathPoints().size()));
        } else {
            QMessageBox::warning(this, "Error", "Failed to load CSV file!");
        }
    }
});
custom_btn_layout->addWidget(load_csv_btn);

QPushButton* save_csv_btn = new QPushButton("Save Path...", this);
connect(save_csv_btn, &QPushButton::clicked, [this]() {
    QString filename = QFileDialog::getSaveFileName(
        this, "Save Path as CSV", "my_path.csv", "CSV Files (*.csv)");
    if (!filename.isEmpty() && custom_path_loaded_) {
        if (custom_path_.saveToCSV(filename.toStdString())) {
            QMessageBox::information(this, "Success", "Path saved!");
        }
    }
});
custom_btn_layout->addWidget(save_csv_btn);

control_layout->addLayout(custom_btn_layout);
```

### 步骤 4: 添加成员变量

在 MainWindow 类的 private 部分（约第522-529行），添加：

```cpp
// 在 animation_running_ 之后添加：
PathCurve custom_path_;
bool custom_path_loaded_ = false;
```

### 步骤 5: 修改 generateControl() 方法

找到 `generateControl()` 方法（约第330行），修改路径创建部分：

```cpp
void generateControl() {
    updateAGVModel();

    PathCurve path;
    QString path_type = path_combo_->currentText();

    if (path_type == "Load from CSV") {
        if (!custom_path_loaded_) {
            QMessageBox::warning(this, "Warning", 
                "Please load a CSV file first using 'Browse CSV...' button!");
            return;
        }
        path = custom_path_;
    } 
    else if (path_type == "Custom Spline") {
        if (!custom_path_loaded_) {
            // 如果没有预加载，让用户输入关键点
            bool ok;
            int num_points = QInputDialog::getInt(this, "Spline Input",
                "Number of key points (2-10):", 4, 2, 10, 1, &ok);
            if (!ok) return;

            std::vector<PathPoint> key_points;
            for (int i = 0; i < num_points; ++i) {
                double x = QInputDialog::getDouble(this, "Key Point",
                    QString("Point %1 - X coordinate:").arg(i+1), 
                    i * 3.0, -100, 100, 2, &ok);
                if (!ok) return;
                
                double y = QInputDialog::getDouble(this, "Key Point",
                    QString("Point %1 - Y coordinate:").arg(i+1),
                    (i % 2) * 3.0, -100, 100, 2, &ok);
                if (!ok) return;
                
                key_points.push_back(PathPoint(x, y));
            }

            path.generateSpline(key_points, 200, 0.5);
            custom_path_ = path;
            custom_path_loaded_ = true;
        } else {
            path = custom_path_;
        }
    }
    else if (path_type == "Circle Arc") {
        path.generateCircleArc(5.0, 0.0, 5.0, M_PI, M_PI / 2, 100);
    } else if (path_type == "Straight Line") {
        PathPoint start(0, 0, 0, 0);
        PathPoint end(10, 0, 0, 0);
        path.generateLine(start, end, 100);
    } else if (path_type == "S-Curve") {
        PathPoint p0(0, 0, 0, 0);
        PathPoint p1(3, 2, 0, 0);
        PathPoint p2(7, 2, 0, 0);
        PathPoint p3(10, 0, 0, 0);
        path.generateCubicBezier(p0, p1, p2, p3, 100);
    }

    // 验证路径
    if (path.getPathPoints().empty()) {
        QMessageBox::warning(this, "Error", "Invalid path!");
        return;
    }

    // 其余代码保持不变...
    tracker_->setReferencePath(path);
    // ...
}
```

### 步骤 6: 添加 QInputDialog 头文件（可选，用于简单输入）

如果使用 QInputDialog，在文件开头添加：

```cpp
#include <QInputDialog>
```

## 完整修改示例（精简版）

如果你想要最简单的实现，只需做以下 3 处修改：

### 修改 1: 头文件（第1行附近）

```cpp
#include "path_tracker.h"
#include <QApplication>
// ... 现有的 includes ...
#include <QFileDialog>        // 添加
#include <QMessageBox>        // 添加
```

### 修改 2: 添加成员变量（MainWindow 类 private 部分）

```cpp
private:
    // ... 现有成员 ...
    bool animation_running_ = false;
    
    // 添加以下两行：
    PathCurve custom_path_;
    bool custom_path_loaded_ = false;
};
```

### 修改 3: 修改路径类型选择和控制生成

在 path_combo_ 添加项后（约第279行）：

```cpp
path_combo_->addItem("Load from CSV");
```

在 generateControl() 中添加（约第336行）：

```cpp
if (path_type == "Load from CSV") {
    QString filename = QFileDialog::getOpenFileName(
        this, "Open CSV", "", "CSV Files (*.csv)");
    if (filename.isEmpty()) return;
    
    if (!path.loadFromCSV(filename.toStdString(), true)) {
        QMessageBox::warning(this, "Error", "Failed to load CSV!");
        return;
    }
} else if (path_type == "Circle Arc") {
    // 原有代码...
```

## 编译

修改完成后重新编译：

```bash
cd build
cmake ..
cmake --build .
```

运行增强版 GUI：

```bash
./agv_qt_gui
```

## 使用方法

1. 启动程序
2. 在 "Path Type" 下拉框中选择 "Load from CSV"
3. 点击 "Generate Control" 会弹出文件选择对话框
4. 选择你的 CSV 文件（例如 `examples/custom_path.csv`）
5. 程序会加载路径并显示可视化
6. 点击 "Start Animation" 查看 AGV 跟踪效果

## CSV 文件格式示例

创建一个 `my_path.csv` 文件：

```csv
# My custom path
# x, y
0, 0
2, 1
4, 3
6, 4
8, 4
10, 3
12, 1
14, 0
```

## 高级功能（可选）

如果需要更完整的功能（样条插值对话框、保存路径等），可以参考已创建的完整版本：

```
examples/qt_gui_enhanced.cpp
```

该文件包含：
- 完整的样条插值对话框
- CSV 加载和保存功能
- 路径信息显示
- 更好的用户界面

## 故障排除

### 问题 1: 编译错误 "loadFromCSV 未定义"

**解决方案：** 确保已经：
1. 修改了 `include/path_curve.h` 添加方法声明
2. 在 `CMakeLists.txt` 中添加了 `src/path_curve_custom.cpp`
3. 重新运行 cmake 和编译

### 问题 2: CSV 文件加载失败

**解决方案：**
- 检查 CSV 格式是否正确
- 确保文件路径正确
- 尝试使用绝对路径

### 问题 3: QT5 未找到

**解决方案：**
- 安装 QT5: `sudo apt-get install qt5-default` (Linux)
- 或下载 QT5 并设置环境变量

## 总结

通过以上修改，你的 QT GUI 现在支持：
- ✅ 从 CSV 文件加载自定义路径
- ✅ 使用样条插值创建平滑路径
- ✅ 保存路径到 CSV
- ✅ 所有原有的预设路径类型

Enjoy your enhanced AGV path tracking GUI! 🚀
