Làm cách nào để tính hộp giới hạn cho khoảng cách và vĩ độ / kinh độ đã cho


13

Tôi cần có thể tính toán một hộp giới hạn hoặc vòng tròn cho một vĩ độ WGS84 và kinh độ WGS84 nhất định và khoảng cách nhưng không biết bắt đầu từ đâu!

Khoảng cách từ lúc bắt đầu Lat / Lon sẽ là 10Km hoặc ít hơn.

Ai đó có thể cho tôi một vài gợi ý / Ví dụ về cách thực hiện việc này không


Đối với các vòng tròn không bao gồm một trong hai cực, câu trả lời chi tiết được đưa ra tại gis.stackexchange.com/questions/19221/ . Nhưng đây không phải là câu chuyện đầy đủ, như các câu trả lời hiện tại cho thấy: bạn có thể thực hiện các sự đánh đổi độ phức tạp của chương trình chính xác và tốc độ. Cũng lưu ý rằng có một vấn đề "bao bọc" trong việc chỉ định các hộp giới hạn khi bạn làm việc ở lat-lon (những khó khăn xảy ra ở kinh tuyến + -180 độ). Để biết giải pháp cho vấn đề này, hãy xem gis.stackexchange.com/questions/17788/iêu .
whuber

Bạn có thực sự cần một hộp, hoặc 4 điểm gần một điểm nhất định là đủ? Cho một điểm p, tìm khoảng cách 4 điểm d tại các hướng NE, SW, SE và NW từ p.
Kirk Kuykendall

@Kirk - Nếu bạn có tọa độ của 4 điểm, thì bạn có ô ...
martinstoeckli

@martinstoeckli đúng, tôi chỉ hy vọng đơn giản hóa vấn đề bằng cách không phải hình dung ra một cái hộp được chiếu lên một quả cầu trông như thế nào. Cũng lưu ý rằng vấn đề có thể được khái quát hóa để làm rõ rằng các cạnh của hộp không bắt buộc phải rơi trên cùng một vĩ độ / kinh độ (nói cách khác là một hộp xoay).
Kirk Kuykendall

@Kirk - Ahh tốt, nếu bạn cần nó chính xác, thì tất nhiên bạn đúng. Tôi nghĩ rằng hộp chỉ hữu ích để tìm các ứng cử viên có thể nhanh chóng. Để kiểm tra xem hai điểm có nằm trong một khoảng cách nhất định (vòng tròn) không, có thể sử dụng công thức haversine phức tạp hơn.
martinstoeckli

Câu trả lời:


15

WGS-gì? WGS-84? Tùy thuộc vào độ chính xác bạn cần, bạn có thể cần biết thêm nhiều thông tin - tôi đoán đó là lý do tại sao bạn bị bỏ phiếu, mặc dù không ai bận tâm để lại nhận xét cho biết lý do.

Đây là hai cách:

Không chính xác, nhưng có lẽ 'đủ tốt'

Một độ vĩ độ xấp xỉ 10001.965729 / 90 km (khoảng cách từ đường xích đạo đến cực, chia cho chín mươi độ) hoặc 111.113 km, sử dụng mốc thời gian WGS-84. Đây là một xấp xỉ vì hình dạng của trái đất và bởi vì khoảng cách thay đổi khi bạn tiếp cận các cực (một lý do để sử dụng vĩ độ, không phải kinh độ - cuối cùng khoảng cách của một độ kinh độ bằng không!) Trái đất cũng không hoàn hảo quả cầu. Cả hai đều là lý do để sử dụng một cách tiếp cận dựa trên phép chiếu và dữ liệu phức tạp hơn, trong câu trả lời thứ hai của tôi.

10001.965729km = 90 degrees
1km = 90/10001.965729 degrees = 0.0089982311916 degrees
10km = 0.089982311915998 degrees

Đây là sử dụng độ thập phân, không phải độ / phút / giây.

Vì vậy, hộp giới hạn của bạn sẽ là điểm của bạn, cộng và trừ 0,08999 độ. Ngoài ra, bạn có thể sử dụng số này làm bán kính, cung cấp cho bạn một vòng tròn giới hạn .

Bất kỳ người GIS nào đọc nó cũng sẽ rùng mình. Nó sẽ chủ yếu là chính xác, mặc dù, tùy thuộc vào nơi bạn ở trên thế giới. Đối với bán kính 10km thì sẽ ổn thôi.

Chính xác hơn nhiều, nhưng nhiều mã hơn

Sử dụng một thư viện chiếu và chỉ định mốc thời gian của bạn, v.v. Tôi khuyên dùng Proj4; nó được sử dụng rộng rãi để Google trả về hàng đống kết quả cho các câu hỏi về nó và có các hàm bao Delphi . Nếu bạn gặp khó khăn khi sử dụng nó, hãy đăng một câu hỏi khác ở đây trên SO - nó nằm ngoài phạm vi của câu hỏi này. Trang web Proj4 có các ví dụ sử dụng các API cơ bản và mặc dù chúng có trong C nhưng nó khá dễ dịch. Tham chiếu API của họ là nơi tốt nhất để bắt đầu, tiếp theo là Câu hỏi thường gặp .

Tôi sẽ sử dụng WGS-84 làm mốc chuẩn cơ bản (đại diện cho trái đất) trừ khi bạn biết một loại cụ thể mà bạn muốn sử dụng hoặc được sử dụng để tạo tọa độ của bạn. Nó thường được sử dụng và khá chính xác.

Nếu vị trí của bạn đến từ Google Maps (ví dụ), hãy chỉ định phép chiếu Mercator. Bạn có thể muốn sử dụng một phép chiếu khác hoặc sử dụng tọa độ UTMthay vì vĩ độ và kinh độ, tùy thuộc vào nguồn dữ liệu của bạn và nếu bạn muốn độ chính xác cao cho một khu vực địa phương nhỏ. (UTM có nhiều vùng, tất cả đều thay đổi biến dạng sao cho trong vùng đó, nó rất chính xác; nếu bạn sử dụng một vùng cho tọa độ bên ngoài nó, độ méo sẽ tăng lên rất nhiều khi bạn di chuyển ra xa. khu vực, nó có thể không được nhận dạng. Nhưng trong một khu vực, các bản dịch UTM sẽ tốt như bạn có thể nhận được. Các tọa độ thường được chỉ định bằng mét, không phải bằng độ, vì vậy nó có thể hữu ích hơn cho bạn, vì bạn cần 10km bán kính 10km dễ dàng trong một vùng duy nhất, bạn chỉ cần chọn vùng thích hợp dựa trên tọa độ trung tâm của mình. Điều khó khăn duy nhất là khi bạn tiếp cận một đường viền: đó là một tình huống phổ biến, và nó vẫn ổn, chỉ cần lànhất quán trong cách bạn chọn cái nào bạn sử dụng . Proj4 cũng sẽ cho phép bạn dịch các phép chiếu, do đó bạn có thể đi từ Mercator WGS-84 lat / long sang vùng UTM n , ví dụ, hoặc đến và từ hai vùng UTM.)


2
Đối với nơi chúng tôi sống, một nhà khảo sát đã từng nói với tôi rằng anh ta sử dụng 1 độ xấp xỉ 108 km cho các tính toán tinh thần của mình. Khoảng 10 km là khoảng 0,1 độ. Vì đây là các xấp xỉ thô tốt nhất để xử lý chúng chính xác đến 1 chữ số có nghĩa (nhiều nhất là 2 hoặc 3) thay vì 0,089982311915998 vì điều đó hàm ý mức độ chính xác.
Stephen Quan

1
Thật sự không khó để tính toán độ chính xác hơn, tính đến vĩ độ. Vì máy tính thực hiện phép tính, không có gì đạt được với xấp xỉ (xem hàm đầu tiên trong ví dụ của tôi).
martinstoeckli

3

Giả sử bạn muốn thực hiện một truy vấn trong cơ sở dữ liệu, có lẽ bạn muốn thực hiện tìm kiếm nhanh (không chính xác) và sau đó tính toán chính xác khoảng cách cho các vị trí kết quả. Đó có phải là kịch bản của bạn?

Hàm sau (trong PHP, xin lỗi) sẽ tính toán gần đúng sự khác biệt về vĩ độ và kinh độ. Sự khác biệt này phụ thuộc vào vĩ độ của điểm tìm kiếm của bạn. Sử dụng chúng (với một dung sai nhỏ) để thực hiện tìm kiếm nhanh trong cơ sở dữ liệu. Hộp có thể được tính đơn giản với vĩ độ + -deltaLatitude và kinh độ + -deltaLongitude.

deltaLatitude[rad] = distance[m] / earthRadius[m]
deltaLongitude[rad] = distance[m] / (cos(latitude[rad]) * $earthRadius[m])

/**
 * Calculates the deltas in latitude and longitude to use, for a db search
 * around a location in the database.
 * @param float $distance Radius to use for the search [m]
 * @param float $latitude Latitude of the location, we need the angle deltas for [deg decimal]
 * @param float $deltaLatitude Calculated delta in latitude [deg]
 * @param float $deltaLongitude Calculated delta in longitude [deg]
 * @param float $earthRadius Mean earth radius in [m]
 */
public static function angleFromSphericDistance($distance, $latitude,
  &$deltaLatitude, &$deltaLongitude, $earthRadius = 6371000)
{
  $lat = deg2rad($latitude);

  $radiusOnLatitude = cos($lat) * $earthRadius;
  $deltaLatitude = $distance / $earthRadius;
  $deltaLongitude = $distance / $radiusOnLatitude;

  $deltaLatitude = rad2deg($deltaLatitude);
  $deltaLongitude = rad2deg($deltaLongitude);
}

Với công thức haversine , bạn có thể tính khoảng cách trên quả cầu. Sử dụng nó cho mỗi nơi được tìm thấy, để có được khoảng cách "chính xác". Bằng cách này bạn có thể kiểm tra, nếu hai địa điểm nằm trong một bán kính nhất định (một vòng tròn thay vì hộp).

/**
 * Calculates the great-circle distance between two points, with
 * the Haversine formula.
 * @param float $latitudeFrom Latitude of start point in [deg decimal]
 * @param float $longitudeFrom Longitude of start point in [deg decimal]
 * @param float $latitudeTo Latitude of target point in [deg decimal]
 * @param float $longitudeTo Longitude of target point in [deg decimal]
 * @param float $earthRadius Mean earth radius in [m]
 * @return float Distance between points in [m] (same as earthRadius)
 */
public static function haversineGreatCircleDistance(
  $latitudeFrom, $longitudeFrom, $latitudeTo, $longitudeTo, $earthRadius = 6371000)
{
  // convert from degrees to radians
  $latFrom = deg2rad($latitudeFrom);
  $lonFrom = deg2rad($longitudeFrom);
  $latTo = deg2rad($latitudeTo);
  $lonTo = deg2rad($longitudeTo);

  $latDelta = $latTo - $latFrom;
  $lonDelta = $lonTo - $lonFrom;

  $angle = 2 * asin(sqrt(pow(sin($latDelta / 2), 2) +
    cos($latFrom) * cos($latTo) * pow(sin($lonDelta / 2), 2)));
  return $angle * $earthRadius;
}

3

Để kiểm tra xem lat / lon nằm trong hay ngoài vòng tròn giới hạn, bạn cần tính khoảng cách từ lat / lon tham chiếu đến điểm lat / lon bạn muốn kiểm tra. Vì khoảng cách của bạn là 10km hoặc ít hơn, tôi sẽ thử sử dụng phép tính xấp xỉ Equir chữ nhật để có được khoảng cách thay vì Haversine vì đơn giản. Để có được khoảng cách tính bằng km:

x = (lonRef - lon) * cos ( latRef )
y = latRef - lat
distance = EarthRadius * sqrt( x*x + y*y )

Lưu ý quan trọng: lat / lon trong các công thức này được tính bằng radian chứ không phải độ. Giá trị tiêu biểu của EarthRadius là 6371 km sẽ trả về khoảng cách theo đơn vị km. Bây giờ nó là một thử nghiệm đơn giản nếu khoảng cách của bạn nằm trong hoặc ngoài vòng tròn. Nếu một vòng tròn giới hạn hoạt động, tôi sẽ đi với nó.

Đối với hình chữ nhật giới hạn, tôi sẽ giả sử bạn muốn hình chữ nhật được xác định bằng cách song song với đường xích đạo. Sau đó, tôi sẽ tính toán các góc của hộp giới hạn bằng cách tính toán phạm vi / ổ trục (vòng bi là 45 độ, 135 độ, 225 độ và 315 độ). Từ đó, tôi cho rằng bạn không ở quanh các cực và sử dụng một điểm trong kiểm tra đa giác.


2

Dưới đây là mã T-SQL mà tôi sử dụng để xây dựng hộp giới hạn trong SQL-Server 2012. Trong trường hợp của tôi, tôi nhận được các giá trị thập phân cho Lat, Long. Tôi sử dụng điều này để nhanh chóng giới hạn số lượng hàng trước khi tôi sử dụng STDistancehàm SQL để xác minh rằng kết quả thực sự nằm trong khoảng cách cụ thể. Các chức năng địa lý rất tốn kém trong SQL Server do đó bằng cách xây dựng hộp giới hạn, tôi có thể giảm đáng kể số lần phải thực hiện.

DECLARE @Lat DECIMAL(20, 13) = 35.7862
   ,@Long DECIMAL(20, 13) = -80.3095
   ,@Radius DECIMAL(7, 2) = 5
   ,@Distance DECIMAL(10, 2)
   ,@Earth_Radius INT = 6371000;

SET @Distance = @Radius * 1609.344;

DECLARE @NorthLat DECIMAL(20, 13) = @Lat + DEGREES(@distance / @Earth_Radius)
   ,@SouthLat DECIMAL(20, 13) = @Lat - DEGREES(@distance / @Earth_Radius)
   ,@EastLong DECIMAL(20, 13) = @Long + DEGREES(@distance / @Earth_Radius / COS(RADIANS(@Lat)))
   ,@WestLong DECIMAL(20, 13) = @Long - DEGREES(@distance / @Earth_Radius / COS(RADIANS(@Lat)));

SELECT *
    FROM CustomerPosition AS cp
    WHERE (
            cp.Lat >= @SouthLat
            AND cp.Lat <= @NorthLat )
        AND (
              cp.Long >= @WestLong
              AND cp.Long <= @EastLong )
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.