Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Dead end connection #1613

Merged
merged 25 commits into from
Sep 30, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
c62e1d8
dead end
kianzarrin Jul 14, 2022
e43fdda
kianzarrin Jul 15, 2022
60919b3
fill color for dead end lane curve
kianzarrin Jul 15, 2022
e41dd64
kianzarrin Jul 15, 2022
4f961a0
lane connection code cleanup
kianzarrin Jul 17, 2022
c533aae
kianzarrin Jul 17, 2022
58fa219
merge
kianzarrin Jul 17, 2022
e03aaef
kianzarrin Jul 17, 2022
1680031
kianzarrin Jul 17, 2022
c36c4b0
render dead ends for all nodes
kianzarrin Jul 17, 2022
b3bee3e
merge
kianzarrin Aug 12, 2022
bd1ab6a
fixed merge
kianzarrin Aug 12, 2022
2792e1a
don't create lane transition to same lane.
kianzarrin Aug 12, 2022
d8c4e6e
bug fix: don't remove dead end cache when connecting to dead end lane.
kianzarrin Aug 12, 2022
b418f7b
updated x texture and svg
kianzarrin Aug 14, 2022
a92d189
bugfix: load dead end conncetion
kianzarrin Aug 19, 2022
78816d9
bugfix: show dead end sign on one way roads when refreshing node.
kianzarrin Aug 19, 2022
9559eb6
pr fixes
kianzarrin Sep 7, 2022
23beaee
Merge branch 'master' into LCM-dead-end
kianzarrin Sep 7, 2022
eb48b16
Merge branch 'master' into LCM-dead-end
kianzarrin Sep 22, 2022
78fefac
fixed car dead ends are not rendered after reentering the tool
kianzarrin Sep 26, 2022
c207794
fixed hiding lane connections that would be removed when hovering ove…
kianzarrin Sep 26, 2022
34b4ee7
Merge branch 'master' into LCM-dead-end
kianzarrin Sep 29, 2022
f6e8709
reset selected lane when resting node to avoid minor visual glitch.
kianzarrin Sep 29, 2022
a9c4e95
reset lane arrows when clearing node lane connections.
kianzarrin Sep 29, 2022
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 12 additions & 0 deletions TLM/TLM/Manager/Impl/LaneArrowManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,18 @@ public void ResetLaneArrows(uint laneId) {
}
}

/// <summary>
/// Resets lane arrows to their default value for the given node
/// </summary>
public void ResetNodeLaneArrows(ushort nodeId) {
ref NetNode node = ref nodeId.ToNode();
for (int i = 0; i < 8; ++i) {
ushort segmentId = node.GetSegment(i);
bool startNode = segmentId.ToSegment().IsStartNode(nodeId);
LaneArrowManager.Instance.ResetLaneArrows(segmentId, startNode);
}
}

/// <summary>
/// Updates all road relevant segments so that the dedicated turning lane policy would take effect.
/// </summary>
Expand Down
2 changes: 2 additions & 0 deletions TLM/TLM/Manager/Impl/LaneConnection/LaneConnectionManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ static LaneConnectionManager() {

public static LaneConnectionManager Instance { get; }

public LaneConnectionSubManager SubManager(bool track) => track ? Track : Road;

public override void OnBeforeLoadData() {
base.OnBeforeLoadData();
Road.OnBeforeLoadData();
Expand Down
235 changes: 77 additions & 158 deletions TLM/TLM/Manager/Impl/LaneConnection/LaneConnectionSubManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -249,6 +249,7 @@ internal bool RemoveLaneConnection(uint sourceLaneId, uint targetLaneId, bool so
ushort targetSegmentId = targetLaneId.ToLane().m_segment;
ushort nodeId = sourceSegmentId.ToSegment().GetNodeId(sourceStartNode);
var result = connectionDataBase_.Disconnect(sourceLaneId, targetLaneId, nodeId);
AssertLane(sourceLaneId, sourceStartNode);

if (verbose_) {
Log._Debug($"LaneConnectionSubManager({Group}).RemoveLaneConnection({sourceLaneId}, {targetLaneId}, " +
Expand Down Expand Up @@ -298,6 +299,10 @@ internal void RemoveLaneConnectionsFromNode(ushort nodeId) {
}
}

if (Supports(LaneEndTransitionGroup.Road)) {
LaneArrowManager.Instance.ResetNodeLaneArrows(nodeId);
}

for (int i = 0; i < 8; ++i) {
ushort segmentId = node.GetSegment(i);
RoutingManager.Instance.RequestRecalculation(segmentId);
Expand Down Expand Up @@ -341,9 +346,6 @@ internal void RemoveLaneConnections(uint laneId,
/// <param name="sourceStartNode">The affected node</param>
/// <returns>true if any connection was added</returns>
internal bool AddLaneConnection(uint sourceLaneId, uint targetLaneId, bool sourceStartNode) {
if (sourceLaneId == targetLaneId) {
return false;
}

bool valid = ValidateLane(sourceLaneId) & ValidateLane(targetLaneId);
if (!valid) {
Expand Down Expand Up @@ -376,14 +378,17 @@ static bool IsDirectionValid(ref NetLane lane, NetInfo.Lane laneInfo, ushort nod
return dir.IsFlagSet(NetInfo.Direction.Backward);
}
}
canConnect =
IsDirectionValid(ref sourceNetLane, sourceLaneInfo, nodeId, true) &&
IsDirectionValid(ref targetNetLane, targetLaneInfo, nodeId, false);
canConnect = IsDirectionValid(ref sourceNetLane, sourceLaneInfo, nodeId, true);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ternary expression for the win

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

notice the &= operator. won't fit well with ternary.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

true! I didn't see that at first.
wouldn't it be better to encapsulate the logic in the isdirectionvalid method itself?
since the method with the change now only does a "90% job".

bool deadEnd = sourceLaneId == targetLaneId;
if (!deadEnd) {
canConnect &= IsDirectionValid(ref targetNetLane, targetLaneInfo, nodeId, false);
}

if (!canConnect) {
return false;
}

if (Group == LaneEndTransitionGroup.Track) {
if (!deadEnd && Group == LaneEndTransitionGroup.Track) {
bool targetStartnode = targetSegmentId.ToSegment().IsStartNode(nodeId);
canConnect = LaneConnectionManager.CheckSegmentsTurningAngle(
sourceSegmentId, sourceStartNode, targetSegmentId, targetStartnode);
Expand All @@ -392,8 +397,36 @@ static bool IsDirectionValid(ref NetLane lane, NetInfo.Lane laneInfo, ushort nod
}
}

var connections = GetLaneConnections(sourceLaneId, sourceStartNode);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this could be its own method right?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

what can be its own method?

Copy link
Contributor

@DaEgi01 DaEgi01 Aug 25, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

basically the whole block that was added.
than again, I can't think of a good name, probably because these are actually two different things that are happening here based on deadEnd. I'd do it the other way around.
if (deadEnd)
removeNonDeadEndConnections()
else
removeDeadEndConnection()
and move the laneId loop inside.

or something like that.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it would be two one line functions (unless if you count in the verbose log). Not sure this is a good idea.

if (verbose_) {
Log._Debug($"AddLaneConnection: {sourceLaneId}->{targetLaneId} at {nodeId} connections={connections.ToSTR()}");
}
if (connections != null) {
foreach (uint laneId in connections) {
LaneEnd key = new(laneId, nodeId);
if (deadEnd) {
if (laneId != sourceLaneId) {
// dead end lane connection cannot have other lane connections.
if (verbose_) {
Log._Debug($"making a dead end connection disconnecting {sourceLaneId}->{laneId} at {nodeId}");
}
connectionDataBase_.Disconnect(sourceLaneId, laneId, nodeId);
}
} else {
if (laneId == sourceLaneId) {
// if adding a new connection then remove the dead end connection.
if (verbose_) {
Log._Debug($"removing dead end connection for lane:{sourceLaneId} at node:{nodeId}");
}
connectionDataBase_.Disconnect(sourceLaneId, sourceLaneId, nodeId);
}
}
}
}

connectionDataBase_.ConnectTo(sourceLaneId, targetLaneId, nodeId);
Assert(AreLanesConnected(sourceLaneId, targetLaneId, sourceStartNode), $"AreLanesConnected({sourceLaneId}, {targetLaneId}, {sourceStartNode})");
AssertLane(sourceLaneId, sourceStartNode);

if (verbose_) {
Log._Debug($"LaneConnectionSubManager({Group}).AddLaneConnection({sourceLaneId}, " +
Expand Down Expand Up @@ -423,6 +456,16 @@ static bool IsDirectionValid(ref NetLane lane, NetInfo.Lane laneInfo, ushort nod
return true;
}

private void AssertLane(uint laneId, bool startNode) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As this function ends with Assert call, is that a debug assert? And in release will it do the calculations but no assert?
Declare this function as [Conditional("DEBUG")]?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

its only called when adding/removing lane connections so its not performance critical. therefore I decided to include it in release build. you never know .... it might help with debugging user errors.

Should I make it conditional?

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I mean the assert function is marked debug only. i believe it is. So in release this code does nothing, just calculates values and returns.

Copy link
Collaborator Author

@kianzarrin kianzarrin Aug 14, 2022

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Assert is not marked as debug.
AssertNotNone is the only one that is marked as debug. its inconsistent with all the rest of the assert functions.
but that does not matter. I think its a good idea to execute assert in release mode here.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I removed the [Conditional("DEBUG")] from AssertNotNone() and instead added #if DEBUG around the usage. so now its consistent

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

probably AssertDeadEndConnection would be a better method name.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think i should also add IsValidWithSegment() too. i mean if we are asserting stuff we might as well do it right.

Assert(laneId.ToLane().IsValidWithSegment(), $"IsValidWithSegment() faild for laneId:{laneId}");
var connections = GetLaneConnections(laneId, startNode);
if (connections != null && connections.Contains(laneId)) {
// dead end should only have one connection to itself.
ushort nodeId = laneId.ToLane().GetNodeId(startNode);
Assert(connections.Length == 1, $"connections for lane:{laneId} at node:{nodeId} = " + connections.ToSTR());
}
}

private void ReleasingSegment(ushort segmentId, ref NetSegment segment) {
if (verbose_) {
Log._Debug($"LaneConnectionSubManager({Group}).ReleasingSegment({segmentId}, isValid={segment.IsValid()}): " +
Expand Down Expand Up @@ -462,15 +505,6 @@ private void RecalculateLaneArrows(uint laneId, ushort nodeId, bool startNode) {
return;
}

if (!HasOutgoingConnections(laneId, startNode)) {
if (verbose_) {
Log._Debug($"LaneConnectionSubManager({Group}).RecalculateLaneArrows({laneId}, {nodeId}): " +
$"lane {laneId} does not have outgoing connections");
}

return;
}

if (nodeId == 0) {
if (verbose_) {
Log._Debug($"LaneConnectionSubManager({Group}).RecalculateLaneArrows({laneId}, {nodeId}): " +
Expand All @@ -480,7 +514,6 @@ private void RecalculateLaneArrows(uint laneId, ushort nodeId, bool startNode) {
return;
}

var arrows = LaneArrows.None;
ushort segmentId = laneId.ToLane().m_segment;

if (segmentId == 0) {
Expand Down Expand Up @@ -508,153 +541,43 @@ private void RecalculateLaneArrows(uint laneId, ushort nodeId, bool startNode) {
return;
}

IExtSegmentEndManager segEndMan = Constants.ManagerFactory.ExtSegmentEndManager;
ExtSegmentEnd segEnd = segEndMan.ExtSegmentEnds[segEndMan.GetIndex(segmentId, startNode)];

for (int i = 0; i < 8; ++i) {
ushort otherSegmentId = netNode.GetSegment(i);
if (otherSegmentId != 0) {
//TODO move the following into a function
ArrowDirection dir = segEndMan.GetDirection(ref segEnd, otherSegmentId);

if (verbose_) {
Log._Debug(
$"LaneConnectionSubManager({Group}).RecalculateLaneArrows({laneId}, {nodeId}): " +
$"processing connected segment {otherSegmentId}. dir={dir}");
}

// check if arrow has already been set for this direction
switch (dir) {
case ArrowDirection.Turn: {
if (LHT) {
if ((arrows & LaneArrows.Right) != LaneArrows.None) {
continue;
}
} else {
if ((arrows & LaneArrows.Left) != LaneArrows.None) {
continue;
}
}

break;
}

case ArrowDirection.Forward: {
if ((arrows & LaneArrows.Forward) != LaneArrows.None) {
continue;
}

break;
}

case ArrowDirection.Left: {
if ((arrows & LaneArrows.Left) != LaneArrows.None) {
continue;
}

break;
}

case ArrowDirection.Right: {
if ((arrows & LaneArrows.Right) != LaneArrows.None) {
continue;
}

break;
}

default: {
continue;
}
}

if (verbose_) {
Log._Debug(
$"LaneConnectionSubManager({Group}).RecalculateLaneArrows({laneId}, {nodeId}): " +
$"processing connected segment {otherSegmentId}: need to determine arrows");
}

bool addArrow = false;
uint curLaneId = otherSegmentId.ToSegment().m_lanes;

while (curLaneId != 0) {
if (verbose_) {
Log._Debug(
$"LaneConnectionSubManager({Group}).RecalculateLaneArrows({laneId}, {nodeId}): " +
$"processing connected segment {otherSegmentId}: checking lane {curLaneId}");
}

if (AreLanesConnected(laneId, curLaneId, startNode)) {
if (verbose_) {
Log._Debug(
$"LaneConnectionSubManager({Group}).RecalculateLaneArrows({laneId}, {nodeId}): " +
$"processing connected segment {otherSegmentId}: checking lane " +
$"{curLaneId}: lanes are connected");
}

addArrow = true;
break;
}

curLaneId = curLaneId.ToLane().m_nextLane;
}

if (verbose_) {
Log._Debug(
$"LaneConnectionSubManager({Group}).RecalculateLaneArrows({laneId}, {nodeId}): " +
$"processing connected segment {otherSegmentId}: finished processing " +
$"lanes. addArrow={addArrow} arrows (before)={arrows}");
}

if (!addArrow) {
continue;
}

switch (dir) {
case ArrowDirection.Turn: {
if (LHT) {
arrows |= LaneArrows.Right;
} else {
arrows |= LaneArrows.Left;
}

break;
}

case ArrowDirection.Forward: {
arrows |= LaneArrows.Forward;
break;
}

case ArrowDirection.Left: {
arrows |= LaneArrows.Left;
break;
}
var targetLaneIds = this.GetLaneConnections(laneId, startNode);
if (targetLaneIds.IsNullOrEmpty()) {
LaneArrowManager.Instance.ResetLaneArrows(laneId);
return;
}

case ArrowDirection.Right: {
arrows |= LaneArrows.Right;
break;
}
ref ExtSegmentEnd segEnd = ref ExtSegmentEndManager.Instance.ExtSegmentEnds[segEndMan.GetIndex(segmentId, startNode)];

default: {
continue;
}
}

if (verbose_) {
Log._Debug(
$"LaneConnectionSubManager({Group}).RecalculateLaneArrows({laneId}, {nodeId}): " +
$"processing connected segment {otherSegmentId}: arrows={arrows}");
}
var arrows = LaneArrows.None;
foreach (uint targetLaneId in targetLaneIds) {
if (targetLaneId != laneId) {
ArrowDirection dir = segEndMan.GetDirection(ref segEnd, targetLaneId.ToLane().m_segment);
arrows |= ToLaneArrows(dir);
}
}

if (verbose_) {
Log._Debug($"LaneConnectionSubManager({Group}).RecalculateLaneArrows({laneId}, {nodeId}): " +
$"setting lane arrows to {arrows}");
$"setting lane arrows to {arrows}");
}

LaneArrowManager.Instance.SetLaneArrows(laneId, arrows, true);

static LaneArrows ToLaneArrows(ArrowDirection dir) {
switch (dir) {
case ArrowDirection.Forward:
return LaneArrows.Forward;
case ArrowDirection.Left:
return LaneArrows.Left;
case ArrowDirection.Right:
return LaneArrows.Right;
case ArrowDirection.Turn:
return LaneArrows_Far;
default:
return LaneArrows.None;
}
}
}

internal void ResetLaneConnections() {
Expand Down Expand Up @@ -682,10 +605,6 @@ public bool LoadData(List<Configuration.LaneConnection> data) {
continue;
}

if (conn.sourceLaneId == conn.targetLaneId) {
continue;
}

ushort nodeId = sourceLane.GetNodeId(conn.sourceStartNode);
#if DEBUGLOAD
Log._Debug($"Loading lane connection: lane {conn.sourceLaneId} -> {conn.targetLaneId} @ node: {nodeId}");
Expand Down
6 changes: 4 additions & 2 deletions TLM/TLM/Manager/Impl/RoutingManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -647,7 +647,9 @@ void _ExtendedLogImpl(params object[] lines) => DetailLogger.LogDebug(
extendedLog?.Invoke(new { prevSegmentId, _ = "Exploring", nextSegmentId, nextLaneId, nextLaneIndex });

// next is compatible lane
if (IsSupported(nextLaneInfo) && (prevLaneInfo.m_vehicleType & nextLaneInfo.m_vehicleType) != 0) {
if (nextLaneId != prevLaneId &&
IsSupported(nextLaneInfo) &&
(prevLaneInfo.m_vehicleType & nextLaneInfo.m_vehicleType) != 0) {
extendedLog?.Invoke(new { _ = "vehicle type check passed for", nextLaneId, nextLaneIndex });

// next is incoming lane
Expand Down Expand Up @@ -920,7 +922,7 @@ void _ExtendedLogImpl(params object[] lines) => DetailLogger.LogDebug(

nextLaneId = nextLaneId.ToLane().m_nextLane;
++nextLaneIndex;
} // foreach lane
}

extendedLog?.Invoke(new { isNextSegmentValid, nextCompatibleTransitionDatas = nextCompatibleTransitionDataIndices?.ArrayToString() });

Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading