}
#if 0
//使用随机数来进行测试
- srand(time(NULL));
+ srand(time(NULL));
// 纬度范围:
float lat = (rand() % 420) / 10.0f + 224.5;
lat = lat / 10.0f;
- // 经度范围:
+ // 经度范围:
float lng = (rand() % 890) / 10.0f + 1137.5;
lng = lng / 10.0f;
- TraingModel::GetInstance()->AddGPSData(0, lat, lng);
+ uint32_t time = TraingModel::GetInstance()->get_current_time();
+ TraingModel::GetInstance()->AddGPSData(time, lat, lng);
return;
#endif
#if defined(SUPPORT_GNSS)
*/
static double getmin(double a, double b) { return a < b ? a : b; }
-
static double getmax(double a, double b) { return a > b ? a : b; }
-
-// 计算点p到由p1和p2确定的线段的垂直距离
+// 计算点p到由p1和p2确定的线段的垂直距离(优化版)
static double perpendicularDistance(const Point &p, const Point &p1,
const Point &p2) {
+ // 计算向量 p1->p2
double dx = p2.x - p1.x;
double dy = p2.y - p1.y;
// 线段长度的平方
double len2 = dx * dx + dy * dy;
- // 如果线段实际上是一个点,返回点p到p1的距离
- if (len2 == 0)
- return std::sqrt((p.x - p1.x) * (p.x - p1.x) + (p.y - p1.y) * (p.y - p1.y));
+ // 如果线段退化为一个点,直接计算点到点的距离
+ if (len2 == 0) {
+ return std::hypot(p.x - p1.x, p.y - p1.y);
+ }
- // è\80\83è\99\91ä»\8ep1å\88°pç\9a\84å\90\91é\87\8få\9c¨ä»\8ep1å\88°p2ç\9a\84å\90\91é\87\8fä¸\8aç\9a\84æ\8a\95å½±
+ // 计ç®\97æ\8a\95å½±æ¯\94ä¾\8b t
double t = ((p.x - p1.x) * dx + (p.y - p1.y) * dy) / len2;
if (t < 0) {
- // 投影在p1之前
- return std::sqrt((p.x - p1.x) * (p.x - p1.x) + (p.y - p1.y) * (p.y - p1.y));
+ // 投影在p1之前,返回p到p1的距离
+ return std::hypot(p.x - p1.x, p.y - p1.y);
}
+
if (t > 1) {
- // 投影在p2之后
- return std::sqrt((p.x - p2.x) * (p.x - p2.x) + (p.y - p2.y) * (p.y - p2.y));
+ // 投影在p2之后,返回p到p2的距离
+ return std::hypot(p.x - p2.x, p.y - p2.y);
}
- // 投影在线段上
- Point projection;
- projection.x = p1.x + t * dx;
- projection.y = p1.y + t * dy;
-
- return std::sqrt((p.x - projection.x) * (p.x - projection.x) +
- (p.y - projection.y) * (p.y - projection.y));
+ // 投影在线段上,计算投影点并返回距离
+ double projX = p1.x + t * dx;
+ double projY = p1.y + t * dy;
+ return std::hypot(p.x - projX, p.y - projY);
}
-// Douglas-Peucker算法实现
+// Douglas-Peucker算法实现(优化版)
static void douglasPeucker(const std::vector<Point> &points, double epsilon,
std::vector<Point> &result) {
+ if (points.size() <= 2) {
+ // 点数量不足,直接返回
+ result = points;
+ return;
+ }
+
double dmax = 0;
int index = 0;
int end = points.size() - 1;
std::vector<Point> recResults1, recResults2;
// 递归处理前半部分
- std::vector<Point> firstSegment(points.begin(), points.begin() + index + 1);
- douglasPeucker(firstSegment, epsilon, recResults1);
+ douglasPeucker(
+ std::vector<Point>(points.begin(), points.begin() + index + 1), epsilon,
+ recResults1);
// 递归处理后半部分
- std::vector<Point> secondSegment(points.begin() + index, points.end());
- douglasPeucker(secondSegment, epsilon, recResults2);
+ douglasPeucker(std::vector<Point>(points.begin() + index, points.end()),
+ epsilon, recResults2);
- // 合并结果
+ // 合并结果(避免重复添加端点)
result.assign(recResults1.begin(), recResults1.end() - 1);
result.insert(result.end(), recResults2.begin(), recResults2.end());
} else {
// 否则保留首尾点
- result.clear();
- result.push_back(points[0]);
- result.push_back(points[end]);
+ result = {points[0], points[end]};
}
}
-// 修改后的GetPointData函数
+// 改进的GetPointData函数(优化版)
void TraingModel::GetPointData() {
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,
+ "Generating point data from %zu GPS points", gpsData.size());
+
std::vector<GPSData> sampledData;
- // 使用Douglas-Peucker算法简化轨迹
+ // 处理GPS数据
if (gpsData.size() > 100) {
- // 先将GPS数据转换为屏幕坐标
- std::vector<Point> screenPoints;
-
// 计算经纬度范围
double minLat = 90.0, maxLat = -90.0;
double minLon = 180.0, maxLon = -180.0;
+
+ // 同时计算平均值用于判断数据分布
+ double sumLat = 0, sumLon = 0;
+
for (const auto &point : gpsData) {
minLat = getmin(minLat, point.latitude);
maxLat = getmax(maxLat, point.latitude);
minLon = getmin(minLon, point.longitude);
maxLon = getmax(maxLon, point.longitude);
+ sumLat += point.latitude;
+ sumLon += point.longitude;
}
- // 转换为屏幕坐标
- for (const auto &point : gpsData) {
- double normLat = (point.latitude - minLat) / (maxLat - minLat);
- double normLon = (point.longitude - minLon) / (maxLon - minLon);
- screenPoints.push_back({normLon * 300 + 50, (1.0 - normLat) * 300 + 50});
- }
+ // 计算经纬度范围和平均值
+ double rangeLat = maxLat - minLat;
+ double rangeLon = maxLon - minLon;
+ double avgLat = sumLat / gpsData.size();
+ double avgLon = sumLon / gpsData.size();
- // 使用Douglas-Peucker算法简化
- std::vector<Point> simplifiedPoints;
- douglasPeucker(screenPoints, 2.0, simplifiedPoints); // 阈值2.0可以调整
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,
+ "GPS range: lat=[%.6f, %.6f], lon=[%.6f, %.6f]", minLat,
+ maxLat, minLon, maxLon);
- // 如果简化后的点仍然超过100个,则进行均匀采样
- if (simplifiedPoints.size() > 100) {
- double step = static_cast<double>(simplifiedPoints.size() - 1) / 99;
+ // 检查数据是否集中在极小区域或几乎相同
+ const double MIN_SIGNIFICANT_RANGE = 0.01; // 根据实际情况调整
+ bool isDataDegenerate =
+ (rangeLat < MIN_SIGNIFICANT_RANGE && rangeLon < MIN_SIGNIFICANT_RANGE);
+
+ if (isDataDegenerate) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+ "GPS data is degenerate (very small range)");
+ // 使用均匀采样,避免算法失效
+ double step = static_cast<double>(gpsData.size() - 1) / 99;
for (int i = 0; i < 100; i++) {
int index = static_cast<int>(i * step);
- // 这里需要将屏幕坐标反推回GPS坐标
- double normX = (simplifiedPoints[index].x - 50) / 300;
- double normY = (simplifiedPoints[index].y - 50) / 300;
- double lat = minLat + (1.0 - normY) * (maxLat - minLat);
- double lon = minLon + normX * (maxLon - minLon);
- sampledData.push_back({lat, lon});
+ sampledData.push_back(gpsData[index]);
}
} else {
- // 简化后的点少于100个,直接使用
- for (const auto &point : simplifiedPoints) {
- double normX = (point.x - 50) / 300;
- double normY = (point.y - 50) / 300;
- double lat = minLat + (1.0 - normY) * (maxLat - minLat);
- double lon = minLon + normX * (maxLon - minLon);
- sampledData.push_back({lat, lon});
+ // 转换GPS坐标到屏幕坐标
+ std::vector<Point> screenPoints;
+ screenPoints.reserve(gpsData.size());
+
+ for (const auto &point : gpsData) {
+ double normLat = (point.latitude - minLat) / rangeLat;
+ double normLon = (point.longitude - minLon) / rangeLon;
+ screenPoints.push_back(
+ {normLon * 300 + 50, (1.0 - normLat) * 300 + 50});
+ }
+
+ // 使用Douglas-Peucker算法简化轨迹
+ std::vector<Point> simplifiedPoints;
+ douglasPeucker(screenPoints, 0.5, simplifiedPoints);
+
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,
+ "After Douglas-Peucker: %zu points",
+ simplifiedPoints.size());
+
+ // 处理简化结果
+ if (simplifiedPoints.size() <= 2) {
+ WEARABLE_LOGE(
+ WEARABLE_LOG_MODULE_APP,
+ "Trajectory over-simplified! Using uniform sampling instead.");
+ // 过度简化时回退到均匀采样
+ double step = static_cast<double>(gpsData.size() - 1) / 99;
+ for (int i = 0; i < 100; i++) {
+ int index = static_cast<int>(i * step);
+ sampledData.push_back(gpsData[index]);
+ }
+ } else if (simplifiedPoints.size() > 100) {
+ // 简化后仍超过100点,再次均匀采样
+ double step = static_cast<double>(simplifiedPoints.size() - 1) / 99;
+ for (int i = 0; i < 100; i++) {
+ int index = static_cast<int>(i * step);
+ // 屏幕坐标反推回GPS坐标
+ double normX = (simplifiedPoints[index].x - 50) / 300;
+ double normY = (simplifiedPoints[index].y - 50) / 300;
+ double lat = minLat + (1.0 - normY) * rangeLat;
+ double lon = minLon + normX * rangeLon;
+ sampledData.push_back({0, lat, lon});
+ }
+ } else {
+ // 简化后点数量合适,直接使用
+ for (const auto &point : simplifiedPoints) {
+ double normX = (point.x - 50) / 300;
+ double normY = (point.y - 50) / 300;
+ double lat = minLat + (1.0 - normY) * rangeLat;
+ double lon = minLon + normX * rangeLon;
+ sampledData.push_back({0, lat, lon});
+ }
}
}
} else {
+ // GPS点数不足100,直接使用全部数据
sampledData = gpsData;
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+ "Using all %zu GPS points (no sampling)", sampledData.size());
}
- // æ\8e¥ä¸\8bæ\9d¥ç\9a\84å\9d\90æ \87æ\98 å°\84é\83¨å\88\86ä¿\9dæ\8c\81ä¸\8då\8f\98
+ // æ\98 å°\84å\88°ç\94»å¸\83å\9d\90æ \87
canvasData.clear();
- const double canvasSize = 300.0;
- const double offset = 50.0;
+ canvasData.reserve(sampledData.size());
+
+ // 如果没有采样数据,直接返回
+ if (sampledData.empty()) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "No sampled data to map!");
+ return;
+ }
- // 重新计算经纬度范围(基于采样后的数据)
+ // 基于采样数据重新计算经纬度范围
double minLat = 90.0, maxLat = -90.0;
double minLon = 180.0, maxLon = -180.0;
+
for (const auto &point : sampledData) {
minLat = getmin(minLat, point.latitude);
maxLat = getmax(maxLat, point.latitude);
maxLon = getmax(maxLon, point.longitude);
}
- // 映射到画布坐标
+ double rangeLat = maxLat - minLat;
+ double rangeLon = maxLon - minLon;
+
+ // 避免除零错误
+ if (rangeLat == 0)
+ rangeLat = 1e-10;
+ if (rangeLon == 0)
+ rangeLon = 1e-10;
+
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,
+ "Sampled GPS range: lat=[%.6f, %.6f], lon=[%.6f, %.6f]", minLat,
+ maxLat, minLon, maxLon);
+
+ // 映射每个点到画布
for (const auto &point : sampledData) {
- double normLat = (point.latitude - minLat) / (maxLat - minLat);
- double normLon = (point.longitude - minLon) / (maxLon - minLon);
- double x = normLon * canvasSize + offset;
- double y = (1.0 - normLat) * canvasSize + offset;
+ double normLat = (point.latitude - minLat) / rangeLat;
+ double normLon = (point.longitude - minLon) / rangeLon;
+
+ // 转换到画布坐标
+ double x = normLon * 300 + 50;
+ double y = (1.0 - normLat) * 300 + 50;
+
canvasData.push_back({x, y});
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP,
+ "Mapped point: (%.6f, %.6f) -> (%.2f, %.2f)", point.latitude,
+ point.longitude, x, y);
}
+
+ WEARABLE_LOGD(WEARABLE_LOG_MODULE_APP, "Generated %zu canvas points",
+ canvasData.size());
}
// 添加经纬度数据集
double longitude) {
// 判断数据是否合理
if (latitude < -90 || latitude > 90 || longitude < -180 || longitude > 180) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Invalid GPS data");
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+ "Invalid GPS data: lat=%.6f, lon=%.6f", latitude, longitude);
return;
}
- // 校验时间戳是不是重复 比较最后一个?
- if (gpsData.size() > 0 && timestamp <= gpsData.back().timestamp) {
- WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP, "Timestamp is not increasing");
+
+ // 校验时间戳是否递增
+ if (!gpsData.empty() && timestamp <= gpsData.back().timestamp) {
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+ "Timestamp not increasing: current=%u, last=%u", timestamp,
+ gpsData.back().timestamp);
return;
}
+
// 添加数据
gpsData.push_back({timestamp, latitude, longitude});
+ WEARABLE_LOGE(WEARABLE_LOG_MODULE_APP,
+ "Added GPS data #%zu: ts=%u, (%.6f, %.6f)", gpsData.size(),
+ timestamp, latitude, longitude);
}
-
//保存gps数据
bool TraingModel::SaveCanvasData() {