/// <summary> /// Assembles a geometrically sorted list of lanes for the given segment. /// If the <paramref name="startNode"/> parameter is set only lanes supporting traffic to flow towards the given node are added to the list, otherwise all matched lanes are added. /// </summary> /// <param name="segmentId">segment id</param> /// <param name="segment">segment data</param> /// <param name="startNode">reference node (optional)</param> /// <param name="laneTypeFilter">lane type filter, lanes must match this filter mask</param> /// <param name="vehicleTypeFilter">vehicle type filter, lanes must match this filter mask</param> /// <param name="reverse">if true, lanes are ordered from right to left (relative to the segment's start node / the given node), otherwise from left to right</param> /// <returns>sorted list of lanes for the given segment</returns> public IList <LanePos> GetSortedLanes(ushort segmentId, ref NetSegment segment, bool?startNode, NetInfo.LaneType?laneTypeFilter = null, VehicleInfo.VehicleType?vehicleTypeFilter = null, bool reverse = false) // TODO refactor together with getSegmentNumVehicleLanes, especially the vehicle type and lane type checks { NetManager netManager = Singleton <NetManager> .instance; var laneList = new List <LanePos>(); bool inverted = ((segment.m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None); NetInfo.Direction?filterDir = null; NetInfo.Direction sortDir = NetInfo.Direction.Forward; if (startNode != null) { filterDir = (bool)startNode ? NetInfo.Direction.Backward : NetInfo.Direction.Forward; filterDir = inverted ? NetInfo.InvertDirection((NetInfo.Direction)filterDir) : filterDir; sortDir = NetInfo.InvertDirection((NetInfo.Direction)filterDir); } else if (inverted) { sortDir = NetInfo.Direction.Backward; } if (reverse) { sortDir = NetInfo.InvertDirection(sortDir); } NetInfo segmentInfo = segment.Info; uint curLaneId = segment.m_lanes; byte laneIndex = 0; while (laneIndex < segmentInfo.m_lanes.Length && curLaneId != 0u) { NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex]; if ((laneTypeFilter == null || (laneInfo.m_laneType & laneTypeFilter) != NetInfo.LaneType.None) && (vehicleTypeFilter == null || (laneInfo.m_vehicleType & vehicleTypeFilter) != VehicleInfo.VehicleType.None) && (filterDir == null || segmentInfo.m_lanes[laneIndex].m_finalDirection == filterDir)) { laneList.Add(new LanePos(curLaneId, laneIndex, segmentInfo.m_lanes[laneIndex].m_position, laneInfo.m_vehicleType, laneInfo.m_laneType)); } curLaneId = netManager.m_lanes.m_buffer[curLaneId].m_nextLane; ++laneIndex; } laneList.Sort(delegate(LanePos x, LanePos y) { bool fwd = sortDir == NetInfo.Direction.Forward; if (x.position == y.position) { if (x.position > 0) { // mirror type-bound lanes (e.g. for coherent disply of lane-wise speed limits) fwd = !fwd; } if (x.laneType == y.laneType) { if (x.vehicleType == y.vehicleType) { return(0); } else if ((x.vehicleType < y.vehicleType) == fwd) { return(-1); } else { return(1); } } else if ((x.laneType < y.laneType) == fwd) { return(-1); } else { return(1); } } if ((x.position < y.position) == fwd) { return(-1); } return(1); }); return(laneList); }
public static void Traverse(ushort initialSegmentId, TraverseDirection direction, TraverseSide side, LaneStopCriterion laneStopCrit, SegmentStopCriterion segStopCrit, NetInfo.LaneType?laneTypeFilter, VehicleInfo.VehicleType?vehicleTypeFilter, SegmentLaneVisitor laneVisitor) { IList <LanePos> initialSortedLanes = null; //------------------------------------- // Function applies via SegmentTraverser //------------------------------------- bool VisitorFun(SegmentVisitData segData) { bool isInitialSeg = segData.Initial; bool reverse = !isInitialSeg && segData.ViaStartNode == segData.ViaInitialStartNode; bool ret = false; //------------------------------------- // Function applies for each segment //------------------------------------- bool VisitorProcessFun(ushort segmentId, ref NetSegment segment) { // Log._Debug($"SegmentLaneTraverser: Reached segment {segmentId}: // isInitialSeg={isInitialSeg} viaStartNode={segData.viaStartNode} // viaInitialStartNode={segData.viaInitialStartNode} reverse={reverse}"); IList <LanePos> sortedLanes = Constants.ServiceFactory.NetService.GetSortedLanes( segmentId, ref segment, null, laneTypeFilter, vehicleTypeFilter, reverse); if (isInitialSeg) { initialSortedLanes = sortedLanes; } else if (initialSortedLanes == null) { throw new ApplicationException("Initial list of sorted lanes not set."); } else if (sortedLanes.Count != initialSortedLanes.Count && (laneStopCrit & LaneStopCriterion.LaneCount) != LaneStopCriterion.None) { // Log._Debug($"SegmentLaneTraverser: Stop criterion reached @ {segmentId}: // {sortedLanes.Count} current vs. {initialSortedLanes.Count} initial lanes"); return(false); } for (int i = 0; i < sortedLanes.Count; ++i) { // Log._Debug($"SegmentLaneTraverser: Traversing segment lane // {sortedLanes[i].laneIndex} @ {segmentId} (id {sortedLanes[i].laneId}, // pos {sortedLanes[i].position})"); if (!laneVisitor( new SegmentLaneVisitData( segData, i, sortedLanes[i], initialSortedLanes[i]))) { return(false); } } ret = true; return(true); } Constants.ServiceFactory.NetService.ProcessSegment( segData.CurSeg.segmentId, VisitorProcessFun); return(ret); } SegmentTraverser.Traverse(initialSegmentId, direction, side, segStopCrit, VisitorFun); }