/// <summary> /// Builds a location referenced point for the last vertex. /// </summary> /// <returns></returns> public static Model.LocationReferencePoint BuildLocationReferencePointLast(this ReferencedLine referencedLocation, Coder coder, int before) { Model.FormOfWay fow; Model.FunctionalRoadClass frc; var end = referencedLocation.Vertices.Length - 1; // get all coordinates along the sequence starting at 'before' and ending at 'end'. var coordinates = referencedLocation.GetCoordinates(coder.Router.Db, before, end - before + 1); // create location reference point. var locationReferencedPoint = new Model.LocationReferencePoint(); locationReferencedPoint.Coordinate = coder.Router.Db.Network.GetVertex(referencedLocation.Vertices[end]).ToCoordinate(); var edgeProfile = coder.Router.Db.EdgeProfiles.Get(coder.Router.Db.Network.GetEdge(referencedLocation.Edges[end - 1]).Data.Profile); if (!coder.Profile.Extract(edgeProfile, out frc, out fow)) { throw new ReferencedEncodingException(referencedLocation, "Could not find frc and/or fow for the given tags."); } locationReferencedPoint.FormOfWay = fow; locationReferencedPoint.FuntionalRoadClass = frc; locationReferencedPoint.Bearing = (int)BearingEncoder.EncodeBearing(coordinates, true); return(locationReferencedPoint); }
/// <summary> /// Returns the bearing calculate between two given vertices along the given edge. /// </summary> /// <param name="vertexFrom"></param> /// <param name="edge"></param> /// <param name="edgeShape"></param> /// <param name="vertexTo"></param> /// <param name="forward">When true the edge is forward relative to the vertices, false the edge is backward.</param> /// <returns></returns> public virtual Degree GetBearing(long vertexFrom, LiveEdge edge, GeoCoordinateSimple[] edgeShape, long vertexTo, bool forward) { var coordinates = new List <GeoCoordinate>(); float latitude, longitude; this.Graph.GetVertex(vertexFrom, out latitude, out longitude); coordinates.Add(new GeoCoordinate(latitude, longitude)); if (edgeShape != null) { // there are intermediates, add them in the correct order. if (forward) { coordinates.AddRange(edgeShape.Select <GeoCoordinateSimple, GeoCoordinate>(x => { return(new GeoCoordinate(x.Latitude, x.Longitude)); })); } else { coordinates.AddRange(edgeShape.Reverse().Select <GeoCoordinateSimple, GeoCoordinate>(x => { return(new GeoCoordinate(x.Latitude, x.Longitude)); })); } } this.Graph.GetVertex(vertexTo, out latitude, out longitude); coordinates.Add(new GeoCoordinate(latitude, longitude)); return(BearingEncoder.EncodeBearing(coordinates)); }
/// <summary> /// Builds a location referenced point for the last vertex. /// </summary> /// <returns></returns> public LocationReferencePoint BuildLocationReferencePointLast(ReferencedLine referencedLocation, int before) { FormOfWay fow; FunctionalRoadClass frc; var end = referencedLocation.Vertices.Length - 1; // get all coordinates along the sequence starting at 'before' and ending at 'end'. var coordinates = referencedLocation.GetCoordinates(this.Graph, before, end - before + 1); // create location reference point. var locationReferencedPoint = new LocationReferencePoint(); locationReferencedPoint.Coordinate = this.GetVertexLocation(referencedLocation.Vertices[end]); var tags = this.GetTags(referencedLocation.Edges[end - 1].Tags); if (!this.TryMatching(tags, out frc, out fow)) { throw new ReferencedEncodingException(referencedLocation, "Could not find frc and/or fow for the given tags."); } locationReferencedPoint.FormOfWay = fow; locationReferencedPoint.FuntionalRoadClass = frc; locationReferencedPoint.Bearing = (int)BearingEncoder.EncodeBearing(coordinates, true).Value; return(locationReferencedPoint); }
public void TestBearingEncoding() { // (topLeft) ---- 12.5m ---- (topMiddle) ---- 12.5m ---- (topRight) // | | | // | | | // | | | // 10m 10m 10m // | | | // | | | // | | | // (left) ---- 12.5m ---- (middle) ---- 12.5m ---- (right) var left = new Coordinate(50.84431698343915f, 3.144611937981996f); var right = new Coordinate(50.84431699551239f, 3.1449685962923635f); var topLeft = new Coordinate(50.84440717501314f, 3.1446117265095705f); var topRight = new Coordinate(50.84440717501314f, 3.1449675435791398f); var middle = new Coordinate(50.8443169894425f, 3.144789284159275f); var topMiddle = new Coordinate(50.84440717501314f, 3.1447892841399474f); // encode left-right. var coordinates = new List <Coordinate>(); coordinates.Add(left); coordinates.Add(right); Assert.AreEqual(90, BearingEncoder.EncodeBearing(coordinates), 1); // encode right-left. coordinates = new List <Coordinate>(); coordinates.Add(right); coordinates.Add(left); Assert.AreEqual(270, BearingEncoder.EncodeBearing(coordinates), 1); // encode left-topLeft-topMiddle. coordinates = new List <Coordinate>(); coordinates.Add(left); coordinates.Add(topLeft); coordinates.Add(topMiddle); Assert.AreEqual(58.98, BearingEncoder.EncodeBearing(coordinates), 1); // encode middle-topMiddle-topLeft. coordinates = new List <Coordinate>(); coordinates.Add(middle); coordinates.Add(topMiddle); coordinates.Add(topLeft); Assert.AreEqual(301.01, BearingEncoder.EncodeBearing(coordinates), 1); }
/// <summary> /// Builds a location referenced point for the vertex at the given start-index. /// </summary> /// <returns></returns> public LocationReferencePoint BuildLocationReferencePoint(ReferencedLine referencedLocation, int start, int end) { FormOfWay fow; FunctionalRoadClass frc; // get all coordinates along the sequence starting at 'start' and ending at 'end'. var coordinates = referencedLocation.GetCoordinates(this.Graph, start, end - start + 1); // create location reference point. var locationReferencePoint = new LocationReferencePoint(); locationReferencePoint.Coordinate = this.GetVertexLocation(referencedLocation.Vertices[start]); var tags = this.GetTags(referencedLocation.Edges[start].Tags); if (!this.TryMatching(tags, out frc, out fow)) { throw new ReferencedEncodingException(referencedLocation, "Could not find frc and/or fow for the given tags."); } locationReferencePoint.FormOfWay = fow; locationReferencePoint.FuntionalRoadClass = frc; locationReferencePoint.Bearing = (int)BearingEncoder.EncodeBearing(coordinates).Value; locationReferencePoint.DistanceToNext = (int)coordinates.Length().Value; FunctionalRoadClass?lowest = null; for (var edge = start; edge < end; edge++) { tags = this.GetTags(referencedLocation.Edges[edge].Tags); if (!this.TryMatching(tags, out frc, out fow)) { throw new ReferencedEncodingException(referencedLocation, "Could not find frc and/or fow for the given tags."); } if (!lowest.HasValue || frc < lowest) { lowest = frc; } } locationReferencePoint.LowestFunctionalRoadClassToNext = lowest; return(locationReferencePoint); }
/// <summary> /// Builds a location referenced point for the vertex at the given start-index. /// </summary> /// <returns></returns> public static Model.LocationReferencePoint BuildLocationReferencePoint(this ReferencedLine referencedLocation, Coder coder, int start, int end) { Model.FormOfWay fow; Model.FunctionalRoadClass frc; // get all coordinates along the sequence starting at 'start' and ending at 'end'. var coordinates = referencedLocation.GetCoordinates(coder.Router.Db, start, end - start + 1); // create location reference point. var locationReferencePoint = new Model.LocationReferencePoint(); locationReferencePoint.Coordinate = coder.Router.Db.Network.GetVertex(referencedLocation.Vertices[start]).ToCoordinate(); var edgeProfile = coder.Router.Db.EdgeProfiles.Get(coder.Router.Db.Network.GetEdge(referencedLocation.Edges[start]).Data.Profile); if (!coder.Profile.Extract(edgeProfile, out frc, out fow)) { throw new ReferencedEncodingException(referencedLocation, "Could not find frc and/or fow for the given tags."); } locationReferencePoint.FormOfWay = fow; locationReferencePoint.FuntionalRoadClass = frc; locationReferencePoint.Bearing = (int)BearingEncoder.EncodeBearing(coordinates); locationReferencePoint.DistanceToNext = (int)coordinates.Length(); Model.FunctionalRoadClass?lowest = null; for (var edge = start; edge < end; edge++) { edgeProfile = coder.Router.Db.EdgeProfiles.Get(coder.Router.Db.Network.GetEdge(referencedLocation.Edges[edge]).Data.Profile); if (!coder.Profile.Extract(edgeProfile, out frc, out fow)) { throw new ReferencedEncodingException(referencedLocation, "Could not find frc and/or fow for the given tags."); } if (!lowest.HasValue || frc > lowest) { lowest = frc; } } locationReferencePoint.LowestFunctionalRoadClassToNext = lowest; return(locationReferencePoint); }
/// <summary> /// Returns true if the given vertex is a valid candidate to use as a location reference point. /// </summary> public static bool IsVertexValid(this Coder coder, uint vertex) { var profile = coder.Profile; var edges = coder.Router.Db.Network.GetEdges(vertex); // go over each arc and count the traversible arcs. var traversCount = 0; foreach (var edge in edges) { var factor = profile.Profile.Factor(coder.Router.Db.EdgeProfiles.Get(edge.Data.Profile)); if (factor.Value != 0) { traversCount++; } } if (traversCount != 3) { // no special cases, only 1=valid, 2=invalid or 4 and up=valid. if (traversCount == 2) { // only two traversable edges, no options here! return(false); } return(true); } else { // special cases possible here, we need more info here. var incoming = new List <Tuple <long, IAttributeCollection, uint> >(); var outgoing = new List <Tuple <long, IAttributeCollection, uint> >(); var bidirectional = new List <Tuple <long, IAttributeCollection, uint> >(); foreach (var edge in edges) { var edgeProfile = coder.Router.Db.EdgeProfiles.Get(edge.Data.Profile); var factor = profile.Profile.Factor(edgeProfile); if (factor.Value != 0) { if (factor.Direction == 0) { // bidirectional, can be used as incoming. bidirectional.Add(new Tuple <long, IAttributeCollection, uint>(edge.From, edgeProfile, edge.Id)); } else if ((factor.Direction == 2 && !edge.DataInverted) || (factor.Direction == 1 && edge.DataInverted)) { // oneway is forward but arc is backward, arc is incoming. // oneway is backward and arc is forward, arc is incoming. incoming.Add(new Tuple <long, IAttributeCollection, uint>(edge.From, edgeProfile, edge.Id)); } else if ((factor.Direction == 2 && edge.DataInverted) || (factor.Direction == 1 && !edge.DataInverted)) { // oneway is forward and arc is forward, arc is outgoing. // oneway is backward and arc is backward, arc is outgoing. outgoing.Add(new Tuple <long, IAttributeCollection, uint>(edge.From, edgeProfile, edge.Id)); } } } if (bidirectional.Count == 1 && incoming.Count == 1 && outgoing.Count == 1) { // all special cases are found here. // get incoming's frc and fow. FormOfWay incomingFow, outgoingFow, bidirectionalFow; FunctionalRoadClass incomingFrc, outgoingFrc, bidirectionalFrc; if (profile.Extract(incoming[0].Item2, out incomingFrc, out incomingFow)) { if (incomingFow == FormOfWay.Roundabout) { // is this a roundabout, always valid. return(true); } if (profile.Extract(outgoing[0].Item2, out outgoingFrc, out outgoingFow)) { if (outgoingFow == FormOfWay.Roundabout) { // is this a roundabout, always valid. return(true); } if (incomingFrc != outgoingFrc) { // is there a difference in frc. return(true); } if (profile.Extract(bidirectional[0].Item2, out bidirectionalFrc, out bidirectionalFow)) { if (incomingFrc != bidirectionalFrc) { // is there a difference in frc. return(true); } } } // at this stage we have: // - two oneways, in opposite direction // - one bidirectional // - all same frc. // the only thing left to check is if the oneway edges go in the same general direction or not. // compare bearings but only if distance is large enough. var incomingShape = coder.Router.Db.Network.GetShape(coder.Router.Db.Network.GetEdge(incoming[0].Item3)); var outgoingShape = coder.Router.Db.Network.GetShape(coder.Router.Db.Network.GetEdge(outgoing[0].Item3)); if (incomingShape.Length() < 25 && outgoingShape.Length() < 25) { // edges are too short to compare bearing in a way meaningful for determining this. // assume not valid. return(false); } var incomingBearing = BearingEncoder.EncodeBearing(incomingShape); var outgoingBearing = BearingEncoder.EncodeBearing(outgoingShape); if (OpenLR.Extensions.AngleSmallestDifference(incomingBearing, outgoingBearing) > 30) { // edges are clearly not going in the same direction. return(true); } } return(false); } return(true); } }
/// <summary> /// Returns true if the given vertex is a valid candidate to use as a location reference point. /// </summary> /// <param name="vertex">The vertex is validate.</param> /// <returns></returns> public virtual bool IsVertexValid(long vertex) { var arcs = this.Graph.GetEdges(vertex); // go over each arc and count the traversible arcs. var traversCount = 0; foreach (var arc in arcs) { var tags = this.Graph.TagsIndex.Get(arc.Value.Tags); if (this.Vehicle.CanTraverse(tags)) { traversCount++; } } if (traversCount != 3) { // no special cases, only 1=valid, 2=invalid or 4 and up=valid. if (traversCount == 2) { // only two traversable edges, no options here! return(false); } return(true); } else { // special cases possible here, we need more info here. var incoming = new List <Tuple <long, TagsCollectionBase, LiveEdge> >(); var outgoing = new List <Tuple <long, TagsCollectionBase, LiveEdge> >(); var bidirectional = new List <Tuple <long, TagsCollectionBase, LiveEdge> >(); foreach (var arc in arcs) { var tags = this.Graph.TagsIndex.Get(arc.Value.Tags); if (this.Vehicle.CanTraverse(tags)) { var oneway = this.Vehicle.IsOneWay(tags); if (!oneway.HasValue) { // bidirectional, can be used as incoming. bidirectional.Add(new Tuple <long, TagsCollectionBase, LiveEdge>(arc.Key, tags, arc.Value)); } else if (oneway.Value != arc.Value.Forward) { // oneway is forward but arc is backward, arc is incoming. // oneway is backward and arc is forward, arc is incoming. incoming.Add(new Tuple <long, TagsCollectionBase, LiveEdge>(arc.Key, tags, arc.Value)); } else if (oneway.Value == arc.Value.Forward) { // oneway is forward and arc is forward, arc is outgoing. // oneway is backward and arc is backward, arc is outgoing. outgoing.Add(new Tuple <long, TagsCollectionBase, LiveEdge>(arc.Key, tags, arc.Value)); } } } if (bidirectional.Count == 1 && incoming.Count == 1 && outgoing.Count == 1) { // all special cases are found here. // get incoming's frc and fow. FormOfWay incomingFow, outgoingFow, bidirectionalFow; FunctionalRoadClass incomingFrc, outgoingFrc, bidirectionalFrc; if (this.TryMatching(incoming[0].Item2, out incomingFrc, out incomingFow)) { if (incomingFow == FormOfWay.Roundabout) { // is this a roundabout, always valid. return(true); } if (this.TryMatching(outgoing[0].Item2, out outgoingFrc, out outgoingFow)) { if (outgoingFow == FormOfWay.Roundabout) { // is this a roundabout, always valid. return(true); } if (incomingFrc != outgoingFrc) { // is there a difference in frc. return(true); } if (this.TryMatching(bidirectional[0].Item2, out bidirectionalFrc, out bidirectionalFow)) { if (incomingFrc != bidirectionalFrc) { // is there a difference in frc. return(true); } } } // at this stage we have: // - two oneways, in opposite direction // - one bidirectional // - all same frc. // the only thing left to check is if the oneway edges go in the same general direction or not. // compare bearings but only if distance is large enough. var incomingShape = this.Graph.GetCoordinates(new Tuple <long, long, LiveEdge>( vertex, incoming[0].Item1, incoming[0].Item3)); var outgoingShape = this.Graph.GetCoordinates(new Tuple <long, long, LiveEdge>( vertex, outgoing[0].Item1, outgoing[0].Item3)); if (incomingShape.Length().Value < 25 && outgoingShape.Length().Value < 25) { // edges are too short to compare bearing in a way meaningful for determining this. // assume not valid. return(false); } var incomingBearing = BearingEncoder.EncodeBearing(incomingShape); var outgoingBearing = BearingEncoder.EncodeBearing(outgoingShape); if (incomingBearing.SmallestDifference(outgoingBearing) > 30) { // edges are clearly not going in the same direction. return(true); } } return(false); } return(true); } }