Come calcolare l'angolo in cui due linee si intersecano in PostGIS?


19

Voglio calcolare l'angolo tra due linee in cui si intersecano in PostGIS.

Il punto di partenza per i calcoli angolari in PostGIS sembra essere ST_Azimuth - ma questo prende punti come input. Il mio primo pensiero è stato quello di prendere gli estremi delle linee che si intersecano e di eseguire un calcolo Azimut su quelle. Questo non è abbastanza buono, perché la maggior parte delle caratteristiche della linea non sono dritte e sono interessato all'angolo all'intersezione. Quindi quello che mi è venuto in mente è un'operazione nidificata che passa attraverso i seguenti passaggi:

  1. Identificare tutte le intersezioni tra le tabelle delle caratteristiche di due linee.
  2. Crea un buffer molto piccolo attorno al punto di intersezione
  3. Identifica i punti in cui le caratteristiche della linea intersecano l'esterno del buffer (prendendo il primo punto se ce ne sono più di uno - Sono davvero interessato solo a sapere se l'angolo è vicino a 0, 90 o 180 gradi)
  4. Calcola ST_Azimuth per quei due punti.

L'intero SQL è un po 'lungo da pubblicare qui, ma l'ho indicato qui se sei interessato. (A proposito, c'è un modo migliore che riportare tutti i campi che scendono dalle istruzioni WITH?)

I risultati non sembrano giusti, quindi sto chiaramente facendo qualcosa di sbagliato:

esempio di output 1 esempio di output 2

MODIFICA Ho rifatto i calcoli in EPSG: 3785 e i risultati sono leggermente diversi ma ancora non corretti:

uscita in 3785 # 1 uscita in 3785 # 2

La mia domanda è dove sono i difetti in questo processo. Sto fraintendendo cosa fa ST_Azimuth? C'è un problema CRS? Qualcos'altro del tutto? O forse c'è un modo molto, molto più semplice per farlo?


1
Qual era il CRS originale? I calcoli angolari devono essere eseguiti con una proiezione conforme, non con lat / long non proiettato (SRID = 4326).
Mike T,

Era EPSG: originariamente 4326 coordinate, includevo ST_Translate solo per essere sicuro al 100% che tutta l'elaborazione sarebbe stata eseguita nello stesso CRS. Proverò una proiezione conforme, grazie.
mvexel,

Ho rifatto i calcoli è EPSG: 3785 e fa la differenza - modificherò la domanda per mostrare i nuovi risultati - ma il risultato non riflette ancora l'angolo reale.
mvexel,

Risposte:


12

Ho avuto l'epifania. È piuttosto banale. Stavo tralasciando un'informazione essenziale per PostGIS per calcolare l'angolo retto.

Quello che stavo calcolando era l'angolo tra solo i due punti che intersecano il piccolo buffer esterno. Per calcolare l'angolo dell'intersezione, devo calcolare entrambi gli angoli tra entrambi i punti sull'esterno del buffer e il punto di intersezione delle due linee e sottrarle.

Ho aggiornato l' SQL completo , ma ecco il bit saliente:

SELECT
    ...
    abs
    (
        round
        (
            degrees
            (
            ST_Azimuth
            (
                points.point2,
                points.intersection
            )
            -
            ST_Azimuth
            (
                points.point1,
                points.intersection
            )
        )::decimal % 180.0
        ,2
    )
)
AS angle
...
FROM
points 

1
Stavo pensando all'angolo del punto tamponato rispetto all'intersezione, ma non ho tempo di approfondire. Un altro aspetto sono le unità angolari. È necessario moltiplicare il risultato in radianti da ST_Azimuth per 180,0 / pi () per ottenere risultati in gradi.
Mike T,

Sì, grazie a ciò uso la funzione gradi () di PostgreSQL.
mvexel,

Mannaia. (Non sapevo nemmeno che esistesse una funzione gradi fino ad ora.) Sarebbe bello racchiudere tutta questa logica in una chiamata di funzione, ma ho difficoltà a concettualizzare come funzionerebbe, cioè ST_IntersectionAngle(...?
Mike T,

In realtà sono rimasto sorpreso dal fatto che non sia una funzione PostGIS. Grazie per il tuo feedback su questo.
mvexel,

2

Di recente ho dovuto calcolare la stessa cosa, ma ho deciso di adottare un approccio più semplice e probabilmente più veloce.

Per trovare i punti extra per il calcolo dell'azimut, controllo solo una permyriad della lunghezza dietro l'intersezione (o dopo nel raro caso in cui si verifica all'inizio della linea) usando ST_Line_Locate_Point e ST_Line_Interpolate_Point :

abs(degrees( 
  ST_Azimuth (
    intersection, 
    ST_Line_Interpolate_Point(
      line1, 
      abs(ST_Line_Locate_Point(line1, intersection) - 0.0001)
    )
  )
  -
  ST_Azimuth (
    intersection, 
    ST_Line_Interpolate_Point(
      line2, 
      abs(ST_Line_Locate_Point(line2, intersection) - 0.0001)
    )
  )
))

La permyriad era arbitraria e per risultati più coerenti sarebbe meglio usare un offset assoluto. Ad esempio, per controllare 20 m in anticipo, è necessario modificare 0,0001 in 20/ST_Length(line1)e 20/ST_Length(line2)rispettivamente.

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.