/// <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);
        }
Exemple #2
0
        /// <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));
        }
Exemple #3
0
        /// <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);
        }
Exemple #4
0
        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);
        }
Exemple #5
0
        /// <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);
        }
Exemple #7
0
        /// <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);
            }
        }
Exemple #8
0
        /// <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);
            }
        }