计算两个方向之间的差异
Calculate difference between 2 directions
我如何计算两个角度之间的度差?
这对大多数人来说很简单,因为我只是使用:
var difference = Math.Abs(direction1 - direction2);
然而,当方向 2 为北(0 度)且方向 1 为西北(例如 318 度)时,显然这是出路。
计算北 (0) 边界后差异的正确方法是什么?
编辑:此答案假定方向是 向量 而不是角度。有关角度,请参阅
一般情况下,你取点积,用反余弦得到角度,然后乘以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 度。反之亦然,具体取决于您的坐标系。
这很简单,你需要做的就是添加一个检查,看看方向(航向)是否大于180,如果是,从360中减去差值。像这样:
static int GetHeadingDifference(int heading1, int heading2)
{
var difference = Math.Abs(heading1 - heading2);
if (difference > 180)
return 360 - difference;
return difference;
}
这将 return 正确的标题。 Here 演示。
但您可能希望将其包装在自定义 object 中以便为您处理所有事情。您可以这样做:
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
我如何计算两个角度之间的度差?
这对大多数人来说很简单,因为我只是使用:
var difference = Math.Abs(direction1 - direction2);
然而,当方向 2 为北(0 度)且方向 1 为西北(例如 318 度)时,显然这是出路。
计算北 (0) 边界后差异的正确方法是什么?
编辑:此答案假定方向是 向量 而不是角度。有关角度,请参阅
一般情况下,你取点积,用反余弦得到角度,然后乘以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 度。反之亦然,具体取决于您的坐标系。
这很简单,你需要做的就是添加一个检查,看看方向(航向)是否大于180,如果是,从360中减去差值。像这样:
static int GetHeadingDifference(int heading1, int heading2)
{
var difference = Math.Abs(heading1 - heading2);
if (difference > 180)
return 360 - difference;
return difference;
}
这将 return 正确的标题。 Here 演示。
但您可能希望将其包装在自定义 object 中以便为您处理所有事情。您可以这样做:
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