Esempio n. 1
0
        private void DrawSign(bool viewOnly, ref Vector3 camPos, ref Vector3 xu, ref Vector3 yu, float f, ref Vector3 zero, int x, int y, ref Color guiColor, Texture2D signTexture, out bool hoveredHandle)
        {
            Vector3 signCenter = zero + f * (float)x * xu + f * (float)y * yu;             // in game coordinates

            Vector3 signScreenPos;
            bool    visible = MainTool.WorldToScreenPoint(signCenter, out signScreenPos);

            if (!visible)
            {
                hoveredHandle = false;
                return;
            }

            Vector3 diff = signCenter - camPos;

            var zoom = 1.0f / diff.magnitude * 100f * MainTool.GetBaseZoom();
            var size = (viewOnly ? 0.8f : 1f) * junctionRestrictionsSignSize * zoom;

            var boundingBox = new Rect(signScreenPos.x - size / 2, signScreenPos.y - size / 2, size, size);

            hoveredHandle = !viewOnly && TrafficManagerTool.IsMouseOver(boundingBox);
            if (hoveredHandle)
            {
                // mouse hovering over sign
                guiColor.a = 0.8f;
            }
            else
            {
                guiColor.a = 0.5f;
            }

            GUI.color = guiColor;
            GUI.DrawTexture(boundingBox, signTexture);
        }
        private void DrawRestrictionsSign(bool viewOnly, Vector3 camPos, out Vector3 diff, Vector3 xu, Vector3 yu, float f, Vector3 zero, uint x, uint y, ref Color guiColor, Texture2D signTexture, out bool hoveredHandle)
        {
            Vector3 signCenter = zero + f * (float)x * xu + f * (float)y * yu;             // in game coordinates

            var signScreenPos = Camera.main.WorldToScreenPoint(signCenter);

            signScreenPos.y = Screen.height - signScreenPos.y;
            diff            = signCenter - camPos;

            var zoom = 1.0f / diff.magnitude * 100f * MainTool.GetBaseZoom();
            var size = (viewOnly ? 0.8f : 1f) * vehicleRestrictionsSignSize * zoom;

            var boundingBox = new Rect(signScreenPos.x - size / 2, signScreenPos.y - size / 2, size, size);

            hoveredHandle = !viewOnly && TrafficManagerTool.IsMouseOver(boundingBox);
            if (hoveredHandle)
            {
                // mouse hovering over sign
                guiColor.a = 0.8f;
            }
            else
            {
                guiColor.a = 0.5f;
            }

            GUI.color = guiColor;
            GUI.DrawTexture(boundingBox, signTexture);
        }
        private void DrawSign(bool viewOnly,
                              bool small,
                              ref Vector3 camPos,
                              ref Vector3 xu,
                              ref Vector3 yu,
                              float f,
                              ref Vector3 zero,
                              int x,
                              int y,
                              Color guiColor,
                              Texture2D signTexture,
                              out bool hoveredHandle)
        {
            Vector3 signCenter = zero + (f * x * xu) + (f * y * yu); // in game coordinates

            Vector3 signScreenPos;
            bool    visible = MainTool.WorldToScreenPoint(signCenter, out signScreenPos);

            if (!visible)
            {
                hoveredHandle = false;
                return;
            }

            Vector3 diff = signCenter - camPos;

            float zoom = 1.0f / diff.magnitude * 100f * MainTool.GetBaseZoom();
            float size = (small ? 0.75f : 1f) * (viewOnly ? 0.8f : 1f) *
                         junctionRestrictionsSignSize * zoom;

            var boundingBox = new Rect(
                signScreenPos.x - size / 2,
                signScreenPos.y - size / 2,
                size,
                size);

            hoveredHandle = !viewOnly && TrafficManagerTool.IsMouseOver(boundingBox);
            guiColor.a    = TrafficManagerTool.GetHandleAlpha(hoveredHandle);

            GUI.color = guiColor;
            GUI.DrawTexture(boundingBox, signTexture);
        }
        private void DrawSpeedLimitHandles(ushort segmentId,
                                           ref NetSegment segment,
                                           bool viewOnly,
                                           ref Vector3 camPos)
        {
            if (viewOnly && !Options.speedLimitsOverlay)
            {
                return;
            }

            Vector3    center          = segment.m_bounds.center;
            NetManager netManager      = Singleton <NetManager> .instance;
            SpeedValue speedLimitToSet = viewOnly
                                             ? new SpeedValue(-1f)
                                             : currentPaletteSpeedLimit;
            bool showPerLane = showLimitsPerLane;

            if (!viewOnly)
            {
                showPerLane = showLimitsPerLane ^
                              (Input.GetKey(KeyCode.LeftControl) ||
                               Input.GetKey(KeyCode.RightControl));
            }

            // US signs are rectangular, all other are round
            float speedLimitSignVerticalScale = GetVerticalTextureScale();

            if (showPerLane)
            {
                // show individual speed limit handle per lane
                int numLanes = TrafficManagerTool.GetSegmentNumVehicleLanes(
                    segmentId,
                    null,
                    out int numDirections,
                    SpeedLimitManager.VEHICLE_TYPES);

                NetInfo segmentInfo = segment.Info;
                Vector3 yu          = (segment.m_endDirection - segment.m_startDirection).normalized;
                Vector3 xu          = Vector3.Cross(yu, new Vector3(0, 1f, 0)).normalized;

                // if ((segment.m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) {
                //        xu = -xu; }
                float   f    = viewOnly ? 4f : 7f; // reserved sign size in game coordinates
                Vector3 zero = center - (0.5f * (((numLanes - 1) + numDirections) - 1) * f * xu);

                uint            x           = 0;
                IList <LanePos> sortedLanes = Constants.ServiceFactory.NetService.GetSortedLanes(
                    segmentId,
                    ref segment,
                    null,
                    SpeedLimitManager.LANE_TYPES,
                    SpeedLimitManager.VEHICLE_TYPES);
                bool onlyMonorailLanes = sortedLanes.Count > 0;

                if (!viewOnly)
                {
                    foreach (LanePos laneData in sortedLanes)
                    {
                        byte         laneIndex = laneData.laneIndex;
                        NetInfo.Lane laneInfo  = segmentInfo.m_lanes[laneIndex];

                        if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Monorail) ==
                            VehicleInfo.VehicleType.None)
                        {
                            onlyMonorailLanes = false;
                            break;
                        }
                    }
                }

                var directions      = new HashSet <NetInfo.Direction>();
                int sortedLaneIndex = -1;

                foreach (LanePos laneData in sortedLanes)
                {
                    ++sortedLaneIndex;
                    uint laneId    = laneData.laneId;
                    byte laneIndex = laneData.laneIndex;

                    NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex];
                    if (!directions.Contains(laneInfo.m_finalDirection))
                    {
                        if (directions.Count > 0)
                        {
                            ++x; // space between different directions
                        }

                        directions.Add(laneInfo.m_finalDirection);
                    }

                    SpeedValue laneSpeedLimit = new SpeedValue(
                        SpeedLimitManager.Instance.GetCustomSpeedLimit(laneId));

                    bool hoveredHandle = MainTool.DrawGenericOverlayGridTexture(
                        SpeedLimitTextures.GetSpeedLimitTexture(laneSpeedLimit),
                        camPos,
                        zero,
                        f,
                        f,
                        xu,
                        yu,
                        x,
                        0,
                        speedLimitSignSize,
                        speedLimitSignSize * speedLimitSignVerticalScale,
                        !viewOnly);

                    if (!viewOnly &&
                        !onlyMonorailLanes &&
                        ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Monorail) !=
                         VehicleInfo.VehicleType.None))
                    {
                        Texture2D tex1 = RoadUITextures.VehicleInfoSignTextures[
                            LegacyExtVehicleType.ToNew(ExtVehicleType.PassengerTrain)];
                        MainTool.DrawStaticSquareOverlayGridTexture(
                            tex1,
                            camPos,
                            zero,
                            f,
                            xu,
                            yu,
                            x,
                            1,
                            speedLimitSignSize);
                    }

                    if (hoveredHandle)
                    {
                    }

                    if (hoveredHandle && Input.GetMouseButton(0) && !IsCursorInPanel())
                    {
                        SpeedLimitManager.Instance.SetSpeedLimit(
                            segmentId,
                            laneIndex,
                            laneInfo,
                            laneId,
                            speedLimitToSet.GameUnits);

                        if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
                        {
                            int slIndexCopy = sortedLaneIndex;

                            SegmentLaneTraverser.Traverse(
                                segmentId,
                                SegmentTraverser.TraverseDirection.AnyDirection,
                                SegmentTraverser.TraverseSide.AnySide,
                                SegmentLaneTraverser.LaneStopCriterion.LaneCount,
                                SegmentTraverser.SegmentStopCriterion.Junction,
                                SpeedLimitManager.LANE_TYPES,
                                SpeedLimitManager.VEHICLE_TYPES,
                                data => {
                                if (data.SegVisitData.Initial)
                                {
                                    return(true);
                                }

                                if (slIndexCopy != data.SortedLaneIndex)
                                {
                                    return(true);
                                }

                                Constants.ServiceFactory.NetService.ProcessSegment(
                                    data.SegVisitData.CurSeg.segmentId,
                                    (ushort curSegmentId, ref NetSegment curSegment) =>
                                {
                                    NetInfo.Lane curLaneInfo = curSegment.Info.m_lanes[
                                        data.CurLanePos.laneIndex];

                                    SpeedLimitManager.Instance.SetSpeedLimit(
                                        curSegmentId,
                                        data.CurLanePos.laneIndex,
                                        curLaneInfo,
                                        data.CurLanePos.laneId,
                                        speedLimitToSet.GameUnits);
                                    return(true);
                                });

                                return(true);
                            });
                        }
                    }

                    ++x;
                }
            }
            else
            {
                // draw speedlimits over mean middle points of lane beziers

                if (!segmentCenterByDir.TryGetValue(
                        segmentId,
                        out Dictionary <NetInfo.Direction, Vector3> segCenter))
                {
                    segCenter = new Dictionary <NetInfo.Direction, Vector3>();
                    segmentCenterByDir.Add(segmentId, segCenter);
                    TrafficManagerTool.CalculateSegmentCenterByDir(segmentId, segCenter);
                }

                foreach (KeyValuePair <NetInfo.Direction, Vector3> e in segCenter)
                {
                    bool visible = MainTool.WorldToScreenPoint(e.Value, out Vector3 screenPos);

                    if (!visible)
                    {
                        continue;
                    }

                    float zoom        = (1.0f / (e.Value - camPos).magnitude) * 100f * MainTool.GetBaseZoom();
                    float size        = (viewOnly ? 0.8f : 1f) * speedLimitSignSize * zoom;
                    Color guiColor    = GUI.color;
                    var   boundingBox = new Rect(screenPos.x - (size / 2),
                                                 screenPos.y - (size / 2),
                                                 size,
                                                 size * speedLimitSignVerticalScale);
                    bool hoveredHandle = !viewOnly && TrafficManagerTool.IsMouseOver(boundingBox);

                    guiColor.a = TrafficManagerTool.GetHandleAlpha(hoveredHandle);

                    if (hoveredHandle)
                    {
                        // mouse hovering over sign
                    }

                    // Draw something right here, the road sign texture
                    GUI.color = guiColor;
                    SpeedValue displayLimit = new SpeedValue(
                        SpeedLimitManager.Instance.GetCustomSpeedLimit(segmentId, e.Key));
                    Texture2D tex = SpeedLimitTextures.GetSpeedLimitTexture(displayLimit);

                    GUI.DrawTexture(boundingBox, tex);

                    if (hoveredHandle && Input.GetMouseButton(0) && !IsCursorInPanel())
                    {
                        // change the speed limit to the selected one
                        // Log._Debug($"Setting speed limit of segment {segmentId}, dir {e.Key.ToString()}
                        //     to {speedLimitToSet}");
                        SpeedLimitManager.Instance.SetSpeedLimit(segmentId,
                                                                 e.Key,
                                                                 currentPaletteSpeedLimit.GameUnits);

                        if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
                        {
                            NetInfo.Direction normDir = e.Key;
                            if ((netManager.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None)
                            {
                                normDir = NetInfo.InvertDirection(normDir);
                            }

                            SegmentLaneTraverser.Traverse(
                                segmentId,
                                SegmentTraverser.TraverseDirection.AnyDirection,
                                SegmentTraverser.TraverseSide.AnySide,
                                SegmentLaneTraverser.LaneStopCriterion.LaneCount,
                                SegmentTraverser.SegmentStopCriterion.Junction,
                                SpeedLimitManager.LANE_TYPES,
                                SpeedLimitManager.VEHICLE_TYPES,
                                data =>
                            {
                                if (data.SegVisitData.Initial)
                                {
                                    return(true);
                                }

                                bool reverse =
                                    data.SegVisitData.ViaStartNode
                                    == data.SegVisitData.ViaInitialStartNode;

                                ushort otherSegmentId    = data.SegVisitData.CurSeg.segmentId;
                                NetInfo otherSegmentInfo =
                                    netManager.m_segments.m_buffer[otherSegmentId].Info;
                                byte laneIndex        = data.CurLanePos.laneIndex;
                                NetInfo.Lane laneInfo = otherSegmentInfo.m_lanes[laneIndex];

                                NetInfo.Direction otherNormDir = laneInfo.m_finalDirection;

                                if (((netManager.m_segments.m_buffer[otherSegmentId].m_flags
                                      & NetSegment.Flags.Invert)
                                     != NetSegment.Flags.None) ^ reverse)
                                {
                                    otherNormDir = NetInfo.InvertDirection(otherNormDir);
                                }

                                if (otherNormDir == normDir)
                                {
                                    SpeedLimitManager.Instance.SetSpeedLimit(
                                        otherSegmentId,
                                        laneInfo.m_finalDirection,
                                        speedLimitToSet.GameUnits);
                                }

                                return(true);
                            });
                        }
                    }

                    guiColor.a = 1f;
                    GUI.color  = guiColor;
                }
            }
        }
Esempio n. 5
0
        private bool DrawParkingRestrictionHandles(ushort segmentId,
                                                   bool clicked,
                                                   ref NetSegment segment,
                                                   bool viewOnly,
                                                   ref Vector3 camPos)
        {
            if (viewOnly && !Options.parkingRestrictionsOverlay)
            {
                return(false);
            }

            NetManager netManager = Singleton <NetManager> .instance;
            ParkingRestrictionsManager parkingManager = ParkingRestrictionsManager.Instance;
            bool hovered = false;

            // draw parking restriction signs over mean middle points of lane beziers
            if (!segmentCenterByDir.TryGetValue(
                    segmentId,
                    out Dictionary <NetInfo.Direction, Vector3> segCenter))
            {
                segCenter = new Dictionary <NetInfo.Direction, Vector3>();
                segmentCenterByDir.Add(segmentId, segCenter);
                TrafficManagerTool.CalculateSegmentCenterByDir(segmentId, segCenter);
            }

            foreach (KeyValuePair <NetInfo.Direction, Vector3> e in segCenter)
            {
                bool allowed = parkingManager.IsParkingAllowed(segmentId, e.Key);
                if (allowed && viewOnly)
                {
                    continue;
                }

                bool visible = MainTool.WorldToScreenPoint(e.Value, out Vector3 screenPos);

                if (!visible)
                {
                    continue;
                }

                float zoom        = (1.0f / (e.Value - camPos).magnitude) * 100f * MainTool.GetBaseZoom();
                float size        = (viewOnly ? 0.8f : 1f) * SIGN_SIZE * zoom;
                Color guiColor    = GUI.color;
                Rect  boundingBox = new Rect(
                    screenPos.x - (size / 2),
                    screenPos.y - (size / 2),
                    size,
                    size);

                if (Options.speedLimitsOverlay)
                {
                    boundingBox.y -= size + 10f;
                }

                bool hoveredHandle = !viewOnly && TrafficManagerTool.IsMouseOver(boundingBox);

                guiColor.a = TrafficManagerTool.GetHandleAlpha(hoveredHandle);

                if (hoveredHandle)
                {
                    // mouse hovering over sign
                    hovered = true;
                }

                GUI.color = guiColor;
                GUI.DrawTexture(boundingBox, RoadUITextures.ParkingRestrictionTextures[allowed]);

                if (hoveredHandle && clicked && !IsCursorInPanel() &&
                    parkingManager.ToggleParkingAllowed(segmentId, e.Key))
                {
                    allowed = !allowed;

                    if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
                    {
                        NetInfo.Direction normDir = e.Key;

                        if ((netManager.m_segments.m_buffer[segmentId].m_flags &
                             NetSegment.Flags.Invert) != NetSegment.Flags.None)
                        {
                            normDir = NetInfo.InvertDirection(normDir);
                        }

                        bool LaneVisitor(SegmentLaneVisitData data)
                        {
                            if (data.SegVisitData.Initial)
                            {
                                return(true);
                            }

                            bool reverse = data.SegVisitData.ViaStartNode ==
                                           data.SegVisitData.ViaInitialStartNode;

                            ushort  otherSegmentId   = data.SegVisitData.CurSeg.segmentId;
                            NetInfo otherSegmentInfo =
                                netManager.m_segments.m_buffer[otherSegmentId].Info;
                            byte laneIndex = data.CurLanePos.laneIndex;

                            NetInfo.Lane laneInfo = otherSegmentInfo.m_lanes[laneIndex];

                            NetInfo.Direction otherNormDir = laneInfo.m_finalDirection;
                            if (((netManager.m_segments.m_buffer[otherSegmentId].m_flags &
                                  NetSegment.Flags.Invert) != NetSegment.Flags.None) ^ reverse)
                            {
                                otherNormDir = NetInfo.InvertDirection(otherNormDir);
                            }

                            if (otherNormDir == normDir)
                            {
                                parkingManager.SetParkingAllowed(
                                    otherSegmentId,
                                    laneInfo.m_finalDirection,
                                    allowed);
                            }

                            return(true);
                        }

                        SegmentLaneTraverser.Traverse(
                            segmentId,
                            SegmentTraverser.TraverseDirection.AnyDirection,
                            SegmentTraverser.TraverseSide.AnySide,
                            SegmentLaneTraverser.LaneStopCriterion.LaneCount,
                            SegmentTraverser.SegmentStopCriterion.Junction,
                            ParkingRestrictionsManager.LANE_TYPES,
                            ParkingRestrictionsManager.VEHICLE_TYPES,
                            LaneVisitor);
                    }
                }

                guiColor.a = 1f;
                GUI.color  = guiColor;
            }

            return(hovered);
        }
Esempio n. 6
0
        public void ShowGUI(bool viewOnly)
        {
            try {
                TrafficLightSimulationManager tlsMan  = TrafficLightSimulationManager.Instance;
                TrafficPriorityManager        prioMan = TrafficPriorityManager.Instance;
                TrafficLightManager           tlm     = TrafficLightManager.Instance;

                bool clicked = !viewOnly?MainTool.CheckClicked() : false;

                var hoveredSegment = false;
                //Log.Message("_guiPrioritySigns called. num of prio segments: " + TrafficPriority.PrioritySegments.Count);

                HashSet <ushort> nodeIdsWithSigns = new HashSet <ushort>();
                foreach (ushort segmentId in currentPrioritySegmentIds)
                {
                    var trafficSegment = prioMan.TrafficSegments[segmentId];
                    if (trafficSegment == null)
                    {
                        continue;
                    }
                    SegmentGeometry geometry = SegmentGeometry.Get(segmentId);

                    prioritySegments[0] = null;
                    prioritySegments[1] = null;

                    if (tlsMan.GetNodeSimulation(trafficSegment.Node1) == null)
                    {
                        SegmentEnd tmpSeg1   = prioMan.GetPrioritySegment(trafficSegment.Node1, segmentId);
                        bool       startNode = geometry.StartNodeId() == trafficSegment.Node1;
                        if (tmpSeg1 != null && !geometry.IsOutgoingOneWay(startNode))
                        {
                            prioritySegments[0] = tmpSeg1;
                            nodeIdsWithSigns.Add(trafficSegment.Node1);
                            prioMan.AddPriorityNode(trafficSegment.Node1);
                        }
                    }
                    if (tlsMan.GetNodeSimulation(trafficSegment.Node2) == null)
                    {
                        SegmentEnd tmpSeg2   = prioMan.GetPrioritySegment(trafficSegment.Node2, segmentId);
                        bool       startNode = geometry.StartNodeId() == trafficSegment.Node2;
                        if (tmpSeg2 != null && !geometry.IsOutgoingOneWay(startNode))
                        {
                            prioritySegments[1] = tmpSeg2;
                            nodeIdsWithSigns.Add(trafficSegment.Node2);
                            prioMan.AddPriorityNode(trafficSegment.Node2);
                        }
                    }

                    //Log.Message("init ok");

                    foreach (var prioritySegment in prioritySegments)
                    {
                        if (prioritySegment == null)
                        {
                            continue;
                        }

                        var nodeId = prioritySegment.NodeId;
                        //Log.Message("_guiPrioritySigns: nodeId=" + nodeId);

                        var nodePositionVector3 = Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId].m_position;
                        var camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position;
                        var diff   = nodePositionVector3 - camPos;
                        if (diff.magnitude > TrafficManagerTool.PriorityCloseLod)
                        {
                            continue;                             // do not draw if too distant
                        }
                        if (Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startNode == (ushort)nodeId)
                        {
                            nodePositionVector3.x += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startDirection.x * 10f;
                            nodePositionVector3.y += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startDirection.y * 10f;
                            nodePositionVector3.z += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startDirection.z * 10f;
                        }
                        else
                        {
                            nodePositionVector3.x += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_endDirection.x * 10f;
                            nodePositionVector3.y += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_endDirection.y * 10f;
                            nodePositionVector3.z += Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_endDirection.z * 10f;
                        }

                        var nodeScreenPosition = Camera.main.WorldToScreenPoint(nodePositionVector3);
                        nodeScreenPosition.y = Screen.height - nodeScreenPosition.y;
                        if (nodeScreenPosition.z < 0)
                        {
                            continue;
                        }
                        var zoom            = 1.0f / diff.magnitude * 100f * MainTool.GetBaseZoom();
                        var size            = 110f * zoom;
                        var guiColor        = GUI.color;
                        var nodeBoundingBox = new Rect(nodeScreenPosition.x - size / 2, nodeScreenPosition.y - size / 2, size, size);
                        hoveredSegment = !viewOnly && TrafficManagerTool.IsMouseOver(nodeBoundingBox);

                        if (hoveredSegment)
                        {
                            // mouse hovering over sign
                            guiColor.a = 0.8f;
                        }
                        else
                        {
                            guiColor.a = 0.5f;
                            size       = 90f * zoom;
                        }
                        var nodeDrawingBox = new Rect(nodeScreenPosition.x - size / 2, nodeScreenPosition.y - size / 2, size, size);

                        GUI.color = guiColor;

                        bool setUndefinedSignsToMainRoad = false;
                        switch (prioritySegment.Type)
                        {
                        case SegmentEnd.PriorityType.Main:
                            GUI.DrawTexture(nodeDrawingBox, TrafficLightToolTextureResources.SignPriorityTexture2D);
                            if (clicked && hoveredSegment)
                            {
                                //Log._Debug("Click on node " + nodeId + ", segment " + segmentId + " to change prio type (1)");
                                //Log.Message("PrioritySegment.Type = Yield");
                                prioritySegment.Type        = SegmentEnd.PriorityType.Yield;
                                setUndefinedSignsToMainRoad = true;
                                clicked = false;
                            }
                            break;

                        case SegmentEnd.PriorityType.Yield:
                            GUI.DrawTexture(nodeDrawingBox, TrafficLightToolTextureResources.SignYieldTexture2D);
                            if (clicked && hoveredSegment)
                            {
                                //Log._Debug("Click on node " + nodeId + ", segment " + segmentId + " to change prio type (2)");
                                prioritySegment.Type        = SegmentEnd.PriorityType.Stop;
                                setUndefinedSignsToMainRoad = true;
                                clicked = false;
                            }

                            break;

                        case SegmentEnd.PriorityType.Stop:
                            GUI.DrawTexture(nodeDrawingBox, TrafficLightToolTextureResources.SignStopTexture2D);
                            if (clicked && hoveredSegment)
                            {
                                //Log._Debug("Click on node " + nodeId + ", segment " + segmentId + " to change prio type (3)");
                                prioritySegment.Type = SegmentEnd.PriorityType.Main;
                                clicked = false;
                            }
                            break;

                        case SegmentEnd.PriorityType.None:
                            if (viewOnly)
                            {
                                break;
                            }
                            GUI.DrawTexture(nodeDrawingBox, TrafficLightToolTextureResources.SignNoneTexture2D);

                            if (clicked && hoveredSegment)
                            {
                                //Log._Debug("Click on node " + nodeId + ", segment " + segmentId + " to change prio type (4)");
                                //Log.Message("PrioritySegment.Type = None");
                                prioritySegment.Type = GetNumberOfMainRoads(nodeId, ref Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId]) >= 2
                                                                                ? SegmentEnd.PriorityType.Yield
                                                                                : SegmentEnd.PriorityType.Main;
                                if (prioritySegment.Type == SegmentEnd.PriorityType.Yield)
                                {
                                    setUndefinedSignsToMainRoad = true;
                                }
                                clicked = false;
                            }
                            break;
                        }

                        if (setUndefinedSignsToMainRoad)
                        {
                            foreach (var otherPrioritySegment in prioMan.GetPrioritySegments(nodeId))
                            {
                                if (otherPrioritySegment.SegmentId == prioritySegment.SegmentId)
                                {
                                    continue;
                                }
                                if (otherPrioritySegment.Type == SegmentEnd.PriorityType.None)
                                {
                                    otherPrioritySegment.Type = SegmentEnd.PriorityType.Main;
                                }
                            }
                        }
                    }
                }

                if (viewOnly)
                {
                    return;
                }

                ushort hoveredExistingNodeId = 0;
                foreach (ushort nodeId in nodeIdsWithSigns)
                {
                    var nodePositionVector3 = Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId].m_position;
                    var camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position;
                    var diff   = nodePositionVector3 - camPos;
                    if (diff.magnitude > TrafficManagerTool.PriorityCloseLod)
                    {
                        continue;
                    }

                    // draw deletion button
                    var nodeScreenPosition = Camera.main.WorldToScreenPoint(nodePositionVector3);
                    nodeScreenPosition.y = Screen.height - nodeScreenPosition.y;
                    if (nodeScreenPosition.z < 0)
                    {
                        continue;
                    }
                    var zoom            = 1.0f / diff.magnitude * 100f * MainTool.GetBaseZoom();
                    var size            = 90f * zoom;
                    var nodeBoundingBox = new Rect(nodeScreenPosition.x - size / 2, nodeScreenPosition.y - size / 2, size, size);

                    var guiColor          = GUI.color;
                    var nodeCenterHovered = TrafficManagerTool.IsMouseOver(nodeBoundingBox);
                    if (nodeCenterHovered)
                    {
                        hoveredExistingNodeId = nodeId;
                        guiColor.a            = 0.8f;
                    }
                    else
                    {
                        guiColor.a = 0.5f;
                    }
                    GUI.color = guiColor;

                    GUI.DrawTexture(nodeBoundingBox, TrafficLightToolTextureResources.SignRemoveTexture2D);
                }

                // add a new or delete a priority segment node
                if (HoveredNodeId != 0 || hoveredExistingNodeId != 0)
                {
                    bool delete = false;
                    if (hoveredExistingNodeId != 0)
                    {
                        delete = true;
                    }

                    // determine if we may add new priority signs to this node
                    bool ok = false;
                    TrafficLightSimulation nodeSim = tlsMan.GetNodeSimulation(HoveredNodeId);
                    if ((Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_flags & NetNode.Flags.TrafficLights) == NetNode.Flags.None)
                    {
                        // no traffic light set
                        ok = true;
                    }
                    else if (nodeSim == null || !nodeSim.IsTimedLight())
                    {
                        ok = true;
                    }

                    if (!Flags.mayHaveTrafficLight(HoveredNodeId))
                    {
                        ok = false;
                    }

                    if (clicked)
                    {
                        Log._Debug("_guiPrioritySigns: hovered+clicked @ nodeId=" + HoveredNodeId + "/" + hoveredExistingNodeId + " ok=" + ok);

                        if (delete)
                        {
                            prioMan.RemovePrioritySegments(hoveredExistingNodeId);
                            RefreshCurrentPrioritySegmentIds();
                        }
                        else if (ok)
                        {
                            //if (!prioMan.IsPriorityNode(HoveredNodeId)) {
                            Log._Debug("_guiPrioritySigns: adding prio segments @ nodeId=" + HoveredNodeId);
                            tlsMan.RemoveNodeFromSimulation(HoveredNodeId, false, true);
                            tlm.RemoveTrafficLight(HoveredNodeId);
                            prioMan.AddPriorityNode(HoveredNodeId);
                            RefreshCurrentPrioritySegmentIds();
                            //}
                        }
                        else if (nodeSim != null && nodeSim.IsTimedLight())
                        {
                            MainTool.ShowTooltip(Translation.GetString("NODE_IS_TIMED_LIGHT"), Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId].m_position);
                        }
                    }
                }
            } catch (Exception e) {
                Log.Error(e.ToString());
            }
        }
        private bool drawSpeedLimitHandles(ushort segmentId, ref NetSegment segment, bool viewOnly, ref Vector3 camPos)
        {
            if (viewOnly && !Options.speedLimitsOverlay)
            {
                return(false);
            }

            Vector3    center     = segment.m_bounds.center;
            NetManager netManager = Singleton <NetManager> .instance;

            bool   hovered         = false;
            ushort speedLimitToSet = viewOnly ? (ushort)0 : SpeedLimitManager.Instance.AvailableSpeedLimits[curSpeedLimitIndex];

            bool showPerLane = showLimitsPerLane;

            if (!viewOnly)
            {
                showPerLane = showLimitsPerLane ^ (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl));
            }
            if (showPerLane)
            {
                // show individual speed limit handle per lane
                int numDirections;
                int numLanes = TrafficManagerTool.GetSegmentNumVehicleLanes(segmentId, null, out numDirections, SpeedLimitManager.VEHICLE_TYPES);

                NetInfo segmentInfo = segment.Info;
                Vector3 yu          = (segment.m_endDirection - segment.m_startDirection).normalized;
                Vector3 xu          = Vector3.Cross(yu, new Vector3(0, 1f, 0)).normalized;

                /*if ((segment.m_flags & NetSegment.Flags.Invert) == NetSegment.Flags.None) {
                 *      xu = -xu;
                 * }*/
                float   f    = viewOnly ? 4f : 7f;            // reserved sign size in game coordinates
                Vector3 zero = center - 0.5f * (float)(numLanes - 1 + numDirections - 1) * f * xu;

                uint            x                 = 0;
                var             guiColor          = GUI.color;
                IList <LanePos> sortedLanes       = Constants.ServiceFactory.NetService.GetSortedLanes(segmentId, ref segment, null, SpeedLimitManager.LANE_TYPES, SpeedLimitManager.VEHICLE_TYPES);
                bool            onlyMonorailLanes = sortedLanes.Count > 0;
                if (!viewOnly)
                {
                    foreach (LanePos laneData in sortedLanes)
                    {
                        byte         laneIndex = laneData.laneIndex;
                        NetInfo.Lane laneInfo  = segmentInfo.m_lanes[laneIndex];

                        if ((laneInfo.m_vehicleType & VehicleInfo.VehicleType.Monorail) == VehicleInfo.VehicleType.None)
                        {
                            onlyMonorailLanes = false;
                            break;
                        }
                    }
                }

                HashSet <NetInfo.Direction> directions = new HashSet <NetInfo.Direction>();
                int sortedLaneIndex = -1;
                foreach (LanePos laneData in sortedLanes)
                {
                    ++sortedLaneIndex;
                    uint laneId    = laneData.laneId;
                    byte laneIndex = laneData.laneIndex;

                    NetInfo.Lane laneInfo = segmentInfo.m_lanes[laneIndex];
                    if (!directions.Contains(laneInfo.m_finalDirection))
                    {
                        if (directions.Count > 0)
                        {
                            ++x;                             // space between different directions
                        }
                        directions.Add(laneInfo.m_finalDirection);
                    }

                    bool hoveredHandle = MainTool.DrawGenericSquareOverlayGridTexture(TextureResources.SpeedLimitTextures[SpeedLimitManager.Instance.GetCustomSpeedLimit(laneId)], camPos, zero, f, xu, yu, x, 0, speedLimitSignSize, !viewOnly, 0.5f, 0.8f);
                    if (!viewOnly && !onlyMonorailLanes && (laneInfo.m_vehicleType & VehicleInfo.VehicleType.Monorail) != VehicleInfo.VehicleType.None)
                    {
                        MainTool.DrawStaticSquareOverlayGridTexture(TextureResources.VehicleInfoSignTextures[ExtVehicleType.PassengerTrain], camPos, zero, f, xu, yu, x, 1, speedLimitSignSize, 0.5f);
                    }
                    if (hoveredHandle)
                    {
                        hovered = true;
                    }

                    if (hoveredHandle && Input.GetMouseButton(0) && !IsCursorInPanel())
                    {
                        SpeedLimitManager.Instance.SetSpeedLimit(segmentId, laneIndex, laneInfo, laneId, speedLimitToSet);

                        if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
                        {
                            SegmentLaneTraverser.Traverse(segmentId, SegmentTraverser.TraverseDirection.AnyDirection, SegmentTraverser.TraverseSide.AnySide, SegmentLaneTraverser.LaneStopCriterion.LaneCount, SegmentTraverser.SegmentStopCriterion.Junction, SpeedLimitManager.LANE_TYPES, SpeedLimitManager.VEHICLE_TYPES, delegate(SegmentLaneVisitData data) {
                                if (data.segVisitData.initial)
                                {
                                    return(true);
                                }

                                if (sortedLaneIndex != data.sortedLaneIndex)
                                {
                                    return(true);
                                }

                                Constants.ServiceFactory.NetService.ProcessSegment(data.segVisitData.curGeo.SegmentId, delegate(ushort curSegmentId, ref NetSegment curSegment) {
                                    NetInfo.Lane curLaneInfo = curSegment.Info.m_lanes[data.curLanePos.laneIndex];
                                    SpeedLimitManager.Instance.SetSpeedLimit(curSegmentId, data.curLanePos.laneIndex, curLaneInfo, data.curLanePos.laneId, speedLimitToSet);
                                    return(true);
                                });

                                return(true);
                            });
                        }
                    }

                    ++x;
                }
            }
            else
            {
                // draw speedlimits over mean middle points of lane beziers
                Dictionary <NetInfo.Direction, Vector3> segCenter;
                if (!segmentCenterByDir.TryGetValue(segmentId, out segCenter))
                {
                    segCenter = new Dictionary <NetInfo.Direction, Vector3>();
                    segmentCenterByDir.Add(segmentId, segCenter);
                    TrafficManagerTool.CalculateSegmentCenterByDir(segmentId, segCenter);
                }

                foreach (KeyValuePair <NetInfo.Direction, Vector3> e in segCenter)
                {
                    Vector3 screenPos;
                    bool    visible = MainTool.WorldToScreenPoint(e.Value, out screenPos);

                    if (!visible)
                    {
                        continue;
                    }

                    float zoom          = 1.0f / (e.Value - camPos).magnitude * 100f * MainTool.GetBaseZoom();
                    float size          = (viewOnly ? 0.8f : 1f) * speedLimitSignSize * zoom;
                    Color guiColor      = GUI.color;
                    Rect  boundingBox   = new Rect(screenPos.x - size / 2, screenPos.y - size / 2, size, size);
                    bool  hoveredHandle = !viewOnly && TrafficManagerTool.IsMouseOver(boundingBox);

                    if (hoveredHandle)
                    {
                        // mouse hovering over sign
                        hovered    = true;
                        guiColor.a = 0.8f;
                    }
                    else
                    {
                        guiColor.a = 0.5f;
                    }

                    GUI.color = guiColor;
                    GUI.DrawTexture(boundingBox, TextureResources.SpeedLimitTextures[SpeedLimitManager.Instance.GetCustomSpeedLimit(segmentId, e.Key)]);

                    if (hoveredHandle && Input.GetMouseButton(0) && !IsCursorInPanel())
                    {
                        // change the speed limit to the selected one
                        //Log._Debug($"Setting speed limit of segment {segmentId}, dir {e.Key.ToString()} to {speedLimitToSet}");
                        SpeedLimitManager.Instance.SetSpeedLimit(segmentId, e.Key, speedLimitToSet);

                        if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
                        {
                            NetInfo.Direction normDir = e.Key;
                            if ((netManager.m_segments.m_buffer[segmentId].m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None)
                            {
                                normDir = NetInfo.InvertDirection(normDir);
                            }

                            SegmentLaneTraverser.Traverse(segmentId, SegmentTraverser.TraverseDirection.AnyDirection, SegmentTraverser.TraverseSide.AnySide, SegmentLaneTraverser.LaneStopCriterion.LaneCount, SegmentTraverser.SegmentStopCriterion.Junction, SpeedLimitManager.LANE_TYPES, SpeedLimitManager.VEHICLE_TYPES, delegate(SegmentLaneVisitData data) {
                                if (data.segVisitData.initial)
                                {
                                    return(true);
                                }
                                bool reverse = data.segVisitData.viaStartNode == data.segVisitData.viaInitialStartNode;

                                ushort otherSegmentId    = data.segVisitData.curGeo.SegmentId;
                                NetInfo otherSegmentInfo = netManager.m_segments.m_buffer[otherSegmentId].Info;
                                uint laneId           = data.curLanePos.laneId;
                                byte laneIndex        = data.curLanePos.laneIndex;
                                NetInfo.Lane laneInfo = otherSegmentInfo.m_lanes[laneIndex];

                                NetInfo.Direction otherNormDir = laneInfo.m_finalDirection;
                                if ((netManager.m_segments.m_buffer[otherSegmentId].m_flags & NetSegment.Flags.Invert) != NetSegment.Flags.None ^
                                    reverse)
                                {
                                    otherNormDir = NetInfo.InvertDirection(otherNormDir);
                                }

                                if (otherNormDir == normDir)
                                {
                                    SpeedLimitManager.Instance.SetSpeedLimit(otherSegmentId, laneInfo.m_finalDirection, speedLimitToSet);
                                }

                                return(true);
                            });
                        }
                    }

                    guiColor.a = 1f;
                    GUI.color  = guiColor;
                }
            }
            return(hovered);
        }
        private bool drawSpeedLimitHandles(ushort segmentId, bool viewOnly, ref Vector3 camPos)
        {
            if (viewOnly && !Options.speedLimitsOverlay)
            {
                return(false);
            }

            // draw speedlimits over mean middle points of lane beziers
            if (!segmentCenterByDir.ContainsKey(segmentId))
            {
                segmentCenterByDir.Add(segmentId, new Dictionary <NetInfo.Direction, Vector3>());
                TrafficManagerTool.CalculateSegmentCenterByDir(segmentId, segmentCenterByDir[segmentId]);
            }

            bool hovered = false;

            foreach (KeyValuePair <NetInfo.Direction, Vector3> e in segmentCenterByDir[segmentId])
            {
                var screenPos = Camera.main.WorldToScreenPoint(e.Value);
                screenPos.y = Screen.height - screenPos.y;

                float zoom          = 1.0f / (e.Value - camPos).magnitude * 100f * MainTool.GetBaseZoom();
                float size          = speedLimitSignSize * zoom;
                Color guiColor      = GUI.color;
                Rect  boundingBox   = new Rect(screenPos.x - size / 2, screenPos.y - size / 2, size, size);
                bool  hoveredHandle = !viewOnly && TrafficManagerTool.IsMouseOver(boundingBox);

                if (hoveredHandle)
                {
                    // mouse hovering over sign
                    hovered    = true;
                    guiColor.a = 0.8f;
                }
                else
                {
                    guiColor.a = 0.5f;
                }

                GUI.color = guiColor;

                try {
                    GUI.DrawTexture(boundingBox, TrafficLightToolTextureResources.SpeedLimitTextures[SpeedLimitManager.Instance.GetCustomSpeedLimit(segmentId, e.Key)]);
                } catch (Exception ex) {
                    Log.Error("segment " + segmentId + " limit: " + SpeedLimitManager.Instance.GetCustomSpeedLimit(segmentId, e.Key) + ", ex: " + ex.ToString());
                }

                if (hoveredHandle && Input.GetMouseButton(0) && !IsCursorInPanel())
                {
                    // change the speed limit to the selected one
                    ushort speedLimitToSet = SpeedLimitManager.Instance.AvailableSpeedLimits[curSpeedLimitIndex];
                    //Log._Debug($"Setting speed limit of segment {segmentId}, dir {e.Key.ToString()} to {speedLimitToSet}");
                    SpeedLimitManager.Instance.SetSpeedLimit(segmentId, e.Key, speedLimitToSet);

                    // TODO use SegmentTraverser
                    if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
                    {
                        // apply new speed limit to connected segments
                        NetInfo         selectedSegmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].Info;
                        List <object[]> selectedSortedLanes = TrafficManagerTool.GetSortedVehicleLanes(segmentId, selectedSegmentInfo, null, VehicleInfo.VehicleType.Car | VehicleInfo.VehicleType.Tram | VehicleInfo.VehicleType.Metro | VehicleInfo.VehicleType.Train);                        // TODO refactor vehicle mask

                        LinkedList <ushort> nodesToProcess    = new LinkedList <ushort>();
                        HashSet <ushort>    processedNodes    = new HashSet <ushort>();
                        HashSet <ushort>    processedSegments = new HashSet <ushort>();
                        processedSegments.Add(SelectedSegmentId);

                        ushort selectedStartNodeId = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_startNode;
                        ushort selectedEndNodeId   = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].m_endNode;

                        if (selectedStartNodeId != 0)
                        {
                            nodesToProcess.AddFirst(selectedStartNodeId);
                        }
                        if (selectedEndNodeId != 0)
                        {
                            nodesToProcess.AddFirst(selectedEndNodeId);
                        }

                        while (nodesToProcess.First != null)
                        {
                            ushort nodeId = nodesToProcess.First.Value;
                            nodesToProcess.RemoveFirst();
                            processedNodes.Add(nodeId);

                            if (Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId].CountSegments() > 2)
                            {
                                continue;                                 // junction. stop.
                            }
                            // explore segments at node
                            for (var s = 0; s < 8; s++)
                            {
                                var otherSegmentId = Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId].GetSegment(s);

                                if (otherSegmentId <= 0 || processedSegments.Contains(otherSegmentId))
                                {
                                    continue;
                                }
                                processedSegments.Add(otherSegmentId);

                                NetInfo         segmentInfo = Singleton <NetManager> .instance.m_segments.m_buffer[otherSegmentId].Info;
                                List <object[]> sortedLanes = TrafficManagerTool.GetSortedVehicleLanes(otherSegmentId, segmentInfo, null, VehicleInfo.VehicleType.Car | VehicleInfo.VehicleType.Tram | VehicleInfo.VehicleType.Metro | VehicleInfo.VehicleType.Train);                                // TODO refactor vehicle mask

                                if (sortedLanes.Count == selectedSortedLanes.Count)
                                {
                                    // number of lanes matches selected segment
                                    for (int i = 0; i < sortedLanes.Count; ++i)
                                    {
                                        object[] selectedLaneData = selectedSortedLanes[i];
                                        object[] laneData         = sortedLanes[i];

                                        uint         selectedLaneId    = (uint)selectedLaneData[0];
                                        uint         selectedLaneIndex = (uint)selectedLaneData[2];
                                        NetInfo.Lane selectedLaneInfo  = segmentInfo.m_lanes[selectedLaneIndex];

                                        uint         laneId    = (uint)laneData[0];
                                        uint         laneIndex = (uint)laneData[2];
                                        NetInfo.Lane laneInfo  = segmentInfo.m_lanes[laneIndex];

                                        if (laneInfo.m_finalDirection == e.Key)
                                        {
                                            SpeedLimitManager.Instance.SetSpeedLimit(otherSegmentId, laneInfo.m_finalDirection, speedLimitToSet);
                                        }

                                        // apply restrictions of selected segment & lane
                                        //VehicleRestrictionsManager.SetAllowedVehicleTypes(otherSegmentId, segmentInfo, laneIndex, laneInfo, laneId, VehicleRestrictionsManager.GetAllowedVehicleTypes(SelectedSegmentId, selectedSegmentInfo, selectedLaneIndex, selectedLaneInfo));
                                    }

                                    // add nodes to explore
                                    ushort startNodeId = Singleton <NetManager> .instance.m_segments.m_buffer[otherSegmentId].m_startNode;
                                    ushort endNodeId   = Singleton <NetManager> .instance.m_segments.m_buffer[otherSegmentId].m_endNode;

                                    if (startNodeId != 0 && !processedNodes.Contains(startNodeId))
                                    {
                                        nodesToProcess.AddFirst(startNodeId);
                                    }
                                    if (endNodeId != 0 && !processedNodes.Contains(endNodeId))
                                    {
                                        nodesToProcess.AddFirst(endNodeId);
                                    }
                                }
                            }
                        }
                    }
                    //mouseClickProcessed = true;
                }

                guiColor.a = 1f;
                GUI.color  = guiColor;
            }
            return(hovered);
        }
        private bool drawSpeedLimitHandles(ushort segmentId, bool viewOnly)
        {
            if (!LoadingExtension.IsPathManagerCompatible)
            {
                return(false);
            }

            if (viewOnly && !Options.speedLimitsOverlay)
            {
                return(false);
            }

            // draw speedlimits over mean middle points of lane beziers
            if (!segmentCenterByDir.ContainsKey(segmentId))
            {
                segmentCenterByDir.Add(segmentId, new Dictionary <NetInfo.Direction, Vector3>());
                TrafficManagerTool.CalculateSegmentCenterByDir(segmentId, segmentCenterByDir[segmentId]);
            }

            bool hovered = false;

            foreach (KeyValuePair <NetInfo.Direction, Vector3> e in segmentCenterByDir[segmentId])
            {
                Vector3 signPos   = e.Value;
                var     screenPos = Camera.main.WorldToScreenPoint(signPos);
                screenPos.y = Screen.height - screenPos.y;
                if (screenPos.z < 0)
                {
                    return(false);
                }
                var camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position;
                var diff   = signPos - camPos;

                if (diff.magnitude > TrafficManagerTool.PriorityCloseLod)
                {
                    return(false);                    // do not draw if too distant
                }
                ItemClass connectionClass = Singleton <NetManager> .instance.m_segments.m_buffer[segmentId].Info.GetConnectionClass();
                if (!(connectionClass.m_service == ItemClass.Service.Road ||
                      (connectionClass.m_service == ItemClass.Service.PublicTransport && connectionClass.m_subService == ItemClass.SubService.PublicTransportTrain)))
                {
                    return(false);
                }

                var  zoom          = 1.0f / diff.magnitude * 100f * MainTool.GetBaseZoom();
                var  size          = speedLimitSignSize * zoom;
                var  guiColor      = GUI.color;
                var  boundingBox   = new Rect(screenPos.x - size / 2, screenPos.y - size / 2, size, size);
                bool hoveredHandle = !viewOnly && TrafficManagerTool.IsMouseOver(boundingBox);

                if (hoveredHandle)
                {
                    // mouse hovering over sign
                    hovered    = true;
                    guiColor.a = 0.8f;
                }
                else
                {
                    guiColor.a = 0.5f;
                }

                GUI.color = guiColor;

                try {
                    GUI.DrawTexture(boundingBox, TrafficLightToolTextureResources.SpeedLimitTextures[SpeedLimitManager.GetCustomSpeedLimit(segmentId, e.Key)]);
                } catch (Exception ex) {
                    Log.Error("segment " + segmentId + " limit: " + SpeedLimitManager.GetCustomSpeedLimit(segmentId, e.Key) + ", ex: " + ex.ToString());
                }

                if (hoveredHandle && Input.GetMouseButton(0))
                {
                    // change the speed limit to the selected one
                    ushort speedLimitToSet = SpeedLimitManager.AvailableSpeedLimits[curSpeedLimitIndex];
                    //Log._Debug($"Setting speed limit of segment {segmentId}, dir {e.Key.ToString()} to {speedLimitToSet}");
                    SpeedLimitManager.SetSpeedLimit(segmentId, e.Key, speedLimitToSet);
                    //mouseClickProcessed = true;
                }

                guiColor.a = 1f;
                GUI.color  = guiColor;
            }
            return(hovered);
        }