Obliczanie maksymalnej odległości w obrębie wielokąta w kierunku x (kierunek wschód-zachód) w PostGIS?


13

Interesuje mnie maksymalna szerokość wielokąta, np. Jeziora, w kierunku wschód-zachód. Ramki ograniczające pomogą tylko w prostych wielokątach, ale nie w złożonych wielokątach wklęsłych.


3
Nie znam funkcji Postgis. Jednak może istnieć narzędzie ramki ograniczającej. Szerokość obwiedni byłaby maksymalną odległością w kierunku EW.
Fezter

4
@Fetzter, który nie jest poprawny: kontrprzykład, nawet dla prostego złożonego wielokąta, jest cienkim rombem rozciągającym się od SW do NE. Jego maksymalna szerokość wschód-zachód może być dowolnie małym ułamkiem szerokości jego obwiedni.
whuber

1
Na podstawie tego i tych propozycji stworzyłem narzędzie do tego zadania . Potrafi obliczyć maksymalną lub minimalną szerokość wielokąta. Obecnie działa z plikami shp, ale możesz przepisać go do pracy z PostGIS lub po prostu poczekać, aż rozwinie się w wtyczkę QGIS, która również będzie działać z PostGIS. Szczegółowy opis i link do pobrania tutaj .
SS_Rebelious

Odpowiedzi:


16

Prawdopodobnie wymaga to trochę skryptów na dowolnej platformie GIS.

Najbardziej efektywną metodą (asymptotycznie) jest przeciąganie linii pionowej: wymaga sortowania krawędzi według ich minimalnych współrzędnych y, a następnie przetwarzania krawędzi od dołu (minimum y) do góry (maksimum y), dla O (e * log ( e)) algorytm, gdy zaangażowane są e zbocza.

Procedura, choć prosta, jest zaskakująco trudna do wykonania we wszystkich przypadkach. Wieloboki mogą być paskudne: mogą mieć zwisające, odłamki, dziury, być rozłączane, mieć zduplikowane wierzchołki, biegi wierzchołków wzdłuż prostych linii i mieć nierozpuszczone granice między dwoma sąsiednimi składnikami. Oto przykład pokazujący wiele z tych cech (i więcej):

Wielokąt

Będziemy w szczególności poszukiwać segmentów poziomych o maksymalnej długości leżących całkowicie w obrębie zamknięcia wielokąta. Na przykład eliminuje to zwis pomiędzy x = 20 a x = 40 emanujący z otworu między x = 10 a x = 25. Łatwo jest wtedy pokazać, że co najmniej jeden z poziomych odcinków o maksymalnej długości przecina co najmniej jeden wierzchołek. (Jeśli istnieją rozwiązania nie przecinające się wierzchołki, będą leżeć we wnętrzu pewnego równoległoboku ograniczonego na górze i na dole przez rozwiązań zrobienia przecinają co najmniej jeden wierzchołek. To daje nam środki, aby znaleźć wszystkie rozwiązania).

W związku z tym przeciąganie linii musi zaczynać się od najniższych wierzchołków, a następnie przesuwać się w górę (to znaczy w kierunku wyższych wartości y), aby zatrzymać się na każdym wierzchołku. Na każdym przystanku znajdujemy wszelkie nowe krawędzie wychodzące z tej wysokości; wyeliminuj wszelkie krawędzie kończące się od dołu na tej wysokości (jest to jeden z kluczowych pomysłów: upraszcza algorytm i eliminuje połowę potencjalnego przetwarzania); i ostrożnie przetwarzaj wszystkie krawędzie leżące całkowicie na stałym poziomie (krawędzie poziome).

Weźmy na przykład stan, gdy osiągnięty zostanie poziom y = 10. Od lewej do prawej znajdują się następujące krawędzie:

      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

W tej tabeli (x.min, y.min) są współrzędnymi dolnego punktu końcowego krawędzi, a (x.max, y.max) są współrzędnymi jego górnego punktu końcowego. Na tym poziomie (y = 10) pierwsza krawędź jest przechwytywana w jej wnętrzu, druga krawędź jest przechwytywana na jej dole i tak dalej. Niektóre krawędzie kończące się na tym poziomie, takie jak od (10,0) do (10,10), nie są uwzględnione na liście.

Aby określić, gdzie znajdują się punkty wewnętrzne i zewnętrzne, wyobraź sobie, że zaczynasz od skrajnej lewej - oczywiście poza wielokątem - i przesuwasz się poziomo w prawo. Za każdym razem, gdy przekraczamy krawędź, która nie jest pozioma , na przemian przełączamy się z zewnątrz na wnętrze i z tyłu. (To kolejny kluczowy pomysł.) Jednak wszystkie punkty w obrębie dowolnej poziomej krawędzi są określone jako znajdujące się wewnątrz wielokąta, bez względu na wszystko. (Zamknięcie wielokąta zawsze obejmuje jego krawędzie.)

Kontynuując przykład, oto posortowana lista współrzędnych x, gdzie krawędzie inne niż poziome zaczynają się od linii y = 10 lub przecinają ją:

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

(Zauważ, że x = 40 nie ma na tej liście.) Wartości interiortablicy oznaczają lewe punkty końcowe segmentów wewnętrznych: 1 oznacza interwał wewnętrzny, 0 interwał zewnętrzny. Zatem pierwsza 1 wskazuje, że przedział od x = 6,7 do x = 10 znajduje się wewnątrz wielokąta. Następne 0 wskazuje, że przedział od x = 10 do x = 20 znajduje się poza wielokątem. I tak dalej: tablica identyfikuje cztery oddzielne przedziały jako wewnątrz wielokąta.

Niektóre z tych przedziałów, takie jak od x = 60 do x = 63,3, nie przecinają żadnych wierzchołków: szybkie sprawdzenie współrzędnych x wszystkich wierzchołków z y = 10 eliminuje takie przedziały.

Podczas skanowania możemy monitorować długości tych przedziałów, zachowując dane dotyczące znalezionych dotychczas przedziałów maksymalnej długości.

Zwróć uwagę na niektóre konsekwencje tego podejścia. Kiedy napotkamy wierzchołek w kształcie litery „v”, powstają dwie krawędzie. Dlatego podczas przełączania występują dwa przełączniki. Te przełączniki się anulują. Każde odwrócone „v” nie jest nawet przetwarzane, ponieważ obie jego krawędzie są eliminowane przed rozpoczęciem skanowania od lewej do prawej. W obu przypadkach taki wierzchołek nie blokuje odcinka poziomego.

Więcej niż dwie krawędzie mogą współdzielić wierzchołek: ilustruje to (10,0), (60,5), (25, 20) i - choć trudno powiedzieć - w (20,10) i (40 , 10). (To dlatego, że dynda idzie (20,10) -> (40,10) -> (40,0) -> (40, -50) -> (40, 10) -> (20, 10) Zauważ, że wierzchołek przy (40,0) znajduje się również wewnątrz innej krawędzi ... to paskudne.) Ten algorytm radzi sobie z tymi sytuacjami w porządku.

Trudna sytuacja została zilustrowana na samym dole: współrzędne x segmentów innych niż poziome

30, 50

Powoduje to, że wszystko po lewej stronie x = 30 jest uważane za zewnętrzne, wszystko między 30 a 50 jest wewnętrzne, a wszystko po 50 ponownie jest zewnętrzne. Wierzchołek przy x = 40 nigdy nie jest nawet brany pod uwagę w tym algorytmie.

Oto jak wygląda wielokąt na końcu skanu. Pokazuję wszystkie wewnętrzne odstępy zawierające wierzchołki w kolorze ciemnoszarym, wszelkie odstępy o maksymalnej długości w kolorze czerwonym i koloruję wierzchołki zgodnie z ich współrzędnymi y. Maksymalny odstęp wynosi 64 jednostki.

Po skanie

Jedynymi wymaganymi obliczeniami geometrycznymi są obliczenia, w których krawędzie przecinają linie poziome: jest to prosta interpolacja liniowa. Obliczenia są również potrzebne do określenia, które zawierają segmenty wewnętrzne wierzchołki: są betweenness ustalenia, łatwo obliczone z kilkoma nierówności. Ta prostota sprawia, że ​​algorytm jest solidny i odpowiedni zarówno dla reprezentacji współrzędnych całkowitych, jak i zmiennoprzecinkowych.

Jeśli współrzędne są geograficzne , wówczas linie poziome są rzeczywiście na okręgach szerokości geograficznej. Ich długości nie są trudne do obliczenia: wystarczy pomnożyć ich długości euklidesowe przez cosinus ich szerokości geograficznej (w modelu sferycznym). Dlatego ten algorytm ładnie dostosowuje się do współrzędnych geograficznych. (Aby poradzić sobie z zawijaniem się wokół studni południka + -180, może być konieczne znalezienie krzywej od bieguna południowego do bieguna północnego, która nie przechodzi przez wielokąt. Po ponownym wyrażeniu wszystkich współrzędnych x jako przemieszczenia poziome względem tego krzywej, ten algorytm poprawnie znajdzie maksymalny segment poziomy).


Poniżej znajduje się Rkod zaimplementowany do wykonywania obliczeń i tworzenia ilustracji.

#
# 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)

Czy istnieje twierdzenie, które dowodzi, że linia o maksymalnej długości wewnątrz wielokąta niewypukłego w danym kierunku przecina przynajmniej jeden wierzchołek tego wielokąta?
SS_Rebelious

@SS Tak, jest. Oto szkic dowodu: jeśli nie ma przecięcia, wówczas punkty końcowe segmentu leżą na wnętrzach krawędzi, a segment można przesuwać, przynajmniej trochę, w górę iw dół. Jego długość jest funkcją liniową wielkości przesunięcia. Zatem może mieć maksymalną długość tylko wtedy, gdy długość nie zmienia się podczas przenoszenia. Oznacza to, że zarówno (a) jest to część równoległoboku utworzonego z segmentów o maksymalnej długości, a (b) zarówno górna, jak i dolna krawędź tego równoległoboku muszą spotkać się z wierzchołkiem QED.
whuber

A jak nazywa się to twierdzenie? Próbuję to znaleźć. BTW, a co z zakrzywionymi krawędziami, które nie mają wierzchołków (mam na myśli podejście teoretyczne)? Mam na myśli szkic przykładu figury (wielokąta w kształcie tępego dzwonu): „C = D”.
SS_Rebelious

@SS Gdy krawędzie są zakrzywione, twierdzenie nie ma już zastosowania. W celu uzyskania użytecznych wyników można zastosować techniki geometrii różniczkowej. Nauczyłem się tych metod z książki Cheegera i Ebina „ Twierdzenia porównawcze w geometrii Riemanniana” . Jednak większość GIS i tak przybliża krzywe szczegółowymi poliliniami, więc pytanie (w praktyce) jest dyskusyjne.
whuber

czy możesz podać nazwę twierdzenia (i stronę, jeśli to możliwe)? Mam książkę i nie byłem w stanie znaleźć potrzebnego twierdzenia.
SS_Rebelious

9

Oto rozwiązanie oparte na rastrze. Jest szybki (całą pracę wykonałem od początku do końca w 14 minut), nie wymaga skryptów, zajmuje tylko kilka operacji i jest dość dokładny.

Zacznij od rastrowej reprezentacji wielokąta. Ten wykorzystuje siatkę 550 wierszy i 1200 kolumn:

Wielokąt

W tej reprezentacji szare (wewnętrzne) komórki mają wartość 1, a wszystkie pozostałe komórki to NoData.

Oblicz akumulację przepływu w kierunku z zachodu na wschód, używając wartości komórek jednostkowych dla siatki ciężaru (ilość „opadów”):

Akumulacja przepływu

Niska akumulacja jest ciemna, zwiększając się do najwyższych akumulacji w jasnożółtym.

Strefowe maksimum (używając wielokąta dla siatki i akumulacji przepływu dla wartości) identyfikuje komórkę (komórki), w których przepływ jest największy. Aby to pokazać, musiałem powiększyć w prawym dolnym rogu:

Maksymalny

Czerwone krwinki zaznaczają końce najwyższych akumulacji przepływu: są to skrajnie prawe punkty końcowe wewnętrznych odcinków wielokąta o maksymalnej długości.

Aby znaleźć te segmenty, umieść cały ciężar na czerwonych krwinkach i uruchom przepływ wstecz!

Wynik

Czerwony pasek u dołu oznacza dwa rzędy komórek: w nich znajduje się odcinek poziomy o maksymalnej długości. Użyj tej prezentacji w obecnej postaci do dalszej analizy lub przekonwertuj ją na kształt polilinii (lub wielokąta).

Wystąpił błąd dyskretyzacji związany z reprezentacją rastrową. Można to zmniejszyć, zwiększając rozdzielczość, przy pewnym koszcie w czasie obliczeń.


Jednym z naprawdę fajnych aspektów tego podejścia jest to, że zwykle znajdujemy ekstremalne wartości rzeczy w ramach większego przepływu pracy, w którym należy osiągnąć pewien cel: umieszczenie rurociągu lub boiska do piłki nożnej, tworzenie buforów ekologicznych i tak dalej. Proces obejmuje kompromisy. Zatem najdłuższa linia pozioma może nie być częścią optymalnego rozwiązania. Zamiast tego powinniśmy wiedzieć, gdzie leżą prawie najdłuższe linie. Jest to proste: zamiast wybierać strefowy maksymalny przepływ, zaznacz wszystkie komórki w pobliżu maksymalnego strefowego. W tym przykładzie strefowa maksimum wynosi 744 (liczba kolumn rozciągnięta przez najdłuższy segment wewnętrzny). Zamiast tego zaznaczmy wszystkie komórki w granicach 5% tego maksimum:

Wybrane prawie optymalne komórki

Uruchomienie przepływu ze wschodu na zachód tworzy tę kolekcję segmentów poziomych:

Prawie optymalne rozwiązania

Jest to mapa lokalizacji, w których nieprzerwany zasięg wschód-zachód wynosi 95% lub więcej niż maksymalny zasięg wschód-zachód w dowolnym miejscu wielokąta.


3

Dobrze. Mam inny (lepszy) pomysł ( pomysł nr 2 ). Ale przypuszczam, że lepiej jest być realizowanym jako skrypt Pythona, a nie jako kwerenda SQL. Ponownie tutaj jest powszechny przypadek, nie tylko EW.

Będziesz potrzebował ramki granicznej dla wielokąta i azymutu (A) jako kierunku pomiaru. Załóżmy, że długość krawędzi BBox to LA i LB. Maksymalna możliwa odległość (MD) wewnątrz wielokąta jest: MB = (LA^2 * LB^2)^(1/2), więc poszukiwanie wartości (V) jest nie większy niż MB: V <= MB.

  1. Zaczynając od dowolnego wierzchołka BBoxa utwórz linię (LL) o długości MB i azymucie A.
  2. Przecinaj linię LL z wielokątem, aby uzyskać linię przecięcia (IL)
  3. Sprawdź geometrię IL - jeśli w linii IL są tylko dwa punkty, oblicz jej długość. Jeśli 4 lub więcej - oblicz segmenty i wybierz długość najdłuższego. Null (brak skrzyżowania) - zignoruj.
  4. Powtarzaj tworzenie kolejnych linii LL przesuwających się od punktu początkowego w kierunku przeciwnym do ruchu wskazówek zegara lub w kierunku krawędzi BBox, dopóki nie skończysz w punkcie początkowym (wykonasz całą pętlę przez BBox).
  5. Wybierz największą wartość długości IL (w rzeczywistości nie musisz przechowywać wszystkich długości, możesz zachować maksymalną wartość „jak dotąd” podczas zapętlania) - to będzie to, czego szukasz.

Brzmi to jak podwójna pętla nad wierzchołkami: jest to na tyle nieefektywne, że należy tego unikać (z wyjątkiem bardzo uproszczonych wielokątów).
whuber

@ Whuber, nie widzę tutaj żadnych dodatkowych pętli. Jest tylko pewne bezsensowne przetwarzanie 2 stron BB, które da nic poza zerami. Ale to przetwarzanie zostało wykluczone w skrypcie, który podałem w odpowiedzi, która została tutaj usunięta (wydaje się, że jest to teraz komentarz, ale nie widzę go jako komentarza - tylko jako usuniętą odpowiedź)
SS_Rebelious

(1) Jest to trzeci komentarz do pytania. (2) Masz rację: po uważnym przeczytaniu opisu wydaje mi się teraz, że znajdujesz najdłuższy odcinek między (czterema) wierzchołkami obwiedni i wierzchołkami wielokąta. Nie rozumiem jednak, jak to odpowiada na pytanie: wynik zdecydowanie nie jest tym, o co zabiegał PO.
whuber

@ whuber, proponowany algorytm znajduje najdłuższe przecięcie wielokąta z linią reprezentującą dany kierunek. Najwyraźniej wynik JEST tym, o co pytano, czy odległość między liniami przecięcia -> 0, czy mija wszystkie wierzchołki (dla figur nie zakrzywionych).
SS_Rebelious

3

Nie jestem pewien, czy odpowiedź Fetzera jest tym, co chcesz zrobić, ale dlatego st_box2d może wykonać to zadanie.

Pomysł SS_Rebeliousa nr 1 zadziała w wielu przypadkach, ale nie w przypadku niektórych wklęsłych wielokątów.

Myślę, że musisz stworzyć sztuczne linie LW, których punkty podążają za krawędziami, gdy linie wykonane przez wierzchołki przecinają granice wielokąta, jeśli istnieje możliwość linii wschód-zachód. przykład, w którym to nie zadziała

W tym celu możesz spróbować zrobić wielokąt o 4 węzłach, w którym długość linii jest wysoka, uczyń wielokąt P *, który jest poprzednim zachodzącym na ciebie oryginalnym wielokątem, i sprawdź, czy min (y1) i max (y2) pozostawiają jakąś linię x możliwość. (gdzie y1 jest zbiorem punktu między lewym górnym rogiem a prawym górnym rogiem, a y2 zbiorem y między lewym dolnym i prawym dolnym rogiem 4-węzłowego wielokąta). To nie jest takie proste Mam nadzieję, że znajdziesz narzędzia psql, które ci pomogą!


To jest na dobrej drodze. Najdłuższy odcinek EW znajdzie się między przecięciami z wnętrzem wielokąta z poziomymi liniami przechodzącymi przez wierzchołki wielokąta. Wymaga to pętli kodu nad wierzchołkami. Dostępna jest alternatywna (ale równoważna) metoda polegająca na sztucznym przepływie wschód-zachód przez reprezentację rastrową wielokąta: maksymalna długość przepływu znaleziona w wielokącie (która jest jedną z jego „statystyk strefowych”) ma pożądaną szerokość. Rozwiązanie rastrowe uzyskuje się w zaledwie 3 lub 4 krokach i nie wymaga zapętlania ani pisania skryptów.
whuber

@ Nazwa, proszę dodać „1” do „Pomysłu SS_Rebeliousa”, aby uniknąć nieporozumień: dodałem kolejną propozycję. Nie mogę samodzielnie edytować twojej odpowiedzi, ponieważ ta edycja ma mniej niż 6 znaków.
SS_Rebelious

1

Mam pomysł - №1 ( edycja : dla zwykłego przypadku, nie tylko kierunek EW i z pewnymi ograniczeniami opisanymi w komentarzach). Nie podam kodu, tylko koncepcję. „Kierunek x” jest w rzeczywistości azymutem, który jest obliczany przez ST_Azimuth. Proponowane kroki to:

  1. Wyodrębnij wszystkie wierzchołki z wielokąta jako punkty.
  2. Utwórz linie między każdą parą punktów.
  3. Wybierz linie (nazwijmy je liniami LW), które znajdują się w oryginalnym wielokącie (nie potrzebujemy linii, które przekroczą granice wielokąta).
  4. Znajdź odległości i azymuty dla każdej linii LW.
  5. Wybierz najdłuższą odległość od linii lw, w których azymut jest równy poszukiwanemu azymutowi lub leży w pewnym przedziale (być może żaden azymut nie będzie dokładnie taki sam, jak poszukiwany azymut).

To nie zadziała nawet w przypadku niektórych trójkątów , takich jak ten w wierzchołkach (0,0), (1000, 1000) i (501, 499). Jego maksymalna szerokość wschód-zachód wynosi około 2; azymuty mają około 45 stopni; i niezależnie od tego, najkrótszy odcinek linii między wierzchołkami jest ponad 350 razy dłuższy niż szerokość wschód-zachód.
whuber

@ whuber, masz rację, nie powiedzie się w przypadku trójkątów, ale w przypadku wielokątów reprezentujących niektóre cechy natury może być przydatny.
SS_Rebelious

1
Trudno polecić procedurę, która dramatycznie się nie udaje, nawet w prostych przypadkach, mając nadzieję, że czasem uzyska prawidłową odpowiedź!
whuber

@ Whuber, więc nie polecaj tego! ;-) Zaproponowałem to obejście, ponieważ nie było odpowiedzi na to pytanie. Zauważ, że możesz opublikować swoją lepszą odpowiedź. BTW, jeśli
umieścisz

Zasugerowałem kilka podejść. Raster jest na gis.stackexchange.com/questions/32552/... i opracowany na forums.esri.com/Thread.asp?c=93&f=982&t=107703&mc=3 . Kolejny - nie do końca odpowiedni, ale mający ciekawe zastosowania - znajduje się na stronie gis.stackexchange.com/questions/23664/… (transformacja radonu). Ilustruje to stats.stackexchange.com/a/33102 .
whuber

1

Spójrz na moje pytanie i odpowiedź Geniusza Zła.

Mam nadzieję, że twój wielokąt jeziora ma wiele punktów, możesz tworzyć linie na tych punktach z azymutem (aspekt, kierunek geograficzny). Wybierz wystarczająco dużą długość linii (część ST_MakePoint), abyś mógł obliczyć najkrótszą linię między dwiema najbardziej odległymi liniami.

Oto przykład:

wprowadź opis zdjęcia tutaj

Przykład pokazuje maksymalną szerokość wielokąta. Wybieram ST_ShortestLine (czerwona linia) dla tego podejścia. ST_MakeLine zwiększy wartość (niebieska linia), a punkt końcowy linii (lewy dolny róg) uderzy w niebieską linię wielokąta. Musisz obliczyć odległość za pomocą centroidów utworzonych linii (pomocy).

Pomysł na nieregularne lub wklęsłe wielokąty dla tego podejścia. Być może będziesz musiał przeciąć wielokąt rastrem.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.