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 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 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"); }
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"); } } } } } }
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 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")); }
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 void Validate(string fileName) { string fullFileName = Path.Combine(_fixturesPath, fileName); Assert.True(File.Exists(fullFileName), "Vector tile exists"); byte[] data = File.ReadAllBytes(fullFileName); Assert.Throws(Is.InstanceOf <Exception>(), () => { VectorTile vt = new VectorTile(data); foreach (var layerName in vt.LayerNames()) { var layer = vt.GetLayer(layerName); for (int i = 0; i < layer.FeatureCount(); i++) { var feat = layer.GetFeature(i); feat.GetProperties(); } } }); }
public void IterateAllProperties(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()) { var layer = vt.GetLayer(layerName); for (int i = 0; i < layer.FeatureCount(); i++) { var feat = layer.GetFeature(i); var properties = feat.GetProperties(); foreach (var prop in properties) { Assert.IsInstanceOf <string>(prop.Key); } } } }
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); } } }
/// <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 VectorTile 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}}}"; List <string> geojsonFeatures = new List <string>(); foreach (var layerName in tile.LayerNames()) { var layer = tile.GetLayer(layerName); for (int i = 0; i < layer.FeatureCount(); i++) { var feat = layer.GetFeature(i, clipBuffer); if (feat.GeometryType == GeomType.UNKNOWN) { continue; } //resolve properties List <string> keyValue = new List <string>(); for (int j = 0; j < feat.Tags.Count; 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"; #if NET20 List <LatLng> allPoints = new List <LatLng>(); foreach (var part in geomWgs84) { foreach (var pnt in part) { allPoints.Add(pnt); } } geojsonCoords = string.Join( "," , allPoints.ConvertAll <string>(g => string.Format(NumberFormatInfo.InvariantInfo, "[{0},{1}]", g.Lng, g.Lat)).ToArray() ); #else geojsonCoords = string.Join( "," , geomWgs84 .SelectMany((List <LatLng> g) => g) .Select(g => string.Format(NumberFormatInfo.InvariantInfo, "[{0},{1}]", g.Lng, g.Lat)).ToArray() ); #endif break; case GeomType.LINESTRING: geomType = "MultiLineString"; List <string> parts = new List <string>(); foreach (var part in geomWgs84) { parts.Add("[" + string.Join( "," #if NET20 , part.ConvertAll <string>(g => string.Format(NumberFormatInfo.InvariantInfo, "[{0},{1}]", g.Lng, g.Lat)).ToArray() #else , part.Select(g => string.Format(NumberFormatInfo.InvariantInfo, "[{0},{1}]", g.Lng, g.Lat)).ToArray() #endif ) + "]"); } geojsonCoords = string.Join(",", parts.ToArray()); break; case GeomType.POLYGON: geomType = "MultiPolygon"; List <string> partsMP = new List <string>(); foreach (var part in geomWgs84) { partsMP.Add("[" + string.Join( "," #if NET20 , part.ConvertAll <string>(g => string.Format(NumberFormatInfo.InvariantInfo, "[{0},{1}]", g.Lng, g.Lat)).ToArray() #else , part.Select(g => string.Format(NumberFormatInfo.InvariantInfo, "[{0},{1}]", g.Lng, g.Lat)).ToArray() #endif ) + "]"); } geojsonCoords = "[" + string.Join(",", partsMP.ToArray()) + "]"; break; default: 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( "," #if NET20 , geomWgs84[0].ConvertAll <string>(g => string.Format(NumberFormatInfo.InvariantInfo, "[{0},{1}]", g.Lng, g.Lat)).ToArray() #else , geomWgs84[0].Select(g => string.Format(NumberFormatInfo.InvariantInfo, "[{0},{1}]", g.Lng, g.Lat)).ToArray() #endif ); break; case GeomType.POLYGON: geojsonCoords = "[" + string.Join( "," #if NET20 , geomWgs84[0].ConvertAll <string>(g => string.Format(NumberFormatInfo.InvariantInfo, "[{0},{1}]", g.Lng, g.Lat)).ToArray() #else , geomWgs84[0].Select(g => string.Format(NumberFormatInfo.InvariantInfo, "[{0},{1}]", g.Lng, g.Lat)).ToArray() #endif ) + "]"; break; default: 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); }
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); }
public string[] SelectLayerNames(VectorTile tile) { // names: railway, road, building, label, symbol, contour, elevation, landforml, transl return(tile.LayerNames().ToArray()); }
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); } } }
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"); }
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); }