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ígonos e polilinhas
    1. containsLocation()
    2. isLocationOnEdge()

Visão geral

Os conceitos neste 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 deve ser explicitamente especificada por meio do 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 fornece funções utilitárias para o cálculo de dados geométricos na superfície da Terra. A biblioteca inclui três namespaces:

  • O spherical contém utilitários de geometria esférica que permitem calcular ângulos, distâncias e áreas de latitudes e longitudes.
  • O encoding contém utilitários para codificação e decodificação de caminhos de polilinha, de acordo com o algoritmo de polilinha codificada.
  • O 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, ela contém métodos estáticos sobre os namespaces acima.

Conceitos de geometria esférica

As imagens na API Maps JavaScript são bidimensionais e "fixas". No entanto, a Terra é tridimensional e frequentemente aproximada como um esferoide achatado ou, simplesmente, uma esfera. Na API Maps, usamos uma esfera. Para representar a Terra em uma superfície achatada e 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 exige alguma distorção, muitas vezes a geometria euclidiana simples não é relevante. 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 formam 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 na projeção dela) precisam usar Spherical Geometry para calcular unidades como distância, orientação e área. Os utilitários usados para calcular essas unidades geométricas esféricas ficam no namespace google.maps.geometry.spherical da API Maps. Esse namespace oferece métodos estáticos para calcular valores escalares 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 computar essa distância, chame computeDistanceBetween(), passando seus dois objetos LatLng.

Em vez disso, também é possível usar 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 de uma região poligonal (em metros quadrados), chame computeArea(), transmitindo a matriz de objetos LatLng que definem um loop fechado.

Na navegação em uma esfera, uma orientação é o ângulo de uma rota em relação a um ponto de referência fixo, normalmente o norte verdadeiro. Com a API Google Maps, uma orientação é definida em graus em relação ao norte verdadeiro, onde as orientações são medidas no sentido horário a partir do norte verdadeiro (0 grau). Você pode computar essa orientação entre dois locais com o método computeHeading(), passando seus dois objetos from e to LatLng.

Com uma posição específica, um local de origem e a distância para viajar (em metros), você pode calcular as coordenadas de destino usando o computeOffset().

Com dois objetos LatLng e um valor entre 0 e 1, você também pode calcular um destino entre eles usando o método interpolate(). Esse método realiza a interpolação linear esférica entre os dois locais, onde o valor indica a distância fracionária para viajar ao longo do caminho desde a 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 liga as duas localidades) e calcula a orientaçã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;
Exemplo

Testar amostra

Métodos de codificação

Os caminhos na API Maps JavaScript geralmente são especificados como um Array de objetos LatLng. No entanto, essa matriz é volumosa demais para ser passada. Em vez disso, use um algoritmo de polilinha codificada do Google para compactar um caminho específico, que poderá 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 passar uma matriz de LatLngs ou MVCArray (que é retornada por Polyline.getPath()).

Para decodificar um caminho, 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 é exibida 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;
Exemplo

Testar amostra

Funções de polígono e polilinha

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

containsLocation()

containsLocation(point:LatLng, polygon:Polygon)

Para saber se um determinado ponto está dentro de um polígono, passe o ponto e o polígono para google.maps.geometry.poly.containsLocation(). A função retorna true quando o ponto está dentro ou na borda do polígono.

O código a seguir escreve "true" no console do navegador quando o clique do usuário é feito dentro do triângulo definido. Caso contrário, vai ser "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 desse código vai desenhar um triângulo azul no mapa se o clique for feito dentro do Triângulo das Bermuda. Caso contrário, o círculo será vermelho:

Exemplo

isLocationOnEdge()

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

Para determinar se um ponto está sobre ou perto de uma polilinha ou de uma borda de polígono, passe o ponto, a polilinha ou o polígono e, opcionalmente um valor de tolerância em graus para google.maps.geometry.poly.isLocationOnEdge() A função retorna true se a distância entre o ponto e o ponto mais próximo na linha ou borda está dentro da tolerância especificada. A tolerância padrão é 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);