/* * Copyright (c) 2005-2006 Erik Tigerholm * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */ namespace OpenTraffic.Model.Importer { using System; using System.Collections.Generic; using System.IO; using OpenTraffic.Model.SpeedFunctions; using OpenTraffic.Model.StopCriteria; public class ContramNetwork : Contram, IImporterModel { private int nLinks; private int persistence = 3; private Dictionary nodeLookup; private FileInfo file; private float lastTime; private string revision; private float headway; private TrafficGenerator.ODTrafficGenerator traffic; private Result.TimeSliceFactory resFactory; private List Times; private Dictionary[]> timings; private Dictionary> turns; private Dictionary uturns; public ContramNetwork() { commands.Add("NODE", this.LoadNodes); commands.Add("ZONE", this.LoadNodes); commands.Add("LINK", this.LoadLinks); commands.Add("CONNECTOR", this.LoadLinks); commands.Add("SHAPE", this.LoadShapes); commands.Add("CLASS", this.LoadClass); commands.Add("DEMAND", this.LoadDemand); commands.Add("TIME", this.LoadTime); commands.Add("SPEED_FLOW", this.LoadSpeedFlow); commands.Add("CATEGORY", this.LoadCategory); commands.Add("PARAMETERS", this.LoadParameters); commands.Add("PRIORITY", this.LoadPriority); commands.Add("SIGNAL_PLAN", this.LoadSignalplan); commands.Add("SIGNAL_TIMING", this.LoadSignalTiming); commands.Add("BACKGROUND_IMAGE", this.LoadBackgroundImage); commands.Add("TURNS", this.LoadTurns); commands.Add("FLARE", this.LoadFlare); } public override string GetName() { return "Contram Network"; } public override string GetExtensions() { return "Contram Network|*.net;"; } [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Design", "CA1062:Validate arguments of public methods", MessageId = "1")] public void LoadFile(FileInfo file1, OpenTraffic.Model.TrafficModel m) { this.file = file1; nodeLookup = new Dictionary(); turns = new Dictionary>(); timings = new Dictionary[]>(); uturns = new Dictionary(); m.Reset(); lastTime = -1; nLinks = 0; m.TrafficGenerator = traffic = new TrafficGenerator.NonProbOD(); m.ResultFactory = resFactory = new Result.TimeSliceFactory(); Times = new List(); Lookup.Get().Clear(); try { LoadFile(file1, m, false); } catch (Exception exp) { throw new Exception("Error reading network file.", exp); } m.StartTime = Times[0].StartTime; m.StopTime = Times[Times.Count - 1].StopTime; m.TimeSlices = new List(Times); m.PostLoad(); foreach (TrafficModelLink o in m.TrafficModelLinks) { FillInTurns(o); } foreach (TrafficModelLink o in m.TrafficModelConnectors) { FillInTurns(o); } FillInStages(); // m.ResultFactory = new Result.FixedFactory(m.StartTime, m.StopTime, 60); } private void FillInStages() { foreach (KeyValuePair[]> kv in this.timings) { for (int stage = 0; stage < kv.Value.Length; stage++) { foreach (TrafficModelLink l in kv.Value[stage]) { foreach (Turning t in l.Turnings) { kv.Key.Stages[stage].Turns.Add(t); } } } } } private void FillInTurns(TrafficModelLink o) { foreach (TrafficModelLink d in o.Target.LinksOut) { if (turns.ContainsKey(o) && turns[o].ContainsKey(d)) { Turning t = turns[o][d]; if (t.Rate != -1) { o.Turnings.Add(t); } } else { if (o.Source != d.Target || uturns.ContainsKey(o.Target)) { o.Turnings.Add(new Turning(++idTurns, o, d, 0)); } } } } private void LoadBackgroundImage(string line, TrafficModel m, Dictionary d, string commandName) { String[] values = SplitLine(line); float xmin = GetFloat("xmin", d, values); float xmax = GetFloat("xmax", d, values); float ymin = GetFloat("ymin", d, values); if (revision.Equals("b")) { float t = xmax; xmax = ymin; ymin = t; } string filename = GetString("file", d, values); string state = GetString("show", d, values); IMAGE_STATES s = state.Equals("SHOW") ? IMAGE_STATES.HIDE : IMAGE_STATES.SHOW; string afName = File.Exists(filename) ? filename : (File.Exists(file.DirectoryName + filename) ? file.DirectoryName + filename : null); if (afName != null) { m.BackgroundImages.Add(new BackgroundImage(new FileInfo(file.DirectoryName + "\\" + filename), xmin, xmax, -ymin, s)); } } private void LoadParameters(string line, TrafficModel m, Dictionary d, string commandName) { //* code speed sat_flow storage nlane sfd restrict name String[] values = SplitLine(line); AbstractStopCriteria stop = null; float f; switch (GetString("parameter", d, values)) { case "persistence": persistence = GetInt("value", d, values); break; case "RMS": f = GetFloat("value", d, values); if (f != 0) stop = new StopCriteria.RootMeanSquare(f); break; case "AAD": f = GetFloat("value", d, values); if (f != 0) stop = new StopCriteria.AverageAbsoluteDifference(f, persistence); break; case "revision": revision = GetString("value", d, values); break; case "headway": headway = GetFloat("value", d, values); break; } if (stop != null) { m.StopCriterias.Add(stop); } } private void LoadCategory(string line, TrafficModel m, Dictionary d, string commandName) { //* code speed sat_flow storage nlane sfd restrict name String[] cols = SplitLine(line); // IMPLEMENT APPLIES string name = GetString("code", d, cols); float speed = GetFloat("speed", d, cols) / 3.6f; float storage = GetFloat("storage", d, cols); float lanes = GetFloat("nlane", d, cols); string spfName = cols[d["sfd"]]; string description = cols[d["name"]]; float saturationFlow = GetFloat("sat_flow", d, cols) / (3600); SpeedFlow spf = null; if (!string.IsNullOrEmpty(spfName) && !spfName.Equals("0")) { spf = Lookup.Get().GetObject(spfName); } LinkCategory cat = new LinkCategory(name, lanes, speed, storage, saturationFlow, spf, description); Lookup.Get().Add(name, cat); m.LinkCategories.Add(cat); } private void LoadSignalTiming(string line, TrafficModel m, Dictionary d, string commandName) { //* plan U_link D_link S_stage E_stage I_G E_delay min max Q_limit String[] cols = SplitLine(line); string idPlan = GetString("plan", d, cols); TrafficModelLink l = Lookup.Get().GetObject(GetString("U_link", d, cols)); int startStage = GetInt("S_stage", d, cols) - 1; int stopStage = GetInt("E_stage", d, cols) - 1; SignalPlans.SignalPlan p = Lookup.Get().GetObject(idPlan); if (startStage <= stopStage) { for (int i = startStage; i <= stopStage; i++) { timings[p][i].Add(l); } } else { for (int i = 0; i <= stopStage; i++) { timings[p][i].Add(l); } for (int i = startStage; i < p.NumberOfStages; i++) { timings[p][i].Add(l); } } } private void LoadSignalplan(string line, TrafficModel m, Dictionary d, string commandName) { //* plan group control cycle_time offset start finish stage_lengths... name String[] cols = SplitLine(line); // IMPLEMENT APPLIES string id = GetString("plan", d, cols); string algorithm = GetString("control", d, cols); float maxCycleTime = GetInt("cycle_time", d, cols); float offset = GetInt("offset", d, cols); int start = GetInt("start", d, cols) - 1; int stop = GetInt("finish", d, cols) - 1; TimeSlice active = new TimeSlice(); active.StartTime = (start < Times.Count) ? Times[start].StartTime : Times[Times.Count - 1].StopTime; active.StopTime = (stop < Times.Count) ? Times[stop].StopTime : Times[Times.Count - 1].StopTime; List stages = new List(); int i = d["stage_lengths..."]; for (int res = 0; i < cols.Length && int.TryParse(cols[i], out res); i++) { System.Diagnostics.Debug.Assert(res > 0); stages.Add(res); } if (algorithm != "Fixed") { Console.WriteLine("!!! " + algorithm + " signalplan is not supported"); } // System.Diagnostics.Debug.Assert(algorithm == "Fixed"); string name = ""; for (; i < cols.Length; i++) { name += cols[i] + " "; } name = name.Trim(); // RouteNode n = nodeLookup[int.Parse(id.Split('.')[0])]; SignalPlans.SignalPlan sp = new SignalPlans.Fixed(id, name, maxCycleTime, offset, active); timings.Add(sp, new List[stages.Count]); for (int j = 0; j < stages.Count; j++) timings[sp][j] = new List(); foreach (float duration in stages) { sp.Stages.Add(new SignalPlans.SignalStage(duration, new List())); } Lookup.Get().Add(id, sp); m.SignalPlans.Add(sp); } private void LoadSpeedFlow(string line, TrafficModel m, Dictionary d, string commandName) { String[] cols = SplitLine(line); // IMPLEMENT APPLIES string name = cols[d["number"]]; //int lanes = GetInt("lanes", d, cols); string description = cols[d["name"]]; float smin = GetFloat("s_min", d, cols) / 3.6f; float smax = GetFloat("s_max", d, cols) / 3.6f; int c; for (c = 1; c <= 4; c++) { if (GetFloat("s" + c, d, cols) == 0) break; } SpeedFlowPoint[] points1; SpeedFunctions.FlowPoint[] points2; points1 = new SpeedFlowPoint[c]; points2 = new SpeedFunctions.FlowPoint[c]; for (int i = 1; i < c; i++) { float s = GetFloat("s" + i, d, cols) / 3.6f; float q = GetFloat("f" + i, d, cols) / 3600f; float demand = q / s; points1[i - 1] = new SpeedFlowPoint(demand, s); points2[i - 1] = new SpeedFunctions.FlowPoint(q, s); } //Extrapolate to it hits the min speed. float s1 = points1[c - 3].Speed; float s2 = points1[c - 2].Speed; // Should be possible to change this to points2... I'm afraid of the index, do you dare fix it? float f1 = GetFloat("f" + (c - 2), d, cols) / 3600.0f; float f2 = GetFloat("f" + (c - 1), d, cols) / 3600.0f; float k = (s2 - s1) / (f2 - f1); float f = (smin - s1) / k + f1; points1[c - 1] = new SpeedFlowPoint(f / smin, smin); points2[c - 1] = new SpeedFunctions.FlowPoint(f, smin); // SpeedFlow sf = new SpeedFunctions.DensityPartlyLinear(name, description, smax, smin, points1); SpeedFlow sf2 = new SpeedFunctions.FlowPartlyLinear("sf" + name, description, smax, smin, points2); Lookup.Get().Add(name, sf2); m.SpeedFlows.Add(sf2); // m.SpeedFlows.Add(sf2); } private void LoadPriority(string line, OpenTraffic.Model.TrafficModel m, Dictionary d, string commandName) { String[] cols = SplitLine(line); TrafficModelLink origin = Lookup.Get().GetObject(cols[d["U_Link"]]); TrafficModelLink opposing = Lookup.Get().GetObject(cols[d["C_Link"]]); float intercept = GetFloat("intercept", d, cols) / (60 * 60); float slope = GetFloat("slope", d, cols); if (intercept > 0) { origin.Priorities.Add(new TrafficPriority(origin, opposing, intercept, slope)); } } private void LoadLinks(string line, OpenTraffic.Model.TrafficModel m, Dictionary d, string commandName) { String[] values = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); String[] nodes = values[d["link"]].Trim().Split(new char[] { '/' }); nLinks++; string name = ""; //d["name"] < values.Length ? values[d["name"]] : null; for (int i = d["name"]; i < values.Length; i++) name += values[i] + " "; name = name.Trim(); IntersectionNode source = nodeLookup[Int32.Parse(nodes[0])]; IntersectionNode target = nodeLookup[Int32.Parse(nodes[1])]; float speed = GetFloat("speed", d, values) / 3.6f; float length = GetFloat("length", d, values); float capacity = GetFloat("storage", d, values); float lanes = GetFloat("lanes", d, values); ClassField cf = new ClassField(values[d["restrict"]]); string catName = GetString("category", d, values); string sfName = GetString("sfd", d, values); string id = values[d["link"]]; LinkCategory cat = null; SpeedFlow sf = null; if (!string.IsNullOrEmpty(catName) && !catName.Equals("0")) { cat = Lookup.Get().GetObject(catName); } if (!string.IsNullOrEmpty(sfName) && !sfName.Equals("0")) { sf = Lookup.Get().GetObject(sfName); } float satFlow = GetFloat("sat_flow", d, values) / 3600; TrafficModelLink link = null; if (commandName == "CONNECTOR") { TrafficModelConnector con; link = con = new TrafficModelConnector(nLinks, source, target, id, name, speed, satFlow, length, lanes, capacity, cf, cat, sf); m.TrafficModelConnectors.Add(con); } else { link = new TrafficModelLink(nLinks, source, target, id, name, speed, satFlow, length, lanes, capacity, cf, cat, sf); m.TrafficModelLinks.Add(link); } if (link.CapacityActive == 0) { link.Capacity = link.LanesActive * length / headway; } if (link.CapacityActive == 0) { Console.WriteLine(link); } /* float minSpeed = link.SpeedFlowActive == null ? link.SpeedActive : link.SpeedFlowActive.MinSpeed; float tt = link.Length / minSpeed; if (tt < 10.0f) { Console.WriteLine("WARNING: Too small link: " + tt + "s at " + link); } */ Lookup.Get().Add(id, link); } private void LoadNodes(string line, OpenTraffic.Model.TrafficModel m, Dictionary d, string commandName) { String[] values = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); int id = GetInt("number", d, values); float x = GetFloat("x-coord", d, values); // float.Parse(cols[d["x-coord"]]); float y = -GetFloat("y-coord", d, values); int uturn = GetInt("u-turn", d, values); string name = ""; for (int i = d["name"]; i < values.Length; i++) name += values[i] + " "; name = name.Trim(); if (commandName == "ZONE") { TrafficZone node = new TrafficZone(id, name, x, y); nodeLookup.Add(id, node); m.TrafficZones.Add(node); } else { IntersectionNode node = new IntersectionNode(id, name, x, y); nodeLookup.Add(id, node); m.IntersectionNodes.Add(node); if (uturn == 1) uturns.Add(node, true); } } private void LoadShapes( string line, OpenTraffic.Model.TrafficModel m, Dictionary d, string commandName) { // NumberFormatInfo nfi = new CultureInfo("en-US", false).NumberFormat; String[] cols = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); TrafficModelLink link = Lookup.Get().GetObject(cols[d["l_number"]]); for (int i = 0; (i < 4) && (cols.Length > (d["ypoint"] + i * 2)); i++) { link.Shape.Add(new Graph.GraphCoordinate(float.Parse(cols[d["xpoint"] + i * 2]), -float.Parse(cols[d["ypoint"] + i * 2]))); } } private void LoadClass( string line, OpenTraffic.Model.TrafficModel m, Dictionary d, string commandName) { String[] values = line.Split(new char[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); int number = Int32.Parse(values[d["number"]]); float pcu = GetFloat("rel_pcus", d, values); float speedFactor = GetFloat("rel_speed", d, values); float headway1 = GetFloat("headway", d, values); string name = values[d["name"]]; float distance = GetFloat("distance", d, values) / 1000; float time = GetFloat("time", d, values) / (60 * 60); VehicleClass c = new VehicleClass(number, pcu, speedFactor, headway1, name, time, distance); Lookup.Get().Add(number, c); m.VehicleClasses.Add(c); } private void LoadDemand(string line, OpenTraffic.Model.TrafficModel m, Dictionary cols, string commandName) { String[] values = SplitLine(line); // *origin dest class route start packet 600 630 700 715 730 745 800 815 830 845 900 915 930 1000 int originId = GetInt("origin", cols, values); int destId = GetInt(cols.ContainsKey("destin.") ? "destin." : "dest", cols, values); int classId = GetInt("class", cols, values); // int routeId = GetInt("route", cols, values); int start = GetInt("start", cols, values) - 1; float[] demands = new float[start + values.Length - cols["packet"] - 1]; int index = cols["packet"] + 1; for (int i = 0; i < demands.Length; i++) { if (i < start) { demands[i] = 0; } else { demands[i] = GetFloat(index, values) / 3600; index++; } } TrafficZone origin = (TrafficZone)this.nodeLookup[originId]; TrafficZone target = (TrafficZone)this.nodeLookup[destId]; VehicleClass c = Lookup.Get().GetObject(classId); traffic.Demands.Add(new Demand(origin, target, c, demands)); } public void LoadTime(string line, OpenTraffic.Model.TrafficModel m, Dictionary d, string commandName) { String[] cols = SplitLine(line); string timeStr = GetString("start", d, cols); float time = (float.Parse(timeStr.Substring(0, timeStr.Length - 2)) * 60 + float.Parse(timeStr.Substring(timeStr.Length - 2, 2))) * 60; // int id = GetInt("time_slice", d, cols) - 1; if (lastTime != -1) { Times.Add(new TimeSlice(lastTime, time)); resFactory.Times.Add(new TimeSlice(lastTime, time)); traffic.Times.Add(new TimeSlice(lastTime, time)); } lastTime = time; } private int idTurns = 0; public void LoadTurns(string line, OpenTraffic.Model.TrafficModel m, Dictionary d, string commandName) { String[] cols = SplitLine(line); string orgId = GetString("U_Link", d, cols); string destId = GetString("D_Link", d, cols); int restrict = GetInt("restrict", d, cols); TrafficModelLink org = Lookup.Get().GetObject(orgId); TrafficModelLink dest = Lookup.Get().GetObject(destId); float rate = (restrict == 0) ? -GetFloat("penalty", d, cols) : -1; Turning turn = new Turning(++idTurns, org, dest, rate); if (!turns.ContainsKey(org)) turns.Add(org, new Dictionary()); if (!turns[org].ContainsKey(dest)) turns[org].Add(dest, turn); } public void LoadFlare(string line, OpenTraffic.Model.TrafficModel m, Dictionary d, string commandName) { String[] cols = SplitLine(line); string orgId = GetString("U_Link", d, cols); string destId = GetString("D_Link", d, cols); TrafficModelLink org = Lookup.Get().GetObject(orgId); TrafficModelLink dest = Lookup.Get().GetObject(destId); float capacity = GetFloat("storage", d, cols); float satFlow = GetFloat("sat_flow", d, cols) / 3600; org.Flares.Add(new Flare(org, dest, capacity, satFlow)); } } }