ฉันสนใจในความกว้างสูงสุดของรูปหลายเหลี่ยมเช่นทะเลสาบในทิศทางตะวันออก - ตะวันตก กล่องที่ถูกผูกไว้จะช่วยในรูปหลายเหลี่ยมอย่างง่ายเท่านั้น แต่ไม่ได้อยู่ในรูปหลายเหลี่ยมหลายเหลี่ยมที่ซับซ้อน
ฉันสนใจในความกว้างสูงสุดของรูปหลายเหลี่ยมเช่นทะเลสาบในทิศทางตะวันออก - ตะวันตก กล่องที่ถูกผูกไว้จะช่วยในรูปหลายเหลี่ยมอย่างง่ายเท่านั้น แต่ไม่ได้อยู่ในรูปหลายเหลี่ยมหลายเหลี่ยมที่ซับซ้อน
คำตอบ:
สิ่งนี้น่าจะต้องมีสคริปต์ในแพลตฟอร์ม GIS ใด ๆ
วิธีที่มีประสิทธิภาพมากที่สุด (asymptotically) เป็นเส้นกวาดแนวตั้ง:มันต้องเรียงลำดับขอบด้วยพิกัด y ขั้นต่ำของพวกเขาแล้วประมวลผลขอบจากด้านล่าง (ต่ำสุด y) ไปด้านบน (สูงสุด y) สำหรับ O (e * log ( e)) อัลกอริทึมเมื่อขอบeเกี่ยวข้อง
ขั้นตอนแม้ว่าจะง่าย แต่ก็ยากที่จะทำให้ถูกต้องในทุกกรณี รูปหลายเหลี่ยมอาจเป็นสิ่งที่น่ารังเกียจ: พวกเขาสามารถมี dangles, slivers, hole, ถูกตัดการเชื่อมต่อ, มีจุดยอดซ้ำ, การวิ่งของจุดยอดตามเส้นตรงและมีขอบเขตไม่แน่นอนระหว่างสองส่วนประกอบที่อยู่ติดกัน นี่คือตัวอย่างที่แสดงคุณสมบัติเหล่านี้มากมาย (และอื่น ๆ ):
เราจะหาส่วนของแนวนอนที่มีความยาวสูงสุดโดยเฉพาะภายในการปิดของรูปหลายเหลี่ยม ตัวอย่างเช่นสิ่งนี้จะช่วยลดการห้อยระหว่าง x = 20 และ x = 40 เล็ดลอดออกมาจากหลุมระหว่าง x = 10 และ x = 25 จากนั้นก็ตรงไปตรงมาเพื่อแสดงว่าอย่างน้อยหนึ่งส่วนแนวนอนที่มีความยาวสูงสุดตัดกับจุดยอดอย่างน้อยหนึ่งจุด (หากมีการแก้ปัญหาการตัดไม่มีจุดที่พวกเขาจะอยู่ในการตกแต่งภายในของรูปสี่เหลี่ยมด้านขนานบางขอบเขตที่ด้านบนและด้านล่างโดยการแก้ปัญหาที่ทำตัดอย่างน้อยหนึ่งจุดสุดยอด. นี้ทำให้เรามีวิธีที่จะหาทุกโซลูชั่น.)
ดังนั้นการกวาดบรรทัดจะต้องเริ่มต้นด้วยจุดยอดต่ำสุดแล้วเลื่อนขึ้นไปข้างบน (นั่นคือไปยังค่า y ที่สูงกว่า) เพื่อหยุดที่แต่ละจุดยอด ทุกครั้งที่หยุดเราจะพบขอบใหม่ ๆ ที่แผ่ขึ้นจากระดับความสูงนั้น กำจัดขอบใด ๆ ที่สิ้นสุดลงจากด้านล่างที่ระดับความสูงนั้น (นี่เป็นหนึ่งในแนวคิดหลัก: มันลดความซับซ้อนของอัลกอริทึมและกำจัดครึ่งหนึ่งของการประมวลผลที่อาจเกิดขึ้น) และประมวลผลขอบใด ๆ ที่อยู่ในระดับความสูงอย่างสม่ำเสมอ (ขอบแนวนอน)
ตัวอย่างเช่นพิจารณาสถานะเมื่อถึงระดับ y = 10 จากซ้ายไปขวาเราพบขอบดังต่อไปนี้:
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
ในตารางนี้ (x.min, y.min) เป็นพิกัดของจุดสิ้นสุดด้านล่างของขอบและ (x.max, y.max) เป็นพิกัดของจุดปลายด้านบน ที่ระดับนี้ (y = 10) ขอบแรกจะถูกดักภายในภายในขอบด้านที่สองจะถูกดักไว้ที่ด้านล่างและอื่น ๆ ขอบบางอันสิ้นสุดที่ระดับนี้เช่นจาก (10,0) ถึง (10,10) จะไม่รวมอยู่ในรายการ
ในการพิจารณาว่าจุดภายในนั้นอยู่ที่ใดและอยู่ภายนอกลองจินตนาการว่าเริ่มต้นจากด้านซ้ายสุด - ซึ่งอยู่นอกรูปหลายเหลี่ยมแน่นอน - และเคลื่อนที่ในแนวนอนไปทางขวา ทุกครั้งที่เราข้ามขอบซึ่งไม่ได้เป็นแนวนอนเราสลับจากภายนอกไปสู่การตกแต่งภายในและด้านหลัง (นี่เป็นแนวคิดหลักอีกข้อหนึ่ง) อย่างไรก็ตามจุดทั้งหมดที่อยู่ในขอบแนวนอนนั้นถูกกำหนดให้อยู่ในรูปหลายเหลี่ยมไม่ว่าจะเกิดอะไรขึ้น (การปิดของรูปหลายเหลี่ยมจะรวมถึงขอบเสมอ)
ต่อจากตัวอย่างนี่คือรายการที่เรียงลำดับของพิกัด x โดยที่ขอบที่ไม่ใช่แนวนอนเริ่มต้นที่หรือข้ามเส้น y = 10:
x.array 6.7 10 20 48 60 63.3 65 90
interior 1 0 1 0 1 0 1 0
(ขอให้สังเกตว่า x = 40 ไม่ได้อยู่ในรายการนี้) ค่าของinterior
อาร์เรย์ทำเครื่องหมายจุดสิ้นสุดด้านซ้ายของส่วนภายใน: 1 กำหนดช่วงเวลาภายใน 0 ช่วงเวลาภายนอก ดังนั้น 1 แรกแสดงช่วงเวลาจาก x = 6.7 ถึง x = 10 อยู่ภายในรูปหลายเหลี่ยม 0 ถัดไประบุช่วงเวลาจาก x = 10 ถึง x = 20 อยู่นอกรูปหลายเหลี่ยม ดังนั้นมันจึงดำเนินการ: อาเรย์ระบุช่วงเวลาสี่ช่วงแยกกันภายในรูปหลายเหลี่ยม
บางช่วงเวลาเหล่านี้เช่นช่วงจาก x = 60 ถึง x = 63.3 จะไม่ตัดจุดยอดใด ๆ : การตรวจสอบอย่างรวดเร็วกับพิกัด x ของจุดยอดทั้งหมดที่มี y = 10 จะกำจัดช่วงดังกล่าว
ในระหว่างการสแกนเราสามารถตรวจสอบความยาวของช่วงเวลาเหล่านี้โดยเก็บข้อมูลที่เกี่ยวข้องกับช่วงความยาวสูงสุดที่พบ
สังเกตความหมายบางส่วนของวิธีการนี้ จุดยอดรูป v "เมื่อพบคือต้นกำเนิดของสองขอบ ดังนั้นสวิตช์สองตัวจึงเกิดขึ้นเมื่อข้ามมัน สวิตช์เหล่านั้นยกเลิก การกลับหัว "v" ใด ๆ ที่ไม่ได้ประมวลผลแม้แต่เพราะขอบทั้งสองของมันจะถูกกำจัดก่อนที่จะเริ่มการสแกนจากซ้ายไปขวา ในทั้งสองกรณีจุดสุดยอดดังกล่าวจะไม่บล็อกส่วนแนวนอน
มากกว่าสองขอบสามารถแบ่งปันจุดสุดยอด: นี่คือภาพประกอบที่ (10,0), (60,5), (25, 20) และ - แม้ว่ามันจะยากที่จะบอก - ที่ (20,10) และ (40 10) (นั่นเป็นเพราะห้อยไป (20,10) -> (40,10) -> (40,0) -> (40, -50) -> (40, 10) -> (20, 10). สังเกตว่าจุดสุดยอดที่ (40,0) นั้นอยู่ในส่วนใดของขอบอีกข้างหนึ่ง ... มันน่ารังเกียจ) อัลกอริธึมนี้จัดการกับสถานการณ์เหล่านั้นได้ดี
สถานการณ์ที่ยุ่งยากนั้นแสดงไว้ที่ด้านล่างสุด: พิกัด x ของส่วนที่ไม่ใช่แนวนอนนั้นมี
30, 50
สิ่งนี้ทำให้ทุกอย่างทางด้านซ้ายของ x = 30 ได้รับการพิจารณาภายนอกโดยทุกอย่างระหว่าง 30 ถึง 50 จะเป็นการตกแต่งภายในและทุกอย่างหลังจาก 50 ไปเป็นภายนอกอีกครั้ง จุดสุดยอดที่ x = 40 ไม่เคยถูกพิจารณาในอัลกอริทึมนี้
นี่คือรูปหลายเหลี่ยมที่ดูเหมือนในตอนท้ายของการสแกน ฉันแสดงช่วงเวลาการตกแต่งภายในที่มีจุดสุดยอดทั้งหมดในสีเทาเข้ม, ช่วงความยาวสูงสุดใด ๆ ที่เป็นสีแดง, และสีของจุดยอดตามพิกัด y ของพวกเขา ช่วงเวลาสูงสุดคือ 64 หน่วยยาว
การคำนวณทางเรขาคณิตที่เกี่ยวข้องเพียงอย่างเดียวคือการคำนวณที่ขอบตัดกับเส้นแนวนอนนั่นคือการแก้ไขเชิงเส้นอย่างง่าย จำเป็นต้องมีการคำนวณเพื่อกำหนดว่าส่วนภายในใดที่มีจุดยอด: สิ่งเหล่านี้เป็นความมุ่งมั่นระหว่างการคำนวณได้อย่างง่ายดายด้วยความไม่เท่าเทียมกันสองอย่าง ความเรียบง่ายนี้ทำให้อัลกอริธึมแข็งแกร่งและเหมาะสมทั้งสำหรับจำนวนเต็มและการแทนจุดพิกัดร่วม
หากพิกัดทางภูมิศาสตร์แสดงว่าเส้นแนวนอนอยู่ในวงกลมละติจูดจริงๆ ความยาวของพวกเขานั้นไม่ยากในการคำนวณเพียงแค่คูณความยาวแบบยุคลิดของพวกเขาด้วยโคไซน์ของละติจูดของพวกเขา (ในรูปแบบทรงกลม) ดังนั้นอัลกอริทึมนี้จึงปรับให้เหมาะกับพิกัดทางภูมิศาสตร์ (เพื่อจัดการกับการพันรอบจุดศูนย์กลาง + -180 หนึ่งอาจต้องก่อนเพื่อหาเส้นโค้งจากขั้วโลกใต้ไปยังขั้วโลกเหนือที่ไม่ผ่านรูปหลายเหลี่ยมหลังจากแสดงพิกัด x ทั้งหมดอีกครั้งในลักษณะการเคลื่อนที่ตามแนวนอนเมื่อเทียบกับ เส้นโค้งอัลกอริทึมนี้จะค้นหาส่วนแนวนอนสูงสุดได้อย่างถูกต้อง)
ต่อไปนี้เป็นR
รหัสที่ใช้ในการคำนวณและสร้างภาพประกอบ
#
# 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)
นี่คือวิธีการแก้ปัญหาตามแรสเตอร์ มันเร็ว (ฉันทำงานทั้งหมดตั้งแต่ต้นจนจบใน 14 นาที) ไม่ต้องใช้สคริปต์ใช้การดำเนินการเพียงไม่กี่ครั้งและมีความแม่นยำพอสมควร
เริ่มต้นด้วยการเป็นตัวแทนแรสเตอร์ของรูปหลายเหลี่ยม อันนี้ใช้กริด 550 แถวและ 1200 คอลัมน์:
ในการแสดงนี้เซลล์สีเทา (ภายใน) มีค่า 1 และเซลล์อื่น ๆ ทั้งหมดคือ NoData
คำนวณการสะสมการไหลในทิศทางตะวันตกไปตะวันออกโดยใช้ค่าเซลล์หน่วยสำหรับตารางน้ำหนัก (จำนวน "ปริมาณน้ำฝน"):
การสะสมที่ต่ำคือความมืดเพิ่มการสะสมสูงสุดในสีเหลืองสดใส
Zonal maximum (การใช้รูปหลายเหลี่ยมสำหรับกริดและการสะสมโฟลว์สำหรับค่า) ระบุเซลล์ (s) โดยที่การไหลมากที่สุด ในการแสดงสิ่งเหล่านี้ฉันต้องซูมไปทางขวาล่าง:
เซลล์สีแดงทำเครื่องหมายจุดสิ้นสุดของการไหลสะสมสูงสุด: เป็นจุดสิ้นสุดที่ถูกต้องของส่วนภายในที่มีความยาวสูงสุดของรูปหลายเหลี่ยม
หากต้องการค้นหากลุ่มเหล่านี้ให้วางน้ำหนักทั้งหมดที่เซลล์สีแดงและไหลย้อนกลับ!
แถบสีแดงใกล้ด้านล่างทำเครื่องหมายสองแถวของเซลล์: ภายในส่วนนั้นจะอยู่ในส่วนแนวนอนที่มีความยาวสูงสุด ใช้การแทนค่านี้ตามที่เป็นอยู่สำหรับการวิเคราะห์เพิ่มเติมหรือแปลงเป็นรูปหลายเหลี่ยม (หรือรูปหลายเหลี่ยม)
มีข้อผิดพลาด discretization เกิดขึ้นกับการเป็นตัวแทนแรสเตอร์ มันสามารถลดลงได้โดยการเพิ่มความละเอียดในบางเวลาในการคำนวณ
แง่มุมที่ดีอย่างหนึ่งของวิธีการนี้คือโดยทั่วไปแล้วเราจะพบคุณค่าของสิ่งต่าง ๆ มากที่สุดซึ่งเป็นส่วนหนึ่งของกระบวนการทำงานที่มีขนาดใหญ่ขึ้นซึ่งต้องบรรลุวัตถุประสงค์บางประการเช่นการวางท่อหรือสนามฟุตบอลการสร้างบัฟเฟอร์เชิงนิเวศน์ กระบวนการเกี่ยวข้องกับการแลกเปลี่ยน ดังนั้นเส้นแนวนอนที่ยาวที่สุดอาจไม่ได้เป็นส่วนหนึ่งของทางออกที่ดีที่สุด เราอาจจะดูแลแทนที่จะทราบว่าเกือบสายที่ยาวที่สุดจะโกหก นี่เป็นเรื่องง่าย: แทนที่จะเลือกโฟลวสูงสุดของโซนเลือกเซลล์ทั้งหมดใกล้กับสูงสุดของโซน ในตัวอย่างนี้ zonal max เท่ากับ 744 (จำนวนคอลัมน์ที่ขยายโดยส่วนภายในที่ยาวที่สุด) แต่ขอเลือกเซลล์ทั้งหมดภายใน 5% ของสูงสุดที่:
การไหลจากตะวันออกไปตะวันตกทำให้เกิดกลุ่มแนวนอนนี้:
นี่คือแผนที่ของสถานที่ที่ขอบเขตตะวันออก - ตะวันตกไม่ถูกรบกวน 95% หรือมากกว่าขอบเขตตะวันออก - ตะวันตกสูงสุดที่ใดก็ได้ภายในรูปหลายเหลี่ยม
ตกลง. ฉันมีความคิดอื่น (ดีกว่า) ( ความคิด - №2 ) แต่ฉันคิดว่ามันจะดีกว่าที่จะรับรู้เป็นสคริปต์หลามไม่เป็น SQL-querry อีกครั้งที่นี่เป็นกรณีทั่วไปไม่ใช่แค่ EW
คุณจะต้องใช้กล่องขอบเขตสำหรับรูปหลายเหลี่ยมและมุมราบ (A) ตามทิศทางการวัดของคุณ สมมติว่าความยาวของขอบ BBox คือ LA และ LB ระยะทางที่เป็นไปได้สูงสุด (MD) ภายในรูปหลายเหลี่ยมคือMB = (LA^2 * LB^2)^(1/2)
ดังนั้นการแสวงหาค่า (V) ไม่ได้มีขนาดใหญ่กว่า V <= MB
MB:
ฉันไม่แน่ใจว่าคำตอบของ Fetzer เป็นสิ่งที่คุณต้องการทำ แต่ st_box2d อาจทำงานได้
ความคิดของ SS_Rebelious N ° 1 จะใช้ได้ในหลายกรณี แต่ไม่ใช่สำหรับรูปหลายเหลี่ยมเว้าบางส่วน
ฉันคิดว่าคุณต้องสร้าง lw-line เทียมซึ่งมีจุดตามขอบเมื่อเส้นที่ทำยอดจุดตัดข้ามเส้นเหลี่ยมของรูปหลายเหลี่ยมถ้ามีความเป็นไปได้ของเส้นตะวันออก - ตะวันตก
สำหรับสิ่งนี้คุณสามารถลองสร้างรูปหลายเหลี่ยม 4 โหนดที่มีความยาวบรรทัดสูงสร้างรูปหลายเหลี่ยม P * ซึ่งเป็นรูปหลายเหลี่ยมที่ซ้อนทับกันก่อนหน้านี้กับรูปหลายเหลี่ยมเดิมของคุณและดูว่า min (y1) และ max (y2) ความเป็นไปได้ (โดยที่ y1 คือชุดของจุดระหว่างมุมบนซ้ายและมุมบนขวาและ y2 คือชุดของ y ระหว่างมุมซ้ายล่างและมุมขวาล่างของรูปหลายเหลี่ยม 4 โหนดของคุณ) นี่ไม่ใช่เรื่องง่ายที่ฉันหวังว่าคุณจะพบเครื่องมือ psql เพื่อช่วยคุณ!
ฉันมีความคิด-№1 ( แก้ไข:สำหรับกรณีทั่วไปไม่ใช่เฉพาะทิศทาง EW และมีข้อ จำกัด บางอย่างที่อธิบายไว้ในความคิดเห็น) ฉันจะไม่ให้รหัสเพียงแค่แนวคิด "ทิศทาง x" เป็นจริงแอซิมัทซึ่งคำนวณโดย ST_Azimuth ขั้นตอนที่เสนอคือ:
ดูคำถามของฉันและคำตอบจาก Evil Genius
หวังว่ารูปหลายเหลี่ยมทะเลสาบของคุณจะมีจำนวนจุดคุณสามารถสร้างเส้นบนจุดเหล่านี้ด้วยมุมราบ (ทิศทาง, ทิศทางภูมิศาสตร์) เลือกความยาวของเส้นที่มีขนาดใหญ่พอ (ส่วน ST_MakePoint) เพื่อให้คุณสามารถคำนวณเส้นที่สั้นที่สุดระหว่างสองบรรทัดที่อยู่ไกลที่สุด
นี่คือตัวอย่าง:
ตัวอย่างแสดงความกว้างสูงสุดของรูปหลายเหลี่ยม ฉันเลือก ST_ShortestLine (เส้นสีแดง) สำหรับวิธีนี้ ST_MakeLine จะเพิ่มค่า (เส้นสีน้ำเงิน) และจุดสิ้นสุดของบรรทัด (ซ้ายล่าง) จะกดเส้นสีน้ำเงินของรูปหลายเหลี่ยม คุณต้องคำนวณระยะทางด้วยเซนทรอยด์ของบรรทัดที่สร้างขึ้น (ความช่วยเหลือ)
แนวคิดสำหรับรูปหลายเหลี่ยมที่ผิดปกติหรือเว้าสำหรับวิธีนี้ อาจเป็นเพราะคุณต้องตัดรูปหลายเหลี่ยมด้วยแรสเตอร์