using System; using System.Collections.Generic; using System.Text; using OpenTraffic.Model.Graph; namespace OpenTraffic.Model.Route { public class RouteFactory { private TrafficZone lastStart; private float lastTime; private TrafficModel model; private Graph.ShortestPath sp; Dictionary nodes; private Result.ResultData result; private List turns; private LinkNode v0; private float randFactor; private Random rand; private class LinkNode : Vertex { public LinkNode(int id) : base(id, null, 0, 0) { } } private class StopZone : LinkNode { public StopZone(int id) : base(id) { } } private class StartNode : LinkNode { public StartNode() : base(0) { } } private class TurnEdge : GraphEdge { public Turning t; public TurnEdge(Turning t, LinkNode l1, LinkNode l2) : base(t.Id, l1, l2, null) { this.t = t; } } public RouteFactory(TrafficModel m, Result.ResultData res) { init(m, res, float.NaN); } public RouteFactory(TrafficModel m, Result.ResultData res, float randFactor) { init(m, res, randFactor); } private void init(TrafficModel m, Result.ResultData res, float randFactor1) { this.randFactor = randFactor1; this.model = m; this.result = res; sp = new Graph.ShortestPath(); lastStart = null; lastTime = float.NaN; turns = new List(); rand = new Random(23); nodes = new Dictionary(); int id = 1; foreach (TrafficModelLink l in model.TrafficModelLinks) { LinkNode v = new LinkNode(++id); nodes.Add(l.Id, v); } foreach (TrafficZone z in model.TrafficZones) { StopZone v = new StopZone(++id); nodes.Add(-z.Id, v); } foreach (TrafficModelLink l in m.TrafficModelLinks) { foreach (Turning t in l.Turnings) { LinkNode te = (t.Destination is TrafficModelConnector) ? nodes[-t.Destination.Target.Id] : nodes[t.Destination.Id]; turns.Add(new TurnEdge(t, nodes[t.Origin.Id], te)); } } } public RouteContainer GetRoute(TrafficZone v1, TrafficZone v2) { return GetRoute(v1, v2, 0, true, null); } public RouteContainer GetRoute(TrafficZone startZone, TrafficZone stopZone, float startTime, bool cache) { return GetRoute(startZone, stopZone, startTime, cache, null); } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1011:ConsiderPassingBaseTypesAsParameters")] public RouteContainer GetRoute(TrafficZone startZone, TrafficZone stopZone, float startTime, bool cache, VehicleClass c) { if (startZone == stopZone || startZone == null || stopZone == null) { return null; } if (lastStart != startZone || lastTime != startTime) { TrafficProfile.GetProfile().Start("Creating graph"); Graph.Graph graph = new Graph(); foreach (KeyValuePair kv in nodes) { graph.Add(kv.Value); } foreach (TurnEdge t in turns) { graph.Add(t); } v0 = new StartNode(); graph.Add(v0); foreach (TrafficModelLink l in startZone.LinksOut) // This should be connectors { foreach (Turning t in l.Turnings) { LinkNode te = (t.Destination is TrafficModelConnector) ? nodes[-t.Destination.Target.Id] : nodes[t.Destination.Id]; graph.Add(new TurnEdge(t, v0, te)); } } TrafficProfile.GetProfile().SStart("Djikstra"); sp.Proceed(graph, v0, null, delegate(TurnEdge te, float cIn, ref float t) { TrafficModelLink l = te.t.Origin; TrafficModelLink d = te.t.Destination; float speedfactor = c == null ? 1.0f : c.SpeedFactor; float travelTime = GetLinkTT(t, l, speedfactor, 0.0f); if (d is TrafficModelConnector) { travelTime += GetLinkTT(t, d, speedfactor, te.t.Rate); } t += travelTime; float cost = (c == null) ? cost = travelTime : c.CalculateCost(travelTime, l.Length); if (!float.IsNaN(randFactor)) { cost = cost * (1.0f + (float)rand.NextDouble() * randFactor - randFactor / 2.0f); } return cost; //return (float)Math.Max(cost, 0.1); }, startTime); lastStart = startZone; lastTime = startTime; TrafficProfile.GetProfile().Stop(); } if (!cache) { lastStart = null; lastTime = -1; } TrafficProfile.GetProfile().Start("extract"); List lr = sp.ExtractRoute(v0, nodes[-stopZone.Id]); TrafficModelLink[] links = new TrafficModelLink[lr.Count - 1]; TrafficModelLink start = lr[0].t.Origin; TrafficModelLink stop = lr[lr.Count - 1].t.Destination; for (int i = 0; i < links.Length; i++) links[i] = lr[i].t.Destination; RouteContainer r = new RouteContainer(-1, start, stop, links); // System.Diagnostics.Debug.Assert(r.IsValid()); TrafficProfile.GetProfile().Stop(); return r; } private float GetLinkTT(float t, TrafficModelLink l, float speedfactor, float extraTT) { float travelTime = 0.0f; if (result != null) { Result.ResultLink rl = result.GetLinkResultFromTime(t, l.Id); if (rl != null) { travelTime = rl.TravelTime / speedfactor + rl.QueuingTime; } } if (travelTime == 0.0f) { travelTime = l.CalculateFreeFlowTravelTime() / speedfactor; travelTime += extraTT; } return travelTime; } } }