/// <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);
        }
Beispiel #2
0
        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);
        }