/* * 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 { using System; using System.Collections.Generic; using System.Xml.Serialization; using OpenTraffic.Model.Graph; using OpenTraffic.Model.Simulator; using OpenTraffic.Model.SpeedFunctions; [Serializable] public class TrafficModelLink : GraphEdge { /* =========== XML Elements =========== */ #region XmlExport [XmlAttribute(AttributeName = "Speed")] public float Speed { get; set; } [XmlAttribute(AttributeName = "Lanes")] public float Lanes { get; set; } [XmlAttribute(AttributeName = "Length")] public float Length { get; set; } [XmlAttribute(AttributeName = "Capacity")] public float Capacity { get; set; } [XmlAttribute(AttributeName = "SaturationFlow")] public float SaturationFlow { get; set; } [XmlAttribute(AttributeName = "Id")] public int XmlExportRegisterId { get { return this.Id; } set { Importer.Lookup.Get().Add(value, this); //UGLY List l = Importer.Lookup.Get().GetList("PriorityOpposingLink", value); // Fill in registred opposing link in Priority if (l != null) { foreach (TrafficPriority p in l) { p.OpposingLink = this; } } // UGLY l = Importer.Lookup.Get().GetList("TurningDestinationLinks", value); // Fill in registred turns in if (l != null) { foreach (Turning t in l) { t.Destination = this; } } this.Id = value; } } [XmlAttribute(AttributeName = "Target")] public int XmlExportTargetId { get { return Target != null ? Target.Id : 0; } set { Target = (IntersectionNode)Importer.Lookup.Get().GetObject(value); } } [XmlAttribute(AttributeName = "Source")] public int XmlExportSourceId { get { return Source != null ? Source.Id : 0; } set { Source = (IntersectionNode)Importer.Lookup.Get().GetObject(value); } } [XmlAttribute(AttributeName = "Restrict")] public int XmlExportRestrict { get { return Restrict.Field; } set { Restrict = new ClassField(value); } } // Todo ugly because of the simulation does not always exists. Probably should be in simulation. [XmlAttribute(AttributeName = "SaturationExitFlow")] public virtual float SaturationExitFlow { get { if (Priorities.Count != 0) { float flow = Priorities[0].Intercept; foreach (TrafficPriority p in Priorities) { flow -= p.OpposingLink.Simulator.GetEstimatedFlow() * p.Slope; } return Math.Max(0.0f, flow); } return float.PositiveInfinity; } } [XmlElement(ElementName = "SpeedFlow")] public string XmlExportSpeedFlow { get { if (SpeedFlow == null) return null; return SpeedFlow.SpeedFlowName; } set { SpeedFlow = Importer.Lookup.Get().GetObject(value); } } [XmlElement(ElementName = "Category")] public string XmlExportCategory { get { if (linkCategory == null) return null; return linkCategory.Name; } set { linkCategory = Importer.Lookup.Get().GetObject(value); } } [XmlArray(ElementName = "Turnings")] [XmlArrayItem(ElementName = "t")] public List Turnings { get; set; } [XmlArray(ElementName = "Priorities")] [XmlArrayItem(ElementName = "p")] public List XmlExportPriorities { get { return this.Priorities; } set { this.Priorities = value; foreach (TrafficPriority p in Priorities) { p.Origin = this; } } } #endregion /* =========== Ignored XML Elements =========== */ #region XmlIgnore [XmlIgnore] public List Priorities { get; private set; } [XmlIgnore] public ClassField Restrict { get; private set; } [XmlIgnore] public SpeedFlow SpeedFlow { get; set; } [XmlIgnore] public LinkCategory linkCategory { get; set; } [XmlIgnore] public List Flares { get; private set; } [XmlIgnore] public float MaxDensity { get { return SaturationFlowActive / MinSpeed; } } [XmlIgnore] public float MinSpeed { get { return SpeedFlowActive == null ? SpeedActive : SpeedFlowActive.MinSpeed; } } [XmlIgnore] public ILinkSimulator Simulator { get { return this.simulator1; } set { this.simulator1 = value; } } [XmlIgnore] [NonSerialized] private ILinkSimulator simulator1; [XmlIgnore] public float SaturationFlowActive { get { return SaturationFlow != 0 ? SaturationFlow : linkCategory != null ? linkCategory.SaturationFlow : 0.0f; } } [XmlIgnore] public float CapacityActive { get { return Capacity != 0 ? Capacity : linkCategory != null ? linkCategory.Storage : 0.0f; } } [XmlIgnore] public float SpeedActive { get { return Speed != 0 ? Speed : linkCategory != null ? linkCategory.Speed : 0.0f; } } [XmlIgnore] public float LanesActive { get { return Lanes != 0 ? Lanes : linkCategory != null ? linkCategory.Lanes : 1; } } [XmlIgnore] public SpeedFlow SpeedFlowActive { get { return SpeedFlow != null ? SpeedFlow : linkCategory != null ? linkCategory.SpeedFlow : null; } } [XmlIgnore] public TrafficModelLink Reference { get { return this; } } #endregion public TrafficModelLink() : base(0, null, null, null) { Restrict = new ClassField(false); Priorities = new List(); Turnings = new List(); Flares = new List(); } public TrafficModelLink( int id, IntersectionNode source, IntersectionNode target, string name, string description, float speed, float satFlow, float length, float lanes, float capacity, ClassField cf, LinkCategory cat, SpeedFlow sf) : base(id, source, target, name, description) { this.Speed = speed; this.Capacity = capacity; this.Lanes = lanes; this.Length = length; Restrict = cf == null ? new ClassField(false) : cf; this.SpeedFlow = sf; this.linkCategory = cat; this.SaturationFlow = satFlow; Priorities = new List(); Turnings = new List(); Flares = new List(); } public override string ToString() { return "Link: " + Id; } public bool Allowed(VehicleClass c) { if (Restrict != null) { return !Restrict.IsSet(c); } return true; } public float CalculateFreeFlowTravelTime(VehicleClass c) { if (c == null) return CalculateFreeFlowTravelTime(); return CalculateTravelTime(c, 0); } public float CalculateTravelTime(VehicleClass c, float density) { if (c != null) { return CalculateTravelTime(density) / c.SpeedFactor; } return float.MaxValue; } public float CalculateFreeFlowTravelTime() { return CalculateTravelTime(0); } private float CalculateTravelTime(float density) { SpeedFlow sf = this.SpeedFlowActive; float speed = sf == null ? SpeedActive : sf.GetSpeedByDensity(density); return Length / speed; } public float GetObservedTotalTravelTime(float time, VehicleClass c, Result.ResultData res) { float t = 0f; float speedFactor = c == null ? 1.0f : c.SpeedFactor; if (res != null) { t = res.GetTravelTime(time, this) / speedFactor + res.GetQueuingTime(time, this); } if (t == 0) return CalculateFreeFlowTravelTime(c) / speedFactor; return t; } public override void GenerateShape(int nvert) { float d = 10; foreach (TrafficModelLink l in Source.LinksOut) { if (l == this) break; if (l.Source == Source && l.Target == Target) d += 10; } base.GenerateShape(nvert, d); } } }