public override void OnActivate() { #if DEBUG bool logLaneConn = DebugSwitch.LaneConnections.Get(); if (logLaneConn) { Log._Debug("LaneConnectorTool: OnActivate"); } #endif SelectedNodeId = 0; selectedLaneEnd = null; hoveredLaneEnd = null; stayInLaneMode = StayInLaneMode.None; RefreshCurrentNodeMarkers(); }
public override void OnSecondaryClickOverlay() { #if DEBUG bool logLaneConn = DebugSwitch.LaneConnections.Get(); #else const bool logLaneConn = false; #endif if (IsCursorInPanel()) { return; } switch (GetSelectionMode()) { // also: case MarkerSelectionMode.None: default: { Log._DebugIf( logLaneConn, () => "LaneConnectorTool: OnSecondaryClickOverlay: nothing to do"); stayInLaneMode = StayInLaneMode.None; break; } case SelectionMode.SelectSource: { // deselect node Log._DebugIf( logLaneConn, () => "LaneConnectorTool: OnSecondaryClickOverlay: selected node id = 0"); SelectedNodeId = 0; break; } case SelectionMode.SelectTarget: { // deselect source marker Log._DebugIf( logLaneConn, () => "LaneConnectorTool: OnSecondaryClickOverlay: switch to selected source mode"); selectedLaneEnd = null; break; } } }
private bool CanConnect(LaneEnd source, LaneEnd target) { bool ret = source != target && source.IsSource && target.IsTarget; ret &= (target.VehicleType & source.VehicleType) != 0; bool IsRoad(LaneEnd laneEnd) => (laneEnd.LaneType & LaneArrowManager.LANE_TYPES) != 0 && (laneEnd.VehicleType & LaneArrowManager.VEHICLE_TYPES) != 0; // turning angle does not apply to roads. bool isRoad = IsRoad(source) && IsRoad(target); // checktrack turning angles are within bounds ret &= isRoad || CheckSegmentsTurningAngle( source.SegmentId, ref GetSeg(source.SegmentId), source.StartNode, target.SegmentId, ref GetSeg(target.SegmentId), target.StartNode); return(ret); }
public override void OnPrimaryClickOverlay() { #if DEBUG bool logLaneConn = DebugSwitch.LaneConnections.Get(); #else const bool logLaneConn = false; #endif Log._DebugIf( logLaneConn, () => $"LaneConnectorTool: OnPrimaryClickOverlay. SelectedNodeId={SelectedNodeId} " + $"SelectedSegmentId={SelectedSegmentId} HoveredNodeId={HoveredNodeId} " + $"HoveredSegmentId={HoveredSegmentId}"); if (IsCursorInPanel()) { return; } if (GetSelectionMode() == SelectionMode.None) { if (HoveredNodeId != 0) { Log._DebugIf( logLaneConn, () => "LaneConnectorTool: HoveredNode != 0"); if (NetManager.instance.m_nodes.m_buffer[HoveredNodeId].CountSegments() < 2) { // this node cannot be configured (dead end) Log._DebugIf( logLaneConn, () => "LaneConnectorTool: Node is a dead end"); SelectedNodeId = 0; selectedLaneEnd = null; stayInLaneMode = StayInLaneMode.None; return; } if (SelectedNodeId != HoveredNodeId) { Log._DebugIf( logLaneConn, () => $"Node {HoveredNodeId} has been selected. Creating markers."); // selected node has changed. create markers List <LaneEnd> laneEnds = GetLaneEnds( HoveredNodeId, ref Singleton <NetManager> .instance.m_nodes.m_buffer[HoveredNodeId]); if (laneEnds != null) { SelectedNodeId = HoveredNodeId; selectedLaneEnd = null; stayInLaneMode = StayInLaneMode.None; currentLaneEnds[SelectedNodeId] = laneEnds; } // this.allNodeMarkers[SelectedNodeId] = GetNodeMarkers(SelectedNodeId); } } else { Log._DebugIf( logLaneConn, () => $"LaneConnectorTool: Node {SelectedNodeId} has been deselected."); // click on free spot. deselect node SelectedNodeId = 0; selectedLaneEnd = null; stayInLaneMode = StayInLaneMode.None; return; } } if (hoveredLaneEnd == null) { return; } //----------------------------------- // Hovered Marker //----------------------------------- stayInLaneMode = StayInLaneMode.None; Log._DebugIf( logLaneConn, () => $"LaneConnectorTool: hoveredMarker != null. selMode={GetSelectionMode()}"); // hovered marker has been clicked if (GetSelectionMode() == SelectionMode.SelectSource) { // select source marker selectedLaneEnd = hoveredLaneEnd; Log._DebugIf( logLaneConn, () => "LaneConnectorTool: set selected marker"); } else if (GetSelectionMode() == SelectionMode.SelectTarget) { // select target marker // bool success = false; if (LaneConnectionManager.Instance.RemoveLaneConnection( selectedLaneEnd.LaneId, hoveredLaneEnd.LaneId, selectedLaneEnd.StartNode)) { // try to remove connection selectedLaneEnd.ConnectedLaneEnds.Remove(hoveredLaneEnd); Log._DebugIf( logLaneConn, () => $"LaneConnectorTool: removed lane connection: {selectedLaneEnd.LaneId}, " + $"{hoveredLaneEnd.LaneId}"); // success = true; } else if (LaneConnectionManager.Instance.AddLaneConnection( selectedLaneEnd.LaneId, hoveredLaneEnd.LaneId, selectedLaneEnd.StartNode)) { // try to add connection selectedLaneEnd.ConnectedLaneEnds.Add(hoveredLaneEnd); Log._DebugIf( logLaneConn, () => $"LaneConnectorTool: added lane connection: {selectedLaneEnd.LaneId}, " + $"{hoveredLaneEnd.LaneId}"); // success = true; } /*if (success) { * // connection has been modified. switch back to source marker selection * Log._Debug($"LaneConnectorTool: switch back to source marker selection"); * selectedMarker = null; * selMode = MarkerSelectionMode.SelectSource; * }*/ } }
public override void RenderOverlay(RenderManager.CameraInfo cameraInfo) { // Log._Debug($"LaneConnectorTool: RenderOverlay. SelectedNodeId={SelectedNodeId} // SelectedSegmentId={SelectedSegmentId} HoveredNodeId={HoveredNodeId} // HoveredSegmentId={HoveredSegmentId} IsInsideUI={MainTool.GetToolController().IsInsideUI}"); // draw lane markers and connections hoveredLaneEnd = null; ShowOverlay(false, cameraInfo); // draw bezier from source marker to mouse position in target marker selection if (SelectedNodeId != 0) { if (GetSelectionMode() == SelectionMode.SelectTarget) { Vector3 selNodePos = NetManager.instance.m_nodes.m_buffer[SelectedNodeId].m_position; // Draw a currently dragged curve var pos = HitPos; if (hoveredLaneEnd == null) { float hitH = TrafficManagerTool.GetAccurateHitHeight(); pos.y = hitH; // fix height. float mouseH = MousePosition.y; if (hitH < mouseH - TrafficManagerTool.MAX_HIT_ERROR) { // for metros lane curve is projected on the ground. pos = MousePosition; } } else { // snap to hovered: pos = hoveredLaneEnd.NodeMarker.TerrainPosition; } DrawLaneCurve( cameraInfo, selectedLaneEnd.NodeMarker.TerrainPosition, pos, selNodePos, Color.Lerp(selectedLaneEnd.Color, Color.white, 0.33f), Color.white, size: 0.11f); } bool deleteAll = (frameClearPressed > 0) && ((Time.frameCount - frameClearPressed) < 20); // 0.33 sec NetNode[] nodesBuffer = Singleton <NetManager> .instance.m_nodes.m_buffer; // Must press Shift+S (or another shortcut) within last 20 frames for this to work bool stayInLane = (frameStayInLanePressed > 0) && ((Time.frameCount - frameStayInLanePressed) < 20) && // 0.33 sec (nodesBuffer[SelectedNodeId].CountSegments() == 2); if (stayInLane) { frameStayInLanePressed = 0; // not pressed anymore (consumed) deleteAll = true; } if (deleteAll) { frameClearPressed = 0; // consumed // remove all connections at selected node LaneConnectionManager.Instance.RemoveLaneConnectionsFromNode(SelectedNodeId); RefreshCurrentNodeMarkers(SelectedNodeId); } if (stayInLane) { // "stay in lane" switch (stayInLaneMode) { case StayInLaneMode.None: { stayInLaneMode = StayInLaneMode.Both; break; } case StayInLaneMode.Both: { stayInLaneMode = StayInLaneMode.Forward; break; } case StayInLaneMode.Forward: { stayInLaneMode = StayInLaneMode.Backward; break; } case StayInLaneMode.Backward: { stayInLaneMode = StayInLaneMode.None; break; } } if (stayInLaneMode != StayInLaneMode.None) { selectedLaneEnd = null; StayInLane(SelectedNodeId, stayInLaneMode); RefreshCurrentNodeMarkers(SelectedNodeId); } } // if stay in lane } // if selected node if ((GetSelectionMode() == SelectionMode.None) && (HoveredNodeId != 0)) { // draw hovered node MainTool.DrawNodeCircle(cameraInfo, HoveredNodeId, Input.GetMouseButton(0)); } }
private void ShowOverlay(bool viewOnly, RenderManager.CameraInfo cameraInfo) { if (viewOnly && !(Options.connectedLanesOverlay || PrioritySignsTool.MassEditOVerlay.IsActive)) { return; } NetManager netManager = Singleton <NetManager> .instance; Vector3 camPos = Singleton <SimulationManager> .instance.m_simulationView.m_position; // Bounds bounds = new Bounds(Vector3.zero, Vector3.one); Camera currentCamera = Camera.main; // Check if camera pos/angle has changed then re-filter the visible nodes // Assumption: The states checked in this loop don't change while the tool is active var currentCameraState = new CameraTransformValue(currentCamera); if (!LastCachedCamera.Equals(currentCameraState)) { CachedVisibleNodeIds.Clear(); LastCachedCamera = currentCameraState; for (uint nodeId = 1; nodeId < NetManager.MAX_NODE_COUNT; ++nodeId) { if (!Constants.ServiceFactory.NetService.IsNodeValid((ushort)nodeId)) { continue; } //--------------------------- // Check the connection class //--------------------------- // TODO refactor connection class check ItemClass connectionClass = NetManager.instance.m_nodes.m_buffer[nodeId].Info.GetConnectionClass(); if ((connectionClass == null) || !((connectionClass.m_service == ItemClass.Service.Road) || ((connectionClass.m_service == ItemClass.Service.PublicTransport) && ((connectionClass.m_subService == ItemClass.SubService.PublicTransportTrain) || (connectionClass.m_subService == ItemClass.SubService.PublicTransportMetro) || (connectionClass.m_subService == ItemClass.SubService.PublicTransportMonorail))))) { continue; } //-------------------------- // Check the camera distance //-------------------------- Vector3 diff = NetManager.instance.m_nodes.m_buffer[nodeId].m_position - camPos; if (diff.sqrMagnitude > TrafficManagerTool.MAX_OVERLAY_DISTANCE_SQR) { continue; // do not draw if too distant } // Add CachedVisibleNodeIds.Add(nodeId); } } for (int cacheIndex = CachedVisibleNodeIds.Size - 1; cacheIndex >= 0; cacheIndex--) { var nodeId = CachedVisibleNodeIds.Values[cacheIndex]; bool hasMarkers = currentLaneEnds.TryGetValue((ushort)nodeId, out List <LaneEnd> laneEnds); if (!viewOnly && (GetSelectionMode() == SelectionMode.None)) { MainTool.DrawNodeCircle( cameraInfo, (ushort)nodeId, DefaultLaneEndColor, true); } if (!hasMarkers) { continue; } foreach (LaneEnd laneEnd in laneEnds) { if (!Constants.ServiceFactory.NetService.IsLaneValid(laneEnd.LaneId)) { continue; } if (laneEnd != selectedLaneEnd) { foreach (LaneEnd targetLaneEnd in laneEnd.ConnectedLaneEnds) { // render lane connection from laneEnd to targetLaneEnd if (!Constants.ServiceFactory.NetService.IsLaneValid(targetLaneEnd.LaneId)) { continue; } DrawLaneCurve( cameraInfo, laneEnd.NodeMarker.TerrainPosition, targetLaneEnd.NodeMarker.TerrainPosition, NetManager.instance.m_nodes.m_buffer[nodeId].m_position, laneEnd.Color, Color.black); } } if (viewOnly || (nodeId != SelectedNodeId)) { continue; } bool drawMarker = false; bool SourceMode = GetSelectionMode() == SelectionMode.SelectSource; bool TargetMode = GetSelectionMode() == SelectionMode.SelectTarget; if (SourceMode & laneEnd.IsSource) { // draw source marker in source selection mode, // make exception for markers that have no target: foreach (var targetLaneEnd in laneEnds) { if (CanConnect(laneEnd, targetLaneEnd)) { drawMarker = true; break; } } } else if (TargetMode) { // selected source marker in target selection mode drawMarker = selectedLaneEnd == laneEnd || CanConnect(selectedLaneEnd, laneEnd); } // highlight hovered marker and selected marker if (drawMarker) { bool markerIsHovered = false; if (hoveredLaneEnd == null) { float hitH = TrafficManagerTool.GetAccurateHitHeight(); markerIsHovered = laneEnd.IntersectRay(); if (markerIsHovered) { hoveredLaneEnd = laneEnd; } } bool isTarget = selectedLaneEnd != null && laneEnd != selectedLaneEnd; var color = isTarget ? Color.white : laneEnd.Color; bool highlightMarker = laneEnd == selectedLaneEnd || markerIsHovered; laneEnd.RenderOverlay(cameraInfo, color, highlightMarker); } // if drawMarker if (selectedLaneEnd != null) { // lane curves for selectedMarker will be drawn last to // be on the top of other lane markers. foreach (LaneEnd targetLaneEnd in selectedLaneEnd.ConnectedLaneEnds) { if (!Constants.ServiceFactory.NetService.IsLaneValid(targetLaneEnd.LaneId)) { continue; } DrawLaneCurve( cameraInfo, selectedLaneEnd.NodeMarker.TerrainPosition, targetLaneEnd.NodeMarker.TerrainPosition, NetManager.instance.m_nodes.m_buffer[nodeId].m_position, selectedLaneEnd.Color, Color.grey, size: 0.18f // Embolden ); } // end foreach selectedMarker.ConnectedMarkers } // end if selectedMarker != null } // end foreach lanemarker in node markers } // end for node in all nodes }