/// <summary> /// Matches nwb/fow. /// </summary> public virtual float Match(IAttributeCollection attributes, FormOfWay fow, FunctionalRoadClass frc) { FormOfWay actualFow; FunctionalRoadClass actualFrc; if (this.Extract(attributes, out actualFrc, out actualFow)) { // a mapping was found. match and score. return(MatchScoring.MatchAndScore(frc, fow, actualFrc, actualFow)); } return(0); }
/// <summary> /// Encodes a functional road class into binary data. /// </summary> /// <param name="functionalRoadClass"></param> /// <param name="data"></param> /// <param name="startIndex"></param> /// <param name="byteIndex"></param> public static void Encode(FunctionalRoadClass functionalRoadClass, byte[] data, int startIndex, int byteIndex) { if (byteIndex > 5) { throw new ArgumentOutOfRangeException("byteIndex", "byteIndex has to be a value in the range of [0-5]."); } byte value = 0; switch (functionalRoadClass) { case FunctionalRoadClass.Frc0: value = 0; break; case FunctionalRoadClass.Frc1: value = 1; break; case FunctionalRoadClass.Frc2: value = 2; break; case FunctionalRoadClass.Frc3: value = 3; break; case FunctionalRoadClass.Frc4: value = 4; break; case FunctionalRoadClass.Frc5: value = 5; break; case FunctionalRoadClass.Frc6: value = 6; break; case FunctionalRoadClass.Frc7: value = 7; break; } byte target = data[startIndex]; byte mask = (byte)(7 << (5 - byteIndex)); target = (byte)(target & ~mask); // set to zero. value = (byte)(value << (5 - byteIndex)); // move value to correct position. target = (byte)(target | value); // add to byte. data[startIndex] = target; }
/// <summary> /// Calculates a match between the tags collection and the properties of the OpenLR location reference. /// </summary> /// <param name="tags"></param> /// <param name="fow"></param> /// <param name="frc"></param> /// <returns></returns> public override float MatchArc(TagsCollectionBase tags, FormOfWay fow, FunctionalRoadClass frc) { FormOfWay actualFow; FunctionalRoadClass actualFrc; if (NWBMapping.ToOpenLR(tags, out actualFow, out actualFrc)) { // a mapping was found. match and score. return(MatchScoring.MatchAndScore(frc, fow, actualFrc, actualFow)); } return(0); }
/// <summary> /// Calculates a matching and score by comparing the expected agains the actual FRC's and FOW's. /// </summary> /// <param name="expectedFrc"></param> /// <param name="expectedFow"></param> /// <param name="actualFrc"></param> /// <param name="actualFow"></param> /// <returns></returns> public static float MatchAndScore(FunctionalRoadClass expectedFrc, FormOfWay expectedFow, FunctionalRoadClass actualFrc, FormOfWay actualFow) { if (expectedFow == actualFow && expectedFrc == actualFrc) { // perfect score. return(1); } // sore frc and fow seperately and take frc for 75% and fow for 25%. float frcWeight = .75f, fowWeight = .25f; return(MatchScoring.MatchAndScore(expectedFrc, actualFrc) * frcWeight + MatchScoring.MatchAndScore(expectedFow, actualFow) * fowWeight); }
/// <summary> /// Calculates a route between the two given vertices. /// </summary> /// <returns></returns> public abstract CandidateRoute FindCandidateRoute(CandidateVertexEdge from, CandidateVertexEdge to, FunctionalRoadClass minimum, bool ignoreFromEdge = false, bool ignoreToEdge = false);
/// <summary> /// Calculates a match between the tags collection and the properties of the OpenLR location reference. /// </summary> /// <param name="tags"></param> /// <param name="fow"></param> /// <param name="frc"></param> /// <returns></returns> public abstract float MatchArc(TagsCollectionBase tags, FormOfWay fow, FunctionalRoadClass frc);
/// <summary> /// Finds candidate edges starting at a given vertex matching a given fow and frc. /// </summary> /// <param name="vertex"></param> /// <param name="forward"></param> /// <param name="fow"></param> /// <param name="frc"></param> /// <param name="bearing"></param> /// <returns></returns> public virtual IEnumerable <CandidateEdge> FindCandidateEdgesFor(long vertex, bool forward, FormOfWay fow, FunctionalRoadClass frc, Degree bearing) { var relevantEdges = new List <CandidateEdge>(); foreach (var arc in this.Graph.GetEdges(vertex)) { var tags = this.Graph.TagsIndex.Get(arc.Value.Tags); // check one-way. if (_vehicle.CanTraverse(tags)) { // yay! can traverse. var oneway = _vehicle.IsOneWay(tags); if (oneway == null || (forward && oneway.Value == arc.Value.Forward) || (!forward && oneway.Value != arc.Value.Forward)) { var score = Score.New(Score.MATCH_ARC, "Metric indicating a match with fow, frc etc...", this.MatchArc(tags, fow, frc), 2); if (score.Value > 0) { // ok, there is a match. // check bearing. var shape = this.Graph.GetEdgeShape(vertex, arc.Key); var localBearing = this.GetBearing(vertex, arc.Value, shape, arc.Key, true); var localBearingDiff = (float)System.Math.Abs(localBearing.SmallestDifference(bearing)); relevantEdges.Add(new CandidateEdge() { TargetVertex = arc.Key, Score = score + Score.New(Score.BEARING_DIFF, "Bearing difference (0=0 & 180=1)", ((180f - localBearingDiff) / 180f), 1), Edge = arc.Value }); } } } } return(relevantEdges); }
/// <summary> /// Tries to match the given tags and figure out a corresponding frc and fow. /// </summary> /// <param name="tags"></param> /// <param name="frc"></param> /// <param name="fow"></param> /// <returns>False if no matching was found.</returns> public abstract bool TryMatching(TagsCollectionBase tags, out FunctionalRoadClass frc, out FormOfWay fow);
/// <summary> /// Calculates a matching and score by comparing the expected agains the actual FRC's. /// </summary> /// <param name="expected"></param> /// <param name="actual"></param> /// <returns></returns> public static float MatchAndScore(FunctionalRoadClass expected, FunctionalRoadClass actual) { if (expected == actual) { // perfect score for frc. return(1); } else { float frcOneDifferent = 0.8f; float frcTwoDifferent = 0.6f; float frcMoreDifferent = 0.2f; switch (expected) { case FunctionalRoadClass.Frc0: if (actual == FunctionalRoadClass.Frc1) { return(frcOneDifferent); } else if (actual == FunctionalRoadClass.Frc2) { return(frcTwoDifferent); } else { return(frcMoreDifferent); } case FunctionalRoadClass.Frc1: if (actual == FunctionalRoadClass.Frc0 || actual == FunctionalRoadClass.Frc2) { return(frcOneDifferent); } else if (actual == FunctionalRoadClass.Frc3) { return(frcTwoDifferent); } else { return(frcMoreDifferent); } case FunctionalRoadClass.Frc2: if (actual == FunctionalRoadClass.Frc1 || actual == FunctionalRoadClass.Frc3) { return(frcOneDifferent); } else if (actual == FunctionalRoadClass.Frc4 || actual == FunctionalRoadClass.Frc0) { return(frcTwoDifferent); } else { return(frcMoreDifferent); } case FunctionalRoadClass.Frc3: if (actual == FunctionalRoadClass.Frc2 || actual == FunctionalRoadClass.Frc4) { return(frcOneDifferent); } else if (actual == FunctionalRoadClass.Frc1 || actual == FunctionalRoadClass.Frc5) { return(frcTwoDifferent); } else { return(frcMoreDifferent); } case FunctionalRoadClass.Frc4: if (actual == FunctionalRoadClass.Frc3 || actual == FunctionalRoadClass.Frc5) { return(frcOneDifferent); } else if (actual == FunctionalRoadClass.Frc2 || actual == FunctionalRoadClass.Frc6) { return(frcTwoDifferent); } else { return(frcMoreDifferent); } case FunctionalRoadClass.Frc5: if (actual == FunctionalRoadClass.Frc4 || actual == FunctionalRoadClass.Frc6) { return(frcOneDifferent); } else if (actual == FunctionalRoadClass.Frc3 || actual == FunctionalRoadClass.Frc7) { return(frcTwoDifferent); } else { return(frcMoreDifferent); } case FunctionalRoadClass.Frc6: if (actual == FunctionalRoadClass.Frc5 || actual == FunctionalRoadClass.Frc7) { return(frcOneDifferent); } else if (actual == FunctionalRoadClass.Frc4) { return(frcTwoDifferent); } else { return(frcMoreDifferent); } case FunctionalRoadClass.Frc7: if (actual == FunctionalRoadClass.Frc6) { return(frcOneDifferent); } else if (actual == FunctionalRoadClass.Frc5) { return(frcTwoDifferent); } else { return(frcMoreDifferent); } } return(0); } }
/// <summary> /// Calculates a route between the two given vertices. /// </summary> public static CandidateRoute FindCandidateRoute(this Coder coder, CandidatePathSegment from, CandidatePathSegment to, FunctionalRoadClass minimum, bool invertTargetEdge = true) { var weightHandler = coder.Profile.Profile.DefaultWeightHandler(coder.Router); var directedEdgeFrom = from.Path.Edge; var directedEdgeTo = -to.Path.Edge; if (!invertTargetEdge) { directedEdgeTo = -directedEdgeTo; } // TODO: probably the bug is one-edge routes. var path = coder.Router.TryCalculateRaw(coder.Profile.Profile, weightHandler, directedEdgeFrom, directedEdgeTo, coder.Profile.RoutingSettings); if (Itinero.LocalGeo.Coordinate.DistanceEstimateInMeter(from.Location.Location(), to.Location.Location()) > coder.Profile.MaxSearch / 2) { try { coder.Profile.RoutingSettings.SetMaxSearch(coder.Profile.Profile.FullName, coder.Profile.MaxSearch * 4); path = coder.Router.TryCalculateRaw(coder.Profile.Profile, weightHandler, directedEdgeFrom, directedEdgeTo, coder.Profile.RoutingSettings); } catch { throw; } finally { coder.Profile.RoutingSettings.SetMaxSearch(coder.Profile.Profile.FullName, coder.Profile.MaxSearch); } } // if no route is found, score is 0. if (path.IsError) { return(new CandidateRoute() { Route = null, Score = Score.New(Score.CANDIDATE_ROUTE, "Candidate route quality.", 0, 1) }); } var pathAsList = path.Value.ToList(); var edges = new List <long>(); var vertices = new List <uint>(); for (var i = 0; i < pathAsList.Count; i++) { vertices.Add(pathAsList[i].Vertex); if (i > 0) { if (pathAsList[i].Edge != Itinero.Constants.NO_EDGE && pathAsList[i].Edge != -Itinero.Constants.NO_EDGE) { edges.Add(pathAsList[i].Edge); } else { var edgeEnumerator = coder.Router.Db.Network.GeometricGraph.Graph.GetEdgeEnumerator(); float best; var edge = edgeEnumerator.FindBestEdge(weightHandler, vertices[vertices.Count - 2], vertices[vertices.Count - 1], out best); edges.Add(edge); } } } var startLocation = from.Location; if (!from.Location.IsVertex()) { // first vertex is virtual. vertices[0] = Itinero.Constants.NO_VERTEX; } else { // make sure routerpoint has same edge. startLocation = coder.Router.Db.CreateRouterPointForEdgeAndVertex(edges[0], vertices[0]); } var endLocation = to.Location; if (!to.Location.IsVertex()) { // last vertex is virtual. vertices[vertices.Count - 1] = Itinero.Constants.NO_VERTEX; } else { // make sure routerpoint has the same edge. endLocation = coder.Router.Db.CreateRouterPointForEdgeAndVertex(edges[edges.Count - 1], vertices[vertices.Count - 1]); } return(new CandidateRoute() { Route = new ReferencedLine() { Edges = edges.ToArray(), Vertices = vertices.ToArray(), StartLocation = startLocation, EndLocation = endLocation }, Score = Score.New(Score.CANDIDATE_ROUTE, "Candidate route quality.", 1, 1) }); }
/// <summary> /// Finds candidate edges starting at a given vertex matching a given fow and frc. /// </summary> public static IEnumerable <CandidatePathSegment> FindCandidatePathSegmentsFor(this Coder coder, CandidateLocation location, bool forward, FormOfWay fow, FunctionalRoadClass frc, float bearing) { var profile = coder.Profile; var relevantEdges = new List <CandidatePathSegment>(); if (location.Location.IsVertex()) { // location is a vertex, probably 99% of the time. var vertex = location.Location.VertexId(coder.Router.Db); var edgeEnumerator = coder.Router.Db.Network.GetEdgeEnumerator(vertex); foreach (var edge in edgeEnumerator) { var edgeProfile = coder.Router.Db.EdgeProfiles.Get(edge.Data.Profile); var factor = profile.Profile.Factor(edgeProfile); if (factor.Value > 0 && (factor.Direction == 0 || (forward && (factor.Direction == 1) != edge.DataInverted) || (!forward && (factor.Direction == 1) == edge.DataInverted))) { var matchScore = Score.New(Score.MATCH_ARC, "Metric indicating a match with fow, frc etc...", profile.Match(edgeProfile, fow, frc), 2); if (matchScore.Value > 0) { // ok, there is a match. // check bearing. var shape = coder.Router.Db.Network.GetShape(edge); var localBearing = BearingEncoder.EncodeBearing(shape, false); var localBearingDiff = System.Math.Abs(Extensions.AngleSmallestDifference(localBearing, bearing)); var bearingScore = Score.New(Score.BEARING_DIFF, "Bearing difference score (0=1 & 180=0)", (1f - (localBearingDiff / 180f)) * 2, 2); relevantEdges.Add(new CandidatePathSegment() { Score = location.Score * (matchScore + bearingScore), Location = location.Location, Path = new EdgePath <float>(edge.To, factor.Value * edge.Data.Distance, edge.IdDirected(), new EdgePath <float>(vertex)) }); } } } } else { // location is not a vertex but a virtual point, try available directions. var paths = location.Location.ToEdgePaths(coder.Router.Db, coder.Profile.Profile.DefaultWeightHandlerCached(coder.Router.Db), forward); var edgeEnumerator = coder.Router.Db.Network.GetEdgeEnumerator(); var locationOnNetwork = location.Location.LocationOnNetwork(coder.Router.Db); foreach (var path in paths) { if (path.From == null) { throw new Exception("An LRP was resolved while at the same time it resolved to an exact vertex."); } edgeEnumerator.MoveToEdge(path.Edge); var edge = edgeEnumerator.Current; var edgeProfile = coder.Router.Db.EdgeProfiles.Get(edge.Data.Profile); var matchScore = Score.New(Score.MATCH_ARC, "Metric indicating a match with fow, frc etc...", profile.Match(edgeProfile, fow, frc), 2); if (matchScore.Value > 0) { // ok, there is a match. // check bearing. // get shape from location -> path. var shape = location.Location.ShapePointsTo(coder.Router.Db, path.Vertex); shape.Insert(0, locationOnNetwork); shape.Add(coder.Router.Db.Network.GetVertex(path.Vertex)); var localBearing = BearingEncoder.EncodeBearing(shape, false); var localBearingDiff = System.Math.Abs(Extensions.AngleSmallestDifference(localBearing, bearing)); var bearingScore = Score.New(Score.BEARING_DIFF, "Bearing difference score (0=1 & 180=0)", (1f - (localBearingDiff / 180f)) * 2, 2); relevantEdges.Add(new CandidatePathSegment() { Score = location.Score * (matchScore + bearingScore), Location = location.Location, Path = path }); } } } return(relevantEdges); }
/// <summary> /// Calculates a path between the two candidates using the information in the candidates. /// </summary> /// <returns></returns> public PathSegment <long> Calculate(BasicRouterDataSource <LiveEdge> graph, IRoutingInterpreter interpreter, Vehicle vehicle, CandidateVertexEdge from, CandidateVertexEdge to, FunctionalRoadClass minimum, uint maxSettles, bool ignoreFromEdge, bool ignoreToEdge) { // first check for the simple stuff. if (from.Vertex == to.Vertex) { // route consists of one vertex. return(new PathSegment <long>(from.Vertex)); } // check paths. var fromPath = new PathSegment <long>(from.TargetVertex, vehicle.Weight(graph.TagsIndex.Get(from.Edge.Tags), from.Edge.Distance), new PathSegment <long>(from.Vertex)); if (!ignoreFromEdge || !ignoreToEdge) { // do not check paths when one of the edges need to be ignored. if (from.Vertex == to.TargetVertex && to.Vertex == from.TargetVertex) { // edges are the same, return(fromPath); } } if (ignoreFromEdge) { // ignore from edge, just use the from-vertex. fromPath = new PathSegment <long>(from.Vertex); } // initialize the heap/visit list. var heap = new BinaryHeap <PathSegment <long> >(maxSettles / 4); var visited = new HashSet <long>(); visited.Add(from.Vertex); // set target. var target = to.Vertex; var targetWeight = double.MaxValue; if (!ignoreToEdge) { // also add the target to the visit list and actually search for the target candidate edge ending. target = to.TargetVertex; visited.Add(to.Vertex); } // create a path segment from the from-candidate. heap.Push(fromPath, (float)fromPath.Weight); // keep searching for the target. while (true) { // get the next vertex. var current = heap.Pop(); if (current == null) { // there is nothing more in the queue, target will not be found. break; } if (visited.Contains(current.VertexId)) { // move to the next neighbour. continue; } visited.Add(current.VertexId); // check for the target. if (current.VertexId == target) { // target was found. if (ignoreToEdge) { return(current); } return(new PathSegment <long>(to.Vertex, current.Weight, current)); } // check if the maximum settled vertex count has been reached. if (visited.Count >= maxSettles) { // stop search, target will not be found. break; } // add the neighbours to queue. var neighbours = graph.GetEdges(current.VertexId); if (neighbours != null) { // neighbours exist. foreach (var neighbour in neighbours) { // check if the neighbour was settled before. if (visited.Contains(neighbour.Key)) { // move to the next neighbour. continue; } // get tags and check traversability and oneway. var tags = graph.TagsIndex.Get(neighbour.Value.Tags); if (vehicle.CanTraverse(tags)) { // yay! can traverse. var oneway = vehicle.IsOneWay(tags); if (oneway == null || oneway.Value == neighbour.Value.Forward) { // create path to neighbour and queue it. var weight = vehicle.Weight(graph.TagsIndex.Get(neighbour.Value.Tags), neighbour.Value.Distance); var path = new PathSegment <long>(neighbour.Key, current.Weight + weight, current); if (path.Weight < targetWeight) { // the weight of the neighbour is smaller than the first neighbour found. heap.Push(path, (float)path.Weight); // save distance. if (path.VertexId == target) { // the target is already found, no use of queuing neigbours that have a higher weight. if (targetWeight > path.Weight) { // set the weight. targetWeight = path.Weight; } } } } } } } } return(null); }
/// <summary> /// Calculates a path between the two candidates using the information in the candidates. /// </summary> public PathSegment <long> Calculate(BasicRouterDataSource <LiveEdge> graph, IRoutingInterpreter interpreter, Vehicle vehicle, CandidateVertexEdge from, CandidateVertexEdge to, FunctionalRoadClass minimum, bool ignoreFromEdge, bool ignoreToEdge) { return(this.Calculate(graph, interpreter, vehicle, from, to, minimum, MaxSettles, ignoreFromEdge, ignoreToEdge)); }
/// <summary> /// Calculates a match between the tags collection and the properties of the OpenLR location reference. /// </summary> /// <param name="tags"></param> /// <param name="fow"></param> /// <param name="frc"></param> /// <returns></returns> public override float MatchArc(TagsCollectionBase tags, FormOfWay fow, FunctionalRoadClass frc) { string frcString; if (!tags.TryGetValue("FRC", out frcString)) { // not even an FRC column. return(0); } float frcOneDifferent = 0.8f; float frcTwoDifferent = 0.6f; float frcMoreDifferent = 0.4f; var frcScore = 0.0f; switch (frcString) { case "0": // main road. if (frc == FunctionalRoadClass.Frc0) { frcScore = 1; } else if (frc == FunctionalRoadClass.Frc1) { frcScore = frcOneDifferent; } else if (frc == FunctionalRoadClass.Frc2) { frcScore = frcTwoDifferent; } else { frcScore = frcMoreDifferent; } break; case "1": // first class road. if (frc == FunctionalRoadClass.Frc1) { frcScore = 1; } else if (frc == FunctionalRoadClass.Frc0 || frc == FunctionalRoadClass.Frc2) { frcScore = frcOneDifferent; } else if (frc == FunctionalRoadClass.Frc3) { frcScore = frcTwoDifferent; } else { frcScore = frcMoreDifferent; } break; case "2": // second class road. if (frc == FunctionalRoadClass.Frc2) { frcScore = 1; } else if (frc == FunctionalRoadClass.Frc1 || frc == FunctionalRoadClass.Frc3) { frcScore = frcOneDifferent; } else if (frc == FunctionalRoadClass.Frc4 || frc == FunctionalRoadClass.Frc0) { frcScore = frcTwoDifferent; } else { frcScore = frcMoreDifferent; } break; case "3": if (frc == FunctionalRoadClass.Frc3) { frcScore = 1; } else if (frc == FunctionalRoadClass.Frc2 || frc == FunctionalRoadClass.Frc4) { frcScore = frcOneDifferent; } else if (frc == FunctionalRoadClass.Frc1 || frc == FunctionalRoadClass.Frc5) { frcScore = frcTwoDifferent; } else { frcScore = frcMoreDifferent; } break; case "4": if (frc == FunctionalRoadClass.Frc4) { frcScore = 1; } else if (frc == FunctionalRoadClass.Frc3 || frc == FunctionalRoadClass.Frc5) { frcScore = frcOneDifferent; } else if (frc == FunctionalRoadClass.Frc2 || frc == FunctionalRoadClass.Frc6) { frcScore = frcTwoDifferent; } else { frcScore = frcMoreDifferent; } break; case "5": if (frc == FunctionalRoadClass.Frc5) { frcScore = 1; } else if (frc == FunctionalRoadClass.Frc4 || frc == FunctionalRoadClass.Frc6) { frcScore = frcOneDifferent; } else if (frc == FunctionalRoadClass.Frc3 || frc == FunctionalRoadClass.Frc7) { frcScore = frcTwoDifferent; } else { frcScore = frcMoreDifferent; } break; case "6": if (frc == FunctionalRoadClass.Frc6) { frcScore = 1; } else if (frc == FunctionalRoadClass.Frc5 || frc == FunctionalRoadClass.Frc7) { frcScore = frcOneDifferent; } else if (frc == FunctionalRoadClass.Frc4) { frcScore = frcTwoDifferent; } else { frcScore = frcMoreDifferent; } break; case "7": if (frc == FunctionalRoadClass.Frc7) { frcScore = 1; } else if (frc == FunctionalRoadClass.Frc6) { frcScore = frcOneDifferent; } else if (frc == FunctionalRoadClass.Frc5) { frcScore = frcTwoDifferent; } else { frcScore = frcMoreDifferent; } break; case "8": if (frc == FunctionalRoadClass.Frc7) { frcScore = frcOneDifferent; } else if (frc == FunctionalRoadClass.Frc6) { frcScore = frcTwoDifferent; } else { frcScore = frcMoreDifferent; } break; } float fowOneDifferent = 0.8f; float fowMoreDifferent = 0.4f; var fowScore = 0.0f; string fowString; if (tags.TryGetValue("FOW", out fowString)) { fowScore = 0.2f; switch (fowString) { case "1": if (fow == FormOfWay.Motorway) { fowScore = 1; } else if (fow == FormOfWay.MultipleCarriageWay) { fowScore = fowOneDifferent; } break; case "2": if (fow == FormOfWay.MultipleCarriageWay) { fowScore = 1; } else if (fow == FormOfWay.Motorway || fow == FormOfWay.SingleCarriageWay) { fowScore = fowOneDifferent; } break; case "3": if (fow == FormOfWay.SingleCarriageWay) { fowScore = 1; } else if (fow == FormOfWay.MultipleCarriageWay) { fowScore = fowOneDifferent; } break; case "4": if (fow == FormOfWay.Roundabout) { fowScore = 1; } fowScore = fowMoreDifferent; break; case "8": if (fow == FormOfWay.TrafficSquare) { fowScore = 1; } fowScore = fowMoreDifferent; break; case "10": if (fow == FormOfWay.SlipRoad) { fowScore = 1; } fowScore = fowMoreDifferent; break; case "6": case "7": case "9": case "11": case "12": case "14": case "15": if (fow == FormOfWay.Other) { fowScore = fowOneDifferent; } break; default: if (fow == FormOfWay.Undefined) { fowScore = fowMoreDifferent; } break; } } return(frcScore + fowScore); }
/// <summary> /// Tries to match the given tags and figure out a corresponding frc and fow. /// </summary> /// <param name="tags"></param> /// <param name="frc"></param> /// <param name="fow"></param> /// <returns>False if no matching was found.</returns> public override bool TryMatching(TagsCollectionBase tags, out FunctionalRoadClass frc, out FormOfWay fow) { frc = FunctionalRoadClass.Frc7; fow = FormOfWay.Undefined; string frcValue; if (tags.TryGetValue("FRC", out frcValue)) { switch (frcValue) { case "0": // main road. frc = FunctionalRoadClass.Frc0; break; case "1": // main road. frc = FunctionalRoadClass.Frc1; break; case "2": // main road. frc = FunctionalRoadClass.Frc2; break; case "3": // main road. frc = FunctionalRoadClass.Frc3; break; case "4": // main road. frc = FunctionalRoadClass.Frc4; break; case "5": // main road. frc = FunctionalRoadClass.Frc5; break; case "6": // main road. frc = FunctionalRoadClass.Frc6; break; case "7": // main road. frc = FunctionalRoadClass.Frc7; break; } } string fowValue; if (tags.TryGetValue("FOW", out fowValue)) { switch (fowValue) { case "1": // main road. fow = FormOfWay.Motorway; break; case "2": fow = FormOfWay.MultipleCarriageWay; break; case "3": fow = FormOfWay.SingleCarriageWay; break; case "4": fow = FormOfWay.Roundabout; break; case "8": fow = FormOfWay.TrafficSquare; break; case "10": fow = FormOfWay.SlipRoad; break; case "6": case "7": case "9": case "11": case "12": case "14": case "15": fow = FormOfWay.Other; break; } } return(true); }
/// <summary> /// Tries to extract fow/frc from the given attributes. /// </summary> public abstract bool Extract(IAttributeCollection tags, out FunctionalRoadClass frc, out FormOfWay fow);
/// <summary> /// Extracts nwb/fow. /// </summary> public override bool Extract(IAttributeCollection attributes, out FunctionalRoadClass frc, out FormOfWay fow) { fow = FormOfWay.Undefined; frc = FunctionalRoadClass.Frc7; string baansubsrt = string.Empty, wegbeerder = string.Empty, wegnummer = string.Empty, rijrichting = string.Empty, dvkletter_ = string.Empty; if (!attributes.TryGetValue(BAANSUBSRT, out baansubsrt) & !attributes.TryGetValue(WEGBEHSRT, out wegbeerder) & !attributes.TryGetValue(WEGNUMMER, out wegnummer) & !attributes.TryGetValue(HECTOLTTR, out dvkletter_) & !attributes.TryGetValue(RIJRICHTNG, out rijrichting)) { // not even a BAANSUBSRT tag! // defaults: FRC5, OTHER. fow = FormOfWay.Other; frc = FunctionalRoadClass.Frc5; return(true); } // make sure everything is lowercase. char?dvkletter = null; // assume dkv letter is the suffix used for exits etc. see: http://www.wegenwiki.nl/Hectometerpaal#Suffix if (!string.IsNullOrWhiteSpace(wegbeerder)) { wegbeerder = wegbeerder.ToLowerInvariant(); } if (!string.IsNullOrWhiteSpace(baansubsrt)) { baansubsrt = baansubsrt.ToLowerInvariant(); } if (!string.IsNullOrWhiteSpace(wegnummer)) { wegnummer = wegnummer.ToLowerInvariant(); if (!string.IsNullOrEmpty(dvkletter_)) { dvkletter = dvkletter_[0]; } } if (!string.IsNullOrWhiteSpace(rijrichting)) { rijrichting = rijrichting.ToLowerInvariant(); } fow = FormOfWay.Other; frc = FunctionalRoadClass.Frc5; if (wegbeerder == "r") { if (baansubsrt == "hr") { fow = FormOfWay.Motorway; frc = FunctionalRoadClass.Frc0; } else if (baansubsrt == "nrb" || baansubsrt == "mrb") { fow = FormOfWay.Roundabout; frc = FunctionalRoadClass.Frc0; } else if (baansubsrt == "pst") { if (dvkletter.HasValue) { fow = FormOfWay.SlipRoad; if (dvkletter == 'a' || dvkletter == 'b' || dvkletter == 'c' || dvkletter == 'd') { // r pst (a|b|c|d) frc = FunctionalRoadClass.Frc3; } else { // r pst !(a|b|c|d) frc = FunctionalRoadClass.Frc0; } } else if (!string.IsNullOrWhiteSpace(rijrichting)) { // r pst !(a|b|c|d) fow = FormOfWay.SlipRoad; frc = FunctionalRoadClass.Frc0; } } else if (baansubsrt == "opr" || baansubsrt == "afr") { frc = FunctionalRoadClass.Frc3; fow = FormOfWay.SlipRoad; } else if (baansubsrt.StartsWith("vb")) { if (!string.IsNullOrWhiteSpace(rijrichting)) { fow = FormOfWay.SlipRoad; frc = FunctionalRoadClass.Frc0; } } } else if (wegbeerder == "p") { if (baansubsrt == "hr") { frc = FunctionalRoadClass.Frc3; fow = FormOfWay.MultipleCarriageWay; if (string.IsNullOrWhiteSpace(rijrichting)) { frc = FunctionalRoadClass.Frc2; fow = FormOfWay.SingleCarriageWay; } } else if (baansubsrt == "nrb" || baansubsrt == "mrb") { frc = FunctionalRoadClass.Frc3; fow = FormOfWay.Roundabout; } else if (baansubsrt == "opr" || baansubsrt == "afr") { frc = FunctionalRoadClass.Frc3; fow = FormOfWay.SlipRoad; } else if (baansubsrt == "pst" || baansubsrt.StartsWith("vb")) { frc = FunctionalRoadClass.Frc3; fow = FormOfWay.SlipRoad; } } return(true); }
/// <summary> /// Tries to match the given tags and figure out a corresponding frc and fow. /// </summary> /// <param name="tags"></param> /// <param name="frc"></param> /// <param name="fow"></param> /// <returns>False if no matching was found.</returns> public override bool TryMatching(TagsCollectionBase tags, out FunctionalRoadClass frc, out FormOfWay fow) { frc = FunctionalRoadClass.Frc7; fow = FormOfWay.Undefined; string highway; if (tags.TryGetValue("highway", out highway)) { switch (highway) { // check there reference values against OSM: http://wiki.openstreetmap.org/wiki/Highway case "motorway": case "trunk": frc = FunctionalRoadClass.Frc0; break; case "primary": case "primary_link": frc = FunctionalRoadClass.Frc1; break; case "secondary": case "secondary_link": frc = FunctionalRoadClass.Frc2; break; case "tertiary": case "tertiary_link": frc = FunctionalRoadClass.Frc3; break; case "road": case "road_link": case "unclassified": case "residential": frc = FunctionalRoadClass.Frc4; break; case "living_street": frc = FunctionalRoadClass.Frc5; break; default: frc = FunctionalRoadClass.Frc7; break; } switch (highway) { // check there reference values against OSM: http://wiki.openstreetmap.org/wiki/Highway case "motorway": case "trunk": fow = FormOfWay.Motorway; break; case "primary": case "primary_link": fow = FormOfWay.MultipleCarriageWay; break; case "secondary": case "secondary_link": case "tertiary": case "tertiary_link": fow = FormOfWay.SingleCarriageWay; break; default: fow = FormOfWay.SingleCarriageWay; break; } return(true); // should never fail on a highway tag. } return(false); }
/// <summary> /// Tries to match the given tags and figure out a corresponding frc and fow. /// </summary> /// <param name="tags"></param> /// <param name="frc"></param> /// <param name="fow"></param> /// <returns>False if no matching was found.</returns> protected bool TryMatching(TagsCollectionBase tags, out FunctionalRoadClass frc, out FormOfWay fow) { return(_mainEncoder.TryMatching(tags, out frc, out fow)); }
/// <summary> /// Calculates a match between the tags collection and the properties of the OpenLR location reference. /// </summary> /// <param name="tags"></param> /// <param name="fow"></param> /// <param name="frc"></param> /// <returns></returns> public override float MatchArc(TagsCollectionBase tags, FormOfWay fow, FunctionalRoadClass frc) { string highway; if (!tags.TryGetValue("highway", out highway)) { // not even a highway tag! return(0); } // TODO: take into account form of way? Maybe not for OSM-data? switch (frc) { // check there reference values against OSM: http://wiki.openstreetmap.org/wiki/Highway case FunctionalRoadClass.Frc0: // main road. if (highway == "motorway" || highway == "trunk") { return(1); } break; case FunctionalRoadClass.Frc1: // first class road. if (highway == "primary" || highway == "primary_link") { return(1); } break; case FunctionalRoadClass.Frc2: // second class road. if (highway == "secondary" || highway == "secondary_link") { return(1); } break; case FunctionalRoadClass.Frc3: // third class road. if (highway == "tertiary" || highway == "tertiary_link") { return(1); } break; case FunctionalRoadClass.Frc4: if (highway == "road" || highway == "road_link" || highway == "unclassified" || highway == "residential") { return(1); } break; case FunctionalRoadClass.Frc5: if (highway == "road" || highway == "road_link" || highway == "unclassified" || highway == "residential" || highway == "living_street") { return(1); } break; case FunctionalRoadClass.Frc6: if (highway == "road" || highway == "track" || highway == "unclassified" || highway == "residential" || highway == "living_street") { return(1); } break; case FunctionalRoadClass.Frc7: // other class road. if (highway == "footway" || highway == "bridleway" || highway == "steps" || highway == "path" || highway == "living_street") { return(1); } break; } if (highway != null && highway.Length > 0) { // for any other highway return a low match. return(0.2f); } return(0); }
/// <summary> /// Calculates a route between the two given vertices. /// </summary> /// <returns></returns> public override CandidateRoute FindCandidateRoute(CandidateVertexEdge from, CandidateVertexEdge to, FunctionalRoadClass minimum, bool ignoreFromEdge = false, bool ignoreToEdge = false) { var edgeInterpreter = new ShapefileEdgeInterpreter(); var interpreter = new ShapefileRoutingInterpreter(); var path = this.GetRouter().Calculate(this.Graph, interpreter, this.Vehicle, from, to, minimum, ignoreFromEdge, ignoreToEdge); // if no route is found, score is 0. if (path == null) { return(new CandidateRoute() { Route = null, Score = Score.New(Score.CANDIDATE_ROUTE, "Candidate route quality.", 0, 1) }); } var edges = new List <LiveEdge>(); var vertices = new List <long>(); vertices.Add(path.VertexId); while (path.From != null) { // add to vertices list. vertices.Add(path.From.VertexId); // get edge between current and from. var fromVertex = path.From.VertexId; var toVertex = path.VertexId; var edgeDistance = double.MaxValue; var arcs = this.Graph.GetEdges(fromVertex); LiveEdge?edge = null; foreach (var arc in arcs) { if (arc.Key == toVertex && arc.Value.Distance < edgeDistance) { // there is a candidate arc. edgeDistance = arc.Value.Distance; edge = arc.Value; } } if (!edge.HasValue) { // this should be impossible. throw new Exception("No edge found between two consequtive vertices on a route."); } edges.Add(edge.Value); // move to next segment. path = path.From; } // reverse lists. edges.Reverse(); vertices.Reverse(); // fill shapes. var edgeShapes = new GeoCoordinateSimple[edges.Count][]; for (int i = 0; i < edges.Count; i++) { edgeShapes[i] = this.Graph.GetEdgeShape(vertices[i], vertices[i + 1]); } return(new CandidateRoute() { Route = new ReferencedLine(this.Graph) { Edges = edges.ToArray(), EdgeShapes = edgeShapes, Vertices = vertices.ToArray() }, Score = Score.New(Score.CANDIDATE_ROUTE, "Candidate route quality.", 1, 1) }); }
/// <summary> /// Tries to match the given tags and figure out a corresponding frc and fow. /// </summary> /// <param name="tags"></param> /// <param name="frc"></param> /// <param name="fow"></param> /// <returns>False if no matching was found.</returns> public override bool TryMatching(TagsCollectionBase tags, out FunctionalRoadClass frc, out FormOfWay fow) { return(NWBMapping.ToOpenLR(tags, out fow, out frc)); }