This commit is contained in:
runette committed 2024-04-22 15:52:51 +01:00
commit e0afef912e
1285 files changed
+83219

No files matched your search

File diff suppressed because it is too large. Load diff
+13
View File
@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: cd961b1c9541a4cee99686069ecce852
timeCreated: 1520299462
licenseType: Pro
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+433
View File
@@ -0,0 +1,433 @@
using Mapbox.Unity.Map.Interfaces;
namespace Mapbox.Unity.Map
{
using System.Linq;
using System.Collections.Generic;
using UnityEngine;
using Mapbox.Map;
using Mapbox.Unity.MeshGeneration.Factories;
using Mapbox.Unity.MeshGeneration.Data;
using System;
using Mapbox.Platform;
using UnityEngine.Serialization;
using Mapbox.Unity.Utilities;
using Mapbox.Unity.MeshGeneration.Enums;
using Mapbox.Unity.MeshGeneration.Interfaces;
/// <summary>
/// Map Visualizer
/// Represents a map.Doesn’t contain much logic and at the moment, it creates requested tiles and relays them to the factories
/// under itself.It has a caching mechanism to reuse tiles and does the tile positioning in unity world.
/// Later we’ll most likely keep track of map features here as well to allow devs to query for features easier
/// (i.e.query all buildings x meters around any restaurant etc).
/// </summary>
public abstract class AbstractMapVisualizer : ScriptableObject
{
[SerializeField]
[NodeEditorElementAttribute("Factories")]
[FormerlySerializedAs("_factories")]
public List<AbstractTileFactory> Factories;
protected IMapReadable _map;
protected Dictionary<UnwrappedTileId, UnityTile> _activeTiles = new Dictionary<UnwrappedTileId, UnityTile>();
protected Queue<UnityTile> _inactiveTiles = new Queue<UnityTile>();
private int _counter;
private ModuleState _state;
public ModuleState State
{
get
{
return _state;
}
internal set
{
if (_state != value)
{
_state = value;
OnMapVisualizerStateChanged(_state);
}
}
}
public IMapReadable Map { get { return _map; } }
public Dictionary<UnwrappedTileId, UnityTile> ActiveTiles { get { return _activeTiles; } }
public Dictionary<UnwrappedTileId, int> _tileProgress;
public event Action<ModuleState> OnMapVisualizerStateChanged = delegate { };
public event Action<UnityTile> OnTileFinished = delegate { };
/// <summary>
/// Gets the unity tile from unwrapped tile identifier.
/// </summary>
/// <returns>The unity tile from unwrapped tile identifier.</returns>
/// <param name="tileId">Tile identifier.</param>
public UnityTile GetUnityTileFromUnwrappedTileId(UnwrappedTileId tileId)
{
return _activeTiles[tileId];
}
/// <summary>
/// Initializes the factories by passing the file source down, which is necessary for data (web/file) calls
/// </summary>
/// <param name="fileSource"></param>
public virtual void Initialize(IMapReadable map, IFileSource fileSource)
{
_map = map;
_tileProgress = new Dictionary<UnwrappedTileId, int>();
// Allow for map re-use by recycling any active tiles.
var activeTiles = _activeTiles.Keys.ToList();
foreach (var tile in activeTiles)
{
DisposeTile(tile);
}
State = ModuleState.Initialized;
foreach (var factory in Factories)
{
if (null == factory)
{
Debug.LogError("AbstractMapVisualizer: Factory is NULL");
}
else
{
factory.Initialize(fileSource);
UnregisterEvents(factory);
RegisterEvents(factory);
}
}
}
private void RegisterEvents(AbstractTileFactory factory)
{
factory.OnTileError += Factory_OnTileError;
}
private void UnregisterEvents(AbstractTileFactory factory)
{
factory.OnTileError -= Factory_OnTileError;
}
public virtual void Destroy()
{
if (Factories != null)
{
_counter = Factories.Count;
for (int i = 0; i < _counter; i++)
{
if (Factories[i] != null)
{
UnregisterEvents(Factories[i]);
}
}
}
// Inform all downstream nodes that we no longer need to process these tiles.
// This scriptable object may be re-used, but it's gameobjects are likely
// to be destroyed by a scene change, for example.
foreach (var tileId in _activeTiles.Keys.ToList())
{
DisposeTile(tileId);
}
_activeTiles.Clear();
_inactiveTiles.Clear();
}
#region Factory event callbacks
//factory event callback, not relaying this up for now
private void TileHeightStateChanged(UnityTile tile)
{
if (tile.HeightDataState == TilePropertyState.Loaded)
{
OnTileHeightProcessingFinished(tile);
}
TileStateChanged(tile);
}
private void TileRasterStateChanged(UnityTile tile)
{
if (tile.RasterDataState == TilePropertyState.Loaded)
{
OnTileImageProcessingFinished(tile);
}
TileStateChanged(tile);
}
private void TileVectorStateChanged(UnityTile tile)
{
if (tile.VectorDataState == TilePropertyState.Loaded)
{
OnTileVectorProcessingFinished(tile);
}
TileStateChanged(tile);
}
public virtual void TileStateChanged(UnityTile tile)
{
bool rasterDone = (tile.RasterDataState == TilePropertyState.None ||
tile.RasterDataState == TilePropertyState.Loaded ||
tile.RasterDataState == TilePropertyState.Error ||
tile.RasterDataState == TilePropertyState.Cancelled);
bool terrainDone = (tile.HeightDataState == TilePropertyState.None ||
tile.HeightDataState == TilePropertyState.Loaded ||
tile.HeightDataState == TilePropertyState.Error ||
tile.HeightDataState == TilePropertyState.Cancelled);
bool vectorDone = (tile.VectorDataState == TilePropertyState.None ||
tile.VectorDataState == TilePropertyState.Loaded ||
tile.VectorDataState == TilePropertyState.Error ||
tile.VectorDataState == TilePropertyState.Cancelled);
if (rasterDone && terrainDone && vectorDone)
{
tile.TileState = MeshGeneration.Enums.TilePropertyState.Loaded;
OnTileFinished(tile);
// Check if all tiles in extent are active tiles
if (_map.CurrentExtent.Count == _activeTiles.Count)
{
bool allDone = true;
// Check if all tiles are loaded.
foreach (var currentTile in _map.CurrentExtent)
{
allDone = allDone && (_activeTiles.ContainsKey(currentTile) && _activeTiles[currentTile].TileState == TilePropertyState.Loaded);
}
if (allDone)
{
State = ModuleState.Finished;
}
else
{
State = ModuleState.Working;
}
}
else
{
State = ModuleState.Working;
}
}
}
#endregion
/// <summary>
/// Registers requested tiles to the factories
/// </summary>
/// <param name="tileId"></param>
public virtual UnityTile LoadTile(UnwrappedTileId tileId)
{
UnityTile unityTile = null;
if (_inactiveTiles.Count > 0)
{
unityTile = _inactiveTiles.Dequeue();
}
if (unityTile == null)
{
unityTile = new GameObject().AddComponent<UnityTile>();
try
{
unityTile.MeshRenderer.sharedMaterial = Instantiate(_map.TileMaterial);
}
catch
{
Debug.Log("Tile Material not set. Using default material");
unityTile.MeshRenderer.sharedMaterial = Instantiate(new Material(Shader.Find("Diffuse")));
}
unityTile.transform.SetParent(_map.Root, false);
}
unityTile.Initialize(_map, tileId, _map.WorldRelativeScale, _map.AbsoluteZoom, _map.LoadingTexture);
PlaceTile(tileId, unityTile, _map);
// Don't spend resources naming objects, as you shouldn't find objects by name anyway!
#if UNITY_EDITOR
unityTile.gameObject.name = unityTile.CanonicalTileId.ToString();
#endif
unityTile.OnHeightDataChanged += TileHeightStateChanged;
unityTile.OnRasterDataChanged += TileRasterStateChanged;
unityTile.OnVectorDataChanged += TileVectorStateChanged;
unityTile.TileState = MeshGeneration.Enums.TilePropertyState.Loading;
ActiveTiles.Add(tileId, unityTile);
foreach (var factory in Factories)
{
factory.Register(unityTile);
}
return unityTile;
}
public virtual void DisposeTile(UnwrappedTileId tileId)
{
var unityTile = ActiveTiles[tileId];
foreach (var factory in Factories)
{
factory.Unregister(unityTile);
}
unityTile.Recycle();
ActiveTiles.Remove(tileId);
_inactiveTiles.Enqueue(unityTile);
}
/// <summary>
/// Repositions active tiles instead of recreating them. Useful for panning the map
/// </summary>
/// <param name="tileId"></param>
public virtual void RepositionTile(UnwrappedTileId tileId)
{
UnityTile currentTile;
if (ActiveTiles.TryGetValue(tileId, out currentTile))
{
PlaceTile(tileId, currentTile, _map);
}
}
protected abstract void PlaceTile(UnwrappedTileId tileId, UnityTile tile, IMapReadable map);
public void ClearMap()
{
UnregisterAllTiles();
if (Factories != null)
{
foreach (var tileFactory in Factories)
{
if (tileFactory != null)
{
tileFactory.Clear();
DestroyImmediate(tileFactory);
}
}
}
foreach (var tileId in _activeTiles.Keys.ToList())
{
_activeTiles[tileId].ClearAssets();
DisposeTile(tileId);
}
foreach (var tile in _inactiveTiles)
{
tile.ClearAssets();
DestroyImmediate(tile.gameObject);
}
_inactiveTiles.Clear();
State = ModuleState.Initialized;
}
public void ReregisterAllTiles()
{
foreach (var activeTile in _activeTiles)
{
foreach (var abstractTileFactory in Factories)
{
abstractTileFactory.Register(activeTile.Value);
}
}
}
public void UnregisterAllTiles()
{
foreach (var activeTile in _activeTiles)
{
foreach (var abstractTileFactory in Factories)
{
abstractTileFactory.Unregister(activeTile.Value);
}
}
}
public void UnregisterTilesFrom(AbstractTileFactory factory)
{
foreach (KeyValuePair<UnwrappedTileId, UnityTile> tileBundle in _activeTiles)
{
factory.Unregister(tileBundle.Value);
}
}
public void UnregisterAndRedrawTilesFromLayer(VectorTileFactory factory, LayerVisualizerBase layerVisualizer)
{
foreach (KeyValuePair<UnwrappedTileId, UnityTile> tileBundle in _activeTiles)
{
factory.UnregisterLayer(tileBundle.Value, layerVisualizer);
}
layerVisualizer.Clear();
layerVisualizer.UnbindSubLayerEvents();
layerVisualizer.SetProperties(layerVisualizer.SubLayerProperties);
layerVisualizer.InitializeStack();
foreach (KeyValuePair<UnwrappedTileId, UnityTile> tileBundle in _activeTiles)
{
factory.RedrawSubLayer(tileBundle.Value, layerVisualizer);
}
}
public void RemoveTilesFromLayer(VectorTileFactory factory, LayerVisualizerBase layerVisualizer)
{
foreach (KeyValuePair<UnwrappedTileId, UnityTile> tileBundle in _activeTiles)
{
factory.UnregisterLayer(tileBundle.Value, layerVisualizer);
}
factory.RemoveVectorLayerVisualizer(layerVisualizer);
}
public void ReregisterTilesTo(VectorTileFactory factory)
{
foreach (KeyValuePair<UnwrappedTileId, UnityTile> tileBundle in _activeTiles)
{
factory.Register(tileBundle.Value);
}
}
public void UpdateTileForProperty(AbstractTileFactory factory, LayerUpdateArgs updateArgs)
{
foreach (KeyValuePair<UnwrappedTileId, UnityTile> tileBundle in _activeTiles)
{
factory.UpdateTileProperty(tileBundle.Value, updateArgs);
}
}
#region Events
/// <summary>
/// The <c>OnTileError</c> event triggers when there's a <c>Tile</c> error.
/// Returns a <see cref="T:Mapbox.Map.TileErrorEventArgs"/> instance as a parameter, for the tile on which error occurred.
/// </summary>
public event EventHandler<TileErrorEventArgs> OnTileError;
private void Factory_OnTileError(object sender, TileErrorEventArgs e)
{
EventHandler<TileErrorEventArgs> handler = OnTileError;
if (handler != null)
{
handler(this, e);
}
}
/// <summary>
/// Event delegate, gets called when terrain factory finishes processing a tile.
/// </summary>
public event Action<UnityTile> OnTileHeightProcessingFinished = delegate {};
/// <summary>
/// Event delegate, gets called when image factory finishes processing a tile.
/// </summary>
public event Action<UnityTile> OnTileImageProcessingFinished = delegate {};
/// <summary>
/// Event delegate, gets called when vector factory finishes processing a tile.
/// </summary>
public event Action<UnityTile> OnTileVectorProcessingFinished = delegate {};
#endregion
}
}
+12
View File
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: cefaf3a12c7842d499a032db9077170d
timeCreated: 1504617939
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,33 @@
namespace Mapbox.Unity.Map
{
using System.Collections;
using Mapbox.Unity.Location;
using UnityEngine;
public class InitializeMapWithLocationProvider : MonoBehaviour
{
[SerializeField]
AbstractMap _map;
ILocationProvider _locationProvider;
private void Awake()
{
// Prevent double initialization of the map.
_map.InitializeOnStart = false;
}
protected virtual IEnumerator Start()
{
yield return null;
_locationProvider = LocationProviderFactory.Instance.DefaultLocationProvider;
_locationProvider.OnLocationUpdated += LocationProvider_OnLocationUpdated; ;
}
void LocationProvider_OnLocationUpdated(Unity.Location.Location location)
{
_locationProvider.OnLocationUpdated -= LocationProvider_OnLocationUpdated;
_map.Initialize(location.LatitudeLongitude, _map.AbsoluteZoom);
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 96f0fa82f89d64bb9a6524c72d538179
timeCreated: 1506092731
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: d3f7157c1c1f94f4aaac6081e3449f9b
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
+49
View File
@@ -0,0 +1,49 @@
using System;
using System.Collections.Generic;
using Mapbox.Map;
using Mapbox.Utils;
using UnityEngine;
namespace Mapbox.Unity.Map.Interfaces
{
public interface IMap : IMapReadable, IMapWritable, IUnifiedMap { }
public interface IMapReadable
{
Vector2d CenterMercator { get; }
float WorldRelativeScale { get; }
Vector2d CenterLatitudeLongitude { get; }
/// <summary>
/// Gets the zoom value of the map.
/// This allows for zoom values in between actual zoom level "AbsoluteZoom" requested from the service.
/// </summary>
float Zoom { get; }
/// <summary>
/// Gets the zoom value at which the map was intialized.
/// </summary>
int InitialZoom { get; }
/// <summary>
/// Gets the zoom value at which the tiles will be requested from the service.
/// Use this only for calls which require an integer value of zoom to be passed in.
/// </summary>
int AbsoluteZoom { get; }
Transform Root { get; }
float UnityTileSize { get; }
Texture2D LoadingTexture { get; }
Material TileMaterial { get; }
HashSet<UnwrappedTileId> CurrentExtent { get; }
event Action OnInitialized;
event Action OnUpdated;
Vector2d WorldToGeoPosition(Vector3 realworldPoint);
Vector3 GeoToWorldPosition(Vector2d latitudeLongitude, bool queryHeight = true);
}
public interface IMapWritable
{
void SetCenterMercator(Vector2d centerMercator);
void SetCenterLatitudeLongitude(Vector2d centerLatitudeLongitude);
void SetZoom(float zoom);
void SetWorldRelativeScale(float scale);
}
}
+12
View File
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: d5a989744ad8746e5bc533ee230d00c6
timeCreated: 1494990683
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,7 @@
namespace Mapbox.Unity.Map.Interfaces
{
public interface IMapPlacementStrategy
{
void SetUpPlacement(AbstractMap map);
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: aa6c9ee2f3b546dc9df96694c85e82c5
timeCreated: 1538658253
@@ -0,0 +1,7 @@
namespace Mapbox.Unity.Map.Interfaces
{
public interface IMapScalingStrategy
{
void SetUpScaling(AbstractMap map);
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a3d0db333c6d474aa152ccac7439e444
timeCreated: 1538658226
+42
View File
@@ -0,0 +1,42 @@
using System;
using Mapbox.Map;
using Mapbox.Unity.Map.TileProviders;
namespace Mapbox.Unity.Map.Interfaces
{
public interface ITileProvider
{
event EventHandler<ExtentArgs> ExtentChanged;
ITileProviderOptions Options { get; }
// TODO: add cancel event?
// Alternatively, give mapvisualizer an object recycling strategy that can separately determine when to change gameobjects.
// This removal would essentially lead to a cancel request and nothing more.
void Initialize(IMap map);
// TODO: Maybe combine both these methods.
void SetOptions(ITileProviderOptions options);
// TODO: add reset/clear method?
}
public interface IUnifiedTileProvider
{
event Action<UnwrappedTileId> OnTileAdded;
event Action<UnwrappedTileId> OnTileRemoved;
// TODO: add cancel event?
// Alternatively, give mapvisualizer an object recycling strategy that can separately determine when to change gameobjects.
// This removal would essentially lead to a cancel request and nothing more.
void Initialize(IUnifiedMap map);
// TODO: add reset/clear method?
}
public class TileStateChangedEventArgs : EventArgs
{
public UnwrappedTileId TileId;
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 21517bafda8f54be39ccf7c230b76f9c
timeCreated: 1494606252
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+10
View File
@@ -0,0 +1,10 @@
using Mapbox.Utils;
namespace Mapbox.Unity.Map.Interfaces
{
public interface IUnifiedMap
{
void UpdateMap(Vector2d latLon, float zoom);
void ResetMap();
}
}
+3
View File
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: be115c5fdb26480791b43d27c2bc1bfb
timeCreated: 1538657911
+51
View File
@@ -0,0 +1,51 @@
using Mapbox.Unity.Map.Interfaces;
namespace Mapbox.Unity.Map
{
using UnityEngine;
using Mapbox.Unity.MeshGeneration.Data;
using Mapbox.Map;
public enum ModuleState
{
Initialized,
Working,
Finished
}
public class AssignmentTypeAttribute : PropertyAttribute
{
public System.Type Type;
public AssignmentTypeAttribute(System.Type t)
{
Type = t;
}
}
/// <summary>
/// Map Visualizer
/// Represents a map.Doesn't contain much logic and at the moment, it creates requested tiles and relays them to the factories
/// under itself.It has a caching mechanism to reuse tiles and does the tile positioning in unity world.
/// Later we'll most likely keep track of map features here as well to allow devs to query for features easier
/// (i.e.query all buildings x meters around any restaurant etc).
/// </summary>
[CreateAssetMenu(menuName = "Mapbox/MapVisualizer/BasicMapVisualizer")]
public class MapVisualizer : AbstractMapVisualizer
{
protected override void PlaceTile(UnwrappedTileId tileId, UnityTile tile, IMapReadable map)
{
var rect = tile.Rect;
// TODO: this is constant for all tiles--cache.
var scale = tile.TileScale;
var scaleFactor = Mathf.Pow(2, (map.InitialZoom - map.AbsoluteZoom));
var position = new Vector3(
(float)(rect.Center.x - map.CenterMercator.x) * scale * scaleFactor,
0,
(float)(rect.Center.y - map.CenterMercator.y) * scale * scaleFactor);
tile.transform.localPosition = position;
}
}
}
+12
View File
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 526c8a90df31d41fe8057a6f85c7a3e4
timeCreated: 1494993890
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 817a1846479397d458272568e8bb804f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,13 @@
using Mapbox.Unity.Map.Interfaces;
using Mapbox.Unity.Utilities;
namespace Mapbox.Unity.Map.Strategies
{
public class MapPlacementAtLocationCenterStrategy : IMapPlacementStrategy
{
public void SetUpPlacement(AbstractMap map)
{
map.SetCenterMercator(Conversions.LatLonToMeters(map.CenterLatitudeLongitude));
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d44d0606bd83495bab6d3da0a48ad090
timeCreated: 1538658271
@@ -0,0 +1,15 @@
using Mapbox.Map;
using Mapbox.Unity.Map.Interfaces;
using Mapbox.Unity.Utilities;
namespace Mapbox.Unity.Map.Strategies
{
public class MapPlacementAtTileCenterStrategy : IMapPlacementStrategy
{
public void SetUpPlacement(AbstractMap map)
{
var referenceTileRect = Conversions.TileBounds(TileCover.CoordinateToTileId(map.CenterLatitudeLongitude, map.AbsoluteZoom));
map.SetCenterMercator(referenceTileRect.Center);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 559d97f03cf14bf79a007b09ad4f1336
timeCreated: 1538658263
@@ -0,0 +1,15 @@
using Mapbox.Map;
using Mapbox.Unity.Map.Interfaces;
using Mapbox.Unity.Utilities;
namespace Mapbox.Unity.Map.Strategies
{
public class MapScalingAtUnityScaleStrategy : IMapScalingStrategy
{
public void SetUpScaling(AbstractMap map)
{
var referenceTileRect = Conversions.TileBounds(TileCover.CoordinateToTileId(map.CenterLatitudeLongitude, map.AbsoluteZoom));
map.SetWorldRelativeScale((float)(map.Options.scalingOptions.unityTileSize / referenceTileRect.Size.x));
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6f52911bb8a44f60a4ef4feb3602d386
timeCreated: 1538658244
@@ -0,0 +1,14 @@
using Mapbox.Unity.Map.Interfaces;
using UnityEngine;
namespace Mapbox.Unity.Map.Strategies
{
public class MapScalingAtWorldScaleStrategy : IMapScalingStrategy
{
public void SetUpScaling(AbstractMap map)
{
var scaleFactor = Mathf.Pow(2, (map.AbsoluteZoom - map.InitialZoom));
map.SetWorldRelativeScale(scaleFactor * Mathf.Cos(Mathf.Deg2Rad * (float)map.CenterLatitudeLongitude.x));
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cc8da5d9c56144fc8758276cc931710e
timeCreated: 1538658236
+8
View File
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 59af73b59e6beff4abd67db34649e6e1
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,60 @@
using System;
using System.Collections.Generic;
using Mapbox.Map;
using Mapbox.Unity.Map.Interfaces;
using UnityEngine;
namespace Mapbox.Unity.Map.TileProviders
{
public class ExtentArgs : EventArgs
{
//TODO: Override GetHashCode for UnwrappedTileId
public HashSet<UnwrappedTileId> activeTiles;
}
public abstract class AbstractTileProvider : MonoBehaviour, ITileProvider
{
public event EventHandler<ExtentArgs> ExtentChanged;
protected IMap _map;
protected ExtentArgs _currentExtent = new ExtentArgs();
protected ITileProviderOptions _options;
public ITileProviderOptions Options
{
get
{
return _options;
}
}
public virtual void Initialize(IMap map)
{
_map = map;
OnInitialized();
}
public virtual void OnExtentChanged()
{
if (ExtentChanged != null)
{
ExtentChanged(this, _currentExtent);
}
}
public abstract void OnInitialized();
public abstract void UpdateTileExtent();
public abstract bool Cleanup(UnwrappedTileId tile);
public virtual void SetOptions(ITileProviderOptions options)
{
_options = options;
}
public virtual void UpdateTileProvider()
{
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: b7386ebbea7d44bb29c2107b2c909409
timeCreated: 1494606252
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,34 @@
using System.Collections.Generic;
using Mapbox.Map;
using Mapbox.Utils;
namespace Mapbox.Unity.Map.TileProviders
{
public class GlobeTileProvider : AbstractTileProvider
{
public override void OnInitialized()
{
_currentExtent.activeTiles = new HashSet<UnwrappedTileId>();
}
public override void UpdateTileExtent()
{
// HACK: don't allow too many tiles to be requested.
if (_map.AbsoluteZoom > 5)
{
throw new System.Exception("Too many tiles! Use a lower zoom level!");
}
var tileCover = TileCover.Get(Vector2dBounds.World(), _map.AbsoluteZoom);
foreach (var tile in tileCover)
{
_currentExtent.activeTiles.Add(new UnwrappedTileId(tile.Z, tile.X, tile.Y));
}
OnExtentChanged();
}
public override bool Cleanup(UnwrappedTileId tile)
{
return (!_currentExtent.activeTiles.Contains(tile));
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: a718f313c2f574a4aad42d7b52867205
timeCreated: 1500047799
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,39 @@
using Mapbox.Map;
using Mapbox.Unity.Map.Interfaces;
using Mapbox.Unity.MeshGeneration.Data;
using Mapbox.Unity.Utilities;
using Mapbox.Utils;
using UnityEngine;
namespace Mapbox.Unity.Map.TileProviders
{
//TODO : obsolete.
[CreateAssetMenu(menuName = "Mapbox/MapVisualizer/QuadTreeMapVisualizer")]
public class QuadTreeMapVisualizer : AbstractMapVisualizer
{
protected override void PlaceTile(UnwrappedTileId tileId, UnityTile tile, IMapReadable map)
{
//get the tile covering the center (Unity 0,0,0) of current extent
UnwrappedTileId centerTile = TileCover.CoordinateToTileId(map.CenterLatitudeLongitude, map.AbsoluteZoom);
//get center WebMerc corrdinates of tile covering the center (Unity 0,0,0)
Vector2d centerTileCenter = Conversions.TileIdToCenterWebMercator(centerTile.X, centerTile.Y, map.AbsoluteZoom);
//calculate distance between WebMerc center coordinates of center tile and WebMerc coordinates exactly at center
Vector2d shift = map.CenterMercator - centerTileCenter;
var unityTileSize = map.UnityTileSize;
// get factor at equator to avoid shifting errors at higher latitudes
float factor = Conversions.GetTileScaleInMeters(0f, map.AbsoluteZoom) * 256.0f / unityTileSize;
var scaleFactor = Mathf.Pow(2, (map.InitialZoom - map.AbsoluteZoom));
//position the tile relative to the center tile of the current viewport using the tile id
//multiply by tile size Unity units (unityTileScale)
//shift by distance of current viewport center to center of center tile
float shiftX = (float)shift.x / factor;
float shiftY = (float)shift.y / factor;
Vector3 position = new Vector3(
((tileId.X - centerTile.X) * unityTileSize - shiftX) * scaleFactor
, 0
, ((centerTile.Y - tileId.Y) * unityTileSize - shiftY) * scaleFactor);
tile.transform.localPosition = position;
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 1dfd965733118434481fedf30fa380c1
timeCreated: 1508892338
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,200 @@
using System;
using System.Collections.Generic;
using Mapbox.Map;
using Mapbox.Unity.Utilities;
using Mapbox.Utils;
using UnityEngine;
namespace Mapbox.Unity.Map.TileProviders
{
public class QuadTreeTileProvider : AbstractTileProvider
{
private static readonly int HIT_POINTS_COUNT = 4;
private Plane _groundPlane;
private bool _shouldUpdate;
[SerializeField] private CameraBoundsTileProviderOptions _cbtpOptions;
private Vector2dBounds _viewPortWebMercBounds;
#region Tile decision and raycasting fields
private HashSet<UnwrappedTileId> _tiles;
private HashSet<CanonicalTileId> _canonicalTiles;
private Ray _ray00;
private Ray _ray01;
private Ray _ray10;
private Ray _ray11;
private Vector3[] _hitPnt = new Vector3[HIT_POINTS_COUNT];
private Vector2d[] _hitPntGeoPos = new Vector2d[HIT_POINTS_COUNT];
private bool _isFirstLoad;
#endregion
public override void OnInitialized()
{
_tiles = new HashSet<UnwrappedTileId>();
_canonicalTiles = new HashSet<CanonicalTileId>();
if (Options != null)
{
_cbtpOptions = (CameraBoundsTileProviderOptions)_options;
}
else
{
_cbtpOptions = new CameraBoundsTileProviderOptions();
}
if (_cbtpOptions.camera == null)
{
_cbtpOptions.camera = Camera.main;
}
_cbtpOptions.camera.transform.hasChanged = false;
_groundPlane = new Plane(Vector3.up, 0);
_shouldUpdate = true;
_currentExtent.activeTiles = new HashSet<UnwrappedTileId>();
}
public override void UpdateTileExtent()
{
if (!_shouldUpdate)
{
return;
}
//update viewport in case it was changed by switching zoom level
_viewPortWebMercBounds = getcurrentViewPortWebMerc();
_currentExtent.activeTiles = GetWithWebMerc(_viewPortWebMercBounds, _map.AbsoluteZoom);
OnExtentChanged();
}
public HashSet<UnwrappedTileId> GetWithWebMerc(Vector2dBounds bounds, int zoom)
{
_tiles.Clear();
_canonicalTiles.Clear();
if (bounds.IsEmpty()) { return _tiles; }
//stay within WebMerc bounds
Vector2d swWebMerc = new Vector2d(Math.Max(bounds.SouthWest.x, -Utils.Constants.WebMercMax), Math.Max(bounds.SouthWest.y, -Utils.Constants.WebMercMax));
Vector2d neWebMerc = new Vector2d(Math.Min(bounds.NorthEast.x, Utils.Constants.WebMercMax), Math.Min(bounds.NorthEast.y, Utils.Constants.WebMercMax));
UnwrappedTileId swTile = WebMercatorToTileId(swWebMerc, zoom);
UnwrappedTileId neTile = WebMercatorToTileId(neWebMerc, zoom);
for (int x = swTile.X; x <= neTile.X; x++)
{
for (int y = neTile.Y; y <= swTile.Y; y++)
{
UnwrappedTileId uwtid = new UnwrappedTileId(zoom, x, y);
//hack: currently too many tiles are created at lower zoom levels
//investigate formulas, this worked before
if (!_canonicalTiles.Contains(uwtid.Canonical))
{
_tiles.Add(uwtid);
_canonicalTiles.Add(uwtid.Canonical);
}
}
}
return _tiles;
}
public UnwrappedTileId WebMercatorToTileId(Vector2d webMerc, int zoom)
{
var tileCount = Math.Pow(2, zoom);
var dblX = webMerc.x / Utils.Constants.WebMercMax;
var dblY = webMerc.y / Utils.Constants.WebMercMax;
int x = (int)Math.Floor((1 + dblX) / 2 * tileCount);
int y = (int)Math.Floor((1 - dblY) / 2 * tileCount);
return new UnwrappedTileId(zoom, x, y);
}
private Vector2dBounds getcurrentViewPortWebMerc(bool useGroundPlane = true)
{
if (useGroundPlane)
{
// rays from camera to groundplane: lower left and upper right
_ray00 = _cbtpOptions.camera.ViewportPointToRay(new Vector3(0, 0));
_ray01 = _cbtpOptions.camera.ViewportPointToRay(new Vector3(0, 1));
_ray10 = _cbtpOptions.camera.ViewportPointToRay(new Vector3(1, 0));
_ray11 = _cbtpOptions.camera.ViewportPointToRay(new Vector3(1, 1));
_hitPnt[0] = getGroundPlaneHitPoint(_ray00);
_hitPnt[1] = getGroundPlaneHitPoint(_ray01);
_hitPnt[2] = getGroundPlaneHitPoint(_ray10);
_hitPnt[3] = getGroundPlaneHitPoint(_ray11);
}
// Find min max bounding box.
// TODO : Find a better way of doing this.
double minLat = double.MaxValue;
double minLong = double.MaxValue;
double maxLat = double.MinValue;
double maxLong = double.MinValue;
for (int pointIndex = 0; pointIndex < HIT_POINTS_COUNT; ++pointIndex)
{
_hitPntGeoPos[pointIndex] = _map.WorldToGeoPosition(_hitPnt[pointIndex]);
}
for (int i = 0; i < HIT_POINTS_COUNT; i++)
{
if (_hitPnt[i] == Vector3.zero)
{
continue;
}
else
{
if (minLat > _hitPntGeoPos[i].x)
{
minLat = _hitPntGeoPos[i].x;
}
if (minLong > _hitPntGeoPos[i].y)
{
minLong = _hitPntGeoPos[i].y;
}
if (maxLat < _hitPntGeoPos[i].x)
{
maxLat = _hitPntGeoPos[i].x;
}
if (maxLong < _hitPntGeoPos[i].y)
{
maxLong = _hitPntGeoPos[i].y;
}
}
}
Vector2d hitPntSWGeoPos = new Vector2d(minLat, minLong);
Vector2d hitPntNEGeoPos = new Vector2d(maxLat, maxLong);
Vector2dBounds tileBounds = new Vector2dBounds(Conversions.LatLonToMeters(hitPntSWGeoPos), Conversions.LatLonToMeters(hitPntNEGeoPos)); // Bounds debugging.
#if UNITY_EDITOR
Debug.DrawLine(_cbtpOptions.camera.transform.position, _map.GeoToWorldPosition(hitPntSWGeoPos), Color.blue);
Debug.DrawLine(_cbtpOptions.camera.transform.position, _map.GeoToWorldPosition(hitPntNEGeoPos), Color.red);
#endif
return tileBounds;
}
private Vector3 getGroundPlaneHitPoint(Ray ray)
{
float distance;
if (!_groundPlane.Raycast(ray, out distance)) { return Vector3.zero; }
return ray.GetPoint(distance);
}
public override void UpdateTileProvider()
{
if (_cbtpOptions != null && _cbtpOptions.camera != null && _cbtpOptions.camera.transform.hasChanged)
{
UpdateTileExtent();
_cbtpOptions.camera.transform.hasChanged = false;
}
}
public override bool Cleanup(UnwrappedTileId tile)
{
return (!_currentExtent.activeTiles.Contains(tile));
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 756a01a914208439d8d2fc8dcd68b229
timeCreated: 1508278498
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,84 @@
using System.Collections.Generic;
using Mapbox.Map;
using UnityEngine;
namespace Mapbox.Unity.Map.TileProviders
{
public class RangeAroundTransformTileProvider : AbstractTileProvider
{
[SerializeField] private RangeAroundTransformTileProviderOptions _rangeTileProviderOptions;
private bool _initialized = false;
private UnwrappedTileId _currentTile;
private bool _waitingForTargetTransform = false;
public override void OnInitialized()
{
if (Options != null)
{
_rangeTileProviderOptions = (RangeAroundTransformTileProviderOptions)Options;
}
else if (_rangeTileProviderOptions == null)
{
_rangeTileProviderOptions = new RangeAroundTransformTileProviderOptions();
}
if (_rangeTileProviderOptions.targetTransform == null)
{
Debug.LogError("TransformTileProvider: No location marker transform specified.");
_waitingForTargetTransform = true;
}
else
{
_initialized = true;
}
_currentExtent.activeTiles = new HashSet<UnwrappedTileId>();
_map.OnInitialized += UpdateTileExtent;
_map.OnUpdated += UpdateTileExtent;
}
public override void UpdateTileExtent()
{
if (!_initialized) return;
_currentExtent.activeTiles.Clear();
_currentTile = TileCover.CoordinateToTileId(_map.WorldToGeoPosition(_rangeTileProviderOptions.targetTransform.localPosition), _map.AbsoluteZoom);
for (int x = _currentTile.X - _rangeTileProviderOptions.visibleBuffer; x <= (_currentTile.X + _rangeTileProviderOptions.visibleBuffer); x++)
{
for (int y = _currentTile.Y - _rangeTileProviderOptions.visibleBuffer; y <= (_currentTile.Y + _rangeTileProviderOptions.visibleBuffer); y++)
{
_currentExtent.activeTiles.Add(new UnwrappedTileId(_map.AbsoluteZoom, x, y));
}
}
OnExtentChanged();
}
public override void UpdateTileProvider()
{
if (_waitingForTargetTransform && !_initialized)
{
if (_rangeTileProviderOptions.targetTransform != null)
{
_initialized = true;
}
}
if (_rangeTileProviderOptions != null && _rangeTileProviderOptions.targetTransform != null && _rangeTileProviderOptions.targetTransform.hasChanged)
{
UpdateTileExtent();
_rangeTileProviderOptions.targetTransform.hasChanged = false;
}
}
public override bool Cleanup(UnwrappedTileId tile)
{
bool dispose = false;
dispose = tile.X > _currentTile.X + _rangeTileProviderOptions.disposeBuffer || tile.X < _currentTile.X - _rangeTileProviderOptions.disposeBuffer;
dispose = dispose || tile.Y > _currentTile.Y + _rangeTileProviderOptions.disposeBuffer || tile.Y < _currentTile.Y - _rangeTileProviderOptions.disposeBuffer;
return (dispose);
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 15eed3c0528a3498dae4ff8f7b8ae77f
timeCreated: 1505936421
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,53 @@
using System.Collections.Generic;
using Mapbox.Map;
namespace Mapbox.Unity.Map.TileProviders
{
public class RangeTileProvider : AbstractTileProvider
{
private RangeTileProviderOptions _rangeTileProviderOptions;
private bool _initialized = false;
public override void OnInitialized()
{
if (Options != null)
{
_rangeTileProviderOptions = (RangeTileProviderOptions)Options;
}
else
{
_rangeTileProviderOptions = new RangeTileProviderOptions();
}
_initialized = true;
_currentExtent.activeTiles = new HashSet<UnwrappedTileId>();
}
public override void UpdateTileExtent()
{
if (!_initialized || _rangeTileProviderOptions == null)
{
return;
}
_currentExtent.activeTiles.Clear();
var centerTile = TileCover.CoordinateToTileId(_map.CenterLatitudeLongitude, _map.AbsoluteZoom);
_currentExtent.activeTiles.Add(new UnwrappedTileId(_map.AbsoluteZoom, centerTile.X, centerTile.Y));
for (int x = (centerTile.X - _rangeTileProviderOptions.west); x <= (centerTile.X + _rangeTileProviderOptions.east); x++)
{
for (int y = (centerTile.Y - _rangeTileProviderOptions.north); y <= (centerTile.Y + _rangeTileProviderOptions.south); y++)
{
_currentExtent.activeTiles.Add(new UnwrappedTileId(_map.AbsoluteZoom, x, y));
}
}
OnExtentChanged();
}
public override bool Cleanup(UnwrappedTileId tile)
{
return (!_currentExtent.activeTiles.Contains(tile));
}
}
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 7d7ff8ed3b76a4ee5a451d64a5393e3f
timeCreated: 1494606252
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:
@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Mapbox.Map;
using UnityEngine;
using UnityEngine.Events;
namespace Mapbox.Unity.Map.TileProviders
{
/// <summary>
/// Monobehavior Script to handle TileErrors.
/// There's an OnTileError event on AbstractMapVisualizer, AbstractTileFactory and UnityTile classes that one can subscribe to to listen to tile errors
/// </summary>
public class TileErrorHandler : MonoBehaviour
{
[SerializeField]
private AbstractMap _mapInstance;
public TileErrorEvent OnTileError;
protected virtual void OnEnable()
{
if (_mapInstance == null)
{
_mapInstance = GetComponent<AbstractMap>();
}
_mapInstance.OnInitialized += MapInstance_OnInitialized;
}
private void MapInstance_OnInitialized()
{
_mapInstance.OnInitialized -= MapInstance_OnInitialized;
_mapInstance.MapVisualizer.OnTileError += _OnTileErrorHandler;
}
private void _OnTileErrorHandler(object sender, TileErrorEventArgs e)
{
// check if request has been aborted: show warning not error
if (e.Exceptions.Count > 0)
{
// 1. aborted is always the first exception
// additional exceptions are always caused by the request being aborted
// show all of them as warnings
// 2. 'Unable to write data' is another exception associated
// with aborted requests: request finshed successfully but
// was aborted during filling of local buffer, also show as warning
if (
e.Exceptions[0].Message.Contains("Request aborted")
|| e.Exceptions[0].Message.Equals("Unable to write data")
)
{
Debug.LogWarning(printMessage(e.Exceptions, e));
}
else
{
Debug.LogError(printMessage(e.Exceptions, e));
}
}
if (OnTileError != null)
{
OnTileError.Invoke(e);
}
}
private string printMessage(List<Exception> exceptions, TileErrorEventArgs e)
{
return string.Format(
"{0} Exception(s) caused on the tile. Tile ID:{1} Tile Type:{4}{2}{3}"
, exceptions.Count
, e.TileId
, Environment.NewLine
, string.Join(Environment.NewLine, exceptions.Select(ex => ex.Message).ToArray())
, e.TileType
);
}
protected virtual void OnDisable()
{
_mapInstance.MapVisualizer.OnTileError -= _OnTileErrorHandler;
}
}
[System.Serializable]
public class TileErrorEvent : UnityEvent<TileErrorEventArgs> { }
}
@@ -0,0 +1,12 @@
fileFormatVersion: 2
guid: 76a256726e16d4966a3f30b97a17e1d5
timeCreated: 1509146285
licenseType: Pro
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: