/// <summary> /// Entfernt alle LineChangePoints, die von nc ausgehen und evtl. eingehen /// </summary> /// <param name="nc">NodeConnection dessen ausgehende LineChangePoints gelöscht werden</param> /// <param name="removeOutgoingLineChangePoints">ausgehende LineChangePoints löschen</param> /// <param name="removeIncomingLineChangePoints">eingehende LineChangePoints löschen</param> public void RemoveLineChangePoints(NodeConnection nc, bool removeOutgoingLineChangePoints, bool removeIncomingLineChangePoints) { if (removeOutgoingLineChangePoints) { nc.ClearLineChangePoints(); } if (removeIncomingLineChangePoints) { foreach (NodeConnection otherNc in _connections) { otherNc.RemoveAllLineChangePointsTo(nc); } } }
/// <summary> /// Berechnet alle Spurwechselstellen der NodeConnection nc mit anderen NodeConnections /// </summary> /// <param name="nc">zu untersuchende NodeConnection</param> /// <param name="distanceBetweenChangePoints">Distanz zwischen einzelnen LineChangePoints (quasi Genauigkeit)</param> /// <param name="maxDistanceToOtherNodeConnection">maximale Entfernung zwischen zwei NodeConnections zwischen denen ein Spurwechsel stattfinden darf</param> public void FindLineChangePoints(NodeConnection nc, double distanceBetweenChangePoints, double maxDistanceToOtherNodeConnection) { nc.ClearLineChangePoints(); double currentArcPosition = distanceBetweenChangePoints/2; double delta = distanceBetweenChangePoints / 4; /* * TODO: Spurwechsel funktioniert soweit so gut. Einziges Manko ist der Spurwechsel über LineNodes hinweg: * * Zum einen, können so rote Ampeln überfahren werden und zum anderen, kommt es z.T. zu sehr komischen Situationen, wo * das spurwechselnde Auto irgendwie denkt es sei viel weiter vorne und so mittendrin wartet und erst weiterfährt, wenn * das Auto 20m weiter weg ist. * * Als workaround werden jetzt doch erstmal Spurwechsel kurz vor LineNodes verboten, auch wenn das eigentlich ja gerade * auch ein Ziel der hübschen Spurwechsel war. * */ // nur so lange suchen, wie die NodeConnection lang ist while (currentArcPosition < nc.lineSegment.length - distanceBetweenChangePoints/2) { Vector2 startl = nc.lineSegment.AtPosition(currentArcPosition - delta); Vector2 startr = nc.lineSegment.AtPosition(currentArcPosition + delta); Vector2 leftVector = nc.lineSegment.DerivateAtTime(nc.lineSegment.PosToTime(currentArcPosition - delta)).RotatedClockwise.Normalized; Vector2 rightVector = nc.lineSegment.DerivateAtTime(nc.lineSegment.PosToTime(currentArcPosition + delta)).RotatedCounterClockwise.Normalized; // Faule Implementierung: statt Schnittpunkt Gerade/Bezierkurve zu berechnen nutzen wir vorhandenen // Code und Berechnen den Schnittpunkt zwischen zwei Bezierkurven. // TODO: Sollte das hier zu langsam sein, muss eben neuer optimierter Code her für die Berechnung // von Schnittpunkten Gerade/Bezierkurve LineSegment leftLS = new LineSegment(0, startl, startl + 0.25 * maxDistanceToOtherNodeConnection * leftVector, startl + 0.75 * maxDistanceToOtherNodeConnection * leftVector, startl + maxDistanceToOtherNodeConnection * leftVector); LineSegment rightLS = new LineSegment(0, startr, startr + 0.25 * maxDistanceToOtherNodeConnection * rightVector, startr + 0.75 * maxDistanceToOtherNodeConnection * rightVector, startr + maxDistanceToOtherNodeConnection * rightVector); foreach (NodeConnection nc2 in _connections) { if (nc2.enableIncomingLineChange && (nc2.carsAllowed || nc2.busAllowed) && nc != nc2 && nc.startNode.networkLayer == nc2.startNode.networkLayer && nc.endNode.networkLayer == nc2.endNode.networkLayer) { // LINKS: Zeitparameterpaare ermitteln List<Pair<double>> intersectionTimes = CalculateIntersections(leftLS, nc2.lineSegment, 0d, 1d, 0d, 1d, 8, leftLS, nc2.lineSegment); if (intersectionTimes != null) { // Startposition NodeConnection.SpecificPosition start = new NodeConnection.SpecificPosition(currentArcPosition - delta, nc); // LineChangePoints erstellen foreach (Pair<double> p in intersectionTimes) { // Winkel überprüfen if (Vector2.AngleBetween(nc.lineSegment.DerivateAtTime(nc.lineSegment.PosToTime(currentArcPosition - delta)), nc2.lineSegment.DerivateAtTime(p.Right)) < Constants.maximumAngleBetweenConnectionsForLineChangePoint) { NodeConnection.SpecificPosition otherStart = new NodeConnection.SpecificPosition(nc2, p.Right); // Einfädelpunkt des Fahrzeugs bestimmen und evtl. auf nächste NodeConnection weiterverfolgen: double distance = (nc.lineSegment.AtPosition(currentArcPosition - delta) - nc2.lineSegment.AtTime(p.Right)).Abs; // Einfädelpunkt: double arcPositionTarget = nc2.lineSegment.TimeToArcPosition(p.Right) + 3 * distance; if (arcPositionTarget <= nc2.lineSegment.length) { NodeConnection.SpecificPosition target = new NodeConnection.SpecificPosition(arcPositionTarget, nc2); nc.AddLineChangePoint(new NodeConnection.LineChangePoint(start, target, otherStart)); } else { double diff = arcPositionTarget - nc2.lineSegment.length; foreach (NodeConnection nextNc in nc2.endNode.nextConnections) { if ( (diff <= nextNc.lineSegment.length) && (nextNc.enableIncomingLineChange && (nextNc.carsAllowed || nextNc.busAllowed)) && (nc != nextNc)) { NodeConnection.SpecificPosition target = new NodeConnection.SpecificPosition(diff, nextNc); nc.AddLineChangePoint(new NodeConnection.LineChangePoint(start, target, otherStart)); } } } break; } } } // RECHTS: Zeitparameterpaare ermitteln intersectionTimes = CalculateIntersections(rightLS, nc2.lineSegment, 0d, 1d, 0d, 1d, 8, leftLS, nc2.lineSegment); if (intersectionTimes != null) { // Startposition NodeConnection.SpecificPosition start = new NodeConnection.SpecificPosition(currentArcPosition + delta, nc); // LineChangePoints erstellen foreach (Pair<double> p in intersectionTimes) { // Winkel überprüfen if (Vector2.AngleBetween(nc.lineSegment.DerivateAtTime(nc.lineSegment.PosToTime(currentArcPosition + delta)), nc2.lineSegment.DerivateAtTime(p.Right)) < Constants.maximumAngleBetweenConnectionsForLineChangePoint) { NodeConnection.SpecificPosition otherStart = new NodeConnection.SpecificPosition(nc2, p.Right); // Einfädelpunkt des Fahrzeugs bestimmen und evtl. auf nächste NodeConnection weiterverfolgen: double distance = (nc.lineSegment.AtPosition(currentArcPosition + delta) - nc2.lineSegment.AtTime(p.Right)).Abs; // Einfädelpunkt: double arcPositionTarget = nc2.lineSegment.TimeToArcPosition(p.Right) + 3 * distance; if (arcPositionTarget <= nc2.lineSegment.length) { NodeConnection.SpecificPosition target = new NodeConnection.SpecificPosition(arcPositionTarget, nc2); nc.AddLineChangePoint(new NodeConnection.LineChangePoint(start, target, otherStart)); } else { double diff = arcPositionTarget - nc2.lineSegment.length; foreach (NodeConnection nextNc in nc2.endNode.nextConnections) { if ((diff <= nextNc.lineSegment.length) && (nextNc.enableIncomingLineChange && (nextNc.carsAllowed || nextNc.busAllowed)) && (nc != nextNc)) { NodeConnection.SpecificPosition target = new NodeConnection.SpecificPosition(diff, nextNc); nc.AddLineChangePoint(new NodeConnection.LineChangePoint(start, target, otherStart)); } } } break; } } } } } currentArcPosition += distanceBetweenChangePoints; } }