Biblioteca de geometría

  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 que se incluyen en 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, sino que debe especificarse de forma explícita mediante el uso de un parámetro de arranque libraries. Para obtener más información, consulta el artículo Descripción general de las bibliotecas.

La biblioteca de geometría 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íneas según el algoritmo de polilínea codificada.
  • poly contiene funciones de utilidad para hacer cálculos que incluyen polígonos y polilíneas.

La biblioteca google.maps.geometry no contiene ninguna clase; 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 a menudo se la concibe como un esferoide oblato o como una esfera. En la API de Google Maps, usamos una esfera y, para representar la Tierra en una superficie plana bidimensional (como la pantalla de una computadora), usamos una proyección.

En las proyecciones 2D, las apariencias a veces pueden ser engañosas. Dado que la proyección del mapa requiere algún grado de distorsión, a menudo no es posible aplicar la geometría euclidiana simple. Por ejemplo, la distancia más corta entre dos puntos de una esfera no es una línea recta, sino un círculo máximo (un tipo de línea geodésica), y los ángulos que componen 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, la orientación y el área. El espacio de nombres google.maps.geometry.spherical de la API de Google Maps incluye utilidades para calcular estas construcciones geométricas esféricas. Este espacio de nombres proporciona métodos estáticos para el cálculo de valores escalares a partir de coordenadas esféricas (latitudes y longitudes).

Funciones de distancia y área

La distancia entre dos puntos es la extensión de la ruta más corta entre ellos. Esta ruta se conoce como línea geodésica. En una esfera, todas las líneas geodésicas son segmentos de un círculo máximo. 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 determinada si tienes varias ubicaciones.

Los resultados de las distancias se expresan en metros.

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

Al navegar en una esfera, la orientación es un ángulo de dirección a partir de un punto de referencia fijo, generalmente el norte geográfico. En la API de Google Maps, la orientación se define en grados a partir del norte geográfico, donde las orientaciones se miden en el sentido de las manecillas del reloj a partir del norte geográfico (0 grados). Puedes calcular la orientación entre dos ubicaciones con el método computeHeading() y pasarle dos objetos from y to LatLng.

A partir de una orientación en particular, una ubicación de origen y la distancia de viaje (en metros), puedes calcular las coordenadas de destino mediante computeOffset().

A partir de dos objetos LatLng y un valor entre 0 y 1, también puedes calcular un destino entre ellos mediante el método interpolate(). Este realiza una interpolación lineal esférica entre las dos ubicaciones, donde 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 línea "recta" que conectan las dos ubicaciones) y se calcula la orientación del recorrido de un punto al otro:

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

Prueba la muestra

Métodos de codificación

Las rutas de la API de Maps JavaScript a menudo se especifican como un Array de objetos LatLng. Sin embargo, este tipo de array suele ser muy pesado para pasarlo. 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 la 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 proporcionada. Puedes pasar un array 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 siguiente ejemplo, se muestra un mapa de Oxford, Misisipi. Cuando se hace clic en el mapa, se agrega un punto a una polilínea. A medida que se construye la polilínea, la 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

Prueba 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 "true" si el punto se encuentra dentro del polígono o en su borde.

El siguiente código escribe "true" en la consola del navegador si el clic que realiza el usuario se encuentra dentro del triángulo definido. De lo contrario, escribe "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);

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

Ver ejemplo

isLocationOnEdge()

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

Para determinar si un punto se encuentra 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 este punto y el punto más cercano de la línea o del borde se encuentra dentro del valor de tolerancia especificado. 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);