Показать сообщение отдельно
Старый 04.09.2006, 18:48   #1
SubZer0
Администратор
 
Аватар для SubZer0
 
Регистрация: 03.09.2005
Сообщений: 2,408
Написано 301 полезных сообщений
(для 996 пользователей)
Радость ATAN2 своими руками

Привет всем! вот наконец я и добрался рассказать как мучался с такой вещью в JAVAME без матлиб и т.п.

для чего такая байда нужна? обычно нужно чтобы объект научился "смотреть" на другой...

заключается сия функция в расчете углов по двум координатам (а-ля угол вектора)

покопался в нете, нарыл формулу по которой раскладывается атан: atn=32*x*x + 9*y*y;

гы! я тут всем в аську проспамил может думаю какое друое решение есть, а то в этом умножений много... тормозить будет, а я из тех программистов которые раскладывают все формулы на листочке и записывают простейший вариант в код, не люблю когда выдумают жутко громоздкую формулу и потом комп парится их вычисляет... не надо надо мной смеяться придумывая как я бы расписывал массив... я упрощаю все в пределах разумного...

так! где я там остановился... ага... атан, мать его! ну короче мучались мы поисками мучались, нифига не нашли, и PAX замутил код:
 public float atan2(float x, float y) {
      float atn,atn1;
      atn1=32*x*x + 9*y*y;
      if (atn1==0) {//если угол перпендикулярен оси х
        if (x>0) {return 90;} else{ return 270; }
      }
          atn=32*(x*y)/atn1;
      if (x>=0) {
        if (y>=0){
          return atn;//первая четверть
        }else{
          return 360-atn;//четвертая четверть
        }
      }else{
        if (y>=0){
          return 90+atn;//вторая четверть
        }else{
          return 270-atn;//третья четверть
        }
      }
    }
но меня это все не устраивало... казалось мне, что можно более простой вариант придумать... тем более что у меня в игре не 360 углов а всего 16... этот код еще преобразовывать надо было бы...

и придумал я свой вариант... чисто специализированный... к другому коду не подойдет...

итак:

сначала рисунок:


пестровато конечно, но попробую объяснить всю суть моей затеи...

по прямой OY координата Y равна нулю, точно также и по ОХ. По синей прямой кордината X будет всегда равна Y... уже половину углов можно описать простейшими условиями, и без вычислений... Но это всеголишь 8 углов... а у меня 16... и я придумал такую весчъ!

придумал делить одну координату на другую и сравнивать с заранее высчитанным результатом... а прежде сравнивать их, если, при положительный координатах, X больше чем Y, то угол будет в коричневом секторе, если наоборот то желтом.

для угла 45 градусов результат будет 1, для угла в 22.5 градуса высчитывается по формуле cos(22,5)/sin(22,5), и все это равно 2,414213562373... теперь мы точно можем сказать, что если результат деления одной координаты на другую получился в пределах от 1 до 2,41, то нужно повергуться на угол гдето между двойкой и тройкой!

но это маленько не то, что нам было нужно... нам нужно знать примерный угол "3"! для этого поделим секторы между (2 и 3) и (3 и 4) еще пополам... таким образом у нас получились лучи расположенные под углами 11.5 и 33.75... высчитаем у них результаты деления одной координаты на другую...

cos(11,25)/sin(11,25)*=*5,027339492126
cos(33,75)/sin(33,75)*=*1,496605762665

вот теперь то, что надо! теперь если результат деления одной координаты на другую будет больше чем 5, то это будет угол 4 (красный сектор), если от 1.49 до 5 то угол 3 (зеленый сектор), а если меньше 1.49, то угол 2...

и такими темпами есь круг... итого требудется всего одно деление и условия (которые обрабатываются значительно быстрее)...

итого: надо выбрать четверть, потом восьмую часть (путем сравнения координат кака больше) и поделить координаты!

начал я мутить программу по такому вот кнцепту... и получилось что там еще надо добавить немножко условий, а именно: чтоб исключить деление на ноль, а в остальном все так и осталось как и было:

                        xp=PositionX-PositionX1; 
                        yp=PositionY-PositionY1;
                        
                        xp1=xp; if (xp1<0) xp1=-xp1;
                        yp1=yp; if (yp1<0) yp1=-yp1;
                        
                        if (xp>0) {
                            if (yp>0) {
                                if (xp1>yp1) {
                                    if (yp1==0) angle=12; else {
                                        j=(xp1*16)/yp1;
                                        if (j>=80) angle=12;
                                        if (j<80 && j>=24) angle=13;
                                        if (j<24) angle=14;
                                    }
                                } else {
                                    if (xp1==0) angle=0; else {
                                        j=(yp1*16)/xp1;
                                        if (j>=80) angle=0;
                                        if (j<80 && j>=24) angle=15;
                                        if (j<24) angle=14;
                                    }
                                }
                            } else {
                                if (xp1>yp1) {
                                    if (yp1==0) angle=12; else {
                                        j=(xp1*16)/yp1;
                                        if (j>=80) angle=12;
                                        if (j<80 && j>=24) angle=11;
                                        if (j<24) angle=10;
                                    }
                                } else {
                                    if (xp1==0) angle=8; else {
                                        j=(yp1*16)/xp1;
                                        if (j>=80) angle=8;
                                        if (j<80 && j>=24) angle=9;
                                        if (j<24) angle=10;
                                    }
                                }
                            }
                        } else {
                            if (yp>0) {
                                if (xp1>yp1) {
                                    if (yp1==0) angle=4; else {
                                        j=(xp1*16)/yp1;
                                        if (j>=80) angle=4;
                                        if (j<80 && j>=24) angle=3;
                                        if (j<24) angle=2;
                                    }
                                } else {
                                    if (xp1==0) angle=0; else {
                                        j=(yp1*16)/xp1;
                                        if (j>=80) angle=0;
                                        if (j<80 && j>=24) angle=1;
                                        if (j<24) angle=2;
                                    }
                                }
                            } else {
                                if (xp1>yp1) {
                                    if (yp1==0) angle=4; else {
                                        j=(xp1*16)/yp1;
                                        if (j>=80) angle=4;
                                        if (j<80 && j>=24) angle=5;
                                        if (j<24) angle=6;
                                    }
                                } else {
                                    if (xp1==0) angle=8; else {
                                        j=(yp1*16)/xp1;
                                        if (j>=80) angle=8;
                                        if (j<80 && j>=24) angle=7;
                                        if (j<24) angle=6;
                                    }
                                }
                            }
                            
                        }
в ходе кода встретлся с проблемой, низя юзать десятичные дроби, пэтому пришлось юзать умножение... и сравнивать потом с заранее умноженными вариантами... зато теперь теоретически прога должна выполняться быстрее , на каждом проходе получается - 5 условий, одно умножение и одно деление...

вот так вот...
__________________
Как минимум я помог многим (с)
(Offline)
 
Ответить с цитированием