【问题标题】:geosphere/R: Calculate intersection points between two great circles defined with 4 pointsgeosphere/R:计算用 4 个点定义的两个大圆之间的交点
【发布时间】:2019-08-26 03:27:28
【问题描述】:

我正在尝试使用geosphere 来计算两个大圆之间的交点,这些圆以这样的数据框格式给出:

library(dplyr)
library(geosphere)

df <- data.frame(
  # first line
  ln1_lonb = 1:4,
  ln1_lone = 2:5,
  ln1_latb = 10:13,
  ln1_late = 11:14,
  # second line
  ln2_lonb = 5:8,
  ln2_lone = 6:9,
  ln2_latb = 14:17,
  ln2_late = 15:18
)

我尝试使用geosphere 中的gcintersect 函数,该函数将矩阵作为输入。为了在数据框中使用它,我使用了cbind,但似乎 mutate 不适用于此:

df %>% 
  mutate(
    int_points = gcIntersect(
      cbind(ln1_lonb, ln1_latb),
      cbind(ln1_lone, ln1_late),
      cbind(ln2_lonb, ln2_latb),
      cbind(ln2_lone, ln2_late)
    )
  )
>Error: Column `int_points` must be length 4 (the number of rows) or one, not 16

错误可能是由于输出比预期的长(数据帧的行数)。所以我试着把它放在一个列表中:

df %>% 
  mutate(
    int_points = list(gcIntersect(
      cbind(ln1_lonb, ln1_latb),
      cbind(ln1_lone, ln1_late),
      cbind(ln2_lonb, ln2_latb),
      cbind(ln2_lone, ln2_late)
    ))
  )

在这里,我再次看到输出是所有组合,而不是获取每行 2 个交点的 4 个坐标。

预期的输出将是新列中单元格中的列表,其中包含两个点的坐标。

是否有不使用循环(或purrr)的解决方案,因为这将比mutate 慢得多。

第一行的 int_points 的值应该和这个的输出一样:

gcIntersect(cbind(1,2), cbind(10,11), cbind(5,6), cbind(14,15))

【问题讨论】:

    标签: r spatial intersection geosphere


    【解决方案1】:

    我们可以做一个rowwise

    library(tidyverse)
    library(geosphere)
    df %>% 
          rowwise %>% 
          mutate( int_points = list(gcIntersect(
            cbind(ln1_lonb, ln1_latb),
            cbind(ln1_lone, ln1_late),
            cbind(ln2_lonb, ln2_latb),
            cbind(ln2_lone, ln2_late)
         ))) %>% 
         ungroup %>%
        mutate(int_points = map(int_points, as_tibble)) %>% 
        unnest(int_points)
    # A tibble: 4 x 12
    #  ln1_lonb ln1_lone ln1_latb ln1_late ln2_lonb ln2_lone ln2_latb ln2_late  lon1  lat1  lon2  lat2
    #     <int>    <int>    <int>    <int>    <int>    <int>    <int>    <int> <dbl> <dbl> <dbl> <dbl>
    #1        1        2       10       11        5        6       14       15 -176. -12.6  3.61  12.6
    #2        2        3       11       12        6        7       15       16 -175. -13.6  4.60  13.6
    #3        3        4       12       13        7        8       16       17 -174. -14.6  5.60  14.6
    #4        4        5       13       14        8        9       17       18 -173. -15.6  6.59  15.6
    

    【讨论】:

    • 但输出不正确,因为这会计算所有 ln1 坐标(所有 4 行)与所有 ln2 坐标(所有 4 行)的交点。我用预期的输出更新了问题
    • @adi 我得到的和with(df, gcIntersect( + cbind(ln1_lonb, ln1_latb), + cbind(ln1_lone, ln1_late), + cbind(ln2_lonb, ln2_latb), + cbind(ln2_lone, ln2_late) + ))一样
    • 是的,这将是正确的输出。有没有办法用mutate 以某种方式做到这一点?
    【解决方案2】:

    鉴于 geosphere 方法是矢量化的(正如人们在 R 中所期望的那样),我会这样做

    gcIntersect(df[,c(1,3)], df[,c(2,4)], df[,c(5,7)], df[,c(6,8)])
    
    #          lon1      lat1     lon2     lat2
    #[1,] -176.3902 -12.58846 3.609757 12.58846
    #[2,] -175.3968 -13.58017 4.603188 13.58017
    #[3,] -174.4023 -14.57291 5.597652 14.57291
    #[4,] -173.4070 -15.56648 6.592953 15.56648
    

    你也可以先这样重组

    d <- df[,c("ln1_lonb", "ln1_latb", "ln1_lone", "ln1_late", "ln2_lonb", "ln2_latb", "ln2_lone", "ln2_late")]
    
    gcIntersect(d[,c(1,2)], d[,c(3,4)], d[,c(5,6)], d[,c(7:8)])
    

    或者像这样

    begin1 <- df[,c("ln1_lonb", "ln1_latb")]
    end1 <- df[,c("ln1_lone", "ln1_late")]
    begin2 <- df[,c("ln2_lonb", "ln2_latb")]
    end2 <- df[,c("ln2_lone", "ln2_late")]
    
    gcIntersect(begin1, end1, begin2, end2)
    

    我知道您专门通过 mutate 要求提供解决方案,但我添加了这些解决方案以供其他需要清晰简单解决方案的人使用。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-27
      • 1970-01-01
      • 2018-02-14
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多