private List <Module> DefineSideModules(SegmentEnd end, bool isStart) { List <Module> res = null; if (end == SegmentEnd.End) { var dir = DirectionLeftToRight;// Direction.ToRight(); if (isStart) { Cell lastCell; res = parser.GetSteps(CellStartLeft, dir, out lastCell); } else { Cell lastCell; res = parser.GetSteps(CellEndLeft, dir, out lastCell); } if (res != null && res.Count == 4) { res.RemoveAt(0); res.RemoveAt(res.Count - 1); } } return(res); }
public ISegmentEnd GetOrAddSegmentEnd(ushort segmentId, bool startNode) { ISegmentEnd end = GetSegmentEnd(segmentId, startNode); if (end != null) { return(end); } SegmentGeometry segGeo = SegmentGeometry.Get(segmentId); if (segGeo == null) { Log.Warning($"SegmentEndManager.GetOrAddSegmentEnd({segmentId}, {startNode}): Refusing to add segment end for invalid segment."); return(null); } SegmentEndGeometry endGeo = segGeo.GetEnd(startNode); if (endGeo == null) { Log.Warning($"SegmentEndManager.GetOrAddSegmentEnd({segmentId}, {startNode}): Refusing to add segment end for invalid segment end."); return(null); } return(SegmentEnds[GetIndex(segmentId, startNode)] = new SegmentEnd(segmentId, startNode)); }
public override void OnMouseDrag(Event e) { SegmentEnd.RawSegmentBezier.Trajectory.GetHitPosition(Tool.Ray, out _, out var t, out _); SegmentEnd.Offset = SegmentEnd.RawSegmentBezier.Distance(0f, t).RoundToNearest(RoundTo); SegmentEnd.SetRotate(CachedRotate, true); SegmentEnd.UpdateNode(); Tool.Panel.RefreshPanel(); }
public override void OnMouseDrag(Event e) { var quaternion = Quaternion.FromToRotation(BeginDirection, CurrentDirection); var angle = (BeginRotate + quaternion.eulerAngles.y).RoundToNearest(RoundTo) % 360f; SegmentEnd.RotateAngle = angle > 180f ? angle - 360f : angle; SegmentEnd.UpdateNode(); Tool.Panel.RefreshPanel(); }
public static bool ShouldConnectTracks( ushort nodeId, int nodeInfoIDX, ref RenderManager.Instance data) { ushort sourceSegmentID = nodeId.ToNode().GetSegment(data.m_dataInt0 & 7); int targetSegmentIDX = data.m_dataInt0 >> 4; return(SegmentEnd.GetShouldConnectTracks( sourceSegmentID, targetSegmentIDX, nodeId, nodeInfoIDX)); }
public override void OnMouseDrag(Event e) { SegmentEnd[Corner].RawBezier.Trajectory.GetHitPosition(Tool.Ray, out _, out var t, out _); var offset = SegmentEnd[Corner].RawBezier.Distance(0f, t).RoundToNearest(RoundTo); if (Corner == SideType.Left) { SegmentEnd.LeftOffset = offset; } else { SegmentEnd.RightOffset = offset; } SegmentEnd.UpdateNode(); Tool.Panel.RefreshPanel(); }
public override void RenderOverlay(RenderManager.CameraInfo cameraInfo) { SegmentEnd.RenderSides(new OverlayData(cameraInfo), new OverlayData(cameraInfo) { Color = Colors.Red }); var defaultColor = new OverlayData(cameraInfo) { Color = SegmentEnd.OverlayColor }; var yellow = new OverlayData(cameraInfo) { Color = Colors.Yellow }; SegmentEnd.Render(defaultColor, yellow, defaultColor); }
public override void RenderOverlay(RenderManager.CameraInfo cameraInfo) { SegmentEnd[Corner].Render(new OverlayData(cameraInfo), new OverlayData(cameraInfo) { Color = Colors.Red }); SegmentEnd.RenderСontour(new OverlayData(cameraInfo) { Color = SegmentEnd.OverlayColor }); SegmentEnd.RenderEnd(new OverlayData(cameraInfo) { Color = SegmentEnd.OverlayColor }); SegmentEnd[Corner].RenderCircle(new OverlayData(cameraInfo) { Color = Colors.Yellow }); }
public ISegmentEnd GetOrAddSegmentEnd(ushort segmentId, bool startNode) { ISegmentEnd end = GetSegmentEnd(segmentId, startNode); if (end != null) { return(end); } if (!Services.NetService.IsSegmentValid(segmentId)) { Log.Warning( $"SegmentEndManager.GetOrAddSegmentEnd({segmentId}, {startNode}): Refusing to " + "add segment end for invalid segment."); return(null); } return(SegmentEnds[GetIndex(segmentId, startNode)] = new SegmentEnd(segmentId, startNode)); }
/// <summary> /// Swaps the starting point and the ending point /// </summary> private void SwapEnds() { double distTemp = StartDistance; StartDistance = EndDistance; EndDistance = distTemp; SegmentEnd typeTemp = StartType; StartType = EndType; EndType = typeTemp; Vertex vertexTemp = StartVertex; StartVertex = EndVertex; EndVertex = vertexTemp; Vector3 posTemp = StartPosition; StartPosition = EndPosition; EndPosition = posTemp; }
public override void RenderOverlay(RenderManager.CameraInfo cameraInfo) { SegmentEnd.RenderSides(new OverlayData(cameraInfo), new OverlayData(cameraInfo) { Color = Colors.Red }); SegmentEnd.SegmentBezier.Render(new OverlayData(cameraInfo) { Width = SegmentEndData.CenterDotRadius * 2 + 1 }); var defaultColor = new OverlayData(cameraInfo) { Color = SegmentEnd.OverlayColor }; var yellow = new OverlayData(cameraInfo) { Color = Colors.Yellow }; SegmentEnd.Render(defaultColor, defaultColor, yellow); }
internal Segment(Cell cellStartLeft, Cell cellStartRight, Cell direction, ISchemeParser parser, HouseSpot houseSpot) { HouseSpot = houseSpot; Number = houseSpot.Segments.Count + 1; CellStartLeft = cellStartLeft; CellStartRight = cellStartRight; Direction = direction; DirectionLeftToRight = direction.ToRight(); this.parser = parser; ModulesLeft = parser.GetSteps(cellStartLeft, direction, out CellEndLeft); ModulesRight = parser.GetSteps(cellStartRight, direction, out CellEndRight); // Кол шагов в секции CountSteps = ModulesLeft.Count > ModulesRight.Count ? ModulesLeft.Count : ModulesRight.Count; IsVertical = defineVertical(); StartLevel = GetMaxLevel(cellStartLeft, cellStartRight, direction); EndLevel = GetMaxLevel(CellEndLeft, CellEndRight, direction.Negative); // Определение вида торцов сегмента StartType = defineEndType(CellStartLeft, CellStartRight, direction.Negative, true); EndType = defineEndType(CellEndLeft, CellEndRight, direction, false); // Если старт секции угловой - отнимаем три лишних шага if (StartType == SegmentEnd.CornerLeft || StartType == SegmentEnd.CornerRight) { CountSteps -= (HouseSpot.WidthOrdinary - 1); } // боковая инсоляция ModulesSideStart = DefineSideModules(StartType, true); ModulesSideEnd = DefineSideModules(EndType, false); }
public void ShowGUI(bool viewOnly) { try { TrafficLightSimulationManager tlsMan = TrafficLightSimulationManager.Instance; TrafficPriorityManager prioMan = TrafficPriorityManager.Instance; TrafficLightManager tlm = TrafficLightManager.Instance; bool clicked = !viewOnly?MainTool.CheckClicked() : false; var hoveredSegment = false; //Log.Message("_guiPrioritySigns called. num of prio segments: " + TrafficPriority.PrioritySegments.Count); HashSet <ushort> nodeIdsWithSigns = new HashSet <ushort>(); foreach (ushort segmentId in currentPrioritySegmentIds) { var trafficSegment = prioMan.TrafficSegments[segmentId]; if (trafficSegment == null) { continue; } SegmentGeometry geometry = SegmentGeometry.Get(segmentId); prioritySegments[0] = null; prioritySegments[1] = null; if (tlsMan.GetNodeSimulation(trafficSegment.Node1) == null) { SegmentEnd tmpSeg1 = prioMan.GetPrioritySegment(trafficSegment.Node1, segmentId); bool startNode = geometry.StartNodeId() == trafficSegment.Node1; if (tmpSeg1 != null && !geometry.IsOutgoingOneWay(startNode)) { prioritySegments[0] = tmpSeg1; nodeIdsWithSigns.Add(trafficSegment.Node1); prioMan.AddPriorityNode(trafficSegment.Node1); } } if (tlsMan.GetNodeSimulation(trafficSegment.Node2) == null) { SegmentEnd tmpSeg2 = prioMan.GetPrioritySegment(trafficSegment.Node2, segmentId); bool startNode = geometry.StartNodeId() == trafficSegment.Node2; if (tmpSeg2 != null && !geometry.IsOutgoingOneWay(startNode)) { prioritySegments[1] = tmpSeg2; nodeIdsWithSigns.Add(trafficSegment.Node2); prioMan.AddPriorityNode(trafficSegment.Node2); } } //Log.Message("init ok"); foreach (var prioritySegment in prioritySegments) { if (prioritySegment == null) { continue; } var nodeId = prioritySegment.NodeId; //Log.Message("_guiPrioritySigns: nodeId=" + nodeId); var nodePositionVector3 = Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId].m_position; var camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position; var diff = nodePositionVector3 - camPos; if (diff.magnitude > TrafficManagerTool.PriorityCloseLod) { continue; // do not draw if too distant } if (Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startNode == (ushort)nodeId) { nodePositionVector3.x += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startDirection.x * 10f; nodePositionVector3.y += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startDirection.y * 10f; nodePositionVector3.z += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startDirection.z * 10f; } else { nodePositionVector3.x += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_endDirection.x * 10f; nodePositionVector3.y += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_endDirection.y * 10f; nodePositionVector3.z += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_endDirection.z * 10f; } var nodeScreenPosition = Camera.main.WorldToScreenPoint(nodePositionVector3); nodeScreenPosition.y = Screen.height - nodeScreenPosition.y; if (nodeScreenPosition.z < 0) { continue; } var zoom = 1.0f / diff.magnitude * 100f * MainTool.GetBaseZoom(); var size = 110f * zoom; var guiColor = GUI.color; var nodeBoundingBox = new Rect(nodeScreenPosition.x - size / 2, nodeScreenPosition.y - size / 2, size, size); hoveredSegment = !viewOnly && TrafficManagerTool.IsMouseOver(nodeBoundingBox); if (hoveredSegment) { // mouse hovering over sign guiColor.a = 0.8f; } else { guiColor.a = 0.5f; size = 90f * zoom; } var nodeDrawingBox = new Rect(nodeScreenPosition.x - size / 2, nodeScreenPosition.y - size / 2, size, size); GUI.color = guiColor; bool setUndefinedSignsToMainRoad = false; switch (prioritySegment.Type) { case SegmentEnd.PriorityType.Main: GUI.DrawTexture(nodeDrawingBox, TrafficLightToolTextureResources.SignPriorityTexture2D); if (clicked && hoveredSegment) { //Log._Debug("Click on node " + nodeId + ", segment " + segmentId + " to change prio type (1)"); //Log.Message("PrioritySegment.Type = Yield"); prioritySegment.Type = SegmentEnd.PriorityType.Yield; setUndefinedSignsToMainRoad = true; clicked = false; } break; case SegmentEnd.PriorityType.Yield: GUI.DrawTexture(nodeDrawingBox, TrafficLightToolTextureResources.SignYieldTexture2D); if (clicked && hoveredSegment) { //Log._Debug("Click on node " + nodeId + ", segment " + segmentId + " to change prio type (2)"); prioritySegment.Type = SegmentEnd.PriorityType.Stop; setUndefinedSignsToMainRoad = true; clicked = false; } break; case SegmentEnd.PriorityType.Stop: GUI.DrawTexture(nodeDrawingBox, TrafficLightToolTextureResources.SignStopTexture2D); if (clicked && hoveredSegment) { //Log._Debug("Click on node " + nodeId + ", segment " + segmentId + " to change prio type (3)"); prioritySegment.Type = SegmentEnd.PriorityType.Main; clicked = false; } break; case SegmentEnd.PriorityType.None: if (viewOnly) { break; } GUI.DrawTexture(nodeDrawingBox, TrafficLightToolTextureResources.SignNoneTexture2D); if (clicked && hoveredSegment) { //Log._Debug("Click on node " + nodeId + ", segment " + segmentId + " to change prio type (4)"); //Log.Message("PrioritySegment.Type = None"); prioritySegment.Type = GetNumberOfMainRoads(nodeId, ref Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId]) >= 2 ? SegmentEnd.PriorityType.Yield : SegmentEnd.PriorityType.Main; if (prioritySegment.Type == SegmentEnd.PriorityType.Yield) { setUndefinedSignsToMainRoad = true; } clicked = false; } break; } if (setUndefinedSignsToMainRoad) { foreach (var otherPrioritySegment in prioMan.GetPrioritySegments(nodeId)) { if (otherPrioritySegment.SegmentId == prioritySegment.SegmentId) { continue; } if (otherPrioritySegment.Type == SegmentEnd.PriorityType.None) { otherPrioritySegment.Type = SegmentEnd.PriorityType.Main; } } } } } if (viewOnly) { return; } ushort hoveredExistingNodeId = 0; foreach (ushort nodeId in nodeIdsWithSigns) { var nodePositionVector3 = Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId].m_position; var camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position; var diff = nodePositionVector3 - camPos; if (diff.magnitude > TrafficManagerTool.PriorityCloseLod) { continue; } // draw deletion button var nodeScreenPosition = Camera.main.WorldToScreenPoint(nodePositionVector3); nodeScreenPosition.y = Screen.height - nodeScreenPosition.y; if (nodeScreenPosition.z < 0) { continue; } var zoom = 1.0f / diff.magnitude * 100f * MainTool.GetBaseZoom(); var size = 90f * zoom; var nodeBoundingBox = new Rect(nodeScreenPosition.x - size / 2, nodeScreenPosition.y - size / 2, size, size); var guiColor = GUI.color; var nodeCenterHovered = TrafficManagerTool.IsMouseOver(nodeBoundingBox); if (nodeCenterHovered) { hoveredExistingNodeId = nodeId; guiColor.a = 0.8f; } else { guiColor.a = 0.5f; } GUI.color = guiColor; GUI.DrawTexture(nodeBoundingBox, TrafficLightToolTextureResources.SignRemoveTexture2D); } // add a new or delete a priority segment node if (HoveredNodeId != 0 || hoveredExistingNodeId != 0) { bool delete = false; if (hoveredExistingNodeId != 0) { delete = true; } // determine if we may add new priority signs to this node bool ok = false; TrafficLightSimulation nodeSim = tlsMan.GetNodeSimulation(HoveredNodeId); if ((Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_flags & NetNode.Flags.TrafficLights) == NetNode.Flags.None) { // no traffic light set ok = true; } else if (nodeSim == null || !nodeSim.IsTimedLight()) { ok = true; } if (!Flags.mayHaveTrafficLight(HoveredNodeId)) { ok = false; } if (clicked) { Log._Debug("_guiPrioritySigns: hovered+clicked @ nodeId=" + HoveredNodeId + "/" + hoveredExistingNodeId + " ok=" + ok); if (delete) { prioMan.RemovePrioritySegments(hoveredExistingNodeId); RefreshCurrentPrioritySegmentIds(); } else if (ok) { //if (!prioMan.IsPriorityNode(HoveredNodeId)) { Log._Debug("_guiPrioritySigns: adding prio segments @ nodeId=" + HoveredNodeId); tlsMan.RemoveNodeFromSimulation(HoveredNodeId, false, true); tlm.RemoveTrafficLight(HoveredNodeId); prioMan.AddPriorityNode(HoveredNodeId); RefreshCurrentPrioritySegmentIds(); //} } else if (nodeSim != null && nodeSim.IsTimedLight()) { MainTool.ShowTooltip(Translation.GetString("NODE_IS_TIMED_LIGHT"), Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_position); } } } } catch (Exception e) { Log.Error(e.ToString()); } }
/// <summary> /// Displays segment ids over segments /// </summary> private void _guiSegments() { GUIStyle _counterStyle = new GUIStyle(); Array16 <NetSegment> segments = Singleton <NetManager> .instance.m_segments; for (int i = 1; i < segments.m_size; ++i) { if (segments.m_buffer[i].m_flags == NetSegment.Flags.None) // segment is unused { continue; } #if !DEBUG if ((segments.m_buffer[i].m_flags & NetSegment.Flags.Untouchable) != NetSegment.Flags.None) { continue; } #endif var segmentInfo = segments.m_buffer[i].Info; Vector3 centerPos = segments.m_buffer[i].m_bounds.center; var screenPos = Camera.main.WorldToScreenPoint(centerPos); screenPos.y = Screen.height - screenPos.y; if (screenPos.z < 0) { continue; } var camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position; var diff = centerPos - camPos; if (diff.magnitude > DebugCloseLod) { continue; // do not draw if too distant } if (Options.nodesOverlay) { var zoom = 1.0f / diff.magnitude * 150f; _counterStyle.fontSize = (int)(12f * zoom); _counterStyle.normal.textColor = new Color(1f, 0f, 0f); String labelStr = "Segment " + i; #if DEBUGx labelStr += ", flags: " + segments.m_buffer[i].m_flags.ToString() + ", condition: " + segments.m_buffer[i].m_condition; #endif #if DEBUG SegmentEnd startEnd = TrafficPriority.GetPrioritySegment(segments.m_buffer[i].m_startNode, (ushort)i); SegmentEnd endEnd = TrafficPriority.GetPrioritySegment(segments.m_buffer[i].m_endNode, (ushort)i); labelStr += "\nstart? " + (startEnd != null) + " veh.: " + startEnd?.GetRegisteredVehicleCount() + ", end? " + (endEnd != null) + " veh.: " + endEnd?.GetRegisteredVehicleCount(); #endif labelStr += "\nTraffic: " + segments.m_buffer[i].m_trafficDensity + " %"; #if MARKCONGESTEDSEGMENTS if (CustomRoadAI.initDone && CustomRoadAI.segmentCongestion[i]) { labelStr += " congested!"; } #endif float meanLaneSpeed = 0f; int lIndex = 0; uint laneId = segments.m_buffer[i].m_lanes; int validLanes = 0; while (lIndex < segmentInfo.m_lanes.Length && laneId != 0u) { NetInfo.Lane lane = segmentInfo.m_lanes[lIndex]; if (lane.CheckType(NetInfo.LaneType.Vehicle | NetInfo.LaneType.TransportVehicle, VehicleInfo.VehicleType.Car)) { if (CustomRoadAI.laneMeanSpeeds[i] != null && lIndex < CustomRoadAI.laneMeanSpeeds[i].Length) { if (CustomRoadAI.laneMeanSpeeds[i][lIndex] >= 0) { meanLaneSpeed += (float)CustomRoadAI.laneMeanSpeeds[i][lIndex]; ++validLanes; } } } lIndex++; laneId = Singleton <NetManager> .instance.m_lanes.m_buffer[laneId].m_nextLane; } if (validLanes > 0) { meanLaneSpeed /= Convert.ToSingle(validLanes); } /*if (CustomRoadAI.InStartupPhase) * labelStr += " (in start-up phase)"; * else*/ labelStr += " (avg. speed: " + String.Format("{0:0.##}", meanLaneSpeed) + " %)"; #if DEBUG labelStr += "\nstart: " + segments.m_buffer[i].m_startNode + ", end: " + segments.m_buffer[i].m_endNode; #endif Vector2 dim = _counterStyle.CalcSize(new GUIContent(labelStr)); Rect labelRect = new Rect(screenPos.x - dim.x / 2f, screenPos.y, dim.x, dim.y); GUI.Label(labelRect, labelStr, _counterStyle); if (Options.showLanes) { _guiLanes((ushort)i, ref segments.m_buffer[i], ref segmentInfo); } } } }
internal void Recalculate() { #if DEBUGGEO Log._Debug($"NodeGeometry: Recalculate @ {NodeId}"); #endif Cleanup(); Flags.applyNodeTrafficLightFlag(NodeId); TrafficLightSimulationManager tlsMan = TrafficLightSimulationManager.Instance(); // check if node is valid if (!IsValid()) { for (int i = 0; i < 8; ++i) { SegmentEndGeometries[i] = null; } tlsMan.RemoveNodeFromSimulation(NodeId, false, true); Flags.setNodeTrafficLight(NodeId, false); } else { NetManager netManager = Singleton <NetManager> .instance; TrafficPriorityManager prioMan = TrafficPriorityManager.Instance(); bool hasTrafficLight = (netManager.m_nodes.m_buffer[NodeId].m_flags & NetNode.Flags.TrafficLights) != NetNode.Flags.None; var nodeSim = tlsMan.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 = prioMan.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 += prioMan.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(); }
/// <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); }
/// <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); }
/// <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(bool onlyMoving, int stepRefIndex, out float wait, out float flow) { uint numFlows = 0; uint numWaits = 0; uint curMeanFlow = 0; uint curMeanWait = 0; // TODO checking agains getCurrentFrame() is only valid if this is the current step if (onlyMoving && getCurrentFrame() <= startFrame + minTime + 1) // during start phase all vehicles on "green" segments are counted as flowing { onlyMoving = false; } TrafficLightSimulationManager tlsMan = TrafficLightSimulationManager.Instance; TrafficPriorityManager prioMan = TrafficPriorityManager.Instance; foreach (ushort timedNodeId in timedNode.NodeGroup) { TrafficLightSimulation sim = tlsMan.GetNodeSimulation(timedNodeId); if (sim == null || !sim.IsTimedLight()) { continue; } TimedTrafficLights slaveTimedNode = sim.TimedLight; TimedTrafficLightsStep slaveStep = slaveTimedNode.Steps[stepRefIndex]; //List<int> segmentIdsToDelete = new List<int>(); // minimum time reached. check traffic! foreach (KeyValuePair <ushort, CustomSegmentLights> e in slaveStep.segmentLights) { var sourceSegmentId = e.Key; var segLights = e.Value; #if DEBUGMETRIC bool debug = sourceSegmentId == 20857 && GlobalConfig.Instance.DebugSwitches[1]; #elif DEBUG bool debug = GlobalConfig.Instance.DebugSwitches[7] && GlobalConfig.Instance.TTLDebugNodeId == timedNodeId; #else bool debug = false; #endif Dictionary <ushort, ArrowDirection> directions = null; if (slaveStep.timedNode.Directions.ContainsKey(sourceSegmentId)) { directions = slaveStep.timedNode.Directions[sourceSegmentId]; } else { #if DEBUG if (debug) { Log._Debug($"calcWaitFlow: No arrow directions defined for segment {sourceSegmentId} @ {timedNodeId}"); } #endif continue; } // one of the traffic lights at this segment is green: count minimum traffic flowing through SegmentEnd sourceSegmentEnd = prioMan.GetPrioritySegment(timedNodeId, sourceSegmentId); if (sourceSegmentEnd == null) { Log.Warning($"TimedTrafficLightsStep.calcWaitFlow: No priority segment @ seg. {sourceSegmentId} found!"); continue; // skip invalid segment } ExtVehicleType validVehicleTypes = VehicleRestrictionsManager.Instance.GetAllowedVehicleTypes(sourceSegmentId, 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. {sourceSegmentId}, node {timedNode.NodeId}!"); continue; } #if DEBUG if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Checking lane {laneIndex} @ seg. {sourceSegmentId}. Vehicle types: {vehicleType}"); } #endif Dictionary <ushort, uint> carsFlowingToSegmentMetric = null; Dictionary <ushort, uint> allCarsToSegmentMetric = null; bool evalFlowingVehicles = segLight.IsAnyGreen(); // flowing vehicle need only to be evaluated if a light is green if (evalFlowingVehicles && onlyMoving) { carsFlowingToSegmentMetric = sourceSegmentEnd.GetVehicleMetricGoingToSegment(false, laneIndex, debug); } allCarsToSegmentMetric = sourceSegmentEnd.GetVehicleMetricGoingToSegment(true, laneIndex, debug); // calculate waiting/flowing traffic foreach (KeyValuePair <ushort, uint> f in allCarsToSegmentMetric) { ushort targetSegmentId = f.Key; uint totalNumCars = f.Value; if (!directions.ContainsKey(targetSegmentId)) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Direction undefined for target segment {targetSegmentId} @ {timedNodeId}"); continue; } if (evalFlowingVehicles) { uint totalNumFlowingCars = onlyMoving ? carsFlowingToSegmentMetric[f.Key] : totalNumCars; #if DEBUG if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Total num of flowing cars on seg. {sourceSegmentId}, lane {laneIndex} going to seg. {targetSegmentId}: {totalNumFlowingCars}"); } #endif bool addToFlow = false; switch (directions[targetSegmentId]) { case ArrowDirection.Turn: addToFlow = TrafficPriorityManager.IsLeftHandDrive() ? segLight.IsRightGreen() : segLight.IsLeftGreen(); break; case ArrowDirection.Left: addToFlow = segLight.IsLeftGreen(); break; case ArrowDirection.Right: addToFlow = segLight.IsRightGreen(); break; case ArrowDirection.Forward: default: addToFlow = segLight.IsMainGreen(); break; } if (addToFlow) { curMeanFlow += totalNumFlowingCars; ++numFlows; } else { curMeanWait += totalNumCars; ++numWaits; } } else { curMeanWait += totalNumCars; ++numWaits; } #if DEBUG if (debug) { Log._Debug($"TimedTrafficLightsStep.calcWaitFlow: Vehicles on lane {laneIndex} on seg. {sourceSegmentId} going to seg. {targetSegmentId} curMeanFlow={curMeanFlow}, curMeanWait={curMeanWait}, numFlows={numFlows}, numWaits={numWaits}"); } #endif } } } } /*if (numFlows > 0) * curMeanFlow /= numFlows; * if (numWaits > 0) * curMeanWait /= numWaits;*/ float fCurMeanFlow = numFlows > 0 ? (float)curMeanFlow / (float)numFlows : 0; float fCurMeanWait = numWaits > 0 ? (float)curMeanWait / (float)numWaits : 0; fCurMeanFlow /= waitFlowBalance; // a value smaller than 1 rewards steady traffic currents wait = (float)fCurMeanWait; flow = fCurMeanFlow; return(true); }