如何在 C# 中进行径向集合查询?

How to do radial collections querying in C#?

我在 2d space 中有很多点(具有 .X.Y 坐标)例如 KDTree 或其他一些 IEnumerable<AnyXYPointImpl> 集合.我想做的查询不是方形的,而是基于 Circle\Radius 的:

我想要的很简单:有一个点 P、方向 D 和半角 a 我们想要得到收集区域中的所有点,这些点被一个扇形所覆盖他们。

那么如何使用 LINQ 在 C# 中执行此类径向集合查询?

这是一个 non-LINQ 解决方案。

    var filteredPoints = new List<Point2D>();

    foreach (var point in points)
        if (point.IsInSector(origin, d, a))
            filteredPoints.Add(point);

这是一个solution:

用法示例:

var field = new List<Vector2>() {
            new Vector2(-1,1),  new Vector2(1,1), 
            new Vector2(-1,-1), new Vector2(1,-1)
        };

        Console.WriteLine(string.Join("; ", field.IsInSector(new Vector2(0,0), new Vector2(2,2), 45.0)));
        Console.WriteLine(string.Join("; ", field.IsInSector(new Vector2(0,0), new Vector2(2,-2), 45.0)));
        Console.WriteLine(string.Join("; ", field.IsInSector(new Vector2(0,0), new Vector2(2,0), 90.0)));

检查点的主要逻辑是通过 IEnumerable 扩展在扇区中:

public static class Extenctions {
    public static IEnumerable<IXYPoint> IsInSector(this IEnumerable<IXYPoint> source, Vector2 pointToCheck, Vector2 direction, double halfAngle)
    {
        if(!source.Any() || pointToCheck == null || halfAngle <= 0)
            return new IXYPoint[0];

        var dirVector = new Vector2() {
            X = direction.X - pointToCheck.X,
            Y = direction.Y - pointToCheck.Y
        };

        var radius = Distance(direction, pointToCheck);
        var result = new List<IXYPoint>();

        foreach(var p in source)
        {
            if(Distance(p, pointToCheck) > radius){ // check is point in circle
                continue;
            }


            if(IsPointInSector(dirVector, p, halfAngle)) // main check 
                result.Add(p);
        }

        return result;
    }

    private static double Distance(IXYPoint from, IXYPoint to)
    {
        return Math.Sqrt(Math.Pow(to.X - from.X,2) + Math.Pow(from.Y-to.Y,2));
    }

    private static bool IsPointInSector(IXYPoint directionVector, IXYPoint pointToCheck, double halfAngle)
    {
        var rq0 = Math.Pow(directionVector.X,2) + Math.Pow(directionVector.Y,2);
        var rq = Math.Pow(pointToCheck.X,2) + Math.Pow(pointToCheck.Y,2);
        return rq0 >= rq && (directionVector.X*pointToCheck.X + directionVector.Y*pointToCheck.Y)/Math.Sqrt(rq0*rq) >= Math.Cos(halfAngle/180.0*Math.PI);
    }

}