我需要一个沿椭圆运动的方程

时间:2014-11-05 21:31:08

标签: objective-c math swift

我正在编程像行星在太阳周围移动,以及移动行星我正在使用一个函数

CGPointMake(object.center.x + 1, sqrt(75*75*150*150 - 75*75*(object.center.x - 300)*(object.center.x - 300))/150 + 150)

使用eliptic方程,其中a = 150,b = 75,p = 300,q = 150,但是当物体接近x = 450左右时,它的速度上升,我猜这是因为pitagora,因为它的路径是c = sqrt((x-x0)^ 2 *(y-y0)^ 2)

我注意到我的c总是在0.5左右,但是当它到达x域的末尾时它会上升到0.8所以我需要一个程序或数学解决方案来使对象围绕椭圆曲线以相同的速度移动

谢谢!

2 个答案:

答案 0 :(得分:4)

如果你想要真实的东西

然后行星更接近主要焦点(恒星系统的质心...... 非常接近到恒星)移动得更快,所以在这里使用Kepler's equation:{{3} }。不要忘记查看该答案中的所有子链接,您可以找到所需的一切。

如果你想要恒定速度

然后使用参数椭圆方程

x(a)=x0+rx*cos(a)
y(a)=y0+ry*sin(a)

其中a是角度<0,2.0*PI> (x0,y0)是椭圆中心,(rx,ry)是椭圆半轴(半径)。

如果a以恒定速度递增,则面积增加是恒定的,因此a是平均圆角而不是椭圆上的视觉!有关详细信息,请查看此处:

[edit1]为** MartinR 指出速度不恒定**

所以这里是他的速度公式的近似值。椭圆是由x0,y0,rx,ry (rx>=ry)定义的轴对齐周长aproximation l

h=(rx-ry)/(rx+ry); h*=3.0*h; l=M_PI*(rx+ry)*(1.0+(h/(10.0+sqrt(4.0-h))));

如果你想在周边有n个大小相等的步骤,那么

l/=n;

初始计算:

double x0,y0,rx,ry,n,l,h;
x0=Form1->ClientWidth>>1;  // center is centered on form
y0=Form1->ClientHeight>>1;
rx=200; // semiaxises rx>=ry !!!
ry=75;
n=40.0; // number of chunks per ellipse (1/speed)
//l=2.0*M_PI*sqrt(0.5*((rx*rx)+(ry*ry)));  // not accurate enough
h=(rx-ry)/(rx+ry); h*=3.0*h; l=M_PI*(rx+ry)*(1.0+(h/(10.0+sqrt(4.0-h)))); // this is more precise
l/=n; // single step size in units,pixels,or whatever

首先是慢速暴力攻击(黑色):

int i;
double a,da,x,y,xx,yy,ll;
a=0.0;
x=x0+rx*cos(a);
y=y0+ry*sin(a);
for (i=n;i>0;i--)
    {
    xx=x; yy=y;
    for (da=a;;)
        {
        a+=0.001;
        x=x0+rx*cos(a);
        y=y0+ry*sin(a);
        ll=sqrt(((xx-x)*(xx-x))+((yy-y)*(yy-y)));
        if (ll>=l) break;
        } da=a-da;
    scr->MoveTo(5.0+50.0*a,5.0);
    scr->LineTo(5.0+50.0*a,5.0+300.0*da);

    scr->MoveTo(x0,y0);
    scr->LineTo(xx,yy);
    scr->LineTo(x ,y );
    ll=sqrt(((xx-x)*(xx-x))+((yy-y)*(yy-y)));
    scr->TextOutA(0.5*(x+xx)+20.0*cos(a),0.5*(y+yy)+20.0*sin(a),floor(ll));
    }

现在近似(蓝色):

a=0.0; da=0;
x=x0+rx*cos(a);
y=y0+ry*sin(a);
for (i=n;i>0;i--)
    {
    scr->MoveTo(5.0+50.0*a,5.0+300.0*da);
    xx=rx*sin(a);
    yy=ry*cos(a);
    da=l/sqrt((xx*xx)+(yy*yy)); a+=da;
    scr->LineTo(5.0+50.0*a,5.0+300.0*da);

    xx=x; yy=y;
    x=x0+rx*cos(a);
    y=y0+ry*sin(a);

    scr->MoveTo(x0,y0);
    scr->LineTo(xx,yy);
    scr->LineTo(x ,y );
    ll=sqrt(((xx-x)*(xx-x))+((yy-y)*(yy-y)));
    scr->TextOutA(0.5*(x+xx)+40.0*cos(a),0.5*(y+yy)+40.0*sin(a),floor(ll));
    }

这是干净的椭圆步骤(没有调试绘制)

a=???; // some initial angle
// point on ellipse 
x=x0+rx*cos(a);
y=y0+ry*sin(a);
// next angle by almost constant speed
xx=rx*sin(a);
yy=ry*cos(a);
da=l/sqrt((xx*xx)+(yy*yy)); a+=da;
// next point on ellipse ...
x=x0+rx*cos(a);
y=y0+ry*sin(a);

这里比较暴力和逼近的输出:

this is how the result looks like

[edit2]微小精确提升

 a,da=???; // some initial angle and step (last)
 x=x0+rx*cos(a);
 y=y0+ry*sin(a);
 // next angle by almost constant speed
 xx=rx*sin(a+0.5*da); // use half step angle for aproximation ....
 yy=ry*cos(a+0.5*da);
 da=l/sqrt((xx*xx)+(yy*yy)); a+=da;
 // next point on ellipse ...
 x=x0+rx*cos(a);
 y=y0+ry*sin(a);

much closer to bruteforce attack

近似的半步角导致暴力攻击的结果更接近

答案 1 :(得分:1)

嗯...

你可以使用SpriteKit轻松地伪造这样的东西。注:您的整个应用程序不必使用SpriteKit。您可以相当轻松地将SKView放入非SpriteKit应用程序中。

总之...

创造你的星球......

SKSpritNode *planet = [SKSpritNode spriteNodeWithImageNamed:@"mars"];
[solarSystemView addChild:planet];

创建您的椭圆路径......

UIBezierPath *ellipse = [UIBezierPath bezierPathWithOvalInRect:/*your rect*/]; //or create it any other way.

创建一个动作......

SKAction *singleOrbit = [SKAction followPath:ellipse.CGPath speed:10];
SKAction *orbit = [SKAction repeatActionForever:singleOrbit];

运行动作...

[planet runAction:orbit];