/// <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); }
/// <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)); }
/// <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!"); }
/// <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); }