/// <summary> /// Initialize VectorTileFeature /// </summary> /// <param name="layer">Parent <see cref="VectorTileLayer"/></param> public VectorTileFeature(VectorTileLayer layer, uint?clipBuffer = null, float scale = 1.0f) { _layer = layer; _clipBuffer = clipBuffer; _scale = scale; Tags = new List <int>(); }
/// <summary> /// Get a feature of the <see cref="VectorTileLayer"/> /// </summary> /// <param name="layer"><see cref="VectorTileLayer"/> containing the feature</param> /// <param name="data">Raw byte data of the feature</param> /// <param name="validate">If true, run checks if the tile contains valid data. Decreases decoding speed.</param> /// <param name="clippBuffer"> /// <para>'null': returns the geometries unaltered as they are in the vector tile. </para> /// <para>Any value >=0 clips a border with the size around the tile. </para> /// <para>These are not pixels but the same units as the 'extent' of the layer. </para> /// </param> /// <returns></returns> public static VectorTileFeature GetFeature( VectorTileLayer layer , byte[] data , bool validate = true , uint?clippBuffer = null ) { PbfReader featureReader = new PbfReader(data); VectorTileFeature feat = new VectorTileFeature(layer); bool geomTypeSet = false; while (featureReader.NextByte()) { int featureType = featureReader.Tag; if (validate) { if (!ConstantsAsDictionary.FeatureType.ContainsKey(featureType)) { throw new System.Exception(string.Format("Layer [{0}] has unknown feature type: {1}", layer.Name, featureType)); } } switch ((FeatureType)featureType) { case FeatureType.Id: feat.Id = (ulong)featureReader.Varint(); break; case FeatureType.Tags: #if NET20 List <int> tags = featureReader.GetPackedUnit32().ConvertAll <int>(ui => (int)ui); #else List <int> tags = featureReader.GetPackedUnit32().Select(t => (int)t).ToList(); #endif feat.Tags = tags; break; case FeatureType.Type: int geomType = (int)featureReader.Varint(); if (validate) { if (!ConstantsAsDictionary.GeomType.ContainsKey(geomType)) { throw new System.Exception(string.Format("Layer [{0}] has unknown geometry type tag: {1}", layer.Name, geomType)); } } feat.GeometryType = (GeomType)geomType; geomTypeSet = true; break; case FeatureType.Geometry: if (null != feat.Geometry) { throw new System.Exception(string.Format("Layer [{0}], feature already has a geometry", layer.Name)); } //get raw array of commands and coordinates List <uint> geometryCommands = featureReader.GetPackedUnit32(); //decode commands and coordinates List <List <Point2d> > geom = DecodeGeometry.GetGeometry( layer.Extent , feat.GeometryType , geometryCommands ); if (clippBuffer.HasValue) { geom = clipGeometries(geom, feat.GeometryType, (long)layer.Extent, clippBuffer.Value); } feat.Geometry = geom; break; default: featureReader.Skip(); break; } } if (validate) { if (!geomTypeSet) { throw new System.Exception(string.Format("Layer [{0}]: feature missing geometry type", layer.Name)); } if (null == feat.Geometry) { throw new System.Exception(string.Format("Layer [{0}]: feature has no geometry", layer.Name)); } if (0 != feat.Tags.Count % 2) { throw new System.Exception(string.Format("Layer [{0}]: uneven number of feature tag ids", layer.Name)); } if (feat.Tags.Count > 0) { #if NET20 int maxKeyIndex = -9999; for (int i = 0; i < feat.Tags.Count; i += 2) { if (feat.Tags[i] > maxKeyIndex) { maxKeyIndex = feat.Tags[i]; } } int maxValueIndex = -9999; for (int i = 1; i < feat.Tags.Count; i += 2) { if (feat.Tags[i] > maxValueIndex) { maxValueIndex = feat.Tags[i]; } } #else int maxKeyIndex = feat.Tags.Where((key, idx) => idx % 2 == 0).Max(); int maxValueIndex = feat.Tags.Where((key, idx) => (idx + 1) % 2 == 0).Max(); #endif if (maxKeyIndex >= layer.Keys.Count) { throw new System.Exception(string.Format("Layer [{0}]: maximum key index equal or greater number of key elements", layer.Name)); } if (maxValueIndex >= layer.Values.Count) { throw new System.Exception(string.Format("Layer [{0}]: maximum value index equal or greater number of value elements", layer.Name)); } } } return(feat); }
private VectorTileLayer getLayer(byte[] data) { VectorTileLayer layer = new VectorTileLayer(data); PbfReader layerReader = new PbfReader(layer.Data); while (layerReader.NextByte()) { int layerType = layerReader.Tag; if (_Validate) { if (!ConstantsAsDictionary.LayerType.ContainsKey(layerType)) { throw new System.Exception(string.Format("Unknown layer type: {0}", layerType)); } } switch ((LayerType)layerType) { case LayerType.Version: ulong version = (ulong)layerReader.Varint(); layer.Version = version; break; case LayerType.Name: ulong strLength = (ulong)layerReader.Varint(); layer.Name = layerReader.GetString(strLength); break; case LayerType.Extent: layer.Extent = (ulong)layerReader.Varint(); break; case LayerType.Keys: byte[] keyBuffer = layerReader.View(); string key = Encoding.UTF8.GetString(keyBuffer, 0, keyBuffer.Length); layer.Keys.Add(key); break; case LayerType.Values: byte[] valueBuffer = layerReader.View(); PbfReader valReader = new PbfReader(valueBuffer); while (valReader.NextByte()) { switch ((ValueType)valReader.Tag) { case ValueType.String: byte[] stringBuffer = valReader.View(); string value = Encoding.UTF8.GetString(stringBuffer, 0, stringBuffer.Length); layer.Values.Add(value); break; case ValueType.Float: float snglVal = valReader.GetFloat(); layer.Values.Add(snglVal); break; case ValueType.Double: double dblVal = valReader.GetDouble(); layer.Values.Add(dblVal); break; case ValueType.Int: long i64 = valReader.Varint(); layer.Values.Add(i64); break; case ValueType.UInt: long u64 = valReader.Varint(); layer.Values.Add(u64); break; case ValueType.SInt: long s64 = valReader.Varint(); layer.Values.Add(s64); break; case ValueType.Bool: long b = valReader.Varint(); layer.Values.Add(b == 1); break; default: throw new System.Exception(string.Format( NumberFormatInfo.InvariantInfo , "NOT IMPLEMENTED valueReader.Tag:{0} valueReader.WireType:{1}" , valReader.Tag , valReader.WireType )); //uncomment the following lines when not throwing!! //valReader.Skip(); //break; } } break; case LayerType.Features: layer.AddFeatureData(layerReader.View()); break; default: layerReader.Skip(); break; } } if (_Validate) { if (string.IsNullOrEmpty(layer.Name)) { throw new System.Exception("Layer has no name"); } if (0 == layer.Version) { throw new System.Exception(string.Format("Layer [{0}] has invalid version. Only version 2.x of 'Mapbox Vector Tile Specification' (https://github.com/mapbox/vector-tile-spec) is supported.", layer.Name)); } if (2 != layer.Version) { throw new System.Exception(string.Format("Layer [{0}] has invalid version: {1}. Only version 2.x of 'Mapbox Vector Tile Specification' (https://github.com/mapbox/vector-tile-spec) is supported.", layer.Name, layer.Version)); } if (0 == layer.Extent) { throw new System.Exception(string.Format("Layer [{0}] has no extent.", layer.Name)); } if (0 == layer.FeatureCount()) { throw new System.Exception(string.Format("Layer [{0}] has no features.", layer.Name)); } //TODO: find equivalent of 'Distinct()' for NET20 #if !NET20 if (layer.Values.Count != layer.Values.Distinct().Count()) { throw new System.Exception(string.Format("Layer [{0}]: duplicate attribute values found", layer.Name)); } #endif } return(layer); }
/// <summary> /// Initialize VectorTileFeature /// </summary> /// <param name="layer">Parent <see cref="VectorTileLayer"/></param> public VectorTileFeature(VectorTileLayer layer) { _Layer = layer; Tags = new List <int>(); }
public static int Main(string[] args) { string vtIn = string.Empty; uint? clipBuffer = null; bool outGeoJson = false; ulong? zoom = null; ulong? tileCol = null; ulong? tileRow = null; for (int i = 0; i < args.Length; i++) { string argLow = args[i].ToLower(); if (argLow.Contains("vt:")) { vtIn = argLow.Replace("vt:", ""); } else if (argLow.Contains("clip:")) { clipBuffer = Convert.ToUInt32(argLow.Replace("clip:", "")); } else if (argLow.Contains("out:")) { outGeoJson = argLow.Replace("out:", "").Equals("geojson"); } else if (argLow.Contains("tileid:")) { parseArg(argLow.Replace("tileid:", ""), out zoom, out tileCol, out tileRow); } } if (!File.Exists(vtIn)) { Console.WriteLine($"file [{vtIn}] not found"); usage(); return(1); } // z-x-y weren't passed via parameters, try to get them from file name if (!zoom.HasValue || !tileCol.HasValue || !tileRow.HasValue) { if (!parseArg(Path.GetFileName(vtIn), out zoom, out tileCol, out tileRow)) { usage(); return(1); } } var bufferedData = File.ReadAllBytes(vtIn); VectorTile tile = new VectorTile(bufferedData); if (outGeoJson) { Console.WriteLine(tile.ToGeoJson(zoom.Value, tileCol.Value, tileRow.Value, clipBuffer)); } else { foreach (string lyrName in tile.LayerNames()) { VectorTileLayer lyr = tile.GetLayer(lyrName); Console.WriteLine(string.Format("------------ {0} ---------", lyrName)); //if (lyrName != "building") { continue; } int featCnt = lyr.FeatureCount(); for (int i = 0; i < featCnt; i++) { VectorTileFeature feat = lyr.GetFeature(i, clipBuffer); Console.WriteLine(string.Format("feature {0}: {1}", i, feat.GeometryType)); Dictionary <string, object> props = feat.GetProperties(); foreach (var prop in props) { Console.WriteLine(string.Format(" {0}\t : ({1}) {2}", prop.Key, prop.Value.GetType(), prop.Value)); } } } } return(0); }