/// <summary> /// Calculates the current metrics for flowing and waiting vehicles /// </summary> /// <param name="wait"></param> /// <param name="flow"></param> /// <returns>true if the values could be calculated, false otherwise</returns> public bool calcWaitFlow(out float wait, out float flow) { #if TRACE Singleton <CodeProfiler> .instance.Start("TimedTrafficLightsStep.calcWaitFlow"); #endif #if DEBUGMETRIC bool debug = timedNode.NodeId == 3201; #else bool debug = false; #endif #if DEBUGMETRIC if (debug) { Log.Warning($"TimedTrafficLightsStep.calcWaitFlow: ***START*** @ node {timedNode.NodeId}"); } #endif uint numFlows = 0; uint numWaits = 0; uint curMeanFlow = 0; uint curMeanWait = 0; // we are the master node. calculate traffic data foreach (ushort timedNodeId in timedNode.NodeGroup) { TrafficLightSimulation sim = TrafficLightSimulation.GetNodeSimulation(timedNodeId); if (sim == null || !sim.IsTimedLight()) { continue; } TimedTrafficLights slaveTimedNode = sim.TimedLight; if (slaveTimedNode.NumSteps() <= timedNode.CurrentStep) { for (int i = 0; i < slaveTimedNode.NumSteps(); ++i) { slaveTimedNode.GetStep(i).invalid = true; } continue; } TimedTrafficLightsStep slaveStep = slaveTimedNode.Steps[timedNode.CurrentStep]; //List<int> segmentIdsToDelete = new List<int>(); // minimum time reached. check traffic! foreach (KeyValuePair <ushort, CustomSegmentLights> e in slaveStep.segmentLights) { var fromSegmentId = e.Key; var segLights = e.Value; // one of the traffic lights at this segment is green: count minimum traffic flowing through SegmentEnd fromSeg = TrafficPriority.GetPrioritySegment(timedNodeId, fromSegmentId); if (fromSeg == null) { #if DEBUGMETRIC if (debug) { Log.Warning($"TimedTrafficLightsStep.calcWaitFlow: No priority segment @ seg. {fromSegmentId} found!"); } #endif //Log.Warning("stepDone(): prioSeg is null"); //segmentIdsToDelete.Add(fromSegmentId); continue; // skip invalid segment } //bool startPhase = getCurrentFrame() <= startFrame + minTime + 2; // during start phase all vehicles on "green" segments are counted as flowing ExtVehicleType validVehicleTypes = VehicleRestrictionsManager.GetAllowedVehicleTypes(fromSegmentId, timedNode.NodeId); foreach (KeyValuePair <byte, ExtVehicleType> e2 in segLights.VehicleTypeByLaneIndex) { byte laneIndex = e2.Key; ExtVehicleType vehicleType = e2.Value; if (vehicleType != ExtVehicleType.None && (validVehicleTypes & vehicleType) == ExtVehicleType.None) { continue; } CustomSegmentLight segLight = segLights.GetCustomLight(laneIndex); if (segLight == null) { Log.Warning($"Timed traffic light step: Failed to get custom light for vehicleType {vehicleType} @ seg. {fromSegmentId}, node {timedNode.NodeId}!"); continue; } #if DEBUGMETRIC if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Checking lane {laneIndex} @ seg. {fromSegmentId}. Vehicle types: {vehicleType}"); } #endif Dictionary <ushort, uint> carsFlowingToSegmentMetric = null; Dictionary <ushort, uint> allCarsToSegmentMetric = null; try { carsFlowingToSegmentMetric = fromSeg.GetVehicleMetricGoingToSegment(false, laneIndex, debug); } catch (Exception ex) { Log.Warning("calcWaitFlow (1): " + ex.ToString()); } try { allCarsToSegmentMetric = fromSeg.GetVehicleMetricGoingToSegment(true, laneIndex, debug); } catch (Exception ex) { Log.Warning("calcWaitFlow (2): " + ex.ToString()); } if (carsFlowingToSegmentMetric == null) { continue; } // build directions from toSegment to fromSegment Dictionary <ushort, Direction> directions = new Dictionary <ushort, Direction>(); foreach (KeyValuePair <ushort, uint> f in allCarsToSegmentMetric) { var toSegmentId = f.Key; SegmentGeometry geometry = SegmentGeometry.Get(fromSegmentId); Direction dir = geometry.GetDirection(toSegmentId, timedNodeId == geometry.StartNodeId()); directions[toSegmentId] = dir; #if DEBUGMETRIC if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Calculated direction for seg. {fromSegmentId} -> seg. {toSegmentId}: {dir}"); } #endif } // calculate waiting/flowing traffic foreach (KeyValuePair <ushort, uint> f in allCarsToSegmentMetric) { ushort toSegmentId = f.Key; uint totalNormCarLength = f.Value; uint totalFlowingNormCarLength = carsFlowingToSegmentMetric[f.Key]; #if DEBUGMETRIC if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Total norm. car length of vehicles on lane {laneIndex} going to seg. {toSegmentId}: {totalNormCarLength}"); } #endif bool addToFlow = false; switch (directions[toSegmentId]) { case Direction.Turn: addToFlow = TrafficPriority.IsLeftHandDrive() ? segLight.isRightGreen() : segLight.isLeftGreen(); break; case Direction.Left: addToFlow = segLight.isLeftGreen(); break; case Direction.Right: addToFlow = segLight.isRightGreen(); break; case Direction.Forward: default: addToFlow = segLight.isForwardGreen(); break; } if (addToFlow) { ++numFlows; curMeanFlow += totalFlowingNormCarLength; } else { ++numWaits; curMeanWait += totalNormCarLength; } #if DEBUGMETRIC if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Vehicles on lane {laneIndex} on seg. {fromSegmentId} going to seg. {toSegmentId} flowing? {addToFlow} curMeanFlow={curMeanFlow}, curMeanWait={curMeanWait}"); } #endif } } } // delete invalid segments from step /*foreach (int segmentId in segmentIdsToDelete) { * slaveStep.segmentLightStates.Remove(segmentId); * }*/ if (slaveStep.segmentLights.Count <= 0) { invalid = true; flow = 0f; wait = 0f; #if TRACE Singleton <CodeProfiler> .instance.Stop("TimedTrafficLightsStep.calcWaitFlow"); #endif return(false); } } #if DEBUGMETRIC if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: ### Calculation completed. numFlows={numFlows}, numWaits={numWaits}, curMeanFlow={curMeanFlow}, curMeanWait={curMeanWait}"); } wait = curMeanWait; flow = curMeanFlow; #else if (numFlows > 0) { curMeanFlow /= numFlows; } if (numWaits > 0) { curMeanWait /= numWaits; } float fCurMeanFlow = curMeanFlow; fCurMeanFlow /= waitFlowBalance; // a value smaller than 1 rewards steady traffic currents wait = (float)curMeanWait; flow = fCurMeanFlow; #endif #if TRACE Singleton <CodeProfiler> .instance.Stop("TimedTrafficLightsStep.calcWaitFlow"); #endif return(true); }
internal void Join(TimedTrafficLights otherTimedLight) { if (NumSteps() < otherTimedLight.NumSteps()) { // increase the number of steps at our timed lights for (int i = NumSteps(); i < otherTimedLight.NumSteps(); ++i) { TimedTrafficLightsStep otherStep = otherTimedLight.GetStep(i); foreach (ushort slaveNodeId in NodeGroup) { TrafficLightSimulation ourSim = TrafficLightSimulation.GetNodeSimulation(slaveNodeId); if (ourSim == null || !ourSim.IsTimedLight()) continue; TimedTrafficLights ourTimedLight = ourSim.TimedLight; ourTimedLight.AddStep(otherStep.minTime, otherStep.maxTime, otherStep.waitFlowBalance, true); } } } else { // increase the number of steps at their timed lights for (int i = otherTimedLight.NumSteps(); i < NumSteps(); ++i) { TimedTrafficLightsStep ourStep = GetStep(i); foreach (ushort slaveNodeId in otherTimedLight.NodeGroup) { TrafficLightSimulation theirSim = TrafficLightSimulation.GetNodeSimulation(slaveNodeId); if (theirSim == null || !theirSim.IsTimedLight()) continue; TimedTrafficLights theirTimedLight = theirSim.TimedLight; theirTimedLight.AddStep(ourStep.minTime, ourStep.maxTime, ourStep.waitFlowBalance, true); } } } // join groups and re-defined master node, determine mean min/max times & mean wait-flow-balances HashSet<ushort> newNodeGroupSet = new HashSet<ushort>(); newNodeGroupSet.UnionWith(NodeGroup); newNodeGroupSet.UnionWith(otherTimedLight.NodeGroup); List<ushort> newNodeGroup = new List<ushort>(newNodeGroupSet); ushort newMasterNodeId = newNodeGroup[0]; int[] minTimes = new int[NumSteps()]; int[] maxTimes = new int[NumSteps()]; float[] waitFlowBalances = new float[NumSteps()]; foreach (ushort timedNodeId in newNodeGroup) { TrafficLightSimulation timedSim = TrafficLightSimulation.GetNodeSimulation(timedNodeId); if (timedSim == null || !timedSim.IsTimedLight()) continue; TimedTrafficLights timedLight = timedSim.TimedLight; for (int i = 0; i < NumSteps(); ++i) { minTimes[i] += timedLight.GetStep(i).minTime; maxTimes[i] += timedLight.GetStep(i).maxTime; waitFlowBalances[i] += timedLight.GetStep(i).waitFlowBalance; } timedLight.NodeGroup = newNodeGroup; timedLight.masterNodeId = newMasterNodeId; } // build means if (NumSteps() > 0) { for (int i = 0; i < NumSteps(); ++i) { minTimes[i] = Math.Max(1, minTimes[i] / newNodeGroup.Count); maxTimes[i] = Math.Max(1, maxTimes[i] / newNodeGroup.Count); waitFlowBalances[i] = Math.Max(0.001f, waitFlowBalances[i] / (float)newNodeGroup.Count); } } // apply means & reset foreach (ushort timedNodeId in newNodeGroup) { TrafficLightSimulation timedSim = TrafficLightSimulation.GetNodeSimulation(timedNodeId); if (timedSim == null || !timedSim.IsTimedLight()) continue; TimedTrafficLights timedLight = timedSim.TimedLight; timedLight.Stop(); timedLight.testMode = false; timedLight.lastSimulationStep = 0; for (int i = 0; i < NumSteps(); ++i) { timedLight.GetStep(i).minTime = minTimes[i]; timedLight.GetStep(i).maxTime = maxTimes[i]; timedLight.GetStep(i).waitFlowBalance = waitFlowBalances[i]; } } }
internal void Join(TimedTrafficLights otherTimedLight) { TrafficLightSimulationManager tlsMan = TrafficLightSimulationManager.Instance(); if (NumSteps() < otherTimedLight.NumSteps()) { // increase the number of steps at our timed lights for (int i = NumSteps(); i < otherTimedLight.NumSteps(); ++i) { TimedTrafficLightsStep otherStep = otherTimedLight.GetStep(i); foreach (ushort slaveNodeId in NodeGroup) { TrafficLightSimulation ourSim = tlsMan.GetNodeSimulation(slaveNodeId); if (ourSim == null || !ourSim.IsTimedLight()) { continue; } TimedTrafficLights ourTimedLight = ourSim.TimedLight; ourTimedLight.AddStep(otherStep.minTime, otherStep.maxTime, otherStep.waitFlowBalance, true); } } } else { // increase the number of steps at their timed lights for (int i = otherTimedLight.NumSteps(); i < NumSteps(); ++i) { TimedTrafficLightsStep ourStep = GetStep(i); foreach (ushort slaveNodeId in otherTimedLight.NodeGroup) { TrafficLightSimulation theirSim = tlsMan.GetNodeSimulation(slaveNodeId); if (theirSim == null || !theirSim.IsTimedLight()) { continue; } TimedTrafficLights theirTimedLight = theirSim.TimedLight; theirTimedLight.AddStep(ourStep.minTime, ourStep.maxTime, ourStep.waitFlowBalance, true); } } } // join groups and re-defined master node, determine mean min/max times & mean wait-flow-balances HashSet <ushort> newNodeGroupSet = new HashSet <ushort>(); newNodeGroupSet.UnionWith(NodeGroup); newNodeGroupSet.UnionWith(otherTimedLight.NodeGroup); List <ushort> newNodeGroup = new List <ushort>(newNodeGroupSet); ushort newMasterNodeId = newNodeGroup[0]; int[] minTimes = new int[NumSteps()]; int[] maxTimes = new int[NumSteps()]; float[] waitFlowBalances = new float[NumSteps()]; foreach (ushort timedNodeId in newNodeGroup) { TrafficLightSimulation timedSim = tlsMan.GetNodeSimulation(timedNodeId); if (timedSim == null || !timedSim.IsTimedLight()) { continue; } TimedTrafficLights timedLight = timedSim.TimedLight; for (int i = 0; i < NumSteps(); ++i) { minTimes[i] += timedLight.GetStep(i).minTime; maxTimes[i] += timedLight.GetStep(i).maxTime; waitFlowBalances[i] += timedLight.GetStep(i).waitFlowBalance; } timedLight.NodeGroup = newNodeGroup; timedLight.masterNodeId = newMasterNodeId; } // build means if (NumSteps() > 0) { for (int i = 0; i < NumSteps(); ++i) { minTimes[i] = Math.Max(1, minTimes[i] / newNodeGroup.Count); maxTimes[i] = Math.Max(1, maxTimes[i] / newNodeGroup.Count); waitFlowBalances[i] = Math.Max(0.001f, waitFlowBalances[i] / (float)newNodeGroup.Count); } } // apply means & reset foreach (ushort timedNodeId in newNodeGroup) { TrafficLightSimulation timedSim = tlsMan.GetNodeSimulation(timedNodeId); if (timedSim == null || !timedSim.IsTimedLight()) { continue; } TimedTrafficLights timedLight = timedSim.TimedLight; timedLight.Stop(); timedLight.testMode = false; timedLight.lastSimulationStep = 0; for (int i = 0; i < NumSteps(); ++i) { timedLight.GetStep(i).minTime = minTimes[i]; timedLight.GetStep(i).maxTime = maxTimes[i]; timedLight.GetStep(i).waitFlowBalance = waitFlowBalances[i]; } } }
public void UpdateLiveLights(bool noTransition) { try { CustomSegmentLightsManager customTrafficLightsManager = CustomSegmentLightsManager.Instance; bool atEndTransition = !noTransition && (IsInEndTransition() || IsEndTransitionDone()); // = yellow bool atStartTransition = !noTransition && !atEndTransition && IsInStartTransition(); // = red + yellow #if DEBUG if (timedNode == null) { Log.Error($"TimedTrafficLightsStep: timedNode is null!"); return; } #endif if (PreviousStepRefIndex >= timedNode.NumSteps()) { PreviousStepRefIndex = -1; } if (NextStepRefIndex >= timedNode.NumSteps()) { NextStepRefIndex = -1; } TimedTrafficLightsStep previousStep = timedNode.Steps[PreviousStepRefIndex >= 0 ? PreviousStepRefIndex : ((timedNode.CurrentStep + timedNode.Steps.Count - 1) % timedNode.Steps.Count)]; TimedTrafficLightsStep nextStep = timedNode.Steps[NextStepRefIndex >= 0 ? NextStepRefIndex : ((timedNode.CurrentStep + 1) % timedNode.Steps.Count)]; #if DEBUG if (previousStep == null) { Log.Error($"TimedTrafficLightsStep: previousStep is null!"); return; } if (nextStep == null) { Log.Error($"TimedTrafficLightsStep: nextStep is null!"); return; } if (previousStep.segmentLights == null) { Log.Error($"TimedTrafficLightsStep: previousStep.segmentLights is null!"); return; } if (nextStep.segmentLights == null) { Log.Error($"TimedTrafficLightsStep: nextStep.segmentLights is null!"); return; } if (segmentLights == null) { Log.Error($"TimedTrafficLightsStep: segmentLights is null!"); return; } #endif #if DEBUG //Log._Debug($"TimedTrafficLightsStep.SetLights({noTransition}) called for NodeId={timedNode.NodeId}. atStartTransition={atStartTransition} atEndTransition={atEndTransition}"); #endif foreach (KeyValuePair <ushort, CustomSegmentLights> e in segmentLights) { var segmentId = e.Key; var curStepSegmentLights = e.Value; #if DEBUG //Log._Debug($"TimedTrafficLightsStep.SetLights({noTransition}) -> segmentId={segmentId} @ NodeId={timedNode.NodeId}"); #endif if (!previousStep.segmentLights.ContainsKey(segmentId)) { #if DEBUG Log._Debug($"TimedTrafficLightsStep: previousStep does not contain lights for segment {segmentId}!"); #endif continue; } if (!nextStep.segmentLights.ContainsKey(segmentId)) { #if DEBUG Log._Debug($"TimedTrafficLightsStep: nextStep does not contain lights for segment {segmentId}!"); #endif continue; } var prevStepSegmentLights = previousStep.segmentLights[segmentId]; var nextStepSegmentLights = nextStep.segmentLights[segmentId]; //segLightState.makeRedOrGreen(); // TODO temporary fix var liveSegmentLights = customTrafficLightsManager.GetSegmentLights(segmentId, curStepSegmentLights.StartNode, false); if (liveSegmentLights == null) { continue; } RoadBaseAI.TrafficLightState pedLightState = calcLightState((RoadBaseAI.TrafficLightState)prevStepSegmentLights.PedestrianLightState, (RoadBaseAI.TrafficLightState)curStepSegmentLights.PedestrianLightState, (RoadBaseAI.TrafficLightState)nextStepSegmentLights.PedestrianLightState, atStartTransition, atEndTransition); //Log._Debug($"TimedStep.SetLights: Setting pedestrian light state @ seg. {segmentId} to {pedLightState} {curStepSegmentLights.ManualPedestrianMode}"); liveSegmentLights.ManualPedestrianMode = curStepSegmentLights.ManualPedestrianMode; liveSegmentLights.PedestrianLightState = liveSegmentLights.AutoPedestrianLightState = pedLightState; //Log.Warning($"Step @ {timedNode.NodeId}: Segment {segmentId}: Ped.: {liveSegmentLights.PedestrianLightState.ToString()} / {liveSegmentLights.AutoPedestrianLightState.ToString()}"); #if DEBUG if (curStepSegmentLights.VehicleTypes == null) { Log.Error($"TimedTrafficLightsStep: curStepSegmentLights.VehicleTypes is null!"); return; } #endif foreach (ExtVehicleType vehicleType in curStepSegmentLights.VehicleTypes) { #if DEBUG //Log._Debug($"TimedTrafficLightsStep.SetLights({noTransition}) -> segmentId={segmentId} @ NodeId={timedNode.NodeId} for vehicle {vehicleType}"); #endif CustomSegmentLight liveSegmentLight = liveSegmentLights.GetCustomLight(vehicleType); if (liveSegmentLight == null) { #if DEBUG Log._Debug($"Timed step @ seg. {segmentId}, node {timedNode.NodeId} has a traffic light for {vehicleType} but the live segment does not have one."); #endif continue; } CustomSegmentLight curStepSegmentLight = curStepSegmentLights.GetCustomLight(vehicleType); CustomSegmentLight prevStepSegmentLight = prevStepSegmentLights.GetCustomLight(vehicleType); CustomSegmentLight nextStepSegmentLight = nextStepSegmentLights.GetCustomLight(vehicleType); #if DEBUG if (curStepSegmentLight == null) { Log.Error($"TimedTrafficLightsStep: curStepSegmentLight is null!"); return; } if (prevStepSegmentLight == null) { Log.Error($"TimedTrafficLightsStep: prevStepSegmentLight is null!"); return; } if (nextStepSegmentLight == null) { Log.Error($"TimedTrafficLightsStep: nextStepSegmentLight is null!"); return; } #endif liveSegmentLight.currentMode = curStepSegmentLight.CurrentMode; /*curStepSegmentLight.EnsureModeLights(); * prevStepSegmentLight.EnsureModeLights(); * nextStepSegmentLight.EnsureModeLights();*/ RoadBaseAI.TrafficLightState mainLight = calcLightState(prevStepSegmentLight.LightMain, curStepSegmentLight.LightMain, nextStepSegmentLight.LightMain, atStartTransition, atEndTransition); RoadBaseAI.TrafficLightState leftLight = calcLightState(prevStepSegmentLight.LightLeft, curStepSegmentLight.LightLeft, nextStepSegmentLight.LightLeft, atStartTransition, atEndTransition); RoadBaseAI.TrafficLightState rightLight = calcLightState(prevStepSegmentLight.LightRight, curStepSegmentLight.LightRight, nextStepSegmentLight.LightRight, atStartTransition, atEndTransition); liveSegmentLight.SetStates(mainLight, leftLight, rightLight, false); #if DEBUGTTL Log._Debug($"TimedTrafficLightsStep.SetLights({noTransition}) -> *SETTING* LightLeft={liveSegmentLight.LightLeft} LightMain={liveSegmentLight.LightMain} LightRight={liveSegmentLight.LightRight} for segmentId={segmentId} @ NodeId={timedNode.NodeId} for vehicle {vehicleType}"); #endif //Log._Debug($"Step @ {timedNode.NodeId}: Segment {segmentId} for vehicle type {vehicleType}: L: {liveSegmentLight.LightLeft.ToString()} F: {liveSegmentLight.LightMain.ToString()} R: {liveSegmentLight.LightRight.ToString()}"); } /*if (timedNode.NodeId == 20164) { * Log._Debug($"Step @ {timedNode.NodeId}: Segment {segmentId}: {segmentLight.LightLeft.ToString()} {segmentLight.LightMain.ToString()} {segmentLight.LightRight.ToString()} {segmentLight.LightPedestrian.ToString()}"); * }*/ liveSegmentLights.UpdateVisuals(); } } catch (Exception e) { Log.Error($"Exception in TimedTrafficStep.SetLights for node {timedNode.NodeId}: {e.ToString()}"); //invalid = true; } }
/// <summary> /// Calculates the current metrics for flowing and waiting vehicles /// </summary> /// <param name="wait"></param> /// <param name="flow"></param> /// <returns>true if the values could be calculated, false otherwise</returns> public bool calcWaitFlow(out float wait, out float flow) { #if DEBUG bool debug = timedNode.NodeId == 17857; #else bool debug = false; #endif uint numFlows = 0; uint numWaits = 0; uint curMeanFlow = 0; uint curMeanWait = 0; // we are the master node. calculate traffic data foreach (ushort timedNodeId in groupNodeIds) { TrafficLightSimulation sim = TrafficLightSimulation.GetNodeSimulation(timedNodeId); if (sim == null || !sim.IsTimedLight()) { continue; } TimedTrafficLights slaveTimedNode = sim.TimedLight; if (slaveTimedNode.NumSteps() <= timedNode.CurrentStep) { for (int i = 0; i < slaveTimedNode.NumSteps(); ++i) { slaveTimedNode.GetStep(i).invalid = true; } continue; } TimedTrafficLightsStep slaveStep = slaveTimedNode.Steps[timedNode.CurrentStep]; //List<int> segmentIdsToDelete = new List<int>(); // minimum time reached. check traffic! foreach (KeyValuePair <ushort, CustomSegmentLights> e in slaveStep.segmentLights) { var fromSegmentId = e.Key; var segLights = e.Value; // one of the traffic lights at this segment is green: count minimum traffic flowing through SegmentEnd fromSeg = TrafficPriority.GetPrioritySegment(timedNodeId, fromSegmentId); if (fromSeg == null) { //Log.Warning("stepDone(): prioSeg is null"); //segmentIdsToDelete.Add(fromSegmentId); continue; // skip invalid segment } bool startPhase = getCurrentFrame() <= startFrame + minTime + 2; // during start phase all vehicles on "green" segments are counted as flowing ExtVehicleType validVehicleTypes = VehicleRestrictionsManager.GetAllowedVehicleTypes(fromSegmentId, timedNode.NodeId); foreach (ExtVehicleType vehicleType in segLights.VehicleTypes) { if (vehicleType != ExtVehicleType.None && (validVehicleTypes & vehicleType) == ExtVehicleType.None) { continue; } CustomSegmentLight segLight = segLights.GetCustomLight(vehicleType); if (segLight == null) { Log.Warning($"Timed traffic light step: Failed to get custom light for vehicleType {vehicleType} @ seg. {fromSegmentId}, node {timedNode.NodeId}!"); continue; } Dictionary <ushort, uint>[] carsToSegmentMetrics = new Dictionary <ushort, uint> [startPhase ? 1: 2]; try { carsToSegmentMetrics[0] = fromSeg.GetVehicleMetricGoingToSegment(null, vehicleType, segLights.SeparateVehicleTypes, debug); } catch (Exception ex) { Log.Warning("calcWaitFlow: " + ex.ToString()); } if (!startPhase) { try { carsToSegmentMetrics[1] = fromSeg.GetVehicleMetricGoingToSegment(0.1f, vehicleType, segLights.SeparateVehicleTypes, debug); } catch (Exception ex) { Log.Warning("calcWaitFlow: " + ex.ToString()); } } if (carsToSegmentMetrics[0] == null) { continue; } // build directions from toSegment to fromSegment Dictionary <ushort, Direction> directions = new Dictionary <ushort, Direction>(); foreach (KeyValuePair <ushort, uint> f in carsToSegmentMetrics[0]) { var toSegmentId = f.Key; SegmentGeometry geometry = CustomRoadAI.GetSegmentGeometry(fromSegmentId); Direction dir = geometry.GetDirection(toSegmentId, timedNodeId); directions[toSegmentId] = dir; } // calculate waiting/flowing traffic for (int i = 0; i < carsToSegmentMetrics.Length; ++i) { if (carsToSegmentMetrics[i] == null) { continue; } foreach (KeyValuePair <ushort, uint> f in carsToSegmentMetrics[i]) { ushort toSegmentId = f.Key; uint totalNormCarLength = f.Value; bool addToFlow = false; switch (directions[toSegmentId]) { case Direction.Left: if (segLight.isLeftGreen()) { addToFlow = true; } break; case Direction.Right: if (segLight.isRightGreen()) { addToFlow = true; } break; case Direction.Forward: default: if (segLight.isForwardGreen()) { addToFlow = true; } break; } if (addToFlow) { if (i > 0 || startPhase) { ++numFlows; curMeanFlow += totalNormCarLength; } } else if (i == 0) { ++numWaits; curMeanWait += totalNormCarLength; } } } } } // delete invalid segments from step /*foreach (int segmentId in segmentIdsToDelete) { * slaveStep.segmentLightStates.Remove(segmentId); * }*/ if (slaveStep.segmentLights.Count <= 0) { invalid = true; flow = 0f; wait = 0f; return(false); } } if (numFlows > 0) { curMeanFlow /= numFlows; } if (numWaits > 0) { curMeanWait /= numWaits; } float fCurMeanFlow = curMeanFlow; fCurMeanFlow /= 100f * waitFlowBalance; // a value smaller than 1 rewards steady traffic currents wait = (float)curMeanWait / 100f; flow = fCurMeanFlow; return(true); }