internal void RemoveSegmentEnd(SegmentEndGeometry segmentEndGeo, GeometryCalculationMode calcMode) { #if DEBUGGEO if (GlobalConfig.Instance.Debug.Switches[5]) { Log._Debug($">>> NodeGeometry: Remove segment end {segmentEndGeo.SegmentId} @ {NodeId}, calcMode? {calcMode}"); } #endif if (calcMode == GeometryCalculationMode.Init) { return; } if (!IsValid()) { //Log.Warning($"NodeGeometry: Trying to remove segment {segmentId} @ invalid node {NodeId}"); RemoveAllSegmentEnds(); return; } for (int i = 0; i < MAX_NUM_SEGMENTS; ++i) { if (segmentEndGeo.Equals(SegmentEndGeometries[i])) { SegmentEndGeometries[i] = null; } } if (calcMode == GeometryCalculationMode.Propagate) { RecalculateSegments(segmentEndGeo.SegmentId); } Recalculate(); }
/// <summary> /// Registers an observer. /// </summary> /// <param name="observer"></param> /// <returns>An unsubscriber</returns> /*public IDisposable Subscribe(IObserver<NodeGeometry> observer) { * try { * Monitor.Enter(Lock); * observers.Add(observer); * } finally { * Monitor.Exit(Lock); * } * return new GenericUnsubscriber<NodeGeometry>(observers, observer, Lock); * }*/ internal void AddSegmentEnd(SegmentEndGeometry segEndGeo, GeometryCalculationMode calcMode) { #if DEBUGGEO if (GlobalConfig.Instance.Debug.Switches[5]) { Log._Debug($">>> NodeGeometry: Add segment end {segEndGeo.SegmentId}, start? {segEndGeo.StartNode} @ node {NodeId}"); } #endif if (!IsValid()) { //Log.Error($"NodeGeometry: Trying to add segment {segmentId} @ invalid node {NodeId}"); Invalidate(); return; } bool found = false; int freeIndex = -1; for (int i = 0; i < MAX_NUM_SEGMENTS; ++i) { SegmentEndGeometry storedEndGeo = SegmentEndGeometries[i]; if (segEndGeo.Equals(storedEndGeo)) { SegmentEndGeometries[i] = segEndGeo; found = true; break; } else if (storedEndGeo == null && freeIndex < 0) { freeIndex = i; } } if (!found) { if (freeIndex >= 0) { SegmentEndGeometries[freeIndex] = segEndGeo; } else { Log.Error($"NodeGeometry.AddSegmentEnd: Detected inconsistency. Unable to add segment end {segEndGeo} to node {NodeId}. Maximum segment end capacity reached."); } } if (calcMode == GeometryCalculationMode.Propagate) { RecalculateSegments(segEndGeo.SegmentId); } if (!found && lastRemovedSegmentEndId != null) { CurrentSegmentReplacement.oldSegmentEndId = lastRemovedSegmentEndId; CurrentSegmentReplacement.newSegmentEndId = segEndGeo; lastRemovedSegmentEndId = null; } Recalculate(); }
internal void Recalculate(GeometryCalculationMode calcMode) { #if DEBUGGEO if (GlobalConfig.Instance.Debug.Switches[5]) { Log._Debug($">>> SegmentEndGeometry.Recalculate({calcMode}): seg. {SegmentId} @ node {NodeId()}"); } #endif ushort nodeIdBeforeRecalc = LastKnownNodeId; Cleanup(); if (!IsValid()) { if (calcMode == GeometryCalculationMode.Propagate && nodeIdBeforeRecalc != 0) { #if DEBUGGEO if (GlobalConfig.Instance.Debug.Switches[5]) { Log._Debug($"SegmentEndGeometry.Recalculate({calcMode}): seg. {SegmentId} is not valid. nodeIdBeforeRecalc={nodeIdBeforeRecalc}. Removing segment from node."); } #endif NodeGeometry.Get(nodeIdBeforeRecalc).RemoveSegmentEnd(this, GeometryCalculationMode.Propagate); } return; } //NetManager netManager = Singleton<NetManager>.instance; ushort nodeId = NodeId(); LastKnownNodeId = nodeId; bool oneway; bool outgoingOneWay; SegmentGeometry.calculateOneWayAtNode(SegmentId, nodeId, out oneway, out outgoingOneWay); OutgoingOneWay = outgoingOneWay; if (oneway && !OutgoingOneWay) { IncomingOneWay = true; } OnlyHighways = true; #if DEBUGGEO if (GlobalConfig.Instance.Debug.Switches[5]) { Log._Debug($"Checking if segment {SegmentId} is connected to highways only at node {NodeId()}. OnlyHighways={OnlyHighways}"); } #endif //ItemClass connectionClass = netManager.m_segments.m_buffer[SegmentId].Info.GetConnectionClass(); ushort firstClockwiseSegmentId = 0; bool hasOtherSegments = false; for (var s = 0; s < 8; s++) { ushort otherSegmentId = 0; Constants.ServiceFactory.NetService.ProcessNode(nodeId, delegate(ushort nId, ref NetNode node) { otherSegmentId = node.GetSegment(s); if (s == 0) { firstClockwiseSegmentId = otherSegmentId; } return(true); }); if (otherSegmentId == 0 || otherSegmentId == SegmentId || !SegmentGeometry.IsValid(otherSegmentId)) { continue; } /*ItemClass otherConnectionClass = Singleton<NetManager>.instance.m_segments.m_buffer[otherSegmentId].Info.GetConnectionClass(); * if (otherConnectionClass.m_service != connectionClass.m_service) * continue;*/ hasOtherSegments = true; // determine geometry bool otherIsOneWay; bool otherIsOutgoingOneWay; SegmentGeometry.calculateOneWayAtNode(otherSegmentId, nodeId, out otherIsOneWay, out otherIsOutgoingOneWay); bool otherIsHighway = SegmentGeometry.calculateIsHighway(otherSegmentId); #if DEBUGGEO if (GlobalConfig.Instance.Debug.Switches[5]) { Log._Debug($"Segment {SegmentId} is connected to segment {otherSegmentId} at node {NodeId()}. otherIsOneWay={otherIsOneWay} otherIsOutgoingOneWay={otherIsOutgoingOneWay} otherIsHighway={otherIsHighway}"); } #endif if (!otherIsHighway || !otherIsOneWay) { OnlyHighways = false; } if (IsRightSegment(SegmentId, otherSegmentId, nodeId)) { RightSegments[NumRightSegments++] = otherSegmentId; if (!otherIsOutgoingOneWay) { IncomingRightSegments[NumIncomingRightSegments++] = otherSegmentId; if (!otherIsOneWay) { OutgoingRightSegments[NumOutgoingRightSegments++] = otherSegmentId; } } else { OutgoingRightSegments[NumOutgoingRightSegments++] = otherSegmentId; } } else if (IsLeftSegment(SegmentId, otherSegmentId, nodeId)) { LeftSegments[NumLeftSegments++] = otherSegmentId; if (!otherIsOutgoingOneWay) { IncomingLeftSegments[NumIncomingLeftSegments++] = otherSegmentId; if (!otherIsOneWay) { OutgoingLeftSegments[NumOutgoingLeftSegments++] = otherSegmentId; } } else { OutgoingLeftSegments[NumOutgoingLeftSegments++] = otherSegmentId; } } else { StraightSegments[NumStraightSegments++] = otherSegmentId; if (!otherIsOutgoingOneWay) { IncomingStraightSegments[NumIncomingStraightSegments++] = otherSegmentId; if (!otherIsOneWay) { OutgoingStraightSegments[NumOutgoingStraightSegments++] = otherSegmentId; } } else { OutgoingStraightSegments[NumOutgoingStraightSegments++] = otherSegmentId; } } // reset highway lane arrows //Flags.removeHighwayLaneArrowFlagsAtSegment(otherSegmentId); // TODO refactor ConnectedSegments[NumConnectedSegments++] = otherSegmentId; } NumIncomingSegments = (byte)(NumIncomingLeftSegments + NumIncomingStraightSegments + NumIncomingRightSegments); NumOutgoingSegments = (byte)(NumOutgoingLeftSegments + NumOutgoingStraightSegments + NumOutgoingRightSegments); if (!hasOtherSegments) { #if DEBUGGEO if (GlobalConfig.Instance.Debug.Switches[5]) { Log._Debug($"Segment {SegmentId} is not connected to any other segments at node {NodeId()}."); } #endif OnlyHighways = false; } // propagate information to other segments if (calcMode == GeometryCalculationMode.Init || (calcMode == GeometryCalculationMode.Propagate && nodeIdBeforeRecalc != nodeId)) { if (calcMode == GeometryCalculationMode.Propagate && nodeIdBeforeRecalc != 0) { NodeGeometry.Get(nodeIdBeforeRecalc).RemoveSegmentEnd(this, GeometryCalculationMode.Propagate); } NodeGeometry.Get(nodeId).AddSegmentEnd(this, calcMode); } }