public void TestAddWithElevation() { using (var map = new MemoryMapStream()) { var array = new ShapesArray(map, 1024); array.Set(0, new Coordinate(0, 0.1f, 10), new Coordinate(1, 1.1f, 11)); var shape = array[0]; Assert.IsNotNull(shape); Assert.AreEqual(2, shape.Count); Assert.AreEqual(0, shape[0].Latitude, .00001); Assert.AreEqual(0.1, shape[0].Longitude, .00001); Assert.AreEqual(10, shape[0].Elevation); Assert.AreEqual(1, shape[1].Latitude, .00001); Assert.AreEqual(1.1, shape[1].Longitude, .00001); Assert.AreEqual(11, shape[1].Elevation); } using (var map = new MemoryMapStream()) { var box = new Box( new Coordinate(-90, -180), new Coordinate(90, 180)); var refArray = new ShapeBase[1024]; var array = new ShapesArray(map, 1024); var rand = new Randomizer(1587341311); for (var i = 0; i < 1024; i++) { var count = rand.Next(10); var newShape = new List <Coordinate>(count); for (var j = 0; j < count; j++) { newShape.Add(box.GenerateRandomIn()); } var shape = new ShapeEnumerable(newShape); refArray[i] = shape; array[i] = shape; } for (var i = 0; i < refArray.Length; i++) { var refShape = refArray[i]; var shape = array[i]; Assert.IsNotNull(shape); for (var j = 0; j < shape.Count; j++) { Assert.AreEqual(refShape[j].Latitude, shape[j].Latitude); Assert.AreEqual(refShape[j].Longitude, shape[j].Longitude); Assert.AreEqual(refShape[j].Elevation, shape[j].Elevation); } } } }
public void TestCopyToCreateFrom() { var box = new Box( new Coordinate(-90, -180), new Coordinate(90, 180)); var refArray = new ShapesArray(1024); var rand = new System.Random(46541577); var totalCoordinateCount = 0; for (var i = 0; i < 1024; i++) { var count = rand.Next(10); totalCoordinateCount += count; var newShape = new List <Coordinate>(count); for (var j = 0; j < count; j++) { newShape.Add(box.GenerateRandomIn()); } var shape = new ShapeEnumerable(newShape); refArray[i] = shape; } using (var stream = new MemoryStream()) { Assert.AreEqual(16 + (1024 * 8) + (totalCoordinateCount * 8), refArray.CopyTo(stream)); stream.Seek(0, SeekOrigin.Begin); var array = ShapesArray.CreateFrom(stream, true); for (var i = 0; i < refArray.Length; i++) { var refShape = refArray[i]; if (refShape.Count == 0) { continue; } var shape = array[i]; Assert.IsNotNull(shape); for (var j = 0; j < shape.Count; j++) { Assert.AreEqual(refShape[j].Latitude, shape[j].Latitude); Assert.AreEqual(refShape[j].Longitude, shape[j].Longitude); } } stream.Seek(0, SeekOrigin.Begin); array = ShapesArray.CreateFrom(stream, false); for (var i = 0; i < refArray.Length; i++) { var refShape = refArray[i]; if (refShape.Count == 0) { continue; } var shape = array[i]; Assert.IsNotNull(shape); for (var j = 0; j < shape.Count; j++) { Assert.AreEqual(refShape[j].Latitude, shape[j].Latitude); Assert.AreEqual(refShape[j].Longitude, shape[j].Longitude); } } } }
/// <summary> /// Returns the part of the edge between the two offsets not including the vertices at the start or the end. /// </summary> /// <param name="enumerator">The enumerator.</param> /// <param name="offset1">The start offset.</param> /// <param name="offset2">The end offset.</param> /// <param name="includeVertices">Include vertices in case the range start at min offset or ends at max.</param> /// <returns>The shape points between the given offsets. Includes the vertices by default when offsets at min/max.</returns> public static IEnumerable <Coordinate> GetShapeBetween(this RouterDbEdgeEnumerator enumerator, ushort offset1 = 0, ushort offset2 = ushort.MaxValue, bool includeVertices = true) { if (offset1 > offset2) { throw new ArgumentException($"{nameof(offset1)} has to smaller than or equal to {nameof(offset2)}"); } // get edge and shape details. var shape = enumerator.GetShape(); if (shape == null) { shape = new ShapeEnumerable(Enumerable.Empty <Coordinate>()); } // return the entire edge if requested. if (offset1 == 0 && offset2 == ushort.MaxValue) { foreach (var s in enumerator.GetCompleteShape()) { yield return(s); } yield break; } // calculate offsets in meters. var edgeLength = enumerator.EdgeLength(); var offset1Length = (offset1 / (double)ushort.MaxValue) * edgeLength; var offset2Length = (offset2 / (double)ushort.MaxValue) * edgeLength; // TODO: can we make this easier with the complete shape enumeration? // calculate coordinate shape. var before = offset1 > 0; // when there is a start offset. var length = 0.0; var previous = enumerator.FromLocation(); if (offset1 == 0 && includeVertices) { yield return(previous); } for (var i = 0; i < shape.Count + 1; i++) { Coordinate next; if (i < shape.Count) { // the next = shape[i]; } else { // the last location. next = enumerator.ToLocation(); } var segmentLength = Coordinate.DistanceEstimateInMeter(previous, next); if (before) { // check if offset1 length has exceeded. if (segmentLength + length >= offset1Length && offset1 > 0) { // we are before, but not we have move to after. var segmentOffset = offset1Length - length; var location = Coordinate.PositionAlongLine(previous, next, (segmentOffset / segmentLength)); previous = next; before = false; yield return(location); } } if (!before) { // check if offset2 length has exceeded. if (segmentLength + length > offset2Length && offset2 < ushort.MaxValue) { // we are after but now we are after. var segmentOffset = offset2Length - length; var location = Coordinate.PositionAlongLine(previous, next, (segmentOffset / segmentLength)); yield return(location); yield break; } // the case where include vertices is false. if (i == shape.Count && !includeVertices) { yield break; } yield return(next); } // move to the next segment. previous = next; length += segmentLength; } }
/// <summary> /// Adds a new edge and it's inline data. /// </summary> /// <param name="vertex1">The first vertex.</param> /// <param name="vertex2">The second vertex.</param> /// <param name="data">The inline data.</param> /// <param name="shape">The edge shape.</param> /// <returns>The edge id.</returns> public uint AddEdge(VertexId vertex1, VertexId vertex2, IReadOnlyList <byte> data = null, IEnumerable <Coordinate> shape = null) { // try to find vertex1. var(vertex1Pointer, capacity1) = FindTile(vertex1.TileId); if (vertex1Pointer == GraphConstants.TileNotLoaded || vertex1.LocalId >= capacity1) { throw new ArgumentException($"{vertex1} does not exist."); } // try to find vertex2. var(vertex2Pointer, capacity2) = FindTile(vertex2.TileId); if (vertex2Pointer == GraphConstants.TileNotLoaded || vertex2.LocalId >= capacity2) { throw new ArgumentException($"{vertex2} does not exist."); } // get edge pointers. var edgePointer1 = _edgePointers[vertex1Pointer + vertex1.LocalId]; var edgePointer2 = _edgePointers[vertex2Pointer + vertex2.LocalId]; // make sure there is enough space. var rawPointer = (_edgePointer * _edgeSize); if (rawPointer + _edgeSize > _edges.Length) { _edges.EnsureMinimumSize(rawPointer + _edgeSize); } // add edge pointers with new edge. rawPointer += WriteToEdges(rawPointer, vertex1); rawPointer += WriteToEdges(rawPointer, vertex2); // write pointer to previous edge. if (edgePointer1 == GraphConstants.NoEdges) { // if there is no previous edge, write 0 rawPointer += WriteToEdges(rawPointer, 0); } else { // write pointer but offset by 1. rawPointer += WriteToEdges(rawPointer, edgePointer1 + 1); } // write pointer to previous edge. if (edgePointer2 == GraphConstants.NoEdges) { // if there is no previous edge, write 0 rawPointer += WriteToEdges(rawPointer, 0); } else { // write pointer but offset by 1. rawPointer += WriteToEdges(rawPointer, edgePointer2 + 1); } rawPointer += WriteToEdges(rawPointer, data); // write data package. // update edge pointers. var newEdgePointer = _edgePointer; _edgePointers[vertex1Pointer + vertex1.LocalId] = newEdgePointer; _edgePointers[vertex2Pointer + vertex2.LocalId] = newEdgePointer; _edgePointer += 1; // add shape if any. if (shape != null) { if (_shapes.Length <= newEdgePointer) { // TODO: this resizing should be in the shapes array. _shapes.Resize(newEdgePointer + 1024); } _shapes[newEdgePointer] = new ShapeEnumerable(shape); } return(newEdgePointer); }
/// <summary> /// Gets a trip, all it's connections, stops and shape points. /// </summary> public static FeatureCollection GetTripFeatures(this TransitDb transitDb, uint tripId) { var tripEnumerator = transitDb.GetTripsEnumerator(); if (!tripEnumerator.MoveTo(tripId)) { return(new FeatureCollection()); } var features = new FeatureCollection(); var stopsEnumerator = transitDb.GetStopsEnumerator(); var stops = new HashSet <uint>(); var connectionEnumerator = transitDb.GetConnectionsEnumerator(DefaultSorting.DepartureTime); while (connectionEnumerator.MoveNext()) { if (connectionEnumerator.TripId == tripId) { var shape = transitDb.ShapesDb.Get(connectionEnumerator.DepartureStop, connectionEnumerator.ArrivalStop); if (shape == null || shape.Count == 0) { stopsEnumerator.MoveTo(connectionEnumerator.DepartureStop); var stop1 = new Coordinate(stopsEnumerator.Latitude, stopsEnumerator.Longitude); stopsEnumerator.MoveTo(connectionEnumerator.ArrivalStop); var stop2 = new Coordinate(stopsEnumerator.Latitude, stopsEnumerator.Longitude); shape = new ShapeEnumerable(new Coordinate[] { stop1, stop2 }); } if (!stops.Contains(connectionEnumerator.DepartureStop)) { stopsEnumerator.MoveTo(connectionEnumerator.DepartureStop); var meta = transitDb.GetStopMeta(connectionEnumerator.DepartureStop).ToAttributesTable(); meta.AddAttribute("internal_id", connectionEnumerator.DepartureStop); features.Add(new Feature(new Point(new GeoAPI.Geometries.Coordinate(stopsEnumerator.Longitude, stopsEnumerator.Latitude)), meta)); stops.Add(connectionEnumerator.DepartureStop); } if (!stops.Contains(connectionEnumerator.ArrivalStop)) { stopsEnumerator.MoveTo(connectionEnumerator.ArrivalStop); var meta = transitDb.GetStopMeta(connectionEnumerator.ArrivalStop).ToAttributesTable(); meta.AddAttribute("internal_id", connectionEnumerator.ArrivalStop); features.Add(new Feature(new Point(new GeoAPI.Geometries.Coordinate(stopsEnumerator.Longitude, stopsEnumerator.Latitude)), meta)); stops.Add(connectionEnumerator.ArrivalStop); } var tripMeta = transitDb.TripAttributes.Get(tripEnumerator.MetaId).ToAttributesTable(); tripMeta.AddAttribute("internal_stop1", connectionEnumerator.DepartureStop); tripMeta.AddAttribute("internal_stop2", connectionEnumerator.ArrivalStop); features.Add(new Feature(new LineString(shape.ToArray().ToCoordinatesArray()), tripMeta)); } } return(features); }