幾何圖形程式庫

  1. 總覽
  2. 球面幾何圖形概念
    1. 距離與面積函式
    2. 瀏覽函式
  3. 幾何圖形編碼
  4. 多邊形與折線函式
    1. containsLocation()
    2. isLocationOnEdge()

總覽

本文件所述概念僅適用於 google.maps.geometry 程式庫所提供的功能。根據預設,當您載入 Maps JavaScript API 時,不會載入此程式庫。您必須使用 libraries Bootstrap 參數明確指定此程式庫。詳情請參閱程式庫總覽

Maps JavaScript API 幾何圖形程式庫所提供的公用函式,可用於計算地表的幾何圖形資料。此程式庫包含三個命名空間:

  • spherical 包含球面幾何圖形公用程式,以便您根據經緯度計算角度、距離及面積。
  • encoding 包含一些公用程式,可用來根據編碼折線演算法對折線路徑進行編碼及解碼。
  • poly 包含一些公用函式,可用來進行多邊形和折線相關計算。

google.maps.geometry 程式庫不含任何類別,只會提供上述命名空間的靜態方法。

球面幾何圖形概念

Maps JavaScript API 中的圖片都是 2D 平面圖片,而地球是 3D 結構,比較像扁球體或是球體。Maps API 使用投影法在 2D 平面 (例如您的電腦畫面) 上繪製球體代表地球。

在 2D 投影之下,顯示內容可能會出現一些假象,這是因為地圖投影難免會出現失真的情況,因此簡單的歐幾里得幾何圖形往往不適用。舉例來說,在球體上,兩點之間最短的距離不是直線,而是大圓線 (一種測地線),同時球體表面上的三角形角度總合也會大於 180 度。

這幾種差異造成球體上 (或球體投影上) 的幾何函式在計算距離、頂角和面積等建構項目時,必須使用球面幾何圖形。Maps API 的 google.maps.geometry.spherical 命名空間納入計算這些球面幾何建構項目的公用程式。此命名空間提供一些靜態方法,可用來計算球面座標 (經緯度) 純量值。

距離與面積函式

兩點間的距離是指兩點間最短的路徑長度,稱為測地線。在球體上,所有的測地線都是大圓線。如要計算這個距離,可以呼叫 computeDistanceBetween(),並傳遞兩個 LatLng 物件給這個函式。

如果您有數個位置,也可改用 computeLength() 計算指定路徑的長度。

距離的計算結果會以公尺表示。

如要計算多邊形區域的面積 (以平方公尺為單位),可以呼叫 computeArea(),並傳遞 LatLng 物件陣列定義封閉區域。

在球體上進行瀏覽時,頂角就是固定參照點 (通常是正北方) 的方向角。Google Maps API 會將頂角定義為相對於正北方的角度,也就是頂角與正北方 (0 度) 的順時針方向夾角角度。您可以使用 computeHeading() 方法,並傳遞兩個 fromto LatLng 物件給這個函式,來計算兩個位置間的這個頂角。

只要指定特定的頂角、原始位置,以及所要移動的距離 (以公尺為單位),即可使用 computeOffset() 計算出目的地座標。

您也可提供兩個 LatLng 物件和 0 與 1 之間的值,利用 interpolate() 方法計算這兩個物件之間的目的地。這個方法會執行兩個位置間的球面線性差值,其中的值表示起點到目的地間所要移動的距離 (以小數表示)。

以下範例會在您點選地圖上的兩個點時建立兩條折線 (連接兩個位置的一條測地線與一條直線),並計算在兩點間移動時的頂角:

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;
查看範例

試用範例

編碼方法

Maps JavaScript API 中的路徑通常會指定為 LatLng 物件的 Array。傳送這類陣列的步驟通常十分繁複。因此,您可以使用 Google 的折線編碼演算法壓縮指定路徑,稍後再透過解碼來解壓縮。

geometry 程式庫所含的 encoding 命名空間,可提供用於編碼及解碼折線的公用程式。

靜態方法 encodePath() 可以編碼指定路徑。您也可以傳遞 LatLng 陣列或 MVCArray (由 Polyline.getPath() 傳回)。

如要對經過編碼的路徑進行解碼,請呼叫 decodePath(),並將編碼的字串傳遞給該方法。

以下範例顯示密西西比州牛津的地圖。按一下地圖即可在折線中加入點。建構折線時,折線的編碼會顯示在下方。

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;
查看範例

試用範例

多邊形與折線函式

幾何圖形程式庫的 poly 命名空間包含一些公用函式,可用來判斷特定的點是否位於多邊形或折線的內部或附近。

containsLocation()

containsLocation(point:LatLng, polygon:Polygon)

如要確認特定的點是否位於多邊形內,請將該點和多邊形傳遞至 google.maps.geometry.poly.containsLocation()。如果該點位於多邊形內部或邊緣,這個函式就會傳回 TRUE。

如果使用者的點擊位置位於所定義的三角形中,下方程式碼就會將「TRUE」傳回瀏覽器控制台,反之則傳回「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);

如果點擊位置位於百慕達三角中,此程式碼的另一個版本會在地圖上繪製一個藍色三角形,反之則繪製一個紅色圓形:

查看範例

isLocationOnEdge()

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

如要判斷某個點是否位於折線/多邊形邊緣上或附近,請將該點、折線/多邊形,以及公差值 (選用,以度為單位) 傳遞至 google.maps.geometry.poly.isLocationOnEdge()。如果該指定點與折線/多邊形邊緣上最近點之間的距離位於指定的公差內,函式就會傳回 TRUE。預設的公差值為 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);