private static Vector2 GetCorrection()
{
var vessel = FlightGlobals.ActiveVessel;
if (vessel == null)
{
return(new Vector2(0, 0));
}
Vector3? targetPosition = Trajectory.fetch.targetPosition;
var patch = Trajectory.fetch.patches.LastOrDefault();
CelestialBody body = Trajectory.fetch.targetBody;
if (!targetPosition.HasValue || patch == null || !patch.impactPosition.HasValue || patch.startingState.referenceBody != body || !patch.isAtmospheric)
{
return(new Vector2(0, 0));
}
// Get impact position, or, if some point over the trajectory has not enough clearance, smoothly interpolate to that point depending on how much clearance is missing
Vector3 impactPosition = patch.impactPosition.Value;
foreach (var p in patch.atmosphericTrajectory)
{
float neededClearance = 600.0f;
float missingClearance = neededClearance - (p.pos.magnitude - (float)body.Radius - p.groundAltitude);
if (missingClearance > 0.0f)
{
if (Vector3.Distance(p.pos, patch.rawImpactPosition.Value) > 3000.0f)
{
float coeff = missingClearance / neededClearance;
Vector3 rotatedPos = p.pos;
if (!Settings.fetch.BodyFixedMode)
{
rotatedPos = Trajectory.calculateRotatedPosition(body, p.pos, p.time);
}
impactPosition = impactPosition * (1.0f - coeff) + rotatedPos * coeff;
}
break;
}
}
Vector3 right = Vector3.Cross(patch.impactVelocity.Value, impactPosition).normalized;
Vector3 behind = Vector3.Cross(right, impactPosition).normalized;
Vector3 offset = targetPosition.Value - impactPosition;
Vector2 offsetDir = new Vector2(Vector3.Dot(right, offset), Vector3.Dot(behind, offset));
offsetDir *= 0.00005f; // 20km <-> 1 <-> 45° (this is purely indicative, no physical meaning, it would be very complicated to compute an actual correction angle as it depends on the spacecraft behavior in the atmosphere ; a small angle will suffice for a plane, but even a big angle might do almost nothing for a rocket)
Vector3d pos = vessel.GetWorldPos3D() - body.position;
Vector3d vel = vessel.obt_velocity - body.getRFrmVel(body.position + pos); // air velocity
float plannedAngleOfAttack = (float)DescentProfile.fetch.GetAngleOfAttack(body, pos, vel);
if (plannedAngleOfAttack < Math.PI * 0.5f)
{
offsetDir.y = -offsetDir.y; // behavior is different for prograde or retrograde entry
}
float maxCorrection = 1.0f;
offsetDir.x = Mathf.Clamp(offsetDir.x, -maxCorrection, maxCorrection);
offsetDir.y = Mathf.Clamp(offsetDir.y, -maxCorrection, maxCorrection);
return(offsetDir);
}