Ejemplo n.º 1
0
        public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            if (MainTool.GetToolController().IsInsideUI || !Cursor.visible)
            {
                return;
            }

            if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
            {
                // draw hovered segments
                if (HoveredSegmentId != 0)
                {
                    Color color = MainTool.GetToolColor(Input.GetMouseButton(0), false);
                    SegmentTraverser.Traverse(
                        HoveredSegmentId,
                        TraverseDirection.AnyDirection,
                        TraverseSide.Straight,
                        SegmentStopCriterion.None,
                        data => {
                        NetTool.RenderOverlay(
                            cameraInfo,
                            ref Singleton <NetManager> .instance.m_segments.m_buffer[
                                data.CurSeg.segmentId],
                            color,
                            color);
                        return(true);
                    });
                }
                else
                {
                    massEditMode = PrioritySignsMassEditMode.MainYield;
                }

                return;
            }

            massEditMode = PrioritySignsMassEditMode.MainYield;

            if (HoveredNodeId == SelectedNodeId)
            {
                return;
            }

            // no highlight for existing priority node in sign mode
            if (TrafficPriorityManager.Instance.HasNodePrioritySign(HoveredNodeId))
            {
                // Log._Debug($"PrioritySignsTool.RenderOverlay: HasNodePrioritySign({HoveredNodeId})=true");
                return;
            }

            if (!TrafficPriorityManager.Instance.MayNodeHavePrioritySigns(HoveredNodeId))
            {
                // Log._Debug($"PrioritySignsTool.RenderOverlay: MayNodeHavePrioritySigns({HoveredNodeId})=false");
                return;
            }

            MainTool.DrawNodeCircle(cameraInfo, HoveredNodeId, Input.GetMouseButton(0));
        }
Ejemplo n.º 2
0
 private void RenderSegmentsSide(RenderManager.CameraInfo cameraInfo)
 {
     if (!MultiSegmentMode)
     {
         RenderSegmentSideOverlay(cameraInfo, renderData_.SegmentId, renderData_.FinalDirection);
     }
     else
     {
         SegmentTraverser.Traverse(
             renderData_.SegmentId,
             SegmentTraverser.TraverseDirection.AnyDirection,
             SegmentTraverser.TraverseSide.AnySide,
             SegmentTraverser.SegmentStopCriterion.Junction,
             data => {
             NetInfo.Direction finalDirection = renderData_.FinalDirection;
             if (data.IsReversed(renderData_.SegmentId))
             {
                 finalDirection = NetInfo.InvertDirection(finalDirection);
             }
             RenderSegmentSideOverlay(cameraInfo, data.CurSeg.segmentId, finalDirection);
             return(true);
         });
     }
 }
        public override void OnPrimaryClickOverlay()
        {
            if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
            {
                if (HoveredSegmentId != 0)
                {
                    SelectedNodeId = 0;

                    PriorityType primaryPrioType   = PriorityType.None;
                    PriorityType secondaryPrioType = PriorityType.None;
                    switch (massEditMode)
                    {
                    case PrioritySignsMassEditMode.MainYield:
                        primaryPrioType   = PriorityType.Main;
                        secondaryPrioType = PriorityType.Yield;
                        break;

                    case PrioritySignsMassEditMode.MainStop:
                        primaryPrioType   = PriorityType.Main;
                        secondaryPrioType = PriorityType.Stop;
                        break;

                    case PrioritySignsMassEditMode.YieldMain:
                        primaryPrioType   = PriorityType.Yield;
                        secondaryPrioType = PriorityType.Main;
                        break;

                    case PrioritySignsMassEditMode.StopMain:
                        primaryPrioType   = PriorityType.Stop;
                        secondaryPrioType = PriorityType.Main;
                        break;

                    case PrioritySignsMassEditMode.Delete:
                    default:
                        break;
                    }

                    IExtSegmentEndManager segEndMan = Constants.ManagerFactory.ExtSegmentEndManager;
                    SegmentTraverser.Traverse(HoveredSegmentId, TraverseDirection.AnyDirection, TraverseSide.Straight, SegmentStopCriterion.None, delegate(SegmentVisitData data) {
                        foreach (bool startNode in Constants.ALL_BOOL)
                        {
                            TrafficPriorityManager.Instance.SetPrioritySign(data.curSeg.segmentId, startNode, primaryPrioType);
                            ushort nodeId        = Constants.ServiceFactory.NetService.GetSegmentNodeId(data.curSeg.segmentId, startNode);
                            ExtSegmentEnd curEnd = segEndMan.ExtSegmentEnds[segEndMan.GetIndex(data.curSeg.segmentId, startNode)];

                            for (int i = 0; i < 8; ++i)
                            {
                                ushort otherSegmentId = Singleton <NetManager> .instance.m_nodes.m_buffer[nodeId].GetSegment(i);
                                if (otherSegmentId == 0 || otherSegmentId == data.curSeg.segmentId)
                                {
                                    continue;
                                }

                                ArrowDirection dir = segEndMan.GetDirection(ref curEnd, otherSegmentId);
                                if (dir != ArrowDirection.Forward)
                                {
                                    TrafficPriorityManager.Instance.SetPrioritySign(otherSegmentId, (bool)Constants.ServiceFactory.NetService.IsStartNode(otherSegmentId, nodeId), secondaryPrioType);
                                }
                            }
                        }

                        return(true);
                    });

                    // cycle mass edit mode
                    massEditMode = (PrioritySignsMassEditMode)(((int)massEditMode + 1) % Enum.GetValues(typeof(PrioritySignsMassEditMode)).GetLength(0));

                    // update priority node cache
                    RefreshCurrentPriorityNodeIds();
                }
                return;
            }

            if (TrafficPriorityManager.Instance.HasNodePrioritySign(HoveredNodeId))
            {
                return;
            }

            if (!MayNodeHavePrioritySigns(HoveredNodeId))
            {
                return;
            }

            SelectedNodeId = HoveredNodeId;
            Log._Debug($"PrioritySignsTool.OnPrimaryClickOverlay: SelectedNodeId={SelectedNodeId}");
            // update priority node cache
            RefreshCurrentPriorityNodeIds();
        }
        public override void OnPrimaryClickOverlay()
        {
            if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift))
            {
                if (HoveredSegmentId != 0)
                {
                    SelectedNodeId = 0;

                    PriorityType primaryPrioType   = PriorityType.None;
                    PriorityType secondaryPrioType = PriorityType.None;
                    switch (massEditMode)
                    {
                    case PrioritySignsMassEditMode.MainYield:
                        primaryPrioType   = PriorityType.Main;
                        secondaryPrioType = PriorityType.Yield;
                        break;

                    case PrioritySignsMassEditMode.MainStop:
                        primaryPrioType   = PriorityType.Main;
                        secondaryPrioType = PriorityType.Stop;
                        break;

                    case PrioritySignsMassEditMode.YieldMain:
                        primaryPrioType   = PriorityType.Yield;
                        secondaryPrioType = PriorityType.Main;
                        break;

                    case PrioritySignsMassEditMode.StopMain:
                        primaryPrioType   = PriorityType.Stop;
                        secondaryPrioType = PriorityType.Main;
                        break;

                    case PrioritySignsMassEditMode.Delete:
                    default:
                        break;
                    }

                    SegmentTraverser.Traverse(HoveredSegmentId, TraverseDirection.AnyDirection, TraverseSide.Straight, SegmentStopCriterion.None, delegate(SegmentVisitData data) {
                        foreach (bool startNode in Constants.ALL_BOOL)
                        {
                            TrafficPriorityManager.Instance.SetPrioritySign(data.curGeo.SegmentId, startNode, primaryPrioType);

                            foreach (ushort otherSegmentId in data.curGeo.GetConnectedSegments(startNode))
                            {
                                if (!data.curGeo.IsStraightSegment(otherSegmentId, startNode))
                                {
                                    SegmentGeometry otherGeo = SegmentGeometry.Get(otherSegmentId);
                                    if (otherGeo == null)
                                    {
                                        continue;
                                    }
                                    TrafficPriorityManager.Instance.SetPrioritySign(otherSegmentId, otherGeo.StartNodeId() == data.curGeo.GetNodeId(startNode), secondaryPrioType);
                                }
                            }
                        }

                        return(true);
                    });

                    // cycle mass edit mode
                    massEditMode = (PrioritySignsMassEditMode)(((int)massEditMode + 1) % Enum.GetValues(typeof(PrioritySignsMassEditMode)).GetLength(0));

                    // update priority node cache
                    RefreshCurrentPriorityNodeIds();
                }
                return;
            }

            if (TrafficPriorityManager.Instance.HasNodePrioritySign(HoveredNodeId))
            {
                return;
            }

            if (!MayNodeHavePrioritySigns(HoveredNodeId))
            {
                return;
            }

            SelectedNodeId = HoveredNodeId;
            Log._Debug($"PrioritySignsTool.OnPrimaryClickOverlay: SelectedNodeId={SelectedNodeId}");
            // update priority node cache
            RefreshCurrentPriorityNodeIds();
        }
Ejemplo n.º 5
0
        public override void OnPrimaryClickOverlay()
        {
            bool ctrlDown  = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
            bool shiftDown = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);

            if (ctrlDown || shiftDown)
            {
                if (HoveredSegmentId == 0)
                {
                    return;
                }
                SelectedNodeId = 0;
            }

            // TODO provide revert/clear mode issue #568
            if (ctrlDown && shiftDown)
            {
                bool isRAbout = RoundaboutMassEdit.Instance.FixRabout(HoveredSegmentId);
                if (!isRAbout)
                {
                    PriorityRoad.FixRoad(HoveredSegmentId);
                }
                RefreshMassEditOverlay();
                return;
            }
            else if (ctrlDown)
            {
                PriorityRoad.FixJunction(HoveredNodeId);
                RefreshMassEditOverlay();
                return;
            }
            if (shiftDown)
            {
                var primaryPrioType   = PriorityType.None;
                var secondaryPrioType = PriorityType.None;

                switch (massEditMode)
                {
                case PrioritySignsMassEditMode.MainYield: {
                    primaryPrioType   = PriorityType.Main;
                    secondaryPrioType = PriorityType.Yield;
                    break;
                }

                case PrioritySignsMassEditMode.MainStop: {
                    primaryPrioType   = PriorityType.Main;
                    secondaryPrioType = PriorityType.Stop;
                    break;
                }

                case PrioritySignsMassEditMode.YieldMain: {
                    primaryPrioType   = PriorityType.Yield;
                    secondaryPrioType = PriorityType.Main;
                    break;
                }

                case PrioritySignsMassEditMode.StopMain: {
                    primaryPrioType   = PriorityType.Stop;
                    secondaryPrioType = PriorityType.Main;
                    break;
                }
                }

                IExtSegmentEndManager segEndMan = Constants.ManagerFactory.ExtSegmentEndManager;

                bool VisitorFun(SegmentVisitData data)
                {
                    foreach (bool startNode in Constants.ALL_BOOL)
                    {
                        TrafficPriorityManager.Instance.SetPrioritySign(
                            data.CurSeg.segmentId,
                            startNode,
                            primaryPrioType);
                        ushort nodeId = Constants.ServiceFactory.NetService.GetSegmentNodeId(
                            data.CurSeg.segmentId,
                            startNode);
                        ExtSegmentEnd curEnd = segEndMan.ExtSegmentEnds[
                            segEndMan.GetIndex(data.CurSeg.segmentId, startNode)];

                        for (int i = 0; i < 8; ++i)
                        {
                            ushort otherSegmentId = Singleton <NetManager> .instance.m_nodes
                                                    .m_buffer[nodeId]
                                                    .GetSegment(i);

                            if (otherSegmentId == 0 || otherSegmentId == data.CurSeg.segmentId)
                            {
                                continue;
                            }

                            ArrowDirection dir = segEndMan.GetDirection(
                                ref curEnd,
                                otherSegmentId);

                            if (dir != ArrowDirection.Forward)
                            {
                                TrafficPriorityManager.Instance.SetPrioritySign(
                                    otherSegmentId,
                                    (bool)Constants.ServiceFactory.NetService.IsStartNode(
                                        otherSegmentId,
                                        nodeId),
                                    secondaryPrioType);
                            }
                        }
                    }

                    return(true);
                }

                bool isRAbout = RoundaboutMassEdit.Instance.TraverseLoop(HoveredSegmentId, out var segmentList);
                if (isRAbout)
                {
                    SegmentTraverser.Traverse(segmentList, VisitorFun);
                }
                else
                {
                    SegmentTraverser.Traverse(
                        HoveredSegmentId,
                        TraverseDirection.AnyDirection,
                        TraverseSide.Straight,
                        SegmentStopCriterion.None,
                        VisitorFun);
                }

                // cycle mass edit mode
                massEditMode =
                    (PrioritySignsMassEditMode)(((int)massEditMode + 1) %
                                                Enum.GetValues(typeof(PrioritySignsMassEditMode))
                                                .GetLength(0));
            }
            else
            {
                if (TrafficPriorityManager.Instance.HasNodePrioritySign(HoveredNodeId))
                {
                    return;
                }

                if (!MayNodeHavePrioritySigns(HoveredNodeId))
                {
                    return;
                }

                SelectedNodeId = HoveredNodeId;
                Log._Debug($"PrioritySignsTool.OnPrimaryClickOverlay: SelectedNodeId={SelectedNodeId}");
            }

            // update priority node cache
            RefreshCurrentPriorityNodeIds();
        }
Ejemplo n.º 6
0
        public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            if (MainTool.GetToolController().IsInsideUI || !Cursor.visible)
            {
                return;
            }

            bool ctrlDown  = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
            bool shiftDown = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);

            MassEditOVerlay.Show = ctrlDown;

            if (ctrlDown)
            {
                massEditMode = PrioritySignsMassEditMode.MainYield;
            }

            if (HoveredSegmentId == 0)
            {
                if (shiftDown)
                {
                    massEditMode = PrioritySignsMassEditMode.MainYield;
                }
                return;
            }

            if (shiftDown)
            {
                bool  isRAbout = RoundaboutMassEdit.Instance.TraverseLoop(HoveredSegmentId, out var segmentList);
                Color color    = MainTool.GetToolColor(Input.GetMouseButton(0), false);
                if (isRAbout)
                {
                    foreach (uint segmentId in segmentList)
                    {
                        ref NetSegment seg = ref Singleton <NetManager> .instance.m_segments.m_buffer[segmentId];
                        NetTool.RenderOverlay(
                            cameraInfo,
                            ref seg,
                            color,
                            color);
                    } // end foreach
                }
                else
                {
                    SegmentTraverser.Traverse(
                        HoveredSegmentId,
                        TraverseDirection.AnyDirection,
                        TraverseSide.Straight,
                        SegmentStopCriterion.None,
                        data => {
                        NetTool.RenderOverlay(
                            cameraInfo,
                            ref Singleton <NetManager> .instance.m_segments.m_buffer[
                                data.CurSeg.segmentId],
                            color,
                            color);
                        return(true);
                    });
                }
                return;
            }
Ejemplo n.º 7
0
        public override void OnPrimaryClickOverlay()
        {
            if (ControlIsPressed || ShiftIsPressed)
            {
                if (HoveredSegmentId == 0)
                {
                    return;
                }
                SelectedNodeId = 0;
                MainTool.RequestOnscreenDisplayUpdate();
            }

            if (massEditMode == PrioritySignsMassEditMode.Undo)
            {
                record_?.Restore();
            }
            else if (ControlIsPressed && ShiftIsPressed)
            {
                Log.Info("Before FixRoundabout/FixRoad."); // log time for benchmarking.
                bool isRoundabout = RoundaboutMassEdit.Instance.FixRoundabout(
                    HoveredSegmentId, out record_);
                if (!isRoundabout)
                {
                    record_ = PriorityRoad.FixRoad(HoveredSegmentId);
                }
                // TODO: benchmark why bulk setup takes a long time.
                Log.Info("After FixRoundabout/FixRoad. Before RefreshMassEditOverlay"); // log time for benchmarking.
                RefreshMassEditOverlay();
                Log.Info("After RefreshMassEditOverlay.");                              // log time for benchmarking.
            }
            else if (ControlIsPressed)
            {
                record_ = new TrafficRulesRecord();
                (record_ as TrafficRulesRecord).AddNodeAndSegmentEnds(HoveredNodeId);
                PriorityRoad.FixHighPriorityJunction(HoveredNodeId);
            }
            else if (ShiftIsPressed)
            {
                bool isRoundabout = RoundaboutMassEdit.Instance.TraverseLoop(HoveredSegmentId, out var segmentList);
                if (!isRoundabout)
                {
                    var segments = SegmentTraverser.Traverse(
                        HoveredSegmentId,
                        TraverseDirection.AnyDirection,
                        TraverseSide.Straight,
                        SegmentStopCriterion.None,
                        (_) => true);
                    segmentList = new List <ushort>(segments);
                }

                PriorityRoad.FixPrioritySigns(massEditMode, segmentList);
                record_ = null;
            }
            else
            {
                if (TrafficPriorityManager.Instance.HasNodePrioritySign(HoveredNodeId))
                {
                    return;
                }

                if (!MayNodeHavePrioritySigns(HoveredNodeId))
                {
                    return;
                }

                SelectedNodeId = HoveredNodeId;
                MainTool.RequestOnscreenDisplayUpdate();
                // Log._Debug($"PrioritySignsTool.OnPrimaryClickOverlay: SelectedNodeId={SelectedNodeId}");
            }

            // cycle mass edit mode
            if (ControlIsPressed)
            {
                massEditMode =
                    massEditMode != PrioritySignsMassEditMode.MainYield ?
                    PrioritySignsMassEditMode.MainYield :
                    PrioritySignsMassEditMode.Undo;
            }
            else if (ShiftIsPressed)
            {
                massEditMode++;
                if (massEditMode > PrioritySignsMassEditMode.Max)
                {
                    massEditMode = PrioritySignsMassEditMode.Min;
                }
            }

            // refresh cache
            if (ControlIsPressed)
            {
                RefreshMassEditOverlay();
            }
            else
            {
                RefreshCurrentPriorityNodeIds();
            }
        }
Ejemplo n.º 8
0
        public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            if (MainTool.GetToolController().IsInsideUI || !Cursor.visible)
            {
                return;
            }

            ModifyMode mode = ModifyMode.None;

            MassEditOverlay.Show = ControlIsPressed;

            if (HoveredSegmentId == 0)
            {
                massEditMode = PrioritySignsMassEditMode.Min;
                return;
            }

            if (Shortcuts.ShiftIsPressed)
            {
                bool  isRoundabout = RoundaboutMassEdit.Instance.TraverseLoop(HoveredSegmentId, out var segmentList);
                Color color        = MainTool.GetToolColor(Input.GetMouseButton(0), false);
                if (isRoundabout)
                {
                    foreach (uint segmentId in segmentList)
                    {
                        ref NetSegment seg = ref Singleton <NetManager> .instance.m_segments.m_buffer[segmentId];
                        NetTool.RenderOverlay(
                            cameraInfo,
                            ref seg,
                            color,
                            color);
                    } // end foreach
                }
                else
                {
                    SegmentTraverser.Traverse(
                        HoveredSegmentId,
                        TraverseDirection.AnyDirection,
                        TraverseSide.Straight,
                        SegmentStopCriterion.None,
                        data => {
                        NetTool.RenderOverlay(
                            cameraInfo,
                            ref Singleton <NetManager> .instance.m_segments.m_buffer[
                                data.CurSeg.segmentId],
                            color,
                            color);
                        return(true);
                    });
                }
                if (!ControlIsPressed)
                {
                    mode = ModifyMode.PriorityRoad;
                }
                else if (!isRoundabout)
                {
                    mode = ModifyMode.HighPriorityRoad;
                }
                else
                {
                    mode = ModifyMode.Roundabout;
                }

                if (mode != PrevHoveredState.Mode || HoveredSegmentId != PrevHoveredState.SegmentId)
                {
                    massEditMode = PrioritySignsMassEditMode.Min;
                }
            }
Ejemplo n.º 9
0
        public override void RenderOverlay(RenderManager.CameraInfo cameraInfo)
        {
            if (MainTool.GetToolController().IsInsideUI || !Cursor.visible)
            {
                return;
            }

            ModifyMode mode = ModifyMode.None;

            MassEditOverlay.Show = ControlIsPressed;

            if (HoveredSegmentId == 0)
            {
                massEditMode = PrioritySignsMassEditMode.Min;
                return;
            }

            if (Shortcuts.ShiftIsPressed)
            {
                bool  isRoundabout = RoundaboutMassEdit.Instance.TraverseLoop(HoveredSegmentId, out var segmentList);
                Color color        = MainTool.GetToolColor(Input.GetMouseButton(0), false);
                if (isRoundabout)
                {
                    foreach (ushort segmentId in segmentList)
                    {
                        NetTool.RenderOverlay(
                            cameraInfo,
                            ref segmentId.ToSegment(),
                            color,
                            color);
                    } // end foreach
                }
                else
                {
                    SegmentTraverser.Traverse(
                        HoveredSegmentId,
                        TraverseDirection.AnyDirection,
                        TraverseSide.Straight,
                        SegmentStopCriterion.None,
                        data => {
                        NetTool.RenderOverlay(
                            cameraInfo,
                            ref data.CurSeg.segmentId.ToSegment(),
                            color,
                            color);
                        return(true);
                    });
                }
                if (!ControlIsPressed)
                {
                    mode = ModifyMode.PriorityRoad;
                }
                else if (!isRoundabout)
                {
                    mode = ModifyMode.HighPriorityRoad;
                }
                else
                {
                    mode = ModifyMode.Roundabout;
                }

                if (mode != PrevHoveredState.Mode || HoveredSegmentId != PrevHoveredState.SegmentId)
                {
                    massEditMode = PrioritySignsMassEditMode.Min;
                }
            }
            else if (ControlIsPressed)
            {
                Highlight.DrawNodeCircle(
                    cameraInfo: cameraInfo,
                    nodeId: HoveredNodeId,
                    warning: Input.GetMouseButton(0));

                mode = ModifyMode.HighPriorityJunction;

                if (mode != PrevHoveredState.Mode || HoveredNodeId != PrevHoveredState.NodeId)
                {
                    massEditMode = PrioritySignsMassEditMode.Min;
                }
            }
            else
            {
                massEditMode = PrioritySignsMassEditMode.Min;

                if (HoveredNodeId == SelectedNodeId)
                {
                    return;
                }

                // no highlight for existing priority node in sign mode
                if (TrafficPriorityManager.Instance.HasNodePrioritySign(HoveredNodeId))
                {
                    // Log._Debug($"PrioritySignsTool.RenderOverlay: HasNodePrioritySign({HoveredNodeId})=true");
                    return;
                }

                if (!TrafficPriorityManager.Instance.MayNodeHavePrioritySigns(HoveredNodeId))
                {
                    // Log._Debug($"PrioritySignsTool.RenderOverlay: MayNodeHavePrioritySigns({HoveredNodeId})=false");
                    return;
                }

                Highlight.DrawNodeCircle(
                    cameraInfo: cameraInfo,
                    nodeId: HoveredNodeId,
                    warning: Input.GetMouseButton(0));
            }

            PrevHoveredState.Mode      = mode;
            PrevHoveredState.SegmentId = HoveredSegmentId;
            PrevHoveredState.NodeId    = HoveredNodeId;
        }
Ejemplo n.º 10
0
        public override void OnPrimaryClickOverlay()
        {
            bool ctrlDown  = Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl);
            bool shiftDown = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);

            if (ctrlDown || shiftDown)
            {
                if (HoveredSegmentId == 0)
                {
                    return;
                }
                SelectedNodeId = 0;
            }

            // TODO provide revert/clear mode issue #568
            if (ctrlDown && shiftDown)
            {
                Log.Info("Before FixRoundabout/FixRoad."); // log time for benchmarking.
                bool isRoundabout = RoundaboutMassEdit.Instance.FixRoundabout(HoveredSegmentId);
                if (!isRoundabout)
                {
                    PriorityRoad.FixRoad(HoveredSegmentId);
                }
                Log.Info("After FixRoundabout/FixRoad. Before RefreshMassEditOverlay"); // log time for benchmarking.
                RefreshMassEditOverlay();
                Log.Info("After RefreshMassEditOverlay.");                              // log time for benchmarking.
                return;
            }
            else if (ctrlDown)
            {
                PriorityRoad.FixHighPriorityJunction(HoveredNodeId);
                RefreshMassEditOverlay();
                return;
            }
            if (shiftDown)
            {
                bool isRoundabout = RoundaboutMassEdit.Instance.TraverseLoop(HoveredSegmentId, out var segmentList);
                if (!isRoundabout)
                {
                    segmentList = SegmentTraverser.Traverse(
                        HoveredSegmentId,
                        TraverseDirection.AnyDirection,
                        TraverseSide.Straight,
                        SegmentStopCriterion.None,
                        (_) => true);
                }

                PriorityRoad.FixPrioritySigns(massEditMode, segmentList);

                // cycle mass edit mode
                massEditMode =
                    (PrioritySignsMassEditMode)(((int)massEditMode + 1) %
                                                Enum.GetValues(typeof(PrioritySignsMassEditMode))
                                                .GetLength(0));
            }
            else
            {
                if (TrafficPriorityManager.Instance.HasNodePrioritySign(HoveredNodeId))
                {
                    return;
                }

                if (!MayNodeHavePrioritySigns(HoveredNodeId))
                {
                    return;
                }

                SelectedNodeId = HoveredNodeId;
                Log._Debug($"PrioritySignsTool.OnPrimaryClickOverlay: SelectedNodeId={SelectedNodeId}");
            }

            // update priority node cache
            RefreshCurrentPriorityNodeIds();
        }