确定四球面边缘的四叉树邻居的有效方法?

时间:2018-11-20 15:55:16

标签: unity3d quadtree

我一直在尝试优化如何在Quad Sphere的Top和Bottom面以及其余面中查找Quad Tree面的邻居。我尝试了几种方法来确定邻居,最新的方法提高了查找速度,但是我想知道是否还有更好的方法

方法1:

保留所有Quad使用的所有顶点的所有用户的查找表,然后对于每个Quad,查找不是祖先与原始Quad共享边缘顶点的其他任何Quad(减去拐角顶点,因为它们是共享的由多个非邻居)。这对于少量的细分和顶点非常有用,但是随着每个细分和顶点的增加,性能会变得更差。 请参见此实现示例:https://github.com/bicarbon8/QuadSphere/blob/master/Assets/Scripts/QuadVertMap.cs#L104

方法2:

保留每个细分级别的所有Quad的查找表,并按级别进行索引,然后为每个Quad查找不是祖先的同级或少一级(父级)的其他Quad,并检查其边缘顶点以查看它们是否与原始Quad的边缘顶点匹配。这比方法1更好,但是如果您对细分级别的了解太深,它仍然会受到影响。看起来像下面的代码片段:

public Quad FindNeighbor(Quad quad, EdgeType edge)
{
    Vector3[] edgeVerts = quad.GetWorldVerts(quad.GetEdgeVerts(edge));
    int level = quad.GetLevel(); // neighbors can only be equal or 1 lower level

    List<Quad> potentialNeighbors = Quads[level].Where(n => n != quad).ToList();
    if (potentialNeighbors.Any())
    {
        foreach (Quad potentialNeighbor in potentialNeighbors)
        {
            var topEdge = potentialNeighbor.GetWorldVerts(potentialNeighbor.GetEdgeVerts(EdgeType.Top));
            if (topEdge.All(v => edgeVerts.Contains(v)))
            {
                return potentialNeighbor;
            }
            var bottomEdge = potentialNeighbor.GetWorldVerts(potentialNeighbor.GetEdgeVerts(EdgeType.Bottom));
            if (bottomEdge.All(v => edgeVerts.Contains(v)))
            {
                return potentialNeighbor;
            }
            var leftEdge = potentialNeighbor.GetWorldVerts(potentialNeighbor.GetEdgeVerts(EdgeType.Left));
            if (leftEdge.All(v => edgeVerts.Contains(v)))
            {
                return potentialNeighbor;
            }
            var rightEdge = potentialNeighbor.GetWorldVerts(potentialNeighbor.GetEdgeVerts(EdgeType.Right));
            if (rightEdge.All(v => edgeVerts.Contains(v)))
            {
                return potentialNeighbor;
            }
        }
    }

    if (level > 0)
    {
        // if we made it this far we haven't found a neighbor yet so try 1 level lower Quads
        potentialNeighbors = Quads[level - 1].Where(n => n != quad.GetParent()).ToList();
        if (potentialNeighbors.Any())
        {
            foreach (Quad potentialNeighbor in potentialNeighbors)
            {
                var topEdge = potentialNeighbor.GetWorldVerts(potentialNeighbor.GetEdgeVerts(EdgeType.Top));
                if (topEdge.Any(v => edgeVerts.Contains(v)))
                {
                    return potentialNeighbor;
                }
                var bottomEdge = potentialNeighbor.GetWorldVerts(potentialNeighbor.GetEdgeVerts(EdgeType.Bottom));
                if (bottomEdge.Any(v => edgeVerts.Contains(v)))
                {
                    return potentialNeighbor;
                }
                var leftEdge = potentialNeighbor.GetWorldVerts(potentialNeighbor.GetEdgeVerts(EdgeType.Left));
                if (leftEdge.Any(v => edgeVerts.Contains(v)))
                {
                    return potentialNeighbor;
                }
                var rightEdge = potentialNeighbor.GetWorldVerts(potentialNeighbor.GetEdgeVerts(EdgeType.Right));
                if (rightEdge.Any(v => edgeVerts.Contains(v)))
                {
                    return potentialNeighbor;
                }
            }
        }
    }

    return null;
}

是否有任何对此有经验并愿意分享其他优化查找方法的人?预先感谢。

1 个答案:

答案 0 :(得分:0)

由于这篇文章没有收到任何回应,我最终要做的是根据一些基本规则分配同级邻居,然后为非同级邻居找到父级quad,获取其相邻子级,看看他们中是否有人在这个四边形上共享一条边缘

// Get all occurences of the clicked letter and push their positions into array

  function letterClicked(id) {
    var positionsOfLetter = [];
    for (var i = 0; i < randomWord.length; i++) {
      if (randomWord[i] == id) {
        positionsOfLetter.push(i);
      }
    }
    // Replace each box at position that contains the letter clicked with a box containing the letter clicked

    positionsOfLetter.forEach(position => {
      $('#' + position).replaceWith($("#" + id));
    });
  }

这似乎很快起作用,因为所有同级邻居都是直接分配,并且非同级邻居的位置仅限于遍历4个四边形的4个边。这是 HasSharedEdge 方法:

private void AddNeighbors()
{
    switch (QuadType)
    {
        case QuadType.BottomLeft:
            // add siblings
            AddNeighbor(EdgeType.Top, () => { return GetParent().GetChild(QuadType.TopLeft); });
            AddNeighbor(EdgeType.Right, () => { return GetParent().GetChild(QuadType.BottomRight); });

            // add non-siblings
            AddNeighbor(EdgeType.Bottom, () =>
            {
                return GetParent().GetNeighbor(EdgeType.Bottom)?.GetChildren()?.FirstOrDefault(c => c != null && HasSharedEdge(EdgeType.Bottom, c));
            });
            AddNeighbor(EdgeType.Left, () =>
            {
                return GetParent().GetNeighbor(EdgeType.Left)?.GetChildren()?.FirstOrDefault(c => c != null && HasSharedEdge(EdgeType.Left, c));
            });
            break;
        case QuadType.BottomRight:
            // add siblings
            AddNeighbor(EdgeType.Top, () => { return GetParent().GetChild(QuadType.TopRight); });
            AddNeighbor(EdgeType.Left, () => { return GetParent().GetChild(QuadType.BottomLeft); });

            // add non-siblings
            AddNeighbor(EdgeType.Bottom, () =>
            {
                return GetParent().GetNeighbor(EdgeType.Bottom)?.GetChildren()?.FirstOrDefault(c => c != null && HasSharedEdge(EdgeType.Bottom, c));
            });
            AddNeighbor(EdgeType.Right, () =>
            {
                return GetParent().GetNeighbor(EdgeType.Right)?.GetChildren()?.FirstOrDefault(c => c != null && HasSharedEdge(EdgeType.Right, c));
            });
            break;
        case QuadType.TopLeft:
            // add siblings
            AddNeighbor(EdgeType.Bottom, () => { return GetParent().GetChild(QuadType.BottomLeft); });
            AddNeighbor(EdgeType.Right, () => { return GetParent().GetChild(QuadType.TopRight); });

            // add non-siblings
            AddNeighbor(EdgeType.Top, () =>
            {
                return GetParent().GetNeighbor(EdgeType.Top)?.GetChildren()?.FirstOrDefault(c => c != null && HasSharedEdge(EdgeType.Top, c));
            });
            AddNeighbor(EdgeType.Left, () =>
            {
                return GetParent().GetNeighbor(EdgeType.Left)?.GetChildren()?.FirstOrDefault(c => c != null && HasSharedEdge(EdgeType.Left, c));
            });
            break;
        case QuadType.TopRight:
            // add siblings
            AddNeighbor(EdgeType.Bottom, () => { return GetParent().GetChild(QuadType.BottomRight); });
            AddNeighbor(EdgeType.Left, () => { return GetParent().GetChild(QuadType.TopLeft); });

            // add non-siblings
            AddNeighbor(EdgeType.Top, () =>
            {
                return GetParent().GetNeighbor(EdgeType.Top)?.GetChildren()?.FirstOrDefault(c => c != null && HasSharedEdge(EdgeType.Top, c));
            });
            AddNeighbor(EdgeType.Right, () =>
            {
                return GetParent().GetNeighbor(EdgeType.Right)?.GetChildren()?.FirstOrDefault(c => c != null && HasSharedEdge(EdgeType.Right, c));
            });
            break;
    }
}

也许这可以在将来帮助别人