Example #1
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);
        }
Example #2
0
        /// <summary>
        /// Test resolving all nodes.
        /// </summary>
        protected void DoTestResolveBetweenNodes()
        {
            var interpreter = new OsmRoutingInterpreter();
            IBasicRouterDataSource <EdgeData> data        = this.BuildData(interpreter);
            IBasicRouter <EdgeData>           basicRouter = this.BuildBasicRouter(data);

            const float         delta  = 0.001f;
            SearchClosestResult result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0578761, 3.7193972), delta, null, null);

            Assert.IsTrue((result.Vertex1 == 20 && result.Vertex2 == 21) ||
                          (result.Vertex1 == 21 && result.Vertex2 == 20));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0576510, 3.7194124), delta, null, null); //,-104, -14, -12
            Assert.IsTrue((result.Vertex1 == 22 && result.Vertex2 == 23) ||
                          (result.Vertex1 == 23 && result.Vertex2 == 22));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0576829, 3.7196791), delta, null, null); //,-105, -12, -10
            Assert.IsTrue((result.Vertex1 == 22 && result.Vertex2 == 16) ||
                          (result.Vertex1 == 16 && result.Vertex2 == 22));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0577819, 3.7196308), delta, null, null); //,-106, -10,  -8
            Assert.IsTrue((result.Vertex1 == 21 && result.Vertex2 == 16) ||
                          (result.Vertex1 == 16 && result.Vertex2 == 21));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0577516, 3.7198975), delta, null, null); //,-107, -10, -18
            Assert.IsTrue((result.Vertex1 == 17 && result.Vertex2 == 16) ||
                          (result.Vertex1 == 16 && result.Vertex2 == 17));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0578218, 3.7200626), delta, null, null); //,-108, -18, -20
            Assert.IsTrue((result.Vertex1 == 17 && result.Vertex2 == 7) ||
                          (result.Vertex1 == 7 && result.Vertex2 == 17));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0578170, 3.7202480), delta, null, null); //,-109, -20, -76
            Assert.IsTrue((result.Vertex1 == 6 && result.Vertex2 == 7) ||
                          (result.Vertex1 == 7 && result.Vertex2 == 6));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0577580, 3.7204004), delta, null, null); //,-110, -76, -74
            Assert.IsTrue((result.Vertex1 == 5 && result.Vertex2 == 6) ||
                          (result.Vertex1 == 6 && result.Vertex2 == 5));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0579032, 3.7204258), delta, null, null); //,-111, -74, -72
            Assert.IsTrue((result.Vertex1 == 1 && result.Vertex2 == 5) ||
                          (result.Vertex1 == 5 && result.Vertex2 == 1));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0580453, 3.7204614), delta, null, null); //,-112, -72, -70
            Assert.IsTrue((result.Vertex1 == 4 && result.Vertex2 == 1) ||
                          (result.Vertex1 == 1 && result.Vertex2 == 4));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0581938, 3.7203953), delta, null, null); //,-113, -70, -68
            Assert.IsTrue((result.Vertex1 == 3 && result.Vertex2 == 4) ||
                          (result.Vertex1 == 4 && result.Vertex2 == 3));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0581826, 3.7201413), delta, null, null); //,-114, -46, -68
            Assert.IsTrue((result.Vertex1 == 3 && result.Vertex2 == 2) ||
                          (result.Vertex1 == 2 && result.Vertex2 == 3));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0580310, 3.7201998), delta, null, null); //,-115, -46, -72
            Assert.IsTrue((result.Vertex1 == 2 && result.Vertex2 == 1) ||
                          (result.Vertex1 == 1 && result.Vertex2 == 2));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0579208, 3.7200525), delta, null, null); //,-116, -20, -22
            Assert.IsTrue((result.Vertex1 == 11 && result.Vertex2 == 7) ||
                          (result.Vertex1 == 7 && result.Vertex2 == 11));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0580134, 3.7199966), delta, null, null); //,-117, -46, -22
            Assert.IsTrue((result.Vertex1 == 2 && result.Vertex2 == 11) ||
                          (result.Vertex1 == 11 && result.Vertex2 == 2));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0581251, 3.7198950), delta, null, null); //,-118, -46, -48
            Assert.IsTrue((result.Vertex1 == 18 && result.Vertex2 == 2) ||
                          (result.Vertex1 == 2 && result.Vertex2 == 18));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0579479, 3.7197985), delta, null, null); //,-119, -22, -56
            Assert.IsTrue((result.Vertex1 == 10 && result.Vertex2 == 11) ||
                          (result.Vertex1 == 11 && result.Vertex2 == 10));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0580166, 3.7195496), delta, null, null); //,-120, -56, -65
            Assert.IsTrue((result.Vertex1 == 10 && result.Vertex2 == 9) ||
                          (result.Vertex1 == 9 && result.Vertex2 == 10));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0581299, 3.7195673), delta, null, null); //,-121, -65, -50
            Assert.IsTrue((result.Vertex1 == 8 && result.Vertex2 == 9) ||
                          (result.Vertex1 == 9 && result.Vertex2 == 8));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0581651, 3.7196664), delta, null, null); //,-122, -50, -48
            Assert.IsTrue((result.Vertex1 == 8 && result.Vertex2 == 18) ||
                          (result.Vertex1 == 18 && result.Vertex2 == 8));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0582050, 3.7194505), delta, null, null); //,-123, -50, -52
            Assert.IsTrue((result.Vertex1 == 19 && result.Vertex2 == 8) ||
                          (result.Vertex1 == 8 && result.Vertex2 == 19));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0582082, 3.7191330), delta, null, null); //,-124, -52, -54
            Assert.IsTrue((result.Vertex1 == 15 && result.Vertex2 == 19) ||
                          (result.Vertex1 == 19 && result.Vertex2 == 15));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0581651, 3.7189628), delta, null, null); //,-125, -54, -62
            Assert.IsTrue((result.Vertex1 == 15 && result.Vertex2 == 14) ||
                          (result.Vertex1 == 14 && result.Vertex2 == 15));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0580725, 3.7189781), delta, null, null); //,-126, -62, -60
            Assert.IsTrue((result.Vertex1 == 14 && result.Vertex2 == 13) ||
                          (result.Vertex1 == 13 && result.Vertex2 == 14));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0580006, 3.7191305), delta, null, null); //,-127, -60, -58
            Assert.IsTrue((result.Vertex1 == 13 && result.Vertex2 == 12) ||
                          (result.Vertex1 == 12 && result.Vertex2 == 13));
            result = basicRouter.SearchClosest(data, interpreter, Vehicle.Car, new GeoCoordinate(51.0579783, 3.7194149), delta, null, null); //,-128, -58, -56
            Assert.IsTrue((result.Vertex1 == 10 && result.Vertex2 == 12) ||
                          (result.Vertex1 == 12 && result.Vertex2 == 10));
        }
Example #3
0
        /// <summary>
        /// Tests the edge matcher in combination with dykstra routing.
        /// </summary>
        /// <param name="name"></param>
        /// <param name="highway"></param>
        /// <param name="vehicle"></param>
        /// <param name="matcher"></param>
        /// <param name="pointName"></param>
        /// <param name="notFound"></param>
        private void TestResolveOnEdgeSingle(string name, string highway,
                                             Vehicle vehicle, IEdgeMatcher matcher,
                                             string pointName, bool notFound)
        {
            var fromName = new GeoCoordinate(51.0003, 4.0007);
            var toName   = new GeoCoordinate(51.0003, 4.0008);

            var fromNoname = new GeoCoordinate(51.0, 4.0007);
            var toNoname   = new GeoCoordinate(51.0, 4.0008);

            TagsCollectionBase pointTags = new TagsCollection();

            pointTags["name"] = pointName;

            TagsCollectionBase tags = new TagsCollection();

            tags["highway"] = highway;
            //tags["name"] = name;

            var tagsIndex = new TagsTableCollectionIndex();

            // do the data processing.
            var  data          = new DynamicGraphRouterDataSource <LiveEdge>(tagsIndex);
            uint vertexNoname1 = data.AddVertex((float)fromNoname.Latitude, (float)fromNoname.Longitude);
            uint vertexNoname2 = data.AddVertex((float)toNoname.Latitude, (float)toNoname.Longitude);

            data.AddArc(vertexNoname1, vertexNoname2, new LiveEdge()
            {
                Forward = true,
                Tags    = tagsIndex.Add(tags)
            }, null);
            tags            = new TagsCollection();
            tags["highway"] = highway;
            tags["name"]    = name;
            uint vertexName1 = data.AddVertex((float)fromName.Latitude, (float)fromName.Longitude);
            uint vertexName2 = data.AddVertex((float)toName.Latitude, (float)toName.Longitude);

            data.AddArc(vertexName1, vertexName2, new LiveEdge()
            {
                Forward = true,
                Tags    = tagsIndex.Add(tags)
            }, null);

            IRoutingInterpreter interpreter = new OsmRoutingInterpreter();

            // creates the data.
            IBasicRouter <LiveEdge> router = new DykstraRoutingLive();

            var nonameLocation = new GeoCoordinate(
                (fromNoname.Latitude + toNoname.Latitude) / 2.0,
                (fromNoname.Longitude + toNoname.Longitude) / 2.0);
//            var nameLocation = new GeoCoordinate(
//                (fromName.Latitude + toName.Latitude) / 2.0,
//                (fromName.Longitude + toName.Longitude) / 2.0);

            const float         delta  = 0.01f;
            SearchClosestResult result = router.SearchClosest(data, interpreter, vehicle, nonameLocation, delta, matcher, pointTags);

            if (result.Distance < double.MaxValue)
            { // there is a result.
                Assert.IsFalse(notFound, "A result was found but was supposed not to  be found!");

                if (name == pointName)
                { // the name location was supposed to be found!
                    Assert.IsTrue(result.Vertex1 == vertexName1 || result.Vertex1 == vertexName2);
                    Assert.IsTrue(result.Vertex2 == vertexName1 || result.Vertex2 == vertexName2);
                }
                else
                { // the noname location was supposed to be found!
                    Assert.IsTrue(result.Vertex1 == vertexNoname1 || result.Vertex1 == vertexNoname2);
                    Assert.IsTrue(result.Vertex2 == vertexNoname1 || result.Vertex2 == vertexNoname2);
                }
                return;
            }
            Assert.IsTrue(notFound, "A result was not found but was supposed to be found!");
        }
Example #4
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.
                foreach (KeyValuePair <uint, KeyValuePair <uint, TEdgeData> > arc in arcs)
                {
                    if (!graph.TagsIndex.Contains(arc.Value.Value.Tags))
                    { // skip this edge, no valid tags found.
                        continue;
                    }
                    var  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.DistanceReal(fromCoordinates).Value;
                            GeoCoordinateSimple[] coordinates;
                            if (!graph.GetEdgeShape(arc.Key, arc.Value.Key, out coordinates))
                            {
                                coordinates = null;
                            }

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

                            if (distance < closestWithoutMatch.Distance)
                            { // the distance is smaller for the without match.
                                closestWithoutMatch = new SearchClosestResult <TEdgeData>(
                                    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 <TEdgeData>(
                                        distance, arc.Key);
                                }
                            }
                            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, 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 <TEdgeData>(
                                        distance, arc.Value.Key);
                                }
                            }

                            // search along the line.
                            double distanceTotal = 0;
                            var    previous      = fromCoordinates;
                            GeoCoordinateSimple[] arcValueValueCoordinates;
                            if (graph.GetEdgeShape(arc.Key, arc.Value.Key, out arcValueValueCoordinates) &&
                                arcValueValueCoordinates != null)
                            { // calculate distance along all coordinates.
                                for (int idx = 0; idx < arcValueValueCoordinates.Length; idx++)
                                {
                                    var current = new GeoCoordinate(arcValueValueCoordinates[idx].Latitude, arcValueValueCoordinates[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;
                                double            distanceToSegment = 0;
                                if (arcValueValueCoordinates != null)
                                {
                                    for (int idx = 0; idx < arcValueValueCoordinates.Length; idx++)
                                    {
                                        var current = new GeoCoordinate(
                                            arcValueValueCoordinates[idx].Latitude, arcValueValueCoordinates[idx].Longitude);
                                        line = new GeoCoordinateLine(previous, current, true, true);

                                        distance = line.DistanceReal(coordinate).Value;

                                        if (distance < closestWithoutMatch.Distance)
                                        { // the distance is smaller.
                                            PointF2D 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, arc.Key, arc.Value.Key, position, arc.Value.Value, coordinates);
                                            }
                                        }
                                        if (distance < closestWithMatch.Distance)
                                        {
                                            PointF2D 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, arc.Key, arc.Value.Key, position, arc.Value.Value, coordinates);
                                                }
                                            }
                                        }

                                        // 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.
                                    PointF2D 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, arc.Key, arc.Value.Key, position, arc.Value.Value, coordinates);
                                    }
                                }
                                if (distance < closestWithMatch.Distance)
                                {
                                    PointF2D 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, arc.Key, arc.Value.Key, position, arc.Value.Value, coordinates);
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
            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.DistanceReal(vertexCoordinate).Value;
                        if (distance < closestWithoutMatch.Distance)
                        { // the distance found is closer.
                            closestWithoutMatch = new SearchClosestResult <TEdgeData>(
                                distance, arc.Key);
                        }

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

                        GeoCoordinateSimple[] arcValueValueCoordinates;
                        if (graph.GetEdgeShape(arc.Key, arc.Value.Key, out arcValueValueCoordinates))
                        { // search over intermediate points.
                            for (int idx = 0; idx < arcValueValueCoordinates.Length; idx++)
                            {
                                vertexCoordinate = new GeoCoordinate(
                                    arcValueValueCoordinates[idx].Latitude,
                                    arcValueValueCoordinates[idx].Longitude);
                                distance = coordinate.DistanceReal(vertexCoordinate).Value;
                                if (distance < closestWithoutMatch.Distance)
                                { // the distance found is closer.
                                    closestWithoutMatch = new SearchClosestResult <TEdgeData>(
                                        distance, arc.Key, arc.Value.Key, idx, arc.Value.Value, arcValueValueCoordinates);
                                }
                            }
                        }
                    }
                }
            }

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