namespace XFEEDToolBox.Core.Navigation;
public static class SurfaceApproachGeometry
{
public static double SurfaceRange(Vector3d ship,Vector3d site,Vector3d centre,double radius)
=>Math.Acos(Math.Clamp(Vector3d.Dot((ship-centre).Unit(),(site-centre).Unit()),-1,1))*radius;
public static Vector3d EntryPoint(PlanetApproachFrame planet,Vector3d ship)
{
var limits=planet.Limits;if(!limits.Valid)throw new ArgumentException("行星进近参数未校验。");
var site=(planet.SurfaceDestination-planet.Centre).Unit();var radial=(ship-planet.Centre).Unit();
var toward=radial-site*Vector3d.Dot(radial,site);
if(toward.Length<1e-6)toward=FlightGeometry.Perpendicular(site,planet.North);
var range=(limits.GlideEntryAltitude-limits.GlideExitAltitude)/Math.Tan(limits.PreferredGlideAngleDegrees*Math.PI/180);
var arc=Math.Clamp(range/limits.Radius,0,Math.PI/3);
return planet.Centre+(site*Math.Cos(arc)+toward.Unit()*Math.Sin(arc))*(limits.Radius+limits.GlideEntryAltitude*1.08);
}
public static Vector3d ShallowApproach(PlanetApproachFrame planet,Vector3d ship,Vector3d forward)
{
var radial=(ship-planet.Centre).Unit();var toward=planet.SurfaceDestination-ship;
var tangent=toward-radial*Vector3d.Dot(toward,radial);
if(tangent.Length<1)tangent=FlightGeometry.Perpendicular(radial,forward);
return (tangent.Unit()-radial*Math.Tan(planet.Limits.PreferredGlideAngleDegrees*Math.PI/180)).Unit();
}
public static Vector3d LevelDirection(PlanetApproachFrame planet,Vector3d ship,Vector3d forward)
{
var up=(ship-planet.Centre).Unit();var toward=planet.SurfaceDestination-ship;
var tangent=toward-up*Vector3d.Dot(toward,up);
return tangent.Length>1?tangent.Unit():FlightGeometry.Perpendicular(up,forward);
}
public static bool IntersectsPlanet(Vector3d from,Vector3d to,Vector3d centre,double radius)
{
var delta=to-from;var lengthSquared=Vector3d.Dot(delta,delta);
if(lengthSquared<1)return (from-centre).Length<radius;
var t=Math.Clamp(Vector3d.Dot(centre-from,delta)/lengthSquared,0,1);
return (from+delta*t-centre).Length<radius;
}
}
namespace XFEEDToolBox.Core.Navigation;
public static class SurfaceApproachGeometry
{
public static double SurfaceRange(Vector3d ship,Vector3d site,Vector3d centre,double radius)
=>Math.Acos(Math.Clamp(Vector3d.Dot((ship-centre).Unit(),(site-centre).Unit()),-1,1))*radius;
public static Vector3d EntryPoint(PlanetApproachFrame planet,Vector3d ship)
{
var limits=planet.Limits;if(!limits.Valid)throw new ArgumentException("行星进近参数未校验。");
var site=(planet.SurfaceDestination-planet.Centre).Unit();var radial=(ship-planet.Centre).Unit();
var toward=radial-site*Vector3d.Dot(radial,site);
if(toward.Length<1e-6)toward=FlightGeometry.Perpendicular(site,planet.North);
var range=(limits.GlideEntryAltitude-limits.GlideExitAltitude)/Math.Tan(limits.PreferredGlideAngleDegrees*Math.PI/180);
var arc=Math.Clamp(range/limits.Radius,0,Math.PI/3);
return planet.Centre+(site*Math.Cos(arc)+toward.Unit()*Math.Sin(arc))*(limits.Radius+limits.GlideEntryAltitude*1.08);
}
public static Vector3d ShallowApproach(PlanetApproachFrame planet,Vector3d ship,Vector3d forward)
{
var radial=(ship-planet.Centre).Unit();var toward=planet.SurfaceDestination-ship;
var tangent=toward-radial*Vector3d.Dot(toward,radial);
if(tangent.Length<1)tangent=FlightGeometry.Perpendicular(radial,forward);
return (tangent.Unit()-radial*Math.Tan(planet.Limits.PreferredGlideAngleDegrees*Math.PI/180)).Unit();
}
public static Vector3d LevelDirection(PlanetApproachFrame planet,Vector3d ship,Vector3d forward)
{
var up=(ship-planet.Centre).Unit();var toward=planet.SurfaceDestination-ship;
var tangent=toward-up*Vector3d.Dot(toward,up);
return tangent.Length>1?tangent.Unit():FlightGeometry.Perpendicular(up,forward);
}
public static bool IntersectsPlanet(Vector3d from,Vector3d to,Vector3d centre,double radius)
{
var delta=to-from;var lengthSquared=Vector3d.Dot(delta,delta);
if(lengthSquared<1)return (from-centre).Length<radius;
var t=Math.Clamp(Vector3d.Dot(centre-from,delta)/lengthSquared,0,1);
return (from+delta*t-centre).Length<radius;
}
}