计算两个方向之间的差异

时间:2021-04-22 13:40:27

标签: c# math spatial

我将如何计算两个角度之间的差异(以度为单位)?

这对大多数人来说很简单,因为我只是使用:

var difference = Math.Abs(direction1 - direction2);

然而,当方向 2 为北(0 度)且方向 1 为西北(例如 318 度)时,显然这是出路。

计算超过北 (0) 边界的差异的正确方法是什么?

2 个答案:

答案 0 :(得分:2)

编辑:这个答案假设方向是向量而不是角度。有关角度,请参阅 Mindswipes answer

一般情况下,您取点积,使用反余弦得到角度,然后乘以 180d / Math.PI 转换为度数。这假设方向是标准化的。

var angleInDegrees = Math.ACos(direction1.Dot(direction2)) * 180d / Math.PI;

这总是在 [0, 180] 范围内产生一个正角。这适用于 2D 和 3D 向量。

如果您使用 2D 向量并且想要在 [0, 360] 中的角度,您可以通过将向量之一旋转 90 度来检查最近的旋转是顺时针还是逆时针,并检查它与另一个的角度是否为小于或大于 90 度:

var isClockwise = direction1.Dot(new Vector(direction2.Y, -direction2.X)) > 0;

如果是顺时针,则结果加上 180 度。反之亦然,具体取决于您的坐标系。

答案 1 :(得分:2)

这很简单,您只需添加一个检查以查看方向(航向)是否大于 180,如果是,则从 360 中减去差值。就像这样:

static int GetHeadingDifference(int heading1, int heading2)
{   
    var difference = Math.Abs(heading1 - heading2);
    if (difference > 180)
        return 360 - difference;
    
    return difference;
}

这将返回正确的标题。 Here 演示。


但是您可能希望将其包装在一个自定义对象中,以便为您处理所有事情。你可以这样做:

struct Heading
{
    private const float MaxDegrees = 360;
    
    // Use a float for more accurate heading
    public float Degree {get; set;}
    
    public Heading(float heading)
    {
        Degree = heading;
    }
    
    // Override addition to wrap around
    public static Heading operator +(Heading a, Heading b) 
    {
        var val = (a.Degree + b.Degree) % MaxDegrees;
        return new Heading(val);
    }
    
    // Override subtraction to always result in a number <= 180
    public static Heading operator -(Heading a, Heading b)
    {
        var difference = Math.Abs(a.Degree - b.Degree);
        if (difference > 180)
            return new Heading(MaxDegrees - difference);
        
        return new Heading(difference);
    }
    
    // Override equality to check the actual degree value
    public static bool operator ==(Heading a, Heading b)
    {
        return a.Degree == b.Degree;
    }
    
    // Overriding equality requires overriding inequality
    public static bool operator !=(Heading a, Heading b)
    {
        return !(a == b);
    }
    
    // Override Equals to catch explicit a.Equals(b) calls
    public override bool Equals(object other)
    {
        if (other is not Heading)
            return false;
        
        return ((Heading) other).Degree == Degree;
    }
    
    // When overriding equality you must implement GetHashCode
    public override int GetHashCode()
    {
        // Oerflow is ok here, just wrap
        unchecked
        {
            var hash = 17;
            hash = hash * 23 + Degree.GetHashCode();
            return hash;
        }
    }
}

它的工作演示here


P.S 如果您只想拥有一个数字,请使用它,如果您确实有向量,请使用 JonasH's answer