几何图形库

  1. 概览
  2. 球面几何图形概念
    1. 距离和面积函数
    2. 导航函数
  3. 几何图形编码
  4. 多边形和折线函数
    1. containsLocation()
    2. isLocationOnEdge()

概览

本文档中的概念仅指 google.maps.geometry 库中提供的功能。默认情况下,在您加载 Maps JavaScript API 时,该库不会加载,您必须使用 libraries 引导参数进行明确指定。如需了解详情,请参阅库概览

Maps JavaScript API 几何图形库提供了一些实用函数,用于计算地球表面的几何图形数据。此库包含三个命名空间:

  • spherical 包含球面几何图形实用程序,让您能够根据纬度和经度计算角度、距离和面积。
  • encoding 包含一些实用程序,可用于根据编码多段线算法对多段线路径进行编码和解码。
  • poly 包含一些实用函数,可用于执行涉及多边形和多段线的计算。

google.maps.geometry 库不包含任何类,而是包含上述命名空间的静态方法。

球面几何图形概念

Maps JavaScript API 中的图像是二维的“平面”图像。然而,地球是三维的,人们常常将其近似看作扁球体,或者球体。在 Maps API 中,我们使用的是球面;为了在二维平面(例如您的计算机屏幕)上展示地球,Maps API 会使用投影

在二维投影中,表象有时可能具有误导性。由于地图投影必定会导致部分失真,简单的欧几里得几何往往并不适用。例如,球体上两点之间的最短距离不是直线,而是大圆弧(一种测地线),而球体表面上的三角形的内角之和大于 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);