| | | 1 | | using System; |
| | | 2 | | using Itinero.Network; |
| | | 3 | | using Itinero.Routes.Paths; |
| | | 4 | | using Itinero.Routing.Costs; |
| | | 5 | | using Itinero.Routing.Flavours.Dijkstra.Bidirectional; |
| | | 6 | | using Itinero.Snapping; |
| | | 7 | | |
| | | 8 | | namespace Itinero.Routing.Flavours.Dijkstra; |
| | | 9 | | |
| | | 10 | | /// <summary> |
| | | 11 | | /// Extensions related to snap points. |
| | | 12 | | /// </summary> |
| | | 13 | | public static class SnapPointExtensions |
| | | 14 | | { |
| | | 15 | | /// <summary> |
| | | 16 | | /// Returns a factor in the range [0, 1] representing the position on the edge. |
| | | 17 | | /// </summary> |
| | | 18 | | /// <param name="snapPoint">The snap point.</param> |
| | | 19 | | /// <returns>The factor.</returns> |
| | | 20 | | public static double OffsetFactor(this SnapPoint snapPoint) |
| | 147 | 21 | | { |
| | 147 | 22 | | return snapPoint.Offset / (double)ushort.MaxValue; |
| | 147 | 23 | | } |
| | | 24 | | |
| | | 25 | | /// <summary> |
| | | 26 | | /// Calculates a single edge path using the given cost function if the two snap points are on the same edge. |
| | | 27 | | /// </summary> |
| | | 28 | | /// <param name="routingNetwork"></param> |
| | | 29 | | /// <param name="origin"></param> |
| | | 30 | | /// <param name="destination"></param> |
| | | 31 | | /// <param name="costFunction"></param> |
| | | 32 | | /// <param name="path"></param> |
| | | 33 | | /// <param name="cost"></param> |
| | | 34 | | /// <returns></returns> |
| | | 35 | | /// <exception cref="Exception"></exception> |
| | | 36 | | public static bool TrySingleHop(this RoutingNetwork routingNetwork, |
| | | 37 | | SnapPoint origin, SnapPoint destination, ICostFunction costFunction, |
| | | 38 | | out Path path, out double cost) |
| | 15 | 39 | | { |
| | 15 | 40 | | path = null; |
| | 15 | 41 | | cost = double.MaxValue; |
| | 18 | 42 | | if (origin.EdgeId != destination.EdgeId) return false; |
| | | 43 | | |
| | 12 | 44 | | var enumerator = new CostEdgeEnumerator(routingNetwork.GetEdgeEnumerator(), costFunction); |
| | 12 | 45 | | if (!enumerator.MoveTo(origin.EdgeId, true)) throw new Exception(); |
| | 12 | 46 | | var tailToHeadCost = enumerator.GetCost(true); |
| | 12 | 47 | | var headToTailCost = enumerator.GetCost(false); |
| | 12 | 48 | | if (headToTailCost.cost <= 0 && tailToHeadCost.cost <= 0) return false; |
| | | 49 | | |
| | 12 | 50 | | if (origin.Offset == destination.Offset) |
| | 1 | 51 | | { |
| | 1 | 52 | | var tailToHead = tailToHeadCost.cost > 0; |
| | 1 | 53 | | path = new Path(routingNetwork); |
| | 1 | 54 | | path.Append(origin.EdgeId, tailToHead); |
| | 1 | 55 | | path.Offset1 = origin.Offset; |
| | 1 | 56 | | path.Offset2 = destination.Offset; |
| | 1 | 57 | | cost = 0; |
| | 1 | 58 | | } |
| | 11 | 59 | | else if (origin.Offset < destination.Offset) |
| | 6 | 60 | | { |
| | 6 | 61 | | var tailToHead = tailToHeadCost.cost > 0; |
| | 7 | 62 | | if (!tailToHead) return false; |
| | | 63 | | |
| | 5 | 64 | | path = new Path(routingNetwork); |
| | 5 | 65 | | path.Append(origin.EdgeId, true); |
| | 5 | 66 | | path.Offset1 = origin.Offset; |
| | 5 | 67 | | path.Offset2 = destination.Offset; |
| | | 68 | | |
| | 5 | 69 | | cost = (destination.OffsetFactor() - origin.OffsetFactor()) * tailToHeadCost.cost; |
| | 5 | 70 | | } |
| | | 71 | | else |
| | 5 | 72 | | { |
| | 5 | 73 | | var headToTail = headToTailCost.cost > 0; |
| | 6 | 74 | | if (!headToTail) return false; |
| | | 75 | | |
| | 4 | 76 | | path = new Path(routingNetwork); |
| | 4 | 77 | | path.Append(origin.EdgeId, false); |
| | 4 | 78 | | path.Offset1 = (ushort)(ushort.MaxValue - origin.Offset); |
| | 4 | 79 | | path.Offset2 = (ushort)(ushort.MaxValue - destination.Offset); |
| | | 80 | | |
| | 4 | 81 | | cost = (origin.OffsetFactor() - destination.OffsetFactor()) * headToTailCost.cost; |
| | 4 | 82 | | } |
| | | 83 | | |
| | 10 | 84 | | return true; |
| | 15 | 85 | | } |
| | | 86 | | } |