Наименьшее расстояние между двумя градусными отметками на окружности? - PullRequest
9 голосов
/ 01 марта 2012

Я ищу формулу, чтобы найти кратчайшее расстояние в градусах между двумя градусными метками на окружности: например, 30 градусов и 170 градусов (140 градусов).

Две отметки степени могут быть практически любым действительным числом и не обязательно должны быть между 0 и 360 (могут быть отрицательными или намного больше 360, например, -528,2 и 740 (что составляет 171,8 градуса)). Однако расстояние всегда должно быть <= 180 градусов и> = 0 градусов.

Звучит достаточно просто. Но я пытался найти хорошее решение для этого, и я пробовал много другого кода, но ничего, что я нашел, пока не работает во всех случаях, которые я пробовал. Я работаю в C ++. У кого-нибудь есть идеи?

Ответы [ 9 ]

20 голосов
/ 01 марта 2012
  • Шаг 1: Получите «сырую» разницу.Например, с учетом -528.2 и 740.0 это 1268.2.

    • в одну сторону: raw_diff = first > second ? first - second : second - first
    • в другую сторону: raw_diff = std::fabs(first - second)
  • Шаг 2: Вычтите кратное 360.0, чтобы получить значение от 0.0 (включительно) до 360.0 (эксклюзив).

    • mod_diff = std::fmod(raw_diff, 360.0)
  • Шаг 3: Если это значение больше 180.0, вычтите его из 360.0.

    • в одну сторону: dist = mod_diff > 180.0 ? 360.0 - mod_diff : mod_diff
    • по-другому: dist = 180.0 - std::fabs(mod_diff - 180.0)

Это, вероятно, наиболее читабельно в виде серии утверждений:

double raw_diff = first > second ? first - second : second - first;
double mod_diff = std::fmod(raw_diff, 360.0);
double dist = mod_diff > 180.0 ? 360.0 - mod_diff : mod_diff;

Но при желаниинетрудно сложить все это в одно выражение:

180.0 - std::fabs(std::fmod(std::fabs(first - second), 360.0) - 180.0)
2 голосов
/ 01 марта 2012

Вы также можете использовать векторную математику и тригонометрию;здесь углы указаны в радианах.

float angle(float angle1, float angle2)
{
  float x1=cos(angle1);
  float y1=sin(angle1);
  float x2=cos(angle2);
  float y2=sin(angle2);

  float dot_product = x1*x2 + y1*y2;
  return acos(dot_product);
}
0 голосов
/ 29 мая 2019

Для начинающих, таких как я, другие ответы - хотя, скорее всего, они дадут вам хороший результат - было немного трудно понять, что происходит. Поэтому, вот мой метод, который проверяет, какое направление (по часовой стрелке или против часовой стрелки) является кратчайшим между cp (текущая точка) и tp (целевая точка). Это также назначает это самое короткое значение расстояния для переменной shorttestDistance. Исходя из того, для чего мне конкретно нужен этот метод, для меня было важно вернуть логическое значение относительно того, было ли кратчайшее расстояние по часовой стрелке или против часовой стрелки. Вот метод:

public boolean checkIfClockwiseIsShortest(int cp, int tp) {
    boolean clockwiseIsShortest = false;
    if (cp != tp) { // if current point and target point are not the same...
        if (tp > cp) { // if current point is less than target point AND..
            if ((tp - cp) <= ((360 - tp) + cp)) {
                clockwiseIsShortest = true;
                shortestDistance = (tp-cp);
                System.out.println("Case A: " + shortestDistance +" degrees clockwise");//[CAN REMOVE]

            } else if ((tp - cp) > ((360 - tp) + cp)) {
                clockwiseIsShortest = false;
                shortestDistance = ((360 - tp) + cp);
                System.out.println("Case B: " + shortestDistance+" degrees counter-clockwise");//[CAN REMOVE]
            }
        } else { // BUT if target point < current point
            if ((cp - tp) <= ((360 - cp) + tp)) {
                clockwiseIsShortest = false;
                shortestDistance = (cp-tp);
                System.out.println("Case C: " + shortestDistance+" degrees counter-clockwise");//[CAN REMOVE]
            } else if ((cp - tp) > ((360 - cp) + tp)) {
                clockwiseIsShortest = true;
                shortestDistance = ((360 - cp) + tp);
                System.out.println("Case D: " + shortestDistance+" degrees clockwise");//[CAN REMOVE]
            }
        }
    }
    return clockwiseIsShortest;
}

Обратите внимание, что cp является начальной точкой в ​​целых градусах, а tp является целевой точкой в ​​целых градусах; тип может быть изменен на удвоение для большей точности.

Он учитывает движение (против) по часовой стрелке за отметку 0 градусов.

3, если это проверяет:

  1. Начальная / текущая точка (cp) равна целевой точке (tp)? в таком случае расстояние не указывается.
  2. если не равно, является ли целевая точка> текущей точкой в ​​градусах ИЛИ является ли целевая точка <текущей точкой в ​​градусах? </li>
  3. Исходя из этого, последнее, если в гнезде проверяет, идет ли по часовой стрелке меньше градусов, чем против часовой стрелки (или наоборот).

Опять же, другие посты с более коротким кодом могут нормально работать.

Редактировать: Кстати, переменная shorttestDistance является переменной класса, инициализированной в том же классе, что и этот метод; если вы копируете этот код, убедитесь, что ваш класс, в который вы его помещаете, также имеет переменную shorttestDistance, основанную на типе примитива в качестве переменных cp и tp (или приведите его).

0 голосов
/ 06 января 2019

Я искал решение для микроконтроллера, подобное этому, для редуктора, ищущего аниматронную марионетку, и у меня не хватило сил для правильного расчета трига.

@ ruakh Ответ был хорошей основой, но я нашелошибка в модификации подписи @ laggyluk (добавление знака для указания направления) в комментариях (так как оно было удалено).В частности, знак был перевернут в определенных условиях.

Вот решение, которое работало для меня.Это решение работает для отметок степени по кругу, но изменение MAX_VALUE позволяет работать с произвольным максимальным диапазоном (полезно при измерении импульсов датчика положения).

Проверено на Ardunio.Отформатирован для удобства чтения.

#define MAX_VALUE 360

float shortestSignedDistanceBetweenCircularValues(float origin, float target){

  float signedDiff = 0.0;
  float raw_diff = origin > target ? origin - target : target - origin;
  float mod_diff = fmod(raw_diff, MAX_VALUE); //equates max/min boundaries. E.g 0 == 360 degrees in circle

  if(mod_diff > (MAX_VALUE/2) ){
    //There is a shorter path in opposite direction
    signedDiff = (MAX_VALUE - mod_diff);
    if(target>origin) signedDiff = signedDiff * -1;
  } else {
    signedDiff = mod_diff;
    if(origin>target) signedDiff = signedDiff * -1;
  }

  return signedDiff;

}
0 голосов
/ 04 февраля 2018

У меня была похожая проблема с поиском

  • Наименьшее расстояние от любой точки до любой точки круга. Я получил решение следующим образом:

если N = количество точек в круге

                0 -> N-1
        j before n/2 after (n-j)

               1 -> N-1
   (j-1) before [(n/2)+1] after n-j+1

               2 -> N-1
   (j-2) before [(n/2)+2] after n-j+2

               and so on

, где j равно вторая точка и i равно первая точка

Вот небольшой код Python для решения.

for i in range(0, n):
   for j in range(i,n):
          if j < n/2+i:
                 s_rt = j-i
          else :
                 s_rt = n-j+i

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

0 голосов
/ 01 марта 2012

Мы должны предположить, что круг имеет только 360 градусов, иначе это будет сложно.

Итак, первое, что вам нужно сделать, это сделать так, чтобы каждая отметка находилась в диапазоне от 0 до 360. Для этого вы можете взять модуль обеих отметок на 360. Если сумма меньше 0, тогда добавьте 360. *

Скажем, у нас 520 и -45.

mark1 = ((520 % 360) >= 0) ? (520 % 360) : 360 - (520 % 360);

mark2 = ((-45 % 360) >= 0) ? (-45 % 360) : 360 - (-45 % 360);

mark1 будет 160. mark 2 будет 315.

Теперь вы просто берете абсолютную величину разности:

result = abs(mark1 - mark2) = 155
0 голосов
/ 01 марта 2012

Вы можете попробовать получить абсолютное значение разности двух остатков при делении на 360.

#include <iostream>
#include <cmath>

using namespace std;
int degree_difference(int a, int b)
{
    return abs(a%360-b%360);
}

int main()
{
    int result = degree_difference(-235, 15);
    cout << "Difference: " << result << endl;
    return 0;
}
0 голосов
/ 01 марта 2012

Конечно, вам нужно будет импортировать математическую библиотеку для fmod и fabs.

double a = -528.2;
double b = 740.0;
double diff = (a > b ? a - b : b - a);
double mod_diff = fmod(diff, 360);
double result = (mod_diff < 180 ? mod_diff : 360 - mod_diff);
0 голосов
/ 01 марта 2012

Вы можете применить формулу, которую вы найдете здесь (http://en.wikipedia.org/wiki/Arc_(geometry)) для обоих углов и в обоих направлениях. Таким образом, вы найдете два дополнительных расстояния (если вы сложите их, вы получите окружность (или вы можете получить длину одной дуги, вычтя длину другой дуги из окружности).

Затем можно сравнить две длины, чтобы получить минимальное расстояние между двумя точками под разными углами.

В C ++ у вас есть библиотека math.h: http://www.cplusplus.com/reference/clibrary/cmath/

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