/// <summary>
        /// Compares all routes against the reference router.
        /// </summary>
        public void TestCompareAll(string embeddedName)
        {
            // build the routing settings.
            IRoutingInterpreter interpreter = new OsmSharp.Routing.Osm.Interpreter.OsmRoutingInterpreter();

            // get the osm data source.
            IBasicRouterDataSource <LiveEdge> data = this.BuildDykstraDataSource(interpreter, embeddedName);

            // build the reference router.;
            Router referenceRouter = this.BuildDykstraRouter(
                this.BuildDykstraDataSource(interpreter, embeddedName), interpreter,
                new DykstraRoutingLive(data.TagsIndex));

            // build the router to be tested.
            Router router = this.BuildRouter(interpreter, embeddedName);

            // loop over all nodes and resolve their locations.
            var resolvedReference = new RouterPoint[data.VertexCount - 1];
            var resolved          = new RouterPoint[data.VertexCount - 1];

            for (uint idx = 1; idx < data.VertexCount; idx++)
            { // resolve each vertex.
                float latitude, longitude;
                if (data.GetVertex(idx, out latitude, out longitude))
                {
                    resolvedReference[idx - 1] = referenceRouter.Resolve(Vehicle.Car, new GeoCoordinate(latitude, longitude));
                    resolved[idx - 1]          = router.Resolve(Vehicle.Car, new GeoCoordinate(latitude, longitude));
                }

                Assert.IsNotNull(resolvedReference[idx - 1]);
                Assert.IsNotNull(resolved[idx - 1]);

                Assert.AreEqual(resolvedReference[idx - 1].Location.Latitude,
                                resolved[idx - 1].Location.Latitude, 0.0001);
                Assert.AreEqual(resolvedReference[idx - 1].Location.Longitude,
                                resolved[idx - 1].Location.Longitude, 0.0001);
            }

            // check all the routes having the same weight(s).
            for (int fromIdx = 0; fromIdx < resolved.Length; fromIdx++)
            {
                for (int toIdx = 0; toIdx < resolved.Length; toIdx++)
                {
                    OsmSharpRoute referenceRoute = referenceRouter.Calculate(Vehicle.Car,
                                                                             resolvedReference[fromIdx], resolvedReference[toIdx]);
                    OsmSharpRoute route = router.Calculate(Vehicle.Car,
                                                           resolved[fromIdx], resolved[toIdx]);

                    Assert.IsNotNull(referenceRoute);
                    Assert.IsNotNull(route);
                    Assert.AreEqual(referenceRoute.TotalDistance, route.TotalDistance, 0.0001);
                    // TODO: meta data is missing in some CH routing; see issue
                    //Assert.AreEqual(reference_route.TotalTime, route.TotalTime, 0.0001);
                }
            }
        }
示例#2
0
        /// <summary>
        /// Tests that a router actually finds the shortest route.
        /// </summary>
        protected void DoTestShortestDefault()
        {
            var interpreter = new OsmRoutingInterpreter();
            IBasicRouterDataSource <TEdgeData> data        = this.BuildData(interpreter, "OsmSharp.Test.Unittests.test_network.osm");
            IBasicRouter <TEdgeData>           basicRouter = this.BuildBasicRouter(data);
            Router router = this.BuildRouter(
                data, interpreter, basicRouter);
            RouterPoint source = router.Resolve(Vehicle.Car, new GeoCoordinate(51.0578532, 3.7192229));
            RouterPoint target = router.Resolve(Vehicle.Car, new GeoCoordinate(51.0576193, 3.7191801));

            Route route = router.Calculate(Vehicle.Car, source, target);

            Assert.IsNotNull(route);
            Assert.AreEqual(5, route.Entries.Length);

            float latitude, longitude;

            data.GetVertex(20, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Entries[0].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Entries[0].Longitude, 0.00001);
            Assert.AreEqual(RoutePointEntryType.Start, route.Entries[0].Type);

            data.GetVertex(21, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Entries[1].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Entries[1].Longitude, 0.00001);
            Assert.AreEqual(RoutePointEntryType.Along, route.Entries[1].Type);

            data.GetVertex(16, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Entries[2].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Entries[2].Longitude, 0.00001);
            Assert.AreEqual(RoutePointEntryType.Along, route.Entries[2].Type);

            data.GetVertex(22, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Entries[3].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Entries[3].Longitude, 0.00001);
            Assert.AreEqual(RoutePointEntryType.Along, route.Entries[3].Type);

            data.GetVertex(23, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Entries[4].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Entries[4].Longitude, 0.00001);
            Assert.AreEqual(RoutePointEntryType.Stop, route.Entries[4].Type);
        }
        /// <summary>
        /// Tests the the given router class by comparing calculated routes agains a given reference router.
        /// </summary>
        /// <param name="data"></param>
        /// <param name="referenceRouter"></param>
        /// <param name="router"></param>
        protected void TestCompareAll <TEdgeData>(IBasicRouterDataSource <TEdgeData> data, Router referenceRouter, Router router)
            where TEdgeData : IGraphEdgeData
        {
            // loop over all nodes and resolve their locations.
            var resolvedReference = new RouterPoint[data.VertexCount - 1];
            var resolved          = new RouterPoint[data.VertexCount - 1];

            for (uint idx = 1; idx < data.VertexCount; idx++)
            { // resolve each vertex.
                float latitude, longitude;
                if (data.GetVertex(idx, out latitude, out longitude))
                {
                    resolvedReference[idx - 1] = referenceRouter.Resolve(Vehicle.Car, new GeoCoordinate(latitude, longitude), true);
                    resolved[idx - 1]          = router.Resolve(Vehicle.Car, new GeoCoordinate(latitude, longitude), true);
                }

                // reference and resolved have to exist.
                Assert.IsNotNull(resolvedReference[idx - 1]);
                Assert.IsNotNull(resolved[idx - 1]);

                // reference and resolved cannot be more than 10cm apart.
                Assert.AreEqual(0, resolvedReference[idx - 1].Location.DistanceReal(
                                    resolved[idx - 1].Location).Value, 0.1, "Reference and resolved are more than 10cm apart.");
            }

            // limit tests to a fixed number.
            int maxTestCount   = 100;
            int testEveryOther = (resolved.Length * resolved.Length) / maxTestCount;

            testEveryOther = System.Math.Max(testEveryOther, 1);

            // check all the routes having the same weight(s).
            for (int fromIdx = 0; fromIdx < resolved.Length; fromIdx++)
            {
                for (int toIdx = 0; toIdx < resolved.Length; toIdx++)
                {
                    int testNumber = fromIdx * resolved.Length + toIdx;
                    if (testNumber % testEveryOther == 0)
                    {
                        var referenceRoute = referenceRouter.Calculate(Vehicle.Car,
                                                                       resolvedReference[fromIdx], resolvedReference[toIdx]);
                        var route = router.Calculate(Vehicle.Car,
                                                     resolved[fromIdx], resolved[toIdx]);

                        if (referenceRoute != null)
                        {
                            Assert.IsNotNull(referenceRoute);
                            Assert.IsNotNull(route);
                            this.CompareRoutes(referenceRoute, route);
                        }
                    }
                }
            }
        }
示例#4
0
        /// <summary>
        /// Tests that a router actually finds the shortest route.
        /// </summary>
        protected void DoTestShortestWithDirection()
        {
            var interpreter = new OsmRoutingInterpreter();
            IBasicRouterDataSource <EdgeData> data        = this.BuildData(interpreter);
            IBasicRouter <EdgeData>           basicRouter = this.BuildBasicRouter(data);
            Router router = this.BuildRouter(
                data, interpreter, basicRouter);
            RouterPoint source = router.Resolve(Vehicle.Car, new GeoCoordinate(51.0582205, 3.7192647)); // -52
            RouterPoint target = router.Resolve(Vehicle.Car, new GeoCoordinate(51.0579530, 3.7196168)); // -56

            OsmSharpRoute route = router.Calculate(Vehicle.Car, source, target);

            Assert.IsNotNull(route);
            Assert.AreEqual(4, route.Entries.Length);

            float latitude, longitude;

            data.GetVertex(19, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Entries[0].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Entries[0].Longitude, 0.00001);
            Assert.AreEqual(RoutePointEntryType.Start, route.Entries[0].Type);

            data.GetVertex(8, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Entries[1].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Entries[1].Longitude, 0.00001);
            Assert.AreEqual(RoutePointEntryType.Along, route.Entries[1].Type);

            data.GetVertex(9, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Entries[2].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Entries[2].Longitude, 0.00001);
            Assert.AreEqual(RoutePointEntryType.Along, route.Entries[2].Type);

            data.GetVertex(10, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Entries[3].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Entries[3].Longitude, 0.00001);
            Assert.AreEqual(RoutePointEntryType.Stop, route.Entries[3].Type);
        }
示例#5
0
        /// <summary>
        /// Tests that a router preserves tags given to resolved points.
        /// </summary>
        protected void DoTestResolvedTags()
        {
            var interpreter = new OsmRoutingInterpreter();
            IBasicRouterDataSource <TEdgeData> data        = this.BuildData(interpreter, "OsmSharp.Test.Unittests.test_network.osm");
            IBasicRouter <TEdgeData>           basicRouter = this.BuildBasicRouter(data);
            Router router = this.BuildRouter(
                data, interpreter, basicRouter);
            RouterPoint source = router.Resolve(Vehicle.Car, new GeoCoordinate(51.0578532, 3.7192229));

            source.Tags.Add(new KeyValuePair <string, string>("name", "source"));
            RouterPoint target = router.Resolve(Vehicle.Car, new GeoCoordinate(51.0576193, 3.7191801));

            target.Tags.Add(new KeyValuePair <string, string>("name", "target"));

            Route route = router.Calculate(Vehicle.Car, source, target);

            Assert.IsNotNull(route);
            Assert.AreEqual(5, route.Entries.Length);

            float latitude, longitude;

            data.GetVertex(20, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Entries[0].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Entries[0].Longitude, 0.00001);
            Assert.AreEqual(RoutePointEntryType.Start, route.Entries[0].Type);
            Assert.IsNotNull(route.Entries[0].Points[0].Tags);
            Assert.AreEqual(1, route.Entries[0].Points[0].Tags.Length);
            Assert.AreEqual("source", route.Entries[0].Points[0].Tags[0].Value);

            data.GetVertex(23, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Entries[4].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Entries[4].Longitude, 0.00001);
            Assert.AreEqual(RoutePointEntryType.Stop, route.Entries[4].Type);
            Assert.IsNotNull(route.Entries[4].Points[0].Tags);
            Assert.AreEqual(1, route.Entries[4].Points[0].Tags.Length);
            Assert.AreEqual("target", route.Entries[4].Points[0].Tags[0].Value);
        }
示例#6
0
        /// <summary>
        /// Tests that a router actually finds the shortest route.
        /// </summary>
        /// <param name="vehicle"></param>
        /// <param name="accessTags"></param>
        protected void DoTestShortestWithAccess(Vehicle vehicle, List <KeyValuePair <string, string> > accessTags)
        {
            var interpreter = new OsmRoutingInterpreter();
            IBasicRouterDataSource <EdgeData> data        = this.BuildData(interpreter, vehicle, accessTags);
            IBasicRouter <EdgeData>           basicRouter = this.BuildBasicRouter(data, vehicle);
            Router router = this.BuildRouter(
                data, interpreter, basicRouter);
            RouterPoint source = router.Resolve(vehicle, new GeoCoordinate(51.0582205, 3.7192647)); // -52
            RouterPoint target = router.Resolve(vehicle, new GeoCoordinate(51.0579530, 3.7196168)); // -56

            Route route = router.Calculate(vehicle, source, target);

            Assert.IsNotNull(route);
            Assert.AreEqual(4, route.Segments.Length);

            float latitude, longitude;

            data.GetVertex(19, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Segments[0].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Segments[0].Longitude, 0.00001);
            Assert.AreEqual(RouteSegmentType.Start, route.Segments[0].Type);

            data.GetVertex(8, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Segments[1].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Segments[1].Longitude, 0.00001);
            Assert.AreEqual(RouteSegmentType.Along, route.Segments[1].Type);

            data.GetVertex(9, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Segments[2].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Segments[2].Longitude, 0.00001);
            Assert.AreEqual(RouteSegmentType.Along, route.Segments[2].Type);

            data.GetVertex(10, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Segments[3].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Segments[3].Longitude, 0.00001);
            Assert.AreEqual(RouteSegmentType.Stop, route.Segments[3].Type);
        }
示例#7
0
        /// <summary>
        /// Test if the resolving of nodes returns those same nodes.
        ///
        /// (does not work on a lazy loading data source!)
        /// </summary>
        protected void DoTestResolveAllNodes()
        {
            var interpreter = new OsmRoutingInterpreter();
            IBasicRouterDataSource <EdgeData> data        = this.BuildData(interpreter);
            IBasicRouter <EdgeData>           basicRouter = this.BuildBasicRouter(data);
            Router router = this.BuildRouter(
                data, interpreter, basicRouter);

            for (int idx = 1; idx < data.VertexCount; idx++)
            {
                float latitude, longitude;
                if (data.GetVertex((uint)idx, out latitude, out longitude))
                {
                    RouterPoint point = router.Resolve(Vehicle.Car, new GeoCoordinate(latitude, longitude));
                    Assert.AreEqual(idx, (point as RouterPoint).Id);
                }
            }
        }
        public void RoutingSerializationV2CompressedRoutingTest()
        {
            const string embeddedString = "OsmSharp.Test.Unittests.test_network.osm";

            // create the tags index.
            var tagsIndex = new SimpleTagsIndex();

            // creates a new interpreter.
            var interpreter = new OsmRoutingInterpreter();

            // do the data processing.
            var original =
                new DynamicGraphRouterDataSource <LiveEdge>(tagsIndex);
            var targetData = new LiveGraphOsmStreamTarget(
                original, interpreter, tagsIndex);
            var dataProcessorSource = new XmlOsmStreamSource(
                Assembly.GetExecutingAssembly().GetManifestResourceStream(embeddedString));

            targetData.RegisterSource(dataProcessorSource);
            targetData.Pull();

            // create serializer.
            var routingSerializer = new V2RoutingDataSourceLiveEdgeSerializer(true);

            // serialize/deserialize.
            byte[] byteArray;
            using (var stream = new MemoryStream())
            {
                try
                {
                    routingSerializer.Serialize(stream, original);
                    byteArray = stream.ToArray();
                }
                catch (Exception)
                {
                    if (Debugger.IsAttached)
                    {
                        Debugger.Break();
                    }
                    throw;
                }
            }

            IBasicRouterDataSource <LiveEdge> deserializedVersion =
                routingSerializer.Deserialize(new MemoryStream(byteArray));

            Assert.AreEqual(original.TagsIndex.Get(0), deserializedVersion.TagsIndex.Get(0));

            // try to do some routing on the deserialized version.
            var         basicRouter = new DykstraRoutingLive();
            Router      router      = Router.CreateLiveFrom(deserializedVersion, basicRouter, interpreter);
            RouterPoint source      = router.Resolve(Vehicle.Car,
                                                     new GeoCoordinate(51.0578532, 3.7192229));
            RouterPoint target = router.Resolve(Vehicle.Car,
                                                new GeoCoordinate(51.0576193, 3.7191801));

            // calculate the route.
            Route route = router.Calculate(Vehicle.Car, source, target);

            Assert.IsNotNull(route);
            Assert.AreEqual(5, route.Entries.Length);

            float latitude, longitude;

            deserializedVersion.GetVertex(20, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Entries[0].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Entries[0].Longitude, 0.00001);
            Assert.AreEqual(RoutePointEntryType.Start, route.Entries[0].Type);

            deserializedVersion.GetVertex(21, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Entries[1].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Entries[1].Longitude, 0.00001);
            Assert.AreEqual(RoutePointEntryType.Along, route.Entries[1].Type);

            deserializedVersion.GetVertex(16, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Entries[2].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Entries[2].Longitude, 0.00001);
            Assert.AreEqual(RoutePointEntryType.Along, route.Entries[2].Type);

            deserializedVersion.GetVertex(22, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Entries[3].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Entries[3].Longitude, 0.00001);
            Assert.AreEqual(RoutePointEntryType.Along, route.Entries[3].Type);

            deserializedVersion.GetVertex(23, out latitude, out longitude);
            Assert.AreEqual(latitude, route.Entries[4].Latitude, 0.00001);
            Assert.AreEqual(longitude, route.Entries[4].Longitude, 0.00001);
            Assert.AreEqual(RoutePointEntryType.Stop, route.Entries[4].Type);
        }
示例#9
0
        /// <summary>
        /// Searches the data for a point on an edge closest to the given coordinate.
        /// </summary>
        /// <param name="graph"></param>
        /// <param name="vehicle"></param>
        /// <param name="coordinate"></param>
        /// <param name="delta"></param>
        /// <param name="matcher"></param>
        /// <param name="pointTags"></param>
        /// <param name="interpreter"></param>
        /// <param name="verticesOnly"></param>
        public SearchClosestResult SearchClosest(IBasicRouterDataSource <TEdgeData> graph, IRoutingInterpreter interpreter, Vehicle vehicle,
                                                 GeoCoordinate coordinate, float delta, IEdgeMatcher matcher, TagsCollection pointTags, bool verticesOnly)
        {
            var closestWithMatch    = new SearchClosestResult(double.MaxValue, 0);
            var closestWithoutMatch = new SearchClosestResult(double.MaxValue, 0);

            double searchBoxSize = delta;
            // create the search box.
            var searchBox = new GeoCoordinateBox(new GeoCoordinate(
                                                     coordinate.Latitude - searchBoxSize, coordinate.Longitude - searchBoxSize),
                                                 new GeoCoordinate(
                                                     coordinate.Latitude + searchBoxSize, coordinate.Longitude + searchBoxSize));

            // get the arcs from the data source.
            KeyValuePair <uint, KeyValuePair <uint, TEdgeData> >[] arcs = graph.GetArcs(searchBox);

            if (!verticesOnly)
            { // find both closest arcs and vertices.
                // loop over all.
                foreach (KeyValuePair <uint, KeyValuePair <uint, TEdgeData> > arc in arcs)
                {
                    TagsCollection arcTags        = graph.TagsIndex.Get(arc.Value.Value.Tags);
                    bool           canBeTraversed = vehicle.CanTraverse(arcTags);
                    if (canBeTraversed)
                    { // the edge can be traversed.
                        // test the two points.
                        float  fromLatitude, fromLongitude;
                        float  toLatitude, toLongitude;
                        double distance;
                        if (graph.GetVertex(arc.Key, out fromLatitude, out fromLongitude) &&
                            graph.GetVertex(arc.Value.Key, out toLatitude, out toLongitude))
                        { // return the vertex.
                            var fromCoordinates = new GeoCoordinate(fromLatitude, fromLongitude);
                            distance = coordinate.Distance(fromCoordinates);

                            if (distance < 0.00001)
                            { // the distance is smaller than the tolerance value.
                                closestWithoutMatch = new SearchClosestResult(
                                    distance, arc.Key);
                                if (matcher == null ||
                                    (pointTags == null || pointTags.Count == 0) ||
                                    matcher.MatchWithEdge(vehicle, pointTags, arcTags))
                                {
                                    closestWithMatch = new SearchClosestResult(
                                        distance, arc.Key);
                                    break;
                                }
                            }

                            if (distance < closestWithoutMatch.Distance)
                            { // the distance is smaller for the without match.
                                closestWithoutMatch = new SearchClosestResult(
                                    distance, arc.Key);
                            }
                            if (distance < closestWithMatch.Distance)
                            { // the distance is smaller for the with match.
                                if (matcher == null ||
                                    (pointTags == null || pointTags.Count == 0) ||
                                    matcher.MatchWithEdge(vehicle, pointTags, graph.TagsIndex.Get(arc.Value.Value.Tags)))
                                {
                                    closestWithMatch = new SearchClosestResult(
                                        distance, arc.Key);
                                }
                            }
                            var toCoordinates = new GeoCoordinate(toLatitude, toLongitude);
                            distance = coordinate.Distance(toCoordinates);

                            if (distance < closestWithoutMatch.Distance)
                            { // the distance is smaller for the without match.
                                closestWithoutMatch = new SearchClosestResult(
                                    distance, arc.Value.Key);
                            }
                            if (distance < closestWithMatch.Distance)
                            { // the distance is smaller for the with match.
                                if (matcher == null ||
                                    (pointTags == null || pointTags.Count == 0) ||
                                    matcher.MatchWithEdge(vehicle, pointTags, arcTags))
                                {
                                    closestWithMatch = new SearchClosestResult(
                                        distance, arc.Value.Key);
                                }
                            }

                            // create a line.
                            double distanceTotal = fromCoordinates.Distance(toCoordinates);
                            if (distanceTotal > 0)
                            { // the from/to are not the same location.
                                var line = new GeoCoordinateLine(fromCoordinates, toCoordinates, true, true);
                                distance = line.Distance(coordinate);

                                if (distance < closestWithoutMatch.Distance)
                                { // the distance is smaller.
                                    PointF2D projectedPoint =
                                        line.ProjectOn(coordinate);

                                    // calculate the position.
                                    if (projectedPoint != null)
                                    { // calculate the distance
                                        double distancePoint = fromCoordinates.Distance(projectedPoint);
                                        double position      = distancePoint / distanceTotal;

                                        closestWithoutMatch = new SearchClosestResult(
                                            distance, arc.Key, arc.Value.Key, position);
                                    }
                                }
                                if (distance < closestWithMatch.Distance)
                                {
                                    PointF2D projectedPoint =
                                        line.ProjectOn(coordinate);

                                    // calculate the position.
                                    if (projectedPoint != null)
                                    { // calculate the distance
                                        double distancePoint = fromCoordinates.Distance(projectedPoint);
                                        double position      = distancePoint / distanceTotal;

                                        if (matcher == null ||
                                            (pointTags == null || pointTags.Count == 0) ||
                                            matcher.MatchWithEdge(vehicle, pointTags, arcTags))
                                        {
                                            closestWithMatch = new SearchClosestResult(
                                                distance, arc.Key, arc.Value.Key, position);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            else
            { // only find closest vertices.
                // loop over all.
                foreach (KeyValuePair <uint, KeyValuePair <uint, TEdgeData> > arc in arcs)
                {
                    float fromLatitude, fromLongitude;
                    float toLatitude, toLongitude;
                    if (graph.GetVertex(arc.Key, out fromLatitude, out fromLongitude) &&
                        graph.GetVertex(arc.Value.Key, out toLatitude, out toLongitude))
                    {
                        var    vertexCoordinate = new GeoCoordinate(fromLatitude, fromLongitude);
                        double distance         = coordinate.Distance(vertexCoordinate);
                        if (distance < closestWithoutMatch.Distance)
                        { // the distance found is closer.
                            closestWithoutMatch = new SearchClosestResult(
                                distance, arc.Key);
                        }

                        vertexCoordinate = new GeoCoordinate(toLatitude, toLongitude);
                        distance         = coordinate.Distance(vertexCoordinate);
                        if (distance < closestWithoutMatch.Distance)
                        { // the distance found is closer.
                            closestWithoutMatch = new SearchClosestResult(
                                distance, arc.Value.Key);
                        }
                    }
                }
            }

            // return the best result.
            if (closestWithMatch.Distance < double.MaxValue)
            {
                return(closestWithMatch);
            }
            return(closestWithoutMatch);
        }
示例#10
0
        /// <summary>
        /// Builds the scene.
        /// </summary>
        /// <param name="map"></param>
        /// <param name="zoomFactor"></param>
        /// <param name="center"></param>
        /// <param name="view"></param>
        private void BuildScene(Map map, float zoomFactor, GeoCoordinate center, View2D view)
        {
            // get the indexed object at this zoom.
            HashSet <ArcId> interpretedObjects;

            if (!_interpretedObjects.TryGetValue((int)zoomFactor, out interpretedObjects))
            {
                interpretedObjects = new HashSet <ArcId>();
                _interpretedObjects.Add((int)zoomFactor, interpretedObjects);
            }

            // build the boundingbox.
            var viewBox = view.OuterBox;
            var box     = new GeoCoordinateBox(map.Projection.ToGeoCoordinates(viewBox.Min[0], viewBox.Min[1]),
                                               map.Projection.ToGeoCoordinates(viewBox.Max[0], viewBox.Max[1]));

            foreach (var requestedBox in _requestedBoxes)
            {
                if (requestedBox.Contains(box))
                {
                    return;
                }
            }
            _requestedBoxes.Add(box);

            //// set the scene backcolor.
            //SimpleColor? color = _styleInterpreter.GetCanvasColor ();
            //_scene.BackColor = color.HasValue
            //                               ? color.Value.Value
            //                               : SimpleColor.FromArgb (0, 255, 255, 255).Value;

            // get data.
            foreach (var arc in _dataSource.GetEdges(box))
            {
                // translate each object into scene object.
                var arcId = new ArcId()
                {
                    Vertex1 = arc.Key,
                    Vertex2 = arc.Value.Key
                };
                if (!interpretedObjects.Contains(arcId))
                {
                    interpretedObjects.Add(arcId);

                    // create nodes.
                    float latitude, longitude;
                    _dataSource.GetVertex(arcId.Vertex1, out latitude, out longitude);
                    var node1 = new Node();
                    node1.Id        = arcId.Vertex1;
                    node1.Latitude  = latitude;
                    node1.Longitude = longitude;
                    _dataSource.GetVertex(arcId.Vertex2, out latitude, out longitude);
                    var node2 = new Node();
                    node2.Id        = arcId.Vertex2;
                    node2.Latitude  = latitude;
                    node2.Longitude = longitude;

                    // create way.
                    var way = CompleteWay.Create(-1);
                    if (arc.Value.Value.Forward)
                    {
                        way.Nodes.Add(node1);
                        way.Nodes.Add(node2);
                    }
                    else
                    {
                        way.Nodes.Add(node2);
                        way.Nodes.Add(node1);
                    }
                    way.Tags.AddOrReplace(_dataSource.TagsIndex.Get(arc.Value.Value.Tags));

                    _styleInterpreter.Translate(_scene, map.Projection, way);
                    interpretedObjects.Add(arcId);
                }
            }
        }
示例#11
0
        /// <summary>
        /// Does dykstra calculation(s) with several options.
        /// </summary>
        /// <param name="graph"></param>
        /// <param name="interpreter"></param>
        /// <param name="vehicle"></param>
        /// <param name="sourceList"></param>
        /// <param name="targetList"></param>
        /// <param name="weight"></param>
        /// <param name="stopAtFirst"></param>
        /// <param name="returnAtWeight"></param>
        /// <param name="forward"></param>
        /// <returns></returns>
        private PathSegment <long>[] DoCalculation(IBasicRouterDataSource <LiveEdge> graph, IRoutingInterpreter interpreter, Vehicle vehicle,
                                                   PathSegmentVisitList sourceList, PathSegmentVisitList[] targetList, double weight,
                                                   bool stopAtFirst, bool returnAtWeight, bool forward)
        {
            // make copies of the target and source visitlist.
            PathSegmentVisitList source = sourceList.Clone() as PathSegmentVisitList;

            PathSegmentVisitList[] targets = new PathSegmentVisitList[targetList.Length];
            for (int targetIdx = 0; targetIdx < targetList.Length; targetIdx++)
            {
                targets[targetIdx] = targetList[targetIdx].Clone() as PathSegmentVisitList;
            }

            //  initialize the result data structures.
            var  segmentsAtWeight = new List <PathSegment <long> >();
            var  segmentsToTarget = new PathSegment <long> [targets.Length]; // the resulting target segments.
            long foundTargets     = 0;

            // intialize dykstra data structures.
            IPriorityQueue <PathSegment <long> > heap = new BinairyHeap <PathSegment <long> >();
            var chosenVertices = new HashSet <long>();
            var labels         = new Dictionary <long, IList <RoutingLabel> >();

            foreach (long vertex in source.GetVertices())
            {
                labels[vertex] = new List <RoutingLabel>();

                PathSegment <long> path = source.GetPathTo(vertex);
                heap.Push(path, (float)path.Weight);
            }

            // set the from node as the current node and put it in the correct data structures.
            // intialize the source's neighbours.
            PathSegment <long> current = heap.Pop();

            while (current != null &&
                   chosenVertices.Contains(current.VertexId))
            { // keep dequeuing.
                current = heap.Pop();
            }

            // test each target for the source.
            // test each source for any of the targets.
            var pathsFromSource = new Dictionary <long, PathSegment <long> >();

            foreach (long sourceVertex in source.GetVertices())
            {                                                                   // get the path to the vertex.
                PathSegment <long> sourcePath = source.GetPathTo(sourceVertex); // get the source path.
                sourcePath = sourcePath.From;
                while (sourcePath != null)
                { // add the path to the paths from source.
                    pathsFromSource[sourcePath.VertexId] = sourcePath;
                    sourcePath = sourcePath.From;
                }
            }
            // loop over all targets
            for (int idx = 0; idx < targets.Length; idx++)
            { // check for each target if there are paths to the source.
                foreach (long targetVertex in targets[idx].GetVertices())
                {
                    PathSegment <long> targetPath = targets[idx].GetPathTo(targetVertex); // get the target path.
                    targetPath = targetPath.From;
                    while (targetPath != null)
                    { // add the path to the paths from source.
                        PathSegment <long> pathFromSource;
                        if (pathsFromSource.TryGetValue(targetPath.VertexId, out pathFromSource))
                        { // a path is found.
                            // get the existing path if any.
                            PathSegment <long> existing = segmentsToTarget[idx];
                            if (existing == null)
                            { // a path did not exist yet!
                                segmentsToTarget[idx] = targetPath.Reverse().ConcatenateAfter(pathFromSource);
                                foundTargets++;
                            }
                            else if (existing.Weight > targetPath.Weight + pathFromSource.Weight)
                            { // a new path is found with a lower weight.
                                segmentsToTarget[idx] = targetPath.Reverse().ConcatenateAfter(pathFromSource);
                            }
                        }
                        targetPath = targetPath.From;
                    }
                }
            }
            if (foundTargets == targets.Length && targets.Length > 0)
            { // routing is finished!
                return(segmentsToTarget.ToArray());
            }

            if (stopAtFirst)
            {     // only one entry is needed.
                if (foundTargets > 0)
                { // targets found, return the shortest!
                    PathSegment <long> shortest = null;
                    foreach (PathSegment <long> foundTarget in segmentsToTarget)
                    {
                        if (shortest == null)
                        {
                            shortest = foundTarget;
                        }
                        else if (foundTarget != null &&
                                 shortest.Weight > foundTarget.Weight)
                        {
                            shortest = foundTarget;
                        }
                    }
                    segmentsToTarget    = new PathSegment <long> [1];
                    segmentsToTarget[0] = shortest;
                    return(segmentsToTarget);
                }
                else
                { // not targets found yet!
                    segmentsToTarget = new PathSegment <long> [1];
                }
            }

            // test for identical start/end point.
            for (int idx = 0; idx < targets.Length; idx++)
            {
                PathSegmentVisitList target = targets[idx];
                if (returnAtWeight)
                { // add all the reached vertices larger than weight to the results.
                    if (current.Weight > weight)
                    {
                        PathSegment <long> toPath = target.GetPathTo(current.VertexId);
                        toPath.Reverse();
                        toPath = toPath.ConcatenateAfter(current);
                        segmentsAtWeight.Add(toPath);
                    }
                }
                else if (target.Contains(current.VertexId))
                { // the current is a target!
                    PathSegment <long> toPath = target.GetPathTo(current.VertexId);
                    toPath = toPath.Reverse();
                    toPath = toPath.ConcatenateAfter(current);

                    if (stopAtFirst)
                    { // stop at the first occurance.
                        segmentsToTarget[0] = toPath;
                        return(segmentsToTarget);
                    }
                    else
                    { // normal one-to-many; add to the result.
                        // check if routing is finished.
                        if (segmentsToTarget[idx] == null)
                        { // make sure only the first route is set.
                            foundTargets++;
                            segmentsToTarget[idx] = toPath;
                            if (foundTargets == targets.Length)
                            { // routing is finished!
                                return(segmentsToTarget.ToArray());
                            }
                        }
                        else if (segmentsToTarget[idx].Weight > toPath.Weight)
                        { // check if the second, third or later is shorter.
                            segmentsToTarget[idx] = toPath;
                        }
                    }
                }
            }

            // start OsmSharp.Routing.
            KeyValuePair <uint, LiveEdge>[] arcs = graph.GetArcs(
                Convert.ToUInt32(current.VertexId));
            chosenVertices.Add(current.VertexId);

            // loop until target is found and the route is the shortest!
            while (true)
            {
                // get the current labels list (if needed).
                IList <RoutingLabel> currentLabels = null;
                if (interpreter.Constraints != null)
                { // there are constraints, get the labels.
                    currentLabels = labels[current.VertexId];
                    labels.Remove(current.VertexId);
                }

                float latitude, longitude;
                graph.GetVertex(Convert.ToUInt32(current.VertexId), out latitude, out longitude);
                var currentCoordinates = new GeoCoordinate(latitude, longitude);

                // update the visited nodes.
                foreach (KeyValuePair <uint, LiveEdge> neighbour in arcs)
                {
                    // check the tags against the interpreter.
                    TagsCollection tags = graph.TagsIndex.Get(neighbour.Value.Tags);
                    if (vehicle.CanTraverse(tags))
                    { // it's ok; the edge can be traversed by the given vehicle.
                        bool?oneWay = vehicle.IsOneWay(tags);
                        bool canBeTraversedOneWay = (!oneWay.HasValue || oneWay.Value == neighbour.Value.Forward);
                        if ((current.From == null ||
                             interpreter.CanBeTraversed(current.From.VertexId, current.VertexId, neighbour.Key)) && // test for turning restrictions.
                            canBeTraversedOneWay &&
                            !chosenVertices.Contains(neighbour.Key))
                        { // the neigbour is forward and is not settled yet!
                            // check the labels (if needed).
                            bool constraintsOk = true;
                            if (interpreter.Constraints != null)
                            { // check if the label is ok.
                                RoutingLabel neighbourLabel = interpreter.Constraints.GetLabelFor(
                                    graph.TagsIndex.Get(neighbour.Value.Tags));

                                // only test labels if there is a change.
                                if (currentLabels.Count == 0 || !neighbourLabel.Equals(currentLabels[currentLabels.Count - 1]))
                                { // labels are different, test them!
                                    constraintsOk = interpreter.Constraints.ForwardSequenceAllowed(currentLabels,
                                                                                                   neighbourLabel);

                                    if (constraintsOk)
                                    { // update the labels.
                                        var neighbourLabels = new List <RoutingLabel>(currentLabels);
                                        neighbourLabels.Add(neighbourLabel);

                                        labels[neighbour.Key] = neighbourLabels;
                                    }
                                }
                                else
                                { // set the same label(s).
                                    labels[neighbour.Key] = currentLabels;
                                }
                            }

                            if (constraintsOk)
                            { // all constraints are validated or there are none.
                                graph.GetVertex(Convert.ToUInt32(neighbour.Key), out latitude, out longitude);
                                var neighbourCoordinates = new GeoCoordinate(latitude, longitude);

                                // calculate the weight.
                                double weightToNeighbour = vehicle.Weight(tags, currentCoordinates, neighbourCoordinates);

                                // calculate neighbours weight.
                                double totalWeight = current.Weight + weightToNeighbour;

                                // update the visit list;
                                var neighbourRoute = new PathSegment <long>(neighbour.Key, totalWeight, current);
                                heap.Push(neighbourRoute, (float)neighbourRoute.Weight);
                            }
                        }
                    }
                }

                // while the visit list is not empty.
                current = null;
                if (heap.Count > 0)
                {
                    // choose the next vertex.
                    current = heap.Pop();
                    while (current != null &&
                           chosenVertices.Contains(current.VertexId))
                    { // keep dequeuing.
                        current = heap.Pop();
                    }
                    if (current != null)
                    {
                        chosenVertices.Add(current.VertexId);
                    }
                }
                while (current != null && current.Weight > weight)
                {
                    if (returnAtWeight)
                    { // add all the reached vertices larger than weight to the results.
                        segmentsAtWeight.Add(current);
                    }

                    // choose the next vertex.
                    current = heap.Pop();
                    while (current != null &&
                           chosenVertices.Contains(current.VertexId))
                    { // keep dequeuing.
                        current = heap.Pop();
                    }
                }

                if (current == null)
                { // route is not found, there are no vertices left
                    // or the search whent outside of the max bounds.
                    break;
                }

                // check target.
                for (int idx = 0; idx < targets.Length; idx++)
                {
                    PathSegmentVisitList target = targets[idx];
                    if (target.Contains(current.VertexId))
                    { // the current is a target!
                        PathSegment <long> toPath = target.GetPathTo(current.VertexId);
                        toPath = toPath.Reverse();
                        toPath = toPath.ConcatenateAfter(current);

                        if (stopAtFirst)
                        { // stop at the first occurance.
                            segmentsToTarget[0] = toPath;
                            return(segmentsToTarget);
                        }
                        else
                        { // normal one-to-many; add to the result.
                            // check if routing is finished.
                            if (segmentsToTarget[idx] == null)
                            { // make sure only the first route is set.
                                segmentsToTarget[idx] = toPath;
                            }
                            else if (segmentsToTarget[idx].Weight > toPath.Weight)
                            { // check if the second, third or later is shorter.
                                segmentsToTarget[idx] = toPath;
                            }

                            // remove this vertex from this target's paths.
                            target.Remove(current.VertexId);

                            // if this target is empty it's optimal route has been found.
                            if (target.Count == 0)
                            { // now the shortest route has been found for sure!
                                foundTargets++;
                                if (foundTargets == targets.Length)
                                { // routing is finished!
                                    return(segmentsToTarget.ToArray());
                                }
                            }
                        }
                    }
                }

                // get the neigbours of the current node.
                arcs = graph.GetArcs(Convert.ToUInt32(current.VertexId));
            }

            // return the result.
            if (!returnAtWeight)
            {
                return(segmentsToTarget.ToArray());
            }
            return(segmentsAtWeight.ToArray());
        }
示例#12
0
        /// <summary>
        /// Searches the data for a point on an edge closest to the given coordinate.
        /// </summary>
        /// <param name="graph"></param>
        /// <param name="vehicle"></param>
        /// <param name="coordinate"></param>
        /// <param name="delta"></param>
        /// <param name="matcher"></param>
        /// <param name="pointTags"></param>
        /// <param name="interpreter"></param>
        /// <param name="verticesOnly"></param>
        /// <param name="parameters"></param>
        public SearchClosestResult <TEdgeData> SearchClosest(IBasicRouterDataSource <TEdgeData> graph, IRoutingInterpreter interpreter, Vehicle vehicle,
                                                             GeoCoordinate coordinate, float delta, IEdgeMatcher matcher, TagsCollectionBase pointTags, bool verticesOnly, Dictionary <string, object> parameters)
        {
            Meter distanceEpsilon = .1; // 10cm is the tolerance to distinguish points.

            var closestWithMatch    = new SearchClosestResult <TEdgeData>(double.MaxValue, 0);
            var closestWithoutMatch = new SearchClosestResult <TEdgeData>(double.MaxValue, 0);

            double searchBoxSize = delta;
            // create the search box.
            var searchBox = new GeoCoordinateBox(new GeoCoordinate(
                                                     coordinate.Latitude - searchBoxSize, coordinate.Longitude - searchBoxSize),
                                                 new GeoCoordinate(
                                                     coordinate.Latitude + searchBoxSize, coordinate.Longitude + searchBoxSize));

            // get the arcs from the data source.
            var arcs = graph.GetEdges(searchBox);

            if (!verticesOnly)
            { // find both closest arcs and vertices.
                // loop over all.
                while (arcs.MoveNext())
                {
                    if (!graph.TagsIndex.Contains(arcs.EdgeData.Tags))
                    { // skip this edge, no valid tags found.
                        continue;
                    }
                    var arcTags        = graph.TagsIndex.Get(arcs.EdgeData.Tags);
                    var canBeTraversed = vehicle.CanTraverse(arcTags);
                    if (canBeTraversed)
                    { // the edge can be traversed.
                        // test the two points.
                        float  fromLatitude, fromLongitude;
                        float  toLatitude, toLongitude;
                        double distance;
                        if (graph.GetVertex(arcs.Vertex1, out fromLatitude, out fromLongitude) &&
                            graph.GetVertex(arcs.Vertex2, out toLatitude, out toLongitude))
                        { // return the vertex.
                            var fromCoordinates = new GeoCoordinate(fromLatitude, fromLongitude);
                            distance = coordinate.DistanceReal(fromCoordinates).Value;
                            ICoordinateCollection coordinates;
                            ICoordinate[]         coordinatesArray = null;
                            if (!graph.GetEdgeShape(arcs.Vertex1, arcs.Vertex2, out coordinates))
                            {
                                coordinates = null;
                            }
                            if (coordinates != null)
                            {
                                coordinatesArray = coordinates.ToArray();
                            }

                            if (distance < distanceEpsilon.Value)
                            { // the distance is smaller than the tolerance value.
                                closestWithoutMatch = new SearchClosestResult <TEdgeData>(
                                    distance, arcs.Vertex1);
                                if (matcher == null ||
                                    (pointTags == null || pointTags.Count == 0) ||
                                    matcher.MatchWithEdge(vehicle, pointTags, arcTags))
                                {
                                    closestWithMatch = new SearchClosestResult <TEdgeData>(
                                        distance, arcs.Vertex1);
                                    break;
                                }
                            }

                            if (distance < closestWithoutMatch.Distance)
                            { // the distance is smaller for the without match.
                                closestWithoutMatch = new SearchClosestResult <TEdgeData>(
                                    distance, arcs.Vertex1);
                            }
                            if (distance < closestWithMatch.Distance)
                            { // the distance is smaller for the with match.
                                if (matcher == null ||
                                    (pointTags == null || pointTags.Count == 0) ||
                                    matcher.MatchWithEdge(vehicle, pointTags, graph.TagsIndex.Get(arcs.EdgeData.Tags)))
                                {
                                    closestWithMatch = new SearchClosestResult <TEdgeData>(
                                        distance, arcs.Vertex1);
                                }
                            }
                            var toCoordinates = new GeoCoordinate(toLatitude, toLongitude);
                            distance = coordinate.DistanceReal(toCoordinates).Value;

                            if (distance < closestWithoutMatch.Distance)
                            { // the distance is smaller for the without match.
                                closestWithoutMatch = new SearchClosestResult <TEdgeData>(
                                    distance, arcs.Vertex2);
                            }
                            if (distance < closestWithMatch.Distance)
                            { // the distance is smaller for the with match.
                                if (matcher == null ||
                                    (pointTags == null || pointTags.Count == 0) ||
                                    matcher.MatchWithEdge(vehicle, pointTags, arcTags))
                                {
                                    closestWithMatch = new SearchClosestResult <TEdgeData>(
                                        distance, arcs.Vertex2);
                                }
                            }

                            // search along the line.
                            var distanceTotal            = 0.0;
                            var previous                 = fromCoordinates;
                            var arcValueValueCoordinates = arcs.Intermediates;
                            if (arcValueValueCoordinates != null)
                            { // calculate distance along all coordinates.
                                var arcValueValueCoordinatesArray = arcValueValueCoordinates.ToArray();
                                for (int idx = 0; idx < arcValueValueCoordinatesArray.Length; idx++)
                                {
                                    var current = new GeoCoordinate(arcValueValueCoordinatesArray[idx].Latitude, arcValueValueCoordinatesArray[idx].Longitude);
                                    distanceTotal = distanceTotal + current.DistanceReal(previous).Value;
                                    previous      = current;
                                }
                            }
                            distanceTotal = distanceTotal + toCoordinates.DistanceReal(previous).Value;
                            if (distanceTotal > 0)
                            { // the from/to are not the same location.
                                // loop over all edges that are represented by this arc (counting intermediate coordinates).
                                previous = fromCoordinates;
                                GeoCoordinateLine line;
                                var distanceToSegment = 0.0;
                                if (arcValueValueCoordinates != null)
                                {
                                    var arcValueValueCoordinatesArray = arcValueValueCoordinates.ToArray();
                                    for (int idx = 0; idx < arcValueValueCoordinatesArray.Length; idx++)
                                    {
                                        var current = new GeoCoordinate(
                                            arcValueValueCoordinatesArray[idx].Latitude, arcValueValueCoordinatesArray[idx].Longitude);
                                        line = new GeoCoordinateLine(previous, current, true, true);

                                        distance = line.DistanceReal(coordinate).Value;

                                        if (distance < closestWithoutMatch.Distance)
                                        { // the distance is smaller.
                                            var projectedPoint = line.ProjectOn(coordinate);

                                            // calculate the position.
                                            if (projectedPoint != null)
                                            { // calculate the distance
                                                var distancePoint = previous.DistanceReal(new GeoCoordinate(projectedPoint)).Value + distanceToSegment;
                                                var position      = distancePoint / distanceTotal;

                                                closestWithoutMatch = new SearchClosestResult <TEdgeData>(
                                                    distance, arcs.Vertex1, arcs.Vertex2, position, arcs.EdgeData, coordinatesArray);
                                            }
                                        }
                                        if (distance < closestWithMatch.Distance)
                                        {
                                            var projectedPoint = line.ProjectOn(coordinate);

                                            // calculate the position.
                                            if (projectedPoint != null)
                                            { // calculate the distance
                                                var distancePoint = previous.DistanceReal(new GeoCoordinate(projectedPoint)).Value + distanceToSegment;
                                                var position      = distancePoint / distanceTotal;

                                                if (matcher == null ||
                                                    (pointTags == null || pointTags.Count == 0) ||
                                                    matcher.MatchWithEdge(vehicle, pointTags, arcTags))
                                                {
                                                    closestWithMatch = new SearchClosestResult <TEdgeData>(
                                                        distance, arcs.Vertex1, arcs.Vertex2, position, arcs.EdgeData, coordinatesArray);
                                                }
                                            }
                                        }

                                        // add current segment distance to distanceToSegment for the next segment.
                                        distanceToSegment = distanceToSegment + line.LengthReal.Value;

                                        // set previous.
                                        previous = current;
                                    }
                                }

                                // check the last segment.
                                line = new GeoCoordinateLine(previous, toCoordinates, true, true);

                                distance = line.DistanceReal(coordinate).Value;

                                if (distance < closestWithoutMatch.Distance)
                                { // the distance is smaller.
                                    var projectedPoint = line.ProjectOn(coordinate);

                                    // calculate the position.
                                    if (projectedPoint != null)
                                    { // calculate the distance
                                        double distancePoint = previous.DistanceReal(new GeoCoordinate(projectedPoint)).Value + distanceToSegment;
                                        double position      = distancePoint / distanceTotal;

                                        closestWithoutMatch = new SearchClosestResult <TEdgeData>(
                                            distance, arcs.Vertex1, arcs.Vertex2, position, arcs.EdgeData, coordinatesArray);
                                    }
                                }
                                if (distance < closestWithMatch.Distance)
                                {
                                    var projectedPoint = line.ProjectOn(coordinate);

                                    // calculate the position.
                                    if (projectedPoint != null)
                                    { // calculate the distance
                                        double distancePoint = previous.DistanceReal(new GeoCoordinate(projectedPoint)).Value + distanceToSegment;
                                        double position      = distancePoint / distanceTotal;

                                        if (matcher == null ||
                                            (pointTags == null || pointTags.Count == 0) ||
                                            matcher.MatchWithEdge(vehicle, pointTags, arcTags))
                                        {
                                            closestWithMatch = new SearchClosestResult <TEdgeData>(
                                                distance, arcs.Vertex1, arcs.Vertex2, position, arcs.EdgeData, coordinatesArray);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            else
            { // only find closest vertices.
                // loop over all.
                while (arcs.MoveNext())
                {
                    float fromLatitude, fromLongitude;
                    float toLatitude, toLongitude;
                    if (graph.GetVertex(arcs.Vertex1, out fromLatitude, out fromLongitude) &&
                        graph.GetVertex(arcs.Vertex2, out toLatitude, out toLongitude))
                    {
                        var    vertexCoordinate = new GeoCoordinate(fromLatitude, fromLongitude);
                        double distance         = coordinate.DistanceReal(vertexCoordinate).Value;
                        if (distance < closestWithoutMatch.Distance)
                        { // the distance found is closer.
                            closestWithoutMatch = new SearchClosestResult <TEdgeData>(
                                distance, arcs.Vertex1);
                        }

                        vertexCoordinate = new GeoCoordinate(toLatitude, toLongitude);
                        distance         = coordinate.DistanceReal(vertexCoordinate).Value;
                        if (distance < closestWithoutMatch.Distance)
                        { // the distance found is closer.
                            closestWithoutMatch = new SearchClosestResult <TEdgeData>(
                                distance, arcs.Vertex2);
                        }

                        var arcValueValueCoordinates = arcs.Intermediates;
                        if (arcValueValueCoordinates != null)
                        { // search over intermediate points.
                            var arcValueValueCoordinatesArray = arcValueValueCoordinates.ToArray();
                            for (int idx = 0; idx < arcValueValueCoordinatesArray.Length; idx++)
                            {
                                vertexCoordinate = new GeoCoordinate(
                                    arcValueValueCoordinatesArray[idx].Latitude,
                                    arcValueValueCoordinatesArray[idx].Longitude);
                                distance = coordinate.DistanceReal(vertexCoordinate).Value;
                                if (distance < closestWithoutMatch.Distance)
                                { // the distance found is closer.
                                    closestWithoutMatch = new SearchClosestResult <TEdgeData>(
                                        distance, arcs.Vertex1, arcs.Vertex2, idx, arcs.EdgeData, arcValueValueCoordinatesArray);
                                }
                            }
                        }
                    }
                }
            }

            // return the best result.
            if (closestWithMatch.Distance < double.MaxValue)
            {
                return(closestWithMatch);
            }
            return(closestWithoutMatch);
        }