仅使用度数使对象围绕另一个轨道运行(不仅仅是弧度整数数学)

时间:2018-05-07 07:02:30

标签: math integer

我目前正在开发一些需要物体围绕另一个物体运行的东西。虽然,我很有限。我无法使用Radians来实现这一目标。我可以获得罪和cos,以及学位。但我不能使用弧度(它打破了一切)。请注意,这是在Minecraft中,并且那里的值不能保持浮点数或双精度数。因此,0.017之类的答案将是17。出于这个原因,我不能使用弧度。

计算sin和cos的函数限制在-180到180之间。这意味着我不能简单地将0.787弧度变为787弧度,因为它超出了极限,并且回答的答案是完全错误的。

现在代码就像这样:



var distance = 100; // from the centre of orbit
var degrees = 45; // around a 360 degree orbit
var radians = degrees * (Math.PI / 180);

var x = Math.cos(radians) * distance;
var y = Math.sin(radians) * distance;




但该代码完全依赖于将度数转换为弧度。我不能这样做,因为Minecraft的整数限制,以及函数如何计算sin和cos。这根本不可能。

所以主要问题是: 如何只用度,sin和cos找到物体的未来位置? (也许根据答案就好像学位是45)

这是一个很好的示例图片: An image showing what I need to do

1 个答案:

答案 0 :(得分:2)

为什么不在固定点上制作自己的 LUT ?在C ++中是这样的:

const int fp=1000; // fixed point precision
const int mycos[360]={ 1000, 999, 999, 998, 997, 996, 994, 992, 990, ... }

float x,y,x0=0,y0=0,r=50,ang=45;
x = x0 + ( (r*mycos[ ang    %360]) / fp );
y = y0 + ( (r*mycos[(ang+90)%360]) / fp );

您也可以编写一个脚本,为您创建 LUT LUT 中的每个值都计算如下:

LUT[i] = fp*cos(i*M_PI/180); // i = 0,1,2,...359

现在在使用前将角度标准化:

ang %= 360;
if (ang<0) ang+=360;

还有一些方法可以计算只有整数变量的sin,cos表。我们在Z80的8位时代asm中使用它来处理我们的东西以及后来的x86演示......因此可以编写代码直接在Minecraft脚本中创建它而无需其他编译器使用。

您甚至可以将角度单位更改为2而不是360的幂,这样您就可以摆脱模数并将fp设置为2 -1的割草机,这样您甚至不需要分割。在我的源代码档案中进行了一些挖掘之后,我找到了使用这种技术的古老的 TASM MS-DOS 演示。将其移植到 C ++ 并在此处调整常量 C ++ 结果:

int mysinLUT[256];
void mysin_init100() // <-100,+100>
    {
    int bx,si=620,cx=0,dx;  // si ~amplitude
    for (bx=0;bx<256;bx++)
        {
        mysinLUT[bx]=(cx>>8);
        cx+=si;
        dx=41*cx;
        if (dx<0) dx=-((-dx)>>16); else dx>>=16;
        si-=dx;
        }
    }
void mysin_init127() // <-127,+127>
    {
    int bx,si=793,cx=0,dx;  // si ~amplitude
    for (bx=0;bx<256;bx++)
        {
        mysinLUT[bx]=(cx>>8)+1;
        cx+=si;
        dx=41*cx;
        if (dx<0) dx=-((-dx)>>16); else dx>>=16;
        si-=dx;
        }
    }
int mysin(int a){ return mysinLUT[(a   )&255]; }
int mycos(int a){ return mysinLUT[(a+64)&255]; }

设置常数,使sin[256]保持范围<-100,+100><-127,+127>(取决于您调用的init)的粗略近似值,角度周期为256而不是360。您需要先调用mysin_init???();一次以启动 LUT ,之后您可以使用mysin,mycos,不要忘记将最终结果除以/100或{{ 1}}。

当我使用 VCL

渲染真实和近似圆圈的叠加层时
>>7

结果如下:

result

红色是实际圆圈,黑色是使用void draw() { // select range // #define range100 #define range127 // init sin LUT just once static bool _init=true; if (_init) { _init=false; #ifdef range100 mysin_init100(); #endif #ifdef range127 mysin_init127(); #endif } int a,x,y,x0,y0,r; // clear screen bmp->Canvas->Brush->Color=clWhite; bmp->Canvas->FillRect(TRect(0,0,xs,ys)); // compute circle size from window resolution xs,ys x0=xs>>1; y0=ys>>1; r=x0; if (r>y0) r=y0; r=(r*7)/10; // render real circle bmp->Canvas->Pen->Color=clRed; bmp->Canvas->Ellipse(x0-r,y0-r,x0+r,y0+r); // render approximated circle bmp->Canvas->Pen->Color=clBlack; for (a=0;a<=256;a++) { #ifdef range100 x=x0+((r*mycos(a))/100); y=y0-((r*mysin(a))/100); #endif #ifdef range127 // if >> is signed (copying MSB) x=x0+((r*mycos(a))>>7); y=y0-((r*mysin(a))>>7); // if >> is unsigned (inserting 0) and all circle points are non negative // x=( (x0<<7)+(r*mycos(a)) )>>7; // y=( (y0<<7)-(r*mysin(a)) )>>7; // this should work no matter what // x=r*mycos(a); if (x<0) x=-((-x)>>7); else x>>=7; x=x0+x; // y=r*mysin(a); if (y<0) y=-((-y)>>7); else y>>=7; y=y0-y; // this work no matter what but use signed division // x=x0+((r*mycos(a))/127); // y=y0-((r*mysin(a))/127); #endif if (!a) bmp->Canvas->MoveTo(x,y); else bmp->Canvas->LineTo(x,y); } Form1->Canvas->Draw(0,0,bmp); //bmp->SaveToFile("out.bmp"); } 的圆圈。如您所见,由于近似精度存在小的偏差,但此处不使用浮点运算。奇怪的是,3个不同数量的bithift rsults方法(它必须是我的编译器的一些优化),常量被调整为第一种方法。