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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

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

namespace XFEEDToolBox.Core.Galaxy;

/// <summary>Bounded perspective grid and clipped route geometry in the actual Galactic frame.</summary>
public static class GalaxyMapGeometry
{
    /// <summary>A star's vertical connector to the camera's Galactic grid plane, without per-frame coordinate allocations.</summary>
    public static bool TryProjectStalk(GalaxyCamera camera,Coordinates star,out MapSegment segment)
    {
        segment=default;if(!star.IsValid||Math.Abs(star.Y-camera.Focus.Y)<1e-8)return false;
        var dx=star.X-camera.Focus.X;var dz=star.Z-camera.Focus.Z;var height=star.Y-camera.Focus.Y;
        var planeDepth=camera.Distance+dx*camera.Forward.X+dz*camera.Forward.Z;
        var starDepth=planeDepth+height*camera.Forward.Y;
        if(starDepth<camera.Near&&planeDepth<camera.Near)return false;
        var low=0d;var high=1d;var depthChange=planeDepth-starDepth;
        if(Math.Abs(depthChange)>1e-12)
        {
            var near=(camera.Near-starDepth)/depthChange;
            if(depthChange>0)low=Math.Max(0,near);else high=Math.Min(1,near);
        }
        if(low>high)return false;
        (double X,double Y) At(double t)
        {
            var dy=height*(1-t);var scale=camera.FocalLength/Math.Max(camera.Near,starDepth+depthChange*t);
            return(camera.Width/2+(dx*camera.Right.X+dy*camera.Right.Y+dz*camera.Right.Z)*scale,
                camera.Height/2-(dx*camera.Up.X+dy*camera.Up.Y+dz*camera.Up.Z)*scale);
        }
        var a=At(low);var b=At(high);var lineX=b.X-a.X;var lineY=b.Y-a.Y;low=0;high=1;
        bool Bound(double p,double q)
        {
            if(Math.Abs(p)<1e-12)return q>=0;
            var t=q/p;if(p<0){if(t>high)return false;low=Math.Max(low,t);}else{if(t<low)return false;high=Math.Min(high,t);}return true;
        }
        if(!Bound(-lineX,a.X)||!Bound(lineX,camera.Width-a.X)||!Bound(-lineY,a.Y)||!Bound(lineY,camera.Height-a.Y))return false;
        segment=new(a.X+lineX*low,a.Y+lineY*low,a.X+lineX*high,a.Y+lineY*high);return true;
    }
    public static bool TryProjectSegment(GalaxyCamera camera,Coordinates from,Coordinates to,out MapSegment segment)
    {
        segment=default;
        if(!camera.TryProjectSegment(from,to,out var a,out var b))return false;
        var dx=b.X-a.X;var dy=b.Y-a.Y;var low=0d;var high=1d;
        bool Bound(double p,double q)
        {
            if(Math.Abs(p)<1e-12)return q>=0;
            var t=q/p;
            if(p<0){if(t>high)return false;low=Math.Max(low,t);}else{if(t<low)return false;high=Math.Min(high,t);}
            return true;
        }
        if(!Bound(-dx,a.X)||!Bound(dx,camera.Width-a.X)||!Bound(-dy,a.Y)||!Bound(dy,camera.Height-a.Y))return false;
        segment=new(a.X+dx*low,a.Y+dy*low,a.X+dx*high,a.Y+dy*high);return true;
    }

    public static int WriteGrid(Span<MapSegment> output,GalaxyCamera camera,out double step)
    {
        step=0;if(output.Length<8||Math.Abs(Math.Sin(camera.Pitch))<.015)return 0;
        // Four orbit distances reach the far clip plane. Grid lines are snapped
        // to Galactic coordinates so panning never resets the lattice origin.
        var extent=camera.Distance*4;
        var target=Math.Max(20/camera.Scale,extent/70);
        var decade=Math.Pow(10,Math.Floor(Math.Log10(target)));var fraction=target/decade;
        step=decade*(fraction<=1?1:fraction<=2?2:fraction<=5?5:10);
        var budget=Math.Min(output.Length,InfiniteGalaxyGrid.MaximumLines);var count=0;
        var focus=camera.Focus;var minX=focus.X-extent;var maxX=focus.X+extent;var minZ=focus.Z-extent;var maxZ=focus.Z+extent;
        for(var axis=0;axis<2;axis++)
        {
            var first=Math.Ceiling((axis==0?minX:minZ)/step);var last=Math.Floor((axis==0?maxX:maxZ)/step);
            for(var i=first;i<=last&&count<budget;i++)
            {
                var at=i*step;var a=new Coordinates(axis==0?at:minX,focus.Y,axis==0?minZ:at);
                var b=new Coordinates(axis==0?at:maxX,focus.Y,axis==0?maxZ:at);
                if(TryProjectSegment(camera,a,b,out var segment))output[count++]=segment;
            }
        }
        return count;
    }
    /// <summary>Projects the original198 world lines through the shared camera.</summary>
    public static int WriteOriginalGrid(Span<MapSegment> output,GalaxyCamera camera,out double step)
    {
        step=GalaxyOriginalGrid.Step(camera.Distance);
        if(output.Length<GalaxyOriginalGrid.MaximumLines)return 0;
        Span<GalaxyOriginalGridLine> source=stackalloc GalaxyOriginalGridLine[GalaxyOriginalGrid.MaximumLines];
        var generated=GalaxyOriginalGrid.Write(source,camera.Focus,camera.Distance);var count=0;
        foreach(var line in source[..generated])
            if(TryProjectSegment(camera,new(line.FromX,line.FromY,line.FromZ),new(line.ToX,line.ToY,line.ToZ),out var segment))output[count++]=segment;
        return count;
    }
}