You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

基于多边形分割GPX轨迹并计算区域耗时与距离的技术求助

轨迹分割与批量处理优化需求

问题描述

我有多份.gpx轨迹文件,每份轨迹均跨越多个多边形处理区域,同时具备对应多边形的shapefile文件。已编写R代码实现轨迹分割与耗时、距离计算,但仍存在两个问题:

  • 当多边形内仅存在单个轨迹点时,无法统计该点对应的停留时间(即过渡时间),导致数据丢失,需优化代码避免该问题;
  • 需批量处理约100份.gpx文件,最终生成包含原文件名、各多边形总耗时与总距离的数据集,用于评估捕获率的投入力度。

现有代码

library(sf)         # 空间数据处理
library(lubridate)  # 时间处理
library(dplyr)      # 数据清洗
library(geosphere)  # 距离计算
library(sp)         # 空间操作
library(tidyverse)  # 工具集(可选)
library(trackeR)    # GPX解析(可选)

# 加载轨迹
gpx_points <- sf::read_sf("try1/Track_2023-10-20 FRINGE_cjh.gpx", layer = "track_points")

# 加载多边形
polygons <- st_read("try1/polygons_combo.shp")  

# 统一坐标系
gpx_points <- st_transform(gpx_points, st_crs(polygons))

# 创建轨迹线
gpx_line <- gpx_points %>%
  arrange(time) %>%
  summarise(do_union = FALSE) %>%
  st_cast("LINESTRING")

# 分割轨迹线
segments <- st_intersection(gpx_line, polygons)

# 匹配轨迹点到多边形
gpx_in_poly <- st_join(gpx_points, polygons, join = st_within)

# 计算各多边形的耗时与距离
gpx_in_poly1 <- gpx_in_poly %>%
  arrange(time) %>%
  group_by(SiteName) %>%
  mutate(
    next_time = lead(time),
    next_geom = lead(geometry),
    time_diff = as.numeric(difftime(next_time, time, units = "secs")),
    dist_m = geosphere::distHaversine(
      st_coordinates(geometry),
      st_coordinates(next_geom)
    )
  ) %>%
  # 过滤时间间隔大于60秒的片段
  filter(time_diff <= 60) %>%
  summarise(
    total_time_sec = sum(time_diff, na.rm = TRUE),
    total_distance_m = sum(dist_m, na.rm = TRUE)
  )

gpx_in_poly1
 
# 快速可视化
library(ggplot2)
ggplot() +
  geom_sf(data = polygons, fill = NA, color = "grey40") +
  geom_sf(data = gpx_in_poly, aes(color = factor(SiteName)), size = 0.8) +
  scale_color_viridis_d(na.value = "black") +
  theme_minimal()

优化方案

1. 解决单个轨迹点的停留时间统计问题

原代码中单个轨迹点因无后续点导致time_diff为NA,无法统计耗时。优化思路是:先标记每个多边形内的轨迹点数量,对单个点的情况,根据其在整条轨迹中的位置(起点、终点、中间点)分配合理的停留时间。

修改后的核心计算代码:

gpx_in_poly1 <- gpx_in_poly %>%
  arrange(time) %>%
  # 全局标记前后点信息,方便跨分组调用
  mutate(
    prev_time = lag(time),
    next_time_global = lead(time)
  ) %>%
  group_by(SiteName) %>%
  mutate(
    point_count = n(),
    # 多点组常规计算时间差
    time_diff = ifelse(point_count > 1, 
                       as.numeric(difftime(lead(time), time, units = "secs")),
                       NA),
    dist_m = ifelse(point_count > 1,
                    geosphere::distHaversine(st_coordinates(geometry), st_coordinates(lead(geometry))),
                    NA),
    # 单点组按轨迹位置分配时间
    single_point_time = ifelse(point_count == 1,
                               case_when(
                                 # 轨迹起点,取与下一个点的时间差
                                 is.na(prev_time) ~ as.numeric(difftime(next_time_global, time, units = "secs")),
                                 # 轨迹终点,取与上一个点的时间差
                                 is.na(next_time_global) ~ as.numeric(difftime(time, prev_time, units = "secs")),
                                 # 中间单点,取前后点时间差的平均值
                                 TRUE ~ as.numeric(difftime(next_time_global, prev_time, units = "secs")) / 2
                               ),
                               NA)
  ) %>%
  filter(is.na(time_diff) | time_diff <= 60) %>%
  summarise(
    total_time_sec = sum(time_diff, na.rm = TRUE) + sum(single_point_time, na.rm = TRUE),
    total_distance_m = sum(dist_m, na.rm = TRUE)
  )

2. 批量处理.gpx文件

通过定义单个文件处理函数,结合purrr工具批量遍历所有.gpx文件,合并结果并保留原文件名:

# 定义单个gpx文件的处理函数
process_gpx <- function(gpx_path, polygons) {
  # 读取并预处理轨迹点
  gpx_points <- sf::read_sf(gpx_path, layer = "track_points") %>%
    st_transform(st_crs(polygons)) %>%
    arrange(time)
  
  # 匹配轨迹点到多边形
  gpx_in_poly <- st_join(gpx_points, polygons, join = st_within)
  
  # 计算耗时与距离(包含单点处理)
  result <- gpx_in_poly %>%
    mutate(
      prev_time = lag(time),
      next_time_global = lead(time)
    ) %>%
    group_by(SiteName) %>%
    mutate(
      point_count = n(),
      time_diff = ifelse(point_count > 1, 
                         as.numeric(difftime(lead(time), time, units = "secs")),
                         NA),
      dist_m = ifelse(point_count > 1,
                      geosphere::distHaversine(st_coordinates(geometry), st_coordinates(lead(geometry))),
                      NA),
      single_point_time = ifelse(point_count == 1,
                                 case_when(
                                   is.na(prev_time) ~ as.numeric(difftime(next_time_global, time, units = "secs")),
                                   is.na(next_time_global) ~ as.numeric(difftime(time, prev_time, units = "secs")),
                                   TRUE ~ as.numeric(difftime(next_time_global, prev_time, units = "secs")) / 2
                                 ),
                                 NA)
    ) %>%
    filter(is.na(time_diff) | time_diff <= 60) %>%
    summarise(
      total_time_sec = sum(time_diff, na.rm = TRUE) + sum(single_point_time, na.rm = TRUE),
      total_distance_m = sum(dist_m, na.rm = TRUE),
      .groups = "drop"
    ) %>%
    # 添加原文件名
    mutate(gpx_filename = basename(gpx_path))
  
  return(result)
}

# 批量处理流程
# 获取目标文件夹下所有gpx文件路径
gpx_files <- list.files(path = "try1", pattern = "\\.gpx$", full.names = TRUE)

# 加载多边形数据并统一坐标系
polygons <- st_read("try1/polygons_combo.shp") %>%
  st_transform(4326) # 适配GPX默认的WGS84坐标系

# 批量处理并合并所有结果
final_dataset <- purrr::map_dfr(gpx_files, ~process_gpx(.x, polygons))

# 查看结果
head(final_dataset)

# 保存结果为CSV文件
write.csv(final_dataset, "gpx_polygon_stats.csv", row.names = FALSE)

内容的提问来源于stack exchange,提问作者Amanda Goldberg

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 11:27:25