Làm thế nào để tính góc mà hai đường thẳng giao nhau trong PostGIS?


19

Tôi muốn tính góc giữa hai đường mà chúng giao nhau trong PostGIS.

Điểm bắt đầu để tính toán góc trong PostGIS dường như là ST_Azimuth - nhưng lấy điểm làm đầu vào. Suy nghĩ đầu tiên của tôi là lấy các điểm cuối của các đường giao nhau và thực hiện phép tính Azimuth trên các đường đó. Điều đó là không đủ, bởi vì hầu hết các tính năng đường thẳng không thẳng và tôi quan tâm đến góc ở giao lộ. Vì vậy, những gì tôi đã đưa ra là một hoạt động lồng nhau trải qua các bước sau:

  1. Xác định tất cả các giao điểm giữa hai bảng tính năng dòng.
  2. Tạo một vùng đệm rất nhỏ xung quanh điểm giao nhau
  3. Xác định các điểm mà các tính năng đường thẳng giao nhau với bên ngoài bộ đệm (lấy điểm đầu tiên nếu có nhiều hơn một - tôi thực sự chỉ quan tâm đến việc góc đó có gần 0, 90 hay 180 độ không)
  4. Tính ST_Azimuth cho hai điểm đó.

SQL đầy đủ là loại dài để đăng ở đây, nhưng tôi đã viết nó ở đây nếu bạn quan tâm. (Nhân tiện, có cách nào tốt hơn là mang theo tất cả các trường đi xuống các câu lệnh VỚI không?)

Kết quả không đúng, vì vậy rõ ràng tôi đang làm sai:

ví dụ đầu ra 1 ví dụ đầu ra 2

EDIT Tôi làm lại các tính toán trong EPSG: 3785 và kết quả hơi khác một chút nhưng vẫn không đúng:

đầu ra trong 3785 # 1 đầu ra trong 3785 # 2

Câu hỏi của tôi là những sai sót trong quá trình này. Tôi có hiểu nhầm ST_Azimuth không? Có vấn đề CRS không? Một cái gì đó khác hoàn toàn? Hoặc có thể có một cách đơn giản hơn nhiều để làm điều này?


1
CRS ban đầu là gì? Việc tính toán góc phải được thực hiện với phép chiếu phù hợp Không phải với lat / long chưa được cung cấp (SRID = 4326).
Mike T

Đó là tọa độ EPSG: 4326 ban đầu, tôi đã bao gồm ST_Translate chỉ để đảm bảo 100% tất cả quá trình xử lý sẽ được thực hiện trong cùng một CRS. Tôi sẽ thử một phép chiếu phù hợp, cảm ơn.
mvexel

Tôi làm lại các phép tính là EPSG: 3785 và nó tạo ra sự khác biệt - Tôi sẽ sửa đổi câu hỏi để hiển thị kết quả mới - nhưng kết quả vẫn không phản ánh góc độ thực tế.
mvexel

Câu trả lời:


12

Tôi đã có sự hiển linh. Nó khá trần tục. Tôi đã để lại một thông tin cần thiết cho PostGIS để tính toán góc phù hợp.

Những gì tôi đã tính toán là góc giữa chỉ hai điểm giao nhau bên ngoài bộ đệm nhỏ. Để tính góc của giao điểm, tôi cần tính cả hai góc giữa cả hai điểm trên mặt ngoài bộ đệm và điểm giao nhau của hai tính năng đường và trừ chúng.

Tôi đã cập nhật SQL đầy đủ , nhưng đây là bit nổi bật:

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
Tôi đã suy nghĩ về góc của bộ đệm được ghi vào phần bên trong, nhưng tôi không có thời gian để đi vào chi tiết. Một khía cạnh khác là các đơn vị góc. Bạn cần nhân kết quả tính theo radian từ ST_Azimuth với 180.0 / pi () để có kết quả theo độ.
Mike T

Yep cảm ơn, tôi sử dụng hàm độ () PostgreSQL cho điều đó.
mvexel

Cleaver. (Tôi thậm chí còn không biết có chức năng độ cho đến bây giờ.) Thật tuyệt khi gói tất cả logic này trong một lệnh gọi hàm, nhưng tôi gặp khó khăn trong việc khái niệm hóa nó sẽ hoạt động như thế nào, nghĩa là ST_IntersectionAngle(...?
Mike T

Tôi thực sự ngạc nhiên khi nó không phải là một chức năng PostGIS. Cảm ơn phản hồi của bạn về điều này.
mvexel

2

Gần đây tôi đã phải tính toán điều tương tự, nhưng đã quyết định một cách tiếp cận đơn giản hơn và có khả năng nhanh hơn.

Để tìm các điểm bổ sung cho phép tính góc phương vị, tôi chỉ cần kiểm tra vô số độ dài phía sau giao lộ (hoặc sau đó trong trường hợp hiếm hoi xảy ra ở đầu dòng) bằng ST_Line_Locate_PointST_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)
    )
  )
))

Sự cho phép là tùy ý và để có kết quả phù hợp hơn, tốt hơn là sử dụng một độ lệch tuyệt đối. Ví dụ: kiểm tra trước 20m, bạn sẽ thay đổi 0,0001 thành 20/ST_Length(line1)20/ST_Length(line2)tương ứng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.