2010-07-25 5 views
-1

Для меня это очевидный способ сделать это: учитывая начальную точку и конечную точку, скажите мне, находится ли конечная точка вверх/вниз/влево/вверх/прямо ... и т. д. начальной точки. Heres ядра моей логики:Пожалуйста, покажите мне более элегантный способ сделать это

function getSector() { 
    var y = startY - endY; 
    var x = startX - endX; 
    var angle = Math.atan2(y,x) * 57.29578;//~57 deg per radian 
    //atan2(y,x) returns a num between -PI and PI, represents angle in radians 
    console.log("angle:" + angle); 
    if((angle > -22.5) && (angle < 22.5)) attackDir = "left"; 
    if((angle > 22.5) && (angle < 67.5)) attackDir = "upleft"; 
    if((angle > 67.5) && (angle < 112.5)) attackDir = "up"; 
    if((angle > 112.5) && (angle < 157.5)) attackDir = "upright"; 
    if((angle > 157.5) && (angle <= 180)) attackDir = "right"; 
    if((angle > -179) && (angle <= -157)) attackDir = "right"; 
    if((angle > -157) && (angle < -112.5)) attackDir = "downright"; 
    if((angle > -112.5) && (angle < -67.5)) attackDir = "down"; 
    if((angle > -67.5) && (angle < -22.5)) attackDir = "downleft"; 
    console.log("attackDir:" + attackDir); 
} 

Я заинтересован в том, лучший способ, но более того, как вы пришли в этом пути.

Я предполагаю, что ключ сортов будет в порядке: слева = 0 до = 90 вправо = 179 или -179 (вниз, как отрицательное зеркало вверх) вниз = -90

+0

Ваш код только иногда совпадает с равенством. Вы должны либо превратить все '>' 'в'> = ', либо все' '' 'в' <= '. –

ответ

4

Когда делая проверку границ, это гораздо более читаемо, если вы создаете функцию с именем Between (min, val, max);

function Between(min, val, max) 
{ 
return (val > min) && (val < max); 
} 

Кроме того, вы можете проверить вправо/влево, а затем после этого испытания для вниз/вверх .. в то время как добавление к строке. Тогда ваша логика сокращается до 4-х утверждений.

var final=""; 
if(/*IsUp*/) final="up" 
else if(/*IsDown*/) final="down" 

if(/*IsRight*/) final+= "right"; 
else if(/*IsLeft*/) final += "left"; 

Редактировать: Как заявляет Стефан, 57.29578 - это магическое число. Я даже не представлял, что вы имели в виду 180/(Math.Pi) ... Как он также заявил, «оптимизация», которую вы делаете, делает ваш код просто неразборчивым, а прирост производительности спорным.

Вы должны всегда проверять u/d/l/r на позицию x/y относительно источника, а не на углы.

+0

Проклятье, это чертовски приятно. Он возвращает true, если выполняются оба условия. Почему я не могу придумать такой код? =) Я провел большую часть 2 часов, играя с моим примером, и вы отвечаете в течение 10 минут. Спасибо. – jason

+0

Почему один -1? – Warty

+0

и почему это тоже было запрещено? – Anurag

1

Как насчет использования slope?

м = ду/дх

+0

Можете ли вы уточнить? – jason

+0

Почему это было опущено? – Anurag

+0

Как вы проводите различие между 45 градусами и 225 градусами по склону? Склоны линий точно такие же. – Warty

0

Не используйте углы. Кроме того, если вы используете 180/PI, просто напишите 180/PI. Вы получаете очень мало скорости для огромного воздействия на читаемость.

var dy = endY - startY; 
var dx = endX - startX; 
var isUp = dy < 0; 
var isDown = dy > 0;//probably use some fudge here for a better neutral zone, if you're parsing input 
var isLeft = dx < 0; 
var isRight = dx > 0; 

Это предполагает систему координат, которая имеет (0,0) в верхнем левом углу, и (п, п) в правом нижнем углу, как и во многих графических приложениях.

+0

ах, я вижу, что ты там сделал ... умный. может пойти еще дальше: var direction = endY jason

+0

Если вам нужны жесты, вы захотите изменить «0» на некоторый номер «выдумки». –

0

Возможно, у вас меньше кода путем индексации подходящего массива строк («справа», «прямо», «прямо», ...) с parseInt((angle+180)/22.5).

0
if  (angle <= -157) attackDir = "right"; 
else if (angle < -112.5) attackDir = "downright"; 
else if (angle < -67.5) attackDir = "down"; 
else if (angle < -22.5) attackDir = "downleft"; 
else if (angle < 22.5) attackDir = "left"; 
else if (angle < 67.5) attackDir = "upleft"; 
else if (angle < 112.5) attackDir = "up"; 
else if (angle < 157.5) attackDir = "upright"; 
else if (angle <= 180) attackDir = "right"; 
1

Поскольку функция просто функции по биннингу диапазоне углов [-pi, PI] в 8 равных бункерах, существует простое линейное отображение с угла к индексу бен. Это общий шаблон для добавления меток по фиксированному числу одинаково размерных ящиков в фиксированном диапазоне.

Пример:

var angle = Math.atan2(y,x) * 57.29578;//~57 deg per radian 

, где угол находится в пределах диапазона [-180, 180]. Таким образом, (angle + 157.5)/45.0 находится в пределах диапазона [-0,5, 7.5] и (angle+157.5)/45.0 + 0.5 в пределах диапазона [0,0, 8,0]. Эти бункеры разделены на 0,5, 1,5, 2,5 ... 7.5, так что округление значения приведет everythin в левой/правой части boundry на правильный индекс бен:

var bin_index = parseInt(Math.round((angle + 157.5)/45.0 + 0.5)); 

Поскольку бен 8 и бен 0 фактически то же самое, мы используем оператор модуля, чтобы объединить эти корзины индексы в следующем:

bin_index = bin_index % 8; // bin_index == 8 becomes bin_index == 0 too 

Теперь вы можете посмотреть свой результат строку с помощью индекса бен :)

var bin_labels = ['right', 'downright', 'down', 'downleft', 'left', 'upleft', 'up', 'upright']; 
return bin_labels[bin_index]; 

EDIT: ввод выше линий вместе:

function getSector() { 
    var dy = startY - endY; 
    var dx = startX - endX; 
    var angle = Math.atan2(dy,dx) * 180.0/Math.PI; // we can assume -180.0 <= angle <= 180.0 

    // partition angle space in 8 equal bins, 
    // lowest bin should have index 0, the highest 7 
    var bin_index = parseInt(Math.round((angle + 157.5)/45.0 + 0.5)); 
    bin_index = bin_index % 8; // ensure bin_index == 8 -> bin_index == 0 

    // return the correct bin label 
    var bin_labels = ['right', 'downright', 'down', 'downleft', 'left', 'upleft', 'up', 'upright']; 
    return bin_labels[bin_index]; 
} 
Смежные вопросы