Algorithm 如何计算某人身上是否存在某种东西';人的视野

Algorithm 如何计算某人身上是否存在某种东西';人的视野,algorithm,math,vector,language-agnostic,geometry,Algorithm,Math,Vector,Language Agnostic,Geometry,我有一个物体,它在二维空间中有一个位置和一个速度,两者都用矢量表示。主体两侧的视野为135度。它看起来与运动方向相同(速度矢量) 我有一个物体,它在二维空间中的位置由一个向量表示 在图形中,蓝色背景上的对象可见,而红色背景上的对象对主体不可见 如何计算在给定时刻主体视野中的物体 您只需找到与对象的距离以及与对象的角度即可。然后,检查距离是否不大于浅蓝色圆圈的半径,以及速度矢量与对象矢量之间的角度是否过大 欧几里德距离只是sqrt((x2-x1)^2+(y2-y1)^2)() 对于角度,表示矢量(

我有一个物体,它在二维空间中有一个位置和一个速度,两者都用矢量表示。主体两侧的视野为135度。它看起来与运动方向相同(速度矢量)

我有一个物体,它在二维空间中的位置由一个向量表示

在图形中,蓝色背景上的对象可见,而红色背景上的对象对主体不可见

如何计算在给定时刻主体视野中的物体


您只需找到与对象的距离以及与对象的角度即可。然后,检查距离是否不大于浅蓝色圆圈的半径,以及速度矢量与对象矢量之间的角度是否过大

欧几里德距离只是
sqrt((x2-x1)^2+(y2-y1)^2)
()

对于角度,表示矢量
(x2-x1,y2-y1)
和速度
(vx,vy)
,然后检查角度之间的绝对差是否不超过135度。在编程语言中,通常有一个方便的函数
atan2(y,x)
来查找单个向量的极角()


点的极角从矢量Ox沿逆时针方向测量。考虑我们有两点:速度向量的终结点<代码>(Vx,Vy)< /C>(左PIC)和从我们的对象<代码>(x1,y1)的向量的端点到对象<代码>(x2,y2)< /代码>:它是向量<代码>(x2-x1,y2-y1)(中心pic)。假设极角分别为
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
如果角度>+PI:
角度:=角度-2PI
如果角度<-PI:
角度:=角度+2PI

假设每个对象的FOV都需要同时测试(即每个对象都成为主题),一种可能的优化方法是使用对象的Delaunay三角剖分,将其视为图形,以允许BFS进行排序搜索。此BFS有两个限制

  • 离主题太远的对象不会展开
  • 不在视野内的对象也不会展开。对象边缘与至少一条FOV角度线相交的情况除外 下面的示例说明了这一点的重要性,并举例说明了使用窄视场时不太可能出现的最坏情况,以及视场距离太大而无法产生影响的情况。毫无例外,它永远不会到达视野中的唯一物体

    快速编辑:在示例图像中添加数字,使BFS搜索的工作方式更加清晰。标记为1的对象是最近的对象。它被展开,从而导致标记为2的对象。这些对象将扩展为标记为3的对象,依此类推。较粗的线显示在展开过程中使用的边(从较低的标签指向较高的标签)。因此,只有最左边的对象不会展开

    如果需要对每个对象的FOV进行测试,则该算法的性能为:

    O(N log N + NT)
    
    式中,N是物体的数量,T是被测物体的平均数量。这与理想的输出敏感算法O(N*V)进行了比较,其中V是视野中对象的平均数量。平均来说,O(T)应该是O(V)。不利的一面是,因为所有的东西都在FOV区域,所以V很可能是N/C,其中C是一个常数因子,从技术上讲是O(N),但这个常数可能非常低。一种近似C的方法是“(物体凸包的面积)/(视野的面积)”。其基础是凸面外壳的一小部分区域平均可能包含大致相等的一小部分对象

    psudoCode假定每个对象(包括主题)都是类的一部分,为简单起见,将其称为Object,该类提供了一些类方法和类成员。方法和成员概述如下:

    班级成员:

    • 位置:对象的二维位置
    • minDistFOV:最小视场距离。很可能为0.0,但可能更高
    • 最大视场距离:最大视场距离。未知,但算法假定它是固定距离
    类方法:

    • isWithinFOV(对象):确定给定对象是否在此对象的视野内。如果是,则返回True
    下面的函数也不包括在这里,但是包含了关于如何对它们进行编码的链接。在网上找到他们也不会太难

    • (点、角度、方向):返回将二维点偏移给定角度和距离而产生的二维点
    • (段1、段2):确定两条线段是否相交
    伪代码如下所示

    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
    

    如果你对如何用图片计算角度展开一点讨论,这个答案将更有教育意义。另外,atan是不够的,因为它是围绕原点对称的,所以你也应该看看cos的符号。@Visa是种族主义:
    atan2
    正是这样区分的,因此两个参数而不是一个参数。至于图片,好吧,我已经给出了一个,它应该更明显吗?链接的问题是。因此,提取(甚至引用,如果足够简短的话)其中最重要的部分是一个好主意。进一步的