래스터 처리를 사용하여 점이 둘러싸여 있는지 확인


9

자연 위험 모델에 대해 현재 매우 번거로운 벡터 / 파이썬 프로세스를 개선하려고합니다. 현재 우리는 주어진 지점에서 거리 / 베어링 선을 생성하여 다음을 결정하는 긴 스크립트를 가지고 있습니다.

  1. 교차하는 다각형의 유형 (예 : 산림, 잔디, 늪 등)
  2. 그 다각형까지의 거리
  3. 이 선들 중 얼마나 많은 선이 다각형과 교차하여 얼마나 '주변'인지 결정합니다.

더 많은 관련이 있지만 그것이 핵심입니다. 나는 이것을 개선하는 방법을 찾으려고 노력하고 있으며 현재 3 부에 휩싸였다. 아이디어는 점이 200m 이내에 다각형으로 완전히 둘러싸여 있는지 확인하는 것입니다.PointB는 ~ 50 %에 불과한 반면 PointA는 둘러싸여 있습니다.

첨부 된 이미지에서 점 A가 다각형으로 완전히 둘러싸여 있기 때문에 점 A보다 위험이 높은 것으로 표시하고 싶습니다. 이 작업은 약 1,300 만 점에 대해 반복되므로 작은 작업이 아니며 스크립트를 실행하는 대신 값을 도출 할 수있는 표면을 갖고 싶습니다. 수 문학 도구 또는 비용 경로의 변형이 있어야한다고 생각하지만 머리를 감쌀 수는 없습니다.

이 문제를 어떻게 해결할 수 있습니까?


1
Viewshed 는 작업에 달려 있지만 1,300 만 포인트에 적용될 때 상당한 도움이 필요합니다! 직경이 200m 미만인 다각형 외부 영역에있는 점 (예 : "A"는 제외 할 수 있지만 "B"는 제외)과 같이 주변을 쉽게 확인할 수있는 점을 제거하는 방법에 대해 먼저 생각해보십시오. "B"는 뷰 쉐드 (폴리곤 영역을 뷰를 차단하는 "높은"위치로 취함)가 B의 위치에서 200m 이상 연장되기 때문에 배제되지 않습니다.
whuber

좋은 점 @ whuber. 확실히 나는 근접 촬영과 실제로 유일한 위도에 의해 실제로 처리 된 총 포인트 수를 줄일 수 있습니다 (지오 코드 주소를 말하고 있으므로 아파트 블록을 50 포인트에서 1로 줄일 수는 있지만). 수백만 곳에서 필요한 경우 모든 것을 겹치는 블록으로 나눌 수도 있습니다. 조회수를 조사합니다. 감사!
Loz

또 다른 빠른 화면은 고리 모양의 이웃을 사용하여 다각형의 0-1 표시기 격자의 초점 평균을 계산하는 것입니다. 값이 1 인 모든 셀에서 다각형은 둘러싸 야 할 때 반경에서 전체 둘레를 차지합니다. 이것은 빠른 계산이며, 위치와 다각형이 얼마나 복잡한 지에 따라 대부분의 포인트를 제거 할 수 있습니다. 먼저 그리드를 25-50m 정도의 더 거친 해상도로 리샘플링하여 초기 스크리닝 속도를 높일 수도 있습니다.
whuber

또 다른 잠재적 인 처리 단계 또는 전처리 단계는 포인트 주변의 통계를 비교하여 래스터 화 된 데이터 세트 버전을 통해 포인트를 전달하는 것입니다. '주변의'요구 사항을 포인트 주변의 통계로 요약하거나 '주변'이 필요한 경우 래스터 이웃을 사용하여 '쉬운'포인트 (예 : 위험 영역 내에있는 포인트)를 찾을 수 있습니다. 모든 점에서 '쉬운'점을 구문 분석 한 다음 나머지 점에 대해 벡터 분석을 사용하십시오.
DPierce

와우 내 쿼리는 확실히 많은 관심을 불러 일으켰습니다! 제안과 의견을 주신 모든 분들께 감사드립니다. 나는 그들 모두를 통해 내 방식대로 일하고 응답 할 것이지만 그들은 모두 테스트하는 데 약간의 시간이 걸릴 것입니다. 나는 결국 응답하겠다고 약속한다!
Loz

답변:


6

비용 경로 솔루션이 있지만 직접 코딩해야합니다. 다음은 문제의 이미지에서 모든 지점에 적용될 때의 모습입니다 (계산 속도를 높이기 위해 조금 조잡했습니다).

그림 0

검은 셀은 주변 다각형의 일부입니다. 연한 주황색 (짧은 색)에서 파란색 (긴색)까지의 색상은 다각형 셀을 가로 채지 않고 시선 통과를 통해 도달 할 수있는 최대 거리 (최대 50 셀까지)를 나타냅니다. 이 이미지의 범위를 벗어난 모든 셀은 다각형의 일부로 처리됩니다.

데이터의 래스터 표현을 사용하여이를 수행하는 효율적인 방법을 논의 해 봅시다. 이 표현에서, 모든 "주변"다각형 셀은 0이 아닌 값을 가질 것이고 "탐색"될 수있는 임의의 셀은 0을 가질 것이다.

1 단계 : 주변 데이터 구조 사전 계산

먼저 한 셀이 다른 셀을 차단하는 것이 무엇을 의미하는지 결정해야합니다. 내가 찾을 수있는 가장 공정한 규칙 중 하나는 행과 열에 적분 좌표를 사용하고 정사각형 셀을 가정하여 어느 셀이 원점 (0,0)의보기에서 셀 (i, j)을 차단 할 수 있는지 고려해 보겠습니다. 좌표가 i 및 j와 최대 1이 다른 모든 셀 중에서 (i, j)에서 (0,0)을 연결하는 선 세그먼트에 가장 가까운 셀 (i ', j')을 추천합니다. (i, j) = (1,2) (0,1) 및 (1,1) 모두 동일하게 작동하는 고유 한 솔루션을 생성하려면 관계를 해결하는 몇 가지 수단이 필요합니다. 이 관계가 그리드에서 원형 이웃의 대칭을 존중하는 것이 좋을 것입니다. 좌표를 부정하거나 좌표를 전환하면 이러한 이웃이 보존됩니다. 따라서 우리는 어느 세포를 차단할지 결정할 수 있습니다 (i,

이 규칙을 보여주는 것은로 작성된 다음과 같은 프로토 타입 코드입니다 R. 이 코드는 그리드에서 임의의 셀의 "주변"을 결정하는 데 편리한 데이터 구조를 반환합니다.

screen <- function(k=1) {
  #
  # Returns a data structure:
  #   $offset is an array of offsets
  #   $screened is a parallel array of screened offset indexes.
  #   $distance is a parallel array of distances.
  # The first index always corresponds to (0,0).
  #
  screened.by <- function(xy) {
    uv <- abs(xy)
    if (reversed <- uv[2] > uv[1]) {
      uv <- rev(uv)
    }
    i <- which.min(c(uv[1], abs(uv[1]-uv[2]), uv[2]))
    ij <- uv + c(floor((1-i)/3), floor(i/3)-1)
    if (reversed) ij <- rev(ij)
    return(ij * sign(xy))
  }
  #
  # For each lattice point within the circular neighborhood,
  # find the unique lattice point that screens it from the origin.
  #
  xy <- subset(expand.grid(x=(-k:k), y=(-k:k)), 
               subset=(x^2+y^2 <= k^2) & (x != 0 | y != 0))
  g <- t(apply(xy, 1, function(z) c(screened.by(z), z)))
  #
  # Sort by distance from the origin.
  #
  colnames(g) <- c("x", "y", "x.to", "y.to")
  ij <- unique(rbind(g[, 1:2], g[, 3:4]))
  i <- order(abs(ij[,1]), abs(ij[,2])); ij <- ij[i, , drop=FALSE]
  rownames(ij) <- 1:length(i)
  #
  # Invert the "screened by" relation to produce the "screened" relation.
  #
  # (Row, column) offsets.
  ij.df <- data.frame(ij, i=1:length(i))
  #
  # Distances from the origin (in cells).
  distance <- apply(ij, 1, function(u) sqrt(sum(u*u)))
  #
  # "Screens" relation (represented by indexes into ij).
  g <- merge(merge(g, ij.df), ij.df, 
             by.x=c("x.to", "y.to"), by.y=c("x","y"))
  g <- subset(g, select=c(i.x, i.y))
  h <- by(g$i.y, g$i.x, identity)

  return( list(offset=ij, screened=h, distance=distance) )
}

값은 screen(12)이 스크리닝 관계를 묘사하는 데 사용되었습니다. 화살표는 셀에서 해당 셀을 즉시 스크리닝하는 화살표를 가리 킵니다. 색조는이 이웃의 중앙에있는 원점까지의 거리에 따라 비례합니다.

그림 1

이 계산은 빠르며 특정 이웃에 대해 한 번만 수행하면됩니다. 예를 들어, 5m 셀이있는 그리드에서 200m를 볼 때 주변 크기는 200/5 = 40 단위입니다.

2 단계 : 선택한 점에 계산 적용

나머지는 간단합니다. (x, y) (행 및 열 좌표로)에 위치한 셀이이 주변 데이터 구조와 관련하여 "주변"되는지 확인하려면 (i, j)의 오프셋으로 재귀 적으로 테스트를 수행하십시오. = (0,0) (이웃 원점). (x, y) + (i, j)에서 다각형 격자의 값이 0이 아닌 경우 가시성이 차단됩니다. 그렇지 않으면, 오프셋 (i, j)에서 차단 될 수있는 모든 오프셋을 고려해야합니다 screen. 차단 된 것이 없으면 주변에 도달하여 (x, y)가 둘러싸이지 않았다고 결론을 내립니다. 따라서 계산을 중지합니다 (근처의 나머지 지점을 검사하지 않아도됩니다).

알고리즘 중에 도달 한 가장 먼 가시 거리를 추적하여 훨씬 유용한 정보를 수집 할 수 있습니다. 이것이 원하는 반경보다 작 으면 셀이 둘러싸입니다. 그렇지 않으면 그렇지 않습니다.

다음은 R이 알고리즘 의 프로토 타입입니다. R재귀를 구현하는 데 필요한 (단순한) 스택 구조를 기본적으로 지원하지 않기 때문에 스택이 코딩되어야하기 때문에 예상보다 길다 . 실제 알고리즘은 약 3 분의 2에서 시작하며 12 줄 정도만 필요합니다. (그들 중 절반은 그리드 주변의 상황을 처리하고 이웃 지역의 범위를 벗어난 인덱스를 확인합니다. 다각형 그리드를 k주변의 행과 열로 확장하여 더 효율적으로 만들 수 있습니다. 다각형 그리드를 유지하기 위해 약간의 RAM 비용으로 인덱스 범위 검사가 필요합니다.)

#
# Test a grid point `ij` for a line-of-sight connection to the perimeter
# of a circular neighborhood.  
#   `xy` is the grid.
#   `counting` determines whether to return max distance or count of stack ops.
#   `perimeter` is the assumed values beyond the extent of `xy`.
#
# Grid values of zero admit light; all others block visibility
# Returns maximum line-of-sight distance found within `nbr`.
#
panvisibility <- function(ij, xy, nbr=screen(), counting=FALSE, perimeter=1) {
  #
  # Implement a stack for the algorithm.
  #
  count <- 0 # Stack count
  stack <- list(ptr=0, s=rep(NA, dim(nbr$offset)[1]))
  push <- function(x) {
    n <- length(x)
    count <<- count+n         # For timing
    stack$s[1:n + stack$ptr] <<- x
    stack$ptr <<- stack$ptr+n
  }
  pop <- function() {
    count <<- count+1         # For timing
    if (stack$ptr <= 0) return(NULL)
    y <- stack$s[stack$ptr]
    #stack$s[stack$ptr] <<- NA # For debugging
    stack$ptr <<- stack$ptr - 1
    return(y)
  }
  #
  # Initialization.
  #
  m <- dim(xy)[1]; n <- dim(xy)[2]
  push(1) # Stack the *indexes* of nbr$offset and nbr$screened.
  dist.max <- -1
  #
  # The algorithm.
  #
  while (!is.null(i <- pop())) {
    cell <- nbr$offset[i, ] + ij
    if (cell[1] <= 0 || cell[1] > m || cell[2] <= 0 || cell[2] > n) {
      value <- perimeter
    } else {  
      value <- xy[cell[1], cell[2]]
    }
    if (value==0) {
      if (nbr$distance[i] > dist.max) dist.max <- nbr$distance[i]
      s <- nbr$screened[[paste(i)]]
      if (is.null(s)) {
        #exited = TRUE
        break
      }
      push(s)
    }
  }
  if (counting) return ( count )
  return(dist.max)
}

그림 2 : 예

이 예에서 다각형 셀은 검은 색입니다. 색상은 비 다각형 셀에 대한 최대 가시 거리 (50 셀까지)를 제공합니다. 단거리는 연한 주황색에서 가장 먼 거리는 진한 파란색까지 다양합니다. (세포는 한 단위 너비와 높이입니다.) 눈에 띄는 줄무늬는 "강"의 중간에있는 작은 다각형 "섬"에 의해 만들어집니다. 각 줄무늬는 다른 세포의 긴 줄을 차단합니다.

알고리즘 분석

스택 구조는 셀이 둘러싸 이지 않았다는 증거에 대한 이웃 가시성 그래프의 깊이 우선 검색을 구현합니다 . 셀이 다각형과 멀리 떨어져있는 경우이 검색에서는 반경 k 원형 이웃에 대한 O (k) 셀만 검사해야합니다. 최악의 경우는 이웃 내에 흩어져있는 다각형 셀이 적을 때도 발생하지만 이웃의 경계에 도달 할 수는 없습니다. 각 이웃의 거의 모든 셀을 검사해야합니다 .O (k ^ 2) 조작.

다음은 일반적으로 발생하는 동작입니다. k가 작은 값의 경우, 다각형이 대부분의 그리드를 채우지 않는 한 대부분의 비 다각형 셀은 분명히 둘러싸이지 않으며 알고리즘은 O (k)와 같이 확장됩니다. 중간 값의 경우 스케일링은 O (k ^ 2)처럼 보입니다. k가 실제로 커지면 대부분의 셀이 둘러싸이고 전체 이웃을 검사하기 전에 사실을 알 수 있습니다. 그러므로 알고리즘의 계산 노력이 실제 한계에 도달합니다. 이 한계는 인접 반경이 그리드에서 연결된 가장 큰 비-다각형 영역의 직경에 도달 할 때 달성됩니다.

예를 들어, counting프로토 타입에 코딩 된 옵션을 screen사용하여 각 호출에 사용 된 스택 작업 수를 반환합니다. 이것은 계산 노력을 측정합니다. 다음 그래프는 인접 반경의 함수로 평균 스택 연산 수를 나타냅니다. 예상되는 동작을 보여줍니다.

그림 3

이를 사용하여 그리드에서 1,300 만 포인트를 평가하는 데 필요한 계산을 추정 할 수 있습니다. k = 200/5 = 40의 이웃이 사용되었다고 가정하십시오. 그런 다음 평균적으로 수백 개의 스택 작업이 필요합니다 (다각형 그리드의 복잡성과 다각형에 대해 1 천 3 백만 개의 지점이있는 위치에 따라 다름). 효율적인 컴파일 된 언어에서 최대 수천 개의 간단한 숫자 연산을 의미합니다. 추가, 곱하기, 읽기, 쓰기, 오프셋 등이 필요합니다. 대부분의 PC는 그 속도로 약 백만 포인트의 포 위성을 평가할 수 있습니다. (그만큼R구현은 이런 종류의 알고리즘이 열악하기 때문에 그보다 훨씬 느리므로 프로토 타입으로 만 간주 될 수 있습니다.) 따라서 우리는 합리적으로 효율적이고 적절한 언어 인 C ++로 효율적인 구현을 희망 할 수 있습니다. 파이썬은 모든 다각형 그리드가 RAM에 있다고 가정하면 1 분 안에 1,300 만 포인트의 평가를 완료 할 수 있습니다.

그리드가 너무 커서 RAM에 맞지 않으면이 절차를 그리드의 타일 부분에 적용 할 수 있습니다. k행과 열만 겹치면됩니다 . 결과를 모자이크 처리 할 때 겹치는 부분을 최대한 활용하십시오.

다른 응용

바디 물 "페치" 밀접 포인트 "surroundedness"에 관한 것이다. 실제로, 우리가 수역의 지름보다 크거나 같은 이웃 반경을 사용한다면, 우리는 수역의 모든 지점에서 (비 방향성) 페치 그리드를 생성 할 것입니다. 더 작은 인접 반경을 사용함으로써 우리는 적어도 모든 최고 반입 지점에서 반입에 대한 하한을 얻습니다. 특정 방향과의 "차단 기준"관계를 제한하는이 알고리즘의 변형은 해당 방향으로 효율적으로 페치를 계산하는 한 가지 방법입니다. 이러한 변형은 코드를 수정해야합니다 screen. 에 대한 코드 panvisibility는 전혀 변경되지 않습니다.


2

래스터 솔루션을 사용 하여이 작업을 수행하는 방법을 확실히 알 수 있지만 포인트 수를 줄이면 매우 큰 / 고해상도를 기대할 수 있으므로 그리드 또는 그리드 세트를 처리하기가 어렵습니다. 이를 감안할 때 gdb에서 토폴로지를 활용하는 것이 더 효율적인지 궁금합니다. 다음과 같은 방법으로 모든 내부 공극을 찾을 수 있습니다.

arcpy.env.workspace = 'myGDB'
arcpy.CreateTopology_management('myGDB', 'myTopology', '')    
arcpy.AddFeatureClassToTopology_management('myTopology', 'myFeatures', '1','1')    
arcpy.AddRuleToTopology_management ('myToplogy', 'Must Not Have Gaps (Area)', 'myFeatures', '', '', '')    
arcpy.ValidateTopology_management('myTopology', 'Full_Extent')
arcpy.ExportTopologyErrors_management('myTopology', 'myGDB', 'topoErrors')
arcpy.FeatureToPolygon_management('topoErrors_line','topoErrorsVoidPolys', '0.1')`

그런 다음 topoErrorsVoidPolys일반적인 패턴 Intersect_analysis()이나 그 밖의 방식으로 작업 할 수 있습니다 . 에서 관심있는 폴리를 추출하는 데 문제가있을 수 있습니다 topoErrorsVoidPolys. @ whuber는 gis.stackexchange.com의 다른 곳에서 이런 종류의 훌륭한 게시물을 많이 가지고 있습니다.


흥미로운 전처리 아이디어입니다. 200m 제한 (버퍼링 및 교차로 등)을 쉽게 통합 할 수 있다고 생각합니다. GIS에는 문제에 대한 해결책이 순전히 래스터 기반 또는 순전히 벡터 기반이어야한다고 말하는 규칙이 없습니다. 여기에서 제안한 것처럼 정확하게 수행하면 상당한 이점이있을 수 있습니다.
whuber

0

당신이 정말로 래스터를 원한다면 ...이 의사 코드의 라인을 따라 무언가를 할 것입니다 (단지 내가 AML 후퇴 자라는 것을 분명히하기 때문에 울지 마십시오! : p)

  1. 점 ( "pts_g") 및 폴리 ( "polys_g"(
  2. 공극 = regiongroup (con (isnull (polys_g), 1))
  3. 원하지 않는 외부 다각형 / 개방형 우주 영역을 제거하기 위해 공극을 다듬기 위해 무언가를해야 할 수도 있습니다.
  4. pts_surrounded = con (voids, pts_g)

그런 종류의 구성이므로 개선이 필요할 수 있습니다.


귀하의 솔루션은 제한 거리 (예 : 200m)를 참조하지 않으므로 질문에 올바르게 응답하지 않는 것 같습니다.
whuber

네가 옳아. 이것은 나의 다른 대답에도 적용됩니다. 나는 하나를 사용할 수 있다고 생각 Expand()하지만 그 시점에서 @radouxju의 대답은 기능적으로 동일하고 아마도 더 빠를 것이라고 생각할 것입니다. (보기에 반대하는 것은 없으며 많이 사용하지 마십시오).
Roland

시간이 다되었을 때 편집하려고했습니다. Expand()말 을 확장 pts_g하고을 사용 Con()하여 교차 하고 싶습니다 polys_g.
Roland

0

임계 거리 값을 사용하는 경우 (여기서는 약 200m) 벡터 분석을 사용하는 것이 가장 좋습니다.

1) 각 점 주위에 200m 버퍼를 만듭니다 (그림에서 검은 색).

2) 버퍼와 다각형 (그림에서 파란색) 사이에 교차 도구 (분석)를 사용하십시오. 주변 폴리곤의 경계와 버퍼 사이에서이 작업을 수행하면 더 좋아 보이지만 최종 결과는 같습니다.

3) 기능을 다각형에 사용 (관리)하여 점이 완전히 둘러싸여있는 다각형을 만듭니다 (그림에서 빨간색).

4) 위치 (관리) 또는 공간 결합 (분석)별로 레이어를 선택하여 둘러싸는 점을 식별합니다. 공간 결합을 사용하면 추가 처리에 유용 할 수있는 임베딩 다각형 (다각형 영역, 영역 통계 ...)에 대한 정보를 가질 수 있습니다.

대안 2b) 필요에 따라 200m 거리 내에서 주변 다각형을 위치별로 선택할 수 있으며 2)에서와 같이 엄격하지 않은 일부 "인클로저"를 식별 할 수 있습니다.

여기에 이미지 설명을 입력하십시오

"미로 사건"을 고려하면, 이것은 위치에서 "탈출"하는 시간을 평가하는 데 도움이 될 수 있습니다.

  • 완전히 포함되었거나 완전히 무료 인 점을 분석에서 이미 제외 할 수 있습니다

  • 그런 다음 장애물을 래스터로 변환하고 다각형이있는 경우 값을 NoData로 설정하고 그렇지 않은 경우 미터 단위의 셀 크기로 설정하면 비용이 래스터가됩니다.

  • 셋째, 새로 생성 된 비용 래스터를 사용하여 비용 거리를 계산할 수 있습니다

  • 마지막으로, 래스터로 변환 된 버퍼 경계 (환형 형성)를 기반으로 구역 통계를 테이블로 사용합니다. 모든 방향으로 벗어날 수있는 경우 분석의 셀 크기에 따라 최소값은 약 200이어야합니다. 그러나 미로에 있다면 최대 값은 200보다 큽니다. 따라서 영역 통계의 최대 값에서 200을 뺀 값은 "탈출"이 얼마나 어려운지를 나타내는 연속적인 값입니다.


"서라운드"의 정의를 명확히하십시오. 이 질문에 대한 설명은 다각형의 일부가 그 점 주위의 모든 방향 (200m 거리까지) 으로 보일 때 점이 "주변"으로 간주되어야한다고 제안합니다 . 3 단계에서 정확히 어떻게 테스트합니까? (벡터 분석을 사용하는 것은 쉽지 않습니다!)
whuber

나는 작은 그림을 추가했습니다. 그렇게 설명하기가 더 쉽습니다. 버퍼가 모든 방향으로 다각형과 교차하지 않으면 루프가 닫히지 않습니다. 루프가 닫히지 않으면 다각형이 만들어지지 않습니다.
radouxju

"loop"또는 "closed"의 의미를 잘 모르겠습니다. 반경 r의 원 (200m 미만)이 다각형 내에 완전히 포함되지 않은 경우에도 점은 "주변"이 될 수 있습니다. 미로의 생각 : 다각형은 미로의 복도를 제외한 모든 입니다. 미로에서 벗어날 수는 있지만, 미로의 외부는 미로의 외부를 볼 수 없다는 의미에서 "주변"이됩니다.
whuber

내 이해로 말미암아, 당신이 탈출 할 수없는 곳을 둘러싼 의미합니다. ilustration에서 B에서 벗어날 수는 있지만 A에서 벗어날 수는 없습니다. 반면에 뷰 쉐드를 사용하면 B가 둘러싸여있는 것처럼 보입니다 (이미지에 스케일 막대가 없으므로 200m가 아닐 수도 있습니다). 모든 방향을 볼 때 다각형 경계를 참조하십시오). @Loz
radouxju의

만약 "이스케이프 할 수 없음"이 점검 기준이된다면 이것은 어려운 문제가되지 않을 것입니다. 나는 그 질문, 특히 가능한 모든 베어링을 보는 것에 대한 언급을 면밀히 읽으면 "주변"이 의도 된 의미를 명확하게 밝힌다 고 생각한다.
whuber
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.