Calcolo della distanza massima all'interno del poligono in direzione x (direzione est-ovest) in PostGIS?


13

Sono interessato alla larghezza massima di un poligono, ad esempio un lago, in direzione est-ovest. Le scatole di delimitazione aiuteranno solo in poligoni semplici ma non in poligoni concavi complessi.


3
Non ho familiarità con la funzionalità postgis. Tuttavia, potrebbe esserci uno strumento riquadro di selezione. La larghezza del riquadro di delimitazione sarebbe la distanza massima nella direzione EW.
Fezter

4
@Fetzter non è corretto: un controesempio, anche per un semplice poligono complesso, è un rombo sottile che si estende da SW a NE. La sua larghezza massima est-ovest può essere una frazione arbitrariamente piccola della larghezza del suo rettangolo di selezione.
whuber

1
Ho creato un'utilità per questo compito basata su questa e questa proposta. È in grado di calcolare la larghezza massima o minima del poligono. Attualmente funziona con un file shp, ma è possibile riscriverlo per funzionare con un PostGIS o attendere qualche istante fino a quando non si evolve in un plug-in QGIS che funzionerà anche con PostGIS. Descrizione dettagliata e link per il download qui .
SS_Rebelious,

Risposte:


16

Ciò probabilmente richiede alcuni script in qualsiasi piattaforma GIS.

Il metodo più efficiente (asintoticamente) è uno sweep di linea verticale: richiede l'ordinamento dei bordi in base alle loro coordinate y minime e quindi l'elaborazione dei bordi dal basso (minimo y) all'inizio (massimo y), per un O (e * log ( e)) algoritmo quando sono coinvolti i bordi elettronici .

La procedura, sebbene semplice, è sorprendentemente difficile da ottenere in tutti i casi. I poligoni possono essere cattivi: possono avere penzoloni, schegge, buchi, essere disconnessi, avere vertici duplicati, corse di vertici lungo linee rette e avere confini non risolti tra due componenti adiacenti. Ecco un esempio che mostra molte di queste caratteristiche (e altro):

Un poligono

Cercheremo specificamente i segmenti orizzontali di lunghezza massima che si trovano interamente all'interno della chiusura del poligono. Ad esempio, questo elimina il ciondolo tra x = 20 e x = 40 proveniente dal foro tra x = 10 e x = 25. È quindi semplice mostrare che almeno uno dei segmenti orizzontali di massima lunghezza interseca almeno un vertice. (Se ci sono soluzioni che si intersecano senza vertici, si trovano nella parte interna di alcuni parallelogramma delimitata in alto e in basso da soluzioni che fanno si intersecano almeno un vertice. Questo ci dà un mezzo per trovare tutte le soluzioni.)

Di conseguenza, lo sweep di linea deve iniziare con i vertici più bassi e quindi spostarsi verso l'alto (cioè verso valori y più alti) per fermarsi ad ogni vertice. Ad ogni fermata, troviamo eventuali nuovi bordi che emanano verso l'alto da quella elevazione; eliminare eventuali spigoli che terminano dal basso a tale elevazione (questa è una delle idee chiave: semplifica l'algoritmo ed elimina la metà della potenziale elaborazione); ed elaborare con cura tutti i bordi che giacciono interamente ad un'elevazione costante (i bordi orizzontali).

Ad esempio, considerare lo stato quando viene raggiunto un livello di y = 10. Da sinistra a destra, troviamo i seguenti bordi:

      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

In questa tabella, (x.min, y.min) sono le coordinate dell'endpoint inferiore del bordo e (x.max, y.max) sono le coordinate del suo endpoint superiore. A questo livello (y = 10), il primo bordo viene intercettato al suo interno, il secondo viene intercettato nella parte inferiore e così via. Alcuni bordi che terminano a questo livello, come da (10,0) a (10,10), non sono inclusi nell'elenco.

Per determinare dove si trovano i punti interni e quelli esterni, immagina di partire dall'estrema sinistra - che ovviamente si trova all'esterno del poligono - e di spostarti orizzontalmente verso destra. Ogni volta che attraversiamo un bordo che non è orizzontale , alterniamo alternativamente da esterno a interno e posteriore. (Questa è un'altra idea chiave.) Tuttavia, tutti i punti all'interno di qualsiasi bordo orizzontale sono determinati ad essere all'interno del poligono, non importa quale. (La chiusura di un poligono include sempre i suoi bordi.)

Continuando l'esempio, ecco l'elenco ordinato di coordinate x in cui i bordi non orizzontali iniziano o attraversano la linea y = 10:

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

(Si noti che x = 40 non è in questo elenco.) I valori interiordell'array indicano gli endpoint di sinistra dei segmenti interni: 1 indica un intervallo interno, 0 un intervallo esterno. Pertanto, il primo 1 indica che l'intervallo da x = 6,7 a x = 10 è all'interno del poligono. Il prossimo 0 indica che l'intervallo da x = 10 a x = 20 è esterno al poligono. E così procede: l'array identifica quattro intervalli separati come all'interno del poligono.

Alcuni di questi intervalli, come quello da x = 60 a x = 63.3, non intersecano alcun vertice: un rapido controllo contro le coordinate x di tutti i vertici con y = 10 elimina tali intervalli.

Durante la scansione possiamo monitorare le lunghezze di questi intervalli, conservando i dati relativi agli intervalli di lunghezza massima trovati finora.

Nota alcune delle implicazioni di questo approccio. Un vertice a forma di "v", quando incontrato, è l'origine di due bordi. Pertanto quando si incrociano si verificano due interruttori. Questi interruttori si annullano. Qualsiasi "v" capovolta non viene nemmeno elaborata, poiché entrambi i suoi bordi vengono eliminati prima di iniziare la scansione da sinistra a destra. In entrambi i casi, tale vertice non blocca un segmento orizzontale.

Più di due spigoli possono condividere un vertice: questo è illustrato in (10,0), (60,5), (25, 20) e - sebbene sia difficile da dire - in (20,10) e (40 , 10). (Questo perché il ciondolo va (20,10) -> (40,10) -> (40,0) -> (40, -50) -> (40, 10) -> (20, 10) Notate come il vertice in (40,0) sia anche all'interno di un altro bordo ... è brutto.) Questo algoritmo gestisce bene quelle situazioni.

Una situazione difficile è illustrata in fondo: ci sono le coordinate x dei segmenti non orizzontali

30, 50

Questo fa sì che tutto a sinistra di x = 30 sia considerato esterno, tutto tra 30 e 50 sia interno e tutto dopo 50 sia di nuovo esterno. Il vertice in x = 40 non è mai nemmeno considerato in questo algoritmo.

Ecco come appare il poligono alla fine della scansione. Mostro tutti gli intervalli interni contenenti vertici in grigio scuro, tutti gli intervalli di lunghezza massima in rosso e coloro i vertici secondo le loro coordinate y. L'intervallo massimo è di 64 unità.

Dopo la scansione

Gli unici calcoli geometrici coinvolti sono calcolare dove i bordi si intersecano con le linee orizzontali: questa è una semplice interpolazione lineare. I calcoli sono anche necessari per determinare quali segmenti interni contengono vertici: si tratta di determinazioni di intermittenza , facilmente calcolabili con un paio di disuguaglianze. Questa semplicità rende l'algoritmo solido e appropriato sia per le rappresentazioni di coordinate in virgola mobile che in virgola mobile.

Se le coordinate sono geografiche , le linee orizzontali si trovano realmente su cerchi di latitudine. Le loro lunghezze non sono difficili da calcolare: basta moltiplicare le loro lunghezze euclidee per il coseno della loro latitudine (in un modello sferico). Pertanto questo algoritmo si adatta perfettamente alle coordinate geografiche. (Per gestire l'avvolgimento attorno al pozzo del meridiano + -180, potrebbe essere necessario prima trovare una curva dal polo sud al polo nord che non passi attraverso il poligono. Dopo aver riespresso tutte le coordinate x come spostamenti orizzontali rispetto a quello curva, questo algoritmo troverà correttamente il segmento orizzontale massimo.)


Di seguito è riportato il Rcodice implementato per eseguire i calcoli e creare le illustrazioni.

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

Esiste un teorema che dimostra che la linea di massima lunghezza all'interno del poligono non convesso in una data direzione interseca almeno un vertice di questo poligono?
SS_Rebelious,

@SS Sì, c'è. Ecco uno schizzo di una prova: se non c'è intersezione, allora i punti finali del segmento si trovano entrambi sugli interni dei bordi e il segmento può essere spostato, almeno un po ', su e giù. La sua lunghezza è una funzione lineare della quantità di spostamento. Pertanto, può avere una lunghezza massima solo se la lunghezza non cambia quando viene spostata. Ciò implica sia (a) che fa parte di un parallelogramma formato da segmenti di lunghezza massima che (b) che entrambi i bordi superiore e inferiore di quel parallelogramma devono incontrare un vertice, QED.
whuber

E come si chiama questo teorema? Sto lottando per trovarlo. A proposito, che dire dei bordi curvi che non hanno vertici (intendo un approccio teorico)? Uno schizzo di esempio della figura che intendo (un poligono a forma di campana): "C = D".
SS_Rebelious,

@SS Quando i bordi sono curvi, il teorema non regge più. Le tecniche di geometria differenziale possono essere applicate per ottenere risultati utili. Ho imparato questi metodi dal libro di Cheeger & Ebin, Teoremi di confronto in geometria riemanniana . Tuttavia, la maggior parte dei GIS approssima comunque le curve con polilinee dettagliate, quindi la domanda (come una questione pratica) è controversa.
whuber

potresti specificare il nome del teorema (e la pagina se possibile)? Ho il libro e non sono riuscito a individuare il teorema necessario.
SS_Rebelious

9

Ecco una soluzione basata su raster. È veloce (ho fatto tutto il lavoro dall'inizio alla fine in 14 minuti), non richiede script, richiede solo poche operazioni ed è ragionevolmente preciso.

Inizia con una rappresentazione raster del poligono. Questo utilizza una griglia di 550 righe e 1200 colonne:

Poligono

In questa rappresentazione, le celle grigie (interne) hanno il valore 1 e tutte le altre celle sono NoData.

Calcola l'accumulo di flusso nella direzione da ovest a est utilizzando i valori della cella unitaria per la griglia del peso (quantità di "pioggia"):

Accumulo di flusso

Il basso accumulo è scuro, aumentando ai massimi accumuli nel giallo brillante.

Un massimo zonale (usando il poligono per la griglia e l'accumulo di flusso per i valori) identifica le celle in cui il flusso è maggiore. Per mostrarli, ho dovuto ingrandire verso l'angolo in basso a destra:

Massimo

I globuli rossi segnano le estremità dei più alti accumuli di flusso: sono i punti finali più a destra dei segmenti interni di lunghezza massima del poligono.

Per trovare questi segmenti, posiziona tutto il peso sui globuli rossi ed esegui il flusso all'indietro!

Risultato

La striscia rossa vicino al fondo segna due file di celle: al suo interno si trova il segmento orizzontale di massima lunghezza. Utilizzare questa rappresentazione così com'è per ulteriori analisi o convertirla in una forma polilinea (o poligono).

Si è verificato un errore di discretizzazione con una rappresentazione raster. Può essere ridotto aumentando la risoluzione, a un certo costo nei tempi di calcolo.


Un aspetto davvero interessante di questo approccio è che in genere troviamo valori estremi delle cose come parte di un flusso di lavoro più ampio in cui è necessario raggiungere alcuni obiettivi: ubicazione di un oleodotto o di un campo di calcio, creazione di riserve ecologiche e così via. Il processo prevede compromessi. Pertanto, la linea orizzontale più lunga potrebbe non far parte di una soluzione ottimale. Potremmo cura invece di sapere dove quasi linee più lunghe sarebbe mentire. Questo è semplice: anziché selezionare il flusso massimo zonale, selezionare tutte le celle vicine al massimo zonale. In questo esempio, il massimo zonale equivale a 744 (il numero di colonne attraversate dal segmento interno più lungo). Invece, selezioniamo tutte le celle entro il 5% di quel massimo:

Cellule quasi ottimali selezionate

Il flusso da est a ovest produce questa raccolta di segmenti orizzontali:

Soluzioni quasi ottimali

Questa è una mappa dei luoghi in cui l'estensione est-ovest ininterrotta è del 95% o maggiore dell'estensione massima est-ovest in qualsiasi punto del poligono.


3

Ok. Ho un'altra (migliore) idea ( idea-№2 ). Ma suppongo che sia meglio essere realizzato come uno script Python, non come un SQL Querry. Anche in questo caso è il caso comune, non solo EW.

Avrai bisogno di un rettangolo di selezione per il poligono e un azimut (A) come direzione di misurazione. Supponiamo che la lunghezza dei bordi BBox sia LA e LB. Massima distanza possibile (MD) all'interno di un poligono è: MB = (LA^2 * LB^2)^(1/2), quindi alla ricerca di valore (V) non è più grande di MB: V <= MB.

  1. A partire da qualsiasi vertice di BBox creare una linea (LL) con la lunghezza MB e azimut A.
  2. Intersecare la linea LL con il poligono per ottenere la linea di intersezione (IL)
  3. Controlla la geometria di IL - se ci sono solo due punti nella linea IL, calcola la sua lunghezza. Se 4 o più: calcola i segmenti e prendi la lunghezza di quella più lunga. Null (nessuna intersezione) - ignora.
  4. Continua a creare un'altra linea LL spostandoti dal contatore del punto di partenza o in senso orario verso i bordi di BBox fino a quando non finirai al punto di partenza (eseguirai l'intero ciclo attraverso BBox).
  5. Prendi il valore di lunghezza IL più grande (in realtà non devi memorizzare tutte le lunghezze, puoi mantenere solo il valore massimo "finora" durante il loop) - sarà quello che cerchi.

Questo suona come un doppio anello sopra i vertici: è abbastanza inefficiente che dovrebbe essere evitato (tranne che per i poligoni molto semplificati).
whuber

@whuber, non vedo alcun loop extra qui. C'è solo qualche elaborazione insignificante di 2 lati di BB che non darà altro che null. Ma questa elaborazione è stata esclusa nello script che ho fornito nella risposta che è stata eliminata qui (sembra che ora sia un commento, ma non lo vedo come un commento - solo come una risposta eliminata)
SS_Rebelious

(1) È il terzo commento alla domanda. (2) Hai ragione: dopo aver letto la tua descrizione molto attentamente, mi sembra ora che stai trovando il segmento più lungo tra (i quattro) vertici del riquadro di delimitazione e vertici del poligono. Non vedo come questo risponda alla domanda, però: il risultato sicuramente non è quello che l'OP ha cercato.
whuber

@whuber, l'algoritmo proposto trova l'intersezione più lunga del poligono con la linea che rappresenta la direzione data. Apparentemente il risultato è quello che è stato chiesto se la distanza tra le linee di intersezione -> 0 o supera tutti i vertici (per le figure non curve).
SS_Rebelious

3

Non sono sicuro che la risposta di Fetzer sia ciò che vuoi fare, ma è così che st_box2d potrebbe fare il lavoro.

L'idea di SS_Rebelious N ° 1 funzionerà in molti casi, ma non per alcuni poligoni concavi.

Penso che sia necessario creare linee lw artificiali i cui punti seguono i bordi quando le linee create dai vertici attraversano i bordi del poligono se esiste una possibilità di linea est-ovest. un esempio in cui non funzionerà

Per questo potresti provare a creare un poligono a 4 nodi in cui la lunghezza della linea è alta, fare il poligono P * che è la precedente sovrapposizione con il poligono originale e vedere se min (y1) e max (y2) lasciano una linea x possibilità. (dove y1 è l'insieme di punti tra la cornetta in alto a sinistra e l'angolo in alto a destra e y2 l'insieme di y tra gli angoli in basso a sinistra e in basso a destra del poligono a 4 nodi). Non è così facile, spero che troverai strumenti psql per aiutarti!


Questo è sulla strada giusta. Il segmento EW più lungo si troverà tra le intersezioni con l'interno del poligono con linee orizzontali che passano attraverso i vertici del poligono. Ciò richiede che il codice si sovrapponga ai vertici. C'è un metodo alternativo (ma equivalente) disponibile seguendo un flusso artificiale est-ovest attraverso una rappresentazione raster del poligono: la lunghezza massima del flusso trovata nel poligono (che è una delle sue "statistiche zonali") è la larghezza desiderata. La soluzione raster si ottiene in soli 3 o 4 passaggi e non richiede loop o script.
whuber

@ Nome, aggiungi "№1" all'idea di "SS_Rebelious" per evitare incomprensioni: ho aggiunto un'altra proposta. Non posso modificare la tua risposta da solo perché questa modifica ha meno di 6 caratteri.
SS_Rebelious

1

Ho un'idea-№1 ( Modifica: per il caso comune, non solo la direzione EW, e con alcune limitazioni che sono descritte nei commenti). Non fornirò il codice, solo un concetto. La "direzione x" è in realtà un azimut, che viene calcolato da ST_Azimuth. I passaggi proposti sono:

  1. Estrai tutti i vertici dal poligono come punti.
  2. Crea linee tra ogni coppia di punti.
  3. Seleziona le linee (chiamiamole linee a sinistra) che si trovano all'interno del poligono originale (non abbiamo bisogno di linee che attraversino i bordi del poligono).
  4. Trova distanze e azimut per ogni linea sinistra.
  5. Seleziona la distanza più lunga dalle linee a sinistra in cui l'azimut è uguale all'azimut ricercato o si trova in un certo intervallo (è possibile che nessun azimut sia esattamente uguale all'azimut ricercato).

Questo non funzionerà anche per alcuni triangoli , come quello a vertici (0,0), (1000, 1000) e (501, 499). La sua larghezza massima est-ovest è di circa 2; gli azimut sono tutti intorno a 45 gradi; e indipendentemente, il segmento di linea più corto tra i vertici è oltre 350 volte più lungo della larghezza est-ovest.
whuber

@whuber, hai ragione, fallirà per i triangoli, ma per i poligoni, che rappresentano alcune caratteristiche della natura, potrebbe essere utile.
SS_Rebelious

1
È difficile raccomandare una procedura che fallisce drammaticamente anche per casi semplici nella speranza che a volte possa ottenere una risposta corretta!
whuber

@whuber, quindi non lo consiglio! ;-) Ho proposto questa soluzione alternativa perché non c'erano risposte a questa domanda. Nota che puoi pubblicare la tua risposta migliore. A proposito, se posizionerai dei punti sui bordi del triangolo, la mia proposta funzionerà ;-)
SS_Rebelious

Ho suggerito diversi approcci. Uno raster è disponibile all'indirizzo gis.stackexchange.com/questions/32552/… ed elaborato su forums.esri.com/Thread.asp?c=93&f=982&t=107703&mc=3 . Un altro - non del tutto applicabile, ma con usi interessanti - è su gis.stackexchange.com/questions/23664/… (la trasformazione del radon). Questo è illustrato su stats.stackexchange.com/a/33102 .
whuber

1

Dai un'occhiata alla mia domanda e alla risposta di Evil Genius.

Spero che il tuo poligono del lago abbia un numero di punti, puoi creare linee su questi punti con un azimut (aspetto, direzione geografica). Scegli la lunghezza delle linee abbastanza grande (parte ST_MakePoint), in modo da poter calcolare la linea più corta tra le due linee più distanti.

Ecco un esempio:

inserisci qui la descrizione dell'immagine

L'esempio mostra la larghezza massima del poligono. Ho scelto ST_ShortestLine (linea rossa) per questo approccio. ST_MakeLine aumenterebbe il valore (linea blu) e il punto finale della linea (in basso a sinistra) colpirebbe la linea blu del poligono. Devi calcolare la distanza con i centroidi delle linee create (di aiuto).

Un'idea per poligoni irregolari o concavi per questo approccio. Potrebbe essere che devi intersecare il poligono con un raster.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.