C#在XY网格上查找附近的点

时间:2018-08-05 23:20:26

标签: c# grid distance points

说我有一个100by100的网格。

现在我的位置是23,70。

如何在5距离内找到此网格上的所有XY点?

1 个答案:

答案 0 :(得分:1)

您的问题有点含糊,但是根据您的要求和定义,可能有一些简单的方法快速

假设我们正在谈论单位正方形网格,则有3种主要方法来定义距离:

  1. 在8个方向上的步数:n,ne,e,se,s,sw,w,nw
  2. 四个方向上的步数:n,e,s,w
  3. 细胞之间的线性距离(毕达哥拉斯)

第一个是最简单的,只是从[x - 5, y - 5][x + 5, y + 5]的正方形。足够快以进行实时计算。

第二个选项是菱形,它满足以下功能:

static bool InRange(Point C, Point P) => (Math.Abs(P.X - C.X) + Math.Abs(P.Y - C.Y)) <= 5;

最后,线性距离使用毕达哥拉斯(Pythagoras)查找像元之间的距离,并将其与您的阈值进行比较。最终形状将取决于您如何处理重叠。您可以使用以下测试功能:

static bool InRange(Point C, Point P) => ((P.X - C.X) * (P.X - C.X)) + ((P.Y - C.Y) * (P.Y - C.Y)) <= 25;

请注意,在所有情况下,可能的解决方案范围都落在第一个解决方案定义的平方中,因此您不必测试网格上的每个单元。最多有24个测试(针对5个距离)被网格的大小修改。

这是基于LINQ的通用解决方案,因为我喜欢它:

public static IEnumerable<Point> PointsInRange(this Point C, int range, int method)
{
    // select filter function
    Func<int, int, bool> filter = (x, y) => true;
    if (method == 1)
        filter = (x, y) => (Math.Abs(x) + Math.Abs(y)) <= range;
    else if (method == 2)
        filter = (x, y) => (x * x + y * y) <= (range * range);

    // apply filter to all cells in potential range
    var validOffsets = 
        from dx in Enumerable.Range(-range, range * 2 + 1)
        from dy in Enumerable.Range(-range, range * 2 + 1)
        where (dx != 0 || dy != 0) && filter(dx, dy)
        select new { dx, dy };

    // offset from center and clip to grid
    var result = 
        from o in validOffsets
        let x = C.x + o.dx
        let y = C.y + o.dy
        where x >= 0 && x < 100 && y >= 0 && y < 100
        select new Point(x, y);

    return result;
}

一如既往,您可以加快速度。

当然,如果您只想获取特定范围内的有效像元(例如5个),则可以通过在数组中指定有效偏移量而不是像上面那样计算它们来进一步减少它。您可以剪切整个方法的开头,并用具有所需形状的常量数组替换它。或将这两种想法结合起来并缓存答案,以使您具有任意范围的灵活性,并且只计算一次有效偏移即可。