我有一个在2D空间和速度中有位置的主题,两者都由向量表示。受试者的每侧视野为135度。它看起来与移动方向相同(速度矢量)。
我的对象在2D空间中的位置由向量表示。
在图纸中,蓝色背景上的物体是可见的,红色背景上的物体对主体不可见。
我如何计算在给定时刻哪个物体位于受试者的视野中?
答案 0 :(得分:5)
您只需要找到物体的距离和朝向它们的角度。然后,检查距离是否不大于该浅蓝色圆圈的半径,并且速度矢量和对象矢量之间的角度不会太大。
欧几里德距离只是sqrt ((x2 - x1)^2 + (y2 - y1)^2)
(link)。
对于角度,表示polar coordinate system中的向量(x2 - x1, y2 - y1)
和速度(vx, vy)
,然后检查角度之间的绝对差异是否不超过135度。在编程语言中,通常有一个方便的函数atan2 (y, x)
来查找单个向量的极角(link)。
点的极角是从矢量Ox逆时针方向测量的。考虑我们有两点:速度向量的端点(vx, vy)
(左图)和从我们的对象(x1, y1)
到有问题的对象(x2, y2)
的向量的端点:它是向量(x2 - x1, y2 - y1)
(中心图片)。我们假设极角分别为alpha
和beta
。那么(vx, vy)
和(x2 - x1, y2 - y1)
之间的角度就是这些极角的差异(右图)。
然而,这是一个技巧。您获得的alpha
和beta
值通常是从-PI到+ PI,或从0到2PI。因此,差异beta - alpha
将介于-2PI和+ 2PI之间,并且您希望它介于-PI(从当前方向顺时针180度)和+ PI(从当前方向逆时针180度)之间。为此,一些简单的转换就足够了,比如这个伪代码:
if angle > +PI:
angle := angle - 2PI
if angle < -PI:
angle := angle + 2PI
答案 1 :(得分:1)
假设每个对象的FOV需要同时进行测试(也就是每个对象成为主题)的可能优化是使用被视为图形的对象的Delaunay三角剖分以允许BFS搜索各种各样的。这个BFS有两个限制。
下面的例子说明了为什么这很重要,以及给出一个使用窄FOV的不太可能的最坏情况的例子,以及FOV距离太大而无法产生影响的情况。没有例外,它永远不会到达FOV中的唯一对象。
快速编辑:在示例图像中添加了数字,以便更清楚地了解BFS搜索的工作方式。标记为1的对象是最近的对象。它被扩展,导致标记为2的对象。这些对象被用于产生标记为3的对象,依此类推。较粗的线表示在扩展期间使用哪些边缘(从较低标签指向较高标签)。因此,只有最左边的对象不会被扩展。
如果需要针对每个对象测试FOV,算法的性能是:
O(N log N + NT)
其中N是对象的数量,T是测试的平均对象数。将其与O(N * V)的理想输出敏感算法进行比较,其中V是FOV中的平均对象数。平均而言,O(T)应为O(V)。缺点是,由于一切都达到FOV区域,V可能是N / C,其中C是一些常数因子,从技术上讲是O(N),但这个常数确实非常低。近似C的一种方法是&#34;(物体的凸包的面积)/(FOV的面积)&#34;。其基础是,凸包的一小部分面积平均可能包含大致相等的一部分物体。
psudeocode假设每个对象(包括主题)都是类的一部分,为简单起见,将其称为Object,它提供了一些类方法和类成员。方法和成员总结如下:
班级成员:
班级方法:
以下功能也不包含在此处,但包含了如何编码的链接。在网上找到它们也不难。
伪代码如下所示。
function lineSegmentFOV(subject, angle):
# This function gets the one of line segments that represent the edges of the FOV
# That is one of the red lines in the image
segmentNearPos = offset(subject.pos, angle, subject.minDistFOV)
segmentFarPos = offset(subject.pos, angle, subject.maxDistFOV)
return (segmentNearPos, segmentFarPos)
function findObjectsInFOV(subject, objects, triangulation, kdTree):
objectsInFOV = new Set() # A set seemed like the best overall choice here
checkedObjects = new Set()
# Get subject's edge of FOV line segments
halfFOV = subject.FOV / 2
lowerSegment = lineSegmentFOV(subject, subject.dir - halfFOV)
higherSegment = lineSegmentFOV(subject, subject.dir + halfFOV)
# Check nearest object to subject
nearestNeighbor = kdTree.nearestNeighbor(subject)
if not subject.equals(nearestNeighbor): # Subject cannot be in it's FOV
if subject.isWithinFOV(nearestNeighbor):
objectsInFOV.add(nearestNeighbor)
checkedObjects.add(nearestNeighbor)
# Begin the search for objects within the FOV
objectsToExpand = new Queue(nearestNeighbor) # Always expand subject's nearest neighbor
while objectsToExpand.length > 0:
object = objectsToExpand.dequeue() # Get the next object to expand
if object not in checkedObjects: # Don't check an object twice
# Find expandable objects and note those that are in the FOV as well.
for adjacent in triangulation[object]:
edge = (object.pos, adjacent.pos)
# Check if object in FOV
if subject.isWithinFOV(object):
objectsInFOV.add(adjacent)
objectsToExpand.enqueue(adjacent)
# Check if object-adjacent edge intersects one of the FOV line segments
else if intersects(edge, lowerSegment) or intersects(edge, higherSegment):
objectsToExpand.enqueue(adjacent)
checkedObjects.add(adjacent)
return objectsInFOV
function findObjectsInAllFOVs(objects):
triangulation= new DelaunayTriangulation(objects)
kdTree = new KDTree(objects)
allObjectsInFOVs = new Dictionary()
# Cycle through each object to find other objects in it's FOV
for subject in objects:
allObjectsInFOVs = findObjectsInFOV(subject, objects, triangulation, kdTree)
return allObjectsInFOVs