/// <summary> /// Writes the tile to the given stream. /// </summary> /// <param name="vectorTile">The vector tile.</param> /// <param name="stream">The stream to write to.</param> /// <param name="extent">The extent.</param> public static void Write(this VectorTile vectorTile, Stream stream, uint extent = 4096) { var tile = new Tiles.Tile(vectorTile.TileId); double latitudeStep = (tile.Top - tile.Bottom) / extent; double longitudeStep = (tile.Right - tile.Left) / extent; double top = tile.Top; double left = tile.Left; var mapboxTile = new Mapbox.Tile(); foreach (var localLayer in vectorTile.Layers) { var layer = new Mapbox.Tile.Layer { Version = 2, Name = localLayer.Name, Extent = extent }; var keys = new Dictionary <string, uint>(); var values = new Dictionary <string, uint>(); foreach (var localLayerFeature in localLayer.Features) { if (localLayerFeature.Geometry is Point p) { var feature = new Mapbox.Tile.Feature(); var posX = (int)((p.X - left) / longitudeStep); var posY = (int)((top - p.Y) / latitudeStep); GenerateMoveTo(feature.Geometry, posX, posY); feature.Type = Tile.GeomType.Point; AddAttributes(feature.Tags, keys, values, localLayerFeature.Attributes); layer.Features.Add(feature); } else if (localLayerFeature.Geometry is LineString ls) { var feature = new Mapbox.Tile.Feature(); var posX = (int)((ls.Coordinates[0].X - left) / longitudeStep); var posY = (int)((top - ls.Coordinates[0].Y) / latitudeStep); GenerateMoveTo(feature.Geometry, posX, posY); // generate line to. feature.Geometry.Add(GenerateCommandInteger(2, ls.Coordinates.Length - 1)); for (var j = 1; j < ls.Coordinates.Length; j++) { var localPosX = (int)((ls.Coordinates[j].X - left) / longitudeStep); var localPosY = (int)((top - ls.Coordinates[j].Y) / latitudeStep); var dx = localPosX - posX; var dy = localPosY - posY; posX = localPosX; posY = localPosY; feature.Geometry.Add(GenerateParameterInteger(dx)); feature.Geometry.Add(GenerateParameterInteger(dy)); } feature.Type = Tile.GeomType.LineString; AddAttributes(feature.Tags, keys, values, localLayerFeature.Attributes); layer.Features.Add(feature); } } layer.Keys.AddRange(keys.Keys); foreach (var value in values.Keys) { if (int.TryParse(value, out var intValue)) { layer.Values.Add(new Tile.Value() { IntValue = intValue }); } else if (float.TryParse(value, out var floatValue)) { layer.Values.Add(new Tile.Value() { FloatValue = floatValue }); } else { layer.Values.Add(new Tile.Value() { StringValue = value }); } } mapboxTile.Layers.Add(layer); } ProtoBuf.Serializer.Serialize <Tile>(stream, mapboxTile); }
/// <summary> /// Writes the tile to the given stream. /// </summary> public static void Write(this VectorTile vectorTile, Stream stream, Func <IAttributeCollection, Itinero.VectorTiles.Layers.Layer, IAttributeCollection> mapAttributes = null, uint extent = 4096) { var tile = new Tiles.Tile(vectorTile.TileId); double latitudeStep = (tile.Top - tile.Bottom) / extent; double longitudeStep = (tile.Right - tile.Left) / extent; double top = tile.Top; double left = tile.Left; var mapboxTile = new Mapbox.Tile(); foreach (var localLayer in vectorTile.Layers) { var layer = new Mapbox.Tile.Layer(); layer.Version = 2; layer.Name = localLayer.Name; layer.Extent = extent; var keys = new Dictionary <string, uint>(); var values = new Dictionary <string, uint>(); if (localLayer is SegmentLayer) { var segmentLayer = localLayer as SegmentLayer; var segments = segmentLayer.Segments; var edgeProfile = segmentLayer.Profiles; var edgeMeta = segmentLayer.Meta; for (var i = 0; i < segments.Length; i++) { var feature = new Mapbox.Tile.Feature(); var shape = segments[i].Shape; var posX = (int)((shape[0].Longitude - left) / longitudeStep); var posY = (int)((top - shape[0].Latitude) / latitudeStep); GenerateMoveTo(feature.Geometry, posX, posY); // generate line to. feature.Geometry.Add(GenerateCommandInteger(2, shape.Length - 1)); for (var j = 1; j < shape.Length; j++) { var localPosX = (int)((shape[j].Longitude - left) / longitudeStep); var localPosY = (int)((top - shape[j].Latitude) / latitudeStep); var dx = localPosX - posX; var dy = localPosY - posY; posX = localPosX; posY = localPosY; feature.Geometry.Add(GenerateParameterInteger(dx)); feature.Geometry.Add(GenerateParameterInteger(dy)); } feature.Type = Tile.GeomType.LineString; if (mapAttributes != null) { IAttributeCollection attributes = new AttributeCollection(edgeProfile.Get(segments[i].Profile)); var meta = edgeMeta.Get(segments[i].Meta); foreach (var a in meta) { attributes.AddOrReplace(a); } attributes = mapAttributes(attributes, localLayer); foreach (var attribute in attributes) { uint keyId; if (!keys.TryGetValue(attribute.Key, out keyId)) { keyId = (uint)keys.Count; keys.Add(attribute.Key, keyId); } uint valueId; if (!values.TryGetValue(attribute.Value, out valueId)) { valueId = (uint)values.Count; values.Add(attribute.Value, valueId); } feature.Tags.Add(keyId); feature.Tags.Add(valueId); } } else { var profile = edgeProfile.Get(segments[i].Profile); if (profile != null) { foreach (var attribute in profile) { uint keyId; if (!keys.TryGetValue(attribute.Key, out keyId)) { keyId = (uint)keys.Count; keys.Add(attribute.Key, keyId); } uint valueId; if (!values.TryGetValue(attribute.Value, out valueId)) { valueId = (uint)values.Count; values.Add(attribute.Value, valueId); } feature.Tags.Add(keyId); feature.Tags.Add(valueId); } } var meta = edgeMeta.Get(segments[i].Meta); if (meta != null) { foreach (var attribute in meta) { uint keyId; if (!keys.TryGetValue(attribute.Key, out keyId)) { keyId = (uint)keys.Count; keys.Add(attribute.Key, keyId); } uint valueId; if (!values.TryGetValue(attribute.Value, out valueId)) { valueId = (uint)values.Count; values.Add(attribute.Value, valueId); } feature.Tags.Add(keyId); feature.Tags.Add(valueId); } } } layer.Features.Add(feature); } } else if (localLayer is StopLayer) { var pointLayer = localLayer as StopLayer; var points = pointLayer.Points; var metaIndex = pointLayer.Meta; for (var i = 0; i < points.Length; i++) { var point = points[i]; var feature = new Mapbox.Tile.Feature(); var posX = (int)((point.Longitude - left) / longitudeStep); var posY = (int)((top - point.Latitude) / latitudeStep); GenerateMoveTo(feature.Geometry, posX, posY); feature.Type = Tile.GeomType.Point; var attributes = metaIndex.Get(point.MetaId); if (mapAttributes != null) { attributes = mapAttributes(attributes, localLayer); } if (attributes != null) { foreach (var attribute in attributes) { uint keyId; if (!keys.TryGetValue(attribute.Key, out keyId)) { keyId = (uint)keys.Count; keys.Add(attribute.Key, keyId); } uint valueId; if (!values.TryGetValue(attribute.Value, out valueId)) { valueId = (uint)values.Count; values.Add(attribute.Value, valueId); } feature.Tags.Add(keyId); feature.Tags.Add(valueId); } } layer.Features.Add(feature); } } else { // unknown type of layer. continue; } layer.Keys.AddRange(keys.Keys); foreach (var value in values.Keys) { layer.Values.Add(new Tile.Value() { StringValue = value }); } mapboxTile.Layers.Add(layer); } ProtoBuf.Serializer.Serialize <Tile>(stream, mapboxTile); }
/// <summary> /// Writes the tile to the given stream. /// </summary> /// <param name="vectorTile">The vector tile.</param> /// <param name="stream">The stream to write to.</param> /// <param name="extent">The extent.</param> /// <param name="idAttributeName">The name of an attribute property to use as the ID for the Feature. Vector tile feature ID's should be integer or ulong numbers.</param> public static void Write(this VectorTile vectorTile, Stream stream, uint extent = 4096, string idAttributeName = "id") { var tile = new Tiles.Tile(vectorTile.TileId); var tgt = new TileGeometryTransform(tile, extent); var mapboxTile = new Mapbox.Tile(); foreach (var localLayer in vectorTile.Layers) { var layer = new Mapbox.Tile.Layer { Version = 2, Name = localLayer.Name, Extent = extent }; var keys = new Dictionary <string, uint>(); var values = new Dictionary <Tile.Value, uint>(); foreach (var localLayerFeature in localLayer.Features) { var feature = new Mapbox.Tile.Feature(); // Encode geometry switch (localLayerFeature.Geometry) { case IPuntal puntal: feature.Type = Tile.GeomType.Point; feature.Geometry.AddRange(Encode(puntal, tgt)); break; case ILineal lineal: feature.Type = Tile.GeomType.LineString; feature.Geometry.AddRange(Encode(lineal, tgt)); break; case IPolygonal polygonal: feature.Type = Tile.GeomType.Polygon; feature.Geometry.AddRange(Encode(polygonal, tgt, tile.Zoom)); break; default: feature.Type = Tile.GeomType.Unknown; break; } // If geometry collapsed during encoding, we don't add the feature at all if (feature.Geometry.Count == 0) { continue; } // Translate attributes for feature AddAttributes(feature.Tags, keys, values, localLayerFeature.Attributes); //Try and retrieve an ID from the attributes. var id = localLayerFeature.Attributes.GetOptionalValue(idAttributeName); //Converting ID to string, then trying to parse. This will handle situations will ignore situations where the ID value is not actually an integer or ulong number. if (id != null && ulong.TryParse(id.ToString(), out ulong idVal)) { feature.Id = idVal; } // Add feature to layer layer.Features.Add(feature); } layer.Keys.AddRange(keys.Keys); layer.Values.AddRange(values.Keys); mapboxTile.Layers.Add(layer); } ProtoBuf.Serializer.Serialize <Tile>(stream, mapboxTile); }