几何图形库

  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 会使用投影

在 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。

如果用户的点击落入定义的三角形内,以下代码会将此字符写入浏览器控制台;否则,会将 '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);