คำนวณระยะทางสูงสุดภายในรูปหลายเหลี่ยมในทิศทาง x (ทิศตะวันออก - ตะวันตก) ใน PostGIS หรือไม่


13

ฉันสนใจในความกว้างสูงสุดของรูปหลายเหลี่ยมเช่นทะเลสาบในทิศทางตะวันออก - ตะวันตก กล่องที่ถูกผูกไว้จะช่วยในรูปหลายเหลี่ยมอย่างง่ายเท่านั้น แต่ไม่ได้อยู่ในรูปหลายเหลี่ยมหลายเหลี่ยมที่ซับซ้อน


3
ฉันไม่คุ้นเคยกับฟังก์ชั่น postgis อย่างไรก็ตามอาจมีเครื่องมือกล่องขอบเขต ความกว้างของกล่องขอบจะเป็นระยะทางสูงสุดในทิศทาง EW
Fezter

4
@Fetzter ที่ไม่ถูกต้อง: ตัวอย่างที่เป็นรูปหลายเหลี่ยมที่ซับซ้อนแม้จะเป็นรูปสี่เหลี่ยมขนมเปียกปูนเรียบง่ายเป็นรูปสี่เหลี่ยมขนมเปียกปูนบางขยายจาก SW ถึง NE ความกว้างตะวันออก - ตะวันตกสูงสุดของมันอาจเป็นเพียงส่วนเล็ก ๆ ของความกว้างของกล่อง จำกัด
whuber

1
ผมได้สร้างโปรแกรมสำหรับงานนี้บนพื้นฐานนี้และนี้ข้อเสนอ สามารถคำนวณความกว้างสูงสุดหรือต่ำสุดของรูปหลายเหลี่ยมได้ ขณะนี้มันใช้งานได้กับไฟล์ shp แต่คุณสามารถเขียนใหม่เพื่อทำงานกับ PostGIS หรือรอสักครู่จนกว่ามันจะพัฒนาเป็นปลั๊กอิน QGIS ที่จะทำงานกับ PostGIS เช่นกัน คำอธิบายรายละเอียดและดาวน์โหลดเชื่อมโยงที่นี่
SS_Rebelious

คำตอบ:


16

สิ่งนี้น่าจะต้องมีสคริปต์ในแพลตฟอร์ม 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)

มีทฤษฎีบทที่พิสูจน์ให้เห็นว่าเส้นความยาวสูงสุดภายในรูปหลายเหลี่ยมที่ไม่มีนูนในทิศทางใดก็ตามที่กำหนดจุดยอดของรูปหลายเหลี่ยมนี้อย่างน้อยหนึ่งจุดหรือไม่?
SS_Rebelious

@SS ใช่มี นี่คือภาพร่างของการพิสูจน์: หากไม่มีจุดตัดจุดปลายของส่วนนั้นจะอยู่ด้านในของขอบและส่วนนั้นสามารถเคลื่อนย้ายได้อย่างน้อยก็น้อยขึ้นและลง ความยาวของมันคือฟังก์ชันเชิงเส้นของปริมาณการกระจัด ดังนั้นจึงสามารถมีความยาวสูงสุดเฉพาะในกรณีที่ความยาวไม่เปลี่ยนแปลงเมื่อถูกย้าย นี่หมายถึงทั้ง (a) มันเป็นส่วนหนึ่งของสี่เหลี่ยมด้านขนานที่เกิดขึ้นจากส่วนยาวสูงสุดและ (b) ทั้งขอบด้านบนและด้านล่างของสี่เหลี่ยมด้านขนานนั้นจะต้องพบจุดสุดยอด QED
whuber

และชื่อของทฤษฎีบทนี้คืออะไร? ฉันพยายามหามัน BTW สิ่งที่เกี่ยวกับขอบโค้งที่ไม่มีจุดสุดยอด (ฉันหมายถึงวิธีการทางทฤษฎี)? ภาพร่างของตัวอย่างของรูปที่ฉันหมายถึง (รูปหลายเหลี่ยมรูปดัมเบลล์): "C = D"
SS_Rebelious

@SS เมื่อขอบโค้งทฤษฎีบทไม่ได้ถืออีกต่อไป สามารถใช้เทคนิคเรขาคณิตเชิงอนุพันธ์เพื่อให้ได้ผลลัพธ์ที่เป็นประโยชน์ ผมได้เรียนรู้วิธีการเหล่านี้จาก Cheeger & Ebin หนังสือ, เปรียบเทียบทฤษฎีบทในรีมันเรขาคณิต อย่างไรก็ตาม GISes ส่วนใหญ่จะประมาณเส้นโค้งโดย polylines ที่มีรายละเอียดอยู่แล้วดังนั้นคำถาม (เป็นเรื่องที่ปฏิบัติ) เป็น moot
whuber

คุณสามารถระบุชื่อของทฤษฎีบท (และหน้าถ้าเป็นไปได้)? ฉันได้หนังสือมาแล้วและฉันไม่สามารถหาทฤษฎีบทที่ต้องการได้
SS_Rebelious

9

นี่คือวิธีการแก้ปัญหาตามแรสเตอร์ มันเร็ว (ฉันทำงานทั้งหมดตั้งแต่ต้นจนจบใน 14 นาที) ไม่ต้องใช้สคริปต์ใช้การดำเนินการเพียงไม่กี่ครั้งและมีความแม่นยำพอสมควร

เริ่มต้นด้วยการเป็นตัวแทนแรสเตอร์ของรูปหลายเหลี่ยม อันนี้ใช้กริด 550 แถวและ 1200 คอลัมน์:

รูปหลายเหลี่ยม

ในการแสดงนี้เซลล์สีเทา (ภายใน) มีค่า 1 และเซลล์อื่น ๆ ทั้งหมดคือ NoData

คำนวณการสะสมการไหลในทิศทางตะวันตกไปตะวันออกโดยใช้ค่าเซลล์หน่วยสำหรับตารางน้ำหนัก (จำนวน "ปริมาณน้ำฝน"):

การสะสมการไหล

การสะสมที่ต่ำคือความมืดเพิ่มการสะสมสูงสุดในสีเหลืองสดใส

Zonal maximum (การใช้รูปหลายเหลี่ยมสำหรับกริดและการสะสมโฟลว์สำหรับค่า) ระบุเซลล์ (s) โดยที่การไหลมากที่สุด ในการแสดงสิ่งเหล่านี้ฉันต้องซูมไปทางขวาล่าง:

ขีดสุด

เซลล์สีแดงทำเครื่องหมายจุดสิ้นสุดของการไหลสะสมสูงสุด: เป็นจุดสิ้นสุดที่ถูกต้องของส่วนภายในที่มีความยาวสูงสุดของรูปหลายเหลี่ยม

หากต้องการค้นหากลุ่มเหล่านี้ให้วางน้ำหนักทั้งหมดที่เซลล์สีแดงและไหลย้อนกลับ!

ผลลัพธ์

แถบสีแดงใกล้ด้านล่างทำเครื่องหมายสองแถวของเซลล์: ภายในส่วนนั้นจะอยู่ในส่วนแนวนอนที่มีความยาวสูงสุด ใช้การแทนค่านี้ตามที่เป็นอยู่สำหรับการวิเคราะห์เพิ่มเติมหรือแปลงเป็นรูปหลายเหลี่ยม (หรือรูปหลายเหลี่ยม)

มีข้อผิดพลาด discretization เกิดขึ้นกับการเป็นตัวแทนแรสเตอร์ มันสามารถลดลงได้โดยการเพิ่มความละเอียดในบางเวลาในการคำนวณ


แง่มุมที่ดีอย่างหนึ่งของวิธีการนี้คือโดยทั่วไปแล้วเราจะพบคุณค่าของสิ่งต่าง ๆ มากที่สุดซึ่งเป็นส่วนหนึ่งของกระบวนการทำงานที่มีขนาดใหญ่ขึ้นซึ่งต้องบรรลุวัตถุประสงค์บางประการเช่นการวางท่อหรือสนามฟุตบอลการสร้างบัฟเฟอร์เชิงนิเวศน์ กระบวนการเกี่ยวข้องกับการแลกเปลี่ยน ดังนั้นเส้นแนวนอนที่ยาวที่สุดอาจไม่ได้เป็นส่วนหนึ่งของทางออกที่ดีที่สุด เราอาจจะดูแลแทนที่จะทราบว่าเกือบสายที่ยาวที่สุดจะโกหก นี่เป็นเรื่องง่าย: แทนที่จะเลือกโฟลวสูงสุดของโซนเลือกเซลล์ทั้งหมดใกล้กับสูงสุดของโซน ในตัวอย่างนี้ zonal max เท่ากับ 744 (จำนวนคอลัมน์ที่ขยายโดยส่วนภายในที่ยาวที่สุด) แต่ขอเลือกเซลล์ทั้งหมดภายใน 5% ของสูงสุดที่:

เลือกเซลล์ที่เหมาะสมที่สุด

การไหลจากตะวันออกไปตะวันตกทำให้เกิดกลุ่มแนวนอนนี้:

โซลูชันที่ใกล้เคียงที่สุด

นี่คือแผนที่ของสถานที่ที่ขอบเขตตะวันออก - ตะวันตกไม่ถูกรบกวน 95% หรือมากกว่าขอบเขตตะวันออก - ตะวันตกสูงสุดที่ใดก็ได้ภายในรูปหลายเหลี่ยม


3

ตกลง. ฉันมีความคิดอื่น (ดีกว่า) ( ความคิด - №2 ) แต่ฉันคิดว่ามันจะดีกว่าที่จะรับรู้เป็นสคริปต์หลามไม่เป็น SQL-querry อีกครั้งที่นี่เป็นกรณีทั่วไปไม่ใช่แค่ EW

คุณจะต้องใช้กล่องขอบเขตสำหรับรูปหลายเหลี่ยมและมุมราบ (A) ตามทิศทางการวัดของคุณ สมมติว่าความยาวของขอบ BBox คือ LA และ LB ระยะทางที่เป็นไปได้สูงสุด (MD) ภายในรูปหลายเหลี่ยมคือMB = (LA^2 * LB^2)^(1/2)ดังนั้นการแสวงหาค่า (V) ไม่ได้มีขนาดใหญ่กว่า V <= MBMB:

  1. เริ่มต้นจากจุดสุดยอดของ BBox ใด ๆ สร้างเส้น (LL) ที่มีความยาว MB และ azimuth A
  2. ตัดกันเส้น LL ด้วยรูปหลายเหลี่ยมเพื่อให้ได้จุดตัดกัน (IL)
  3. ตรวจสอบรูปทรงเรขาคณิตของ IL - หากมีเพียงสองจุดในบรรทัด IL ให้คำนวณความยาวของมัน ถ้า 4 หรือมากกว่า - คำนวณส่วนและรับความยาวของส่วนที่ยาวที่สุด Null (ไม่มีทางแยกเลย) - ข้าม
  4. สร้างเส้น LL อีกเส้นที่เคลื่อนที่จากจุดเริ่มต้นหรือตามเข็มนาฬิกาไปที่ขอบของ BBox จนกว่าคุณจะไม่จบลงที่จุดเริ่มต้น
  5. เลือกค่าความยาว IL ที่ใหญ่ที่สุด (จริงๆแล้วคุณไม่จำเป็นต้องเก็บทุกความยาวคุณสามารถเก็บค่าสูงสุดเพียง 'จนถึง' ขณะวนลูป) - มันจะเป็นสิ่งที่คุณต้องการ

ฟังดูเหมือนเป็นลูปสองครั้งเหนือจุดยอด: มันไม่มีประสิทธิภาพเพียงพอที่จะหลีกเลี่ยงได้ (ยกเว้นรูปหลายเหลี่ยมที่ง่ายมาก)
whuber

@whuber ฉันไม่เห็นลูปพิเศษใด ๆ ที่นี่ มีเพียงการประมวลผลที่ไร้ความหมายของสองด้านของ BB ที่จะไม่ให้อะไรนอกจากเป็นโมฆะ แต่การประมวลผลนี้ไม่รวมอยู่ในสคริปต์ที่ฉันให้ไว้ในคำตอบที่ถูกลบที่นี่ (ดูเหมือนว่าตอนนี้มันเป็นความคิดเห็น แต่ฉันไม่เห็นว่ามันเป็นความคิดเห็น - เป็นเพียงคำตอบที่ถูกลบ)
SS_Rebelious

(1) มันเป็นความคิดเห็นที่สามของคำถาม (2) คุณพูดถูก: เมื่ออ่านคำอธิบายของคุณอย่างระมัดระวังตอนนี้ฉันกำลังหากลุ่มที่ยาวที่สุดระหว่างจุดยอด (สี่) ของกล่องขอบและจุดยอดของรูปหลายเหลี่ยม ฉันไม่เห็นว่าสิ่งนี้ตอบคำถามอย่างไร: ผลลัพธ์ไม่ใช่สิ่งที่ OP ต้องการ
whuber

@whuber อัลกอริธึมที่นำเสนอค้นหาจุดตัดยาวที่สุดของรูปหลายเหลี่ยมที่มีเส้นที่แสดงถึงทิศทางที่กำหนด เห็นได้ชัดว่าผลลัพธ์คือสิ่งที่ถูกถามว่าระยะห่างระหว่างเส้นตัด -> 0 หรือผ่านจุดยอดทั้งหมด (ไม่ใช่ตัวเลขโค้ง)
SS_Rebelious

3

ฉันไม่แน่ใจว่าคำตอบของ Fetzer เป็นสิ่งที่คุณต้องการทำ แต่ st_box2d อาจทำงานได้

ความคิดของ SS_Rebelious N ° 1 จะใช้ได้ในหลายกรณี แต่ไม่ใช่สำหรับรูปหลายเหลี่ยมเว้าบางส่วน

ฉันคิดว่าคุณต้องสร้าง lw-line เทียมซึ่งมีจุดตามขอบเมื่อเส้นที่ทำยอดจุดตัดข้ามเส้นเหลี่ยมของรูปหลายเหลี่ยมถ้ามีความเป็นไปได้ของเส้นตะวันออก - ตะวันตก ตัวอย่างที่ใช้ไม่ได้

สำหรับสิ่งนี้คุณสามารถลองสร้างรูปหลายเหลี่ยม 4 โหนดที่มีความยาวบรรทัดสูงสร้างรูปหลายเหลี่ยม P * ซึ่งเป็นรูปหลายเหลี่ยมที่ซ้อนทับกันก่อนหน้านี้กับรูปหลายเหลี่ยมเดิมของคุณและดูว่า min (y1) และ max (y2) ความเป็นไปได้ (โดยที่ y1 คือชุดของจุดระหว่างมุมบนซ้ายและมุมบนขวาและ y2 คือชุดของ y ระหว่างมุมซ้ายล่างและมุมขวาล่างของรูปหลายเหลี่ยม 4 โหนดของคุณ) นี่ไม่ใช่เรื่องง่ายที่ฉันหวังว่าคุณจะพบเครื่องมือ psql เพื่อช่วยคุณ!


นี่คือเส้นทางที่ถูกต้อง ส่วนที่ยาวที่สุดของ EW จะพบได้ในทางแยกด้วยการตกแต่งภายในของรูปหลายเหลี่ยมที่มีเส้นแนวนอนผ่านจุดยอดของรูปหลายเหลี่ยม ต้องใช้รหัสในการวนรอบจุดยอด มีวิธีทางเลือก (แต่เทียบเท่า) ที่มีให้โดยการทำตามการไหลแบบตะวันออก - ตะวันตกที่เป็นรูปธรรมในรูปตัวแทนแรสเตอร์ของรูปหลายเหลี่ยม: ความยาวของการไหลสูงสุดที่พบในรูปหลายเหลี่ยม (ซึ่งเป็นหนึ่งใน วิธีการแก้ปัญหาแรสเตอร์จะได้รับเพียง 3 หรือ 4 ขั้นตอนและไม่จำเป็นต้องวนซ้ำหรือการเขียนสคริปต์
whuber

@ ชื่อโปรดเพิ่ม "№1" ใน "ความคิดของ SS_Rebelious" เพื่อหลีกเลี่ยงความเข้าใจผิด: ฉันได้เพิ่มข้อเสนออื่น ฉันไม่สามารถแก้ไขคำตอบของคุณเองได้เนื่องจากการแก้ไขนี้มีความยาวน้อยกว่า 6 ตัวอักษร
SS_Rebelious

1

ฉันมีความคิด-№1 ( แก้ไข:สำหรับกรณีทั่วไปไม่ใช่เฉพาะทิศทาง EW และมีข้อ จำกัด บางอย่างที่อธิบายไว้ในความคิดเห็น) ฉันจะไม่ให้รหัสเพียงแค่แนวคิด "ทิศทาง x" เป็นจริงแอซิมัทซึ่งคำนวณโดย ST_Azimuth ขั้นตอนที่เสนอคือ:

  1. แยกจุดยอดทั้งหมดจากรูปหลายเหลี่ยมเป็นจุด
  2. สร้างเส้นระหว่างคะแนนทุกคู่
  3. เลือกเส้น (ให้เรียกมันว่าเส้น lw) ที่อยู่ภายในรูปหลายเหลี่ยมดั้งเดิม (เราไม่ต้องการเส้นที่จะข้ามเส้นขอบของรูปหลายเหลี่ยม)
  4. ค้นหาระยะทางและ azimuths สำหรับทุก ๆ lw-line
  5. เลือกระยะทางที่ยาวที่สุดจาก lw-line ที่ azimuth เท่ากับ azimuth ที่ต้องการหาหรืออยู่ในบางช่วงเวลา

สิ่งนี้จะไม่สามารถใช้งานได้กับสามเหลี่ยมบางอันเช่นที่จุดยอด (0,0), (1,000, 1,000) และ (501, 499) ความกว้างตะวันออก - ตะวันตกสูงสุดประมาณ 2 ที่ราบประมาณ 45 องศา; และไม่คำนึงถึงส่วนของเส้นที่สั้นที่สุดระหว่างจุดยอดนั้นยาวกว่าความกว้างตะวันออก - ตะวันตกมากกว่า 350 เท่า
whuber

@whuber คุณถูกต้องมันจะล้มเหลวสำหรับรูปสามเหลี่ยม แต่สำหรับรูปหลายเหลี่ยมซึ่งแสดงถึงลักษณะบางอย่างที่เป็นประโยชน์อาจเป็นประโยชน์
SS_Rebelious

1
มันยากที่จะแนะนำขั้นตอนที่ล้มเหลวอย่างมากแม้ในกรณีง่าย ๆ ด้วยความหวังว่าบางครั้งมันอาจได้รับคำตอบที่ถูกต้อง!
whuber

@ โฮเบอร์ดังนั้นอย่าแนะนำเลย! ;-) ฉันเสนอวิธีแก้ปัญหานี้เพราะไม่มีคำตอบสำหรับคำถามนี้ สังเกตว่าคุณอาจโพสต์คำตอบที่ดีกว่าของคุณเอง BTW ถ้าคุณจะวางบางจุดบนขอบสามเหลี่ยมข้อเสนอของฉันจะใช้งานได้ ;-)
SS_Rebelious

ฉันแนะนำหลายวิธี ภาพแรสเตอร์หนึ่งที่gis.stackexchange.com/questions/32552/...และเนื้อหาที่forums.esri.com/Thread.asp?c=93&f=982&t=107703&mc=3 อีกอันหนึ่ง - ไม่ค่อยเหมาะสม แต่มีการใช้ที่น่าสนใจ - อยู่ที่gis.stackexchange.com/questions/23664/… (การเปลี่ยนเรดอน) นี่คือตัวอย่างที่stats.stackexchange.com/a/33102
whuber

1

ดูคำถามของฉันและคำตอบจาก Evil Genius

หวังว่ารูปหลายเหลี่ยมทะเลสาบของคุณจะมีจำนวนจุดคุณสามารถสร้างเส้นบนจุดเหล่านี้ด้วยมุมราบ (ทิศทาง, ทิศทางภูมิศาสตร์) เลือกความยาวของเส้นที่มีขนาดใหญ่พอ (ส่วน ST_MakePoint) เพื่อให้คุณสามารถคำนวณเส้นที่สั้นที่สุดระหว่างสองบรรทัดที่อยู่ไกลที่สุด

นี่คือตัวอย่าง:

ป้อนคำอธิบายรูปภาพที่นี่

ตัวอย่างแสดงความกว้างสูงสุดของรูปหลายเหลี่ยม ฉันเลือก ST_ShortestLine (เส้นสีแดง) สำหรับวิธีนี้ ST_MakeLine จะเพิ่มค่า (เส้นสีน้ำเงิน) และจุดสิ้นสุดของบรรทัด (ซ้ายล่าง) จะกดเส้นสีน้ำเงินของรูปหลายเหลี่ยม คุณต้องคำนวณระยะทางด้วยเซนทรอยด์ของบรรทัดที่สร้างขึ้น (ความช่วยเหลือ)

แนวคิดสำหรับรูปหลายเหลี่ยมที่ผิดปกติหรือเว้าสำหรับวิธีนี้ อาจเป็นเพราะคุณต้องตัดรูปหลายเหลี่ยมด้วยแรสเตอร์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.