Tính khoảng cách tối đa trong đa giác theo hướng x (hướng đông-tây) trong PostGIS?


13

Tôi quan tâm đến chiều rộng tối đa của một đa giác, ví dụ như một cái hồ, theo hướng đông tây. Các hộp giới hạn sẽ chỉ giúp trong các đa giác đơn giản chứ không phải trong các đa giác lõm phức tạp.


3
Tôi không quen với chức năng postgis. Tuy nhiên, có thể có một công cụ hộp giới hạn. Chiều rộng của khung giới hạn sẽ là khoảng cách tối đa theo hướng EW.
Fezter

4
@Fetzter điều đó không chính xác: một ví dụ mẫu, ngay cả đối với một đa giác phức tạp đơn giản, là một hình thoi mỏng kéo dài từ SW đến NE. Chiều rộng đông-tây tối đa của nó có thể là một phần nhỏ tùy ý chiều rộng của hộp giới hạn của nó.
whuber

1
Tôi đã tạo ra một tiện ích cho nhiệm vụ này dựa trên điều này và các đề xuất này . Nó có thể tính chiều rộng tối đa hoặc tối thiểu của đa giác. Hiện tại nó hoạt động với một tệp shp, nhưng bạn có thể viết lại để hoạt động với PostGIS hoặc chỉ chờ một thời gian cho đến khi nó phát triển thành plugin QGIS cũng sẽ hoạt động với PostGIS. Mô tả chi tiết và liên kết tải về tại đây .
SS_Rebelious

Câu trả lời:


16

Điều này có thể yêu cầu một số kịch bản trong bất kỳ nền tảng GIS.

Phương pháp hiệu quả nhất (không có triệu chứng) là quét đường thẳng đứng: nó yêu cầu sắp xếp các cạnh theo tọa độ y tối thiểu của chúng và sau đó xử lý các cạnh từ dưới cùng (tối thiểu y) đến đầu (tối đa y), cho nhật ký O (e * ( e)) thuật toán khi các cạnh e có liên quan.

Thủ tục, mặc dù đơn giản, nhưng đáng ngạc nhiên là khó khăn để có được đúng trong mọi trường hợp. Đa giác có thể khó chịu: chúng có thể có các mối nguy hiểm, mảnh, lỗ, bị ngắt kết nối, có các đỉnh trùng lặp, chạy các đỉnh dọc theo các đường thẳng và có ranh giới không bị phá hủy giữa hai thành phần liền kề. Dưới đây là một ví dụ thể hiện nhiều đặc điểm này (và hơn thế nữa):

Một đa giác

Chúng tôi sẽ đặc biệt tìm kiếm (các) phân đoạn ngang có chiều dài tối đa nằm hoàn toàn trong phạm vi đóng của đa giác. Chẳng hạn, điều này giúp loại bỏ sự nguy hiểm giữa x = 20 và x = 40 phát ra từ lỗ giữa x = 10 và x = 25. Sau đó, thật đơn giản để chỉ ra rằng ít nhất một trong các đoạn ngang có chiều dài tối đa giao nhau ít nhất một đỉnh. (Nếu có những giải pháp giao nhau không có đỉnh, họ sẽ nằm trong nội thất của một số hình bình hành bao bọc ở phía trên và phía dưới của giải pháp mà làm giao nhau ít nhất một đỉnh. Điều này cho chúng ta một phương tiện để tìm tất cả các giải pháp.)

Theo đó, quá trình quét dòng phải bắt đầu bằng các đỉnh thấp nhất và sau đó di chuyển lên trên (nghĩa là hướng tới các giá trị y cao hơn) để dừng tại mỗi đỉnh. Tại mỗi điểm dừng, chúng tôi tìm thấy bất kỳ cạnh mới nào phát ra từ độ cao đó; loại bỏ bất kỳ cạnh nào chấm dứt từ bên dưới ở độ cao đó (đây là một trong những ý tưởng chính: nó đơn giản hóa thuật toán và loại bỏ một nửa khả năng xử lý tiềm năng); và cẩn thận xử lý bất kỳ cạnh nào nằm hoàn toàn ở độ cao không đổi (các cạnh ngang).

Ví dụ, hãy xem xét trạng thái khi đạt đến mức y = 10. Từ trái sang phải, chúng tôi tìm thấy các cạnh sau:

      x.min x.max y.min y.max
 [1,]    10     0     0    30
 [2,]    10    24    10    20
 [3,]    20    24    10    20
 [4,]    20    40    10    10
 [5,]    40    20    10    10
 [6,]    60     0     5    30
 [7,]    60    60     5    30
 [8,]    60    70     5    20
 [9,]    60    70     5    15
[10,]    90   100    10    40

Trong bảng này, (x.min, y.min) là tọa độ của điểm cuối thấp hơn của cạnh và (x.max, y.max) là tọa độ của điểm cuối trên của nó. Ở cấp độ này (y = 10), cạnh thứ nhất bị chặn trong phần bên trong của nó, cạnh thứ hai bị chặn ở dưới cùng, v.v. Một số cạnh chấm dứt ở cấp độ này, chẳng hạn như từ (10.0) đến (10,10), không được đưa vào danh sách.

Để xác định vị trí của các điểm bên trong và các điểm bên ngoài, hãy tưởng tượng bắt đầu từ cực bên trái - dĩ nhiên nằm ngoài đa giác - và di chuyển theo chiều ngang sang phải. Mỗi lần chúng ta đi qua một cạnh không nằm ngang , chúng ta luân phiên chuyển từ bên ngoài sang bên trong và phía sau. (Đây là một ý tưởng quan trọng khác.) Tuy nhiên, tất cả các điểm trong bất kỳ cạnh ngang nào được xác định là nằm trong đa giác, không có vấn đề gì. (Việc đóng một đa giác luôn bao gồm các cạnh của nó.)

Tiếp tục ví dụ, đây là danh sách tọa độ x được sắp xếp trong đó các cạnh không nằm ngang bắt đầu tại hoặc vượt qua đường y = 10:

x.array    6.7 10 20 48 60 63.3 65 90
interior     1  0  1  0  1    0  1  0

(Lưu ý rằng x = 40 không có trong danh sách này.) Các giá trị của interiormảng đánh dấu các điểm cuối bên trái của các phân đoạn bên trong: 1 chỉ định một khoảng bên trong, 0 một khoảng bên ngoài. Do đó, 1 đầu tiên chỉ ra khoảng từ x = 6,7 đến x = 10 nằm trong đa giác. 0 tiếp theo cho biết khoảng từ x = 10 đến x = 20 nằm ngoài đa giác. Và do đó, nó tiến hành: mảng xác định bốn khoảng riêng biệt như bên trong đa giác.

Một số trong các khoảng này, chẳng hạn như một từ x = 60 đến x = 63.3, không giao nhau với bất kỳ đỉnh nào: kiểm tra nhanh đối với tọa độ x của tất cả các đỉnh với y = 10 sẽ loại bỏ các khoảng đó.

Trong quá trình quét, chúng tôi có thể theo dõi độ dài của các khoảng này, giữ lại dữ liệu liên quan đến (các) khoảng thời gian dài tối đa được tìm thấy cho đến nay.

Lưu ý một số ý nghĩa của phương pháp này. Một đỉnh hình chữ "v", khi gặp phải, là gốc của hai cạnh. Do đó, hai công tắc xảy ra khi đi qua nó. Những công tắc đó hủy bỏ. Bất kỳ "v" lộn ngược nào thậm chí không được xử lý, bởi vì cả hai cạnh của nó đều bị loại bỏ trước khi bắt đầu quét từ trái sang phải. Trong cả hai trường hợp, một đỉnh như vậy không chặn một đoạn ngang.

Nhiều hơn hai cạnh có thể chia sẻ một đỉnh: điều này được minh họa ở (10.0), (60,5), (25, 20) và - mặc dù rất khó để nói - tại (20,10) và (40 , 10). (Đó là vì dangle đi (20,10) -> (40,10) -> (40,0) -> (40, -50) -> (40, 10) -> (20, 10). Lưu ý rằng đỉnh ở (40,0) cũng nằm trong phần bên của cạnh khác ... thật khó chịu.) Thuật toán này xử lý các tình huống đó tốt.

Một tình huống khó khăn được minh họa ở phía dưới cùng: tọa độ x của các phân đoạn không nằm ngang có

30, 50

Điều này khiến mọi thứ ở bên trái của x = 30 được coi là bên ngoài, mọi thứ trong khoảng từ 30 đến 50 là bên trong và mọi thứ sau 50 sẽ trở lại bên ngoài. Đỉnh tại x = 40 thậm chí không bao giờ được xem xét trong thuật toán này.

Đây là những gì đa giác trông giống như ở cuối quét. Tôi hiển thị tất cả các khoảng bên trong chứa đỉnh có màu xám đậm, bất kỳ khoảng thời gian dài tối đa nào có màu đỏ và tô màu các đỉnh theo tọa độ y của chúng. Khoảng thời gian tối đa là 64 đơn vị dài.

Sau khi quét

Các tính toán hình học duy nhất có liên quan là tính toán nơi các cạnh cắt nhau theo đường ngang: đó là phép nội suy tuyến tính đơn giản. Tính toán cũng cần thiết để xác định phân đoạn bên trong nào chứa các đỉnh: đây là các phép xác định giữa , dễ dàng tính toán với một vài bất đẳng thức. Sự đơn giản này làm cho thuật toán mạnh mẽ và phù hợp cả cho các biểu diễn tọa độ nguyên và dấu phẩy động.

Nếu tọa độ là địa lý , thì các đường ngang thực sự nằm trên các vòng tròn vĩ độ. Độ dài của chúng không khó để tính toán: chỉ cần nhân độ dài Euclide của chúng với cosin của vĩ độ của chúng (trong một mô hình hình cầu). Do đó, thuật toán này thích ứng độc đáo với tọa độ địa lý. (Để xử lý việc quấn quanh kinh tuyến + -180, trước tiên người ta có thể cần tìm một đường cong từ cực nam đến cực bắc không đi qua đa giác. đường cong, thuật toán này sẽ tìm chính xác phân đoạn ngang tối đa.)


Sau đây là Rmã được thực hiện để thực hiện các tính toán và tạo các minh họa.

#
# Plotting functions.
#
points.polygon <- function(p, ...) {
  points(p$v, ...)
}
plot.polygon <- function(p, ...) {
  apply(p$e, 1, function(e) lines(matrix(e[c("x.min", "x.max", "y.min", "y.max")], ncol=2), ...))
}
expand <- function(bb, e=1) {
  a <- matrix(c(e, 0, 0, e), ncol=2)
  origin <- apply(bb, 2, mean)
  delta <-  origin %*% a - origin
  t(apply(bb %*% a, 1, function(x) x - delta))
}
#
# Convert polygon to a better data structure.
#
# A polygon class has three attributes:
#   v is an array of vertex coordinates "x" and "y" sorted by increasing y;
#   e is an array of edges from (x.min, y.min) to (x.max, y.max) with y.max >= y.min, sorted by y.min;
#   bb is its rectangular extent (x0,y0), (x1,y1).
#
as.polygon <- function(p) {
  #
  # p is a list of linestrings, each represented as a sequence of 2-vectors 
  # with coordinates in columns "x" and "y". 
  #
  f <- function(p) {
    g <- function(i) {
      v <- p[(i-1):i, ]
      v[order(v[, "y"]), ]
    }
    sapply(2:nrow(p), g)
  }
  vertices <- do.call(rbind, p)
  edges <- t(do.call(cbind, lapply(p, f)))
  colnames(edges) <- c("x.min", "x.max", "y.min", "y.max")
  #
  # Sort by y.min.
  #
  vertices <- vertices[order(vertices[, "y"]), ]
  vertices <- vertices[!duplicated(vertices), ]
  edges <- edges[order(edges[, "y.min"]), ]

  # Maintaining an extent is useful.
  bb <- apply(vertices <- vertices[, c("x","y")], 2, function(z) c(min(z), max(z)))

  # Package the output.
  l <- list(v=vertices, e=edges, bb=bb); class(l) <- "polygon"
  l
}
#
# Compute the maximal horizontal interior segments of a polygon.
#
fetch.x <- function(p) {
  #
  # Update moves the line from the previous level to a new, higher level, changing the
  # state to represent all edges originating or strictly passing through level `y`.
  #
  update <- function(y) {
    if (y > state$level) {
      state$level <<- y
      #
      # Remove edges below the new level from state$current.
      #
      current <- state$current
      current <- current[current[, "y.max"] > y, ]
      #
      # Adjoin edges at this level.
      #
      i <- state$i
      while (i <= nrow(p$e) && p$e[i, "y.min"] <= y) {
        current <- rbind(current, p$e[i, ])
        i <- i+1
      }
      state$i <<- i
      #
      # Sort the current edges by x-coordinate.
      #
      x.coord <- function(e, y) {
        if (e["y.max"] > e["y.min"]) {
          ((y - e["y.min"]) * e["x.max"] + (e["y.max"] - y) * e["x.min"]) / (e["y.max"] - e["y.min"])
        } else {
          min(e["x.min"], e["x.max"])
        }
      }
      if (length(current) > 0) {
        x.array <- apply(current, 1, function(e) x.coord(e, y))
        i.x <- order(x.array)
        current <- current[i.x, ]
        x.array <- x.array[i.x]     
        #
        # Scan and mark each interval as interior or exterior.
        #
        status <- FALSE
        interior <- numeric(length(x.array))
        for (i in 1:length(x.array)) {
          if (current[i, "y.max"] == y) {
            interior[i] <- TRUE
          } else {
            status <- !status
            interior[i] <- status
          }
        }
        #
        # Simplify the data structure by retaining the last value of `interior`
        # within each group of common values of `x.array`.
        #
        interior <- sapply(split(interior, x.array), function(i) rev(i)[1])
        x.array <- sapply(split(x.array, x.array), function(i) i[1])

        print(y)
        print(current)
        print(rbind(x.array, interior))


        markers <- c(1, diff(interior))
        intervals <- x.array[markers != 0]
        #
        # Break into a list structure.
        #
        if (length(intervals) > 1) {
          if (length(intervals) %% 2 == 1) 
            intervals <- intervals[-length(intervals)]
          blocks <- 1:length(intervals) - 1
          blocks <- blocks - (blocks %% 2)
          intervals <- split(intervals, blocks)  
        } else {
          intervals <- list()
        }
      } else {
        intervals <- list()
      }
      #
      # Update the state.
      #
      state$current <<- current
    }
    list(y=y, x=intervals)
  } # Update()

  process <- function(intervals, x, y) {
    # intervals is a list of 2-vectors. Each represents the endpoints of
    # an interior interval of a polygon.
    # x is an array of x-coordinates of vertices.
    #
    # Retains only the intervals containing at least one vertex.
    between <- function(i) {
      1 == max(mapply(function(a,b) a && b, i[1] <= x, x <= i[2]))
    }
    is.good <- lapply(intervals$x, between)
    list(y=y, x=intervals$x[unlist(is.good)])
    #intervals
  }
  #
  # Group the vertices by common y-coordinate.
  #
  vertices.x <- split(p$v[, "x"], p$v[, "y"])
  vertices.y <- lapply(split(p$v[, "y"], p$v[, "y"]), max)
  #
  # The "state" is a collection of segments and an index into edges.
  # It will updated during the vertical line sweep.
  #
  state <- list(level=-Inf, current=c(), i=1, x=c(), interior=c())
  #
  # Sweep vertically from bottom to top, processing the intersection
  # as we go.
  #
  mapply(function(x,y) process(update(y), x, y), vertices.x, vertices.y)
}


scale <- 10
p.raw = list(scale * cbind(x=c(0:10,7,6,0), y=c(3,0,0,-1,-1,-1,0,-0.5,0.75,1,4,1.5,0.5,3)),
             scale *cbind(x=c(1,1,2.4,2,4,4,4,4,2,1), y=c(0,1,2,1,1,0,-0.5,1,1,0)),
             scale *cbind(x=c(6,7,6,6), y=c(.5,2,3,.5)))

#p.raw = list(cbind(x=c(0,2,1,1/2,0), y=c(0,0,2,1,0)))
#p.raw = list(cbind(x=c(0, 35, 100, 65, 0), y=c(0, 50, 100, 50, 0)))

p <- as.polygon(p.raw)

results <- fetch.x(p)
#
# Find the longest.
#
dx <- matrix(unlist(results["x", ]), nrow=2)
length.max <- max(dx[2,] - dx[1,])
#
# Draw pictures.
#
segment.plot <- function(s, length.max, colors,  ...) {
  lapply(s$x, function(x) {
      col <- ifelse (diff(x) >= length.max, colors[1], colors[2])
      lines(x, rep(s$y,2), col=col, ...)
    })
}
gray <- "#f0f0f0"
grayer <- "#d0d0d0"
plot(expand(p$bb, 1.1), type="n", xlab="x", ylab="y", main="After the Scan")
sapply(1:length(p.raw), function(i) polygon(p.raw[[i]], col=c(gray, "White", grayer)[i]))
apply(results, 2, function(s) segment.plot(s, length.max, colors=c("Red", "#b8b8a8"), lwd=4))
plot(p, col="Black", lty=3)
points(p, pch=19, col=round(2 + 2*p$v[, "y"]/scale, 0))
points(p, cex=1.25)

Có một định lý chứng minh rằng đường dài tối đa bên trong đa giác không lồi theo bất kỳ hướng đã cho nào cắt nhau ít nhất một đỉnh của đa giác này không?
SS_Rebelious

@SS Vâng, có. Đây là một bản phác thảo của một bằng chứng: nếu không có giao điểm, thì các điểm cuối của phân khúc đều nằm trên các cạnh của cạnh và phân đoạn có thể được di chuyển, ít nhất là một chút, lên và xuống. Chiều dài của nó là một hàm tuyến tính của lượng dịch chuyển. Do đó, nó có thể có độ dài tối đa chỉ khi chiều dài không thay đổi khi được di chuyển. Điều này ngụ ý cả (a) nó là một phần của hình bình hành được hình thành từ các đoạn có độ dài cực đại và (b) cả hai cạnh trên và dưới của hình bình hành đó phải gặp một đỉnh, QED.
whuber

Và tên của định lý này là gì? Tôi đang vật lộn để tìm nó. BTW, những gì về các cạnh cong không có đỉnh (ý tôi là một cách tiếp cận lý thuyết)? Một bản phác thảo ví dụ về hình tôi muốn nói (một đa giác hình quả chuông): "C = D".
SS_Rebelious

@SS Khi các cạnh bị cong, định lý không còn giữ. Kỹ thuật của hình học vi phân có thể được áp dụng để có được kết quả hữu ích. Tôi đã học được những phương pháp này từ cuốn sách của Cheeger & Ebin, Định lý so sánh trong Hình học Riemannian . Tuy nhiên, hầu hết các hệ thống GIS sẽ xấp xỉ các đường cong bằng các đường dẫn chi tiết, vì vậy câu hỏi (như một vấn đề thực tế) là phải tranh luận.
whuber

bạn có thể chỉ định tên của định lý (và trang nếu có thể)? Tôi đã có cuốn sách và tôi không thể xác định được định lý cần thiết.
SS_Rebelious

9

Đây là một giải pháp dựa trên raster. Thật nhanh chóng (tôi đã thực hiện tất cả các công việc từ đầu đến cuối trong 14 phút), không yêu cầu kịch bản, chỉ mất một vài thao tác và rất chính xác.

Bắt đầu với một đại diện raster của đa giác. Cái này sử dụng lưới 550 hàng và 1200 cột:

Đa giác

Trong biểu diễn này, các ô màu xám (bên trong) có giá trị 1 và tất cả các ô khác là NoData.

Tính toán tích lũy dòng chảy theo hướng từ tây sang đông bằng cách sử dụng các giá trị ô đơn vị cho lưới trọng lượng (lượng "lượng mưa"):

Tích lũy dòng chảy

Tích lũy thấp là tối, tăng đến tích lũy cao nhất trong màu vàng sáng.

Một cực đại vùng (sử dụng đa giác cho lưới và tích lũy luồng cho các giá trị) xác định (các) ô trong đó luồng là lớn nhất. Để hiển thị những thứ này, tôi phải phóng to về phía dưới bên phải:

Tối đa

Các ô màu đỏ đánh dấu các đầu của dòng tích lũy cao nhất: chúng là các điểm cuối bên phải của các đoạn bên trong có độ dài tối đa của đa giác.

Để tìm các phân đoạn này, đặt tất cả trọng lượng tại các ô màu đỏ và chạy dòng chảy ngược!

Kết quả

Dải màu đỏ gần phía dưới đánh dấu hai hàng ô: bên trong chúng nằm ở đoạn ngang có chiều dài tối đa. Sử dụng biểu diễn này như là để phân tích thêm hoặc chuyển đổi nó thành hình dạng đa tuyến (hoặc đa giác).

Có một số lỗi riêng biệt được thực hiện với một đại diện raster. Nó có thể được giảm bằng cách tăng độ phân giải, với một số chi phí trong thời gian tính toán.


Một khía cạnh thực sự tốt đẹp của phương pháp này là thông thường chúng ta tìm thấy các giá trị cực đoan của mọi thứ như là một phần của quy trình công việc lớn hơn, trong đó một số mục tiêu cần phải đạt được: đặt một đường ống hoặc sân bóng đá, tạo ra bộ đệm sinh thái, v.v. Quá trình này bao gồm sự đánh đổi. Do đó, đường ngang dài nhất có thể không phải là một phần của giải pháp tối ưu. Thay vào đó, chúng ta có thể quan tâm để biết những dòng gần như dài nhất sẽ nằm ở đâu. Điều này rất đơn giản: thay vì chọn luồng tối đa của vùng, hãy chọn tất cả các ô gần với mức tối đa của vùng. Trong ví dụ này, zonal max bằng 744 (số lượng cột được kéo dài bởi đoạn nội thất dài nhất). Thay vào đó, hãy chọn tất cả các ô trong phạm vi tối đa 5%:

Các ô gần tối ưu được chọn

Chạy dòng chảy từ đông sang tây tạo ra bộ sưu tập các phân đoạn ngang này:

Giải pháp gần tối ưu

Đây là bản đồ các địa điểm mà phạm vi đông-tây không bị gián đoạn là 95% hoặc lớn hơn phạm vi đông-tây tối đa ở bất cứ đâu trong đa giác.


3

Đồng ý. Tôi đã có một ý tưởng khác (tốt hơn) ( ý tưởng - 2 ). Nhưng tôi cho rằng sẽ tốt hơn nếu được nhận ra là tập lệnh python, không phải là SQL-querry. Một lần nữa ở đây là trường hợp phổ biến, không chỉ EW.

Bạn sẽ cần một hộp giới hạn cho đa giác và góc phương vị (A) làm hướng đo của bạn. Giả sử rằng độ dài của các cạnh BBox là LA và LB. Khoảng cách tối đa có thể (MD) trong đa giác là : MB = (LA^2 * LB^2)^(1/2), vì vậy giá trị tìm kiếm (V) không lớn hơn MB : V <= MB.

  1. Bắt đầu từ bất kỳ đỉnh nào của BBox tạo ra một dòng (LL) với độ dài MB và góc phương vị A.
  2. Giao tuyến LL với đa giác để có đường giao nhau (IL)
  3. Kiểm tra hình học của IL - nếu chỉ có hai điểm trong dòng IL thì hãy tính độ dài của nó. Nếu 4 hoặc nhiều hơn - tính toán các phân đoạn và chọn độ dài của đoạn dài nhất. Null (không có giao lộ nào cả) - bỏ qua.
  4. Tiếp tục tạo một dòng LL khác di chuyển từ bộ đếm điểm bắt đầu hoặc theo chiều kim đồng hồ về phía các cạnh của BBox cho đến khi bạn không kết thúc tại điểm bắt đầu (bạn sẽ thực hiện toàn bộ vòng lặp trên BBox).
  5. Chọn giá trị độ dài IL lớn nhất (thực tế bạn không phải lưu trữ tất cả độ dài, bạn có thể giữ giá trị tối đa 'cho đến nay' trong khi lặp) - đó sẽ là thứ bạn tìm kiếm.

Điều này nghe có vẻ như một vòng lặp kép trên các đỉnh: không đủ hiệu quả nên tránh (ngoại trừ các đa giác rất đơn giản).
whuber

@whuber, tôi không thấy bất kỳ vòng lặp thêm ở đây. Chỉ có một số xử lý vô nghĩa của 2 mặt BB sẽ không mang lại gì ngoài null. Nhưng quá trình xử lý này đã bị loại trừ trong tập lệnh mà tôi đã cung cấp trong câu trả lời đã bị xóa ở đây (có vẻ như đó là một nhận xét, nhưng tôi không xem đó là một nhận xét - chỉ là một câu trả lời đã bị xóa)
SS_Rebelious

(1) Đây là nhận xét thứ ba cho câu hỏi. (2) Bạn nói đúng: khi đọc mô tả của bạn rất cẩn thận, tôi nhận ra rằng bạn đang tìm đoạn dài nhất giữa (bốn) đỉnh của hộp giới hạn và các đỉnh của đa giác. Tôi không thấy cách này trả lời câu hỏi, mặc dù: kết quả chắc chắn không phải là những gì OP tìm kiếm.
whuber

@whuber, thuật toán đề xuất tìm giao điểm dài nhất của đa giác với đường biểu thị hướng đã cho. Rõ ràng kết quả IS đã được hỏi nếu khoảng cách giữa các đường giao nhau -> 0 hoặc nó vượt qua tất cả các đỉnh (đối với các hình không cong).
SS_Rebelious

3

Tôi không chắc chắn rằng câu trả lời của Fetzer là những gì bạn muốn làm, nhưng vì vậy st_box2d có thể thực hiện công việc.

Ý tưởng của SS_Rebelious N ° 1 sẽ hoạt động trong nhiều trường hợp nhưng không phải cho một số đa giác lõm.

Tôi nghĩ rằng bạn phải tạo các đường lw nhân tạo có điểm theo các cạnh khi các đường tạo đỉnh vượt qua biên của đa giác nếu có khả năng đường đông-tây. một ví dụ nơi nó sẽ không hoạt động

Để làm điều này, bạn có thể thử tạo đa giác 4 ​​nút trong đó độ dài của đường cao, tạo đa giác P * là chồng chéo trước với đa giác ban đầu của bạn và xem liệu min (y1) và max (y2) có để lại một số dòng x không khả năng. (trong đó y1 là tập hợp điểm giữa góc trên bên trái và góc trên bên phải và y2 tập hợp y giữa góc dưới bên trái và dưới cùng bên phải của đa giác 4 ​​nút của bạn). Điều này không dễ dàng gì, tôi hy vọng bạn sẽ tìm thấy các công cụ psql để giúp bạn!


Đây là đi đúng hướng. Đoạn EW dài nhất sẽ được tìm thấy trong số các giao điểm với phần bên trong của đa giác với các đường nằm ngang đi qua các đỉnh của đa giác. Điều này đòi hỏi mã để lặp qua các đỉnh. Có một phương pháp thay thế (nhưng tương đương) có sẵn bằng cách theo dòng chảy đông-tây nhân tạo qua biểu diễn raster của đa giác: chiều dài dòng tối đa được tìm thấy trong đa giác (là một trong những "thống kê khu vực" của nó) là chiều rộng mong muốn. Giải pháp raster thu được chỉ trong 3 hoặc 4 bước và không yêu cầu lặp hoặc tạo kịch bản.
whuber

@Aname, vui lòng thêm "1" vào "ý tưởng của SS_Rebelious" để tránh hiểu lầm: Tôi đã thêm một đề xuất khác. Tôi không thể tự chỉnh sửa câu trả lời của bạn vì chỉnh sửa này ít hơn 6 ký tự.
SS_Rebelious

1

Tôi có một ý tưởng-№1 ( Chỉnh sửa: đối với trường hợp phổ biến, không chỉ hướng EW và với một số hạn chế được mô tả trong các nhận xét). Tôi sẽ không cung cấp mã, chỉ là một khái niệm. "Hướng x" thực sự là một góc phương vị, được tính bằng ST_Azimuth. Các bước đề xuất là:

  1. Trích xuất tất cả các đỉnh từ đa giác như các điểm.
  2. Tạo các đường giữa mỗi cặp điểm.
  3. Chọn các dòng (cho phép gọi chúng là lw-lines) nằm trong đa giác ban đầu (chúng ta không cần các dòng sẽ vượt qua biên của đa giác).
  4. Tìm khoảng cách và góc phương vị cho mọi lw-line.
  5. Chọn khoảng cách dài nhất từ ​​lw-lines trong đó góc phương vị bằng với góc phương vị tìm kiếm hoặc nằm trong một khoảng nào đó (có thể là không có góc phương vị nào sẽ chính xác bằng góc phương vị tìm kiếm).

Điều này sẽ không hoạt động ngay cả đối với một số hình tam giác , chẳng hạn như một hình tam giác (0,0), (1000, 1000) và (501, 499). Chiều rộng đông-tây tối đa của nó là khoảng 2; các góc phương vị đều ở khoảng 45 độ; và bất kể, đoạn đường ngắn nhất giữa các đỉnh dài hơn 350 lần so với chiều rộng đông-tây.
whuber

@whuber, bạn đã đúng, nó sẽ thất bại đối với hình tam giác, nhưng đối với đa giác, đại diện cho một số tính năng tự nhiên, nó có thể hữu ích.
SS_Rebelious

1
Thật khó để đề xuất một quy trình thất bại đáng kể ngay cả đối với các trường hợp đơn giản với hy vọng rằng đôi khi nó có thể có câu trả lời chính xác!
whuber

@whuber, vì vậy đừng giới thiệu nó! ;-) Tôi đã đề xuất cách giải quyết này vì không có câu trả lời cho câu hỏi này. Lưu ý rằng bạn có thể đăng câu trả lời tốt hơn của riêng bạn. BTW, nếu bạn sẽ đặt một số điểm trên các cạnh tam giác, đề xuất của tôi sẽ hoạt động ;-)
SS_Rebelious

Tôi đã đề xuất một số cách tiếp cận. Một raster có tại gis.stackexchange.com/questions/32552/ và được xây dựng tại forum.esri.com/Thread.asp?c=93&f=982&t=107703&mc=3 . Một số khác - không hoàn toàn có thể áp dụng, nhưng với những ứng dụng thú vị - có tại gis.stackexchange.com/questions/23664/ ((biến đổi radon). Điều này được minh họa tại stats.stackexchange.com/a/33102 .
whuber

1

Hãy xem câu hỏi của tôi và câu trả lời từ Evil Genius.

Hy vọng rằng đa giác hồ của bạn có một số điểm, bạn có thể tạo các đường trên các điểm này với góc phương vị (khía cạnh, hướng địa lý). Chọn độ dài của các dòng đủ lớn (phần ST_MakePoint), để bạn có thể tính được dòng ngắn nhất giữa hai dòng xa nhất.

Đây là một ví dụ:

nhập mô tả hình ảnh ở đây

Ví dụ cho thấy chiều rộng tối đa của đa giác. Tôi chọn ST_ShortestLine (dòng màu đỏ) cho phương pháp này. ST_MakeLine sẽ tăng giá trị (đường màu xanh) và điểm cuối của đường (phía dưới bên trái) sẽ chạm vào đường màu xanh của đa giác. Bạn phải tính khoảng cách với trọng tâm của các dòng (trợ giúp) đã tạo.

Một ý tưởng cho đa giác không đều hoặc lõm cho phương pháp này. Có thể bạn phải giao cắt đa giác với raster.

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.