diff --git a/TLM/TLM/Manager/Impl/ExtNodeManager.cs b/TLM/TLM/Manager/Impl/ExtNodeManager.cs index 4a935c1db..4fedd223b 100644 --- a/TLM/TLM/Manager/Impl/ExtNodeManager.cs +++ b/TLM/TLM/Manager/Impl/ExtNodeManager.cs @@ -41,9 +41,10 @@ public static bool JunctionHasHighwayRules(ushort nodeId) { return JunctionHasOnlyHighwayRoads(nodeId) && !LaneConnection.LaneConnectionManager.Instance.Sub.HasNodeConnections(nodeId); } - public GetNodeSegmentIdsEnumerable GetNodeSegmentIds(ushort nodeId, ClockDirection clockDirection) { - ref NetNode netNode = ref nodeId.ToNode(); - var initialSegmentId = GetInitialSegment(ref netNode); + public GetNodeSegmentIdsEnumerable GetNodeSegmentIds(ushort nodeId, ClockDirection clockDirection) + => GetNodeSegmentIds(nodeId, clockDirection, GetInitialSegment(ref nodeId.ToNode())); + + internal GetNodeSegmentIdsEnumerable GetNodeSegmentIds(ushort nodeId, ClockDirection clockDirection, ushort initialSegmentId) { var segmentBuffer = Singleton.instance.m_segments.m_buffer; return new GetNodeSegmentIdsEnumerable(nodeId, initialSegmentId, clockDirection, segmentBuffer); } diff --git a/TLM/TLM/Manager/Impl/JunctionRestrictionsManager.cs b/TLM/TLM/Manager/Impl/JunctionRestrictionsManager.cs index cd2ca801a..a4252f3b4 100644 --- a/TLM/TLM/Manager/Impl/JunctionRestrictionsManager.cs +++ b/TLM/TLM/Manager/Impl/JunctionRestrictionsManager.cs @@ -17,6 +17,7 @@ namespace TrafficManager.Manager.Impl { using TrafficManager.Util; using TrafficManager.Util.Extensions; using TrafficManager.Lifecycle; + using TrafficManager.Util.Iterators; public class JunctionRestrictionsManager : AbstractGeometryObservingManager, @@ -632,8 +633,8 @@ public bool IsEnteringBlockedJunctionAllowed(ushort segmentId, bool startNode) { } public bool IsPedestrianCrossingAllowedConfigurable(ushort segmentId, bool startNode, ref NetNode node) { - bool ret = (node.m_flags & (NetNode.Flags.Junction | NetNode.Flags.Bend)) != NetNode.Flags.None - && node.Info?.m_class?.m_service != ItemClass.Service.Beautification; + bool ret = IsNodePedestrianCrossingConfigurable(ref node) + && IsLikelyPedestrianRoute(segmentId, startNode, true); #if DEBUG if (DebugSwitch.JunctionRestrictions.Get()) { Log._Debug( @@ -645,6 +646,11 @@ public bool IsPedestrianCrossingAllowedConfigurable(ushort segmentId, bool start return ret; } + private static bool IsNodePedestrianCrossingConfigurable(ref NetNode node) { + return (node.m_flags & (NetNode.Flags.Junction | NetNode.Flags.Bend)) != NetNode.Flags.None + && node.Info?.m_class?.m_service != ItemClass.Service.Beautification; + } + public bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, bool startNode, ref NetNode node) { #if DEBUG bool logLogic = DebugSwitch.JunctionRestrictions.Get(); @@ -652,11 +658,11 @@ public bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, bool startNode const bool logLogic = false; #endif - if (!IsPedestrianCrossingAllowedConfigurable(segmentId, startNode, ref node)) { + if (!IsNodePedestrianCrossingConfigurable(ref node)) { if (logLogic) { Log._Debug( "JunctionRestrictionsManager.GetDefaultPedestrianCrossingAllowed" + - $"({segmentId}, {startNode}): Setting is not configurable. res=true"); + $"({segmentId}, {startNode}): Setting is not configurable for this node type. res=true"); } return true; @@ -703,8 +709,9 @@ public bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, bool startNode // crossing is allowed at junctions and at untouchable nodes (for example: spiral // underground parking) - bool ret = (node.m_flags & (NetNode.Flags.Junction | NetNode.Flags.Untouchable)) != - NetNode.Flags.None; + bool ret = ((node.m_flags & (NetNode.Flags.Junction | NetNode.Flags.Untouchable)) != NetNode.Flags.None + || !IsNodePedestrianCrossingConfigurable(ref node)) + && IsLikelyPedestrianRoute(segmentId, startNode, false); if (logLogic) { Log._Debug( @@ -715,6 +722,104 @@ public bool GetDefaultPedestrianCrossingAllowed(ushort segmentId, bool startNode return ret; } + private static bool IsLikelyPedestrianRoute(ushort segmentId, bool startNode, bool includeAllReachable) { +#if DEBUG + bool logLogic = DebugSwitch.JunctionRestrictions.Get(); + string logHeading = $"IsLikelyPedestrianRoute(segmentId: {segmentId}, startNode: {startNode}, includeAllReachable: {includeAllReachable})\r\t"; +#else + const bool logLogic = false; + const string logHeading = null; +#endif + + NetSegment segment = segmentId.ToSegment(); + + if (segment.Info.m_hasPedestrianLanes) { + + if (logLogic) { + Log._Debug(logHeading + + $"segment {segmentId} has pedestrian lanes" + + $"returning true"); + } + + return true; + } + + ushort nodeId = startNode ? segment.m_startNode : segment.m_endNode; + + ushort nearestClockwiseSegId = 0; + int clockwiseDistance = 0; + foreach (var otherSegmentId in ExtNodeManager.Instance.GetNodeSegmentIds(nodeId, ClockDirection.Clockwise, segmentId)) { + if (otherSegmentId.ToSegment().Info.m_hasPedestrianLanes) { + nearestClockwiseSegId = otherSegmentId; + break; + } + ++clockwiseDistance; + } + + if (nearestClockwiseSegId == 0) { + + if (logLogic) { + Log._Debug(logHeading + + $"no pedestrian lanes on node {nodeId}" + + $"returning false"); + } + + return false; + } + + if (includeAllReachable) { + + if (logLogic) { + Log._Debug(logHeading + + $"pedestrian lanes found on segment {nearestClockwiseSegId}" + + $"returning true"); + } + + return true; + } + + ushort nearestCounterClockwiseSegId = 0; + int counterClockwiseDistance = 0; + foreach (var otherSegmentId in ExtNodeManager.Instance.GetNodeSegmentIds(nodeId, ClockDirection.CounterClockwise, segmentId)) { + if (otherSegmentId.ToSegment().Info.m_hasPedestrianLanes) { + nearestCounterClockwiseSegId = otherSegmentId; + break; + } + ++counterClockwiseDistance; + } + + if (nearestCounterClockwiseSegId == 0 || nearestClockwiseSegId == nearestCounterClockwiseSegId) { + + if (logLogic) { + Log._Debug(logHeading + + $"no pedestrian lanes on segment {segmentId}" + + $"only one segment on node {nodeId} has pedestrian lanes" + + $"returning false"); + } + + return false; + } + + int distanceThisSide = clockwiseDistance + counterClockwiseDistance - 1; + int distanceOtherSide = 0; + foreach (var otherSegmentId in ExtNodeManager.Instance.GetNodeSegmentIds(nodeId, ClockDirection.Clockwise, nearestClockwiseSegId)) { + ++distanceOtherSide; + if (otherSegmentId == nearestCounterClockwiseSegId) + break; + } + + bool result = distanceThisSide < distanceOtherSide; + + if (logLogic) { + Log._Debug(logHeading + + $"segments with pedestrian lanes - clockwise: {nearestClockwiseSegId}, counter-clockwise: {nearestCounterClockwiseSegId}\r\t" + + $"distanceThisSide: {distanceThisSide}, distanceOtherSide: {distanceOtherSide}\r\t" + + $"returning {result}"); + } + + return result; + } + public bool IsPedestrianCrossingAllowed(ushort segmentId, bool startNode) { return segmentRestrictions[segmentId].GetValueOrDefault(JunctionRestrictionFlags.AllowPedestrianCrossing, startNode); }