private void ToggleMode(ref ExtSegmentEnd segEnd, ref NetNode node) { IExtSegmentManager extSegMan = Constants.ManagerFactory.ExtSegmentManager; IExtSegmentEndManager extSegEndMan = Constants.ManagerFactory.ExtSegmentEndManager; bool startNode = lights.StartNode; bool hasLeftSegment; bool hasForwardSegment; bool hasRightSegment; extSegEndMan.CalculateOutgoingLeftStraightRightSegments(ref segEnd, ref node, out hasLeftSegment, out hasForwardSegment, out hasRightSegment); #if DEBUG Log._Debug($"ChangeMode. segment {SegmentId} @ node {NodeId}, hasLeftSegment={hasLeftSegment}, hasForwardSegment={hasForwardSegment}, hasRightSegment={hasRightSegment}"); #endif LightMode newMode = LightMode.Simple; if (CurrentMode == LightMode.Simple) { if (!hasLeftSegment) { newMode = LightMode.SingleRight; } else { newMode = LightMode.SingleLeft; } } else if (CurrentMode == LightMode.SingleLeft) { if (!hasForwardSegment || !hasRightSegment) { newMode = LightMode.Simple; } else { newMode = LightMode.SingleRight; } } else if (CurrentMode == LightMode.SingleRight) { if (!hasLeftSegment) { newMode = LightMode.Simple; } else { newMode = LightMode.All; } } else { newMode = LightMode.Simple; } CurrentMode = newMode; }
/// <summary> /// Are all segments at nodeId highways? /// </summary> /// <param name="nodeId"></param> /// <returns></returns> public static bool JunctionHasOnlyHighwayRoads(ushort nodeId) { IExtSegmentManager segMan = Constants.ManagerFactory.ExtSegmentManager; bool ret = true; Constants.ServiceFactory.NetService.IterateNodeSegments( nodeId, (ushort segmentId, ref NetSegment segment) => { ret &= segMan.CalculateIsHighway(segmentId); return(ret); }); return(ret); }
protected void UpdateSegmentEnd(ref ExtSegment seg, ref ExtSegmentEnd end) { #if DEBUG bool logTurnOnRed = DebugSwitch.TurnOnRed.Get(); #else const bool logTurnOnRed = false; #endif if (logTurnOnRed) { Log._Debug($"TurnOnRedManager.UpdateSegmentEnd({end.segmentId}, {end.startNode}) called."); } IExtSegmentManager segmentManager = Constants.ManagerFactory.ExtSegmentManager; IExtSegmentEndManager segmentEndManager = Constants.ManagerFactory.ExtSegmentEndManager; ushort segmentId = seg.segmentId; ushort nodeId = end.nodeId; bool hasOutgoingSegment = false; Services.NetService.IterateNodeSegments( end.nodeId, (ushort otherSegId, ref NetSegment otherSeg) => { int index0 = segmentEndManager.GetIndex(otherSegId, otherSeg.m_startNode == nodeId); if (otherSegId != segmentId && segmentEndManager.ExtSegmentEnds[index0].outgoing) { hasOutgoingSegment = true; return(false); } return(true); }); // check if traffic can flow to the node and that there is at least one left segment if (!end.incoming || !hasOutgoingSegment) { if (logTurnOnRed) { Log._Debug($"TurnOnRedManager.UpdateSegmentEnd({end.segmentId}, {end.startNode}): " + "outgoing one-way or insufficient number of outgoing segments."); } return; } bool lht = Services.SimulationService.TrafficDrivesOnLeft; // check node // note that we must not check for the `TrafficLights` flag here because the flag might not be loaded yet ref NetNode node = ref nodeId.ToNode();
protected void UpdateSegmentEnd(ref ExtSegment seg, ref ExtSegmentEnd end) { #if DEBUG bool logTurnOnRed = DebugSwitch.TurnOnRed.Get(); #else const bool logTurnOnRed = false; #endif if (logTurnOnRed) { Log._Debug($"TurnOnRedManager.UpdateSegmentEnd({end.segmentId}, {end.startNode}) called."); } IExtSegmentManager segmentManager = Constants.ManagerFactory.ExtSegmentManager; IExtSegmentEndManager segmentEndManager = Constants.ManagerFactory.ExtSegmentEndManager; ushort segmentId = seg.segmentId; ushort nodeId = end.nodeId; bool hasOutgoingSegment = false; ref NetNode endNode = ref end.nodeId.ToNode();
public void ShowGUI(bool viewOnly) { try { IExtSegmentManager segMan = Constants.ManagerFactory.ExtSegmentManager; IExtSegmentEndManager segEndMan = Constants.ManagerFactory.ExtSegmentEndManager; TrafficLightSimulationManager tlsMan = TrafficLightSimulationManager.Instance; TrafficPriorityManager prioMan = TrafficPriorityManager.Instance; TrafficLightManager tlm = TrafficLightManager.Instance; Vector3 camPos = Constants.ServiceFactory.SimulationService.CameraPosition; bool clicked = !viewOnly?MainTool.CheckClicked() : false; ushort removedNodeId = 0; bool showRemoveButton = false; foreach (ushort nodeId in currentPriorityNodeIds) { if (!Constants.ServiceFactory.NetService.IsNodeValid(nodeId)) { continue; } if (!MainTool.IsNodeWithinViewDistance(nodeId)) { continue; } Vector3 nodePos = default(Vector3); Constants.ServiceFactory.NetService.ProcessNode(nodeId, delegate(ushort nId, ref NetNode node) { nodePos = node.m_position; return(true); }); for (int i = 0; i < 8; ++i) { ushort segmentId = 0; Constants.ServiceFactory.NetService.ProcessNode(nodeId, delegate(ushort nId, ref NetNode node) { segmentId = node.GetSegment(i); return(true); }); if (segmentId == 0) { continue; } bool startNode = (bool)Constants.ServiceFactory.NetService.IsStartNode(segmentId, nodeId); ExtSegment seg = segMan.ExtSegments[segmentId]; ExtSegmentEnd segEnd = segEndMan.ExtSegmentEnds[segEndMan.GetIndex(segmentId, startNode)]; if (seg.oneWay && segEnd.outgoing) { continue; } // calculate sign position Vector3 signPos = nodePos; Constants.ServiceFactory.NetService.ProcessSegment(segmentId, delegate(ushort sId, ref NetSegment segment) { signPos += 10f * (startNode ? segment.m_startDirection : segment.m_endDirection); return(true); }); Vector3 signScreenPos; if (!MainTool.WorldToScreenPoint(signPos, out signScreenPos)) { continue; } // draw sign and handle input PriorityType sign = prioMan.GetPrioritySign(segmentId, startNode); if (viewOnly && sign == PriorityType.None) { continue; } if (!viewOnly && sign != PriorityType.None) { showRemoveButton = true; } if (MainTool.DrawGenericSquareOverlayTexture(TextureResources.PrioritySignTextures[sign], camPos, signPos, 90f, !viewOnly) && clicked) { PriorityType?newSign = null; switch (sign) { case PriorityType.Main: newSign = PriorityType.Yield; break; case PriorityType.Yield: newSign = PriorityType.Stop; break; case PriorityType.Stop: newSign = PriorityType.Main; break; case PriorityType.None: default: newSign = prioMan.CountPrioritySignsAtNode(nodeId, PriorityType.Main) >= 2 ? PriorityType.Yield : PriorityType.Main; break; } if (newSign != null) { SetPrioritySign(segmentId, startNode, (PriorityType)newSign); } } // draw sign } // foreach segment end if (viewOnly) { continue; } // draw remove button and handle click if (showRemoveButton && MainTool.DrawHoverableSquareOverlayTexture(TextureResources.SignRemoveTexture2D, camPos, nodePos, 90f) && clicked) { prioMan.RemovePrioritySignsFromNode(nodeId); Log._Debug($"PrioritySignsTool.ShowGUI: Removed priority signs from node {nodeId}"); removedNodeId = nodeId; } } // foreach node if (removedNodeId != 0) { currentPriorityNodeIds.Remove(removedNodeId); SelectedNodeId = 0; } } catch (Exception e) { Log.Error(e.ToString()); } }
public override void OnToolGUI(Event e) { IExtSegmentManager segMan = Constants.ManagerFactory.ExtSegmentManager; IExtSegmentEndManager segEndMan = Constants.ManagerFactory.ExtSegmentEndManager; var hoveredSegment = false; if (SelectedNodeId != 0) { CustomSegmentLightsManager customTrafficLightsManager = CustomSegmentLightsManager.Instance; TrafficLightSimulationManager tlsMan = TrafficLightSimulationManager.Instance; JunctionRestrictionsManager junctionRestrictionsManager = JunctionRestrictionsManager.Instance; if (!tlsMan.HasManualSimulation(SelectedNodeId)) { return; } tlsMan.TrafficLightSimulations[SelectedNodeId].Housekeeping(); // TODO check // if (Singleton<NetManager>.instance.m_nodes.m_buffer[SelectedNode].CountSegments() == 2) { // _guiManualTrafficLightsCrosswalk( // ref Singleton<NetManager>.instance.m_nodes.m_buffer[SelectedNode]); // return; // } NetNode[] nodesBuffer = Singleton <NetManager> .instance.m_nodes.m_buffer; NetSegment[] segmentsBuffer = Singleton <NetManager> .instance.m_segments.m_buffer; for (int i = 0; i < 8; ++i) { ushort segmentId = nodesBuffer[SelectedNodeId].GetSegment(i); if (segmentId == 0) { continue; } bool startNode = (bool)Constants.ServiceFactory.NetService.IsStartNode( segmentId, SelectedNodeId); Vector3 position = CalculateNodePositionForSegment( nodesBuffer[SelectedNodeId], ref segmentsBuffer[segmentId]); ICustomSegmentLights segmentLights = customTrafficLightsManager.GetSegmentLights(segmentId, startNode, false); if (segmentLights == null) { continue; } bool showPedLight = segmentLights.PedestrianLightState != null && junctionRestrictionsManager.IsPedestrianCrossingAllowed( segmentLights.SegmentId, segmentLights.StartNode); bool visible = MainTool.WorldToScreenPoint(position, out Vector3 screenPos); if (!visible) { continue; } Vector3 diff = position - Camera.main.transform.position; float zoom = 1.0f / diff.magnitude * 100f; // original / 2.5 float lightWidth = 41f * zoom; float lightHeight = 97f * zoom; float pedestrianWidth = 36f * zoom; float pedestrianHeight = 61f * zoom; // SWITCH MODE BUTTON float modeWidth = 41f * zoom; float modeHeight = 38f * zoom; Color guiColor = GUI.color; if (showPedLight) { // pedestrian light // SWITCH MANUAL PEDESTRIAN LIGHT BUTTON hoveredSegment = RenderManualPedestrianLightSwitch( zoom, segmentId, screenPos, lightWidth, segmentLights, hoveredSegment); // SWITCH PEDESTRIAN LIGHT guiColor.a = TrafficManagerTool.GetHandleAlpha( hoveredButton[0] == segmentId && hoveredButton[1] == 2 && segmentLights.ManualPedestrianMode); GUI.color = guiColor; var myRect3 = new Rect( screenPos.x - pedestrianWidth / 2 - lightWidth + 5f * zoom, screenPos.y - pedestrianHeight / 2 + 22f * zoom, pedestrianWidth, pedestrianHeight); switch (segmentLights.PedestrianLightState) { case RoadBaseAI.TrafficLightState.Green: { GUI.DrawTexture( myRect3, TrafficLightTextures.PedestrianGreenLight); break; } // also: case RoadBaseAI.TrafficLightState.Red: default: { GUI.DrawTexture( myRect3, TrafficLightTextures.PedestrianRedLight); break; } } hoveredSegment = IsPedestrianLightHovered( myRect3, segmentId, hoveredSegment, segmentLights); } int lightOffset = -1; foreach (ExtVehicleType vehicleType in segmentLights.VehicleTypes) { ++lightOffset; ICustomSegmentLight segmentLight = segmentLights.GetCustomLight(vehicleType); Vector3 offsetScreenPos = screenPos; offsetScreenPos.y -= (lightHeight + 10f * zoom) * lightOffset; SetAlpha(segmentId, -1); var myRect1 = new Rect( offsetScreenPos.x - modeWidth / 2, offsetScreenPos.y - modeHeight / 2 + modeHeight - 7f * zoom, modeWidth, modeHeight); GUI.DrawTexture(myRect1, TrafficLightTextures.LightMode); hoveredSegment = GetHoveredSegment( myRect1, segmentId, hoveredSegment, segmentLight); // COUNTER hoveredSegment = RenderCounter( segmentId, offsetScreenPos, modeWidth, modeHeight, zoom, segmentLights, hoveredSegment); if (vehicleType != ExtVehicleType.None) { // Info sign float infoWidth = 56.125f * zoom; float infoHeight = 51.375f * zoom; int numInfos = 0; for (int k = 0; k < TrafficManagerTool.InfoSignsToDisplay.Length; ++k) { if ((TrafficManagerTool.InfoSignsToDisplay[k] & vehicleType) == ExtVehicleType.None) { continue; } var infoRect = new Rect( offsetScreenPos.x + modeWidth / 2f + (7f * zoom * (float)(numInfos + 1)) + (infoWidth * (float)numInfos), offsetScreenPos.y - (infoHeight / 2f), infoWidth, infoHeight); guiColor.a = TrafficManagerTool.GetHandleAlpha(false); GUI.DrawTexture( infoRect, RoadUITextures.VehicleInfoSignTextures[TrafficManagerTool.InfoSignsToDisplay[k]]); ++numInfos; } } ExtSegment seg = segMan.ExtSegments[segmentId]; ExtSegmentEnd segEnd = segEndMan.ExtSegmentEnds[segEndMan.GetIndex(segmentId, startNode)]; if (seg.oneWay && segEnd.outgoing) { continue; } segEndMan.CalculateOutgoingLeftStraightRightSegments( ref segEnd, ref nodesBuffer[segmentId], out bool hasLeftSegment, out bool hasForwardSegment, out bool hasRightSegment); switch (segmentLight.CurrentMode) { case LightMode.Simple: { hoveredSegment = SimpleManualSegmentLightMode( segmentId, offsetScreenPos, lightWidth, pedestrianWidth, zoom, lightHeight, segmentLight, hoveredSegment); break; } case LightMode.SingleLeft: { hoveredSegment = LeftForwardRManualSegmentLightMode( hasLeftSegment, segmentId, offsetScreenPos, lightWidth, pedestrianWidth, zoom, lightHeight, segmentLight, hoveredSegment, hasForwardSegment, hasRightSegment); break; } case LightMode.SingleRight: { hoveredSegment = RightForwardLSegmentLightMode( segmentId, offsetScreenPos, lightWidth, pedestrianWidth, zoom, lightHeight, hasForwardSegment, hasLeftSegment, segmentLight, hasRightSegment, hoveredSegment); break; } default: { // left arrow light if (hasLeftSegment) { hoveredSegment = LeftArrowLightMode( segmentId, lightWidth, hasRightSegment, hasForwardSegment, offsetScreenPos, pedestrianWidth, zoom, lightHeight, segmentLight, hoveredSegment); } // forward arrow light if (hasForwardSegment) { hoveredSegment = ForwardArrowLightMode( segmentId, lightWidth, hasRightSegment, offsetScreenPos, pedestrianWidth, zoom, lightHeight, segmentLight, hoveredSegment); } // right arrow light if (hasRightSegment) { hoveredSegment = RightArrowLightMode( segmentId, offsetScreenPos, lightWidth, pedestrianWidth, zoom, lightHeight, segmentLight, hoveredSegment); } break; } } // end switch } // end foreach all vehicle type } // end for all 8 segments } // end if a node is selected if (hoveredSegment) { return; } hoveredButton[0] = 0; hoveredButton[1] = 0; }
private static void TraverseRec(ref ExtSegment prevSeg, ref ExtSegmentEnd prevSegEnd, ref NetNode node, bool viaInitialStartNode, TraverseDirection direction, TraverseSide side, SegmentStopCriterion stopCrit, SegmentVisitor visitorFun, HashSet <ushort> visitedSegmentIds) { // Log._Debug($"SegmentTraverser: Traversing segment {prevSegEnd.segmentId}"); // collect next segment ids to traverse if (direction == TraverseDirection.None) { throw new ArgumentException($"Invalid direction {direction} given."); } if (side == TraverseSide.None) { throw new ArgumentException($"Invalid side {side} given."); } IExtSegmentManager extSegMan = Constants.ManagerFactory.ExtSegmentManager; IExtSegmentEndManager extSegEndMan = Constants.ManagerFactory.ExtSegmentEndManager; HashSet <ushort> nextSegmentIds = new HashSet <ushort>(); for (int i = 0; i < 8; ++i) { ushort nextSegmentId = node.GetSegment(i); if (nextSegmentId == 0 || nextSegmentId == prevSegEnd.segmentId) { continue; } bool nextIsStartNode = (bool)Constants.ServiceFactory.NetService.IsStartNode( nextSegmentId, prevSegEnd.nodeId); ExtSegmentEnd nextSegEnd = extSegEndMan.ExtSegmentEnds[extSegEndMan.GetIndex(nextSegmentId, nextIsStartNode)]; if (direction == TraverseDirection.AnyDirection || (direction == TraverseDirection.Incoming && nextSegEnd.incoming) || (direction == TraverseDirection.Outgoing && nextSegEnd.outgoing)) { if (side == TraverseSide.AnySide) { nextSegmentIds.Add(nextSegmentId); } else { ArrowDirection dir = extSegEndMan.GetDirection( ref prevSegEnd, nextSegmentId); if (((side & TraverseSide.Left) != TraverseSide.None && dir == ArrowDirection.Left) || ((side & TraverseSide.Straight) != TraverseSide.None && dir == ArrowDirection.Forward) || ((side & TraverseSide.Right) != TraverseSide.None && dir == ArrowDirection.Right)) { nextSegmentIds.Add(nextSegmentId); } } } } nextSegmentIds.Remove(0); // Log._Debug($"SegmentTraverser: Fetched next segments to traverse: // {nextSegmentIds.CollectionToString()}"); if (nextSegmentIds.Count >= 2 && (stopCrit & SegmentStopCriterion.Junction) != SegmentStopCriterion.None) { // Log._Debug($"SegmentTraverser: Stop criterion reached @ {prevSegEnd.segmentId}: // {nextSegmentIds.Count} connected segments"); return; } // explore next segments foreach (ushort nextSegmentId in nextSegmentIds) { if (visitedSegmentIds.Contains(nextSegmentId)) { continue; } visitedSegmentIds.Add(nextSegmentId); // Log._Debug($"SegmentTraverser: Traversing segment {nextSegmentId}"); ushort nextStartNodeId = Constants.ServiceFactory.NetService.GetSegmentNodeId(nextSegmentId, true); if (!visitorFun( new SegmentVisitData( ref prevSeg, ref extSegMan.ExtSegments[nextSegmentId], viaInitialStartNode, prevSegEnd.nodeId == nextStartNodeId, false))) { continue; } bool nextNodeIsStartNode = nextStartNodeId != prevSegEnd.nodeId; ExtSegmentEnd nextSegEnd = extSegEndMan.ExtSegmentEnds[extSegEndMan.GetIndex(nextSegmentId, nextNodeIsStartNode)]; Constants.ServiceFactory.NetService.ProcessNode( nextSegEnd.nodeId, (ushort nId, ref NetNode nextNode) => { TraverseRec( ref extSegMan.ExtSegments[nextSegmentId], ref nextSegEnd, ref nextNode, viaInitialStartNode, direction, side, stopCrit, visitorFun, visitedSegmentIds); return(true); }); } // end foreach }
protected void UpdateSegmentEnd(ref ExtSegment seg, ref ExtSegmentEnd end) { #if DEBUG bool logTurnOnRed = DebugSwitch.TurnOnRed.Get(); #else const bool logTurnOnRed = false; #endif if (logTurnOnRed) { Log._Debug($"TurnOnRedManager.UpdateSegmentEnd({end.segmentId}, {end.startNode}) called."); } IExtSegmentManager segmentManager = Constants.ManagerFactory.ExtSegmentManager; IExtSegmentEndManager segmentEndManager = Constants.ManagerFactory.ExtSegmentEndManager; ushort segmentId = seg.segmentId; ushort nodeId = end.nodeId; bool hasOutgoingSegment = false; Services.NetService.IterateNodeSegments( end.nodeId, (ushort otherSegId, ref NetSegment otherSeg) => { int index0 = segmentEndManager.GetIndex(otherSegId, otherSeg.m_startNode == nodeId); if (otherSegId != segmentId && segmentEndManager.ExtSegmentEnds[index0].outgoing) { hasOutgoingSegment = true; return(false); } return(true); }); // check if traffic can flow to the node and that there is at least one left segment if (!end.incoming || !hasOutgoingSegment) { if (logTurnOnRed) { Log._Debug($"TurnOnRedManager.UpdateSegmentEnd({end.segmentId}, {end.startNode}): " + "outgoing one-way or insufficient number of outgoing segments."); } return; } bool lhd = Services.SimulationService.LeftHandDrive; // check node // note that we must not check for the `TrafficLights` flag here because the flag might not be loaded yet bool nodeValid = false; Services.NetService.ProcessNode( nodeId, (ushort _, ref NetNode node) => { nodeValid = (node.m_flags & NetNode.Flags.LevelCrossing) == NetNode.Flags.None && node.Info?.m_class?.m_service != ItemClass.Service.Beautification; return(true); }); if (!nodeValid) { if (logTurnOnRed) { Log._Debug($"TurnOnRedManager.UpdateSegmentEnd({end.segmentId}, {end.startNode}): node invalid"); } return; } // get left/right segments ushort leftSegmentId = 0; ushort rightSegmentId = 0; Services.NetService.ProcessSegment( end.segmentId, (ushort _, ref NetSegment segment) => { segment.GetLeftAndRightSegments( nodeId, out leftSegmentId, out rightSegmentId); return(true); }); if (logTurnOnRed) { Log._Debug( $"TurnOnRedManager.UpdateSegmentEnd({end.segmentId}, {end.startNode}): " + $"got left/right segments: {leftSegmentId}/{rightSegmentId}"); } // validate left/right segments according to geometric properties if (leftSegmentId != 0 && segmentEndManager.GetDirection(ref end, leftSegmentId) != ArrowDirection.Left) { if (logTurnOnRed) { Log._Debug( $"TurnOnRedManager.UpdateSegmentEnd({end.segmentId}, {end.startNode}): " + "left segment is not geometrically left"); } leftSegmentId = 0; } if (rightSegmentId != 0 && segmentEndManager.GetDirection(ref end, rightSegmentId) != ArrowDirection.Right) { if (logTurnOnRed) { Log._Debug($"TurnOnRedManager.UpdateSegmentEnd({end.segmentId}, {end.startNode}): " + "right segment is not geometrically right"); } rightSegmentId = 0; } // check for incoming one-ways if (leftSegmentId != 0 && !segmentEndManager.ExtSegmentEnds[segmentEndManager.GetIndex(leftSegmentId, nodeId)].outgoing) { if (logTurnOnRed) { Log._Debug($"TurnOnRedManager.UpdateSegmentEnd({end.segmentId}, {end.startNode}): " + "left segment is incoming one-way"); } leftSegmentId = 0; } if (rightSegmentId != 0 && !segmentEndManager.ExtSegmentEnds[segmentEndManager.GetIndex(rightSegmentId, nodeId)].outgoing) { if (logTurnOnRed) { Log._Debug($"TurnOnRedManager.UpdateSegmentEnd({end.segmentId}, {end.startNode}): " + "right segment is incoming one-way"); } rightSegmentId = 0; } if (seg.oneWay) { if ((lhd && rightSegmentId != 0) || (!lhd && leftSegmentId != 0)) { // special case: one-way to one-way in non-preferred direction if (logTurnOnRed) { Log._Debug( $"TurnOnRedManager.UpdateSegmentEnd({end.segmentId}, {end.startNode}): " + "source is incoming one-way. checking for one-way in non-preferred direction"); } ushort targetSegmentId = lhd ? rightSegmentId : leftSegmentId; if (!segmentManager.ExtSegments[targetSegmentId].oneWay) { // disallow turn in non-preferred direction if (logTurnOnRed) { Log._Debug( $"TurnOnRedManager.UpdateSegmentEnd({end.segmentId}, {end.startNode}): " + $"turn in non-preferred direction {(lhd ? "right" : "left")} disallowed"); } if (lhd) { rightSegmentId = 0; } else { leftSegmentId = 0; } } } } else if (lhd) { // default case (LHD): turn in preferred direction rightSegmentId = 0; } else { // default case (RHD): turn in preferred direction leftSegmentId = 0; } int index = GetIndex(end.segmentId, end.startNode); TurnOnRedSegments[index].leftSegmentId = leftSegmentId; TurnOnRedSegments[index].rightSegmentId = rightSegmentId; if (logTurnOnRed) { Log._Debug( $"TurnOnRedManager.UpdateSegmentEnd({end.segmentId}, {end.startNode}): " + $"Finished calculation. leftSegmentId={leftSegmentId}, rightSegmentId={rightSegmentId}"); } }
/// <summary> /// Are all segments at nodeId highways? /// </summary> /// <param name="nodeId"></param> /// <returns></returns> public static bool JunctionHasOnlyHighwayRoads(ushort nodeId) { IExtSegmentManager segMan = Constants.ManagerFactory.ExtSegmentManager; ref NetNode node = ref nodeId.ToNode();
public void CalculateAutoPedestrianLightState(ref NetNode node, bool propagate = true) { #if DEBUGTTL bool debug = DebugSwitch.TimedTrafficLights.Get() && DebugSettings.NodeId == NodeId; #endif #if DEBUGTTL if (debug) { Log._Debug($"CustomSegmentLights.CalculateAutoPedestrianLightState: Calculating pedestrian light state of seg. {SegmentId} @ node {NodeId}"); } #endif IExtSegmentManager segMan = Constants.ManagerFactory.ExtSegmentManager; IExtSegmentEndManager segEndMan = Constants.ManagerFactory.ExtSegmentEndManager; ExtSegment seg = segMan.ExtSegments[SegmentId]; ExtSegmentEnd segEnd = segEndMan.ExtSegmentEnds[segEndMan.GetIndex(SegmentId, StartNode)]; ushort nodeId = segEnd.nodeId; if (nodeId != NodeId) { Log.Warning($"CustomSegmentLights.CalculateAutoPedestrianLightState: Node id mismatch! segment end node is {nodeId} but we are node {NodeId}. segEnd={segEnd} this={this}"); return; } if (propagate) { for (int i = 0; i < 8; ++i) { ushort otherSegmentId = node.GetSegment(i); if (otherSegmentId == 0 || otherSegmentId == SegmentId) { continue; } ICustomSegmentLights otherLights = LightsManager.GetSegmentLights(nodeId, otherSegmentId); if (otherLights == null) { #if DEBUGTTL if (debug) { Log._Debug($"CustomSegmentLights.CalculateAutoPedestrianLightState: Expected other (propagate) CustomSegmentLights at segment {otherSegmentId} @ {NodeId} but there was none. Original segment id: {SegmentId}"); } #endif continue; } otherLights.CalculateAutoPedestrianLightState(ref node, false); } } if (IsAnyGreen()) { #if DEBUGTTL if (debug) { Log._Debug($"CustomSegmentLights.CalculateAutoPedestrianLightState: Any green at seg. {SegmentId} @ {NodeId}"); } #endif AutoPedestrianLightState = RoadBaseAI.TrafficLightState.Red; return; } #if DEBUGTTL if (debug) { Log._Debug($"CustomSegmentLights.CalculateAutoPedestrianLightState: Querying incoming segments at seg. {SegmentId} @ {NodeId}"); } #endif ItemClass prevConnectionClass = null; Constants.ServiceFactory.NetService.ProcessSegment(SegmentId, delegate(ushort prevSegId, ref NetSegment segment) { prevConnectionClass = segment.Info.GetConnectionClass(); return(true); }); RoadBaseAI.TrafficLightState autoPedestrianLightState = RoadBaseAI.TrafficLightState.Green; bool lhd = Constants.ServiceFactory.SimulationService.LeftHandDrive; if (!(segEnd.incoming && seg.oneWay)) { for (int i = 0; i < 8; ++i) { ushort otherSegmentId = node.GetSegment(i); if (otherSegmentId == 0 || otherSegmentId == SegmentId) { continue; } //ExtSegment otherSeg = segMan.ExtSegments[otherSegmentId]; if (!segEndMan.ExtSegmentEnds[segEndMan.GetIndex(otherSegmentId, (bool)Constants.ServiceFactory.NetService.IsStartNode(otherSegmentId, NodeId))].incoming) { continue; } #if DEBUGTTL if (debug) { Log._Debug($"CustomSegmentLights.CalculateAutoPedestrianLightState: Checking incoming straight segment {otherSegmentId} at seg. {SegmentId} @ {NodeId}"); } #endif ICustomSegmentLights otherLights = LightsManager.GetSegmentLights(nodeId, otherSegmentId); if (otherLights == null) { #if DEBUGTTL if (debug) { Log._Debug($"CustomSegmentLights.CalculateAutoPedestrianLightState: Expected other (straight) CustomSegmentLights at segment {otherSegmentId} @ {NodeId} but there was none. Original segment id: {SegmentId}"); } #endif continue; } ItemClass nextConnectionClass = null; Constants.ServiceFactory.NetService.ProcessSegment(otherSegmentId, delegate(ushort otherSegId, ref NetSegment segment) { nextConnectionClass = segment.Info.GetConnectionClass(); return(true); }); if (nextConnectionClass.m_service != prevConnectionClass.m_service) { #if DEBUGTTL if (debug) { Log._Debug($"CustomSegmentLights.CalculateAutoPedestrianLightState: Other (straight) segment {otherSegmentId} @ {NodeId} has different connection service than segment {SegmentId} ({nextConnectionClass.m_service} vs. {prevConnectionClass.m_service}). Ignoring traffic light state."); } #endif continue; } ArrowDirection dir = segEndMan.GetDirection(ref segEnd, otherSegmentId); if (dir == ArrowDirection.Forward) { if (!otherLights.IsAllMainRed()) { #if DEBUGTTL if (debug) { Log._Debug($"CustomSegmentLights.CalculateAutoPedestrianLightState: Not all main red at {otherSegmentId} at seg. {SegmentId} @ {NodeId}"); } #endif autoPedestrianLightState = RoadBaseAI.TrafficLightState.Red; break; } } else if ((dir == ArrowDirection.Left && lhd) || (dir == ArrowDirection.Right && !lhd)) { if ((lhd && !otherLights.IsAllRightRed()) || (!lhd && !otherLights.IsAllLeftRed())) { #if DEBUGTTL if (debug) { Log._Debug($"CustomSegmentLights.CalculateAutoPedestrianLightState: Not all left red at {otherSegmentId} at seg. {SegmentId} @ {NodeId}"); } #endif autoPedestrianLightState = RoadBaseAI.TrafficLightState.Red; break; } } } } AutoPedestrianLightState = autoPedestrianLightState; #if DEBUGTTL if (debug) { Log._Debug($"CustomSegmentLights.CalculateAutoPedestrianLightState: Calculated AutoPedestrianLightState for segment {SegmentId} @ {NodeId}: {AutoPedestrianLightState}"); } #endif }