From: Caisking Date: Thu, 3 Jul 2025 07:52:01 +0000 (+0800) Subject: 优化运动结束绘制轨迹 X-Git-Url: http://git.snicker.com.cn/css/static/gitweb.css?a=commitdiff_plain;h=e5df29e820cded3e824ae1446a9f8daeb1e65e53;p=mirrors%2FFD230.git 优化运动结束绘制轨迹 --- diff --git a/code/sdk/application/wearable/fd230app/nativeui/traing/src/TraingModel.cpp b/code/sdk/application/wearable/fd230app/nativeui/traing/src/TraingModel.cpp index e086904fd..ed95b1e94 100644 --- a/code/sdk/application/wearable/fd230app/nativeui/traing/src/TraingModel.cpp +++ b/code/sdk/application/wearable/fd230app/nativeui/traing/src/TraingModel.cpp @@ -191,11 +191,11 @@ static void Training_Notify(void *args, const Topic topic, Request *request) { } #if 0 //使用随机数来进行测试 - srand(time(NULL)); - // 纬度范围: 22.45° 到 22.87° ,适当扩大一点范围 + srand(time(NULL)); + // 纬度范围: float lat = (rand() % 420) / 10.0f + 224.5; lat = lat / 10.0f; - // 经度范围: 113.75° 到 114.64° ,适当扩大一点范围 + // 经度范围: float lng = (rand() % 890) / 10.0f + 1137.5; lng = lng / 10.0f; TraingModel::GetInstance()->AddGPSData(0, lat, lng); @@ -2576,21 +2576,141 @@ 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确定的线段的垂直距离 +static double perpendicularDistance(const Point &p, const Point &p1, + const Point &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)); + + // 考虑从p1到p的向量在从p1到p2的向量上的投影 + 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)); + } + if (t > 1) { + // 投影在p2之后 + return std::sqrt((p.x - p2.x) * (p.x - p2.x) + (p.y - p2.y) * (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)); +} + +// Douglas-Peucker算法实现 +static void douglasPeucker(const std::vector &points, double epsilon, + std::vector &result) { + double dmax = 0; + int index = 0; + int end = points.size() - 1; + + // 找到距离最大的点 + for (int i = 1; i < end; i++) { + double d = perpendicularDistance(points[i], points[0], points[end]); + if (d > dmax) { + index = i; + dmax = d; + } + } + + // 如果最大距离大于阈值,则递归处理 + if (dmax > epsilon) { + std::vector recResults1, recResults2; + + // 递归处理前半部分 + std::vector firstSegment(points.begin(), points.begin() + index + 1); + douglasPeucker(firstSegment, epsilon, recResults1); + + // 递归处理后半部分 + std::vector secondSegment(points.begin() + index, points.end()); + douglasPeucker(secondSegment, 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]); + } +} + +// 修改后的GetPointData函数 void TraingModel::GetPointData() { - // 1. 按比例采样最多100个点位 std::vector sampledData; + + // 使用Douglas-Peucker算法简化轨迹 if (gpsData.size() > 100) { - double step = static_cast(gpsData.size() - 1) / 99; - for (int i = 0; i < 100; i++) { - int index = static_cast(i * step); - sampledData.push_back(gpsData[index]); + // 先将GPS数据转换为屏幕坐标 + std::vector screenPoints; + + // 计算经纬度范围 + double minLat = 90.0, maxLat = -90.0; + double minLon = 180.0, maxLon = -180.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); + } + + // 转换为屏幕坐标 + 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}); + } + + // 使用Douglas-Peucker算法简化 + std::vector simplifiedPoints; + douglasPeucker(screenPoints, 2.0, simplifiedPoints); // 阈值2.0可以调整 + + // 如果简化后的点仍然超过100个,则进行均匀采样 + if (simplifiedPoints.size() > 100) { + double step = static_cast(simplifiedPoints.size() - 1) / 99; + for (int i = 0; i < 100; i++) { + int index = static_cast(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}); + } + } 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}); + } } } else { sampledData = gpsData; } - // 2. 计算经纬度的最小值和最大值 + // 接下来的坐标映射部分保持不变 + canvasData.clear(); + const double canvasSize = 300.0; + const double offset = 50.0; + + // 重新计算经纬度范围(基于采样后的数据) double minLat = 90.0, maxLat = -90.0; double minLon = 180.0, maxLon = -180.0; for (const auto &point : sampledData) { @@ -2600,25 +2720,14 @@ void TraingModel::GetPointData() { maxLon = getmax(maxLon, point.longitude); } - // 3. 将经纬度映射到350×350画布区域(居中在400×400画布) - canvasData.clear(); - const double canvasSize = 300.0; - const double offset = 50.0; // 400 - 300 = 100,两边各留50的边距 - + // 映射到画布坐标 for (const auto &point : sampledData) { - // 归一化处理(0-1范围) 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; // 注意:y轴需要反转(屏幕坐标系向下为正) - + double y = (1.0 - normLat) * canvasSize + offset; canvasData.push_back({x, y}); } - - //修改起点与终点 } // 添加经纬度数据集 @@ -2782,9 +2891,22 @@ static void Traing_TimerCallbackProc(int data) { // return; } #if defined(SUPPORT_GNSS) - - TraingModel::GetInstance()->; - + gps_data_t *gps_data = getGPSGlobaldata(); + if (gps_data == NULL) { + PRINT("gps_data == NULL \n"); + return; + } + //判断是否为第一次定位 + if (gps_data->last_gps_time_ms > 0) { + memcpy_s(&send_gps_data, sizeof(gps_data_t), gps_data, sizeof(gps_data_t)); + } + //判断是否定位成功 + if (send_gps_data.status > 1) { + //定位成功 + TraingModel::GetInstance()->SetGPSConnectState(true); + } else { + TraingModel::GetInstance()->SetGPSConnectState(false); + } #endif } /* diff --git a/code/sdk/application/wearable/fd230app/nativeui/traing/src/TraingNomalPresenter.cpp b/code/sdk/application/wearable/fd230app/nativeui/traing/src/TraingNomalPresenter.cpp index 09c3cbf2a..9336be047 100644 --- a/code/sdk/application/wearable/fd230app/nativeui/traing/src/TraingNomalPresenter.cpp +++ b/code/sdk/application/wearable/fd230app/nativeui/traing/src/TraingNomalPresenter.cpp @@ -75,6 +75,8 @@ namespace OHOS 4.[设置训练目标]进入 {不返回} */ NativeAbility::GetInstance().Back(TransitionType::TRANSITION_BACK_TO_HEXAGONS); + // 关闭gps + TraingModel::GetInstance()->stop_heart_gps(); } bool TraingNomalPresenter::OnDrag(UIView &view, const DragEvent &event) {