Сделать объект вокруг другой только с градусами (не радианы, только целочисленная математика) - PullRequest
0 голосов
/ 07 мая 2018

Я сейчас разрабатываю что-то, что требует, чтобы объекты вращались вокруг другого. Хотя я ограничен. Я не могу использовать радианы, чтобы достичь этого. У меня есть доступ к греху и соз, и степени. Но я не могу использовать радианы (это ломает все). Обратите внимание, что это внутри 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. Это просто невозможно.

Итак, основные вопросы: Как я могу найти будущее положение объекта только с градусами, грехом и cos? (Возможно, ответ основывается, например, на 45 градусов)

Вот отличный пример изображения: An image showing what I need to do

1 Ответ

0 голосов
/ 07 мая 2018

почему бы не сделать свои 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 с целочисленными переменными только там. Мы использовали его в 8-битной эре asm на Z80 для наших вещей, а затем и для демонстраций 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> (зависит от того, какую инициализацию вы вызываете) и период угла равен 256 вместо 360. Сначала вам нужно вызвать mysin_init???(); один раз, чтобы инициировать LUT , после чего вы можете использовать mysin,mycos, только не забудьте разделить окончательный результат на /100 или >>7.

Когда я отрисовываю оверлей реального и приближенного круга, используя VCL :

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");
    }

результат выглядит так:

result

Красный - реальный круг, а Черный - круг с использованием mysin,mycos. Как вы можете видеть, есть небольшие отклонения из-за точности приближений, но здесь не используется операция с плавающей точкой. Это странно, так как три метода смещения битов приводят к разным числам (это должна быть некоторая оптимизация моего компилятора), константы настроены для первого метода.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...