圆上两度标记之间的最短距离?

时间:2012-02-29 20:09:47

标签: c++ trigonometry geometry

我正在寻找一个公式来找到圆上两度标记之间的最短距离:例如,30度和170度(140度)。

两度标记实际上可以是任何实数,并且不一定在0到360之间(可以是负数,或者远大于360,例如-528.2和740(其为171.8度))。然而,距离应该总是<= 180度并且> = 0度。

听起来很简单。但是,我一直试图找到一个很好的解决方案,我已经尝试了很多不同的代码,但到目前为止我发现的所有情况都没有尝试过。我在c ++工作。有没有人有任何想法?

9 个答案:

答案 0 :(得分:20)

  • 第1步:获得“原始”差异。例如,给定-528.2740.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)

答案 1 :(得分:2)

你也可以使用矢量数学和三角学;角度在这里是弧度。

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);
}

答案 2 :(得分:0)

您可以在两个角度和两个方向上应用此处找到的公式(http://en.wikipedia.org/wiki/Arc_(geometry))。 因此,您可以找到两个互补的距离(如果您将它们相加,您将获得圆周(或者您可以通过从圆周中减去另一个圆弧的长度来获得一个圆弧的长度)。

然后,您可以比较两个长度,以获得两个点在不同角度的最小距离。

在C ++中,你有math.h库:http://www.cplusplus.com/reference/clibrary/cmath/

答案 3 :(得分:0)

当然,您需要为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);

答案 4 :(得分:0)

我遇到类似的问题

  • 从任意点到圆圈中任意点的最短距离。 我按如下方式获得了解决方案:

如果 N = 圈子中的点数

price

j 第二点 第一点

这是解决方案的小python代码。

item

我认为这可以通过稍微调整程度来找到解决方案。

答案 5 :(得分:0)

我一直在寻找用于变速箱的类似微控制器的解决方案,以寻找动画电子人偶,但我没有足够的精力来正确地计算触发。

@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;

}

答案 6 :(得分:0)

对于像我这样的初学者,其他答案-尽管很可能会给您带来良好的结果-却很难理解发生了什么。因此,这是我的方法,用于检查cp(当前点)和tp(目标点)之间哪个方向(顺时针或逆时针)最短。还将最短距离值分配给shortestDistance变量。根据我特别需要此方法的条件,对于我来说,返回最短距离是沿顺时针方向还是逆时针方向的布尔值非常重要。方法如下:

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是整数度的目标点;可以将类型更改为double以获得更高的精度。

它确实说明了(逆时针)经过0度标记。

3个if检查:

  1. 起始点/当前点(cp)是否等于目标点(tp)?如果是这样,则不会给出距离。
  2. 如果不相等,则目标点是>当前点(以度为单位)还是目标点<当前点(以度为单位)?
  3. 基于此,嵌套中的最后一个if检查是否顺时针旋转的度数小于逆时针旋转的度数(反之亦然)。

同样,其他代码较短的帖子也可以正常工作。

编辑:顺便说一句,shortestDistance变量是一个类变量,在与此方法相同的类中初始化;如果要翻录这段代码,请确保要放置它的类还具有基于基本类型的shortestDistance变量,作为cp和tp变量(或强制转换)。

答案 7 :(得分:-1)

当你除以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;
}

答案 8 :(得分:-1)

我们必须假设一个圆圈只有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.标记2将为315.

现在你只需取差值的绝对值:

result = abs(mark1 - mark2) = 155