11namespace NodeController . Patches . Corner ;
2+
3+ using ColossalFramework . Math ;
24using HarmonyLib ;
35using KianCommons ;
6+ using KianCommons . Math ;
47using KianCommons . Patches ;
58using KianCommons . Plugins ;
69using System . Collections . Generic ;
710using System . Linq ;
811using System . Reflection ;
912using System . Reflection . Emit ;
1013using UnityEngine ;
14+ using static ColossalFramework . Math . VectorUtils ;
1115
1216[ HarmonyPatch ]
1317static 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