/// <summary> /// Calculates the distance to one of the vertices on the edge this router point is on. /// </summary> /// <returns></returns> public static float DistanceTo(this RouterPoint point, RouterDb routerDb, uint vertex) { var geometricEdge = routerDb.Network.GeometricGraph.GetEdge(point.EdgeId); var edgeDistance = routerDb.Network.GeometricGraph.Length(geometricEdge); var offsetDistance = edgeDistance * ((float)point.Offset / (float)ushort.MaxValue); if (geometricEdge.From == vertex) { // offset = distance. return(offsetDistance); } else if (geometricEdge.To == vertex) { // offset = 100 - distance. return(edgeDistance - offsetDistance); } throw new ArgumentOutOfRangeException(string.Format("Vertex {0} is not part of edge {1}.", vertex, point.EdgeId)); }
/// <summary> /// Snaps to an edge closest to the given coordinates. /// </summary> /// <param name="routerDb">The router db.</param> /// <param name="longitude">The longitude.</param> /// <param name="latitude">The latitude.</param> /// <param name="maxOffsetInMeter">The maximum offset in meter.</param> /// <param name="profile">The profile to snap for.</param> /// <returns>The snap point.</returns> public static Result <SnapPoint> Snap(this RouterDb routerDb, double longitude, double latitude, float maxOffsetInMeter = 1000, Profile profile = null) { ProfileHandler profileHandler = null; if (profile != null) { profileHandler = routerDb.GetProfileHandler(profile); } var offset = 100; while (offset < maxOffsetInMeter) { // calculate search box. var offsets = (new Coordinate(longitude, latitude)).OffsetWithDistances(maxOffsetInMeter); var latitudeOffset = System.Math.Abs(latitude - offsets.Latitude); var longitudeOffset = System.Math.Abs(longitude - offsets.Longitude); var box = (longitude - longitudeOffset, latitude - latitudeOffset, longitude + longitudeOffset, latitude + latitudeOffset); // make sure data is loaded. routerDb.DataProvider?.TouchBox(box); // snap to closest edge. var snapPoint = routerDb.SnapInBox(box, (eEnum) => { if (profileHandler == null) { return(true); } profileHandler.MoveTo(eEnum); var canStop = profileHandler.CanStop; return(canStop); }); if (snapPoint.EdgeId != uint.MaxValue) { return(snapPoint); } offset *= 2; } return(new Result <SnapPoint>($"Could not snap to location: {longitude},{latitude}")); }
/// <summary> /// Gets the get restriction function for the given profile. /// </summary> /// <param name="db">The router db.</param> /// <param name="profile">The vehicle profile.</param> /// <param name="first">When true, only restrictions starting with given vertex, when false only restrictions ending with given vertex already reversed, when null all restrictions are returned.</param> public static Func <uint, IEnumerable <uint[]> > GetGetRestrictions(this RouterDb db, Profiles.Profile profile, bool?first) { var vehicleTypes = new List <string>(profile.VehicleType); vehicleTypes.Insert(0, string.Empty); return((vertex) => { var restrictionList = new List <uint[]>(); for (var i = 0; i < vehicleTypes.Count; i++) { RestrictionsDb restrictionsDb; if (db.TryGetRestrictions(vehicleTypes[i], out restrictionsDb)) { var enumerator = restrictionsDb.GetEnumerator(); if (enumerator.MoveTo(vertex)) { while (enumerator.MoveNext()) { if (first.HasValue && first.Value) { if (enumerator[0] == vertex) { restrictionList.Add(enumerator.ToArray()); } } else if (first.HasValue && !first.Value) { if (enumerator[(int)enumerator.Count - 1] == vertex) { var array = enumerator.ToArray(); array.Reverse(); restrictionList.Add(array); } } else { restrictionList.Add(enumerator.ToArray()); } } } } } return restrictionList; }); }
/// <summary> /// Writes a linestring-geometry for the edge currently in the enumerator. /// </summary> private static void WriteEdge(this RouterDb db, JsonWriter jsonWriter, RoutingNetwork.EdgeEnumerator edgeEnumerator) { var edgeAttributes = new Itinero.Attributes.AttributeCollection(db.EdgeMeta.Get(edgeEnumerator.Data.MetaId)); edgeAttributes.AddOrReplace(db.EdgeProfiles.Get(edgeEnumerator.Data.Profile)); var shape = db.Network.GetShape(edgeEnumerator.Current); jsonWriter.WriteOpen(); jsonWriter.WriteProperty("type", "Feature", true, false); jsonWriter.WritePropertyName("geometry", false); jsonWriter.WriteOpen(); jsonWriter.WriteProperty("type", "LineString", true, false); jsonWriter.WritePropertyName("coordinates", false); jsonWriter.WriteArrayOpen(); foreach (var coordinate in shape) { jsonWriter.WriteArrayOpen(); jsonWriter.WriteArrayValue(coordinate.Longitude.ToInvariantString()); jsonWriter.WriteArrayValue(coordinate.Latitude.ToInvariantString()); jsonWriter.WriteArrayClose(); } jsonWriter.WriteArrayClose(); jsonWriter.WriteClose(); jsonWriter.WritePropertyName("properties"); jsonWriter.WriteOpen(); if (edgeAttributes != null) { foreach (var attribute in edgeAttributes) { jsonWriter.WriteProperty(attribute.Key, attribute.Value, true, true); } } jsonWriter.WriteProperty("edgeid", edgeEnumerator.Id.ToInvariantString()); jsonWriter.WriteProperty("vertex1", edgeEnumerator.From.ToInvariantString()); jsonWriter.WriteProperty("vertex2", edgeEnumerator.To.ToInvariantString()); jsonWriter.WriteClose(); jsonWriter.WriteClose(); }
/// <summary> /// Builds an edge path from a path consisiting of only vertices. /// </summary> public static EdgePath <T> BuildEdgePath <T>(this RouterDb routerDb, WeightHandler <T> weightHandler, RouterPoint source, RouterPoint target, List <uint> vertexPath) where T : struct { if (vertexPath == null || vertexPath.Count == 0) { return(null); } var path = new EdgePath <T>(vertexPath[0]); var i = 1; if (path.Vertex == Constants.NO_VERTEX) { // add first router point segment from source. path = source.EdgePathTo(routerDb, weightHandler, vertexPath[1]); i = 2; } var edgeEnumerator = routerDb.Network.GeometricGraph.Graph.GetEdgeEnumerator(); for (; i < vertexPath.Count; i++) { var vertex = vertexPath[i]; if (vertex == Constants.NO_VERTEX) { if (i != vertexPath.Count - 1) { throw new Exception("Invalid data found in vertex path: a non-vertex id was found at an invalid location."); } var toTarget = target.EdgePathTo(routerDb, weightHandler, path.Vertex, true); path = new EdgePath <T>(toTarget.Vertex, weightHandler.Add(toTarget.Weight, path.Weight), toTarget.Edge, path); break; } T weight; var best = edgeEnumerator.FindBestEdge(weightHandler, path.Vertex, vertexPath[i], out weight); if (best == Constants.NO_EDGE) { throw new Exception(string.Format("Cannot build vertex path, edge {0} -> {1} not found.", path.Vertex, vertexPath[i])); } path = new EdgePath <T>(vertexPath[i], weightHandler.Add(weight, path.Weight), best, path); } return(path); }
/// <summary> /// Calculates the edge path between this router point and the given router point. /// </summary> /// <param name="point">The source point.</param> /// <param name="db">The router db.</param> /// <param name="weightHandler">The weight handler.</param> /// <param name="target">The target point.</param> /// <param name="backward">Forces the direction on the edge to travel in.</param> public static EdgePath <T> EdgePathTo <T>(this RouterPoint point, RouterDb db, WeightHandler <T> weightHandler, RouterPoint target, bool backward = false) where T : struct { if (point.EdgeId != target.EdgeId) { throw new ArgumentException("Target point must be part of the same edge."); } if (point.Offset == target.Offset) { // two points are identical, path of length '0'. return(new EdgePath <T>(point.VertexId(db))); } var forward = point.Offset < target.Offset; if (forward && backward) { // forward travel is required but backward travel is requested. return(null); } var edge = db.Network.GetEdge(point.EdgeId); var distance = ((float)System.Math.Abs((int)point.Offset - (int)target.Offset) / (float)ushort.MaxValue) * edge.Data.Distance; Factor factor; var weight = weightHandler.Calculate(edge.Data.Profile, distance, out factor); if (factor.Value <= 0) { // not possible to travel here. return(null); } if (factor.Direction == 0 || (forward && factor.Direction == 1) || (!forward && factor.Direction == 2)) { // ok, directions match. if (forward) { return(new EdgePath <T>(target.VertexId(db), weight, point.EdgeId + 1, new EdgePath <T>(point.VertexId(db)))); } return(new EdgePath <T>(target.VertexId(db), weight, -point.EdgeId - 1, new EdgePath <T>(point.VertexId(db)))); } return(null); }
/// <summary> /// Calculates the edge path between this router point and the given router point. /// </summary> /// <param name="point">The source point.</param> /// <param name="db">The router db.</param> /// <param name="weightHandler">The weight handler.</param> /// <param name="sourceForward">The source forward flag, true if forward, false if backward, null if don't care.</param> /// <param name="target">The target point.</param> /// <param name="targetForward">The target forward flag, true if forward, false if backward, null if don't care.</param> public static EdgePath <T> EdgePathTo <T>(this RouterPoint point, RouterDb db, WeightHandler <T> weightHandler, bool?sourceForward, RouterPoint target, bool?targetForward) where T : struct { if (!sourceForward.HasValue && !targetForward.HasValue) { return(point.EdgePathTo(db, weightHandler, target)); } if (sourceForward.HasValue && targetForward.HasValue) { if (sourceForward.Value != targetForward.Value) { // impossible route inside one edge. return(null); } } if (sourceForward.HasValue) { return(point.EdgePathTo(db, weightHandler, target, !sourceForward.Value)); } return(point.EdgePathTo(db, weightHandler, target, !targetForward.Value)); }
/// <summary> /// Returns one attribute collection containing both the profile and meta tags. /// </summary> public static IAttributeCollection GetProfileAndMeta(this RouterDb db, uint profileId, uint meta) { var tags = new AttributeCollection(); var metaTags = db.EdgeMeta.Get(meta); if (metaTags != null) { tags.AddOrReplace(metaTags); } var profileTags = db.EdgeProfiles.Get(profileId); if (profileTags != null) { tags.AddOrReplace(profileTags); } return(tags); }
/// <summary> /// Calculates the shape points along the way from this router point to one of it's vertices. /// </summary> public static List <Coordinate> ShapePointsTo(this RouterPoint point, RouterDb routerDb, uint vertex) { List <Coordinate> points = null; var geometricEdge = routerDb.Network.GeometricGraph.GetEdge(point.EdgeId); var edgeDistance = routerDb.Network.GeometricGraph.Length(geometricEdge); var offsetDistance = edgeDistance * ((float)point.Offset / (float)ushort.MaxValue); if (geometricEdge.From == vertex) { // offset = distance. points = routerDb.Network.GeometricGraph.GetShape(geometricEdge, vertex, offsetDistance); points.Reverse(); return(points); } else if (geometricEdge.To == vertex) { // offset = 100 - distance. points = routerDb.Network.GeometricGraph.GetShape(geometricEdge, vertex, edgeDistance - offsetDistance); points.Reverse(); return(points); } throw new ArgumentOutOfRangeException(string.Format("Vertex {0} is not part of edge {1}.", vertex, point.EdgeId)); }
/// <summary> /// Generates an edge path for the given edge. /// </summary> public static EdgePath <T> GetPathForEdge <T>(this RouterDb routerDb, WeightHandler <T> weightHandler, RoutingEdge edge, bool edgeForward, bool asSource) where T : struct { var weight = weightHandler.Calculate(edge.Data.Profile, edge.Data.Distance); if (asSource) { if (edgeForward) { return(new EdgePath <T>(edge.To, weight, edge.IdDirected(), new EdgePath <T>(edge.From))); } return(new EdgePath <T>(edge.From, weight, -edge.IdDirected(), new EdgePath <T>(edge.To))); } else { if (edgeForward) { return(new EdgePath <T>(edge.From, weight, -edge.IdDirected(), new EdgePath <T>(edge.To))); } return(new EdgePath <T>(edge.To, weight, edge.IdDirected(), new EdgePath <T>(edge.From))); } }
/// <summary> /// Determines the direction from the given angle, true meaning forward relative to the edge in the routerpoint, false backwards. /// </summary> /// <param name="routerPoint">The router point.</param> /// <param name="routerDb">The router db.</param> /// <param name="angle">The angle in degrees relative to the longitudinal lines.</param> /// <param name="diffLimit">The diff limit when the angle is smaller than this we consider it the same direction.</param> /// <returns>True when forward, false when backward, null when direction couldn't be determined (outside of difflimit for example).</returns> public static bool?DirectionFromAngle(this RouterPoint routerPoint, RouterDb routerDb, float?angle, float diffLimit = 90) { if (diffLimit <= 0 || diffLimit > 90) { throw new ArgumentOutOfRangeException(nameof(diffLimit), "Expected to be in range ]0, 90]."); } if (routerDb == null) { throw new ArgumentNullException(nameof(routerDb)); } if (routerPoint == null) { throw new ArgumentNullException(nameof(routerPoint)); } if (angle == null) { return(null); } angle = (float)Tools.NormalizeDegrees(angle.Value); var edgeAngle = routerPoint.Angle(routerDb.Network); if (edgeAngle == null) { return(null); // no angle could be determined, for example on extremely short edges. } var diff = System.Math.Abs(Itinero.LocalGeo.Tools.SmallestDiffDegrees(angle.Value, edgeAngle.Value)); if (diff < diffLimit) { // forward, angle is close to that of the edge. return(true); } if (180 - diff < diffLimit) { // backward, angle is close to the anti-direction of the edge. return(false); } return(null); }
/// <summary> /// Writes a point-geometry for the given vertex. /// </summary> private static void WriteVertex(this RouterDb db, JsonWriter jsonWriter, uint vertex) { var coordinate = db.Network.GetVertex(vertex); jsonWriter.WriteOpen(); jsonWriter.WriteProperty("type", "Feature", true, false); jsonWriter.WritePropertyName("geometry", false); jsonWriter.WriteOpen(); jsonWriter.WriteProperty("type", "Point", true, false); jsonWriter.WritePropertyName("coordinates", false); jsonWriter.WriteArrayOpen(); jsonWriter.WriteArrayValue(coordinate.Longitude.ToInvariantString()); jsonWriter.WriteArrayValue(coordinate.Latitude.ToInvariantString()); jsonWriter.WriteArrayClose(); jsonWriter.WriteClose(); jsonWriter.WritePropertyName("properties"); jsonWriter.WriteOpen(); jsonWriter.WriteProperty("id", vertex.ToInvariantString()); jsonWriter.WriteClose(); jsonWriter.WriteClose(); }
internal RouterDbEdgeEnumerator(RouterDb routerDb, EdgeEnumerator edgeEnumerator) { _routerDb = routerDb ?? throw new ArgumentNullException(nameof(routerDb)); _edgeEnumerator = edgeEnumerator ?? throw new ArgumentNullException(nameof(edgeEnumerator));; }
/// <summary> /// Returns true if this db contains complex restrictions for the given profile. /// </summary> public static bool HasComplexRestrictions(this RouterDb db, Profiles.Profile profile) { return(db.HasComplexRestrictions(profile.VehicleType)); }
/// <summary> /// Returns true if this db contains restrictions for the given vehicle type. /// </summary> public static bool HasRestrictions(this RouterDb db, string vehicleType) { RestrictionsDb restrictions; return(db.TryGetRestrictions(vehicleType, out restrictions)); }
/// <summary> /// Deserializes a database from the given stream. /// </summary> public static RouterDb Deserialize(Stream stream) { return(RouterDb.Deserialize(stream, null)); }
/// <summary> /// Creates a new contracted graph and adds it to the router db for the given profile. /// </summary> public static void AddContracted <T>(this RouterDb db, Profiles.Profile profile, WeightHandler <T> weightHandler, bool forceEdgeBased = false) where T : struct { // create the raw directed graph. ContractedDb contractedDb = null; if (!forceEdgeBased) { // check if there are complex restrictions in the routerdb forcing edge-based contraction. if (db.HasComplexRestrictions(profile)) { // there are complex restrictions, use edge-based contraction, the only way to support these in a contracted graph. forceEdgeBased = true; } } lock (db) { if (forceEdgeBased) { // edge-based is needed when complex restrictions found. var contracted = new DirectedDynamicGraph(weightHandler.DynamicSize); var directedGraphBuilder = new Itinero.Algorithms.Contracted.EdgeBased.DirectedGraphBuilder <T>(db.Network.GeometricGraph.Graph, contracted, weightHandler); directedGraphBuilder.Run(); // contract the graph. var priorityCalculator = new Itinero.Algorithms.Contracted.EdgeBased.EdgeDifferencePriorityCalculator <T>(contracted, weightHandler, new Itinero.Algorithms.Contracted.EdgeBased.Witness.DykstraWitnessCalculator <T>(weightHandler, 4, 64)); priorityCalculator.DifferenceFactor = 5; priorityCalculator.DepthFactor = 5; priorityCalculator.ContractedFactor = 8; var hierarchyBuilder = new Itinero.Algorithms.Contracted.EdgeBased.HierarchyBuilder <T>(contracted, priorityCalculator, new Itinero.Algorithms.Contracted.EdgeBased.Witness.DykstraWitnessCalculator <T>(weightHandler, int.MaxValue, 64), weightHandler, db.GetGetRestrictions(profile, null)); hierarchyBuilder.Run(); contractedDb = new ContractedDb(contracted); } else { // vertex-based is ok when no complex restrictions found. var contracted = new DirectedMetaGraph(ContractedEdgeDataSerializer.Size, weightHandler.MetaSize); var directedGraphBuilder = new DirectedGraphBuilder <T>(db.Network.GeometricGraph.Graph, contracted, weightHandler); directedGraphBuilder.Run(); // contract the graph. var priorityCalculator = new EdgeDifferencePriorityCalculator(contracted, new DykstraWitnessCalculator(int.MaxValue)); priorityCalculator.DifferenceFactor = 5; priorityCalculator.DepthFactor = 5; priorityCalculator.ContractedFactor = 8; var hierarchyBuilder = new HierarchyBuilder <T>(contracted, priorityCalculator, new DykstraWitnessCalculator(int.MaxValue), weightHandler); hierarchyBuilder.Run(); contractedDb = new ContractedDb(contracted); } } // add the graph. lock (db) { db.AddContracted(profile, contractedDb); } }
/// <summary> /// Returns true if the given profile is supported. /// </summary> public static bool Supports(this RouterDb db, Profiles.Profile profile) { return(db.Supports(profile.Parent.Name)); }
/// <summary> /// Gets all features inside the given bounding box and writes them as a geojson string. /// </summary> public static void WriteGeoJson(this RouterDb db, Stream stream, float minLatitude, float minLongitude, float maxLatitude, float maxLongitude, bool includeEdges = true, bool includeVertices = true) { db.WriteGeoJson(new StreamWriter(stream), minLatitude, minLongitude, maxLatitude, maxLongitude, includeEdges, includeVertices); }
/// <summary> /// Returns the location on the network. /// </summary> public static Coordinate LocationOnNetwork(this RouterPoint point, RouterDb db) { return(db.LocationOnNetwork(point.EdgeId, point.Offset)); }
/// <summary> /// Converts the router point to paths leading to the closest 2 vertices. /// </summary> public static EdgePath <T>[] ToEdgePaths <T>(this RouterPoint point, RouterDb routerDb, WeightHandler <T> weightHandler, bool asSource) where T : struct { var graph = routerDb.Network.GeometricGraph; var edge = graph.GetEdge(point.EdgeId); float distance; ushort profileId; EdgeDataSerializer.Deserialize(edge.Data[0], out distance, out profileId); Factor factor; var edgeWeight = weightHandler.Calculate(profileId, distance, out factor); var offset = point.Offset / (float)ushort.MaxValue; if (factor.Direction == 0) { // bidirectional. if (offset == 0) { // the first part is just the first vertex. return(new EdgePath <T>[] { new EdgePath <T>(edge.From), new EdgePath <T>(edge.To, weightHandler.Calculate(profileId, distance * (1 - offset)), edge.IdDirected(), new EdgePath <T>(edge.From)) }); } else if (offset == 1) { // the second path it just the second vertex. return(new EdgePath <T>[] { new EdgePath <T>(edge.From, weightHandler.Calculate(profileId, distance * offset), -edge.IdDirected(), new EdgePath <T>(edge.To)), new EdgePath <T>(edge.To) }); } return(new EdgePath <T>[] { new EdgePath <T>(edge.From, weightHandler.Calculate(profileId, distance * offset), -edge.IdDirected(), new EdgePath <T>()), new EdgePath <T>(edge.To, weightHandler.Calculate(profileId, distance * (1 - offset)), edge.IdDirected(), new EdgePath <T>()) }); } else if (factor.Direction == 1) { // edge is forward oneway. if (asSource) { if (offset == 1) { // just return the to-vertex. return(new EdgePath <T>[] { new EdgePath <T>(edge.To) }); } if (offset == 0) { // return both, we are at the from-vertex. return(new EdgePath <T>[] { new EdgePath <T>(edge.From), new EdgePath <T>(edge.To, weightHandler.Calculate(profileId, distance * (1 - offset)), edge.IdDirected(), new EdgePath <T>(edge.From)) }); } return(new EdgePath <T>[] { new EdgePath <T>(edge.To, weightHandler.Calculate(profileId, distance * (1 - offset)), edge.IdDirected(), new EdgePath <T>()) }); } if (offset == 0) { // just return the from vertex. return(new EdgePath <T>[] { new EdgePath <T>(edge.From) }); } if (offset == 1) { // return both, we are at the to-vertex. return(new EdgePath <T>[] { new EdgePath <T>(edge.To), new EdgePath <T>(edge.From, weightHandler.Calculate(profileId, distance * offset), -edge.IdDirected(), new EdgePath <T>(edge.To)) }); } return(new EdgePath <T>[] { new EdgePath <T>(edge.From, weightHandler.Calculate(profileId, distance * offset), -edge.IdDirected(), new EdgePath <T>()) }); } else { // edge is backward oneway. if (!asSource) { if (offset == 1) { // just return the to-vertex. return(new EdgePath <T>[] { new EdgePath <T>(edge.To) }); } if (offset == 0) { // return both, we are at the from-vertex. return(new EdgePath <T>[] { new EdgePath <T>(edge.From), new EdgePath <T>(edge.To, weightHandler.Calculate(profileId, distance * (1 - offset)), edge.IdDirected(), new EdgePath <T>(edge.From)) }); } return(new EdgePath <T>[] { new EdgePath <T>(edge.To, weightHandler.Calculate(profileId, distance * (1 - offset)), edge.IdDirected(), new EdgePath <T>()) }); } if (offset == 0) { // just return the from-vertex. return(new EdgePath <T>[] { new EdgePath <T>(edge.From) }); } if (offset == 1) { // return both, we are at the to-vertex. return(new EdgePath <T>[] { new EdgePath <T>(edge.To), new EdgePath <T>(edge.From, weightHandler.Calculate(profileId, distance * offset), -edge.IdDirected(), new EdgePath <T>(edge.To)) }); } return(new EdgePath <T>[] { new EdgePath <T>(edge.From, weightHandler.Calculate(profileId, distance * offset), -edge.IdDirected(), new EdgePath <T>()) }); } }
/// <summary> /// Creates a new contracted graph and adds it to the router db for the given profile. /// </summary> public static void AddContracted(this RouterDb db, Profiles.Profile profile, bool forceEdgeBased = false) { db.AddContracted <float>(profile, profile.DefaultWeightHandlerCached(db), forceEdgeBased); }
/// <summary> /// Creates a new router point. /// </summary> public static RouterPoint CreateRouterPoint(this RouterDb routerDb, uint edgeId, ushort offset) { var location = routerDb.LocationOnNetwork(edgeId, offset); return(new RouterPoint(location.Latitude, location.Longitude, edgeId, offset)); }
/// <summary> /// Writes geojson describing the given routerpoint. /// </summary> internal static void WriteGeoJson(this RouterPoint routerPoint, TextWriter writer, RouterDb db) { if (db == null) { throw new ArgumentNullException("db"); } if (writer == null) { throw new ArgumentNullException("writer"); } var jsonWriter = new JsonWriter(writer); jsonWriter.WriteOpen(); jsonWriter.WriteProperty("type", "FeatureCollection", true, false); jsonWriter.WritePropertyName("features", false); jsonWriter.WriteArrayOpen(); var edgeEnumerator = db.Network.GetEdgeEnumerator(); edgeEnumerator.MoveToEdge(routerPoint.EdgeId); db.WriteEdge(jsonWriter, edgeEnumerator); db.WriteVertex(jsonWriter, edgeEnumerator.From); db.WriteVertex(jsonWriter, edgeEnumerator.To); // write location on network. var coordinate = routerPoint.LocationOnNetwork(db); jsonWriter.WriteOpen(); jsonWriter.WriteProperty("type", "Feature", true, false); jsonWriter.WritePropertyName("geometry", false); jsonWriter.WriteOpen(); jsonWriter.WriteProperty("type", "Point", true, false); jsonWriter.WritePropertyName("coordinates", false); jsonWriter.WriteArrayOpen(); jsonWriter.WriteArrayValue(coordinate.Longitude.ToInvariantString()); jsonWriter.WriteArrayValue(coordinate.Latitude.ToInvariantString()); jsonWriter.WriteArrayClose(); jsonWriter.WriteClose(); jsonWriter.WritePropertyName("properties"); jsonWriter.WriteOpen(); jsonWriter.WriteProperty("type", "location_on_network", true); jsonWriter.WriteProperty("offset", routerPoint.Offset.ToInvariantString()); jsonWriter.WriteClose(); jsonWriter.WriteClose(); // write original location. coordinate = routerPoint.Location(); jsonWriter.WriteOpen(); jsonWriter.WriteProperty("type", "Feature", true, false); jsonWriter.WritePropertyName("geometry", false); jsonWriter.WriteOpen(); jsonWriter.WriteProperty("type", "Point", true, false); jsonWriter.WritePropertyName("coordinates", false); jsonWriter.WriteArrayOpen(); jsonWriter.WriteArrayValue(coordinate.Longitude.ToInvariantString()); jsonWriter.WriteArrayValue(coordinate.Latitude.ToInvariantString()); jsonWriter.WriteArrayClose(); jsonWriter.WriteClose(); jsonWriter.WritePropertyName("properties"); jsonWriter.WriteOpen(); jsonWriter.WriteProperty("type", "original_location", true); jsonWriter.WriteClose(); jsonWriter.WriteClose(); jsonWriter.WriteArrayClose(); jsonWriter.WriteClose(); }
internal RouterDbEdgeEnumerator(RouterDb routerDb) { _routerDb = routerDb ?? throw new ArgumentNullException(nameof(routerDb)); _enumerator = _routerDb.Network.GetEnumerator(); }
/// <summary> /// Deserializes a database from the given stream. /// </summary> public static RouterDb Deserialize(Stream stream, RouterDbProfile profile) { // deserialize all basic data. // version1: OsmSharp.Routing state of layout. // version2: Added ShortcutsDbs. // version3: Add advanced profile serialization. // version4: Added missing restriction dbs. var version = stream.ReadByte(); if (version != 1 && version != 2 && version != 3 && version != 4) { throw new Exception(string.Format("Cannot deserialize routing db: Invalid version #: {0}.", version)); } var guidBytes = new byte[16]; stream.Read(guidBytes, 0, 16); var guid = new Guid(guidBytes); var supportedVehicleInstances = new List <Vehicle>(); if (version <= 2) { // just contains vehicle names. var supportedVehicles = stream.ReadWithSizeStringArray(); foreach (var vehicleName in supportedVehicles) { Profile vehicleProfile; if (Profile.TryGet(vehicleName, out vehicleProfile)) { supportedVehicleInstances.Add(vehicleProfile.Parent); } else { Itinero.Logging.Logger.Log("RouterDb", Logging.TraceEventType.Warning, "Vehicle with name {0} was not found, register all vehicle profiles before deserializing the router db.", vehicleName); } } } else { // contains the full vehicles. var lengthBytes = new byte[4]; stream.Read(lengthBytes, 0, 4); var size = BitConverter.ToInt32(lengthBytes, 0); for (var i = 0; i < size; i++) { var vehicle = Vehicle.Deserialize(stream); supportedVehicleInstances.Add(vehicle); vehicle.Register(); } } var metaDb = stream.ReadWithSizeAttributesCollection(); var shorcutsCount = (int)0; if (version >= 2) { // when version < 1 there are no shortcuts and thus no shortcut count. shorcutsCount = stream.ReadByte(); } var contractedCount = stream.ReadByte(); var restrictionDbCount = 0; if (version >= 4) { restrictionDbCount = stream.ReadByte(); } var profiles = AttributesIndex.Deserialize(new LimitedStream(stream), true); var meta = AttributesIndex.Deserialize(new LimitedStream(stream), true); var network = RoutingNetwork.Deserialize(stream, profile == null ? null : profile.RoutingNetworkProfile); // create router db. var routerDb = new RouterDb(guid, network, profiles, meta, metaDb, supportedVehicleInstances.ToArray()); // read all shortcut dbs. for (var i = 0; i < shorcutsCount; i++) { var shortcutsName = stream.ReadWithSizeString(); var shorcutsDb = ShortcutsDb.Deserialize(stream); routerDb._shortcutsDbs[shortcutsName] = shorcutsDb; } // read all contracted versions. for (var i = 0; i < contractedCount; i++) { var profileName = stream.ReadWithSizeString(); var contracted = ContractedDb.Deserialize(stream, profile == null ? null : profile.ContractedDbProfile); routerDb._contracted[profileName] = contracted; } // read all restriction dbs. for (var i = 0; i < restrictionDbCount; i++) { var restrictionDbName = stream.ReadWithSizeString(); var restrictionDb = RestrictionsDb.Deserialize(stream, profile == null ? null : profile.RestrictionDbProfile); routerDb._restrictionDbs[restrictionDbName] = restrictionDb; } return(routerDb); }
/// <summary> /// Adds the router point as a vertex. /// </summary> public static uint[] AddAsVertices(this RouterDb routerDb, RouterPoint[] points) { if (routerDb.HasContracted) { throw new InvalidOperationException("Cannot add new vertices to a routerDb with contracted versions of the network."); } var edges = new HashSet <uint>(); for (var i = 0; i < points.Length; i++) { var point = points[i]; if (edges.Contains(point.EdgeId)) { point = null; } else { edges.Add(point.EdgeId); } } var newVertices = new uint[points.Length]; var newEdges = new List <EdgeToSplit>(); for (var i = 0; i < points.Length; i++) { var point = points[i]; if (point == null) { // there was a duplicate edge. newVertices[i] = Constants.NO_VERTEX; newEdges.Add(null); continue; } if (point.IsVertex()) { // the router point is already a vertex. newVertices[i] = point.VertexId(routerDb); newEdges.Add(null); continue; } // add a new vertex at the router point location. var location = point.LocationOnNetwork(routerDb); // add two new edges. var edge = routerDb.Network.GetEdge(point.EdgeId); var shapeFrom = point.ShapePointsTo(routerDb, edge.From); shapeFrom.Reverse(); // we need this shape from edge.From -> vertex. var shapeTo = point.ShapePointsTo(routerDb, edge.To); var distanceFrom = point.DistanceTo(routerDb, edge.From); var distanceTo = point.DistanceTo(routerDb, edge.To); // register new edge. newEdges.Add(new EdgeToSplit() { Coordinate = location, From = edge.From, To = edge.To, DistanceFrom = distanceFrom, DistanceTo = distanceTo, ShapeFrom = shapeFrom, ShapeTo = shapeTo, MetaId = edge.Data.MetaId, Profile = edge.Data.Profile }); } for (var i = 0; i < newEdges.Count; i++) { var edgeToSplit = newEdges[i]; if (edgeToSplit == null) { continue; } // remove original edge. routerDb.Network.RemoveEdges(edgeToSplit.From, edgeToSplit.To); // add vertex. var vertex = routerDb.Network.VertexCount; routerDb.Network.AddVertex(vertex, edgeToSplit.Coordinate.Latitude, edgeToSplit.Coordinate.Longitude); // add two new pieces. routerDb.Network.AddEdge(edgeToSplit.From, vertex, new Data.Network.Edges.EdgeData() { Distance = edgeToSplit.DistanceFrom, MetaId = edgeToSplit.MetaId, Profile = edgeToSplit.Profile }, edgeToSplit.ShapeFrom); routerDb.Network.AddEdge(vertex, edgeToSplit.To, new Data.Network.Edges.EdgeData() { Distance = edgeToSplit.DistanceTo, MetaId = edgeToSplit.MetaId, Profile = edgeToSplit.Profile }, edgeToSplit.ShapeTo); newVertices[i] = vertex; } return(newVertices); }
/// <summary> /// Converts the router point to paths leading to the closest 2 vertices. /// </summary> public static EdgePath <T>[] ToEdgePaths <T>(this RouterPoint point, RouterDb routerDb, WeightHandler <T> weightHandler, bool asSource, bool?forward) where T : struct { if (forward == null) { // don't-care direction, use default implementation. return(point.ToEdgePaths(routerDb, weightHandler, asSource)); } var graph = routerDb.Network.GeometricGraph; var edge = graph.GetEdge(point.EdgeId); float distance; ushort profileId; EdgeDataSerializer.Deserialize(edge.Data[0], out distance, out profileId); Factor factor; var edgeWeight = weightHandler.Calculate(profileId, distance, out factor); var offset = point.Offset / (float)ushort.MaxValue; if (factor.Direction == 0) { // bidirectional. if (forward.Value) { return(new EdgePath <T>[] { new EdgePath <T>(edge.To, weightHandler.Calculate(profileId, distance * (1 - offset)), edge.IdDirected(), new EdgePath <T>()) }); } return(new EdgePath <T>[] { new EdgePath <T>(edge.From, weightHandler.Calculate(profileId, distance * offset), -edge.IdDirected(), new EdgePath <T>()) }); } else if (factor.Direction == 1) { // edge is forward oneway. if (asSource) { if (forward.Value) { return(new EdgePath <T>[] { new EdgePath <T>(edge.To, weightHandler.Calculate(profileId, distance * (1 - offset)), edge.IdDirected(), new EdgePath <T>()) }); } return(new EdgePath <T> [0]); } if (forward.Value) { return(new EdgePath <T> [0]); } return(new EdgePath <T>[] { new EdgePath <T>(edge.From, weightHandler.Calculate(profileId, distance * offset), -edge.IdDirected(), new EdgePath <T>()) }); } else { // edge is backward oneway. if (!asSource) { if (forward.Value) { return(new EdgePath <T>[] { new EdgePath <T>(edge.To, weightHandler.Calculate(profileId, distance * (1 - offset)), edge.IdDirected(), new EdgePath <T>()) }); } return(new EdgePath <T> [0]); } if (forward.Value) { return(new EdgePath <T> [0]); } return(new EdgePath <T>[] { new EdgePath <T>(edge.From, weightHandler.Calculate(profileId, distance * offset), -edge.IdDirected(), new EdgePath <T>()) }); } }
/// <summary> /// Creates a router point for the given edge. /// </summary> public static RouterPoint CreateRouterPointForEdge(this RouterDb routerDb, long directedEdgeId, bool atStart) { var edge = routerDb.Network.GetEdge(directedEdgeId); return(routerDb.CreateRouterPointForEdge(edge, directedEdgeId > 0, atStart)); }
/// <summary> /// Creates a new router. /// </summary> public Router(RouterDb db) { _db = db; this.VerifyAllStoppable = false; }