Biblioteca de geometria

  1. Visão geral
  2. Conceitos de geometria esférica
    1. Funções de distância e área
    2. Funções de navegação
  3. Codificação de geometria
  4. Funções de polígono e polilinha
    1. containsLocation()
    2. isLocationOnEdge()

Visão geral

Os conceitos deste documento se referem aos recursos disponíveis apenas na biblioteca google.maps.geometry. Essa biblioteca não é carregada por padrão quando você carrega a API Maps JavaScript, mas precisa ser explicitamente especificada com o uso de um parâmetro de inicialização libraries. Para mais informações, consulte a Visão geral das bibliotecas.

A biblioteca de geometria da API Maps JavaScript oferece funções utilitárias para o cálculo de dados geométricos na superfície da Terra. A biblioteca inclui três espaços de nome:

  • spherical contém utilitários de geometria esférica que permitem calcular ângulos, distâncias e áreas de latitudes e longitudes.
  • encoding contém utilitários para codificar e decodificar caminhos de polilinha de acordo com o Algoritmo de polilinha codificada.
  • poly contém funções utilitárias para cálculos envolvendo polígonos e polilinhas.

A biblioteca google.maps.geometry não contém classes. Em vez disso, a biblioteca contém métodos estáticos nos namespaces acima.

Conceitos de geometria esférica

As imagens na API Maps JavaScript são bidimensionais e "quot;flat." No entanto, a Terra é tridimensional e geralmente se aproxima de um esferoide lapela ou de uma esfera. Na API Maps, usamos uma esfera e, para representar a Terra em uma superfície plana bidimensional, como a tela do computador, a API Maps usa uma projeção.

Em projeções 2D, as aparências podem enganar. Como a projeção do mapa necessariamente requer alguma distorção, muitas vezes a geometria euclidiana simples não é aplicável. Por exemplo, a menor distância entre dois pontos em uma esfera não é uma linha reta, mas um grande círculo (um tipo de geodésica) e os ângulos que compõem um triângulo na superfície de uma esfera somam mais de 180 graus.

Devido a essas diferenças, as funções geométricas em uma esfera (ou em sua projeção) precisam usar Geometria Esférica para calcular essas construções como distância, direção e área. Os utilitários para calcular essas construções geométricas esféricas estão contidos no namespace google.maps.geometry.spherical da API Maps. O namespace fornece métodos estáticos para calcular valores escalares a partir de coordenadas esféricas (latitudes e longitudes).

Funções de distância e área

A distância entre dois pontos é o comprimento do caminho mais curto entre eles. Esse caminho mais curto é denominado geodésica. Em uma esfera, todas as geodésicas são segmentos de um grande círculo. Para calcular essa distância, chame computeDistanceBetween(), transmitindo dois objetos LatLng.

Em vez disso, use computeLength() para calcular o comprimento de um determinado caminho se você tiver vários locais.

Os resultados de distância são expressos em metros.

Para calcular a área (em metros quadrados) de uma área poligonal, chame computeArea(), transmitindo a matriz de objetos LatLng que definem um loop fechado.

Ao navegar em uma esfera, um título é o ângulo de uma direção a partir de um ponto de referência fixo, geralmente o norte verdadeiro. Na API Google Maps, um título é definido em graus a partir do norte verdadeiro, em que os cabeçalhos são medidos no sentido horário a partir do norte verdadeiro (0 grau). É possível calcular esse título entre dois locais com o método computeHeading(), transmitindo dois objetos from e to LatLng.

Com um título específico, um local de origem e a distância a ser percorrida (em metros), calcule as coordenadas de destino usando computeOffset().

Com dois objetos LatLng e um valor entre 0 e 1, também é possível calcular um destino entre eles usando o método interpolate(), que executa a interpolação linear esférica entre os dois locais, em que o valor indica a distância fracionária a ser percorrida ao longo do caminho da origem até o destino.

O exemplo a seguir cria duas polilinhas quando você clica em dois pontos no mapa (uma linha geodésica e uma reta que conecta os dois locais) e calcula a direção para viajar entre os dois pontos:

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 exemplo

Testar amostra

Métodos de codificação

Os caminhos na API Maps JavaScript geralmente são especificados como uma Array de objetos LatLng. No entanto, transmitir essa matriz geralmente é volumoso. Em vez disso, use o algoritmo de codificação de polilinha do Google para compactar um determinado caminho, que pode ser descompactado posteriormente por meio da decodificação.

A biblioteca geometry contém um namespace encoding para que os utilitários codifiquem e decodifiquem polilinhas.

O método estático encodePath() codifica o caminho fornecido. Você pode transmitir uma matriz de LatLngs ou um MVCArray, que é retornado por Polyline.getPath().

Para decodificar um caminho codificado, chame decodePath() transmitindo o método à string codificada.

O exemplo a seguir exibe um mapa de Oxford, Mississippi. Um clique no mapa adiciona um ponto a uma polilinha. À medida que a polilinha é construída, a codificação dela aparece abaixo.

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 exemplo

Testar amostra

Funções de polígono e polilinha

O namespace poly da biblioteca de geometria contém funções utilitárias que determinam se um determinado ponto está dentro ou perto de um polígono ou polilinha.

containsLocation()

containsLocation(point:LatLng, polygon:Polygon)

Para saber se um ponto específico está dentro de um polígono, transmita o ponto e o polígono para google.maps.geometry.poly.containsLocation(). As funções retornarão "true" se o ponto estiver dentro do polígono ou na borda dele.

O código a seguir grava 'true' no console do navegador se o clique do usuário fica dentro do triângulo definido; caso contrário, ele grava '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);

Outra versão deste código desenha um triângulo azul no mapa se o clique cai no Triângulo das Bermudas e um círculo vermelho caso contrário:

Ver exemplo

isLocationOnEdge()

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

Para determinar se um ponto está em ou perto de uma polilinha ou perto da borda de um polígono, transmita o ponto, a polilinha/polígono e, opcionalmente, um valor de tolerância em graus para google.maps.geometry.poly.isLocationOnEdge(). A função retornará "true" se a distância entre o ponto e o ponto mais próximo na linha ou borda estiver dentro da tolerância especificada. O valor padrão de tolerância é de 10 a 9 graus.

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