如何在 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);
}
}
我在 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);
}
}