【问题标题】:How to find the smallest circumcircle of an irregular polygon on R project?如何在R项目中找到不规则多边形的最小外接圆?
【发布时间】:2020-05-05 22:37:01
【问题描述】:

我想知道如何找到不规则多边形的最小外接圆。我在 R 中使用过空间多边形。

我想以矢量模式重现一些 fragstats 指标,因为我很难使用“landscapemetrics”包来处理大量数据。具体来说,我想实现这个圈子(http://www.umass.edu/landeco/research/fragstats/documents/Metrics/Shape%20Metrics/Metrics/P11%20-%20CIRCLE.htm)。到目前为止,我找不到最小外接圆的公式或脚本。

非常欢迎您的所有 cmets。

比你

【问题讨论】:

  • 欢迎来到 SO。请包括一个最小的可重复示例,说明您尝试过的内容或说出您为尝试找到问题的答案而查看的内容。查看minimal reproducible example 以获取编写可能会得到良好响应的问题的指针。
  • 我不知道这方面的 R 代码,但 Wikipedia 上有一篇关于它的文章,称其为“最小圆问题”:en.wikipedia.org/wiki/Smallest-circle_problem。它包括几个建议的算法;至少其中一个(“Welzl 算法”)非常简单,显然行不通。

标签: r gis spatial-index


【解决方案1】:

正如我在评论中提到的,我不知道现有的 R 代码,但是如果你没有太多的点需要在圈子中,那么蛮力搜索应该足够快。我刚写了这个。 center() 函数基于维基百科的代码,用于在三角形周围画一个圆; circumcircle() 是你想要的函数,通过集合中通过 2 或 3 个点的所有圆通过暴力搜索找到。在我的笔记本电脑上,处理 100 分大约需要 4 秒。如果你有更大的集合,你可能可以通过转换为 C++ 来获得可以接受的结果,但这是一个n^4 的增长率,所以你需要一个更好的解决方案 对于一个非常大的集合。

center <- function(D) {
  if (NROW(D) == 0)
    matrix(numeric(), ncol = 2)
  else if (NROW(D) == 1)
    D
  else if (NROW(D) == 2) {
    (D[1,] + D[2,])/2
  } else if (NROW(D) == 3) {
    B <- D[2,] - D[1,]
    C <- D[3,] - D[1,]
    Dprime <- 2*(B[1]*C[2] - B[2]*C[1])
    if (Dprime == 0) {
      drop <- which.max(c(sum((B-C)^2), sum(C^2), sum(B^2)))
      center(D[-drop,])
    } else 
      c((C[2]*sum(B^2) - B[2]*sum(C^2))/Dprime,
        (B[1]*sum(C^2) - C[1]*sum(B^2))/Dprime) + D[1,]
  } else 
    center(circumcircle(D))
}

radius <- function(D, U = center(D))
  sqrt(sum((D[1,] - U)^2))

circumcircle <- function(P) {
  n <- NROW(P)
  if (n < 3) 
    return(P)
  P <- P[sample(n),]
  bestset <- NULL
  bestrsq <- Inf
  # Brute force search
  for (i in 1:(n-1)) {
    for (j in (i+1):n) {
      D <- P[c(i,j),]
      U <- center(D)
      rsq <- sum((D[1,] - U)^2)
      if (rsq >= bestrsq)
        next
      failed <- FALSE
      for (k in (1:n)[-j][-i]) {
        Pk <- P[k,,drop = FALSE]
        if (sum((Pk - U)^2) > rsq) {
          failed <- TRUE
          break
        }
      }
      if (!failed) {
        bestset <- c(i,j)
        bestrsq <- rsq
      }
    }
  }
  # Look for the best 3 point set
  for (i in 1:(n-2)) {
    for (j in (i+1):(n-1)) {
      for (l in (j+1):n) {
        D <- P[c(i,j,l),]
        U <- center(D)
        rsq <- sum((D[1,] - U)^2)
        if (rsq >= bestrsq)
          next
        failed <- FALSE
        for (k in (1:n)[-l][-j][-i]) {
          Pk <- P[k,,drop = FALSE]
          if (sum((Pk - U)^2) > rsq) {
            failed <- TRUE
            break
          }
        }
        if (!failed) {
          bestset <- c(i,j,l)
          bestrsq <- rsq
        }
      }
    }  
  }
  P[bestset,]
}

showP <- function(P, ...) {
  plot(P, asp = 1, type = "n", ...)
  text(P, labels = seq_len(nrow(P)))
}

showD <- function(D) {
  U <- center(D)
  r <- radius(D, U)
  theta <- seq(0, 2*pi, len = 100)
  lines(U[1] + r*cos(theta), U[2] + r*sin(theta))
}

n <- 100
P <- cbind(rnorm(n), rnorm(n))
D <- circumcircle(P)
showP(P)
showD(D)

这显示了输出

【讨论】:

  • 谢谢。非常感谢!
  • 您好,我尝试使用您的代码,但遇到问题,无法确定原因。它适用于简单的多边形,但是当我尝试使用更复杂的结构时,出现以下错误 _Error in if (rsq >= bestrsq) next : missing value where TRUE/FALSE needed_
  • 我用下面的多边形进行了测试。 &lt;df&lt;-as.matrix(data.frame(x=c(1291121,1291031,1291031,1290971,1290971,1291001,1291001,1291091,1291091,1291121,1291121,1291151,1291151,1291181,1291181,1291151,1291151,1291091,1291091,1291121),y=c(550093.4,550093.4,550123.4,550123.4,550183.4,550183.4,550213.4,550213.4,550183.4,550183.4,550213.4,550213.4,550243.4,550243.4,550183.4,550183.4,550153.4,550153.4,550123.4,550123.4 )))
  • @DarthOrion:你的数据集的问题是一些点正好在一条线上,三角形中心的公式假设三元组形成了一个正确的三角形。您可以添加一点随机噪音,旧代码就可以工作,或者将上面的新代码用于center() 函数。
猜你喜欢
  • 2021-01-25
  • 1970-01-01
  • 2012-03-30
  • 1970-01-01
  • 2014-12-06
  • 2014-05-12
  • 2020-06-14
  • 1970-01-01
  • 2016-03-07
相关资源
最近更新 更多