Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
58 changes: 44 additions & 14 deletions documentation/docs/03-examples.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,27 +2,27 @@

For each example, associated scripts and resources can be found in the same root directory as the scene itself.

### Playground
## Playground

These examples demonstrate how to request specific Mapbox data using our C# library.

#### Forward Geocoder
### Forward Geocoder

*ForwardGeocoder.unity*

A forward geocoding request will fetch GeoJSON from a place name query. A new request is sent every time the user input field is edited.

Visit [our API documentation](https://www.mapbox.com/api-documentation/#geocoding) for more information.

#### Reverse Geocoder
### Reverse Geocoder

*ReverseGeocoder.unity*

A reverse geocoding request will fetch GeoJSON from a location query. The location query string must be in the format of `latitude, longitude`. A new request is sent every time the user input field is edited.

Visit [our API documentation](https://www.mapbox.com/api-documentation/#geocoding) for more information.

#### Directions
### Directions

*Directions.unity*

Expand All @@ -34,7 +34,7 @@ When the geocode requests have been completed, a directions request is executed.

Directions results will be logged to the UI when they are available (in the form of JSON).

#### Raster Tile
### Raster Tile

*RasterTile.unity*

Expand All @@ -44,7 +44,7 @@ See: https://www.mapbox.com/help/define-style/

See: https://www.mapbox.com/api-documentation/#retrieve-raster-tiles-from-styles

#### Vector Tile
### Vector Tile

*VectorTile.unity*

Expand All @@ -54,7 +54,7 @@ In this example, the result is GeoJSON with a feature collection.

Visit [our API documentation](https://www.mapbox.com/api-documentation/#retrieve-features-from-vector-tiles) for more information.

### Mesh Generation Basics
## Mesh Generation Basics

*MeshGeneration.unity*

Expand All @@ -68,21 +68,21 @@ See `MapImageFactory.asset` to customize the raster `MapId` you would like to us

See `MeshFactory.asset` to see how specific layers are extracted from vector tiles. In this case, we are generating meshes for both `building` and `road`. Therefore, each layer has a `VectorLayerVisualizer` responsible for handling that layer's specific data (such as geometry).

### Mesh Generataion Pois
## Mesh Generataion Pois

*PoiGeneration.unity*

With the exception of a `PoiVisualizer ` (`PoiDemoPoiVisualizer`) being added to the `MeshFactory`, this example is identical to `Mesh Generation Basics`.

`PoiDemoPoiVisualizer.asset` allows you to override which prefab to spawn for each `po_label` contained in the vector tile. This prefab should have a component that implements `ILabelVisualizationHelper` attached to it. This exists to inject feature data into (such as label and `Maki` icon).

### Mesh Generation Styles
## Mesh Generation Styles

*StylingDemoMeshGeneration.unity*

This example demonstrates how to use `TypeFilters` to filter specific features for processing. In this case, we have chosen to exclude `schools` from mesh generation. Additionally, you can use `ModifierStacks` to further customize specific features (to color banks differently, for example).

### Drive
## Drive

*Drive.unity*

Expand All @@ -96,17 +96,17 @@ The ground layer was generated with a `flat` `TerrainFactory` and a `MapImageFac

To understand 3D building generation, please see `Mesh Generation Basics`. One particular difference in this example, however, is the use of a `MergedModifierStack` for `DriveBuildingVisualizer.asset`. This `ModifierStack` is responsible for merging buildings during generation. This optimization reduces the number of transforms and draw calls in the scene, vastly improving the final frame rate.

### Slippy Vector Terrain
## Slippy Vector Terrain

*SlippyDemo.Unity*
*SlippyDemo.unity*

This example demonstrates one way to create a [slippy map](http://wiki.openstreetmap.org/wiki/Slippy_Map). The `Slippy` component attached to the `MapController` game object is responsible for requesting new tiles as needed, based on the position of the camera relative to the map. This is achieved using `raycasting` and a dictionary of known (requested and fetched) tiles.

Use W, A, S, D keyboard controls to navigate the map at runtime.

Please see `Mesh Generation Basics` to understand how features are customized.

### Voxels
## Voxels

*VoxelWorld.unity*

Expand All @@ -124,4 +124,34 @@ This Minecraft-inspired example demonstrates a less traditional way to consume M

`Voxel Batch Count`: How many voxels to spawn at once. Keep this number low to prevent locking the main thread during construction.

Please read [the blog post](https://www.mapbox.com/blog/how-to-minecraft-unity/) describing how this was made for more information.
Please read [the blog post](https://www.mapbox.com/blog/how-to-minecraft-unity/) describing how this was made for more information.

## LocationProvider

*LocationProvider.unity*

This example is to demonstrate how to:

- Build a map for your current (device) location
- Update a virtual player's position and rotation based on a real or mock location and heading
- Use mock location providers to test in the Unity editor
- Convert between unity world space<—>earth space (latitude, longitude)

The `LocationProvider` game object in this scene has three children. Each child corresponds to a specific type of `ILocationProvider`. Please [read more about LocationProviders](https://mapbox.github.io/mapbox-unity-sdk/api/unity/Mapbox.Unity.Location.html).

The `MapController` game object has a `BuildMapAtLocation` component attached to it. This component is responsible for overriding the default center point of the `MapController` component, using the DefaultLocationProvider's location. In the Unity editor, this is the `EditorLocationProvider`—intended for mocking. On device, this is the `DeviceLocationProvider`—intended for real world location updates.

To change the location for the map in the Editor, change `EditorLocationProvider`'s `LatitudeLongitude` field on the `Editor` game object. You can use the embedded `Search` button in the inspector to search for a place or address. The default location for this scene is the Metreon, in San Francisco, CA.

**Note: It is important that the `MapController` component be disabled to begin with.**

Press play and observe the map being constructed. Click on the `Player` game object and note the attached components: `PositionWithLocationProvider` and `RotateWithLocationProvider`. These are responsible for updating the transform's position and rotation based on a specified `ILocationProvider`. Again, in the `EditorLocationProvider`, search for `Yerba Buena Gardens` and select the top result. Watch as the player's position updates!

If you check `Use Transform Location Provider` for `PositionWithLocationProvider` and `RotateWithLocationProvider`, the mock `ILocationProvider` will be represented by the `Transform` game object. Press play once more with this toggle checked for both components. In the scene view, move and rotate the `Transform` game object and observe as the `Player` tries to follow that target. It is important to note that the location returned by the `TransformLocationProvider` is actually converted from the transform's world position to latitude, longitude. This is what that conversion looks like:

```cs
return _targetTransform.GetGeoPosition(MapController.ReferenceTileRect.Center, MapController.WorldScaleFactor);
```

If you build to device, you should see a familiar map and can observe the player update with your own location. Because the camera is a child of `Player`, you should always be centered on the map.

9 changes: 9 additions & 0 deletions sdkproject/Assets/Mapbox/Core/Unity/Location.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

140 changes: 140 additions & 0 deletions sdkproject/Assets/Mapbox/Core/Unity/Location/DeviceLocationProvider.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
namespace Mapbox.Unity.Location
{
using System.Collections;
using UnityEngine;
using System;
using Mapbox.Utils;

/// <summary>
/// The DeviceLocationProvider is responsible for providing real world location and heading data,
/// served directly from native hardware and OS.
/// This relies on Unity's <see href="https://docs.unity3d.com/ScriptReference/LocationService.html">LocationService</see> for location
/// and <see href="https://docs.unity3d.com/ScriptReference/Compass.html">Compass</see> for heading.
/// </summary>
public class DeviceLocationProvider : MonoBehaviour, ILocationProvider
{
/// <summary>
/// Using higher value like 500 usually does not require to turn GPS chip on and thus saves battery power.
/// Values like 5-10 could be used for getting best accuracy.
/// </summary>
[SerializeField]
float _desiredAccuracyInMeters = 5f;

/// <summary>
/// The minimum distance (measured in meters) a device must move laterally before Input.location property is updated.
/// Higher values like 500 imply less overhead.
/// </summary>
[SerializeField]
float _updateDistanceInMeters = 5f;

Coroutine _pollRoutine;

double _lastLocationTimestamp;

double _lastHeadingTimestamp;

WaitForSeconds _wait;

Vector2d _location;
/// <summary>
/// Gets the current cached location.
/// </summary>
/// <value>The location.</value>
public Vector2d Location
{
get
{
return _location;
}
}

/// <summary>
/// Occurs when on location updates.
/// </summary>
public event EventHandler<LocationUpdatedEventArgs> OnLocationUpdated;

/// <summary>
/// Occurs when the compass updates.
/// </summary>
public event EventHandler<HeadingUpdatedEventArgs> OnHeadingUpdated;

void Start()
{
_wait = new WaitForSeconds(1f);
if (_pollRoutine == null)
{
_pollRoutine = StartCoroutine(PollLocationRoutine());
}
}

/// <summary>
/// Enable location and compass services.
/// Sends continuous location and heading updates based on
/// _desiredAccuracyInMeters and _updateDistanceInMeters.
/// </summary>
/// <returns>The location routine.</returns>
IEnumerator PollLocationRoutine()
{
if (!Input.location.isEnabledByUser)
{
yield break;
}

Input.location.Start(_desiredAccuracyInMeters, _updateDistanceInMeters);
Input.compass.enabled = true;

int maxWait = 20;
while (Input.location.status == LocationServiceStatus.Initializing && maxWait > 0)
{
yield return _wait;
maxWait--;
}

if (maxWait < 1)
{
yield break;
}

if (Input.location.status == LocationServiceStatus.Failed)
{
yield break;
}

while (true)
{
var timestamp = Input.compass.timestamp;
if (Input.compass.enabled && timestamp > _lastHeadingTimestamp)
{
var heading = Input.compass.trueHeading;
SendHeadingUpdated(heading);
_lastHeadingTimestamp = timestamp;
}

timestamp = Input.location.lastData.timestamp;
if (Input.location.status == LocationServiceStatus.Running && timestamp > _lastLocationTimestamp)
{
_location = new Vector2d(Input.location.lastData.latitude, Input.location.lastData.longitude);
SendLocationUpdated(_location);
_lastLocationTimestamp = timestamp;
}
yield return null;
}
}

void SendHeadingUpdated(float heading)
{
if (OnHeadingUpdated != null)
{
OnHeadingUpdated(this, new HeadingUpdatedEventArgs() { Heading = heading });
}
}

void SendLocationUpdated(Vector2d location)
{
if (OnLocationUpdated != null)
{
OnLocationUpdated(this, new LocationUpdatedEventArgs() { Location = location });
}
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
namespace Mapbox.Unity.Location
{
using System;
using Mapbox.Unity.Utilities;
using Mapbox.Utils;
using UnityEngine;

/// <summary>
/// The EditorLocationProvider is responsible for providing mock location and heading data
/// for testing purposes in the Unity editor.
/// </summary>
public class EditorLocationProvider : MonoBehaviour, ILocationProvider
{
/// <summary>
/// The mock "latitude, longitude" location, respresented with a string.
/// You can search for a place using the embedded "Search" button in the inspector.
/// This value can be changed at runtime in the inspector.
/// </summary>
[SerializeField]
[Geocode]
string _latitudeLongitude;

/// <summary>
/// The mock heading value.
/// </summary>
[SerializeField]
[Range(0, 359)]
float _heading;

/// <summary>
/// Gets the current location, as specified in the inspector.
/// </summary>
/// <value>The location.</value>
public Vector2d Location
{
get
{
var split = _latitudeLongitude.Split(',');
return new Vector2d(double.Parse(split[0]), double.Parse(split[1]));
}
}

/// <summary>
/// Occurs every frame.
/// </summary>
public event EventHandler<HeadingUpdatedEventArgs> OnHeadingUpdated;

/// <summary>
/// Occurs every frame.
/// </summary>
public event EventHandler<LocationUpdatedEventArgs> OnLocationUpdated;

#if UNITY_EDITOR
void Update()
{
SendHeadingUpdated();
SendLocationUpdated();
}
#endif

void SendHeadingUpdated()
{
if (OnHeadingUpdated != null)
{
OnHeadingUpdated(this, new HeadingUpdatedEventArgs() { Heading = _heading });
}
}

void SendLocationUpdated()
{
if (OnLocationUpdated != null)
{
OnLocationUpdated(this, new LocationUpdatedEventArgs() { Location = Location });
}
}
}
}

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading