示例#1
0
        private Dictionary <ushort, uint> numVehiclesGoingToSegmentId;        // no minimum speed required

        public SegmentEnd(ushort nodeId, ushort segmentId, PriorityType type)
        {
            NodeId    = nodeId;
            SegmentId = segmentId;
            Type      = type;
            FirstRegisteredVehicleId = 0;
            SegmentGeometry segGeometry = SegmentGeometry.Get(segmentId);

            OnUpdate(segGeometry);
            segGeometryUnsubscriber = segGeometry.Subscribe(this);
            NodeGeometry nodeGeometry = NodeGeometry.Get(nodeId);

            OnUpdate(nodeGeometry);
            nodeGeometryUnsubscriber = nodeGeometry.Subscribe(this);
        }
        public static void NotifyStartEndNode(ushort segmentId)
        {
            // notify observers of start node and end node
            ushort startNodeId = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startNode;
            ushort endNodeId   = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_endNode;

            if (startNodeId != 0)
            {
                NodeGeometry.Get(startNodeId).NotifyObservers();
            }
            if (endNodeId != 0)
            {
                NodeGeometry.Get(endNodeId).NotifyObservers();
            }
        }
        internal void Recalculate(bool propagate)
        {
#if DEBUG
            //Log._Debug($"SegmentEndGeometry: Recalculate seg. {SegmentId} @ node {NodeId()}, propagate={propagate}");
#endif

            ushort nodeIdBeforeRecalc = LastKnownNodeId;
            Cleanup();

            if (!IsValid())
            {
                if (nodeIdBeforeRecalc != 0)
                {
                    NodeGeometry.Get(nodeIdBeforeRecalc).RemoveSegment(SegmentId, propagate);
                }

                return;
            }

            NetManager netManager = Singleton <NetManager> .instance;

            ushort nodeId = NodeId();
            LastKnownNodeId = nodeId;

            outgoingOneWay = SegmentGeometry.calculateIsOutgoingOneWay(SegmentId, nodeId);
            onlyHighways   = true;

            //ItemClass connectionClass = netManager.m_segments.m_buffer[SegmentId].Info.GetConnectionClass();

            bool hasOtherSegments = false;
            for (var s = 0; s < 8; s++)
            {
                var otherSegmentId = netManager.m_nodes.m_buffer[nodeId].GetSegment(s);
                if (otherSegmentId == 0 || otherSegmentId == SegmentId)
                {
                    continue;
                }

                /*ItemClass otherConnectionClass = Singleton<NetManager>.instance.m_segments.m_buffer[otherSegmentId].Info.GetConnectionClass();
                 * if (otherConnectionClass.m_service != connectionClass.m_service)
                 *      continue;*/
                hasOtherSegments = true;

                // determine geometry
                bool otherIsOneWay;
                bool otherIsOutgoingOneWay;
                SegmentGeometry.calculateOneWayAtNode(otherSegmentId, nodeId, out otherIsOneWay, out otherIsOutgoingOneWay);

                if (!(SegmentGeometry.calculateIsHighway(otherSegmentId) && otherIsOneWay))
                {
                    onlyHighways = false;
                }

                if (IsRightSegment(SegmentId, otherSegmentId, nodeId))
                {
                    RightSegments[NumRightSegments++] = otherSegmentId;
                    if (!otherIsOutgoingOneWay)
                    {
                        IncomingRightSegments[NumIncomingRightSegments++] = otherSegmentId;
                        if (!otherIsOneWay)
                        {
                            OutgoingRightSegments[NumOutgoingRightSegments++] = otherSegmentId;
                        }
                    }
                    else
                    {
                        OutgoingRightSegments[NumOutgoingRightSegments++] = otherSegmentId;
                    }
                }
                else if (IsLeftSegment(SegmentId, otherSegmentId, nodeId))
                {
                    LeftSegments[NumLeftSegments++] = otherSegmentId;
                    if (!otherIsOutgoingOneWay)
                    {
                        IncomingLeftSegments[NumIncomingLeftSegments++] = otherSegmentId;
                        if (!otherIsOneWay)
                        {
                            OutgoingLeftSegments[NumOutgoingLeftSegments++] = otherSegmentId;
                        }
                    }
                    else
                    {
                        OutgoingLeftSegments[NumOutgoingLeftSegments++] = otherSegmentId;
                    }
                }
                else
                {
                    StraightSegments[NumStraightSegments++] = otherSegmentId;
                    if (!otherIsOutgoingOneWay)
                    {
                        IncomingStraightSegments[NumIncomingStraightSegments++] = otherSegmentId;
                        if (!otherIsOneWay)
                        {
                            OutgoingStraightSegments[NumOutgoingStraightSegments++] = otherSegmentId;
                        }
                    }
                    else
                    {
                        OutgoingStraightSegments[NumOutgoingStraightSegments++] = otherSegmentId;
                    }
                }

                // reset highway lane arrows
                Flags.removeHighwayLaneArrowFlagsAtSegment(otherSegmentId);                 // TODO refactor

                ConnectedSegments[NumConnectedSegments++] = otherSegmentId;
            }

            NumIncomingSegments = (byte)(NumIncomingLeftSegments + NumIncomingStraightSegments + NumIncomingRightSegments);
            numOutgoingSegments = (byte)(NumOutgoingLeftSegments + NumOutgoingStraightSegments + NumOutgoingRightSegments);

            if (!hasOtherSegments)
            {
                onlyHighways = false;
            }

            // propagate information to other segments
            if (nodeIdBeforeRecalc != nodeId)
            {
                if (nodeIdBeforeRecalc != 0)
                {
                    NodeGeometry.Get(nodeIdBeforeRecalc).RemoveSegment(SegmentId, propagate);
                }

                NodeGeometry.Get(nodeId).AddSegment(SegmentId, StartNode, propagate);
            }
        }
        /// <summary>
        /// Calculates for each segment the number of cars going to this segment.
        /// We use integer arithmetic for better performance.
        /// </summary>
        public Dictionary <ushort, uint> GetVehicleMetricGoingToSegment(bool includeStopped = true, byte?laneIndex = null, bool debug = false)
        {
            VehicleManager      vehicleManager  = Singleton <VehicleManager> .instance;
            NetManager          netManager      = Singleton <NetManager> .instance;
            VehicleStateManager vehStateManager = VehicleStateManager.Instance;

            Dictionary <ushort, uint> ret = includeStopped ? numVehiclesGoingToSegmentId : numVehiclesFlowingToSegmentId;

            foreach (SegmentEndGeometry endGeo in NodeGeometry.Get(NodeId).SegmentEndGeometries)
            {
                if (endGeo == null)
                {
                    continue;
                }

                if (!endGeo.IncomingOneWay && !ret.ContainsKey(endGeo.SegmentId))
                {
#if DEBUG
                    Log._Debug($"SegmentEnd.GetVehicleMetricGoingToSegment: return dict does not contain entry for segment {endGeo.SegmentId}");
#endif
                }


                ret[endGeo.SegmentId] = 0;
            }

#if DEBUGMETRIC
            if (debug)
            {
                Log._Debug($"GetVehicleMetricGoingToSegment: Segment {SegmentId}, Node {NodeId}. Target segments: {string.Join(", ", ret.Keys.Select(x => x.ToString()).ToArray())}");
            }
#endif

            ushort vehicleId    = FirstRegisteredVehicleId;
            int    numProcessed = 0;
            while (vehicleId != 0)
            {
                VehicleState state = vehStateManager._GetVehicleState(vehicleId);

                bool breakLoop = false;

                state.ProcessCurrentAndNextPathPosition(ref Singleton <VehicleManager> .instance.m_vehicles.m_buffer[vehicleId], delegate(ref Vehicle vehState, ref PathUnit.Position curPos, ref PathUnit.Position nextPos) {
                    if (!state.CheckValidity(ref vehState))
                    {
                        RequestCleanup();
                        return;
                    }

#if DEBUGMETRIC2
                    if (debug)
                    {
                        Log._Debug($" GetVehicleMetricGoingToSegment: Checking vehicle {vehicleId}");
                    }
#endif

                    if (!ret.ContainsKey(nextPos.m_segment))
                    {
#if DEBUGMETRIC2
                        if (debug)
                        {
                            Log._Debug($"  GetVehicleMetricGoingToSegment: ret does not contain key for target segment {nextPos.m_segment}");
                        }
#endif
                        return;
                    }

                    if (!includeStopped && vehState.GetLastFrameVelocity().sqrMagnitude < TrafficPriorityManager.MAX_SQR_STOP_VELOCITY)
                    {
#if DEBUGMETRIC2
                        if (debug)
                        {
                            Log._Debug($"  GetVehicleMetricGoingToSegment: Vehicle {vehicleId}: too slow");
                        }
#endif
                        ++numProcessed;
                        return;
                    }

                    if (laneIndex != null && curPos.m_lane != laneIndex)
                    {
#if DEBUGMETRIC2
                        if (debug)
                        {
                            Log._Debug($"  GetVehicleMetricGoingToSegment: Vehicle {vehicleId}: Lane index mismatch (expected: {laneIndex}, was: {curPos.m_lane})");
                        }
#endif
                        return;
                    }

                    if (Options.simAccuracy <= 2)
                    {
                        uint avgSegmentLength = (uint)netManager.m_segments.m_buffer[SegmentId].m_averageLength;
                        uint normLength       = 100u;
                        if (avgSegmentLength > 0)
                        {
                            normLength = Math.Min(100u, (uint)(state.TotalLength * 100u) / avgSegmentLength);
                        }

#if DEBUGMETRIC
                        if (debug)
                        {
                            Log._Debug($"  GetVehicleMetricGoingToSegment: NormLength of vehicle {vehicleId}: {avgSegmentLength} -> {normLength}");
                        }
#endif

                        ret[nextPos.m_segment] += normLength;
                    }
                    else
                    {
                        ret[nextPos.m_segment] += 10;
                    }

                    ++ret[nextPos.m_segment];
                    ++numProcessed;

                    if ((Options.simAccuracy >= 3 && numProcessed >= 3) || (Options.simAccuracy == 2 && numProcessed >= 5) || (Options.simAccuracy == 1 && numProcessed >= 10))
                    {
                        breakLoop = true;
                        return;
                    }

#if DEBUGMETRIC2
                    if (debug)
                    {
                        Log._Debug($"  GetVehicleMetricGoingToSegment: Vehicle {vehicleId}: *added*! Coming from segment {SegmentId}, lane {laneIndex}. Going to segment {nextPos.m_segment}, lane {nextPos.m_lane}");
                    }
#endif
                });

                if (breakLoop)
                {
                    break;
                }

                vehicleId = state.NextVehicleIdOnSegment;
            }

#if DEBUGMETRIC
            if (debug)
            {
                Log._Debug($"GetVehicleMetricGoingToSegment: Calculation completed. {string.Join(", ", ret.Select(x => x.Key.ToString() + "=" + x.Value.ToString()).ToArray())}");
            }
#endif
            return(ret);
        }
        /// <summary>
        /// Recalculates lane arrows based on present lane connections.
        /// </summary>
        /// <param name="laneId"></param>
        /// <param name="nodeId"></param>
        private void RecalculateLaneArrows(uint laneId, ushort nodeId, bool startNode)
        {
#if DEBUGCONN
            Log._Debug($"LaneConnectionManager.RecalculateLaneArrows({laneId}, {nodeId}) called");
#endif
            if (!Flags.mayHaveLaneArrows(laneId, startNode))
            {
#if DEBUGCONN
                Log._Debug($"LaneConnectionManager.RecalculateLaneArrows({laneId}, {nodeId}): lane {laneId}, startNode? {startNode} must not have lane arrows");
#endif
                return;
            }

            if (!HasConnections(laneId, startNode))
            {
#if DEBUGCONN
                Log._Debug($"LaneConnectionManager.RecalculateLaneArrows({laneId}, {nodeId}): lane {laneId} does not have outgoing connections");
#endif
                return;
            }

            if (nodeId == 0)
            {
#if DEBUGCONN
                Log._Debug($"LaneConnectionManager.RecalculateLaneArrows({laneId}, {nodeId}): invalid node");
#endif
                return;
            }

            Flags.LaneArrows arrows = Flags.LaneArrows.None;

            NetManager netManager = Singleton <NetManager> .instance;
            ushort     segmentId  = netManager.m_lanes.m_buffer[laneId].m_segment;

            if (segmentId == 0)
            {
#if DEBUGCONN
                Log._Debug($"LaneConnectionManager.RecalculateLaneArrows({laneId}, {nodeId}): invalid segment");
#endif
                return;
            }

#if DEBUGCONN
            Log._Debug($"LaneConnectionManager.RecalculateLaneArrows({laneId}, {nodeId}): startNode? {startNode}");
#endif

            NodeGeometry nodeGeo = NodeGeometry.Get(nodeId);
            if (!nodeGeo.IsValid())
            {
#if DEBUGCONN
                Log._Debug($"LaneConnectionManager.RecalculateLaneArrows({laneId}, {nodeId}): invalid node geometry");
#endif
                return;
            }

            SegmentGeometry segmentGeo = SegmentGeometry.Get(segmentId);
            if (!segmentGeo.IsValid())
            {
#if DEBUGCONN
                Log._Debug($"LaneConnectionManager.RecalculateLaneArrows({laneId}, {nodeId}): invalid segment geometry");
#endif
                return;
            }

            ushort[] connectedSegmentIds = segmentGeo.GetConnectedSegments(startNode);
            if (connectedSegmentIds == null)
            {
#if DEBUGCONN
                Log._Debug($"LaneConnectionManager.RecalculateLaneArrows({laneId}, {nodeId}): connectedSegmentIds is null");
#endif
                return;
            }

            foreach (ushort connectedSegmentId in connectedSegmentIds)
            {
                if (connectedSegmentId == 0)
                {
                    continue;
                }
                Direction dir = segmentGeo.GetDirection(connectedSegmentId, startNode);

#if DEBUGCONN
                Log._Debug($"LaneConnectionManager.RecalculateLaneArrows({laneId}, {nodeId}): processing connected segment {connectedSegmentId}. dir={dir}");
#endif

                // check if arrow has already been set for this direction
                switch (dir)
                {
                case Direction.Turn:
                default:
                    continue;

                case Direction.Forward:
                    if ((arrows & Flags.LaneArrows.Forward) != Flags.LaneArrows.None)
                    {
                        continue;
                    }
                    break;

                case Direction.Left:
                    if ((arrows & Flags.LaneArrows.Left) != Flags.LaneArrows.None)
                    {
                        continue;
                    }
                    break;

                case Direction.Right:
                    if ((arrows & Flags.LaneArrows.Right) != Flags.LaneArrows.None)
                    {
                        continue;
                    }
                    break;
                }

#if DEBUGCONN
                Log._Debug($"LaneConnectionManager.RecalculateLaneArrows({laneId}, {nodeId}): processing connected segment {connectedSegmentId}: need to determine arrows");
#endif

                bool addArrow = false;

                uint curLaneId = netManager.m_segments.m_buffer[connectedSegmentId].m_lanes;
                while (curLaneId != 0)
                {
#if DEBUGCONN
                    Log._Debug($"LaneConnectionManager.RecalculateLaneArrows({laneId}, {nodeId}): processing connected segment {connectedSegmentId}: checking lane {curLaneId}");
#endif
                    if (AreLanesConnected(laneId, curLaneId, startNode))
                    {
#if DEBUGCONN
                        Log._Debug($"LaneConnectionManager.RecalculateLaneArrows({laneId}, {nodeId}): processing connected segment {connectedSegmentId}: checking lane {curLaneId}: lanes are connected");
#endif
                        addArrow = true;
                        break;
                    }

                    curLaneId = netManager.m_lanes.m_buffer[curLaneId].m_nextLane;
                }

#if DEBUGCONN
                Log._Debug($"LaneConnectionManager.RecalculateLaneArrows({laneId}, {nodeId}): processing connected segment {connectedSegmentId}: finished processing lanes. addArrow={addArrow} arrows (before)={arrows}");
#endif
                if (addArrow)
                {
                    switch (dir)
                    {
                    case Direction.Turn:
                    default:
                        continue;

                    case Direction.Forward:
                        arrows |= Flags.LaneArrows.Forward;
                        break;

                    case Direction.Left:
                        arrows |= Flags.LaneArrows.Left;
                        break;

                    case Direction.Right:
                        arrows |= Flags.LaneArrows.Right;
                        break;
                    }

#if DEBUGCONN
                    Log._Debug($"LaneConnectionManager.RecalculateLaneArrows({laneId}, {nodeId}): processing connected segment {connectedSegmentId}: arrows={arrows}");
#endif
                }
            }

#if DEBUGCONN
            Log._Debug($"LaneConnectionManager.RecalculateLaneArrows({laneId}, {nodeId}): setting lane arrows to {arrows}");
#endif

            Flags.setLaneArrowFlags(laneId, arrows, true);
        }