Làm thế nào để tạo một bộ đệm định hướng bằng arcpy?


9

Tôi muốn tạo một bộ đệm định hướng cho mọi đa giác trong shapefile của mình bằng arcpy. Theo định hướng tôi có nghĩa là tôi có hai góc a1 và a2 ràng buộc hướng của bộ đệm. Điều này được thể hiện trong biểu đồ dưới đây: nhập mô tả hình ảnh ở đây

Có ý kiến ​​gì không?


3
Người ta sẽ cần thêm thông tin về các góc. Trục nào bạn đang đo các góc từ? CW hay CCW? Làm thế nào để bạn xác định vị trí từng góc trên đa giác? Với những loại đa giác chúng ta đang đối phó? (Một vòng tròn không phải là đa giác.)
Paul

1
+1 thành @Paul nhưng tôi nghĩ một vòng tròn là một đa giác cho đến khi tôi đọc .
PolyGeo

+1 cũng vậy! Tôi đã sử dụng vòng tròn để minh họa dễ dàng vấn đề. Đa giác là kết quả của một phân đoạn trong Nhận thức điện tử theo sau là phân loại để xác định một lớp. Các góc a1 và a2 xuất phát từ góc phương vị chiếu sáng của ảnh vệ tinh được phân đoạn. Trong ví dụ, góc phương vị sẽ bằng 0, a1 và a2 bằng 0 +/- 15 ° (cố định tùy ý đến 15 °).
WAF

2
@PolyGeo "Đa giác" được sử dụng một chút khác biệt trong GIS so với toán học. Ở đây nó đề cập đến một đại diện kỹ thuật số của một khu vực (hai chiều) hoặc đóng cửa của nó . Các khu vực thường (nhưng không phải luôn luôn) được biểu thị bằng các xấp xỉ đa giác , nhưng - vì chúng ta biết các đại diện máy tính của chúng ta chỉ là xấp xỉ - chúng ta bỏ "xấp xỉ" và chỉ sử dụng "đa giác".
whuber

Câu trả lời:


20

Tóm lược

Câu trả lời này đặt câu hỏi vào ngữ cảnh lớn hơn, mô tả một thuật toán hiệu quả áp dụng cho biểu diễn các tính năng của shapefile (như "vectơ" hoặc "linestrings" của các điểm), hiển thị một số ví dụ về ứng dụng của nó và đưa ra mã làm việc để sử dụng hoặc chuyển vào một môi trường GIS.

Lý lịch

Đây là một ví dụ về sự giãn nở hình thái. Nói chung, một sự giãn nở "lan truyền" các điểm của một khu vực vào các khu vực lân cận của họ; bộ sưu tập các điểm mà chúng cuộn lên là "sự giãn nở". Các ứng dụng trong GIS có rất nhiều: mô hình hóa sự lan truyền của lửa, sự di chuyển của các nền văn minh, sự lan rộng của thực vật và nhiều hơn nữa.

Về mặt toán học, và nói chung là rất lớn (nhưng hữu ích), sự giãn nở lan truyền một tập hợp các điểm trong đa tạp Riemannian (như mặt phẳng, hình cầu hoặc ellipsoid). Sự lây lan được quy định bởi một tập hợp con của bó tiếp tuyến tại các điểm này. Điều này có nghĩa là tại mỗi một điểm, một tập các vectơ (hướng và khoảng cách) được đưa ra (tôi gọi đây là "vùng lân cận"); mỗi vectơ này mô tả một đường trắc địa bắt đầu tại điểm gốc của nó. Điểm cơ bản là "trải" đến cuối của tất cả các đường dẫn này. (Để biết định nghĩa hạn chế hơn về "sự giãn nở" thường được sử dụng trong xử lý ảnh, hãy xem bài viết Wikipedia . Hàm lan truyền được gọi là bản đồ theo cấp số nhân trong hình học vi phân.)

"Bộ đệm" của một tính năng là một trong những ví dụ đơn giản nhất về sự giãn nở như vậy: một đĩa có bán kính không đổi (bán kính bộ đệm) được tạo ra (ít nhất là về mặt khái niệm) xung quanh mỗi điểm của tính năng. Sự kết hợp của các đĩa này là bộ đệm.

Câu hỏi này yêu cầu tính toán độ giãn phức tạp hơn một chút trong đó sự lan truyền chỉ được phép xảy ra trong một phạm vi góc nhất định (nghĩa là trong một khu vực hình tròn). Điều này chỉ có ý nghĩa đối với các tính năng không có bề mặt cong đáng kể (chẳng hạn như các đặc điểm nhỏ trên hình cầu hoặc ellipsoid hoặc bất kỳ tính năng nào trong mặt phẳng). Khi chúng ta đang làm việc trong mặt phẳng, việc định hướng tất cả các lĩnh vực theo cùng một hướng cũng có ý nghĩa. (Tuy nhiên, nếu chúng ta mô hình hóa sự lan truyền của lửa bằng gió, chúng ta sẽ muốn các khu vực được định hướng theo gió và kích thước của chúng cũng có thể thay đổi theo tốc độ gió: đó là một động lực cho định nghĩa chung về sự giãn nở mà tôi đã đưa ra. ) (Trên các bề mặt cong như hình elip, nói chung không thể định hướng tất cả các khu vực theo hướng "giống nhau".)

Trong các trường hợp sau, sự giãn nở tương đối dễ dàng để tính toán:

  • Tính năng này nằm trong mặt phẳng (nghĩa là chúng tôi đang mở rộng bản đồ của tính năng và hy vọng bản đồ này khá chính xác).

  • Sự giãn nở sẽ không đổi : sự lan rộng tại mọi điểm của đối tượng địa lý sẽ xảy ra trong các vùng lân cận có cùng hướng.

  • Khu phố chung này là lồi. Convexity đơn giản hóa rất nhiều và tăng tốc độ tính toán.

Câu hỏi này phù hợp với các trường hợp chuyên biệt như vậy: nó yêu cầu sự giãn nở của các đa giác tùy ý bởi các cung tròn có nguồn gốc (trung tâm của các đĩa mà chúng đến) được đặt tại các điểm cơ sở. Với điều kiện những khu vực đó không kéo dài quá 180 độ, chúng sẽ bị lồi. (Các lĩnh vực lớn hơn luôn có thể được chia làm một nửa thành hai khu vực lồi; sự kết hợp của hai độ giãn nhỏ hơn sẽ cho kết quả mong muốn.)


Thực hiện

Bởi vì chúng tôi đang thực hiện các tính toán Euclide - thực hiện việc lan truyền trong mặt phẳng - chúng tôi có thể làm giãn một điểm chỉ bằng cách dịch vùng lân cận giãn nở đến điểm đó. (Để có thể làm điều này, khu phố cần có nguồn gốcđiều đó sẽ tương ứng với điểm cơ bản. Ví dụ, nguồn gốc của các lĩnh vực trong câu hỏi này là trung tâm của vòng tròn mà chúng được hình thành. Nguồn gốc này xảy ra để nằm trên ranh giới của ngành. Trong hoạt động đệm tiêu chuẩn của GIS, vùng lân cận là một vòng tròn có nguồn gốc ở trung tâm của nó; bây giờ nguồn gốc nằm trong phần bên trong của vòng tròn. Chọn một nguồn gốc không phải là một vấn đề lớn về mặt tính toán, bởi vì sự thay đổi nguồn gốc chỉ làm thay đổi toàn bộ sự giãn nở, nhưng nó có thể là một vấn đề lớn về mặt mô hình các hiện tượng tự nhiên. Các sectorchức năng trong các mã dưới đây minh họa cách một nguồn gốc có thể được xác định.)

Việc làm giãn một đoạn đường có thể khó khăn, nhưng đối với một vùng lân cận lồi, chúng ta có thể tạo ra sự giãn nở như là sự kết hợp của sự giãn nở của hai điểm cuối cùng với hình bình hành được chọn cẩn thận. (Vì lợi ích của không gian, tôi sẽ không tạm dừng để chứng minh các xác nhận toán học như thế này, nhưng khuyến khích người đọc thử bằng chứng của riêng họ vì đây là một bài tập sâu sắc.) Dưới đây là một minh họa sử dụng ba lĩnh vực (hiển thị màu hồng). Họ có bán kính đơn vị và góc của họ được đưa ra trong các tiêu đề. Đoạn đường có chiều dài 2, nằm ngang và được hiển thị màu đen:

Phân đoạn giãn

Các hình bình hành được tìm thấy bằng cách định vị các điểm màu hồng càng xa càng tốt so với đoạn theo hướng dọc . Điều này cho hai điểm thấp hơn và hai điểm trên dọc theo đường thẳng song song với đoạn. Chúng ta chỉ cần nối bốn điểm thành một hình bình hành (hiển thị bằng màu xanh). Ở bên phải, điều này có ý nghĩa như thế nào ngay cả khi bản thân khu vực đó chỉ là một đoạn thẳng (và không phải là một đa giác thực sự): ở đó, mọi điểm trên đoạn đã được dịch theo hướng 171 độ về phía bắc cho một khoảng cách từ 0 đến 1. Tập hợp các điểm cuối này là hình bình hành được hiển thị. Các chi tiết của tính toán này xuất hiện trong bufferhàm được định nghĩa trong dilate.edgesmã bên dưới.

Để làm giãn một đa tuyến , chúng ta tạo thành sự kết hợp của độ giãn của các điểm và các đoạn tạo thành nó. Hai dòng cuối cùng dilate.edgesthực hiện vòng lặp này.

Làm giãn một đa giác đòi hỏi bao gồm cả phần bên trong của đa giác cùng với sự giãn nở của ranh giới của nó. (Khẳng định này đưa ra một số giả định về vùng lân cận giãn nở. Một là tất cả các vùng lân cận đều chứa điểm (0,0), đảm bảo đa giác được bao gồm trong sự giãn nở của nó. điểm của đa giác sẽ không vượt ra ngoài sự giãn nở các điểm biên. Đây là trường hợp đối với các vùng lân cận không đổi.)

Chúng ta hãy xem xét một số ví dụ về cách thức hoạt động của nó, đầu tiên với một phi hình (được chọn để tiết lộ chi tiết) và sau đó với một vòng tròn (được chọn để khớp với hình minh họa trong câu hỏi). Các ví dụ sẽ tiếp tục sử dụng ba vùng lân cận giống nhau, nhưng được thu nhỏ lại thành bán kính 1/3.

Pha loãng của một nonagon

Trong hình này, phần bên trong của đa giác có màu xám, độ giãn điểm (cung) là màu hồng và độ giãn cạnh (hình bình hành) có màu xanh.

Sự giãn nở của một vòng tròn

"Vòng tròn" thực sự chỉ là 60 gon, nhưng nó gần đúng với một vòng tròn.


Hiệu suất

Khi tính năng cơ sở được biểu thị bằng N điểm và vùng lân cận giãn nở bằng điểm M, thuật toán này đòi hỏi nỗ lực O (N M) . Nó phải được theo dõi bằng cách đơn giản hóa sự lộn xộn của các đỉnh và cạnh trong liên kết, điều này có thể đòi hỏi nỗ lực O (N M log (N M)): đó là điều cần yêu cầu GIS thực hiện; chúng ta không nên lập trình điều đó.

Nỗ lực tính toán có thể được cải thiện thành O (M + N) cho các tính năng cơ sở lồi (vì bạn có thể tìm ra cách di chuyển xung quanh ranh giới mới bằng cách hợp nhất các danh sách các đỉnh mô tả ranh giới của hai hình dạng ban đầu). Điều này cũng không cần làm sạch sau này.

Khi vùng lân cận giãn nở từ từ thay đổi kích thước và / hoặc hướng khi bạn tiến triển xung quanh tính năng cơ sở, độ giãn của cạnh có thể được xác định gần đúng từ vỏ lồi của sự kết hợp các điểm cuối của nó. Nếu hai vùng lân cận giãn nở có điểm M1 và M2, điều này có thể được tìm thấy với nỗ lực O (M1 + M2) bằng thuật toán được mô tả trong Shamos & Prepata, Hình học tính toán . Do đó, đặt K = M1 + M2 + ... + M (N) là tổng số đỉnh trong vùng lân cận N, chúng ta có thể tính toán độ giãn nở trong thời gian O (K * log (K)).

Tại sao chúng ta muốn giải quyết một khái quát như vậy nếu tất cả những gì chúng ta muốn là một bộ đệm đơn giản? Đối với các đối tượng địa lý lớn trên trái đất, vùng lân cận giãn nở (như đĩa) có kích thước không đổi trong thực tế có thể có kích thước khác nhau trên bản đồ nơi các phép tính này được thực hiện. Do đó, chúng tôi có được một cách để thực hiện các phép tính chính xác cho ellipsoid trong khi tiếp tục tận hưởng tất cả các lợi thế của hình học Euclide.


Các ví dụ được tạo ra với Rnguyên mẫu này , có thể dễ dàng chuyển sang ngôn ngữ yêu thích của bạn (Python, C ++, v.v.). Về cấu trúc, nó tương đồng với phân tích được báo cáo trong câu trả lời này và do đó không cần giải thích riêng. Bình luận làm rõ một số chi tiết.

(Nó có thể là thú vị để lưu ý rằng tính toán lượng giác được sử dụng duy nhất để tạo ra các tính năng chẳng hạn - đó là đa giác thường xuyên -. Và các lĩnh vực Không một phần của phép tính giãn nở đòi hỏi bất kỳ lượng giác.)

#
# Dilate the vertices of a polygon/polyline by a shape.
#
dilate.points <- function(p, q) {
  # Translate a copy of `q` to each vertex of `p`, resulting in a list of polygons.
  pieces <- apply(p, 1, function(x) list(t(t(q)+x)))
  lapply(pieces, function(z) z[[1]]) # Convert to a list of matrices
}
#
# Dilate the edges of a polygon/polyline `p` by a shape `q`. 
# `p` must have at least two rows.
#
dilate.edges <- function(p, q) {
  i <- matrix(c(0,-1,1,0), 2, 2)       # 90 degree rotation
  e <- apply(rbind(p, p[1,]), 2, diff) # Direction vectors of the edges
  # Dilate a single edge from `x` to `x+v` into a parallelogram
  # bounded by parts of the dilation shape that are at extreme distances
  # from the edge.
  buffer <- function(x, v) {
    y <- q %*% i %*% v # Signed distances orthogonal to the edge
    k <- which.min(y)  # Find smallest distance, then the largest *after* it
    l <- (which.max(c(y[-(1:k)], y[1:k])) + k-1) %% length(y)[1] + 1
    list(rbind(x+q[k,], x+v+q[k,], x+v+q[l,], x+q[l,])) # A parallelogram
  }
  # Apply `buffer` to every edge.
  quads <- apply(cbind(p, e), 1, function(x) buffer(x[1:2], x[3:4]))
  lapply(quads, function(z) z[[1]]) # Convert to a list of matrices
}
#----------------------- (This ends the dilation code.) --------------------------#
#
# Display a polygon and its point and edge dilations.
# NB: In practice we would submit the polygon, its point dilations, and edge 
#     dilations to the GIS to create and simplify their union, producing a single
#     polygon.  We keep the three parts separate here in order to illustrate how
#     that polygon is constructed.
#
display <- function(p, d.points, d.edges, ...) {
  # Create a plotting region covering the extent of the dilated figure.
  x <- c(p[,1], unlist(lapply(c(d.points, d.edges), function(x) x[,1])))
  y <- c(p[,2], unlist(lapply(c(d.points, d.edges), function(x) x[,2])))
  plot(c(min(x),max(x)), c(min(y),max(y)), type="n", asp=1, xlab="x", ylab="y", ...)
  # The polygon itself.
  polygon(p, density=-1, col="#00000040")
  # The dilated points and edges.
  plot.list <- function(l, c) lapply(l, function(p) 
                  polygon(p, density=-1, col=c, border="#00000040"))
  plot.list(d.points, "#ff000020")
  plot.list(d.edges, "#0000ff20")
  invisible(NULL) # Doesn't return anything
}
#
# Create a sector of a circle.
# `n` is the number of vertices to use for approximating its outer arc.
#
sector <- function(radius, arg1, arg2, n=1, origin=c(0,0)) {
  t(cbind(origin, radius*sapply(seq(arg1, arg2, length.out=n), 
                  function(a) c(cos(a), sin(a)))))
}
#
# Create a polygon represented as an array of rows.
#
n.vertices <- 60 # Inscribes an `n.vertices`-gon in the unit circle.
angles <- seq(2*pi, 0, length.out=n.vertices+1)
angles <- angles[-(n.vertices+1)]
polygon.the <- cbind(cos(angles), sin(angles))
if (n.vertices==1) polygon.the <- rbind(polygon.the, polygon.the)
#
# Dilate the polygon in various ways to illustrate.
#
system.time({
  radius <- 1/3
  par(mfrow=c(1,3))
  q <- sector(radius, pi/12, 2*pi/3, n=120)
  d.points <- dilate.points(polygon.the, q)
  d.edges <- dilate.edges(polygon.the, q)
  display(polygon.the, d.points, d.edges, main="-30 to 75 degrees")

  q <- sector(radius, pi/3, 4*pi/3, n=180)
  d.points <- dilate.points(polygon.the, q)
  d.edges <- dilate.edges(polygon.the, q)
  display(polygon.the, d.points, d.edges, main="-150 to 30 degrees")

  q <- sector(radius, -9/20*pi, -9/20*pi)
  d.points <- dilate.points(polygon.the, q)
  d.edges <- dilate.edges(polygon.the, q)
  display(polygon.the, d.points, d.edges, main="171 degrees")
})

Thời gian tính toán cho ví dụ này (từ hình cuối cùng), với N = 60 và M = 121 (trái), M = 181 (giữa) và M = 2 (phải), là một phần tư giây. Tuy nhiên, hầu hết điều này là dành cho màn hình. Thông thường, Rmã này sẽ xử lý khoảng N M = 1,5 triệu mỗi giây (chỉ mất 0,002 giây hoặc lâu hơn để thực hiện tất cả các tính toán ví dụ được hiển thị). Tuy nhiên, sự xuất hiện của sản phẩm M N ngụ ý sự giãn nở của nhiều số liệu hoặc số liệu phức tạp thông qua một vùng lân cận chi tiết có thể mất thời gian đáng kể, vì vậy hãy cẩn thận! Điểm chuẩn thời gian cho các vấn đề nhỏ hơn trước khi giải quyết một vấn đề lớn. Trong những trường hợp như vậy, người ta có thể tìm đến một giải pháp dựa trên raster ( dễ thực hiện hơn nhiều , về cơ bản chỉ cần một phép tính lân cận.)


Wow, đó là rất chi tiết và hấp dẫn. Tôi đã không mong đợi ít hơn.
Paul

1

Điều này khá rộng, nhưng bạn có thể:

  1. đệm đa giác ban đầu
  2. tìm điểm gốc của các tia "định hướng" sẽ được tạo trên ranh giới đa giác (một số loại điểm tiếp tuyến?)
  3. tạo / mở rộng một dòng từ điểm đó đến một khoảng cách ngoài bộ đệm bằng cách sử dụng góc được thảo luận trong các nhận xét cho câu hỏi.
  4. cắt đường đó với bộ đệm và đa giác ban đầu. Điều này có thể được thực hiện cùng lúc với 3) với các đối số thích hợp để mở rộng.
  5. trích xuất đa giác "bộ đệm định hướng" mới từ tập hợp đa giác tổng hợp

Tôi tin rằng OP có nghĩa là "bộ đệm định hướng" theo nghĩa là sự giãn nở hình thái của mỗi hình dạng bởi một khu vực của một vòng tròn. (Mô tả này ngay lập tức đưa ra một giải pháp raster; nhưng vì shapefile là ở định dạng vector, một giải pháp vector sẽ được mong muốn Đó là khó khăn để làm..)
whuber

Hy vọng OP sẽ làm rõ điểm đó. Tôi đi vào dòng suy nghĩ của mình dựa trên đồ họa, không phải lúc nào cũng an toàn nhất. Ở mức độ nào, mặc dù người ta có thể đặt một hình dạng bất thường của các ô so với vị trí được tính toán (tôi đã làm nó trong lưới di động ... Tôi cảm thấy cũ!), Tôi nghĩ rằng một giải pháp vectơ sẽ làm sạch / tận dụng các chức năng vectơ của Arc tốt hơn . Phương pháp chung có lẽ là tương tự, bất kể mô hình dữ liệu. Có thể thêm một chút mã hóa cho người dùng ở phía raster.
Roland

Trên thực tế, không có mã hóa cần thiết ở phía raster :-). Nó có thể được thực hiện theo nhiều cách, bao gồm các chỉ số tiêu cự với một vùng lân cận được xác định phù hợp. Tôi đồng ý rằng một giải pháp vectơ thích hợp hơn ở đây: sạch hơn và chính xác hơn. Tuy nhiên, đối với các bộ dữ liệu cực lớn hoặc phức tạp, nó có thể làm hỏng, tuy nhiên, trong khi một giải pháp raster sẽ nhanh, do đó, luôn luôn đáng để biết cách thực hiện cả hai cách.
whuber

Suy nghĩ lãng phí về tiêu điểm , nhưng không chắc hình dạng + góc của OP có khó kết hợp thành một vùng lân cận hay không .
Roland

Chỉ có khu vực phải được mô tả bởi các khu phố, đó là dễ dàng để làm .
whuber
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.