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.