# CSV加载闪退问题修复方案

## 问题分析

经过代码审查，发现"Load from CSV"功能闪退的可能原因：

1. **Windows路径编码问题**（最可能的原因）
   - 在`examples/qt_gui_demo.cpp`第309行和326行使用了`QString::toStdString()`
   - 在Windows MINGW环境下，当文件路径包含中文字符或特殊字符时，这种转换可能产生错误的编码
   - 导致文件路径无法正确打开，或在某些情况下导致程序崩溃

2. **单点路径处理问题**
   - 在`src/path_curve.cpp`的`setPathPoints`函数中，当CSV文件只包含1个数据点时，该点的theta和kappa不会被正确初始化

3. **潜在的异常处理不完整**
   - CSV解析过程中的某些异常可能未被完全捕获

## 修复方案

### 修复1: 更正文件路径编码（重要）

**文件**: `examples/qt_gui_demo.cpp`

**第309行** 需要修改为:
```cpp
// 原代码 (第308-317行):
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!");
    }
}

// 修改为:
if (!filename.isEmpty()) {
    // 使用toLocal8Bit以正确处理Windows路径（包括中文路径）
    std::string filepath = filename.toLocal8Bit().constData();
    if (custom_path_.loadFromCSV(filepath, 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!");
    }
}
```

**第326行** 需要修改为:
```cpp
// 原代码 (第325-329行):
if (!filename.isEmpty() && custom_path_loaded_) {
    if (custom_path_.saveToCSV(filename.toStdString())) {
        QMessageBox::information(this, "Success", "Path saved!");
    }
}

// 修改为:
if (!filename.isEmpty() && custom_path_loaded_) {
    // 使用toLocal8Bit以正确处理Windows路径（包括中文路径）
    std::string filepath = filename.toLocal8Bit().constData();
    if (custom_path_.saveToCSV(filepath)) {
        QMessageBox::information(this, "Success", "Path saved!");
    }
}
```

### 修复2: 改进单点路径处理

**文件**: `src/path_curve.cpp`

在`setPathPoints`函数（第106-134行）中，添加单点处理逻辑：

```cpp
void PathCurve::setPathPoints(const std::vector<PathPoint>& points) {
    path_points_ = points;

    // 计算每个点的切线方向和曲率
    for (size_t i = 0; i < path_points_.size(); ++i) {
        if (i == 0 && path_points_.size() > 1) {
            // 第一个点
            double dx = path_points_[i + 1].x - path_points_[i].x;
            double dy = path_points_[i + 1].y - path_points_[i].y;
            path_points_[i].theta = std::atan2(dy, dx);
        } else if (i == path_points_.size() - 1 && path_points_.size() > 1) {
            // 最后一个点
            double dx = path_points_[i].x - path_points_[i - 1].x;
            double dy = path_points_[i].y - path_points_[i - 1].y;
            path_points_[i].theta = std::atan2(dy, dx);
        } else if (path_points_.size() > 2) {
            // 中间点
            double dx = path_points_[i + 1].x - path_points_[i - 1].x;
            double dy = path_points_[i + 1].y - path_points_[i - 1].y;
            path_points_[i].theta = std::atan2(dy, dx);

            // 计算曲率（使用三点法）
            if (i > 0 && i < path_points_.size() - 1) {
                path_points_[i].kappa = computeCurvature(
                    path_points_[i - 1], path_points_[i], path_points_[i + 1]);
            }
        }
        // 添加: 处理只有单个点的情况
        else if (path_points_.size() == 1) {
            // 单个点保持其原有的theta和kappa值（通常为0）
            // 不需要额外计算
        }
    }
}
```

### 修复3: 添加更完善的异常处理

**文件**: `src/path_curve_custom.cpp`

在`loadFromCSV`函数中添加更完善的错误处理：

```cpp
bool PathCurve::loadFromCSV(const std::string& filename, bool has_header) {
    try {
        std::ifstream file(filename);
        if (!file.is_open()) {
            std::cerr << "Error: Cannot open file " << filename << std::endl;
            return false;
        }

        std::vector<PathPoint> points;
        std::string line;
        int line_num = 0;

        // 跳过表头
        if (has_header && std::getline(file, line)) {
            line_num++;
        }

        while (std::getline(file, line)) {
            line_num++;
            // 跳过空行和注释行
            if (line.empty() || line[0] == '#') {
                continue;
            }

            std::stringstream ss(line);
            std::string token;
            std::vector<double> values;
            bool parse_error = false;

            // 解析CSV行
            while (std::getline(ss, token, ',')) {
                try {
                    // 去除前后空格
                    size_t start = token.find_first_not_of(" \t\r\n");
                    size_t end = token.find_last_not_of(" \t\r\n");
                    if (start == std::string::npos) {
                        // 空token，跳过整行
                        parse_error = true;
                        break;
                    }
                    std::string trimmed = token.substr(start, end - start + 1);
                    values.push_back(std::stod(trimmed));
                } catch (const std::exception& e) {
                    std::cerr << "Error parsing line " << line_num << ": " << line
                              << " (reason: " << e.what() << ")" << std::endl;
                    parse_error = true;
                    break;
                }
            }

            // 如果解析出错或值数量不足，跳过整行
            if (parse_error) {
                continue;
            }

            // 根据列数创建路径点
            if (values.size() >= 2) {
                PathPoint p;
                p.x = values[0];
                p.y = values[1];
                p.theta = (values.size() >= 3) ? values[2] : 0.0;
                p.kappa = (values.size() >= 4) ? values[3] : 0.0;
                points.push_back(p);
            }
        }

        file.close();

        if (points.empty()) {
            std::cerr << "Error: No valid path points loaded from " << filename << std::endl;
            return false;
        }

        // 设置路径点（会自动计算theta和kappa）
        setPathPoints(points);

        std::cout << "Successfully loaded " << points.size() << " points from " << filename << std::endl;
        return true;

    } catch (const std::exception& e) {
        std::cerr << "Exception in loadFromCSV: " << e.what() << std::endl;
        return false;
    }
}
```

## 测试建议

修复后，建议测试以下场景：

1. 加载包含中文路径的CSV文件
2. 加载只有2列（x, y）的CSV文件
3. 加载完整4列（x, y, theta, kappa）的CSV文件
4. 加载只有1个数据点的CSV文件
5. 加载空的CSV文件（只有header）

## 编译和重新生成

修改完成后，需要重新编译项目：

```bash
cd build
cmake --build . --config Release
# 或
cmake --build . --config Debug
```

编译完成后，运行 `agv_qt_gui.exe` 并测试CSV加载功能。
