initial
This commit is contained in:
229
docs/fixes/CSV_LOAD_FIX.md
Normal file
229
docs/fixes/CSV_LOAD_FIX.md
Normal file
@@ -0,0 +1,229 @@
|
||||
# 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加载功能。
|
||||
Reference in New Issue
Block a user