计算给定速度下的轨道截距. [英] Calculate an intercept to an orbit for a given speed.

查看:112
本文介绍了计算给定速度下的轨道截距.的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

背景: 尝试编写一款游戏,其中"FTL"旅行不受重力影响,并且加速度是即时的.

Background: Attempting to write a game where 'FTL' travel is unaffected by gravity and acceleration is instant.

给定行星的开普勒轨道以及船舶的当前位置及其最大FTL速度,如何计算行星的位置. (以米/秒为单位)

How do I calculate where a planet will be, given the Kepler orbit for the planet and a ships current position and its maximum FTL speed. (in m/s)

我可以在给定的DateTime上获取行星的位置,但是我在努力寻找如何计算行星的位置以及将飞船送往何处而又不追随行星在轨道上的位置.

I can get the position of the planet for a given DateTime, but I'm struggling to figure out how to calculate where a planet will be, and where to send the ship to, without chasing the planet around the orbit.

推荐答案

我会迭代...

  1. 计算行星与船舶当前位置之间的距离

据此,如果目标是静态的(不动),则您的船舶需要多少时间才能达到目标.这次叫t.

from that you compute how much time your ship need to meet the target if the target would be static (not moving). Lets call this time t.

计算actual_time+t中的行星位置并为此新位置计算t

compute planet position in actual_time+t and compute t for this new position

记住最后一个t让我们将其称为t0.然后以与#1 中相同的方式计算新的t,但要计算t之后的行星位置.

remember last t lets call it t0. Then compute new t in the same way as in #1 but for position of the planet after t.

循环#2

如果fabs(t-t0)<accuracy,则停止.

除非您的行星移动得太快和/或飞船真的过长或过慢(初始t远大于或大于热带行星,否则此迭代解决方案应与每次迭代都更接近t)年).在这种情况下,您通常会先跳入恒星系统,然后跳到行星上(就像原始的Elite).

This iterative solution should be closer to the finding t with each iteration unless your planet moves too fast and/or ship is really too far or too slow (initial t is significant part or even bigger than the planets tropical year). In such case You usually first jump into the star system and then jump to planet (Like in original Elite).

对于晦涩的行星运动(例如太小的轨道周期),您将需要不同的方法,但要意识到,这种情况暗示着行星离恒星非常近,或者恒星系质量很重,如黑洞……

For obscure planetary movements (like too small orbital period) you would need different methods but realize that such case implies either planet very near to star or very heavy system central mass like black hole...

在FTL速度恒定的代码中,它看起来像这样:

In code with constant FTL speed it would look like this:

vec3 pp,ps=vec3(?,?,?); // planet and ship positions
double t,t0,time;

time=actual_time(); t=0.0;
for (int i=0;i<100;i++) // just avoiding infinite loop in case t/planet_orbit_period>=~0.5
 {
 t0=t;
 pp = planet_position(time+t);
 t=Length(pp-ps)/ship_FTL_speed;
 if (fabs(t-t0)*ship_FTL_speed<=ship_safe_FTL_distance) break;
 }

这应该会很快收敛(例如5-10次迭代就足够了).现在,t应该保留行进所需的时间,而pp应该保留您的船应该驶向的位置.怎么找不到i>=100解决方案,所以您首先需要更靠近系统,或者使用更快的FTL或使用其他方法,但是对于恒星系统FTL来说这不是常见的情况,因为行进时间应该少得多然后是目标轨道周期...

This should converge pretty quickly (like 5-10 iterations should be enough) Now t should hold the time needed for travel and pp should hold the position your ship should head to. How ever if i>=100 no solution was found so you first need to go closer to the system, or use faster FTL or use different method but that should not be the case for common in stellar system FTL as the travel time should be far less then the targets orbital period...

顺便说一句.这可能会让您感兴趣:

btw. this might interest you:

[Edit1]比FTL转换驱动器慢

我给了它一些教导,并稍微修改了算法.首先,它以某一步长(每个周期100点)检查整个行星周期的所有位置,并记住最短的航行时间,而不管航行过程中经过行星的时间长短.然后只需递归"检查最佳位置,角度步长就越来越小.这里是结果预览:

I give it a bit of taught and change the algo a bit. First it check all the positions along whole planet period with some step (100 points per period) and remember the closest time to travel to the ship regardless of periods of planet passed during the travel. Then simply "recursively" check around best location with smaller and smaller angle step. Here Preview of result:

和更新的源代码(完整的VCL应用程序代码,因此只需使用/移植所需的内容,而忽略其余内容)

And updated source (full VCL app code so just use/port what you need and ignore the rest)

//$$---- Form CPP ----
//---------------------------------------------------------------------------
#include <vcl.h>
#include <math.h>
#pragma hdrstop
#include "win_main.h"
#include "GLSL_math.h"  // just for vec3
//---------------------------------------------------------------------------
#pragma package(smart_init)
#pragma resource "*.dfm"
TMain *Main;
//---------------------------------------------------------------------------
// constants
const double deg=M_PI/180.0;
const double t_day=60.0*60.0*24.0;
// view
double view_x0=0.0;
double view_y0=0.0;
double zoom=1.0;
// simulation
double sim_t=0.0,sim_dt=0.01*t_day;
//---------------------------------------------------------------------------
void toscr(double &x,double &y)
    {
    x*=zoom; x+=view_x0;
    y*=zoom; y+=view_y0;
    }
//---------------------------------------------------------------------------
class planet                // Kepler body simplified to 2D axis aligned. For fully 3D orbit add mising orbital parameters and equations
    {
public:
    // input parameters
    double a,b,t0,T;        // major axis,minor axis, time where M=E=0.0 deg, orbital period
    // computet parameters
    double c1,c2,e;

    void ld(double _a,double _b,double _t0,double _T)
        {
        // copy input orbital parameters
        a=_a;
        b=_b;
        t0=_t0;
        T=_T;
        // prepare orbital constants
        e=1.0-((b*b)/(a*a));                // eccentricity
        if (e>=1.0) e=0;                    // wrong e
        c1=sqrt((1.0+e)/(1.0-e));           // some helper constants computation
        c2=a*(1-e*e);
        //b=a*sqrt(1.0-e);
        }
    vec3 position(double t) // actual position relative to center mass of the system
        {
        int q;
        vec3 p;
        double E,V,r,M;
        // compute mean orbital position M [rad] from time t
        M=(t-t0)/T;
        M-=floor(M);
        M*=2.0*M_PI;
        // compute real orbital position E [rad] from M
        for (E=M,q=0;q<20;q++) E=M+e*sin(E);// Kepler's equation
        // heliocentric ellipse
        V=2.0*atan(c1*tan(E/2.0));
        r=c2/(1.0+e*cos(V));
        p.x=r*cos(V);
        p.y=r*sin(V);
        p.z=0.0;
        return p;
        }
    void draw_orbit(TCanvas *scr)
        {
        int i;
        double ang,x,y,r,V,E;
        x=a; y=0; toscr(x,y);
        for (i=2,E=0.0;i;E+=3.6*deg)
            {
            if (E>=2.0*M_PI) { E=0.0; i=0; }
            V=2.0*atan(c1*tan(E/2.0));
            r=c2/(1.0+e*cos(V));
            x=r*cos(V);
            y=r*sin(V);
            toscr(x,y);
            if (i==2){ scr->MoveTo(x,y); i=1; }
             else      scr->LineTo(x,y);
            }
        }
    };
//---------------------------------------------------------------------------
class ship                          // Space ship with translation propulsion
    {
public:
    vec3 pos,dir;                   // position and translation direction
    double spd,tim;                 // translation speed and time to translate or 0.0 if no translation
    ship() { pos=vec3(0.0,0.0,0.0); dir=pos; spd=0.0; tim=0.0; }
    void update(double dt)          // simulate dt time step has passed
        {
        if (tim<=0.0) return;
        if (dt>tim) { dt=tim; tim=0.0; }
         else                 tim-=dt;
        pos+=spd*dt*dir;
        }
    void intercept(planet &pl)      // set course for planet pl intercept
        {
        if (spd<=0.0) { tim=0.0; return; }
        const double d=1000000.0;   // safe distance to target
/*
        // [Iteration]
        int i;
        vec3 p;
        double t0;
        for (tim=0.0,i=0;i<100;i++)
            {
            t0=tim;
            p=pl.position(sim_t+tim);
            tim=length(p-pos)/spd;
            if (fabs(tim-t0)*spd<=d) break;
            }
        dir=normalize(p-pos);
*/
        // [search]
        vec3 p;
        int i;
        double tt,t,dt,a0,a1,T;
        // find orbital position with min error (coarse)
        for (a1=-1.0,t=0.0,dt=0.01*pl.T;t<pl.T;t+=dt)
            {
            p=pl.position(sim_t+t);                     // try time t
            tt=length(p-pos)/spd;
            a0=tt-t; if (a0<0.0) continue;              // ignore overshoots
            a0/=pl.T;                                   // remove full periods from the difference
            a0-=floor(a0);
            a0*=pl.T;
            if ((a0<a1)||(a1<0.0)) { a1=a0; tim=tt; }   // remember best option
            }
        // find orbital position with min error (fine)
        for (i=0;i<3;i++)                               // recursive increase of accuracy
         for (a1=-1.0,t=tim-dt,T=tim+dt,dt*=0.1;t<T;t+=dt)
            {
            p=pl.position(sim_t+t);                     // try time t
            tt=length(p-pos)/spd;
            a0=tt-t; if (a0<0.0) continue;              // ignore overshoots
            a0/=pl.T;                                   // remove full periods from the difference
            a0-=floor(a0);
            a0*=pl.T;
            if ((a0<a1)||(a1<0.0)) { a1=a0; tim=tt; }   // remember best option
            }
        // direction
        p=pl.position(sim_t+tim);
        dir=normalize(p-pos);
        }
    };
//---------------------------------------------------------------------------
planet pl;
ship sh;
//---------------------------------------------------------------------------
void TMain::draw()
    {
    if (!_redraw) return;
    double x,y,r=3;
    vec3 p;

    // clear buffer
    bmp->Canvas->Brush->Color=clBlack;
    bmp->Canvas->FillRect(TRect(0,0,xs,ys));

    // Star
    bmp->Canvas->Pen->Color=clYellow;
    bmp->Canvas->Brush->Color=clYellow;
    x=0; y=0; toscr(x,y);
    bmp->Canvas->Ellipse(x-r,y-r,x+r,y+r);
    // planet
    bmp->Canvas->Pen->Color=clDkGray;
    pl.draw_orbit(bmp->Canvas);
    bmp->Canvas->Pen->Color=clAqua;
    bmp->Canvas->Brush->Color=clAqua;
    p=pl.position(sim_t);
    x=p.x; y=p.y; toscr(x,y);
    bmp->Canvas->Ellipse(x-r,y-r,x+r,y+r);
    // ship
    bmp->Canvas->Pen->Color=clRed;
    bmp->Canvas->Brush->Color=clRed;
    p=sh.pos;
    x=p.x; y=p.y; toscr(x,y);
    bmp->Canvas->Ellipse(x-r,y-r,x+r,y+r);

    // render backbuffer
    Main->Canvas->Draw(0,0,bmp);
    _redraw=false;
    }
//---------------------------------------------------------------------------
__fastcall TMain::TMain(TComponent* Owner) : TForm(Owner)
    {
    pl.ld(1000000000.0,350000000.0,0.0,50.0*t_day);
    sh.pos=vec3(-3500000000.0,-800000000.0,0.0);
    sh.spd=500.0;   // [m/s]
    sh.intercept(pl);

    bmp=new Graphics::TBitmap;
    bmp->HandleType=bmDIB;
    bmp->PixelFormat=pf32bit;
    pyx=NULL;
    _redraw=true;
    }
//---------------------------------------------------------------------------
void __fastcall TMain::FormDestroy(TObject *Sender)
    {
    if (pyx) delete[] pyx;
    delete bmp;
    }
//---------------------------------------------------------------------------
void __fastcall TMain::FormResize(TObject *Sender)
    {
    xs=ClientWidth;  xs2=xs>>1;
    ys=ClientHeight; ys2=ys>>1;
    bmp->Width=xs;
    bmp->Height=ys;
    if (pyx) delete[] pyx;
    pyx=new int*[ys];
    for (int y=0;y<ys;y++) pyx[y]=(int*) bmp->ScanLine[y];
    _redraw=true;

    view_x0=xs-(xs>>3);
    view_y0=ys2;
    zoom=double(xs2)/(2.5*pl.a);

    // draw(); Sleep(5000);
    }
//---------------------------------------------------------------------------
void __fastcall TMain::FormPaint(TObject *Sender)
    {
    _redraw=true;
    }
//---------------------------------------------------------------------------
void __fastcall TMain::tim_redrawTimer(TObject *Sender)
    {
    for (int i=0;i<10;i++)
        {
        sh.update(sim_dt);
        sim_t+=sim_dt;
        if (sh.tim<=0.0) sim_dt=0.0; // stop simulation when jump done
        }
    if (sim_dt>0.0) _redraw=true;
    draw();
    }
//---------------------------------------------------------------------------

重要的东西在两个类中planet,ship然后sim_t是实际模拟时间,而sim_dt是模拟时间步长.在这种情况下,模拟将在船舶到达目的地后停止. ship::tim是在ship::intercept()中计算的剩余行进时间以及预设速度的方向.应该在每个模拟时间步长调用更新...

The important stuff is in the two classes planet,ship then sim_t is actual simulated time and sim_dt is simulated time step. In this case simulation stops after ship reach its destination. The ship::tim is the time of travel left computed in the ship::intercept() along with direction for preset speed. The update should be called on each simulated time step ...

这篇关于计算给定速度下的轨道截距.的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆