private Geometry ReadLineString(TileGeometryTransform tgs, IList <uint> geometry) { int currentIndex = 0; int currentX = 0; int currentY = 0; var sequences = ReadCoordinateSequences(tgs, geometry, ref currentIndex, ref currentX, ref currentY); return(CreateLineal(sequences)); }
/// <summary> /// Reads a Vector Tile stream. /// </summary> /// <param name="stream">Vector tile stream.</param> /// <param name="tileDefinition">Tile information.</param> /// <param name="idAttributeName">Optional. Specifies the name of the attribute that the vector tile feature's ID should be stored in the NetTopologySuite Features AttributeTable.</param> /// <returns></returns> public VectorTile Read(Stream stream, Tiles.Tile tileDefinition, string idAttributeName) { // Deserialize the tile var tile = ProtoBuf.Serializer.Deserialize <Mapbox.Tile>(stream); var vectorTile = new VectorTile { TileId = tileDefinition.Id }; foreach (var mbTileLayer in tile.Layers) { Debug.Assert(mbTileLayer.Version == 2U); var tgs = new TileGeometryTransform(tileDefinition, mbTileLayer.Extent); var layer = new Layer { Name = mbTileLayer.Name }; foreach (var mbTileFeature in mbTileLayer.Features) { var feature = ReadFeature(tgs, mbTileLayer, mbTileFeature, idAttributeName); layer.Features.Add(feature); } vectorTile.Layers.Add(layer); } return(vectorTile); }
private Geometry ReadPolygon(TileGeometryTransform tgs, IList <uint> geometry) { int currentIndex = 0; int currentX = 0; int currentY = 0; var sequences = ReadCoordinateSequences(tgs, geometry, ref currentIndex, ref currentX, ref currentY, 1); return(CreatePolygonal(sequences)); }
private static IEnumerable <uint> Encode(IPolygonal polygonal, TileGeometryTransform tgt, int zoom) { var geometry = (Geometry)polygonal; //Test the whole polygon geometry is larger than a single pixel. if (IsGreaterThanOnePixelOfTile(geometry, zoom)) { int currentX = 0, currentY = 0; for (int i = 0; i < geometry.NumGeometries; i++) { var polygon = (Polygon)geometry.GetGeometryN(i); //Test that individual polygons are larger than a single pixel. if (!IsGreaterThanOnePixelOfTile(polygon, zoom)) { continue; } foreach (uint encoded in Encode(polygon.Shell.CoordinateSequence, tgt, ref currentX, ref currentY, true, false)) { yield return(encoded); } foreach (var hole in polygon.InteriorRings) { foreach (uint encoded in Encode(hole.CoordinateSequence, tgt, ref currentX, ref currentY, true, true)) { yield return(encoded); } } } } }
private static IEnumerable <uint> Encode(IPuntal puntal, TileGeometryTransform tgt) { const int CoordinateIndex = 0; var geometry = (Geometry)puntal; int currentX = 0, currentY = 0; var parameters = new List <uint>(); for (int i = 0; i < geometry.NumGeometries; i++) { var point = (Point)geometry.GetGeometryN(i); (int x, int y) = tgt.Transform(point.CoordinateSequence, CoordinateIndex, ref currentX, ref currentY); if (i == 0 || x > 0 || y > 0) { parameters.Add(GenerateParameterInteger(x)); parameters.Add(GenerateParameterInteger(y)); } } // Return result yield return(GenerateCommandInteger(MapboxCommandType.MoveTo, parameters.Count / 2)); foreach (uint parameter in parameters) { yield return(parameter); } }
private IFeature ReadFeature(TileGeometryTransform tgs, Tile.Layer mbTileLayer, Tile.Feature mbTileFeature, string idAttributeName) { var geometry = ReadGeometry(tgs, mbTileFeature.Type, mbTileFeature.Geometry); var attributes = ReadAttributeTable(mbTileFeature, mbTileLayer.Keys, mbTileLayer.Values); //Check to see if an id value is already captured in the attributes, if not, add it. if (!string.IsNullOrEmpty(idAttributeName) && !mbTileLayer.Keys.Contains(idAttributeName)) { ulong id = mbTileFeature.Id; attributes.Add(idAttributeName, id); } return(new Feature(geometry, attributes)); }
private static IEnumerable <uint> Encode(ILineal lineal, TileGeometryTransform tgt) { var geometry = (Geometry)lineal; int currentX = 0, currentY = 0; for (int i = 0; i < geometry.NumGeometries; i++) { var lineString = (LineString)geometry.GetGeometryN(i); foreach (uint encoded in Encode(lineString.CoordinateSequence, tgt, ref currentX, ref currentY, false)) { yield return(encoded); } } }
private Geometry ReadGeometry(TileGeometryTransform tgs, Tile.GeomType type, IList <uint> geometry) { switch (type) { case Tile.GeomType.Point: return(ReadPoint(tgs, geometry)); case Tile.GeomType.LineString: return(ReadLineString(tgs, geometry)); case Tile.GeomType.Polygon: return(ReadPolygon(tgs, geometry)); } return(null); }
private CoordinateSequence[] ReadSinglePointSequences(TileGeometryTransform tgs, IList <uint> geometry, int numSequences, ref int currentIndex, ref int currentX, ref int currentY) { var res = new CoordinateSequence[numSequences]; var currentPosition = (currentX, currentY); for (int i = 0; i < numSequences; i++) { res[i] = _factory.CoordinateSequenceFactory.Create(1, 2); currentPosition = ParseOffset(currentPosition, geometry, ref currentIndex); TransformOffsetAndAddToSequence(tgs, currentPosition, res[i], 0); } currentX = currentPosition.currentX; currentY = currentPosition.currentY; return(res); }
private void TransformOffsetAndAddToSequence(TileGeometryTransform tgs, (int x, int y) localPosition, CoordinateSequence sequence, int index)
private CoordinateSequence[] ReadCoordinateSequences( TileGeometryTransform tgs, IList <uint> geometry, ref int currentIndex, ref int currentX, ref int currentY, int buffer = 0, bool forPoint = false) { (var command, int count) = ParseCommandInteger(geometry[currentIndex]); Debug.Assert(command == MapboxCommandType.MoveTo); if (count > 1) { currentIndex++; return(ReadSinglePointSequences(tgs, geometry, count, ref currentIndex, ref currentX, ref currentY)); } var sequences = new List <CoordinateSequence>(); var currentPosition = (currentX, currentY); while (currentIndex < geometry.Count) { (command, count) = ParseCommandInteger(geometry[currentIndex++]); Debug.Assert(command == MapboxCommandType.MoveTo); Debug.Assert(count == 1); // Read the current position currentPosition = ParseOffset(currentPosition, geometry, ref currentIndex); if (!forPoint) { // Read the next command (should be LineTo) (command, count) = ParseCommandInteger(geometry[currentIndex++]); if (command != MapboxCommandType.LineTo) { count = 0; } } else { count = 0; } // Create sequence, add starting point var sequence = _factory.CoordinateSequenceFactory.Create(1 + count + buffer, 2); int sequenceIndex = 0; TransformOffsetAndAddToSequence(tgs, currentPosition, sequence, sequenceIndex++); // Read and add offsets for (int i = 1; i <= count; i++) { currentPosition = ParseOffset(currentPosition, geometry, ref currentIndex); TransformOffsetAndAddToSequence(tgs, currentPosition, sequence, sequenceIndex++); } // Check for ClosePath command if (currentIndex < geometry.Count) { (command, _) = ParseCommandInteger(geometry[currentIndex]); if (command == MapboxCommandType.ClosePath) { Debug.Assert(buffer > 0); sequence.SetOrdinate(sequenceIndex, Ordinate.X, sequence.GetOrdinate(0, Ordinate.X)); sequence.SetOrdinate(sequenceIndex, Ordinate.Y, sequence.GetOrdinate(0, Ordinate.Y)); currentIndex++; sequenceIndex++; } } Debug.Assert(sequenceIndex == sequence.Count); sequences.Add(sequence); } // update current position values currentX = currentPosition.currentX; currentY = currentPosition.currentY; return(sequences.ToArray()); }
/// <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); }
private static IEnumerable <uint> Encode(CoordinateSequence sequence, TileGeometryTransform tgt, ref int currentX, ref int currentY, bool ring = false, bool ccw = false) { // how many parameters for LineTo command int count = sequence.Count; // if we have a ring we need to check orientation if (ring) { if (ccw != Algorithm.Orientation.IsCCW(sequence)) { sequence = sequence.Copy(); CoordinateSequences.Reverse(sequence); } } var encoded = new List <uint>(); // Start point encoded.Add(GenerateCommandInteger(MapboxCommandType.MoveTo, 1)); var position = tgt.Transform(sequence, 0, ref currentX, ref currentY); encoded.Add(GenerateParameterInteger(position.x)); encoded.Add(GenerateParameterInteger(position.y)); // Add LineTo command (stub) int lineToCount = 0; encoded.Add(GenerateCommandInteger(MapboxCommandType.LineTo, lineToCount)); for (int i = 1; i < count; i++) { position = tgt.Transform(sequence, i, ref currentX, ref currentY); if (position.x != 0 || position.y != 0) { encoded.Add(GenerateParameterInteger(position.x)); encoded.Add(GenerateParameterInteger(position.y)); lineToCount++; } } if (lineToCount > 0) { encoded[3] = GenerateCommandInteger(MapboxCommandType.LineTo, lineToCount); } // Validate encoded data if (ring) { // A ring has 1 MoveTo and 1 LineTo command. // A ring is only valid if we have at least 3 points, otherwise collapse if (encoded.Count - 2 >= 6) { encoded.Add(GenerateCommandInteger(MapboxCommandType.ClosePath, 1)); } else { encoded.Clear(); } } else { // A line has 1 MoveTo and 1 LineTo command. // A line is valid if it has at least 2 points if (encoded.Count - 2 < 4) { encoded.Clear(); } } return(encoded); }