XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
using XFEEDToolBox.Core.Navigation;

namespace XFEEDToolBox.Core.Rendering;

public sealed record LocalSystemOrbitPath(SystemOrbit Orbit,SystemLocation Child,SystemLocation? Parent,Vector3d FocusPosition,IReadOnlyList<Vector3d> ActualPoints,IReadOnlyList<Vector3d> Points)
{
    public string ParentIdentity=>Parent?.Identity??Orbit.ParentIdentity!;
    public string ParentDisplayName=>Parent?.DisplayName??(!string.IsNullOrWhiteSpace(Orbit.ParentName)?Orbit.ParentName:Orbit.ParentIsBarycentre?"原生父质心":"原生父天体");
}

/// <summary>Samples a focus-centred Kepler ellipse in the supplied, verified system-space basis, in metres.</summary>
public static class LocalSystemOrbitGeometry
{
    public const int DefaultSegments=128;
    private static bool PhysicalBody(SystemLocation location)=>location.Category is SystemLocationCategory.Star or SystemLocationCategory.Planet or SystemLocationCategory.LandablePlanet;
    public static bool TrySampleOrbit(SystemOrbit orbit,CurrentSystemSnapshot snapshot,out SystemLocation? child,out SystemLocation? parent,
        out IReadOnlyList<Vector3d> points,out string? issue)
    {
        child=parent=null;points=[];issue=null;
        if(orbit.SystemAddress!=snapshot.SystemAddress){issue="轨道所属星系与当前目录不一致。";return false;}
        if(string.IsNullOrWhiteSpace(orbit.Source)){issue="轨道参数来源尚未确认。";return false;}
        if(!orbit.Renderable){issue=string.IsNullOrWhiteSpace(orbit.UnavailableReason)?"轨道形状、父子关系或星系空间平面尚未核实。":orbit.UnavailableReason;return false;}
        var physical=snapshot.Locations.Where(PhysicalBody).ToArray();
        var children=physical.Where(location=>location.WorldAddress==orbit.ChildWorldAddress&&location.Identity==orbit.ChildIdentity).ToArray();
        var parents=physical.Where(location=>location.WorldAddress==orbit.ParentWorldAddress&&location.Identity==orbit.ParentIdentity).ToArray();
        if(children.Length!=1||parents.Length>1||parents.Length==1&&children[0].Identity==parents[0].Identity)
        {issue="轨道父子天体无法与当前目录唯一对应。";return false;}
        child=children[0];parent=parents.SingleOrDefault();
        // A verified native barycentre need not be a selectable catalogue row.
        // A conflicting row is never bypassed by substituting that extra focus.
        if(parents.Length==0&&physical.Any(location=>location.WorldAddress==orbit.ParentWorldAddress||location.Identity==orbit.ParentIdentity))
        {issue="原生父天体身份与目录不一致,未替换焦点。";return false;}
        var focus=parent?.Position??orbit.ParentPosition;
        if(child.Position is not{Finite:true} childPoint||!double.IsFinite(childPoint.Length)||focus is not{Finite:true} focusPoint)
        {issue="轨道父子天体的真实坐标尚未确认。";return false;}
        if(parent is not null&&orbit.ParentPosition is {} nativeParent&&(!nativeParent.Finite||!double.IsFinite(nativeParent.Length)
            ||(nativeParent-focusPoint).Length>1000+focusPoint.Length*1e-9))
        {issue="原生父天体焦点与当前目录坐标不一致。";return false;}
        return TrySampleEllipse(focusPoint,orbit.SemiMajorAxisMetres!.Value,orbit.Eccentricity!.Value,
            orbit.PeriapsisDirection!.Value,orbit.TransverseDirection!.Value,out points,out issue);
    }
    public static bool TrySampleEllipse(Vector3d focus,double semiMajorAxisMetres,double eccentricity,Vector3d periapsisAxis,Vector3d transverseAxis,
        out IReadOnlyList<Vector3d> points,out string? issue,int segments=DefaultSegments)
    {
        points=[];issue=null;
        if(!focus.Finite||!double.IsFinite(focus.Length)){issue="parent-position-invalid";return false;}
        if(!double.IsFinite(semiMajorAxisMetres)||semiMajorAxisMetres<=0||!double.IsFinite(eccentricity)||eccentricity is <0 or >=1)
        {issue="ellipse-elements-invalid";return false;}
        if(segments is <16 or >512){issue="sample-budget-invalid";return false;}
        var xLength=periapsisAxis.Length;var yLength=transverseAxis.Length;
        if(!periapsisAxis.Finite||!transverseAxis.Finite||!double.IsFinite(xLength)||!double.IsFinite(yLength)
            ||Math.Abs(xLength-1)>.001||Math.Abs(yLength-1)>.001||Math.Abs(Vector3d.Dot(periapsisAxis,transverseAxis))>.001)
        {issue="system-plane-basis-invalid";return false;}
        // Normalize only the rounding error of an already unit, orthogonal basis.
        // Its direction and periapsis reference must be established by the source.
        var x=periapsisAxis/xLength;var y=transverseAxis/yLength;
        var b=semiMajorAxisMetres*Math.Sqrt((1-eccentricity)*(1+eccentricity));
        if(!double.IsFinite(b)){issue="ellipse-size-overflow";return false;}
        var sampled=new Vector3d[segments+1];
        for(var index=0;index<segments;index++)
        {
            var anomaly=2*Math.PI*index/segments;
            var point=focus+x*(semiMajorAxisMetres*(Math.Cos(anomaly)-eccentricity))+y*(b*Math.Sin(anomaly));
            if(!point.Finite||!double.IsFinite(point.Length)){issue="ellipse-position-overflow";return false;}
            sampled[index]=point;
        }
        sampled[^1]=sampled[0];points=sampled;return true;
    }
}