public void LazyDecoding(string fileName) { string fullFileName = Path.Combine(fixturesPath, fileName); Assert.True(File.Exists(fullFileName), "Vector tile exists"); byte[] data = File.ReadAllBytes(fullFileName); VectorTile vt = new VectorTile(data); foreach (var layerName in vt.LayerNames()) { VectorTileLayer layer = vt.GetLayer(layerName); for (int i = 0; i < layer.FeatureCount(); i++) { VectorTileFeature feat = layer.GetFeature(i); var properties = feat.GetProperties(); foreach (var prop in properties) { Assert.AreEqual(prop.Value, feat.GetValue(prop.Key), "Property values match"); } foreach (var geomPart in feat.Geometry <int>()) { foreach (var coord in geomPart) { //TODO add Assert } } } } string geojson = vt.ToGeoJson(0, 0, 0); Assert.GreaterOrEqual(geojson.Length, 30, "geojson >= 30 chars"); }
private BuildingMeshBuilderProperties MakeProperties(VectorTileLayer layer) { var output = new BuildingMeshBuilderProperties { VectorTileLayer = layer, FeatureCount = layer?.FeatureCount() ?? 0, LayerFeatureFilters = SubLayerProperties.filterOptions.filters.Select(m => m.GetFilterComparer()).ToArray(), LayerFeatureFilterCombiner = new LayerFilterComparer() }; switch (SubLayerProperties.filterOptions.combinerType) { case LayerFilterCombinerOperationType.Any: output.LayerFeatureFilterCombiner = LayerFilterComparer.AnyOf(output.LayerFeatureFilters); break; case LayerFilterCombinerOperationType.All: output.LayerFeatureFilterCombiner = LayerFilterComparer.AllOf(output.LayerFeatureFilters); break; case LayerFilterCombinerOperationType.None: output.LayerFeatureFilterCombiner = LayerFilterComparer.NoneOf(output.LayerFeatureFilters); break; default: throw new ArgumentOutOfRangeException(); } output.BuildingsWithUniqueIds = SubLayerProperties.honorBuildingIdSetting && SubLayerProperties.buildingsWithUniqueIds; return(output); }
public override void Create(VectorTileLayer layer, UnityTile tile) { _container = new GameObject(Key + " Container"); _container.transform.SetParent(tile.transform, false); var fc = layer.FeatureCount(); var filterOut = false; for (int i = 0; i < fc; i++) { filterOut = false; var feature = new VectorFeatureUnity(layer.GetFeature(i, 0), tile); foreach (var filter in Filters) { if (!string.IsNullOrEmpty(filter.Key) && !feature.Properties.ContainsKey(filter.Key)) { continue; } if (!filter.Try(feature)) { filterOut = true; break; } } if (!filterOut) { Build(feature, tile, _container); } } }
public void AtLeastOneLayer(string fileName) { string fullFileName = Path.Combine(fixturesPath, fileName); Assert.True(File.Exists(fullFileName), "Vector tile exists"); byte[] data = File.ReadAllBytes(fullFileName); VectorTile vt = new VectorTile(data); Assert.GreaterOrEqual(vt.LayerNames().Count, 1, "At least one layer"); string geojson = vt.ToGeoJson(0, 0, 0); Assert.GreaterOrEqual(geojson.Length, 30, "geojson >= 30 chars"); foreach (var lyrName in vt.LayerNames()) { VectorTileLayer lyr = vt.GetLayer(lyrName); for (int i = 0; i < lyr.FeatureCount(); i++) { Debug.WriteLine("{0} lyr:{1} feat:{2}", fileName, lyr.Name, i); VectorTileFeature feat = lyr.GetFeature(i); long extent = (long)lyr.Extent; foreach (var part in feat.Geometry <long>()) { foreach (var geom in part) { if (geom.X < 0 || geom.Y < 0 || geom.X > extent || geom.Y > extent) { Debug.WriteLine("{0} lyr:{1} feat:{2} x:{3} y:{4}", fileName, lyr.Name, i, geom.X, geom.Y); } } } } } }
public void ClipHardAtTileBoundary(string fileName) { string fullFileName = Path.Combine(fixturesPath, fileName); Assert.True(File.Exists(fullFileName), "Vector tile exists"); byte[] data = File.ReadAllBytes(fullFileName); VectorTile vt = new VectorTile(data); Assert.GreaterOrEqual(vt.LayerNames().Count, 1, "At least one layer"); string geojson = vt.ToGeoJson(0, 0, 0); Assert.GreaterOrEqual(geojson.Length, 30, "geojson >= 30 chars"); foreach (var lyrName in vt.LayerNames()) { VectorTileLayer lyr = vt.GetLayer(lyrName); for (int i = 0; i < lyr.FeatureCount(); i++) { Debug.WriteLine("{0} lyr:{1} feat:{2}", fileName, lyr.Name, i); VectorTileFeature feat = lyr.GetFeature(i, 0); long extent = (long)lyr.Extent; foreach (var part in feat.Geometry <int>()) { foreach (var geom in part) { Assert.GreaterOrEqual(geom.X, 0, "geom.X equal or greater 0"); Assert.GreaterOrEqual(geom.Y, 0, "geom.Y eqaul or greater 0"); Assert.LessOrEqual(geom.X, extent, "geom.X less or equal extent"); Assert.LessOrEqual(geom.Y, extent, "geom.Y less or equal extent"); } } } } }
public void Clipping(string fileName) { string fullFileName = Path.Combine(fixturesPath, fileName); Assert.True(File.Exists(fullFileName), "Vector tile exists"); byte[] data = File.ReadAllBytes(fullFileName); VectorTile vt = new VectorTile(data); foreach (var lyrName in vt.LayerNames()) { VectorTileLayer lyr = vt.GetLayer(lyrName); for (int i = 0; i < lyr.FeatureCount(); i++) { VectorTileFeature feat = lyr.GetFeature(i); //skip features with unknown geometry type if (feat.GeometryType == GeomType.UNKNOWN) { continue; } List <List <Point2d <long> > > geomRaw = feat.Geometry <long>(); List <List <Point2d <long> > > geomClipped = feat.Geometry <long>(0); for (int j = 0; j < geomRaw.Count; j++) { List <Point2d <long> > part = geomRaw[j]; List <Point2d <long> > partClipped = geomClipped[j]; // Workaround to compare parts as clipping may or may not change the order of vertices // This only works if no actual clipping is done Assert.False(part.Except(partClipped).Any(), $"{fileName}, feature[{i}], geometry part[{j}]: geometry parts don't match after clipping"); } } } }
public void Scaling(string fileName) { float[] scales = new float[] { 1.5f, 2.25f, 5.75f, 197.3f }; string fullFileName = Path.Combine(fixturesPath, fileName); byte[] data = File.ReadAllBytes(fullFileName); VectorTile vt = new VectorTile(data); foreach (var lyrName in vt.LayerNames()) { VectorTileLayer lyr = vt.GetLayer(lyrName); int featCnt = lyr.FeatureCount(); for (int idxFeat = 0; idxFeat < featCnt; idxFeat++) { VectorTileFeature feat = lyr.GetFeature(idxFeat); List <List <Point2d <int> > > rawParts = feat.Geometry <int>(); for (int idxPart = 0; idxPart < rawParts.Count; idxPart++) { List <Point2d <int> > rawGeom = rawParts[idxPart]; foreach (var scale in scales) { List <List <Point2d <float> > > scaledParts = feat.Geometry <float>(null, scale); List <Point2d <float> > scaledGeom = scaledParts[idxPart]; for (int idxVertex = 0; idxVertex < rawGeom.Count; idxVertex++) { Point2d <int> rawVertex = rawGeom[idxVertex]; Point2d <float> scaledVertex = scaledGeom[idxVertex]; Assert.AreEqual(scale * (float)rawVertex.X, scaledVertex.X, $"{fileName}, feature[{idxFeat}], geometry part[{idxPart}], vertex[{idxVertex}], scale[{scale}]: X does not match"); Assert.AreEqual(scale * (float)rawVertex.Y, scaledVertex.Y, $"{fileName}, feature[{idxFeat}], geometry part[{idxPart}], vertex[{idxVertex}], scale[{scale}]: Y does not match"); } } } } } }
/// <summary> /// Creates an object for each layer, extract and filter in/out the features and runs Build method on them. /// </summary> /// <param name="layer"></param> /// <param name="tile"></param> public override IEnumerator AsyncCreate(VectorTileLayer layer, UnityTile tile, Action cb) { var container = new GameObject(Key + " Container"); container.transform.SetParent(tile.transform, false); //testing each feature with filters var fc = layer.FeatureCount(); var filterOut = false; for (int i = 0; i < fc; i++) { filterOut = false; var feature = new VectorFeatureUnity(layer.GetFeature(i, 0), tile, layer.Extent); foreach (var filter in Filters) { if (!string.IsNullOrEmpty(filter.Key) && !feature.Properties.ContainsKey(filter.Key)) { continue; } if (!filter.Try(feature)) { filterOut = true; break; } } if (!filterOut) { Build(feature, tile, container); } if (i % _meshesPerPass == 0) { yield return(null); } } var mergedStack = _defaultStack as MergedModifierStack; if (mergedStack != null) { mergedStack.End(tile, container); } for (int i = 0; i < Stacks.Count; i++) { mergedStack = Stacks[i].Stack as MergedModifierStack; if (mergedStack != null) { mergedStack.End(tile, container); } } // yield return null; cb(); }
public static void AddSortRankToFeatures( this VectorTileLayer tile ) { for (int i = 0; i < tile.FeatureCount(); i++) { VectorTileFeature f = tile.GetFeature(i); } }
private void ParseLabelLayerToList(List <GOParsedLayer> list, VectorTile vt, GOLabelsLayer layer) { string[] lyrs = tile.GetLabelsStrings().Split(','); // string kindKey = tile.GetPoisKindKey(); foreach (string l in lyrs) { VectorTileLayer lyr = vt.GetLayer(l); if (lyr != null) { int featureCount = lyr.FeatureCount(); if (featureCount == 0) { continue; } GOParsedLayer pl = new GOParsedLayer(); pl.name = lyr.Name; pl.labelsLayer = layer; pl.goFeatures = new List <GOFeature> (); for (int i = 0; i < featureCount; i++) { VectorTileFeature vtf = lyr.GetFeature(i); IDictionary properties = vtf.GetProperties(); List <List <LatLng> > geomWgs = vtf.GeometryAsWgs84((ulong)goTile.zoomLevel, (ulong)goTile.tileCoordinates.x, (ulong)goTile.tileCoordinates.y, 0); if (geomWgs.Count == 0 || geomWgs[0].Count <= 1) { continue; } GOFeature gf = new GOFeature(); gf.properties = properties; gf.goFeatureType = vtf.GOFeatureType(geomWgs); gf.labelsLayer = layer; gf.featureIndex = (Int64)i + vt.LayerNames().IndexOf(lyr.Name); gf.goTile = goTile; gf = tile.EditLabelData(gf); gf.goFeatureType = GOFeatureType.Label; gf.ConvertAttributes(); if (geomWgs.Count > 0) { gf.geometry = geomWgs[0]; gf.ConvertGeometries(); gf.preloadedLabelData = GOSegment.FindTheLongestStreightSegment(gf.convertedGeometry, 0); AddFatureToList(gf, pl.goFeatures); } } list.Add(pl); } } }
public override void Create(VectorTileLayer layer, UnityTile tile) { _container = new GameObject(Key + " Container"); _container.transform.SetParent(tile.transform, false); var fc = layer.FeatureCount(); for (int i = 0; i < fc; i++) { var feature = new VectorFeatureUnity(layer.GetFeature(i, 0), tile); Build(feature, tile, _container); } }
public override void Create(VectorTileLayer layer, UnityTile tile) { Debug.LogWarning("PoiVisualer is deprecated. Use regular VectorLayerVisualizer and PrefabModifier."); _container = new GameObject(Key + " Container"); _container.transform.SetParent(tile.transform, false); var fc = layer.FeatureCount(); for (int i = 0; i < fc; i++) { var feature = new VectorFeatureUnity(layer.GetFeature(i, 0), tile, layer.Extent); Build(feature, tile, _container); } }
/// <summary> /// Creates an object for each layer, extract and filter in/out the features and runs Build method on them. /// </summary> /// <param name="layer"></param> /// <param name="tile"></param> public override void Create(VectorTileLayer layer, UnityTile tile) { _container = new GameObject(Key + " Container"); _container.transform.SetParent(tile.transform, false); //testing each feature with filters var fc = layer.FeatureCount(); var filterOut = false; for (int i = 0; i < fc; i++) { filterOut = false; var feature = new VectorFeatureUnity(layer.GetFeature(i, 0), tile, layer.Extent); foreach (var filter in Filters) { if (!string.IsNullOrEmpty(filter.Key) && !feature.Properties.ContainsKey(filter.Key)) { continue; } if (!filter.Try(feature)) { filterOut = true; break; } } if (!filterOut) { Build(feature, tile, _container); } } var mergedStack = _defaultStack as MergedModifierStack; if (mergedStack != null) { mergedStack.End(tile, _container); } foreach (var item in Stacks) { mergedStack = item.Stack as MergedModifierStack; if (mergedStack != null) { mergedStack.End(tile, _container); } } }
public void TestVectTile() { var pbf = File.ReadAllBytes(@"E:\Downloads\63.pbf"); VectorTile vt = new VectorTile(pbf, false); foreach (var layerName in vt.LayerNames()) { VectorTileLayer layer = vt.GetLayer(layerName); for (int j = 0; j < layer.FeatureCount(); j++) { VectorTileFeature feat = layer.GetFeature(j); var ff = feat.Geometry <long>(); var props = feat.GetProperties(); } } }
public override void Create(VectorTileLayer layer, Rect rect, Texture2D height, Transform parent, Tile.Parameters parameters) { _container = new GameObject("Buildings"); _container.transform.SetParent(parent, true); if (layer == null) { return; } for (int i = 0; i < layer.FeatureCount(); i++) { var feature = layer.GetFeature(i); Build(feature, rect, height, _container, parameters); } }
public static void DrawLayer(VectorTileLayer layer, Pallete pallete, Graphics graphics, double divisionRatio) { int featureCount = layer.FeatureCount(); for (int i = 0; i < featureCount; i++) { VectorTileFeature feature = layer.GetFeature(i); if (feature.GeometryType == GeomType.UNKNOWN) { Console.WriteLine("Unknown feature: " + feature); continue; } featureDrawDictionary[feature.GeometryType](feature, pallete, graphics, divisionRatio); } }
public static void CreateLayer(VectorTileLayer layer, Pallete pallete, Model3DGroup model3DGroup, Vector2 <int> shiftCoords) { int featureCount = layer.FeatureCount(); for (int i = 0; i < featureCount; i++) { VectorTileFeature feature = layer.GetFeature(i); if (feature.GeometryType == GeomType.UNKNOWN) { Console.WriteLine("Unknown feature: " + feature); continue; } featureCreateDictionary[feature.GeometryType](feature, pallete, model3DGroup, shiftCoords); } }
// Need check memory and disk existing because we can load road graph for path finding private void CacheRoads(Vector3 <double> lonLatZoom, VectorTileObj data) { if (memoryRoadsCache.ContainsKey(lonLatZoom.ToString())) { return; } if (diskRoadCache.TryGetValue(lonLatZoom.ToString(), out string path)) { memoryRoadsCache.TryAdd(lonLatZoom.ToString(), JsonConvert.DeserializeObject <Graph>(File.ReadAllText(path), settings)); return; } Graph graph; if (data.LayerNames().Contains("roads")) { VectorTileLayer layer = data.GetLayer("roads"); MaskGraphCreator maskDrawer = new MaskGraphCreator(GetTileSize(ConvertToMapZoom(Settings.zoom))); for (int i = 0; i < layer.FeatureCount(); i++) { VectorTileFeature feature = layer.GetFeature(i); foreach (List <Vector2 <int> > geometry in feature.Geometry <int>()) { for (int index = 1; index < geometry.Count; index++) { maskDrawer.DrawMaskLine(geometry[index - 1], geometry[index]); } } } graph = maskDrawer.GetGraph(); } else { graph = new Graph(); } memoryRoadsCache.TryAdd(lonLatZoom.ToString(), graph); // Save to disk path = $"{pathToDataFolder}\\roads\\{lonLatZoom.EncodeToString()}{RoadFileExtension}"; File.WriteAllText(path, JsonConvert.SerializeObject(graph, settings)); // Add to disk cache diskRoadCache.TryAdd(lonLatZoom.ToString(), path); }
public void FeatureSinglePoint() { byte[] data = File.ReadAllBytes(Path.Combine(fixturesPath, "Feature-single-point.mvt")); VectorTile vt = new VectorTile(data); Assert.AreEqual(1, vt.LayerNames().Count, "one layer"); VectorTileLayer lyr = vt.GetLayer(vt.LayerNames()[0]); Assert.AreEqual("layer_name", lyr.Name, "Layer name"); Assert.AreEqual(1, lyr.FeatureCount(), "Feature count"); VectorTileFeature feat = lyr.GetFeature(0); Assert.AreEqual(GeomType.POINT, feat.GeometryType, "Geometry type"); Assert.AreEqual(123, feat.Id, "id"); Dictionary <string, object> properties = feat.GetProperties(); Assert.AreEqual("world", properties["hello"]); Assert.AreEqual("world", feat.GetValue("hello")); }
IEnumerable <Location> GetLocations(VectorTileLayer layer, int x, int y, int z) { if (layer == null) { return(null); } var fc = layer.FeatureCount(); var locations = new List <Location>(); for (int i = 0; i < fc; i++) { var feature = layer.GetFeature(i); var properties = feature.GetProperties(); var points = feature.GeometryAsWgs84((ulong)z, (ulong)x, (ulong)y); //go.layer = LayerMask.NameToLayer(_key); if (!points.Any()) { continue; } int selpos = points[0].Count / 2; var met = Conversions.LatLonToMeters(points[0][selpos].Lat, points[0][selpos].Lng); if (!properties.ContainsKey("name")) { continue; } var location = ConvertToLocation(feature, points, properties); locations.Add(location); } return(locations); }
static int Main(string[] args) { //ul 14/4680/6260 //lr 14/4693/6274 ulong zoom = 14; ulong minCol = 4680; ulong minRow = 6260; ulong maxCol = 4693; ulong maxRow = 6274; string fixturePath = Path.Combine(Path.Combine(Path.Combine(Path.Combine(Path.Combine("..", ".."), ".."), "bench"), "mvt-bench-fixtures"), "fixtures"); if (!Directory.Exists(fixturePath)) { Console.Error.WriteLine("fixture directory not found: [{0}]", fixturePath); return(1); } ulong nrOfTiles = (maxCol - minCol + 1) * (maxRow - minRow + 1); List <TileData> tiles = new List <TileData>((int)nrOfTiles); for (ulong col = minCol; col <= maxCol; col++) { for (ulong row = minRow; row <= maxRow; row++) { string fileName = string.Format("{0}-{1}-{2}.mvt", zoom, col, row); fileName = Path.Combine(fixturePath, fileName); if (!File.Exists(fileName)) { Console.Error.WriteLine("fixture mvt not found: [{0}]", fileName); return(1); } else { tiles.Add(new TileData() { zoom = zoom, col = col, row = row, pbf = File.ReadAllBytes(fileName) }); } } } Stopwatch stopWatch = new Stopwatch(); List <long> elapsed = new List <long>(); for (int i = 0; i <= 100; i++) { Console.Write("."); stopWatch.Start(); foreach (var tile in tiles) { VectorTile vt = new VectorTile(tile.pbf, false); foreach (var layerName in vt.LayerNames()) { VectorTileLayer layer = vt.GetLayer(layerName); for (int j = 0; j < layer.FeatureCount(); j++) { VectorTileFeature feat = layer.GetFeature(j); var props = feat.GetProperties(); } } } stopWatch.Stop(); //skip first run if (i != 0) { elapsed.Add(stopWatch.ElapsedMilliseconds); } stopWatch.Reset(); } Console.WriteLine( @" runs : {0} tiles per run : {1} min [ms] : {2} max [ms] : {3} avg [ms] : {4} StdDev : {5:0.00} overall [ms] : {6} tiles/sec : {7:0.0} ", elapsed.Count, tiles.Count, elapsed.Min(), elapsed.Max(), elapsed.Average(), StdDev(elapsed), elapsed.Sum(), ((float)elapsed.Count * (float)tiles.Count / (float)elapsed.Sum()) * 1000 ); return(0); }
private void btnGo_Click(object sender, EventArgs e) { SynchronizationContext sync = SynchronizationContext.Current; lvInfo.Items.Clear(); int countReq = 0; int countResp = 0; FileSource fs = new FileSource(); //https://api.mapbox.com/v4/mapbox.mapbox-streets-v7/14/3410/6200.vector.pbf //https://api.mapbox.com/v4/mapbox.mapbox-streets-v7/14/3410/6200.vector.pbf //https://a.tiles.mapbox.com/v4/mapbox.mapbox-streets-v7/18/74984/100276.vector.pbf object locker = new object(); DateTime dtStart = DateTime.Now; System.Diagnostics.Debug.WriteLine(string.Format(" ============> WinForm, thread id:{0} <==============", System.Threading.Thread.CurrentThread.ManagedThreadId)); for (int i = (int)outerLoopStart.Value; i < (int)outerLoopStop.Value; i++) { for (int x = (int)tileXstart.Value; x < tileXstop.Value; x++) { countReq++; lblReqCnt.Text = countReq.ToString(); HTTPRequest request = (HTTPRequest)fs.Request( string.Format("https://a.tiles.mapbox.com/v4/mapbox.mapbox-streets-v7/18/{0}/100276.vector.pbf", x) , (Response r) => { System.Diagnostics.Debug.WriteLine(string.Format("winform response, thread id:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId)); //lock (locker) { countResp++; if (countResp == 1) { foreach (var hdr in r.Headers) { addItem(string.Format("{0}: {1}", hdr.Key, hdr.Value)); } } if (0 == countResp % 500) { Application.DoEvents(); } try { if (lblRespCnt.InvokeRequired) { System.Diagnostics.Debug.WriteLine(string.Format("winform lblRespCnt.InvokeRequired, thread id:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId)); //lblRespCnt.Invoke(new Action(() => { lblRespCnt.Text = countResp.ToString(); })); //Invoke((MethodInvoker)delegate { lblRespCnt.Text = countResp.ToString(); }); //sync.Send(delegate { lblRespCnt.Text = countResp.ToString(); }, null); //sync.Send(delegate { lblRespCnt.Text = countResp.ToString(); }, null); sync.Post(delegate { lblRespCnt.Text = countResp.ToString(); }, null); } else { System.Diagnostics.Debug.WriteLine(string.Format("winform !lblRespCnt.InvokeRequired, thread id:{0}", System.Threading.Thread.CurrentThread.ManagedThreadId)); lblRespCnt.Text = countResp.ToString(); } } catch (Exception ex) { addItem(ex.ToString()); } //} if (r.RateLimitHit) { addItem(string.Format("{3} statuscode:{4} rate limit hit:{5} --- LimitInterval:{0} LimitLimit:{1} LimitReset:{2}", r.XRateLimitInterval, r.XRateLimitLimit, r.XRateLimitReset, x, r.StatusCode, r.RateLimitHit)); } if (r.StatusCode != 200) { if (null != r.Data && r.Data.Length > 0) { addItem(Encoding.UTF8.GetString(r.Data)); } else { addItem(string.Format("StatusCode: {0} - NO body", r.StatusCode)); } } if (r.HasError) { addItem(""); foreach (var ex in r.Exceptions) { addItem(ex.ToString()); } addItem(""); return; } if (IDC_chkDecodeVTs.Checked) { try { VectorTile.VectorTile vt = new VectorTile.VectorTile(r.Data); foreach (var lyrName in vt.LayerNames()) { VectorTileLayer lyr = vt.GetLayer(lyrName); for (int j = 0; j < lyr.FeatureCount(); j++) { VectorTileFeature feat = lyr.GetFeature(j); feat.GetProperties(); feat.Geometry <int>(); } } } catch (Exception ex) { addItem(ex.ToString()); } } } ); } } addItem("waiting ..."); Application.DoEvents(); //while (!request.IsCompleted) { } fs.WaitForAllRequests(); DateTime dtFinished = DateTime.Now; addItem(string.Format("finished! requests:{0} responses:{1}", countReq, countResp)); addItem(string.Format( "{0} -> {1}, elapsed {2}s" , dtStart.ToString("HH:mm:ss") , dtFinished.ToString("HH:mm:ss") , dtFinished.Subtract(dtStart).TotalSeconds )); }
public void DifferentPoint2dTypesAndScaling() { string fullFileName = Path.Combine(fixturesPath, "Feature-single-linestring.mvt"); byte[] data = File.ReadAllBytes(fullFileName); VectorTile vt = new VectorTile(data); foreach (var layerName in vt.LayerNames()) { VectorTileLayer layer = vt.GetLayer(layerName); for (int i = 0; i < layer.FeatureCount(); i++) { VectorTileFeature featLong = layer.GetFeature(i); foreach (var geomPart in featLong.Geometry <long>()) { foreach (var coord in geomPart) { Debug.WriteLine("long: {0}/{1}", coord.X, coord.Y); } Assert.AreEqual(2L, geomPart[0].X); Assert.AreEqual(2L, geomPart[0].Y); Assert.AreEqual(2L, geomPart[1].X); Assert.AreEqual(10L, geomPart[1].Y); Assert.AreEqual(10L, geomPart[2].X); Assert.AreEqual(10L, geomPart[2].Y); } // don't clip, as this might change order of vertices // test 'scale' on the VectorTileFeature constructor VectorTileFeature featInt = layer.GetFeature(i, null, 1.5f); foreach (var geomPart in featInt.Geometry <int>()) { foreach (var coord in geomPart) { Debug.WriteLine("integer: {0}/{1}", coord.X, coord.Y); } Assert.AreEqual(3, geomPart[0].X); Assert.AreEqual(3, geomPart[0].Y); Assert.AreEqual(3, geomPart[1].X); Assert.AreEqual(15, geomPart[1].Y); Assert.AreEqual(15, geomPart[2].X); Assert.AreEqual(15, geomPart[2].Y); } // don't clip, as this might change order of vertices VectorTileFeature featFloat = layer.GetFeature(i); // test 'scale' on the Geometry method foreach (var geomPart in featFloat.Geometry <float>(null, 2.0f)) { foreach (var coord in geomPart) { Debug.WriteLine("float: {0}/{1}", coord.X, coord.Y); } Assert.AreEqual(4f, geomPart[0].X); Assert.AreEqual(4f, geomPart[0].Y); Assert.AreEqual(4f, geomPart[1].X); Assert.AreEqual(20f, geomPart[1].Y); Assert.AreEqual(20f, geomPart[2].X); Assert.AreEqual(20f, geomPart[2].Y); } } } string geojson = vt.ToGeoJson(0, 0, 0); Assert.GreaterOrEqual(geojson.Length, 30, "geojson >= 30 chars"); }
private void ParseGOLayerToList(List <GOParsedLayer> list, VectorTile vt, GOLayer layer) { string[] lyrs = tile.GetLayersStrings(layer).Split(','); foreach (string l in lyrs) { VectorTileLayer lyr = vt.GetLayer(l); if (lyr != null) { int featureCount = lyr.FeatureCount(); if (featureCount == 0) { continue; } GOParsedLayer pl = new GOParsedLayer(); pl.name = lyr.Name; pl.goLayer = layer; pl.goFeatures = new List <GOFeature> (); int indexOfLayer = vt.LayerNames().IndexOf(lyr.Name); for (int i = 0; i < featureCount; i++) { VectorTileFeature vtf = lyr.GetFeature(i); List <List <LatLng> > geomWgs = vtf.GeometryAsWgs84((ulong)goTile.zoomLevel, (ulong)goTile.tileCoordinates.x, (ulong)goTile.tileCoordinates.y, 0); GOFeature gf; if (layer.layerType == GOLayer.GOLayerType.Roads) { gf = new GORoadFeature(); } else { gf = new GOFeature(); } gf.properties = vtf.GetProperties(); gf.attributes = GOFeature.PropertiesToAttributes(gf.properties); gf.goFeatureType = vtf.GOFeatureType(geomWgs); gf.layer = layer; gf.featureIndex = (Int64)i; gf.layerIndex = indexOfLayer; gf.featureCount = featureCount; gf = tile.EditFeatureData(gf); gf.goTile = goTile; // gf.setRenderingOptions (); gf.ConvertAttributes(); if (geomWgs.Count > 0) { switch (gf.goFeatureType) { case GOFeatureType.Line: gf.geometry = geomWgs [0]; gf.ConvertGeometries(); AddFatureToList(gf, pl.goFeatures); break; case GOFeatureType.Polygon: gf.geometry = geomWgs[0]; gf.ConvertGeometries(); AddFatureToList(gf, pl.goFeatures); break; case GOFeatureType.MultiLine: foreach (IList geometry in geomWgs) { float indexMulti = (((float)geomWgs.IndexOf((List <LatLng>)geometry) + 1) * (i + 1) / geomWgs.Count); GOFeature gfm; if (layer.layerType == GOLayer.GOLayerType.Roads) { gfm = new GORoadFeature((GORoadFeature)gf); } else { gfm = new GOFeature(gf); } // gfm.index = indexMulti; gfm.geometry = geometry; gfm.ConvertGeometries(); AddFatureToList(gfm, pl.goFeatures); } break; case GOFeatureType.MultiPolygon: foreach (IList geometry in geomWgs) { List <Vector3> convertedSubject = null; List <List <Vector3> > convertedClips = new List <List <Vector3> >(); for (int j = 0; j < geomWgs.Count; j++) //Clip ascending { IList p = geomWgs [j]; List <Vector3> convertedP = GOFeature.CoordsToVerts(p, layer.layerType == GOLayer.GOLayerType.Buildings); if (GOFeature.IsClockwise(convertedP)) { convertedSubject = convertedP; } else { //Add clip convertedClips.Add(convertedP); } //Last one if (j == geomWgs.Count - 1 || (j < geomWgs.Count - 1 && GOFeature.IsGeoPolygonClockwise(geomWgs [j + 1]) && convertedSubject != null)) { GOFeature gfm = new GOFeature(gf); // gfm.index = (i +1)*j; gfm.convertedGeometry = convertedSubject; gfm.clips = convertedClips; AddFatureToList(gfm, pl.goFeatures); convertedSubject = null; convertedClips = new List <List <Vector3> >(); } } } break; } } } if (goTile.combineFeatures) { pl = GOCombineFeatures.Combine(pl); } list.Add(pl); } } }
private void ParsePOILayerToList(List <GOParsedLayer> list, VectorTile vt, GOPOILayer layer) { string[] lyrs = tile.GetPoisStrings().Split(','); string kindKey = tile.GetPoisKindKey(); foreach (string l in lyrs) { VectorTileLayer lyr = vt.GetLayer(l); if (lyr != null) { int featureCount = lyr.FeatureCount(); if (featureCount == 0) { continue; } GOParsedLayer pl = new GOParsedLayer(); pl.name = lyr.Name; pl.poiLayer = layer; pl.goFeatures = new List <GOFeature> (); for (int i = 0; i < featureCount; i++) { VectorTileFeature vtf = lyr.GetFeature(i); IDictionary properties = vtf.GetProperties(); GOPOIKind kind = GOEnumUtils.PoiKindToEnum((string)properties[kindKey]); GOPOIRendering rendering = layer.GetRenderingForPoiKind(kind); if (kind == GOPOIKind.UNDEFINED || rendering == null) { continue; } List <List <LatLng> > geomWgs = vtf.GeometryAsWgs84((ulong)goTile.zoomLevel, (ulong)goTile.tileCoordinates.x, (ulong)goTile.tileCoordinates.y, 0); GOFeature gf = new GOFeature(); gf.poiKind = kind; gf.goTile = goTile; gf.properties = properties; gf.attributes = GOFeature.PropertiesToAttributes(gf.properties); gf.goFeatureType = vtf.GOFeatureType(geomWgs); if (gf.goFeatureType == GOFeatureType.Undefined) { continue; } gf.poiLayer = layer; gf.poiRendering = rendering; gf.featureIndex = (Int64)i + vt.LayerNames().IndexOf(lyr.Name); gf = tile.EditFeatureData(gf); gf.ConvertAttributes(); if (geomWgs.Count > 0 && gf.goFeatureType == GOFeatureType.Point) { gf.geometry = geomWgs [0]; gf.ConvertPOIGeometries(); AddFatureToList(gf, pl.goFeatures); } } list.Add(pl); } } }
private IEnumerator ProcessLayer(VectorTileLayer layer, UnityTile tile, Action callback = null) { //HACK to prevent request finishing on same frame which breaks modules started/finished events yield return(null); if (tile == null) { yield break; } //testing each feature with filters var fc = layer.FeatureCount(); //Get all filters in the array. var filters = _layerProperties.filterOptions.filters.Select(m => m.GetFilterComparer()).ToArray(); // Pass them to the combiner Filters.ILayerFeatureFilterComparer combiner = new Filters.LayerFilterComparer(); switch (_layerProperties.filterOptions.combinerType) { case Filters.LayerFilterCombinerOperationType.Any: combiner = Filters.LayerFilterComparer.AnyOf(filters); break; case Filters.LayerFilterCombinerOperationType.All: combiner = Filters.LayerFilterComparer.AllOf(filters); break; case Filters.LayerFilterCombinerOperationType.None: combiner = Filters.LayerFilterComparer.NoneOf(filters); break; default: break; } for (int i = 0; i < fc; i++) { var buildingsWithUniqueIds = (_layerProperties.honorBuildingIdSetting) && _layerProperties.buildingsWithUniqueIds; var feature = new VectorFeatureUnity(layer.GetFeature(i), tile, layer.Extent, buildingsWithUniqueIds); //skip existing features, only works on tilesets with unique ids if (buildingsWithUniqueIds && _activeIds.Contains(feature.Data.Id)) { continue; } else { _activeIds.Add(feature.Data.Id); if (!_idPool.ContainsKey(tile)) { _idPool.Add(tile, new List <ulong>()); } else { _idPool[tile].Add(feature.Data.Id); } } if (filters.Length == 0) { // no filters, just build the features. if (tile != null && tile.gameObject != null && tile.VectorDataState != Enums.TilePropertyState.Cancelled) { Build(feature, tile, tile.gameObject); } _entityInCurrentCoroutine++; } else { // build features only if the filter returns true. if (combiner.Try(feature)) { if (tile != null && tile.gameObject != null && tile.VectorDataState != Enums.TilePropertyState.Cancelled) { Build(feature, tile, tile.gameObject); } _entityInCurrentCoroutine++; } } if (_performanceOptions != null && _performanceOptions.isEnabled && _entityInCurrentCoroutine >= _performanceOptions.entityPerCoroutine) { _entityInCurrentCoroutine = 0; yield return(null); } } var mergedStack = _defaultStack as MergedModifierStack; if (mergedStack != null && tile != null) { mergedStack.End(tile, tile.gameObject, layer.Name); } if (callback != null) { callback(); } }
public IEnumerator BuildLayer(VectorTileLayer layerData, GOLayer layer, bool delayedLoad) { Profiler.BeginSample("[GoMap] [BuildLayer] game object"); GameObject parent = null; if (transform.Find(layer.name) == null) { parent = new GameObject(); parent.name = layer.name; parent.transform.parent = this.transform; parent.SetActive(!layer.startInactive); } else { parent = transform.Find(layer.name).gameObject; } Profiler.EndSample(); int featureCount = layerData.FeatureCount(); if (featureCount == 0) { yield break; } List <GOFeature> stack = new List <GOFeature> (); //Caching variables.. VectorTileFeature feature; List <List <LatLng> > geomWgs84; //= new List<List<LatLng>>(); GOFeature goFeature; Dictionary <string, object> properties = null; List <KeyValue> attributes = null; List <Vector3> convertedGeometry = null; for (int i = 0; i < featureCount; i++) { feature = layerData.GetFeature(i); properties = feature.GetProperties(); geomWgs84 = feature.GeometryAsWgs84((ulong)map.zoomLevel, (ulong)tileCoordinates.x, (ulong)tileCoordinates.y, 0); attributes = GOFeature.PropertiesToAttributes(properties); if (geomWgs84.Count > 0) { convertedGeometry = GOFeature.CoordsToVerts(geomWgs84[0], false); } //get the feature (here is the actual protobuf conversion) goFeature = ParseFeatureData(feature, properties, layer, -1, -1); //8-11mb if (layer.useOnly.Length > 0 && !layer.useOnly.Contains(goFeature.kind)) { continue; } if (layer.avoid.Length > 0 && layer.avoid.Contains(goFeature.kind)) { continue; } if (layer.layerType == GOLayer.GOLayerType.Roads) { GORoadFeature grf = (GORoadFeature)goFeature; if ((grf.isBridge && !layer.useBridges) || (grf.isTunnel && !layer.useTunnels) || (grf.isLink && !layer.useBridges)) { continue; } } GOFeatureType gotype = feature.GOFeatureType(geomWgs84); if (gotype == GOFeatureType.Undefined || feature.GeometryType == GeomType.POINT) { continue; } if (feature.GeometryType == GeomType.POLYGON && layer.layerType == GOLayer.GOLayerType.Roads) { continue; } Int64 index = vt.LayerNames().IndexOf(layerData.Name) + 1; GOFeature gf; Profiler.BeginSample("[GoMap] [BuildLayer] IF"); if (gotype == GOFeatureType.MultiLine || (gotype == GOFeatureType.Polygon && !layer.isPolygon)) { Profiler.BeginSample("[GoMap] [BuildLayer] multi line"); foreach (IList geometry in geomWgs84) { float indexMulti = ((float)geomWgs84.IndexOf((List <LatLng>)geometry) / geomWgs84.Count); gf = ParseFeatureData(feature, properties, layer, Convert.ToInt64(i) + indexMulti, index); gf.geometry = geometry; gf.layer = layer; gf.parent = parent; gf.properties = properties; gf.ConvertGeometries(); gf.attributes = attributes; gf.goFeatureType = GOFeatureType.MultiLine; stack.Add(gf); } Profiler.EndSample(); } else if (gotype == GOFeatureType.Line) { Profiler.BeginSample("[GoMap] [BuildLayer] line"); gf = ParseFeatureData(feature, properties, layer, Convert.ToInt64(i), index); gf.geometry = geomWgs84 [0]; gf.layer = layer; gf.parent = parent; gf.properties = properties; gf.convertedGeometry = convertedGeometry; gf.attributes = attributes; gf.index = (Int64)i + vt.LayerNames().IndexOf(layerData.Name); gf.goFeatureType = GOFeatureType.Line; if (geomWgs84.Count == 0) { continue; } stack.Add(gf); Profiler.EndSample(); } else if (gotype == GOFeatureType.Polygon) { Profiler.BeginSample("[GoMap] [BuildLayer] polygon"); gf = ParseFeatureData(feature, properties, layer, Convert.ToInt64(i), index); gf.geometry = geomWgs84 [0]; gf.layer = layer; gf.parent = parent; gf.properties = properties; gf.convertedGeometry = convertedGeometry; gf.attributes = attributes; gf.index = (Int64)i + vt.LayerNames().IndexOf(layerData.Name); gf.goFeatureType = GOFeatureType.Polygon; stack.Add(gf); Profiler.EndSample(); } else if (gotype == GOFeatureType.MultiPolygon) { Profiler.BeginSample("[GoMap] [BuildLayer] multi polygon"); // GameObject multi = new GameObject ("MultiPolygon"); // multi.transform.parent = parent.transform; IList subject = null; IList clips = new List <List <LatLng> >(); for (int j = 0; j < geomWgs84.Count; j++) //Clip ascending { IList p = geomWgs84 [j]; if (GOFeature.IsGeoPolygonClockwise(p)) { subject = p; } else { //Add clip clips.Add(p); } //Last one if (j == geomWgs84.Count - 1 || (j < geomWgs84.Count - 1 && GOFeature.IsGeoPolygonClockwise(geomWgs84 [j + 1]) && subject != null)) { gf = ParseFeatureData(feature, properties, layer, Convert.ToInt64(i), index); gf.geometry = subject; gf.clips = clips; gf.layer = layer; gf.parent = parent; gf.properties = properties; gf.ConvertGeometries(); gf.attributes = attributes; gf.index = (Int64)i + vt.LayerNames().IndexOf(layerData.Name); gf.goFeatureType = GOFeatureType.MultiPolygon; stack.Add(gf); subject = null; clips = new List <List <LatLng> >(); } } Profiler.EndSample(); } Profiler.EndSample(); } Profiler.BeginSample("[GoMap] [BuildLayer] merge roads"); IList iStack = (IList)stack; if (layer.layerType == GOLayer.GOLayerType.Roads) { iStack = GORoadFeature.MergeRoads(iStack); // Debug.Log ("Roads: "+stack.Count+" Merged: "+iStack.Count); } Profiler.EndSample(); int n = 25; for (int i = 0; i < iStack.Count; i += n) { for (int k = 0; k < n; k++) { if (i + k >= iStack.Count) { yield return(null); break; } GOFeature r = (GOFeature)iStack [i + k]; IEnumerator routine = r.BuildFeature(this, delayedLoad); if (routine != null) { if (Application.isPlaying) { StartCoroutine(routine); } else { GORoutine.start(routine, this); } } } yield return(null); } Resources.UnloadUnusedAssets(); yield return(null); }
/// <summary> /// Return the whole vector tile as GeoJSON /// </summary> /// <param name="tile"></param> /// <param name="zoom">Zoom level of the tile</param> /// <param name="tileColumn">Column of the tile (OSM tile schema)</param> /// <param name="tileRow">Row of the tile (OSM tile schema)</param> /// <param name="clipBuffer"> /// <para>Vector tiles may contain data reaching beyond the actual tile border.</para> /// <para>Define if/how this data should be included.</para> /// <para>'null': data from the vector tile as is</para> /// <para>'>=0': clip distance in internal tile units</para> /// </param> /// <returns>GeoJSON of the vector tile contents</returns> public static string ToGeoJson( this VectorTileObj tile , ulong zoom , ulong tileColumn , ulong tileRow , uint?clipBuffer = null ) { //to get '.' instead of ',' when using "string.format" with double/float and non-US system number format settings //CultureInfo en_US = new CultureInfo("en-US"); // escaping '{' '}' -> @"{{" "}}" //escaping '"' -> @"""" string templateFeatureCollection = @"{{""type"":""FeatureCollection"",""features"":[{0}]}}"; string templateFeature = @"{{""type"":""Feature"",""geometry"":{{""type"":""{0}"",""coordinates"":[{1}]}},""properties"":{2}}}"; var geojsonFeatures = new List <string>(); foreach (string layerName in tile.LayerNames()) { VectorTileLayer layer = tile.GetLayer(layerName); for (int i = 0; i < layer.FeatureCount(); i++) { VectorTileFeature feat = layer.GetFeature(i, clipBuffer); if (feat.GeometryType == GeomType.UNKNOWN) { continue; } //resolve properties var keyValue = new List <string>(); int tagCnt = feat.Tags.Count; for (int j = 0; j < tagCnt; j += 2) { string key = layer.Keys[feat.Tags[j]]; object val = layer.Values[feat.Tags[j + 1]]; keyValue.Add(string.Format(NumberFormatInfo.InvariantInfo, @"""{0}"":""{1}""", key, val)); } //build geojson properties object from resolved properties string geojsonProps = string.Format( NumberFormatInfo.InvariantInfo , @"{{""id"":{0},""lyr"":""{1}""{2}{3}}}" , feat.Id , layer.Name , keyValue.Count > 0 ? "," : "" , string.Join(",", keyValue.ToArray()) ); //work through geometries string geojsonCoords = ""; string geomType = feat.GeometryType.Description(); //multipart List <List <LatLng> > geomWgs84 = feat.GeometryAsWgs84(zoom, tileColumn, tileRow); if (geomWgs84.Count > 1) { switch (feat.GeometryType) { case GeomType.POINT: geomType = "MultiPoint"; geojsonCoords = string.Join( "," , geomWgs84 .SelectMany(g => g) .Select(g => string.Format(NumberFormatInfo.InvariantInfo, "[{0},{1}]", g.Lng, g.Lat)) .ToArray() ); break; case GeomType.LINESTRING: geomType = "MultiLineString"; var parts = new List <string>(); foreach (List <LatLng> part in geomWgs84) { parts.Add("[" + string.Join( "," , part.Select(g => string.Format(NumberFormatInfo.InvariantInfo, "[{0},{1}]", g.Lng, g.Lat)).ToArray() ) + "]"); } geojsonCoords = string.Join(",", parts.ToArray()); break; case GeomType.POLYGON: geomType = "MultiPolygon"; var partsMP = new List <string>(); foreach (List <LatLng> part in geomWgs84) { partsMP.Add("[" + string.Join( ",", part.Select(g => string.Format(NumberFormatInfo.InvariantInfo, "[{0},{1}]", g.Lng, g.Lat)).ToArray() ) + "]"); } geojsonCoords = "[" + string.Join(",", partsMP.ToArray()) + "]"; break; } } else if (geomWgs84.Count == 1) { //singlepart switch (feat.GeometryType) { case GeomType.POINT: geojsonCoords = string.Format(NumberFormatInfo.InvariantInfo, "{0},{1}", geomWgs84[0][0].Lng, geomWgs84[0][0].Lat); break; case GeomType.LINESTRING: geojsonCoords = string.Join( ",", geomWgs84[0].Select(g => string.Format(NumberFormatInfo.InvariantInfo, "[{0},{1}]", g.Lng, g.Lat)) .ToArray() ); break; case GeomType.POLYGON: geojsonCoords = "[" + string.Join( ",", geomWgs84[0].Select(g => string.Format(NumberFormatInfo.InvariantInfo, "[{0},{1}]", g.Lng, g.Lat)).ToArray() ) + "]"; break; } } else { //no geometry continue; } geojsonFeatures.Add( string.Format( NumberFormatInfo.InvariantInfo , templateFeature , geomType , geojsonCoords , geojsonProps ) ); } } string geoJsonFeatColl = string.Format( NumberFormatInfo.InvariantInfo , templateFeatureCollection , string.Join(",", geojsonFeatures.ToArray()) ); return(geoJsonFeatColl); }
private IEnumerator ProcessLayer(VectorTileLayer layer, UnityTile tile, Action callback = null) { //HACK to prevent request finishing on same frame which breaks modules started/finished events yield return(null); if (tile == null) { yield break; } //testing each feature with filters var fc = layer.FeatureCount(); var filterOut = false; for (int i = 0; i < fc; i++) { filterOut = false; var feature = new VectorFeatureUnity(layer.GetFeature(i, 0), tile, layer.Extent); foreach (var filter in Filters) { if (!string.IsNullOrEmpty(filter.Key) && !feature.Properties.ContainsKey(filter.Key)) { continue; } if (!filter.Try(feature)) { filterOut = true; break; } } if (!filterOut) { if (tile != null && tile.gameObject != null && tile.VectorDataState != Enums.TilePropertyState.Cancelled) { Build(feature, tile, tile.gameObject); } } _entityInCurrentCoroutine++; if (_enableCoroutines && _entityInCurrentCoroutine >= _entityPerCoroutine) { _entityInCurrentCoroutine = 0; yield return(null); } } var mergedStack = _defaultStack as MergedModifierStack; if (mergedStack != null && tile != null) { mergedStack.End(tile, tile.gameObject, layer.Name); } foreach (var item in Stacks) { mergedStack = item.Stack as MergedModifierStack; if (mergedStack != null) { mergedStack.End(tile, tile.gameObject, layer.Name); } } if (callback != null) { callback(); } }
private void ParseTilesetsToList(List <GOParsedLayer> list, VectorTile vt, GOTilesetLayer[] tilesets) { foreach (GOTilesetLayer tileSet in tilesets) { string kind = string.IsNullOrEmpty(tileSet.TilesetKindProperty)? tileSet.TilesetKindProperty : "kind"; VectorTileLayer lyr = vt.GetLayer(tileSet.TilesetName); if (lyr != null) { int featureCount = lyr.FeatureCount(); if (featureCount == 0) { continue; } GOParsedLayer pl = new GOParsedLayer(); pl.name = lyr.Name; pl.tilesetLayer = tileSet; pl.goFeatures = new List <GOFeature>(); for (int i = 0; i < featureCount; i++) { VectorTileFeature vtf = lyr.GetFeature(i); List <List <LatLng> > geomWgs = vtf.GeometryAsWgs84((ulong)goTile.zoomLevel, (ulong)goTile.tileCoordinates.x, (ulong)goTile.tileCoordinates.y, 0); GOFeature gf = new GOFeature(); gf.properties = vtf.GetProperties(); gf.attributes = GOFeature.PropertiesToAttributes(gf.properties); gf.goFeatureType = vtf.GOFeatureType(geomWgs); gf.tileSetKind = kind; gf.tilesetLayer = tileSet; gf.goTile = goTile; gf.featureIndex = (Int64)i; //gf.layerIndex = indexOfLayer; gf.featureCount = featureCount; //gf = tile.EditFeatureData(gf); gf.goTile = goTile; gf.ConvertAttributes(); if (gf.goFeatureType == GOFeatureType.Undefined) { continue; } string name = "Dataset " + gf.goFeatureType.ToString(); //Debug.Log(name); if (geomWgs.Count > 0 && (gf.goFeatureType == GOFeatureType.Point || gf.goFeatureType == GOFeatureType.MultiPoint)) //Probably needs a fix for multi points { //GOPOIKind kind = GOEnumUtils.PoiKindToEnum((string)properties[kindKey]); GOTilesetPOIRendering rendering = tileSet.TilesetPOIRenderingForKind(kind); if (rendering == null) { continue; } gf.geometry = geomWgs[0]; gf.tileSetPoiRendering = rendering; gf.name = name; gf.ConvertPOIGeometries(); AddFatureToList(gf, pl.goFeatures); } else if (geomWgs.Count > 0) { switch (gf.goFeatureType) { case GOFeatureType.Line: GOTilesetLINERendering lineRendering = tileSet.TilesetLINERenderingForKind(kind); if (lineRendering == null) { continue; } gf.geometry = geomWgs[0]; gf.ConvertGeometries(); gf.tileSetLineRendering = lineRendering; gf.name = name; gf.height = lineRendering.height; AddFatureToList(gf, pl.goFeatures); break; case GOFeatureType.Polygon: GOTilesetPOLYGONRendering polygonRendering = tileSet.TilesetPOLYGONRenderingForKind(kind); if (polygonRendering == null) { continue; } gf.geometry = geomWgs[0]; gf.ConvertGeometries(); gf.name = name; gf.tileSetPolygonRendering = polygonRendering; gf.height = polygonRendering.height; AddFatureToList(gf, pl.goFeatures); break; case GOFeatureType.MultiLine: lineRendering = tileSet.TilesetLINERenderingForKind(kind); if (lineRendering == null) { continue; } foreach (IList geometry in geomWgs) { float indexMulti = (((float)geomWgs.IndexOf((List <LatLng>)geometry) + 1) * (i + 1) / geomWgs.Count); GOFeature gfm = new GOFeature(gf); gf.name = name; gfm.geometry = geometry; gfm.ConvertGeometries(); gf.tileSetLineRendering = lineRendering; gf.height = lineRendering.height; AddFatureToList(gfm, pl.goFeatures); } break; case GOFeatureType.MultiPolygon: foreach (IList geometry in geomWgs) { polygonRendering = tileSet.TilesetPOLYGONRenderingForKind(kind); if (polygonRendering == null) { continue; } List <Vector3> convertedSubject = null; List <List <Vector3> > convertedClips = new List <List <Vector3> >(); for (int j = 0; j < geomWgs.Count; j++) { //Clip ascending IList p = geomWgs[j]; List <Vector3> convertedP = GOFeature.CoordsToVerts(p, false); if (GOFeature.IsClockwise(convertedP)) { convertedSubject = convertedP; } else { //Add clip convertedClips.Add(convertedP); } //Last one if (j == geomWgs.Count - 1 || (j < geomWgs.Count - 1 && GOFeature.IsGeoPolygonClockwise(geomWgs[j + 1]) && convertedSubject != null)) { GOFeature gfm = new GOFeature(gf); // gfm.index = (i +1)*j; gfm.convertedGeometry = convertedSubject; gfm.clips = convertedClips; gf.tileSetPolygonRendering = polygonRendering; gf.name = name; AddFatureToList(gfm, pl.goFeatures); convertedSubject = null; convertedClips = new List <List <Vector3> >(); } } } break; } } } list.Add(pl); } } }