Phân tích & Thử nghiệmNền tảng CRM và Dữ liệuCông cụ tiếp thị

Tính toán hoặc truy vấn Khoảng cách vòng tròn lớn giữa các điểm có vĩ độ và kinh độ bằng Công thức Haversine (Ví dụ về PHP, JavaScript, Java, Python, MySQL, MSSQL)

Tháng này, tôi đã lập trình PHP và MySQL cho GIS. Khi nghiên cứu đề tài, tôi gặp khó khăn trong việc tìm kiếm tính toán địa lý để tìm khoảng cách giữa hai địa điểm nên tôi muốn chia sẻ chúng ở đây.

Bản đồ chuyến bay Châu Âu với khoảng cách vòng tròn lớn

Cách đơn giản để tính khoảng cách giữa hai điểm là sử dụng công thức Pitago để tính cạnh huyền của một tam giác (A² + B² = C²). Điều này được gọi là Khoảng cách Euclide.

Đó là một khởi đầu thú vị, nhưng nó không áp dụng được cho địa lý vì khoảng cách giữa các đường vĩ độ và kinh độ là khoảng cách không bằng nhau. Càng đến gần xích đạo, các vĩ tuyến càng xa nhau. Nếu bạn sử dụng một phương trình tam giác đơn giản, nó có thể đo khoảng cách chính xác ở một vị trí và sai ở vị trí khác do độ cong của Trái đất.

Khoảng cách vòng tròn lớn

Các tuyến đường đi một quãng đường dài quanh Trái đất được gọi là Khoảng cách vòng tròn lớn. Đó là… khoảng cách ngắn nhất giữa hai điểm trên một mặt cầu khác với các điểm trên bản đồ phẳng. Kết hợp điều đó với thực tế là các đường kinh tuyến và vĩ độ không cách đều nhau… và bạn sẽ có một phép tính khó.

Đây là video giải thích tuyệt vời về cách các Vòng kết nối lớn hoạt động.

Công thức Haversine

Khoảng cách sử dụng độ cong của Trái đất được kết hợp trong công thức Haversine, sử dụng lượng giác để tính đến độ cong của Trái đất. Khi bạn tìm khoảng cách giữa 2 địa điểm trên Trái đất (theo đường chim bay), đường thẳng thực chất là một vòng cung.

Điều này có thể áp dụng trong chuyến bay – bạn đã bao giờ nhìn vào bản đồ thực tế của các chuyến bay và nhận thấy chúng có hình vòm chưa? Đó là bởi vì bay theo hình vòng cung giữa hai điểm ngắn hơn bay trực tiếp đến địa điểm.

PHP: Tính khoảng cách giữa 2 điểm vĩ độ và kinh độ

Đây là công thức PHP để tính khoảng cách giữa hai điểm (cùng với chuyển đổi Mile so với Kilômét) được làm tròn đến hai chữ số thập phân.

function getDistanceBetweenPointsNew($latitude1, $longitude1, $latitude2, $longitude2, $unit = 'miles') {
  $theta = $longitude1 - $longitude2; 
  $distance = (sin(deg2rad($latitude1)) * sin(deg2rad($latitude2))) + (cos(deg2rad($latitude1)) * cos(deg2rad($latitude2)) * cos(deg2rad($theta))); 
  $distance = acos($distance); 
  $distance = rad2deg($distance); 
  $distance = $distance * 60 * 1.1515; 
  switch($unit) { 
    case 'miles': 
      break; 
    case 'kilometers' : 
      $distance = $distance * 1.609344; 
  } 
  return (round($distance,2)); 
}

Các biến là:

  • $ Latitude1 - một biến cho vĩ độ của vị trí đầu tiên của bạn.
  • $ Kinh độ1 - một biến số cho kinh độ vị trí đầu tiên của bạn
  • $ Latitude2 - một biến cho vĩ độ của vị trí thứ hai của bạn.
  • $ Kinh độ2 - một biến cho kinh độ vị trí thứ hai của bạn.
  • đơn vị $ - mặc định là dặm. Điều này có thể được cập nhật hoặc chuyển thành cây số.

Java: Tính Khoảng Cách Giữa 2 Điểm Vĩ Độ Và Kinh Độ

public static double getDistanceBetweenPointsNew(double latitude1, double longitude1, double latitude2, double longitude2, String unit) {
    double theta = longitude1 - longitude2;
    double distance = 60 * 1.1515 * (180/Math.PI) * Math.acos(
        Math.sin(latitude1 * (Math.PI/180)) * Math.sin(latitude2 * (Math.PI/180)) + 
        Math.cos(latitude1 * (Math.PI/180)) * Math.cos(latitude2 * (Math.PI/180)) * Math.cos(theta * (Math.PI/180))
    );
    if (unit.equals("miles")) {
        return Math.round(distance, 2);
    } else if (unit.equals("kilometers")) {
        return Math.round(distance * 1.609344, 2);
    } else {
        return 0;
    }
}

Các biến là:

  • vĩ độ1 - một biến cho vĩ độ của vị trí đầu tiên của bạn.
  • kinh độ1 - một biến số cho kinh độ vị trí đầu tiên của bạn
  • vĩ độ2 - một biến cho vĩ độ của vị trí thứ hai của bạn.
  • kinh độ2 - một biến cho kinh độ vị trí thứ hai của bạn.
  • đơn vị - mặc định là dặm. Điều này có thể được cập nhật hoặc chuyển thành cây số.

JavaScript: Tính khoảng cách giữa 2 điểm vĩ độ và kinh độ

function getDistanceBetweenPoints(latitude1, longitude1, latitude2, longitude2, unit = 'miles') {
    let theta = longitude1 - longitude2;
    let distance = 60 * 1.1515 * (180/Math.PI) * Math.acos(
        Math.sin(latitude1 * (Math.PI/180)) * Math.sin(latitude2 * (Math.PI/180)) + 
        Math.cos(latitude1 * (Math.PI/180)) * Math.cos(latitude2 * (Math.PI/180)) * Math.cos(theta * (Math.PI/180))
    );
    if (unit == 'miles') {
        return Math.round(distance, 2);
    } else if (unit == 'kilometers') {
        return Math.round(distance * 1.609344, 2);
    }
}

Các biến là:

  • vĩ độ1 - một biến cho vĩ độ của vị trí đầu tiên của bạn.
  • kinh độ1 - một biến số cho kinh độ vị trí đầu tiên của bạn
  • vĩ độ2 - một biến cho vĩ độ của vị trí thứ hai của bạn.
  • kinh độ2 - một biến cho kinh độ vị trí thứ hai của bạn.
  • đơn vị - mặc định là dặm. Điều này có thể được cập nhật hoặc chuyển thành cây số.

Python: Tính khoảng cách giữa 2 điểm vĩ độ và kinh độ

Đây là công thức Python để tính khoảng cách giữa hai điểm (cùng với chuyển đổi Dặm so với Kilomet) được làm tròn đến hai chữ số thập phân. Ghi công cho con trai tôi, Bill Karr, Nhà khoa học dữ liệu của mởINSIGHTS, cho mã.

from numpy import sin, cos, arccos, pi, round

def rad2deg(radians):
    degrees = radians * 180 / pi
    return degrees

def deg2rad(degrees):
    radians = degrees * pi / 180
    return radians

def getDistanceBetweenPointsNew(latitude1, longitude1, latitude2, longitude2, unit = 'miles'):
    
    theta = longitude1 - longitude2
    
    distance = 60 * 1.1515 * rad2deg(
        arccos(
            (sin(deg2rad(latitude1)) * sin(deg2rad(latitude2))) + 
            (cos(deg2rad(latitude1)) * cos(deg2rad(latitude2)) * cos(deg2rad(theta)))
        )
    )
    
    if unit == 'miles':
        return round(distance, 2)
    if unit == 'kilometers':
        return round(distance * 1.609344, 2)

Các biến là:

  • vĩ độ1 - một biến cho vị trí đầu tiên của bạn vĩ độ.
  • kinh độ1 - một biến cho vị trí đầu tiên của bạn kinh độ
  • vĩ độ2 - một biến cho vị trí thứ hai của bạn vĩ độ.
  • kinh độ2 - một biến cho vị trí thứ hai của bạn kinh độ.
  • đơn vị - mặc định là dặm. Điều này có thể được cập nhật hoặc chuyển thành cây số.

MySQL: Truy xuất tất cả các bản ghi trong một phạm vi bằng cách tính khoảng cách tính bằng dặm bằng kinh độ và vĩ độ

Sử dụng các kiểu dữ liệu không gian trong MySQL là cách hiệu quả và thuận tiện hơn để làm việc với dữ liệu địa lý, bao gồm cả việc tính toán khoảng cách giữa các điểm. MySQL hỗ trợ các kiểu dữ liệu không gian như POINT, LINESTRINGPOLYGON, cùng với các hàm không gian như ST_Distance.

Khi bạn sử dụng ST_Distance hoạt động trong MySQL với dữ liệu địa lý được biểu diễn dưới dạng POINT tọa độ, nó tính đến độ cong của bề mặt Trái đất. Mô hình hình cầu được sử dụng bởi ST_Distance sử dụng công thức Haversine. Phép tính gần đúng này phù hợp cho hầu hết các mục đích thực tế nhưng có thể gây ra sự thiếu chính xác đôi chút đối với khoảng cách rất dài.

Đây là cách bạn có thể tính khoảng cách giữa hai điểm bằng cách sử dụng Kiểu dữ liệu không gian:

  1. Tạo bảng với kiểu dữ liệu không gian: Đầu tiên, tạo một bảng có POINT cột để lưu trữ các điểm địa lý. Ví dụ:
CREATE TABLE locations (
    id INT AUTO_INCREMENT PRIMARY KEY,
    name VARCHAR(255),
    coordinates POINT
);

Chèn các điểm địa lý của bạn vào bảng này bằng cách sử dụng POINT người xây dựng:

INSERT INTO locations (name, coordinates)
VALUES
    ('Point A', POINT(40.7128, -74.0060)), -- New York City
    ('Point B', POINT(34.0522, -118.2437)); -- Los Angeles
  1. Tính khoảng cách bằng ST_Distance: Bạn có thể tính khoảng cách giữa hai điểm bằng cách sử dụng ST_Distance chức năng. Đây là một truy vấn mẫu để tính khoảng cách giữa hai điểm:
SELECT
    id1,
    id2,
    (ST_Distance(coordinates1, coordinates2) / 1609.344) AS distance_in_miles
FROM (
    SELECT
        l1.id AS id1,
        l2.id AS id2,
        l1.coordinates AS coordinates1,
        l2.coordinates AS coordinates2
    FROM
        locations l1,
        locations l2
    WHERE
        l1.id = 1 AND l2.id = 2
) AS distances;

Thay thế 12 với ID của hai điểm bạn muốn tính khoảng cách giữa.

  1. Kết quả: Truy vấn sẽ trả về khoảng cách giữa hai điểm tính bằng dặm.

Sử dụng các kiểu dữ liệu không gian và ST_Distance cung cấp một cách hiệu quả và chính xác hơn để làm việc với dữ liệu địa lý trong MySQL. Nó cũng đơn giản hóa việc tính toán khoảng cách giữa các điểm, giúp quản lý và truy vấn dữ liệu của bạn dễ dàng hơn.

MySQL: Truy xuất tất cả các bản ghi trong một phạm vi bằng cách tính toán khoảng cách theo kilomet sử dụng vĩ độ và kinh độ

Theo mặc định ST_Distance trả về khoảng cách tính bằng mét, vì vậy bạn chỉ cần cập nhật truy vấn theo km:

SELECT
    id1,
    id2,
    (ST_Distance(coordinates1, coordinates2) / 1000) AS distance_in_kilometers
FROM (
    SELECT
        l1.id AS id1,
        l2.id AS id2,
        l1.coordinates AS coordinates1,
        l2.coordinates AS coordinates2
    FROM
        locations l1,
        locations l2
    WHERE
        l1.id = 1 AND l2.id = 2
) AS distances;

Khoảng cách địa lý của Microsoft SQL Server: STDistance

Nếu bạn đang sử dụng Microsoft SQL Server, họ cung cấp chức năng riêng, STKhoảng cách để tính khoảng cách giữa hai điểm bằng kiểu dữ liệu Địa lý.

DECLARE @g geography;  
DECLARE @h geography;  
SET @g = geography::STGeomFromText('LINESTRING(-122.360 47.656, -122.343 47.656)', 4326);  
SET @h = geography::STGeomFromText('POINT(-122.34900 47.65100)', 4326);  
SELECT @g.STDistance(@h);  

Lời khen ngợi dành cho Manash Sahoo, người sáng lập và kiến ​​trúc sư cấp cao tại Ion Ba.

Douglas Karr

Douglas Karr là CMO của mởINSIGHTS và người sáng lập ra Martech Zone. Douglas đã giúp hàng chục công ty khởi nghiệp MarTech thành công, đã hỗ trợ thẩm định hơn 5 tỷ USD trong các thương vụ mua lại và đầu tư của Martech, đồng thời tiếp tục hỗ trợ các công ty triển khai và tự động hóa các chiến lược tiếp thị và bán hàng của họ. Douglas là một chuyên gia và diễn giả về chuyển đổi kỹ thuật số và MarTech được quốc tế công nhận. Douglas cũng là tác giả đã xuất bản sách hướng dẫn của Dummie và sách lãnh đạo doanh nghiệp.

Bài viết liên quan

Back to top
Đóng

Đã phát hiện ra khối quảng cáo

Martech Zone có thể cung cấp cho bạn nội dung này miễn phí vì chúng tôi kiếm tiền từ trang web của mình thông qua doanh thu quảng cáo, liên kết đơn vị liên kết và tài trợ. Chúng tôi sẽ đánh giá cao nếu bạn xóa trình chặn quảng cáo của mình khi bạn xem trang web của chúng tôi.