优化运动结束绘制轨迹
authorCaisking <Casiking@zhihuishixun.com>
Thu, 3 Jul 2025 07:52:01 +0000 (15:52 +0800)
committerCaisking <Casiking@zhihuishixun.com>
Thu, 3 Jul 2025 07:52:01 +0000 (15:52 +0800)
code/sdk/application/wearable/fd230app/nativeui/traing/src/TraingModel.cpp
code/sdk/application/wearable/fd230app/nativeui/traing/src/TraingNomalPresenter.cpp

index e086904..ed95b1e 100644 (file)
@@ -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<Point> &points, double epsilon,
+                           std::vector<Point> &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<Point> recResults1, recResults2;
+
+    // 递归处理前半部分
+    std::vector<Point> firstSegment(points.begin(), points.begin() + index + 1);
+    douglasPeucker(firstSegment, epsilon, recResults1);
+
+    // 递归处理后半部分
+    std::vector<Point> 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<GPSData> sampledData;
+
+  // 使用Douglas-Peucker算法简化轨迹
   if (gpsData.size() > 100) {
-    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]);
+    // 先将GPS数据转换为屏幕坐标
+    std::vector<Point> 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<Point> simplifiedPoints;
+    douglasPeucker(screenPoints, 2.0, simplifiedPoints); // 阈值2.0可以调整
+
+    // 如果简化后的点仍然超过100个,则进行均匀采样
+    if (simplifiedPoints.size() > 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) * (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
 }
 /*
index 09c3cbf..9336be0 100644 (file)
@@ -75,6 +75,8 @@ namespace OHOS
             4.[设置训练目标]进入 {不返回}\r
         */\r
         NativeAbility::GetInstance().Back(TransitionType::TRANSITION_BACK_TO_HEXAGONS);\r
+        // 关闭gps\r
+        TraingModel::GetInstance()->stop_heart_gps();\r
     }\r
     bool TraingNomalPresenter::OnDrag(UIView &view, const DragEvent &event)\r
     {\r