Biblioteca de geometría

Organiza tus páginas con colecciones Guarda y categoriza el contenido según tus preferencias.
  1. Descripción general
  2. Conceptos de geometría esférica
    1. Funciones de distancia y área
    2. Funciones de navegación
  3. Codificación de geometría
  4. Funciones de polígonos y polilíneas
    1. containsLocation()
    2. isLocationOnEdge()

Descripción general

Los conceptos dentro de este documento hacen referencia a funciones que solo están disponibles en la biblioteca google.maps.geometry. Esta biblioteca no se carga de forma predeterminada cuando cargas la API de Maps JavaScript, pero debe especificarse de forma explícita mediante el uso de un parámetro de arranque libraries. Para obtener más información, consulta la Descripción general de las bibliotecas.

La biblioteca de geometrías de la API de Maps JavaScript proporciona funciones de utilidad para el cálculo de datos geométricos sobre la superficie de la Tierra. En la biblioteca se incluyen tres espacios de nombres:

  • spherical contiene utilidades de geometría esférica que te permiten calcular ángulos, distancias y áreas a partir de latitudes y longitudes.
  • encoding contiene utilidades para codificar y decodificar rutas de polilínea según el Algoritmo de polilínea codificada.
  • poly contiene funciones de utilidad para cálculos que incluyen polígonos y polilíneas.

La biblioteca google.maps.geometry no contiene clases; en su lugar, contiene métodos estáticos en los espacios de nombres anteriores.

Conceptos de geometría esférica

Las imágenes de la API de Maps JavaScript son bidimensionales y &planas. Sin embargo, la Tierra es tridimensional y se suele aproximar como un esferoide achatado o más como una esfera. Dentro de la API de Google Maps, usamos una esfera, y para representar la Tierra en una superficie bidimensional (como la pantalla de tu computadora), la API de Google Maps usa una proyección.

En las proyecciones 2D, las apariencias a veces pueden engañar. Debido a que la proyección del mapa requiere cierta distorsión, a menudo no se aplica la geometría euclidiana simple. Por ejemplo, la distancia más corta entre dos puntos en una esfera no es una línea recta, sino un círculo grande (un tipo de línea geodésica), y los ángulos que conforman un triángulo en la superficie de una esfera suman más de 180 grados.

Debido a estas diferencias, las funciones geométricas en una esfera (o en su proyección) requieren el uso de geometría esférica para calcular construcciones como la distancia, el rumbo y el área. Las utilidades para calcular estas construcciones geométricas esféricas se encuentran dentro del espacio de nombres google.maps.geometry.spherical de la API de Google Maps. Este espacio de nombres proporciona métodos estáticos para calcular valores escalares a partir de coordenadas esféricas (latitudes y longitudes).

Funciones de distancia y área

La distancia entre dos puntos es la longitud de la ruta más corta entre ellos. Este recorrido se conoce como “línea geodesica”. En una esfera, todas las geodésicas son segmentos de un círculo grande. Para calcular esta distancia, llama a computeDistanceBetween() y pásale dos objetos LatLng.

En su lugar, puedes usar computeLength() para calcular la longitud de una ruta específica si tienes varias ubicaciones.

Los resultados de distancias se expresan en metros.

Para calcular el área (en metros cuadrados) de un área poligonal, llama a computeArea() y pasa el arreglo de objetos LatLng que definen un bucle cerrado.

Cuando se navega por una esfera, un rumbo es el ángulo de una dirección desde un punto de referencia fijo, generalmente el norte verdadero. Dentro de la API de Google Maps, un rumbo se define en grados a partir del norte verdadero, en el que los encabezados se miden en sentido horario desde el norte verdadero (0 grados). Puedes calcular este encabezado entre dos ubicaciones con el método computeHeading() y pasarle dos objetos from y to LatLng.

Dados un rumbo en particular, una ubicación de origen y la distancia de viaje (en metros), puedes calcular las coordenadas del destino mediante computeOffset().

Dados dos objetos LatLng y un valor entre 0 y 1, también puedes calcular un destino entre ellos con el método interpolate(), que realiza la interpolación lineal esférica entre las dos ubicaciones, en las que el valor indica la distancia fraccionaria que se recorrerá desde el origen hasta el destino.

En el siguiente ejemplo, se crean dos polilíneas cuando haces clic en dos puntos del mapa (una línea geodésica y una recta) que conectan las dos ubicaciones y calcula el rumbo para viajar entre los dos puntos:

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;
Ver ejemplo

Probar la muestra

Métodos de codificación:

Las rutas de acceso dentro de la API de Maps JavaScript a menudo se especifican como un Array de objetos LatLng. Sin embargo, pasar un arreglo de este tipo suele ser voluminoso. En su lugar, puedes usar el algoritmo de codificación de polilínea de Google para comprimir una ruta determinada, que luego puedes descomprimir mediante decodificación.

La biblioteca geometry contiene un espacio de nombres encoding para que las utilidades codifiquen y decodifiquen polilíneas.

El método estático encodePath() codifica la ruta determinada. Puedes pasar un arreglo de LatLng o un MVCArray (que muestra Polyline.getPath()).

Para decodificar una ruta codificada, llama a decodePath() y pasa la string codificada al método.

En el ejemplo siguiente se muestra un mapa de Oxford, Mississippi. Cuando se hace clic en el mapa se agrega un punto a una polilínea. A medida que se construye la polilínea, su codificación aparece debajo.

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;
Ver ejemplo

Probar la muestra

Funciones de polígonos y polilíneas

El espacio de nombres poly de la biblioteca de geometría contiene funciones de utilidad que determinan si un punto determinado se encuentra dentro o cerca de un polígono o una polilínea.

containsLocation()

containsLocation(point:LatLng, polygon:Polygon)

Para saber si un punto determinado se encuentra dentro de un polígono, pasa el punto y el polígono a google.maps.geometry.poly.containsLocation(). Las funciones muestran un valor verdadero si el punto está dentro del polígono o en su borde.

El siguiente código escribe &true 3 en la consola del navegador si el clic del usuario se encuentra dentro del triángulo definido; de lo contrario, escribe &false 39.

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);

Otra versión de este código dibuja un triángulo azul en el mapa si el clic se encuentra dentro del triángulo de las Bermudas y, de lo contrario, un círculo rojo:

Ver ejemplo

isLocationOnEdge()

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

Para determinar si un punto cae en una polilínea o cerca de ella, o en el borde de un polígono o cerca de él, pasa el punto, la polilínea o el polígono y, opcionalmente, un valor de tolerancia en grados a google.maps.geometry.poly.isLocationOnEdge(). La función muestra “true” si la distancia entre el punto y el punto más cercano en la línea o el borde se encuentra dentro de la tolerancia especificada. El valor de tolerancia predeterminado es de 10-9 grados.

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);