Geospatial anchors are a type of [anchor](https://developers.google.com/ar/develop/anchors) that allow you to place 3D content in the real world.

## Types of Geospatial anchors

There are three types of Geospatial anchors, which each handle altitude differently:

1. [WGS84 anchors](https://developers.google.com/ar/develop/c/geospatial/anchors#wgs84_anchors):   

   WGS84 anchors let you place 3D content at any given latitude,
   longitude, and altitude.

2. [Terrain anchors](https://developers.google.com/ar/develop/c/geospatial/anchors#terrain_anchors):   

   Terrain anchors let you place content using only latitude and
   longitude with a height relative to the terrain at that position.
   The altitude is determined relative to the ground or floor as known
   by [VPS](https://developers.google.com/ar/develop/geospatial#global_localization_with_vps).

3. [Rooftop anchors](https://developers.google.com/ar/develop/c/geospatial/anchors#rooftop_anchors):   

   Rooftop anchors let you place content using only latitude and
   longitude with a height relative to a building's rooftop at that position.
   The altitude is determined relative to the top of a building as known
   by [Streetscape Geometry](https://developers.google.com/ar/develop/c/geospatial/streetscape-geometry).
   This will default to terrain altitude when not placed on a building.

|   | WGS84 | Terrain | Rooftop |
|---|---|---|---|
| Horizontal Position | Latitude, Longitude | Latitude, Longitude | Latitude, Longitude |
| Vertical Position | Relative to WGS84 altitude | Relative to terrain level determined by Google Maps | Relative to rooftop level determined by Google Maps |
| Needs to be server-resolved? | No | Yes | Yes |

## Prerequisites

Make sure that you [enable the Geospatial API](https://developers.google.com/ar/develop/c/geospatial/enable) before proceeding.

## Place Geospatial anchors

Each anchor type has dedicated APIs to create them; see [Types of Geospatial anchors](https://developers.google.com/ar/develop/c/geospatial/anchors#types) for more information.

### Create an anchor from a hit-test

You can also create a Geospatial anchor from a [hit-test result](https://developers.google.com/ar/develop/hit-test).
Use the Pose from the hit-test and convert it to a [`ArGeospatialPose`](https://developers.google.com/ar/reference/c/group/ar-geospatial-pose). Use it to place any of the 3 anchor types described.

#### Get a Geospatial Pose from an AR Pose

[`ArEarth_getGeospatialPose()`](https://developers.google.com/ar/reference/c/group/ar-earth#arearth_getgeospatialpose) provides an additional way to determine the latitude and longitude by converting an AR Pose to a Geospatial Pose.

#### Get an AR Pose from a Geospatial Pose

[`ArEarth_getPose()`](https://developers.google.com/ar/reference/c/group/ar-earth#arearth_getpose) converts an Earth-specified horizontal position, altitude, and quaternion rotation with respect to an east-up-south coordinate frame to an AR Pose with respect to the GL world coordinate.

### Choose which method suits your use case

Each method of creating an anchor has associated tradeoffs to keep in mind:

- When using [Streetscape Geometry](https://developers.google.com/ar/develop/c/streetscape-geometry), use a hit-test to attach content to a building.
- Prefer Terrain or Rooftop anchors over WGS84 anchors because they use altitude values determined by Google Maps.

## Determine the latitude and longitude of a location

There are three ways you can calculate a location's latitude and longitude:

- Use [Geospatial Creator](https://developers.google.com/ar/geospatial-creator) to view and augment the world with 3D content without having to physically go to a location. This allows you to place 3D immersive content visually using Google maps in the Unity Editor. The content's latitude, longitude, rotation and altitude will be automatically calculated for you.
- Use Google Maps
- Use Google Earth. Note that obtaining these coordinates using Google Earth, as opposed to Google Maps, will give you an error margin of up to several meters.
- Go to the physical location

### Use Google Maps

To get the latitude and longitude of a location using Google Maps:

1. Go to [Google Maps](https://www.google.com/maps) on your desktop computer.

   ![](https://developers.google.com/static/ar/develop/geospatial/images/google-earth-turn-off-3d-buildings-2.png)
2. Navigate to **Layers** \> **More**.

   ![](https://developers.google.com/static/ar/develop/geospatial/images/google-maps-layers.png)

   ![](https://developers.google.com/static/ar/develop/geospatial/images/google-maps-more.png)
3. Change the **Map Type** to **Satellite** and clear the **Globe View** checkbox at the bottom left corner of the screen.

   ![](https://developers.google.com/static/ar/develop/geospatial/images/google-maps-map-type-satellite-globe-view.png)

   This will force a 2D perspective and eliminate possible errors that could come from an angled 3D view.
4. On the map, right-click on the location and select the longitude/latitude to copy it to your clipboard.

### Use Google Earth

You can calculate a location's latitude and longitude from Google Earth by clicking a location in the UI and reading the data from placemark details.

> [!NOTE]
> **Note:** Obtaining these coordinates using Google Earth, as opposed to using Google Maps, will give you an error margin of up to several meters. We recommend using Google Maps and the Elevation API to get the latitude and longitude of a location.

To get the latitude and longitude of a location using Google Earth:

1. Go to [Google Earth](https://earth.google.com/) on your desktop computer.

2. Navigate to the hamburger menu ![](https://developers.google.com/static/ar/develop/geospatial/images/hamburger-menu.png) and select **Map Style**.

   ![](https://developers.google.com/static/ar/develop/geospatial/images/google-earth-turn-off-3d-buildings-2.png)
3. Toggle off the **3D Buildings** switch.

   ![](https://developers.google.com/static/ar/develop/geospatial/images/google-earth-turn-off-3d-buildings-3.png)
4. Once the **3D Buildings** switch has been toggled off, click the pin icon ![](https://developers.google.com/static/ar/develop/geospatial/images/pin-icon.png) to add a placemark at the selected location.

5. Specify a project to contain your placemark and click **Save**.

6. In the **Title** field for the placemark, enter a name for the placemark.

7. Click the back arrow ![](https://developers.google.com/static/ar/develop/geospatial/images/back-button.png) in the project pane and select the ![](https://developers.google.com/static/ar/develop/geospatial/images/more-actions-menu.png) **More Actions** menu.

8. Choose **Export as KML file** from the menu.

   <br />

   ![](https://developers.google.com/static/ar/develop/geospatial/images/google-earth-place-point-6.png)

   <br />

The KLM file reports the latitude, longitude, and altitude for a placemark in the `<coordinates>` tag separated by commas, as follows:

    <coordinates>-122.0755182435043,37.41347299422944,7.420342565583832</coordinates>

Do **not** use the latitude and longitude from the `<LookAt>` tags, which specify the camera position, not the location.

### Go to the physical location

You can calculate a location's altitude by going there physically and doing a local observation.

## Get the rotation quaternion

[`ArGeospatialPose_getEastUpSouthQuaternion()`](https://developers.google.com/ar/reference/c/group/ar-geospatial-pose#argeospatialpose_geteastupsouthquaternion) extracts the orientation from a Geospatial Pose and outputs a quaternion that represents the rotation matrix transforming a vector from the target to the east-up-south (EUS) coordinate system. X+ points east, Y+ points up, and Z+ points south. Values are written in the order `{x, y, z, w}`.

## WGS84 Anchors

A WGS84 Anchor is a type of [anchor](https://developers.google.com/ar/develop/anchors) that allows you to place 3D content at any given latitude, longitude, and altitude. It relies on a Pose, and orientation, to be placed in the real world. The position consists of a latitude, longitude, and altitude, which are specified in the [WGS84 coordinate system](https://en.wikipedia.org/wiki/World_Geodetic_System). The orientation consists of a quaternion rotation.

Altitude is reported in meters above the reference WGS84 ellipsoid such that ground level is **not** at zero. Your app is responsible for providing these coordinates for each created anchor.

### Place a WGS84 anchor in the real world

#### Determine the altitude of a location

There are a few ways to determine a location's altitude for placing anchors:

- If the anchor's location is physically near the user, you can use an altitude that's similar to the altitude of the user's device.
- Once you have the latitude and longitude, use the [Elevation API](https://developers.google.com/maps/documentation/elevation/overview) to get an elevation based on the [EGM96](https://en.wikipedia.org/wiki/Earth_Gravitational_Model) specification. You must convert the Maps API EGM96 elevation to WGS84 for comparison against the [`ArGeospatialPose`](https://developers.google.com/ar/reference/c/group/ar-geospatial-pose) altitude. See the [GeoidEval](https://geographiclib.sourceforge.io/cgi-bin/GeoidEval) that has both a command line and an HTML interface. The Maps API reports latitude and longitude according to the WGS84 specification out of the box.
- You can obtain a location's latitude, longitude, and altitude [from Google Earth](https://developers.google.com/ar/develop/c/geospatial/anchors#use-google-earth). **This will give you an error margin of up to several meters.** Use the latitude, longitude, and altitude from the `<coordinates>` tags, **not** the `<LookAt>` tags, in the KML file.
- If an existing anchor is close by **and** if you are not on a steep incline, you may be able to use the altitude from the camera's [`ArGeospatialPose`](https://developers.google.com/ar/reference/c/group/ar-geospatial-pose) without using another source, such as the Maps API.

#### Create the anchor

Once you have the latitude, longitude, altitude, and rotation quaternion, use [`ArEarth_acquireNewAnchor()`](https://developers.google.com/ar/reference/c/group/ar-earth#arearth_acquirenewanchor)
to anchor content to geographical coordinates that you specify.

```c
float eus_quaternion_4[4] = {qx, qy, qz, qw};
if (ar_earth != NULL) {
  ArTrackingState earth_tracking_state = AR_TRACKING_STATE_STOPPED;
  ArTrackable_getTrackingState(ar_session, (ArTrackable*)ar_earth,
                               &earth_tracking_state);
  if (earth_tracking_state == AR_TRACKING_STATE_TRACKING) {
    ArAnchor* earth_anchor = NULL;
    ArStatus status = ArEarth_acquireNewAnchor(ar_session, ar_earth,
        /* location values */
        latitude, longitude, altitude,
        eus_quaternion_4, &earth_anchor);

    // Attach content to the anchor specified by geodetic location and
    // pose.
  }
}
```

> [!NOTE]
> **Note:** Creating anchors within 0.1 degrees of the North Pole or South Pole (90 degrees or -90 degrees) is not supported. If such an anchor is specified, the anchor will fail to be created.

## Terrain Anchors

A Terrain anchor is a type of [anchor](https://developers.google.com/ar/develop/anchors) that allows you to place AR objects using only latitude and longitude, leveraging information from [VPS](https://developers.google.com/ar/develop/geospatial#global_localization_with_vps) to find the precise altitude above ground.

Rather than inputting the desired altitude, you provide the altitude above the terrain. When this is zero the anchor will be level with the terrain.

### Set the plane-finding mode

Plane finding is optional and not required to utilize anchors. Note that only horizontal planes are used. Horizontal planes will help the dynamic alignment of terrain anchors on ground.

Use [`ArPlaneFindingMode`](https://developers.google.com/ar/reference/c/group/ar-config#arplanefindingmode) to select how your app detects planes.

### Create a Terrain anchor using the new Async API

To create and place a Terrain anchor, call [`ArEarth_resolveAnchorOnTerrainAsync()`](https://developers.google.com/ar/reference/c/group/ar-earth#arearth_resolveanchoronrooftopasync).

The anchor will not be ready right away and needs to resolve. Once it has resolved it will be available in the [`ArResolveAnchorOnTerrainFuture`](https://developers.google.com/ar/reference/c/group/ar-resolve-anchor-on-terrain-future#arresolveanchoronterrainfuture).

Check the terrain anchor state using [`ArResolveAnchorOnTerrainFuture_getResultTerrainAnchorState()`](https://developers.google.com/ar/reference/c/group/ar-resolve-anchor-on-terrain-future#arresolveanchoronterrainfuture_getresultterrainanchorstate).
Get the resolved anchor using [`ArResolveAnchorOnTerrainFuture_acquireResultAnchor()`](https://developers.google.com/ar/reference/c/group/ar-resolve-anchor-on-terrain-future#arresolveanchoronterrainfuture_acquireresultanchor).

```c
float eus_quaternion_4[4] = {qx, qy, qz, qw};
void* context = NULL;
ArResolveAnchorOnTerrainCallback callback = NULL;
ArResolveAnchorOnTerrainFuture* future = NULL;
if (ar_earth != NULL) {
  ArTrackingState earth_tracking_state = AR_TRACKING_STATE_STOPPED;
  ArTrackable_getTrackingState(ar_session, (ArTrackable*)ar_earth,
                               &earth_tracking_state);
  if (earth_tracking_state == AR_TRACKING_STATE_TRACKING) {
    ArStatus status = ArEarth_resolveAnchorOnTerrainAsync(
        ar_session, ar_earth,
        /* location values */
        latitude, longitude, altitude_above_terrain, eus_quaternion_4,
        context, callback, &future);
  }
}
```

> [!NOTE]
> **Note:** Creating anchors within 0.1 degrees of the North or South Poles (90 degrees or -90 degrees) is not supported. If such an anchor is specified, `ArEarth_resolveAnchorOnTerrainAsync()` will return an `AR_ERROR_INVALID_ARGUMENT` and the anchor will fail to be created.

### Check the State of the Future

The Future will have an associated [`ArFutureState`](https://developers.google.com/ar/reference/c/group/ar-future#arfuturestate).

| State | Description |
|---|---|
| [`AR_FUTURE_STATE_PENDING`](https://developers.google.com/ar/reference/c/group/ar-future#arfuturestate) | The operation is still pending. |
| [`AR_FUTURE_STATE_DONE`](https://developers.google.com/ar/reference/c/group/ar-future#arfuturestate) | The operation is complete and the result is available. |
| [`AR_FUTURE_STATE_CANCELLED`](https://developers.google.com/ar/reference/c/group/ar-future#arfuturestate) | The operation has been cancelled. |

### Check the Terrain anchor state of the Future result

The [`ArTerrainAnchorState`](https://developers.google.com/ar/reference/c/group/ar-anchor#arterrainanchorstate) belongs to the asynchronous operation and is part of the final Future result.

```c
switch (terrain_anchor_state) {
  case AR_TERRAIN_ANCHOR_STATE_SUCCESS:
    // A resolving task for this anchor has been successfully resolved.
    break;
  case AR_TERRAIN_ANCHOR_STATE_ERROR_UNSUPPORTED_LOCATION:
    // The requested anchor is in a location that isn't supported by the
    // Geospatial API.
    break;
  case AR_TERRAIN_ANCHOR_STATE_ERROR_NOT_AUTHORIZED:
    // An error occurred while authorizing your app with the ARCore API. See
    // https://developers.google.com/ar/reference/c/group/ar-anchor#:~:text=from%20this%20error.-,AR_TERRAIN_ANCHOR_STATE_ERROR_NOT_AUTHORIZED,-The%20authorization%20provided
    // for troubleshooting steps.
    break;
  case AR_TERRAIN_ANCHOR_STATE_ERROR_INTERNAL:
    // The Terrain anchor could not be resolved due to an internal error.
    break;
  default:
    break;
}
```

## Rooftop Anchors

![Rooftop anchors Hero](https://developers.google.com/static/ar/develop/geospatial/images/hero-rooftop-anchors.jpg)

Rooftop anchors are a type of [anchor](https://developers.google.com/ar/develop/anchors) and are very similar to [Terrain anchors](https://developers.google.com/ar/develop/c/geospatial/anchors#terrain_anchors) above. The difference is that you will provide the altitude above the rooftop rather than the altitude above the terrain.

> [!NOTE]
> **Note:** Some locations have more accurate rooftop information than others. Check out the Quality section in [Streetscape Geometry](https://developers.google.com/ar/develop/c/geospatial/streetscape-geometry) for more information.

### Create a Rooftop anchor using the new Async API

The anchor will not be ready right away and needs to resolve.

To create and place a Rooftop anchor, call [`ArEarth_resolveAnchorOnRooftopAsync()`](https://developers.google.com/ar/reference/c/group/ar-earth#arearth_resolveanchoronrooftopasync). Similarly to Terrain anchors, you will also access the [`ArFutureState`](https://developers.google.com/ar/reference/c/group/ar-future#arfuturestate) of the Future. Then you can check the Future result to access the [`ArRooftopAnchorState`](https://developers.google.com/ar/reference/c/group/ar-anchor#arrooftopanchorstate).

Use [`ArEarth_resolveAnchorOnRooftopAsync()`](https://developers.google.com/ar/reference/c/group/ar-earth#arearth_resolveanchoronrooftopasync) to create a [`ArResolveAnchorOnRooftopFuture`](https://developers.google.com/ar/reference/c/group/ar-resolve-anchor-on-rooftop-future).

Check the rooftop anchor state using [`ArResolveAnchorOnRooftopFuture_getResultRooftopAnchorState()`](https://developers.google.com/ar/reference/c/group/ar-resolve-anchor-on-rooftop-future#arresolveanchoronrooftopfuture_getresultrooftopanchorstate).

Get the resolved anchor using [`ArResolveAnchorOnRooftopFuture_acquireResultAnchor()`](https://developers.google.com/ar/reference/c/group/ar-resolve-anchor-on-rooftop-future#arresolveanchoronrooftopfuture_acquireresultanchor).

```c
float eus_quaternion_4[4] = {qx, qy, qz, qw};
void* context = NULL;
ArResolveAnchorOnRooftopCallback callback = NULL;
ArResolveAnchorOnRooftopFuture* future = NULL;
if (ar_earth != NULL) {
  ArTrackingState earth_tracking_state = AR_TRACKING_STATE_STOPPED;
  ArTrackable_getTrackingState(ar_session, (ArTrackable*)ar_earth,
                               &earth_tracking_state);
  if (earth_tracking_state == AR_TRACKING_STATE_TRACKING) {
    ArStatus status = ArEarth_resolveAnchorOnRooftopAsync(
        ar_session, ar_earth,
        /* location values */
        latitude, longitude, altitude_above_rooftop, eus_quaternion_4,
        context, callback, &future);
  }
}
```

### Check the State of the Future

The Future will have an associated [`ArFutureState`](https://developers.google.com/ar/reference/c/group/ar-future#arfuturestate), see the [table](https://developers.google.com/ar/develop/c/geospatial/anchors#check_the_state_of_the) above.

### Check the Rooftop anchor state of the Future result

The [`ArRooftopAnchorState`](https://developers.google.com/ar/reference/c/group/ar-anchor#arrooftopanchorstate) belongs to the asynchronous operation and is part of the final Future result.

```c
switch (rooftop_anchor_state) {
  case AR_ROOFTOP_ANCHOR_STATE_SUCCESS:
    // A resolving task for this anchor has been successfully resolved.
    break;
  case AR_ROOFTOP_ANCHOR_STATE_ERROR_UNSUPPORTED_LOCATION:
    // The requested anchor is in a location that isn't supported by the
    // Geospatial API.
    break;
  case AR_ROOFTOP_ANCHOR_STATE_ERROR_NOT_AUTHORIZED:
    // An error occurred while authorizing your app with the ARCore API. See
    // https://developers.google.com/ar/reference/c/group/ar-anchor#:~:text=from%20this%20error.-,AR_ROOFTOP_ANCHOR_STATE_ERROR_NOT_AUTHORIZED,-The%20authorization%20provided
    // for troubleshooting steps.
    break;
  case AR_ROOFTOP_ANCHOR_STATE_ERROR_INTERNAL:
    // The Rooftop anchor could not be resolved due to an internal error.
    break;
  default:
    break;
}
```

## What's next

- Make sure you understand the Geospatial [API usage quota](https://developers.google.com/ar/develop/c/geospatial/api-usage-quota).