/* * 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.Simulator.Queue { using System; using System.Collections.Generic; public class FifoLink : ILinkSimulator { private OpenTraffic.Model.TrafficModelLink link; private List> flowPart; private float lastVehicleLeft; private float maxCarsToLeave; public float GetRatioOccupied() { return 0.0f; } public int GetNumberOfVehiclesInQueue() { return 0; } public float Density { get { return flowPart.Count / link.Length / link.LanesActive; } } private float estimatedFlow; private int carPassedFlowEstimated; private const float timeStep = 60.0f * 5.0f; // 60 seconds private float nextSwitch; private float occupancy; private Dictionary turningLookup; public OpenTraffic.Model.TrafficModelLink NetworkLink { get { return link; } } public FifoLink(OpenTraffic.Model.TrafficModelLink link) { this.link = link; flowPart = new List>(16); Clear(); turningLookup = new Dictionary(); foreach (Turning t in this.link.Turnings) { turningLookup.Add(t.Destination, t); } } public void Clear() { estimatedFlow = 0; maxCarsToLeave = 0; lastVehicleLeft = 0; occupancy = 0.0f; carPassedFlowEstimated = 0; flowPart.Clear(); } public void AddCarToTransfer(List cars) { } public float GetEstimatedFlow() { return estimatedFlow; } public int GetNumberOfVehicles() { return flowPart.Count; } public LinkInfo GetLinkInfo() { return new LinkInfo(link.Id, link.CapacityActive - GetNumberOfVehicles(),estimatedFlow); } public void Add(Vehicle v, float time, float extraTurnDelay, Result.ResultData res) { if (v != null && res != null) { occupancy += v.routeClass.Pcu; res.RegisterArrival(v, time); flowPart.Add(new KeyValuePair(time + this.CalculateTravelTime(v) + extraTurnDelay, v)); } } public bool IsFull() { return occupancy >= link.CapacityActive; } public bool PreSimulate(float startTime, float stopTime, Result.ResultData result, TrafficModel model) { return HasWaitingVehicles(stopTime); } public bool Simulate(float startTime, float stopTime, Result.ResultData result, TrafficModel model) { if (startTime > nextSwitch) { estimatedFlow = this.carPassedFlowEstimated / timeStep; nextSwitch = startTime + timeStep; carPassedFlowEstimated = 0; } return MoveVehicleToNextLink(startTime, stopTime, result); } private bool HasWaitingVehicles(float stopTime) { if (flowPart.Count == 0 || flowPart[0].Key >= stopTime) return false; OpenTraffic.Model.TrafficModelLink l = flowPart[0].Value.GetNextLink(); if (l == null) return true; Turning t = turningLookup[flowPart[0].Value.GetNextLink()]; return (!t.Block && !t.Destination.Simulator.IsFull()); } private bool MoveVehicleToNextLink(float startTime, float stopTime, Result.ResultData res) { KeyValuePair kv = flowPart[0]; flowPart.RemoveAt(0); Vehicle v = kv.Value; OpenTraffic.Model.TrafficModelLink nLink = v.GetNextLink(); float time = Math.Max(lastVehicleLeft, Math.Max(startTime, kv.Key)); if (nLink == null) { res.RegisterRouteEnd(v, time); } else { Turning t = turningLookup[nLink]; //time += t.Rate; res.RegisterDeparture(v, time); v.MoveToNextLink(); nLink.Simulator.Add(v, time,t.Rate, res); } maxCarsToLeave--; occupancy -= v.routeClass.Pcu; carPassedFlowEstimated++; lastVehicleLeft = time; return HasWaitingVehicles(stopTime); } private float CalculateTravelTime(Vehicle v) { return link.CalculateTravelTime(v.routeClass, Density); } } }