4

不知道如何使标题更具描述性,所以我将从一个示例开始。我正在使用下面的代码位,它从枚举中选择一个方向,具体取决于与给定方向相比,四个轴中的哪个轴形成的角度最小。

static Direction VectorToDirection(Vector2 direction)
{
    double upDiff = System.Math.Acos(Vector2.Dot(direction, -Vector2.UnitY));
    double downDiff = System.Math.Acos(Vector2.Dot(direction, Vector2.UnitY));
    double leftDiff = System.Math.Acos(Vector2.Dot(direction, -Vector2.UnitX));
    double rightDiff = System.Math.Acos(Vector2.Dot(direction, Vector2.UnitX));

    double smallest = System.Math.Min(System.Math.Min(upDiff, downDiff), System.Math.Min(leftDiff, rightDiff));

    // This is the part I'm unsure about i.e.
    // Comparing smallest with each value in turn
    // To find out which of the four was "selected"
    if (smallest == upDiff) return Direction.Up;
    if (smallest == downDiff) return Direction.Down;
    if (smallest == leftDiff) return Direction.Left;
    return Direction.Right;
}

但是我最后收到了关于浮点相等的 Resharper 警告。我猜这应该不是由于实现的问题,但想知道除了与每个原始值进行比较之外Min,是否还有更好的习惯用法来解决此类问题。 smallest

4

9 回答 9

2

此代码应该为您提供所需的结果。

    if ((Math.Abs(direction.x) >= Math.Abs(direction.y))
      return direction.x >= 0 ? Direction.Right : Direction.Left;
    return direction.y >= 0 ? Direction.Up : Direction.Down;
于 2012-08-06T18:02:18.797 回答
1

您可以制作一个对字典进行<double ,Direction> 排序的字典,并使用正确的枚举获取最小值以返回。

于 2012-08-06T17:59:55.087 回答
1

可以定义一个包含差异和与之关联的值的类。然后,您从这些对象中收集并按差异对它们进行排序。之后返回与第一个元素关联的值。

但是,在您的情况下,我不会去那里,代码很清楚。如果可能值的数量更大(或事先不知道),那么我才会寻求更通用的解决方案。

于 2012-08-06T18:03:02.747 回答
1

你能写一些if语句吗?

if  (upDiff < leftDiff && upDiff < downDiff && upDiff < rightDiff) return Direction.Up;
if  (leftDiff < upDiff && leftDiff < downDiff && leftDiff < rightDiff) return Direction.Left;
if  (rightDiff < leftDiff && rightDiff < upDiff && rightDiff < downDiff) return Direction.Right;
return Direction.Down;

也许它可以进一步清理,但这似乎是直截了当的。

于 2012-08-06T18:05:31.197 回答
1

我会将所有选择放在一个数组中并找到最小索引。对于 4 个选择,排序可能是矫枉过正。如果此代码的性能很重要 - 请确保测量不同变体的时间。

未编译代码如下:

static Direction VectorToDirection(Vector2 direction)
{
  var directions = new Direction[]{
    Direction.Up, Direction.Down, Direction.Right, Direction.Left };
  var unit = new Vector2[] {
   -Vector2.UnitY, Vector2.UnitY, Vector2.UnitX,-Vector2.UnitY};

  var minAngle = 10;
  var minIndex = -1;
  for(var index = 0; index < directions.length; index++)
  {
    double diff = System.Math.Acos(Vector2.Dot(direction, unit[index]));
    if (diff < minAngle)
    { 
      minAngle = diff;
      minIndex = index;
    }

  return directions[minIndex];
}
于 2012-08-06T18:09:27.213 回答
1
static Direction VectorToDirection(Vector2 direction)
{
    var mappings = new[]
    {
        new { Direction = Direction.Up, Axis = -Vector2.UnitY },
        new { Direction = Direction.Down, Axis = Vector2.UnitY },
        new { Direction = Direction.Left, Axis = -Vector2.UnitX },
        new { Direction = Direction.Right, Axis = Vector2.UnitX }
    };
    return mappings.OrderBy(m => Math.Acos(Vector2.Dot(direction, m.Axis))).Select(m => m.Direction).First();
}

林克方式。这未经测试,但你应该得到它。

于 2012-08-06T18:09:45.093 回答
0

设置不准确

if ((Math.Abs(smallest - upDiff) < 0.00001) return Direction.Up;
于 2012-08-06T17:56:27.133 回答
0

有了你这样做,我认为不会有任何错误。但是,如果您将来最终重构或更改代码,您可能会遇到一些问题。

为了安全起见,请按照 resharper 的建议进行操作。

于 2012-08-06T18:01:06.457 回答
0

我通常使用switch而不是if-else(至少 3 个子句)——有点简洁和快速。

switch(smallest) {
  case upDiff: return Direction.Up;
  case downDiff: return Direction.Down;
  case leftDiff: return Direction.Left;
  default: return Direction.Right; 
}
于 2012-08-06T18:03:04.510 回答