Як обчислити кут, під яким дві лінії перетинаються в PostGIS?


19

Я хочу обчислити кут між двома лініями, де вони перетинаються в PostGIS.

Вихідною точкою для обчислення кута в PostGIS, здається, є ST_Azimuth - але це приймає точки як вхідні дані. Першою моєю думкою було взяти кінцеві точки пересічних ліній і виконати обчислення азимуту на них. Це недостатньо добре, оскільки більшість особливостей лінії не прямі, і мене цікавить кут на перетині. Отже, я придумав - це вкладена операція, яка проходить через наступні кроки:

  1. Визначте всі перетини між двома рядками таблиць характеристик.
  2. Створіть дуже маленький буфер навколо точки перетину
  3. Визначте точки, де лінії перетинаються зовнішньою частиною буфера (беручи першу точку, якщо їх більше - я насправді цікавлюсь лише тим, чи кут близький до 0, 90 або 180 градусів)
  4. Обчисліть ST_Azimuth для цих двох точок.

Повний SQL довго не публікується тут, але я подав його сюди, якщо вам цікаво. (До речі, чи є кращий спосіб, ніж переносити всі поля, що йдуть вниз по операторах З?)

Результати виглядають неправильно, тому я чітко роблю щось не так:

вихідний приклад 1 вихідний приклад 2

EDIT Я переосмислив обчислення в EPSG: 3785, і результати дещо відрізняються, але все-таки неправильно:

вихід у 3785 №1 вихід у 3785 №2

Моє запитання - де вади в цьому процесі. Я не розумію, що робить ST_Azimuth? Чи є проблема з CRS? Щось ще взагалі? А може, існує набагато, набагато простіший спосіб зробити це?


1
Якою була початкова CRS? Кутові обчислення слід проводити з конформною проекцією, а не з непроектованим lat / long (SRID = 4326).
Майк Т

Спочатку це було EPSG: 4326 координат, я включив ST_Translate лише для того, щоб бути на 100% впевненим, що вся обробка буде виконана в одній і тій самій CRS. Я спробую конформну проекцію, дякую.
mvexel

Я повторно підрахував розрахунки до EPSG: 3785, і це має значення - я внішу питання, щоб відобразити нові результати, - але результат все ще не відображає фактичного кута.
mvexel

Відповіді:


12

У мене було богоматіння. Це досить буденно. Я залишав одну важливу інформацію для PostGIS для обчислення прямого кута.

Я обчислював кут між лише двома точками, що перетинали малий зовнішній буфер. Щоб обчислити кут перетину, мені потрібно обчислити обидва кути між обома точками на зовнішній стороні буфера та точкою перетину двох ознак лінії та відняти їх.

Я оновив повний SQL , але ось важливий біт:

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
Я думав про кут буферної точки, що розкриває інсекцію, але я не маю часу детально піти. Інший аспект - кутові одиниці. Вам потрібно помножити результат в радіанах від ST_Azimuth на 180,0 / pi (), щоб отримати результати в градусах.
Майк Т

Дякую, я використовую для цього функцію ступенів PostgreSQL.
mvexel

Клівер. (Я до цього часу навіть не знав, що є функція градусів.) Було б непогано зафіксувати всю цю логіку у виклику функції, але мені складно уявити, як це буде працювати, тобто ST_IntersectionAngle(...?
Майк Т

Я насправді був здивований, що це не функція PostGIS. Дякуємо за Ваш відгук про це.
mvexel

2

Нещодавно мені довелося обчислити те саме, але зважився на більш простий і, швидше за все, швидший підхід.

Щоб знайти додаткові точки для обчислення азимуту, я просто перевіряю перміріаду довжини за перетином (або після того, як це в рідкісному випадку трапляється на самому початку лінії), використовуючи ST_Line_Locate_Point та 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)
    )
  )
))

Перміріада була довільною і для більш послідовних результатів було б краще використовувати абсолютне зміщення. Для перевірки, наприклад , 20м заздалегідь, ви б змінити 0,0001 20/ST_Length(line1)і 20/ST_Length(line2)відповідно.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.