计算直线与r中相交平面上所有点之间的距离

时间:2018-09-18 15:11:31

标签: r math spatial euclidean-distance

我有一个x,y,z值的规则矩形网格(图像)。
我还有一条与网格相交的x,y,z线。

对于网格中的每个平面(z层),我想计算网格中每个点与直线与该网格的交点之间的欧几里得距离。

示例:

# create regular 3D array of values
vec <- array(1:21,c(21,21,21))
dimnames(vec) = list(seq(-10,10), seq(-10,10), seq(-10,10))

# convert to data.frame (with names x, y, z, value)
grid <- melt(vec, varnames=c("x","y","z"))

# and a set of points along a line
line <- data.frame(
  x = seq(-10, 10),
  y = seq(-10, 10),
  z = seq(-10, 10)
)

我尝试了几件事,并决定在z值上使用for循环。

解决方案:

# loop through each z-level to compute the euclidean distance between 
# all points on the plane at that level, and 
# the point on the line at that level.
tmp = data.frame()
for(i in line$z) { 
  point <- subset(line, z == i)
  plane <- subset(grid, z == i)

  plane$euclidean = (plane$x - point$x)^2 + (plane$y - point$y)^2
  if(nrow(tmp) == 0) {
    tmp = plane
  } else {
    tmp = rbind(tmp, plane)
  }
}

我对这个解决方案并不特别满意,尽管它相对较快。我不喜欢必须拆分并重新组合数据集以产生新的排序/排序的想法,并且当我在r中使用for循环时,我感觉自己做错了。

我强烈感觉这种方式效率低下,并且可能还有其他(更好的方法)使用以下一种或多种方法来做到这一点:

  1. 没有for循环,subsetrbind方法。
  2. 使用线性代数
  3. 使用apply函数之一
  4. 使用空间数据类型和函数sp::spDistsN1()

另一种解决方案是在z值上merge进行网格和线的转换,然后执行直接计算,但是merge步骤非常缓慢,并且结果数据中的x,y,z列.frame由于列名重复而被重命名。


更新以进行澄清:

  1. 尽管图像的每个点(像素)上的值对于距离的计算并不重要,但稍后需要使用,并且应随身携带。
  2. 与我自己的解决方案一样,我需要将距离值分配给每个x,y,z点。因此,输出应包括(x,y,z,value,euclidean),但不一定必须是data.frame

1 个答案:

答案 0 :(得分:0)

这是我的tidyverse尝试,但是如果实际上比您的方法更清晰的话,这不是很明显。从概念上讲,我认为基本上是相同的:对于每个z,请计算该z的线点与所有其他点之间的距离。

  1. 将数组强制为数据框(这种方式与melt基本上相同)
  2. 使函数使用dist来计算点与矩阵之间的距离。 dist实际上是在矩阵的所有行之间进行计算,因此我们只想保留所得三角形距离的底行。但是,它可能仍然比手工完成欧几里得距离还要快。
  3. nest数据,因此我们每个z都有一行,其中xy作为列表列中的数据框
  4. left_join线上的点,然后使用pmap应用我们的新功能
  5. unnest退出,因此我们在网格中有xyz点,pxpy的列线相交点,以及distance,即到该点的距离。网格中每点一行。
vec <- array(1:21,c(21,21,21))
dimnames(vec) = list(x = seq(-10,10), y = seq(-10,10), z = seq(-10,10))

library(tidyverse)
grid <- vec %>% # same thing as melt basically
  as.tbl_cube(met_name = "value") %>%
  as_tibble() 

line <- data.frame(
  px = seq(-10, 10),
  py = seq(-10, 10),
  pz = seq(-10, 10)
)

my_dist <- function(point_x, point_y, mat){
  point_mat <- rbind(c(point_x, point_y), mat)
  dist_mat <- as.matrix(dist(point_mat))
  dist_vec <- dist_mat[nrow(dist_mat), 1:(ncol(dist_mat) - 1)]
  attributes(dist_vec) <- NULL
  return(dist_vec)
}

grid %>%
  select(-value) %>% 
  nest(x, y) %>% # One row per z
  left_join(line, by = c("z" = "pz")) %>%
  mutate(distance = pmap(list(px, py, data), my_dist)) %>%
  unnest() # Expand back out to one row per point
#> # A tibble: 9,261 x 6
#>        z    px    py distance     x     y
#>    <int> <int> <int>    <dbl> <int> <int>
#>  1   -10   -10   -10     28.3   -10   -10
#>  2   -10   -10   -10     28.3    -9   -10
#>  3   -10   -10   -10     27.6    -8   -10
#>  4   -10   -10   -10     26.9    -7   -10
#>  5   -10   -10   -10     26.2    -6   -10
#>  6   -10   -10   -10     25.6    -5   -10
#>  7   -10   -10   -10     25      -4   -10
#>  8   -10   -10   -10     24.4    -3   -10
#>  9   -10   -10   -10     23.9    -2   -10
#> 10   -10   -10   -10     23.3    -1   -10
#> # ... with 9,251 more rows

reprex package(v0.2.0)于2018-09-18创建。

相关问题