#javascript #math #geometry #angle
#язык JavaScript #математика #геометрия #угол
Вопрос:
У меня есть два нормализованных угла (в диапазоне от 0 до 360 градусов), и я хочу сравнить их, используя оценку от 0 до 1.
Например:
var angle1 = 90; var angle2 = 100; // Something like this, but with respect to the direction the angles pointing to var score = 0.9;
Я придумал следующий код:
function modulo(x, y){ return (x % y y) % y; } // Calculates the closest distance between the two angles var relativeAngle = angle2 - angle1; relativeAngle = modulo((relativeAngle 180), 360) - 180; // Converts the result to a score and logs the result console.log(1 - (Math.abs(relativeAngle) / 360));
Проблема, с которой я сталкиваюсь, заключается в том, что 0, 90 дает тот же результат, что и 0, 270 (0,75), что логично, но бесполезно для сравнения углов, поскольку они указывают в противоположных направлениях.
То, что я ищу, — это метод сравнения углов относительно ориентации, используя оценку от 0 до 1. У кого-нибудь есть идеи, как я мог бы заставить это работать? Заранее спасибо!
Правка 1, пример:
На этом изображении зеленый, желтый и красный углы расположены ближе друг к другу, поэтому они должны иметь большее сходство.
Если бы я мог догадаться:
красно-зеленый = 0,9 красно-оранжевый = 0,8
Фиолетовый, однако, настолько далек от синего, насколько это возможно.
Таким образом, сходство должно быть примерно таким:
фиолетово-синий = 0,1
Правка 2, как должен работать алгоритм:
Комментарии:
1. Если вам нужна информация об ориентации, мне кажется логичным отказаться
abs
от нее и использовать[-1, 1]
интервал для сходства (при правильной нормализации).2. Я тоже об этом подумал. Однако отрицательные углы тогда дали бы более низкую оценку сходства, чем положительные углы, что сделало бы оценку бесполезной.
3. Для контекста: я уменьшаю оценку массива угловых пар, усредняя их.
4. Не могли бы вы поделиться некоторыми примерами? Трудно понять, что вы хотите получить в результате, кроме того, чтобы оно было между 0 и 1.
5.Ваши требования кажутся невыполнимыми. Предполагать
angle1 = 0.0
. Теперь, предположительноangle2 = 0.0
, если вы тоже хотите получить оценку1
. Теперь увеличивайтеangle2
медленно: оценка будет постепенно уменьшаться (она не может увеличиваться, потому1
что это максимальный балл), и для некоторого положительного значенияangle2
она будет0.9
, скажем. Но вы также можете медленно уменьшатьсяangle2
, начиная с0.0
— опять же, в какой-то момент вы получите что-то со счетом0.9
относительно угла 1. Поэтому, предполагая, что вы хотите, чтобы оценка была непрерывной функцией углов, я не вижу способа удовлетворить ваши требования.
Ответ №1:
Из вашего описания кажется, что вы хотите каким-то образом разделить среднюю ориентацию и разделение вместе в одно значение. Я не уверен, что это возможно из-за псевдонимов (на которые вы намекаете в своем вопросе).
Сравнение пары углов, как вы описываете, — это просто вычисление их минимального угла разделения.
Однако при сравнении двух наборов углов так, как вы описываете, также необходимо учитывать разницу в относительной ориентации между двумя наборами. Поскольку каждая пара может быть преобразована в пару [разделение, ориентация], две пары могут быть оценены относительно на основе декартова расстояния.
// Smallest difference between angles as on a circle // range [0, 1) const angle = (a,b) =gt; { const results = a gt; b ? a - b : b - a; return (results gt; 180 ? 360 - results : results) / 180; } // Midway between two angles as on a circle // range [0, 1) const direction = (a,b) =gt; { const large = (a gt; b ? a - b : b - a) gt; 180; const results = (a b) / 2; return (results (large ? (results gt;= 180 ? -180 : 180 ) : 0)) / 180; }; // Cartesian distance score // range [0, 1) // x is angle, y is direction const distance = (x0, y0, x1, y1) =gt; { // direction wraps around so account for that if((y0 gt; y1 ? y0 - y1 : y1 - y0) gt; 0.5) y0 = 1; // the `*2` is because the wrap-around distance is never more than half the interval. return Math.sqrt((x0-x1)**2 ((y0-y1)*2)**2) / Math.SQRT2; } // Difference score for two angles, a and b const diff = (a,b) =gt; angle(a, b); // Difference score for two pairs of angles [[a0, b0], [a1, b1]] const diff2 = (a0, b0, a1, b1) =gt; distance( angle(a0, b0), direction(a0, b0), angle(a1, b1), direction(a1, b1) );
Комментарии:
1. Я думаю, что интервалы равны [0, 1), но я не уверен на 100%. Они могут быть [0, 1].
2. Спасибо, что нашли время. Я только что протестировал его, и, похоже, он возвращает правильные значения.
3. Я заметил некоторые проблемы с расчетом и поведением «направления», поэтому исправил их. Направление оборачивается так, что обертывание должно учитываться в
direction()
иdistance()
. В противном случае в подсчете очков был бы артефакт, когда пары находятся близко, но на противоположных сторонах пересечения 360/0.