Skip to content

Commit 78a5d8e

Browse files
committed
fixed regression: wide angle sharp corners
1 parent 84f2d5f commit 78a5d8e

3 files changed

Lines changed: 112 additions & 6 deletions

File tree

NodeController/NodeController.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
<Product>NodeController</Product>
88
<Copyright>Copyright © 2020</Copyright>
99
<Deterministic>false</Deterministic>
10-
<AssemblyVersion>2.10.1.*</AssemblyVersion>
10+
<AssemblyVersion>2.10.2.*</AssemblyVersion>
1111
<FileAlignment>512</FileAlignment>
1212
<LangVersion>latest</LangVersion>
1313
<DebugType>full</DebugType>

NodeController/Patches/Corner/CalculateCorner_MainPatch.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -106,6 +106,9 @@ public static void Postfix(
106106
ushort segmentID, bool start, bool leftSide,
107107
ref Vector3 cornerPos, ref Vector3 cornerDirection) {
108108
try {
109+
CalculateCorner_SharpPatch.Sharpen2(
110+
segmentId1: segmentID, startNode: start, leftSide: leftSide,
111+
cornerPos: ref cornerPos, cornerDirection: ref cornerDirection);
109112

110113
SegmentEndData data = SegmentEndManager.Instance.GetAt(segmentID, start);
111114
Assertion.AssertNotNull(NCSettings.GameConfig, "Settings.GameConfig");

NodeController/Patches/Corner/CalculateCorner_SharpPatch.cs

Lines changed: 108 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,17 @@
11
namespace NodeController.Patches.Corner;
2+
3+
using ColossalFramework.Math;
24
using HarmonyLib;
35
using KianCommons;
6+
using KianCommons.Math;
47
using KianCommons.Patches;
58
using KianCommons.Plugins;
69
using System.Collections.Generic;
710
using System.Linq;
811
using System.Reflection;
912
using System.Reflection.Emit;
1013
using UnityEngine;
14+
using static ColossalFramework.Math.VectorUtils;
1115

1216
[HarmonyPatch]
1317
static class CalculateCorner_SharpPatch {
@@ -39,6 +43,7 @@ static IEnumerable<CodeInstruction> Transpiler(
3943
var codes = instructions.ToList();
4044
MethodInfo mMax = typeof(Mathf).GetMethod<Max>(throwOnError: true);
4145
MethodInfo mModifySharpness = typeof(CalculateCorner_SharpPatch).GetMethod(nameof(ModifySharpness), throwOnError: true);
46+
MethodInfo mModify140 = typeof(CalculateCorner_SharpPatch).GetMethod(nameof(Modify140), throwOnError: true);
4247

4348
int iLoadSharpness = codes.Search(c => c.LoadsConstant(2f), count: 3);
4449

@@ -49,18 +54,116 @@ static IEnumerable<CodeInstruction> Transpiler(
4954
new CodeInstruction(OpCodes.Call, mModifySharpness),
5055
});
5156

57+
const int locLessThan140 = 27;
58+
int iStoreLessThan140 = codes.Search(c => c.IsStLoc(locLessThan140));
59+
codes.InsertInstructions(iStoreLessThan140, // insert before
60+
new[] {
61+
TranspilerUtils.GetLDArg(original, "ignoreSegmentID"),
62+
TranspilerUtils.GetLDArg(original, "startNodeID"),
63+
new CodeInstruction(OpCodes.Call, mModify140),
64+
});
65+
5266
return codes;
5367

5468
}
5569

5670
public static float ModifySharpness(float sharpness, ushort segmentId, ushort nodeId) {
57-
var data = SegmentEndManager.Instance.GetAt(segmentID: segmentId, nodeID: nodeId);
58-
bool sharp = data?.SharpCorners ?? nodeId.ToNode().Info.GetARSharpCorners();
59-
if (sharp) {
71+
if (IsSharp(segmentId, nodeId)) {
6072
const float OFFSET_SAFETYNET = 0.02f;
61-
sharpness = OFFSET_SAFETYNET;
73+
return OFFSET_SAFETYNET;
74+
} else {
75+
return sharpness;
76+
}
77+
}
78+
79+
public static bool Modify140(bool angle140, ushort segmentId, ushort nodeId) {
80+
if (IsSharp(segmentId, nodeId)) {
81+
return true;
82+
} else {
83+
return angle140;
6284
}
63-
return sharpness;
6485
}
6586

87+
private static bool IsSharp(ushort segmentId, ushort nodeId) {
88+
var data = SegmentEndManager.Instance.GetAt(segmentID: segmentId, nodeID: nodeId);
89+
return data?.SharpCorners ?? nodeId.ToNode().Info.GetARSharpCorners();
90+
}
91+
92+
public static Bezier3 GetBezier(this ref NetSegment segment, ushort nodeId) {
93+
bool startNode = segment.IsStartNode(nodeId);
94+
return segment.CalculateSegmentBezier3(startNode);
95+
}
96+
97+
public static void Sharpen2(
98+
ushort segmentId1, bool startNode, bool leftSide,
99+
ref Vector3 cornerPos, ref Vector3 cornerDirection) {
100+
ref NetSegment segment1 = ref segmentId1.ToSegment();
101+
ushort nodeId = segment1.GetNode(startNode);
102+
if (!IsSharp(segmentId1, nodeId: nodeId)) return;
103+
104+
ref NetNode node = ref nodeId.ToNode();
105+
int nSegments = node.CountSegments();
106+
if (nSegments < 2) {
107+
return;
108+
}
109+
110+
ushort segmentId2;
111+
if (leftSide /*right going toward junction*/) {
112+
segmentId2 = segment1.GetRightSegment(nodeId);
113+
} else {
114+
segmentId2 = segment1.GetLeftSegment(nodeId);
115+
}
116+
ref NetSegment segment2 = ref segmentId2.ToSegment();
117+
118+
Vector3 pos = node.m_position;
119+
float hw1 = segment1.Info.m_halfWidth;
120+
float hw2 = segment2.Info.m_halfWidth;
121+
Vector3 dir1 = NormalizeXZ(segment1.GetDirection(nodeId));
122+
Vector3 dir2 = NormalizeXZ(segment2.GetDirection(nodeId));
123+
124+
float det = VectorUtil.DetXZ(dir1, dir2);
125+
bool lessThan180 = det > 0 == leftSide;
126+
if(lessThan180) {
127+
return; // already handled
128+
}
129+
130+
float sin = Vector3.Cross(dir1, dir2).y;
131+
sin = -sin;
132+
133+
#if SAMEDIR
134+
static bool SameDir(Vector3 tangent, Vector3 dir) {
135+
return DotXZ(tangent, NormalizeXZ(dir)) > 0.95f;
136+
}
137+
138+
Vector3 otherPos1 = segment1.GetOtherNode(nodeId).ToNode().m_position;
139+
Vector3 otherPos2 = segment2.GetOtherNode(nodeId).ToNode().m_position;
140+
bool isStraight1 = SameDir(dir1, otherPos1 - pos);
141+
bool isStraight2 = SameDir(dir2, otherPos2 - pos);
142+
if (!isStraight1 || !isStraight2) {
143+
//var otherDir1 = otherPos1 - pos;
144+
//var otherDir1n = NormalizeXZ(otherDir1);
145+
//float dotxz1 = DotXZ(dir1, otherDir1n);
146+
//Log.Debug($"isStraight1={isStraight1} dir1={dir1} otherDir1={otherDir1} otherDir1.normalizedXZ={otherDir1n} dotxz1={dotxz1}");
147+
//var otherDir2 = otherPos2 - pos;
148+
//var otherDir2n = NormalizeXZ(otherDir2);
149+
//float dotxz2 = DotXZ(dir2, otherDir2n);
150+
//Log.Debug($"isStraight2={isStraight2} dir2={dir2} otherDir2={otherDir2} otherDir2.normalizedXZ={otherDir2n} dotxz2={dotxz2}");
151+
return;
152+
}
153+
#endif
154+
155+
156+
Log.Debug($"p3: node:{nodeId}, segment:{segmentId1} segmentId2:{segmentId2} leftSide={leftSide} sin={sin}", false);
157+
if (Mathf.Abs(sin) > 0.001) {
158+
float scale = 1 / sin;
159+
if (!leftSide)
160+
scale = -scale;
161+
162+
pos += dir2 * hw1 * scale;
163+
pos += dir1 * hw2 * scale; // intersection.
164+
165+
const float OFFSET_SAFETYNET = 0.02f;
166+
cornerPos = pos + dir1 * OFFSET_SAFETYNET;
167+
}
168+
}
66169
}

0 commit comments

Comments
 (0)