Thư viện hình học

  1. Tổng quan
  2. Khái niệm Hình học hình cầu
    1. Hàm khoảng cách và hàm diện tích
    2. Hàm điều hướng
  3. Mã hoá hình học
  4. Hàm đa giác và hàm đa đường
    1. containsLocation()
    2. isLocationOnEdge()

Tổng quan

Các khái niệm trong tài liệu này đề cập đến các tính năng chỉ có trong thư viện google.maps.geometry. Theo mặc định, thư viện này không được tải khi bạn tải API JavaScript của Maps, nhưng bạn phải chỉ định rõ ràng thông qua việc sử dụng thông số tự khởi động libraries. Để biết thêm thông tin, hãy xem phần Tổng quan về thư viện.

Thư viện hình học API JavaScript của Maps cung cấp các hàm tiện ích để tính toán dữ liệu hình học trên bề mặt Earth. Thư viện này có 3 vùng chứa tên:

  • spherical chứa các tiện ích hình học hình cầu cho phép bạn tính góc, khoảng cách và diện tích theo vĩ độ và kinh độ.
  • encoding chứa các tiện ích để mã hoá và giải mã đường dẫn nhiều đường theo Thuật toán đa dòng được mã hoá.
  • poly chứa các hàm hiệu dụng để tính toán liên quan đến đa giác và hình nhiều đường.

Thư viện google.maps.geometry không chứa bất kỳ lớp nào; thay vào đó, thư viện chứa các phương thức tĩnh trong các không gian tên ở trên.

Khái niệm Hình học hình cầu

Hình ảnh trong API JavaScript của Maps là hình ảnh hai chiều và "bằng phẳng". Tuy nhiên, Trái Đất có dạng ba chiều và thường được ước chừng là hình cầu dẹt hoặc nhiều hơn là một hình cầu. Trong API Maps, chúng tôi sử dụng một hình cầu và để biểu thị Trái đất trên một bề mặt phẳng hai chiều — chẳng hạn như màn hình máy tính của bạn — API Maps sử dụng một phép chiếu.

Trong phép chiếu 2D, hình ảnh đôi khi có thể bị đánh lừa. Do phép chiếu bản đồ nhất thiết đòi hỏi một số điểm méo, hình học Euclidian đơn giản thường không thể áp dụng được. Ví dụ: khoảng cách ngắn nhất giữa hai điểm trên một hình cầu không phải là đường thẳng, mà là một hình tròn lớn (một loại hình trắc địa) và các góc tạo nên một tam giác trên bề mặt của một hình cầu có tổng cộng lên đến hơn 180 độ.

Do những khác biệt này, các hàm hình học trên một hình cầu (hoặc trên hình chiếu của nó) đòi hỏi bạn phải sử dụng Hình học hình cầu để tính toán các cấu trúc như vậy như khoảng cách, tiêu đề và diện tích. Các tiện ích để tính toán các cấu trúc hình cầu này nằm trong không gian tên google.maps.geometry.spherical của API Maps. Không gian tên này cung cấp các phương thức tĩnh để tính toán giá trị vô hướng từ toạ độ hình cầu (vĩ độ và kinh độ).

Hàm khoảng cách và diện tích

Khoảng cách giữa hai điểm là độ dài của đường dẫn ngắn nhất giữa hai điểm. Đường đi ngắn nhất này được gọi là trắc địa. Trên một hình cầu, tất cả các trắc địa đều là các đoạn của một vòng tròn lớn. Để tính toán khoảng cách này, hãy gọi computeDistanceBetween(), truyền vào đó 2 đối tượng LatLng.

Thay vào đó, bạn có thể sử dụng computeLength() để tính toán độ dài của một đường dẫn nhất định nếu bạn có nhiều vị trí.

Kết quả khoảng cách được biểu thị bằng mét.

Để tính toán diện tích (tính bằng mét vuông) của một khu vực đa giác, hãy gọi computeArea(), truyền mảng đối tượng LatLng xác định một vòng lặp khép kín.

Khi điều hướng trên một hình cầu, tiêu đề là góc chỉ đường từ một điểm tham chiếu cố định, thường là hướng bắc đúng. Trong API Google Maps, một tiêu đề được xác định bằng độ từ hướng bắc thực, trong đó tiêu đề được đo theo chiều kim đồng hồ từ hướng bắc thực (0 độ). Bạn có thể tính toán tiêu đề này giữa hai vị trí bằng phương thức computeHeading(), truyền vào đó 2 đối tượng fromto LatLng.

Khi có một tiêu đề cụ thể, vị trí gốc và khoảng cách di chuyển (tính bằng mét), bạn có thể tính toạ độ điểm đến bằng cách sử dụng computeOffset().

Cho sẵn 2 đối tượng LatLng và giá trị trong khoảng từ 0 đến 1, bạn cũng có thể tính toán một đích đến giữa các đối tượng đó bằng cách sử dụng phương thức interpolate(). Phương thức này thực hiện nội suy tuyến tính hình cầu giữa 2 vị trí, trong đó giá trị cho biết khoảng cách dạng phân số để di chuyển dọc theo đường dẫn từ gốc đến đích.

Ví dụ sau đây sẽ tạo ra 2 hình nhiều đường khi bạn nhấp vào hai điểm trên bản đồ — một đường trắc địa và một đường "thẳng" kết nối hai vị trí — và tính toán tiêu đề để di chuyển giữa hai điểm:

TypeScript

// This example requires the Geometry library. Include the libraries=geometry
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=geometry">

let marker1: google.maps.Marker, marker2: google.maps.Marker;
let poly: google.maps.Polyline, geodesicPoly: google.maps.Polyline;

function initMap(): void {
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 4,
      center: { lat: 34, lng: -40.605 },
    }
  );

  map.controls[google.maps.ControlPosition.TOP_CENTER].push(
    document.getElementById("info") as HTMLElement
  );

  marker1 = new google.maps.Marker({
    map,
    draggable: true,
    position: { lat: 40.714, lng: -74.006 },
  });

  marker2 = new google.maps.Marker({
    map,
    draggable: true,
    position: { lat: 48.857, lng: 2.352 },
  });

  const bounds = new google.maps.LatLngBounds(
    marker1.getPosition() as google.maps.LatLng,
    marker2.getPosition() as google.maps.LatLng
  );

  map.fitBounds(bounds);

  google.maps.event.addListener(marker1, "position_changed", update);
  google.maps.event.addListener(marker2, "position_changed", update);

  poly = new google.maps.Polyline({
    strokeColor: "#FF0000",
    strokeOpacity: 1.0,
    strokeWeight: 3,
    map: map,
  });

  geodesicPoly = new google.maps.Polyline({
    strokeColor: "#CC0099",
    strokeOpacity: 1.0,
    strokeWeight: 3,
    geodesic: true,
    map: map,
  });

  update();
}

function update() {
  const path = [
    marker1.getPosition() as google.maps.LatLng,
    marker2.getPosition() as google.maps.LatLng,
  ];

  poly.setPath(path);
  geodesicPoly.setPath(path);

  const heading = google.maps.geometry.spherical.computeHeading(
    path[0],
    path[1]
  );

  (document.getElementById("heading") as HTMLInputElement).value =
    String(heading);
  (document.getElementById("origin") as HTMLInputElement).value = String(
    path[0]
  );
  (document.getElementById("destination") as HTMLInputElement).value = String(
    path[1]
  );
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

// This example requires the Geometry library. Include the libraries=geometry
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=geometry">
let marker1, marker2;
let poly, geodesicPoly;

function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 4,
    center: { lat: 34, lng: -40.605 },
  });

  map.controls[google.maps.ControlPosition.TOP_CENTER].push(
    document.getElementById("info"),
  );
  marker1 = new google.maps.Marker({
    map,
    draggable: true,
    position: { lat: 40.714, lng: -74.006 },
  });
  marker2 = new google.maps.Marker({
    map,
    draggable: true,
    position: { lat: 48.857, lng: 2.352 },
  });

  const bounds = new google.maps.LatLngBounds(
    marker1.getPosition(),
    marker2.getPosition(),
  );

  map.fitBounds(bounds);
  google.maps.event.addListener(marker1, "position_changed", update);
  google.maps.event.addListener(marker2, "position_changed", update);
  poly = new google.maps.Polyline({
    strokeColor: "#FF0000",
    strokeOpacity: 1.0,
    strokeWeight: 3,
    map: map,
  });
  geodesicPoly = new google.maps.Polyline({
    strokeColor: "#CC0099",
    strokeOpacity: 1.0,
    strokeWeight: 3,
    geodesic: true,
    map: map,
  });
  update();
}

function update() {
  const path = [marker1.getPosition(), marker2.getPosition()];

  poly.setPath(path);
  geodesicPoly.setPath(path);

  const heading = google.maps.geometry.spherical.computeHeading(
    path[0],
    path[1],
  );

  document.getElementById("heading").value = String(heading);
  document.getElementById("origin").value = String(path[0]);
  document.getElementById("destination").value = String(path[1]);
}

window.initMap = initMap;
Xem ví dụ

Thử mẫu

Phương pháp mã hoá

Đường dẫn trong API JavaScript của Maps thường được chỉ định là Array của các đối tượng LatLng. Tuy nhiên, việc truyền một mảng như vậy thường rất lớn. Thay vào đó, bạn có thể dùng thuật toán mã hoá nhiều dòng của Google để nén một đường dẫn nhất định, sau đó bạn có thể giải nén đường dẫn này bằng cách giải mã.

Thư viện geometry chứa một không gian tên encoding dành cho các tiện ích mã hoá và giải mã hình nhiều đường.

Phương thức tĩnh encodePath() mã hoá đường dẫn đã cho. Bạn có thể truyền một mảng LatLng hoặc MVCArray (được Polyline.getPath() trả về).

Để giải mã đường dẫn đã mã hoá, hãy gọi decodePath() để truyền phương thức chuỗi đã mã hoá.

Ví dụ sau đây hiển thị bản đồ của Oxford, Mississippi. Nhấp vào bản đồ sẽ thêm một điểm vào một hình nhiều đường. Khi hình nhiều đường được tạo, phương thức mã hoá sẽ xuất hiện bên dưới.

TypeScript

// This example requires the Geometry library. Include the libraries=geometry
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=geometry">

function initMap(): void {
  const map = new google.maps.Map(
    document.getElementById("map") as HTMLElement,
    {
      zoom: 14,
      center: { lat: 34.366, lng: -89.519 },
    }
  );
  const poly = new google.maps.Polyline({
    strokeColor: "#000000",
    strokeOpacity: 1,
    strokeWeight: 3,
    map: map,
  });

  // Add a listener for the click event
  google.maps.event.addListener(map, "click", (event) => {
    addLatLngToPoly(event.latLng, poly);
  });
}

/**
 * Handles click events on a map, and adds a new point to the Polyline.
 * Updates the encoding text area with the path's encoded values.
 */
function addLatLngToPoly(
  latLng: google.maps.LatLng,
  poly: google.maps.Polyline
) {
  const path = poly.getPath();

  // Because path is an MVCArray, we can simply append a new coordinate
  // and it will automatically appear
  path.push(latLng);

  // Update the text field to display the polyline encodings
  const encodeString = google.maps.geometry.encoding.encodePath(path);

  if (encodeString) {
    (document.getElementById("encoded-polyline") as HTMLInputElement).value =
      encodeString;
  }
}

declare global {
  interface Window {
    initMap: () => void;
  }
}
window.initMap = initMap;

JavaScript

// This example requires the Geometry library. Include the libraries=geometry
// parameter when you first load the API. For example:
// <script src="https://maps.googleapis.com/maps/api/js?key=YOUR_API_KEY&libraries=geometry">
function initMap() {
  const map = new google.maps.Map(document.getElementById("map"), {
    zoom: 14,
    center: { lat: 34.366, lng: -89.519 },
  });
  const poly = new google.maps.Polyline({
    strokeColor: "#000000",
    strokeOpacity: 1,
    strokeWeight: 3,
    map: map,
  });

  // Add a listener for the click event
  google.maps.event.addListener(map, "click", (event) => {
    addLatLngToPoly(event.latLng, poly);
  });
}

/**
 * Handles click events on a map, and adds a new point to the Polyline.
 * Updates the encoding text area with the path's encoded values.
 */
function addLatLngToPoly(latLng, poly) {
  const path = poly.getPath();

  // Because path is an MVCArray, we can simply append a new coordinate
  // and it will automatically appear
  path.push(latLng);

  // Update the text field to display the polyline encodings
  const encodeString = google.maps.geometry.encoding.encodePath(path);

  if (encodeString) {
    document.getElementById("encoded-polyline").value = encodeString;
  }
}

window.initMap = initMap;
Xem ví dụ

Thử mẫu

Hàm đa giác và đa đường

Không gian tên poly của thư viện hình có chứa các hàm hiệu dụng xác định xem một điểm nhất định nằm bên trong hay gần một đa giác hoặc hình nhiều đường.

containsLocation()

containsLocation(point:LatLng, polygon:Polygon)

Để tìm hiểu xem một điểm cho trước có nằm trong một đa giác hay không, hãy chuyển điểm và đa giác đó đến google.maps.geometry.poly.containsLocation(). Các hàm sẽ trả về giá trị true nếu điểm nằm trong đa giác hoặc trên cạnh của đa giác.

Mã sau đây ghi "true" vào bảng điều khiển trình duyệt nếu lượt nhấp của người dùng nằm trong tam giác đã xác định; nếu không, mã sẽ ghi "false".

function initialize() {
  var mapOptions = {
    zoom: 5,
    center: new google.maps.LatLng(24.886, -70.269),
    mapTypeId: 'terrain'
  };

  var map = new google.maps.Map(document.getElementById('map'),
      mapOptions);

  var bermudaTriangle = new google.maps.Polygon({
    paths: [
      new google.maps.LatLng(25.774, -80.190),
      new google.maps.LatLng(18.466, -66.118),
      new google.maps.LatLng(32.321, -64.757)
    ]
  });

  google.maps.event.addListener(map, 'click', function(event) {
    console.log(google.maps.geometry.poly.containsLocation(event.latLng, bermudaTriangle));
  });
}

google.maps.event.addDomListener(window, 'load', initialize);

Một phiên bản khác của mã này sẽ vẽ một hình tam giác màu xanh dương trên bản đồ nếu lượt nhấp nằm trong Tam giác Bermuda và một vòng tròn màu đỏ nếu không:

Xem ví dụ

isLocationOnEdge()

isLocationOnEdge(point:LatLng, poly:Polygon|Polyline, tolerance?:number)

Để xác định xem một điểm nằm trên hay gần một hình nhiều đường hay nằm trên hoặc gần cạnh của một đa giác, hãy chuyển điểm, hình nhiều đường/đa giác và có thể dùng một giá trị dung sai tính bằng độ thành google.maps.geometry.poly.isLocationOnEdge(). Hàm trả về giá trị true (đúng) nếu khoảng cách giữa điểm và điểm gần nhất trên đường hoặc cạnh nằm trong dung sai đã chỉ định. Giá trị dung sai mặc định là 10-9 độ.

function initialize() {
  var myPosition = new google.maps.LatLng(46.0, -125.9);

  var mapOptions = {
    zoom: 5,
    center: myPosition,
    mapTypeId: 'terrain'
  };

  var map = new google.maps.Map(document.getElementById('map'),
      mapOptions);

  var cascadiaFault = new google.maps.Polyline({
    path: [
      new google.maps.LatLng(49.95, -128.1),
      new google.maps.LatLng(46.26, -126.3),
      new google.maps.LatLng(40.3, -125.4)
    ]
  });

  cascadiaFault.setMap(map);

  if (google.maps.geometry.poly.isLocationOnEdge(myPosition, cascadiaFault, 10e-1)) {
    alert("Relocate!");
  }
}

google.maps.event.addDomListener(window, 'load', initialize);