如何计算某事物是否属于某个人的视野

时间:2014-03-20 19:08:37

标签: algorithm math vector language-agnostic geometry

我有一个在2D空间和速度中有位置的主题,两者都由向量表示。受试者的每侧视野为135度。它看起来与移动方向相同(速度矢量)。

我的对象在2D空间中的位置由向量表示。

在图纸中,蓝色背景上的物体是可见的,红色背景上的物体对主体不可见。

我如何计算在给定时刻哪个物体位于受试者的视野中?

Which objects lie in field of vision

2 个答案:

答案 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)(中心图片)。我们假设极角分别为alphabeta。那么(vx, vy)(x2 - x1, y2 - y1)之间的角度就是这些极角的差异(右图)。

Figure 1 Figure 2 Figure 3

然而,这是一个技巧。您获得的alphabeta值通常是从-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有两个限制。

  1. 距离拍摄对象太远的物体不会扩展。
  2. 不在FOV范围内的对象也不会展开。对于物体的边缘与FOV角度线中的至少一个相交的情况存在例外。
  3. 下面的例子说明了为什么这很重要,以及给出一个使用窄FOV的不太可能的最坏情况的例子,以及FOV距离太大而无法产生影响的情况。没有例外,它永远不会到达FOV中的唯一对象。

    Narrow FOV worst case example

    快速编辑:在示例图像中添加了数字,以便更清楚地了解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,它提供了一些类方法和类成员。方法和成员总结如下:

    班级成员:

    • pos:物体2D位置
    • minDistFOV:最小FOV距离。最有可能是0.0但可能更高。
    • maxDistFOV:最大FOV距离。未知,但算法假设它是固定的距离。

    班级方法:

    • isWithinFOV(Object):确定给定的Object是否在此Object的FOV中。如果是,则返回True。

    以下功能也不包含在此处,但包含了如何编码的链接。在网上找到它们也不难。

    • offset(点,角度,方向):返回通过给定角度和距离偏移2D点而得到的2D点。
    • intersects(segment1,segment2):确定两个线段是否相交。

    伪代码如下所示。

    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