1. [Overview](https://developers.google.com/maps/documentation/javascript/geometry.md.txt#Geometry)
2. [Spherical Geometry Concepts](https://developers.google.com/maps/documentation/javascript/geometry.md.txt#SphericalGeometry)
   1. [Distance and Area Functions](https://developers.google.com/maps/documentation/javascript/geometry.md.txt#Distance)
   2. [Navigation Functions](https://developers.google.com/maps/documentation/javascript/geometry.md.txt#Navigation)
3. [Geometry Encoding](https://developers.google.com/maps/documentation/javascript/geometry.md.txt#Encoding)
4. [Polygon and Polyline Functions](https://developers.google.com/maps/documentation/javascript/geometry.md.txt#poly)
   1. [containsLocation()](https://developers.google.com/maps/documentation/javascript/geometry.md.txt#containsLocation)
   2. [isLocationOnEdge()](https://developers.google.com/maps/documentation/javascript/geometry.md.txt#isLocationOnEdge)
   3. [Geofence and safe-zone radius checks](https://developers.google.com/maps/documentation/javascript/geometry.md.txt#geofencing)

## Overview

The concepts within this document refer to features only
available within the `google.maps.geometry` library. This
library is not loaded by default when you load the Maps Javascript API
but must be explicitly specified through use of a `libraries`
bootstrap parameter. For more information, see the
[Libraries Overview](https://developers.google.com/maps/documentation/javascript/libraries.md.txt).

The Maps JavaScript API geometry library provides utility
functions for the computation of geometric data on the surface of the
Earth. The library includes three namespaces:

- `spherical` contains spherical geometry utilities allowing you to compute angles, distances and areas from latitudes and longitudes.
- `encoding` contains utilities for encoding and decoding polyline paths according to the [Encoded
  Polyline Algorithm](https://developers.google.com/maps/documentation/utilities/polylinealgorithm).
- `poly` contains utility functions for computations involving polygons and polylines.

The `google.maps.geometry` library does not contain any
classes; instead, the library contains static methods on the above
namespaces.

## Spherical Geometry Concepts

The images within the Maps JavaScript API are two-dimensional
and "flat." The Earth, however, is three-dimensional, and is often
approximated as either an
[oblate spheroid](https://en.wikipedia.org/wiki/Oblate_spheroid)
or more as a sphere. Within the Maps API we use a sphere, and to
represent the Earth on a two-dimensional flat surface --- such as
your computer screen --- the Maps API uses a
[projection](https://developers.google.com/maps/documentation/javascript/maptypes.md.txt#Projections).

Within 2D projections, appearances can sometimes be deceiving.
Because the map projection necessarily requires some distortion, simple
Euclidian geometry often is not applicable. For example, the shortest distance
between two points on a sphere is not a straight line, but a great circle
(a type of geodesic), and the angles that make up a triangle on the surface
of a sphere add up to more than 180 degrees.

Because of these differences, geometric functions on a sphere (or on its
projection) necessitate using
[Spherical Geometry](https://en.wikipedia.org/wiki/Spherical_geometry)
to calculate such constructs as distance, heading, and area. Utilities to
calculate these spherical geometric constructs are contained within the Maps
API's `google.maps.geometry.spherical` namespace. This namespace
provides static methods for computing scalar values from spherical coordinates
(latitudes and longitudes).

### Distance and Area Functions

The distance between two points is the length of the shortest path between
them. This shortest path is called a geodesic. On a sphere all geodesics are
segments of a great circle. To compute this distance, call
[`computeDistanceBetween()`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt#spherical.computeDistanceBetween), passing it two `LatLng`
objects.

You may instead use [`computeLength()`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt#spherical.computeLength) to calculate the length
of a given path if you have several locations.

Distance results are expressed in meters.

To compute the area (in square meters) of a polygonal area, call
[`computeArea()`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt#spherical.computeArea), passing the array of `LatLng` objects
defining a closed loop.

### Navigation Functions

When navigating on a sphere, a heading is the angle of a direction
from a fixed reference point, usually true north. Within the Google Maps API,
a heading is defined in degrees from true north, where headings are measured
clockwise from true north (0 degrees). You may compute this heading between
two locations with the
[`computeHeading()`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt#spherical.computeHeading) method, passing it two
`from` and `to` `LatLng` objects.

Given a particular heading, an origin location, and the distance to
travel (in meters), you can calculate the destination coordinates using
[`computeOffset()`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt#spherical.computeOffset).

Given two `LatLng` objects and value between 0 and 1, you may
also calculate a destination between them using the
[`interpolate()`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt#spherical.interpolate) method, which performs spherical linear
interpolation between the two locations, where the value indicates
the fractional distance to travel along the path from the origin to
the destination.

The following example creates two polylines when you click two points
on the map --- one geodesic and one "straight" line connecting the two
locations --- and computes the heading for travelling between the
two points:

### TypeScript

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

> [!NOTE]
> **Note:** Read the [guide](https://developers.google.com/maps/documentation/javascript/using-typescript.md.txt) on using TypeScript and Google Maps.

### JavaScript

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

> [!NOTE]
> **Note:** The JavaScript is compiled from the TypeScript snippet.

[View example](https://developers.google.com/maps/documentation/javascript/examples/geometry-headings.md.txt)

## Encoding Methods

Paths within the Maps JavaScript API are often specified as an
`Array` of `LatLng` objects. However, passing around
such an array is often bulky. You may instead use Google's
[polyline
encoding algorithm](https://developers.google.com/maps/documentation/utilities/polylinealgorithm) to compress a given path, which you can later
decompress through decoding.

The [`geometry`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt)
library contains an [`encoding`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt#encoding)
namespace for utilities to encode and decode polylines.

The static method [`encodePath()`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt#encoding.encodePath) encodes the given path.
You may pass either an array of `LatLng`s or an
`MVCArray` (which is returned by
`Polyline.getPath()`).

To decode an encoded path, call [`decodePath()`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt#encoding.decodePath)
passing the method the encoded string.

The following example displays a map of Oxford, Mississippi.
Clicking on the map adds a point to a polyline. As the polyline is
constructed, its encoding appears underneath.

### TypeScript

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

> [!NOTE]
> **Note:** Read the [guide](https://developers.google.com/maps/documentation/javascript/using-typescript.md.txt) on using TypeScript and Google Maps.

### JavaScript

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

> [!NOTE]
> **Note:** The JavaScript is compiled from the TypeScript snippet.

[View example](https://developers.google.com/maps/documentation/javascript/examples/geometry-encodings.md.txt)

## Polygon and Polyline functions

The geometry library's [`poly`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt#poly) namespace contains utility functions
that determine whether a given point is inside a polygon or circle, or near a
polygon or polyline.

### containsLocation()

```
containsLocation(point:LatLng|LatLngLiteral, polygon:Polygon|Circle|CircleLiteral)
```

To find whether a given point falls within a polygon or circle, pass the
point and the
[`google.maps.Polygon`](https://developers.google.com/maps/documentation/javascript/reference/polygon.md.txt#Polygon),
[`google.maps.Circle`](https://developers.google.com/maps/documentation/javascript/reference/polygon.md.txt#Circle),
or
[`google.maps.CircleLiteral`](https://developers.google.com/maps/documentation/javascript/reference/coordinates.md.txt#CircleLiteral)
to
[`google.maps.geometry.poly.containsLocation()`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt#poly.containsLocation).
The function returns `true` if the point is within the shape or on
its edge.

The following code writes 'true' to the browser console if the user's click
falls within the defined triangle; otherwise, it writes 'false'.

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

Another version of this code draws a blue triangle on the map if the click
falls within the Bermuda Triangle, and a red circle otherwise:
<iframe src="https://geo-devrel-javascript-samples.web.app/samples/poly-containsLocation/app/dist/" allow="fullscreen; "></iframe>

[View example](https://developers.google.com/maps/documentation/javascript/examples/poly-containsLocation.md.txt)

### isLocationOnEdge()

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

To determine whether a point falls on or near a polyline, or on or near the
edge of a polygon, pass the point, the polyline/polygon, and optionally a
tolerance value in degrees to
[`google.maps.geometry.poly.isLocationOnEdge()`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt#poly.isLocationOnEdge). The function
returns true if the distance between the point and the closest point on the
line or edge falls within the specified tolerance. The default tolerance
value is 10^-9^ degrees.

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

### Geofence and safe-zone radius checks

To check whether a live coordinate (such as a vehicle, asset, or user
location) is inside a geofence or safe-zone perimeter on a map, combine
[map shapes](https://developers.google.com/maps/documentation/javascript/shapes.md.txt#geofences) with
the
[`geometry`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt) library:

- **Circular geofence (radius check):** Draw the perimeter with [`google.maps.Circle`](https://developers.google.com/maps/documentation/javascript/reference/polygon.md.txt#Circle) (or define a [`google.maps.CircleLiteral`](https://developers.google.com/maps/documentation/javascript/reference/coordinates.md.txt#CircleLiteral)) and pass the target coordinate and circle to [`google.maps.geometry.poly.containsLocation()`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt#poly.containsLocation). If you also need the distance in meters from [`Circle.getCenter()`](https://developers.google.com/maps/documentation/javascript/reference/polygon.md.txt#Circle.getCenter), pass the target coordinate and center to [`google.maps.geometry.spherical.computeDistanceBetween()`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt#spherical.computeDistanceBetween).
- **Polygonal geofence:** Draw the perimeter with [`google.maps.Polygon`](https://developers.google.com/maps/documentation/javascript/reference/polygon.md.txt#Polygon) and pass the target coordinate and polygon to [`google.maps.geometry.poly.containsLocation()`](https://developers.google.com/maps/documentation/javascript/reference/geometry.md.txt#poly.containsLocation).