You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
mapbox-sdk/Unity/MeshGeneration/Factories/VectorTileFactory.cs

517 lines
14 KiB

using System.Collections.Generic;
using UnityEngine;
using Mapbox.Unity.MeshGeneration.Enums;
using Mapbox.Unity.MeshGeneration.Data;
using Mapbox.Unity.MeshGeneration.Interfaces;
using Mapbox.Map;
using Mapbox.Unity.Map;
using System;
namespace Mapbox.Unity.MeshGeneration.Factories
{
/// <summary>
/// Vector Tile Factory
/// Vector data is much more detailed compared to terrain and image data so we have a different structure to process
/// vector data(compared to other factories). First of all, how does the vector data itself structured? Vector tile
/// data contains 'vector layers' as immediate children.And then each of these vector layers contains a number of
/// 'features' inside.I.e.vector data for a tile has 'building', 'road', 'landuse' etc layers. Then building layer
/// has a number of polygon features, road layer has line features etc.
/// Similar to this, vector tile factory contains bunch of 'layer visualizers' and each one of them corresponds to
/// one (or more) vector layers in data.So when data is received, factory goes through all layers inside and passes
/// them to designated layer visualizers.We're using layer name as key here, to find the designated layer visualizer,
/// like 'building', 'road'. (vector tile factory visual would help here). If it can't find a layer visualizer for
/// that layer, it'll be skipped and not processed at all.If all you need is 1-2 layers, it's indeed a big waste to
/// pull whole vector data and you can use 'Style Optimized Vector Tile Factory' to pull only the layer you want to use.
/// </summary>
//[CreateAssetMenu(menuName = "Mapbox/Factories/Vector Tile Factory")]
public class VectorTileFactory : AbstractTileFactory
{
#region Private/Protected Fields
private Dictionary<string, List<LayerVisualizerBase>> _layerBuilder;
private VectorLayerProperties _properties;
private Dictionary<UnityTile, HashSet<LayerVisualizerBase>> _layerProgress;
protected VectorDataFetcher DataFetcher;
#endregion
#region Properties
public string TilesetId
{
get
{
return _properties.sourceOptions.Id;
}
set
{
_properties.sourceOptions.Id = value;
}
}
public VectorLayerProperties Properties
{
get
{
return _properties;
}
}
#endregion
#region Public Methods
public void RedrawSubLayer(UnityTile tile, LayerVisualizerBase visualizer)
{
CreateFeatureWithBuilder(tile, visualizer.SubLayerProperties.coreOptions.layerName, visualizer);
}
public void UnregisterLayer(UnityTile tile, LayerVisualizerBase visualizer)
{
if (_layerProgress.ContainsKey(tile))
{
_layerProgress.Remove(tile);
}
if (_tilesWaitingProcessing.Contains(tile))
{
_tilesWaitingProcessing.Remove(tile);
}
if (visualizer != null)
{
visualizer.UnregisterTile(tile);
}
}
#endregion
#region Public Layer Operation Api Methods for
public virtual LayerVisualizerBase AddVectorLayerVisualizer(VectorSubLayerProperties subLayer)
{
//if its of type prefabitemoptions then separate the visualizer type
LayerVisualizerBase visualizer = CreateInstance<VectorLayerVisualizer>();
//TODO : FIX THIS !!
visualizer.LayerVisualizerHasChanged += UpdateTileFactory;
// Set honorBuildingSettings - need to set here in addition to the UI.
// Not setting it here can lead to wrong filtering.
bool isPrimitiveTypeValidForBuidingIds = (subLayer.coreOptions.geometryType == VectorPrimitiveType.Polygon) || (subLayer.coreOptions.geometryType == VectorPrimitiveType.Custom);
bool isSourceValidForBuildingIds = _properties.sourceType != VectorSourceType.MapboxStreets;
subLayer.honorBuildingIdSetting = isPrimitiveTypeValidForBuidingIds && isSourceValidForBuildingIds;
// Setup visualizer.
((VectorLayerVisualizer)visualizer).SetProperties(subLayer);
visualizer.Initialize();
if (visualizer == null)
{
return visualizer;
}
if (_layerBuilder.ContainsKey(visualizer.Key))
{
_layerBuilder[visualizer.Key].Add(visualizer);
}
else
{
_layerBuilder.Add(visualizer.Key, new List<LayerVisualizerBase> { visualizer });
}
return visualizer;
}
public virtual LayerVisualizerBase AddPOIVectorLayerVisualizer(PrefabItemOptions poiSubLayer)
{
LayerVisualizerBase visualizer = CreateInstance<LocationPrefabsLayerVisualizer>();
poiSubLayer.performanceOptions = _properties.performanceOptions;
((LocationPrefabsLayerVisualizer)visualizer).SetProperties((PrefabItemOptions)poiSubLayer);
visualizer.LayerVisualizerHasChanged += UpdateTileFactory;
visualizer.Initialize();
if (visualizer == null)
{
return null;
}
if (_layerBuilder.ContainsKey(visualizer.Key))
{
_layerBuilder[visualizer.Key].Add(visualizer);
}
else
{
_layerBuilder.Add(visualizer.Key, new List<LayerVisualizerBase>() { visualizer });
}
return visualizer;
}
public virtual LayerVisualizerBase FindVectorLayerVisualizer(VectorSubLayerProperties subLayer)
{
if (_layerBuilder.ContainsKey(subLayer.Key))
{
var visualizer = _layerBuilder[subLayer.Key].Find((obj) => obj.SubLayerProperties == subLayer);
return visualizer;
}
return null;
}
public virtual void RemoveVectorLayerVisualizer(LayerVisualizerBase subLayer)
{
subLayer.Clear();
if (_layerBuilder.ContainsKey(subLayer.Key))
{
if (Properties.vectorSubLayers.Contains(subLayer.SubLayerProperties))
{
Properties.vectorSubLayers.Remove(subLayer.SubLayerProperties);
}
else if (subLayer.SubLayerProperties is PrefabItemOptions && Properties.locationPrefabList.Contains(subLayer.SubLayerProperties as PrefabItemOptions))
{
Properties.locationPrefabList.Remove(subLayer.SubLayerProperties as PrefabItemOptions);
}
subLayer.LayerVisualizerHasChanged -= UpdateTileFactory;
subLayer.UnbindSubLayerEvents();
_layerBuilder[subLayer.Key].Remove(subLayer);
}
}
#endregion
#region AbstractFactoryOverrides
/// <summary>
/// Set up sublayers using VectorLayerVisualizers.
/// </summary>
protected override void OnInitialized()
{
_layerProgress = new Dictionary<UnityTile, HashSet<LayerVisualizerBase>>();
_layerBuilder = new Dictionary<string, List<LayerVisualizerBase>>();
DataFetcher = ScriptableObject.CreateInstance<VectorDataFetcher>();
DataFetcher.DataRecieved += OnVectorDataRecieved;
DataFetcher.FetchingError += OnDataError;
CreatePOILayerVisualizers();
CreateLayerVisualizers();
}
protected override void OnRegistered(UnityTile tile)
{
if (string.IsNullOrEmpty(TilesetId) || _properties.sourceOptions.isActive == false || (_properties.vectorSubLayers.Count + _properties.locationPrefabList.Count) == 0)
{
tile.VectorDataState = TilePropertyState.None;
return;
}
tile.VectorDataState = TilePropertyState.Loading;
_tilesWaitingResponse.Add(tile);
VectorDataFetcherParameters parameters = new VectorDataFetcherParameters()
{
canonicalTileId = tile.CanonicalTileId,
tilesetId = TilesetId,
tile = tile,
useOptimizedStyle = _properties.useOptimizedStyle,
style = _properties.optimizedStyle
};
DataFetcher.FetchData(parameters);
}
protected override void OnUnregistered(UnityTile tile)
{
if (_layerProgress != null && _layerProgress.ContainsKey(tile))
{
_layerProgress.Remove(tile);
}
if (_tilesWaitingResponse != null && _tilesWaitingProcessing.Contains(tile))
{
_tilesWaitingProcessing.Remove(tile);
}
if (_layerBuilder != null)
{
foreach (var layer in _layerBuilder.Values)
{
foreach (var visualizer in layer)
{
visualizer.UnregisterTile(tile);
}
}
}
}
public override void Clear()
{
DestroyImmediate(DataFetcher);
if (_layerBuilder != null)
{
foreach (var layerList in _layerBuilder.Values)
{
foreach (var layerVisualizerBase in layerList)
{
layerVisualizerBase.Clear();
DestroyImmediate(layerVisualizerBase);
}
}
_layerProgress.Clear();
_tilesWaitingResponse.Clear();
_tilesWaitingProcessing.Clear();
}
}
public override void SetOptions(LayerProperties options)
{
_properties = (VectorLayerProperties)options;
if (_layerBuilder != null)
{
RemoveAllLayerVisualiers();
CreatePOILayerVisualizers();
CreateLayerVisualizers();
}
}
public override void UpdateTileProperty(UnityTile tile, LayerUpdateArgs updateArgs)
{
updateArgs.property.UpdateProperty(tile);
if (updateArgs.property.NeedsForceUpdate())
{
Unregister(tile);
}
Register(tile);
}
protected override void UpdateTileFactory(object sender, EventArgs args)
{
VectorLayerUpdateArgs layerUpdateArgs = args as VectorLayerUpdateArgs;
layerUpdateArgs.factory = this;
base.UpdateTileFactory(sender, layerUpdateArgs);
}
/// <summary>
/// Method to be called when a tile error has occurred.
/// </summary>
/// <param name="e"><see cref="T:Mapbox.Map.TileErrorEventArgs"/> instance/</param>
protected override void OnErrorOccurred(UnityTile tile, TileErrorEventArgs e)
{
base.OnErrorOccurred(tile, e);
}
protected override void OnPostProcess(UnityTile tile)
{
}
public override void UnbindEvents()
{
base.UnbindEvents();
}
protected override void OnUnbindEvents()
{
if (_layerBuilder != null)
{
foreach (var layer in _layerBuilder.Values)
{
foreach (var visualizer in layer)
{
visualizer.LayerVisualizerHasChanged -= UpdateTileFactory;
visualizer.UnbindSubLayerEvents();
}
}
}
}
#endregion
#region DataFetcherEvents
private void OnVectorDataRecieved(UnityTile tile, Mapbox.Map.VectorTile vectorTile)
{
if (tile != null)
{
_tilesWaitingResponse.Remove(tile);
if (tile.VectorDataState != TilePropertyState.Unregistered)
{
tile.SetVectorData(vectorTile);
// FIXME: we can make the request BEFORE getting a response from these!
if (tile.HeightDataState == TilePropertyState.Loading ||
tile.RasterDataState == TilePropertyState.Loading)
{
tile.OnHeightDataChanged += DataChangedHandler;
tile.OnRasterDataChanged += DataChangedHandler;
}
else
{
CreateMeshes(tile);
}
}
}
}
private void DataChangedHandler(UnityTile tile)
{
if (tile.VectorDataState != TilePropertyState.Unregistered &&
tile.RasterDataState != TilePropertyState.Loading &&
tile.HeightDataState != TilePropertyState.Loading)
{
tile.OnHeightDataChanged -= DataChangedHandler;
tile.OnRasterDataChanged -= DataChangedHandler;
CreateMeshes(tile);
}
}
private void OnDataError(UnityTile tile, Mapbox.Map.VectorTile vectorTile, TileErrorEventArgs e)
{
if (tile != null)
{
_tilesWaitingResponse.Remove(tile);
if (tile.VectorDataState != TilePropertyState.Unregistered)
{
tile.SetVectorData(null);
tile.VectorDataState = TilePropertyState.Error;
OnErrorOccurred(e);
}
}
}
#endregion
#region Private Methods
private void CreateMeshes(UnityTile tile)
{
var nameList = new List<string>();
var builderList = new List<LayerVisualizerBase>();
foreach (var layerName in tile.VectorData.Data.LayerNames())
{
if (_layerBuilder.ContainsKey(layerName))
{
//two loops; first one to add it to waiting/tracking list, second to start it
foreach (var builder in _layerBuilder[layerName])
{
nameList.Add(layerName);
builderList.Add(builder);
TrackFeatureWithBuilder(tile, layerName, builder);
}
}
}
for (int i = 0; i < nameList.Count; i++)
{
CreateFeatureWithBuilder(tile, nameList[i], builderList[i]);
}
builderList.Clear();
//emptylayer for visualizers that don't depend on outside data sources
string emptyLayer = "";
if (_layerBuilder.ContainsKey(emptyLayer))
{
//two loops; first one to add it to waiting/tracking list, second to start it
foreach (var builder in _layerBuilder[emptyLayer])
{
builderList.Add(builder);
TrackFeatureWithBuilder(tile, emptyLayer, builder);
}
}
for (int i = 0; i < builderList.Count; i++)
{
CreateFeatureWithBuilder(tile, emptyLayer, builderList[i]);
}
if (!_layerProgress.ContainsKey(tile))
{
tile.VectorDataState = TilePropertyState.Loaded;
}
}
private void TrackFeatureWithBuilder(UnityTile tile, string layerName, LayerVisualizerBase builder)
{
if (builder.Active)
{
if (_layerProgress.ContainsKey(tile))
{
_layerProgress[tile].Add(builder);
}
else
{
_layerProgress.Add(tile, new HashSet<LayerVisualizerBase> {builder});
if (!_tilesWaitingProcessing.Contains(tile))
{
_tilesWaitingProcessing.Add(tile);
}
}
}
}
private void CreateFeatureWithBuilder(UnityTile tile, string layerName, LayerVisualizerBase builder)
{
if (builder.Active)
{
if (_layerProgress.ContainsKey(tile))
{
_layerProgress[tile].Add(builder);
}
else
{
_layerProgress.Add(tile, new HashSet<LayerVisualizerBase> { builder });
if (!_tilesWaitingProcessing.Contains(tile))
{
_tilesWaitingProcessing.Add(tile);
}
}
if (layerName != "")
{
builder.Create(tile.VectorData.Data.GetLayer(layerName), tile, DecreaseProgressCounter);
}
else
{
//just pass the first available layer - we should create a static null layer for this
builder.Create(tile.VectorData.Data.GetLayer(tile.VectorData.Data.LayerNames()[0]), tile, DecreaseProgressCounter);
}
}
}
private void DecreaseProgressCounter(UnityTile tile, LayerVisualizerBase builder)
{
if (_layerProgress.ContainsKey(tile))
{
if (_layerProgress[tile].Contains(builder))
{
_layerProgress[tile].Remove(builder);
}
if (_layerProgress[tile].Count == 0)
{
_layerProgress.Remove(tile);
_tilesWaitingProcessing.Remove(tile);
tile.VectorDataState = TilePropertyState.Loaded;
}
}
}
private void CreatePOILayerVisualizers()
{
foreach (var item in _properties.locationPrefabList)
{
AddPOIVectorLayerVisualizer(item);
}
}
private void CreateLayerVisualizers()
{
foreach (var sublayer in _properties.vectorSubLayers)
{
AddVectorLayerVisualizer(sublayer);
}
}
private void RemoveAllLayerVisualiers()
{
//Clearing gameobjects pooled and managed by modifiers to prevent zombie gameobjects.
foreach (var pairs in _layerBuilder)
{
foreach (var layerVisualizerBase in pairs.Value)
{
layerVisualizerBase.Clear();
}
}
_layerBuilder.Clear();
}
#endregion
}
}