/*public VehiclePosition GetCurrentPosition() { * LinkedListNode<VehiclePosition> firstNode = CurrentPosition; * if (firstNode == null) * return null; * return firstNode.Value; * }*/ internal void UpdatePosition(ref Vehicle vehicleData, ref PathUnit.Position curPos, ref PathUnit.Position nextPos, bool skipCheck = false) { if (!skipCheck && !CheckValidity(ref vehicleData)) { return; } LastPositionUpdate = Singleton <SimulationManager> .instance.m_currentFrameIndex; SegmentEnd end = TrafficPriority.GetPrioritySegment(GetTransitNodeId(ref curPos, ref nextPos), curPos.m_segment); if (CurrentSegmentEnd != end) { if (CurrentSegmentEnd != null) { Unlink(); } WaitTime = 0; if (end != null) { Link(end); JunctionTransitState = VehicleJunctionTransitState.Enter; } else { JunctionTransitState = VehicleJunctionTransitState.None; } } }
internal void Housekeeping() { if (TrafficManagerTool.GetToolMode() != ToolMode.AddPrioritySigns && TrafficLightSimulation.GetNodeSimulation(NodeId) == null && Type == PriorityType.None) { TrafficPriority.RemovePrioritySegments(NodeId); } }
public void AddVehicle(ushort vehicleId, VehiclePosition carPos) { if (carPos.ToNode != NodeId || carPos.FromSegment != SegmentId) { Log.Warning($"Refusing to add vehicle {vehicleId} to PrioritySegment {SegmentId} @ {NodeId} (given: {carPos.FromSegment} @ {carPos.ToNode})."); return; } Vehicles[vehicleId] = carPos; TrafficPriority.MarkVehicleInSegment(vehicleId, SegmentId); }
/// <summary> /// Determines the allowed vehicle types that may approach the given node from the given segment (lane-wise). /// </summary> /// <param name="segmentId"></param> /// <param name="nodeId"></param> /// <returns></returns> internal static Dictionary <byte, ExtVehicleType> GetAllowedVehicleTypesAsDict(ushort segmentId, ushort nodeId) { #if TRACE Singleton <CodeProfiler> .instance.Start("VehicleRestrictionsManager.GetAllowedVehicleTypesAsDict"); #endif Dictionary <byte, ExtVehicleType> ret = new Dictionary <byte, ExtVehicleType>(); NetManager netManager = Singleton <NetManager> .instance; if (segmentId == 0 || (netManager.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Created) == NetSegment.Flags.None || nodeId == 0 || (netManager.m_nodes.m_buffer[nodeId].m_flags & NetNode.Flags.Created) == NetNode.Flags.None) { #if TRACE Singleton <CodeProfiler> .instance.Stop("VehicleRestrictionsManager.GetAllowedVehicleTypesAsDict"); #endif return(ret); } var dir = NetInfo.Direction.Forward; var dir2 = ((netManager.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) ? dir : NetInfo.InvertDirection(dir); var dir3 = TrafficPriority.IsLeftHandDrive() ? NetInfo.InvertDirection(dir2) : dir2; NetInfo segmentInfo = netManager.m_segments.m_buffer[segmentId].Info; uint curLaneId = netManager.m_segments.m_buffer[segmentId].m_lanes; int numLanes = segmentInfo.m_lanes.Length; uint laneIndex = 0; while (laneIndex < numLanes && curLaneId != 0u) { NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; ushort toNodeId = (laneInfo.m_direction == dir3) ? netManager.m_segments.m_buffer[segmentId].m_endNode : netManager.m_segments.m_buffer[segmentId].m_startNode; if (toNodeId == nodeId) { ExtVehicleType vehicleTypes = GetAllowedVehicleTypes(segmentId, segmentInfo, laneIndex, laneInfo); if (vehicleTypes != ExtVehicleType.None) { ret[(byte)laneIndex] = vehicleTypes; } } curLaneId = netManager.m_lanes.m_buffer[curLaneId].m_nextLane; ++laneIndex; } #if TRACE Singleton <CodeProfiler> .instance.Stop("VehicleRestrictionsManager.GetAllowedVehicleTypesAsDict"); #endif return(ret); }
public void OnUpdate(SegmentGeometry geometry) { if (!geometry.IsValid()) { TrafficPriority.RemovePrioritySegment(NodeId, SegmentId); return; } StartNode = Singleton <NetManager> .instance.m_segments.m_buffer[SegmentId].m_startNode == NodeId; numLanes = Singleton <NetManager> .instance.m_segments.m_buffer[SegmentId].Info.m_lanes.Length; numVehiclesFlowingToSegmentId = new Dictionary <ushort, uint>(7); numVehiclesGoingToSegmentId = new Dictionary <ushort, uint>(7); //frontVehicleIds = new ushort[numLanes]; ushort[] outgoingSegmentIds = geometry.GetOutgoingSegments(StartNode); foreach (ushort otherSegmentId in outgoingSegmentIds) { numVehiclesFlowingToSegmentId[otherSegmentId] = 0; numVehiclesGoingToSegmentId[otherSegmentId] = 0; } }
/// <summary> /// Determines the allowed vehicle types that may approach the given node from the given segment. /// </summary> /// <param name="segmentId"></param> /// <param name="nodeId"></param> /// <returns></returns> internal static HashSet <ExtVehicleType> GetAllowedVehicleTypesAsSet(ushort segmentId, ushort nodeId) { HashSet <ExtVehicleType> ret = new HashSet <ExtVehicleType>(); NetManager netManager = Singleton <NetManager> .instance; if (segmentId == 0 || (netManager.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Created) == NetSegment.Flags.None || nodeId == 0 || (netManager.m_nodes.m_buffer[nodeId].m_flags & NetNode.Flags.Created) == NetNode.Flags.None) { return(ret); } var dir = NetInfo.Direction.Forward; var dir2 = ((netManager.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) ? dir : NetInfo.InvertDirection(dir); var dir3 = TrafficPriority.IsLeftHandDrive() ? NetInfo.InvertDirection(dir2) : dir2; NetInfo segmentInfo = netManager.m_segments.m_buffer[segmentId].Info; uint curLaneId = netManager.m_segments.m_buffer[segmentId].m_lanes; int numLanes = segmentInfo.m_lanes.Length; uint laneIndex = 0; while (laneIndex < numLanes && curLaneId != 0u) { NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; ushort toNodeId = (laneInfo.m_direction == dir3) ? netManager.m_segments.m_buffer[segmentId].m_endNode : netManager.m_segments.m_buffer[segmentId].m_startNode; if (toNodeId == nodeId) { ret.Add(GetAllowedVehicleTypes(segmentId, laneIndex, curLaneId, laneInfo)); } curLaneId = netManager.m_lanes.m_buffer[curLaneId].m_nextLane; ++laneIndex; } return(ret); }
/// <summary> /// Calculates for each segment the number of cars going to this segment. /// We use integer arithmetic for better performance. /// </summary> public Dictionary <ushort, uint> GetVehicleMetricGoingToSegment(float?minSpeed, ExtVehicleType?vehicleTypes = null, ExtVehicleType separateVehicleTypes = ExtVehicleType.None, bool debug = false) { Dictionary <ushort, uint> numCarsGoingToSegmentId = new Dictionary <ushort, uint>(); VehicleManager vehicleManager = Singleton <VehicleManager> .instance; NetManager netManager = Singleton <NetManager> .instance; for (var s = 0; s < 8; s++) { var segmentId = netManager.m_nodes.m_buffer[NodeId].GetSegment(s); if (segmentId == 0 || segmentId == SegmentId) { continue; } if (CustomRoadAI.GetSegmentGeometry(segmentId).IsIncomingOneWay(NodeId)) { continue; } numCarsGoingToSegmentId[segmentId] = 0; } List <ushort> vehicleIdsToReHandle = new List <ushort>(); foreach (KeyValuePair <ushort, VehiclePosition> e in Vehicles) { var vehicleId = e.Key; var carPos = e.Value; if (vehicleId <= 0 || carPos.ToSegment <= 0) { continue; } if ((vehicleManager.m_vehicles.m_buffer[vehicleId].m_flags & Vehicle.Flags.Created) == Vehicle.Flags.None) { vehicleIdsToReHandle.Add(vehicleId); continue; } if (minSpeed != null && vehicleManager.m_vehicles.m_buffer[vehicleId].GetLastFrameVelocity().magnitude < minSpeed) { continue; } VehiclePosition globalPos = TrafficPriority.GetVehiclePosition(vehicleId); if (globalPos == null || !globalPos.Valid || globalPos.LastFrame >> 7 < Singleton <SimulationManager> .instance.m_currentFrameIndex >> 7) // ~64 sec. { vehicleIdsToReHandle.Add(vehicleId); continue; } if (vehicleTypes != null) { if (vehicleTypes == ExtVehicleType.None) { if ((globalPos.VehicleType & separateVehicleTypes) != ExtVehicleType.None) { // we want all vehicles that do not have separate traffic lights continue; } } else { if ((globalPos.VehicleType & vehicleTypes) == ExtVehicleType.None) { continue; } } } //debug = vehicleManager.m_vehicles.m_buffer[vehicleId].Info.m_vehicleType == VehicleInfo.VehicleType.Tram; #if DEBUG /*if (debug) { * Log._Debug($"getNumCarsGoingToSegment: Handling vehicle {vehicleId} going from {carPos.FromSegment}/{SegmentId} to {carPos.ToSegment}. carState={globalPos.CarState}. lastUpdate={globalPos.LastCarStateUpdate}"); * }*/ #endif uint avgSegmentLength = (uint)Singleton <NetManager> .instance.m_segments.m_buffer[SegmentId].m_averageLength; uint normLength = (uint)(vehicleManager.m_vehicles.m_buffer[vehicleId].CalculateTotalLength(vehicleId) * 100u) / avgSegmentLength; #if DEBUG /*if (debug) { * Log._Debug($"getNumCarsGoingToSegment: NormLength of vehicle {vehicleId} going to {carPos.ToSegment}: {avgSegmentLength} -> {normLength}"); * }*/ #endif if (numCarsGoingToSegmentId.ContainsKey(carPos.ToSegment)) { /*if (carPos.OnEmergency) * numCarsGoingToSegmentId[carPos.ToSegment] += 10000f; * else*/ numCarsGoingToSegmentId[carPos.ToSegment] += normLength; } // "else" must not happen (incoming one-way) } foreach (ushort vehicleId in vehicleIdsToReHandle) { CustomVehicleAI.HandleVehicle(vehicleId, ref Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleId], false, false); } return(numCarsGoingToSegmentId); }
public bool RemoveVehicle(ushort vehicleId) { Vehicles.Remove(vehicleId); TrafficPriority.UnmarkVehicleInSegment(vehicleId, SegmentId); return(true); }
public bool StepDone() { if (stepDone) { return(true); } if (startFrame + maxTime <= getCurrentFrame()) { // maximum time reached. switch! #if DEBUG //Log.Message("step finished @ " + nodeId); #endif stepDone = true; endTransitionStart = (int)getCurrentFrame(); return(stepDone); } if (startFrame + minTime <= getCurrentFrame()) { if (masterNodeId != null && TrafficLightsTimed.IsTimedLight((ushort)masterNodeId)) { TrafficLightsTimed masterTimedNode = TrafficLightsTimed.GetTimedLight((ushort)masterNodeId); bool done = masterTimedNode.Steps[masterTimedNode.CurrentStep].StepDone(); #if DEBUG //Log.Message("step finished (1) @ " + nodeId); #endif stepDone = done; if (stepDone) { endTransitionStart = (int)getCurrentFrame(); } return(stepDone); } else { int numFlows = 0; int numWaits = 0; float curMeanFlow = 0; float curMeanWait = 0; // we are the master node. calculate traffic data foreach (ushort timedNodeId in groupNodeIds) { if (!TrafficLightsTimed.IsTimedLight(timedNodeId)) { continue; } TrafficLightsTimed slaveTimedNode = TrafficLightsTimed.GetTimedLight(timedNodeId); TimedTrafficStep slaveStep = slaveTimedNode.Steps[timedNode.CurrentStep]; //List<int> segmentIdsToDelete = new List<int>(); // minimum time reached. check traffic! foreach (KeyValuePair <ushort, ManualSegmentLight> e in slaveStep.segmentLightStates) { var fromSegmentId = e.Key; var segLightState = e.Value; float segmentWeight = Singleton <NetManager> .instance.m_segments.m_buffer[fromSegmentId].m_averageLength / maxSegmentLength; // one of the traffic lights at this segment is green: count minimum traffic flowing through PrioritySegment prioSeg = TrafficPriority.GetPrioritySegment(timedNodeId, fromSegmentId); if (prioSeg == null) { //Log.Warning("stepDone(): prioSeg is null"); //segmentIdsToDelete.Add(fromSegmentId); continue; // skip invalid segment } foreach (KeyValuePair <ushort, int> f in prioSeg.numCarsGoingToSegmentId) { var toSegmentId = f.Key; var numCars = f.Value; TrafficPriority.Direction dir = TrafficPriority.GetDirection(fromSegmentId, toSegmentId, timedNodeId); bool addToFlow = false; switch (dir) { case TrafficPriority.Direction.Left: if (segLightState.isLeftGreen()) { addToFlow = true; } break; case TrafficPriority.Direction.Right: if (segLightState.isRightGreen()) { addToFlow = true; } break; case TrafficPriority.Direction.Forward: default: if (segLightState.isForwardGreen()) { addToFlow = true; } break; } if (addToFlow) { ++numFlows; curMeanFlow += (float)numCars * segmentWeight; } else { ++numWaits; curMeanWait += (float)numCars * segmentWeight; } } } // delete invalid segments from step /*foreach (int segmentId in segmentIdsToDelete) { * slaveStep.segmentLightStates.Remove(segmentId); * }*/ if (slaveStep.segmentLightStates.Count <= 0) { invalid = true; return(true); } } if (numFlows > 0) { curMeanFlow /= (float)numFlows; } if (numWaits > 0) { curMeanWait /= (float)numWaits; } float decisionValue = 0.8f; // a value smaller than 1 rewards steady traffic currents curMeanFlow /= decisionValue; if (Single.IsNaN(minFlow)) { minFlow = curMeanFlow; } else { minFlow = Math.Min(curMeanFlow, minFlow); } if (Single.IsNaN(maxWait)) { maxWait = curMeanWait; } else { maxWait = Math.Max(curMeanWait, maxWait); } // if more cars are waiting than flowing, we change the step bool done = maxWait > 0 && minFlow < maxWait; #if DEBUG //Log.Message("step finished (2) @ " + nodeId); #endif stepDone = done; if (stepDone) { endTransitionStart = (int)getCurrentFrame(); } return(stepDone); } } return(false); }
internal void Recalculate() { #if DEBUGGEO Log._Debug($"NodeGeometry: Recalculate @ {NodeId}"); #endif Cleanup(); Flags.applyNodeTrafficLightFlag(NodeId); // check if node is valid if (!IsValid()) { for (int i = 0; i < 8; ++i) { SegmentEndGeometries[i] = null; } TrafficLightSimulation.RemoveNodeFromSimulation(NodeId, false, true); Flags.setNodeTrafficLight(NodeId, false); } else { NetManager netManager = Singleton <NetManager> .instance; bool hasTrafficLight = (netManager.m_nodes.m_buffer[NodeId].m_flags & NetNode.Flags.TrafficLights) != NetNode.Flags.None; var nodeSim = TrafficLightSimulation.GetNodeSimulation(NodeId); if (nodeSim == null) { byte numSegmentsWithSigns = 0; for (var s = 0; s < 8; s++) { var segmentId = netManager.m_nodes.m_buffer[NodeId].GetSegment(s); if (segmentId <= 0) { continue; } #if DEBUGx Log._Debug($"NodeGeometry.Recalculate: Housekeeping segment {segmentId}"); #endif SegmentEnd prioritySegment = TrafficPriority.GetPrioritySegment(NodeId, segmentId); if (prioritySegment == null) { continue; } // if node is a traffic light, it must not have priority signs if (hasTrafficLight && prioritySegment.Type != SegmentEnd.PriorityType.None) { Log.Warning($"Housekeeping: Node {NodeId}, Segment {segmentId} is a priority sign but node has a traffic light!"); prioritySegment.Type = SegmentEnd.PriorityType.None; } // if a priority sign is set, everything is ok if (prioritySegment.Type != SegmentEnd.PriorityType.None) { ++numSegmentsWithSigns; } } if (numSegmentsWithSigns > 0) { // add priority segments for newly created segments numSegmentsWithSigns += TrafficPriority.AddPriorityNode(NodeId); } } // calculate node properties byte incomingSegments = 0; byte outgoingSegments = 0; for (int i = 0; i < 8; ++i) { if (SegmentEndGeometries[i] == null) { continue; } #if DEBUGGEO Log._Debug($"NodeGeometry.Recalculate: Iterating over segment end {SegmentEndGeometries[i].SegmentId} @ node {NodeId}"); #endif bool startNode = SegmentEndGeometries[i].StartNode; if (SegmentEndGeometries[i].GetSegmentGeometry().IsIncoming(startNode)) { ++incomingSegments; } if (SegmentEndGeometries[i].GetSegmentGeometry().IsOutgoing(startNode)) { ++outgoingSegments; } } IsSimpleJunction = incomingSegments == 1 || outgoingSegments == 1; #if DEBUGGEO Log._Debug($"NodeGeometry.Recalculate: Node {NodeId} has {incomingSegments} incoming and {outgoingSegments} outgoing segments."); #endif } NotifyObservers(); }