Вычислить сходство углов — Математика — JavaScript

#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.