UE4 四叉树 QuadTree
Engine\Source\Runtime\Engine\Public\GenericQuadTree.h
TQuadTree
template <typename ElementType, int32 NodeCapacity = 4>
class TQuadTree
{
typedef TQuadTree<ElementType, NodeCapacity> TreeType;
public:
/** DO NOT USE. This constructor is for internal usage only for hot-reload purposes. */
TQuadTree();
TQuadTree(const FBox2D& InBox, float InMinimumQuadSize = 100.f);
/** Gets the TreeBox so systems can test insertions before trying to do so with invalid regions */
const FBox2D& GetTreeBox() const { return TreeBox; }
/** Inserts an object of type ElementType with an associated 2D box of size Box (log n). Pass in a DebugContext so when an issue occurs the log can report what requested this insert. */
void Insert(const ElementType& Element, const FBox2D& Box, const TCHAR* DebugContext = nullptr);
/** Given a 2D box, returns an array of elements within the box. There will not be any duplicates in the list. */
template<typename ElementAllocatorType>
void GetElements(const FBox2D& Box, TArray<ElementType, ElementAllocatorType>& ElementsOut) const;
/** Removes an object of type ElementType with an associated 2D box of size Box (log n). Does not cleanup tree*/
bool Remove(const ElementType& Instance, const FBox2D& Box);
/** Does a deep copy of the tree by going through and re-creating the internal data. Cheaper than re-insertion as it should be linear instead of nlogn */
void Duplicate(TreeType& OutDuplicate) const;
/** Removes all elements of the tree */
void Empty();
void Serialize(FArchive& Ar);
TreeType& operator=(const TreeType& Other);
~TQuadTree();
private:
enum QuadNames
{
TopLeft = 0,
TopRight = 1,
BottomLeft = 2,
BottomRight = 3
};
/** Node used to hold the element and its corresponding 2D box*/
struct FNode
{
FBox2D Box;
ElementType Element;
FNode() {};
FNode(const ElementType& InElement, const FBox2D& InBox)
: Box(InBox)
, Element(InElement)
{}
friend FArchive& operator<<(FArchive& Ar, typename TQuadTree<ElementType, NodeCapacity>::FNode& Node)
{
return Ar << Node.Box << Node.Element;
}
};
/** Given a 2D box, return the subtrees that are touched. Returns 0 for leaves. */
int32 GetQuads(const FBox2D& Box, TreeType* Quads[4]) const;
/** Split the tree into 4 sub-trees */
void Split();
/** Given a list of nodes, return which ones actually intersect the box */
template<typename ElementAllocatorType>
void GetIntersectingElements(const FBox2D& Box, TArray<ElementType, ElementAllocatorType>& ElementsOut) const;
/** Given a list of nodes, remove the node that contains the given element */
bool RemoveNodeForElement(const ElementType& Element);
/** Internal recursive implementation of @see Insert */
void InsertElementRecursive(const ElementType& Element, const FBox2D& Box, const TCHAR* DebugContext);
private:
/**
* Contains the actual elements this tree is responsible for. Nodes are used to keep track of each element's AABB as well.
* For a non-internal leaf, this is the list of nodes that are fully contained within this tree.
* For an internal tree, this contains the nodes that overlap multiple subtrees.
*/
TArray<FNode> Nodes;
/** The sub-trees of this tree */
TreeType* SubTrees[4];
/** AABB of the tree */
FBox2D TreeBox;
/** Center position of the tree */
FVector2D Position;
/** The smallest size of a quad allowed in the tree */
float MinimumQuadSize;
/** Whether this is a leaf or an internal sub-tree */
bool bInternal;
};
Usage
#include "GenericQuadTree.h"
//Setup the Quad tree
float UVsQuadTreeMinSize = 0.001f;
TQuadTree<uint32, 100> QuadTree(BaseMeshUVBound,UVsQuadTreeMinSize);
//Insert data
for (FTriangleElement& TriangleElement : Triangles)
{
QuadTree.Insert(TriangleElement.TriangleIndex, TriangleElement.UVsBound, DebugContext);
}
//Find a match triangle for every target vertices
TArray<uint32> QuadTreeTriangleResults;
//Reserve 10% to speed up the query
QuadTreeTriangleResults.Reserve(Triangles.Num() / 10);
for (uint32 TargetVertexIndex = 0; TargetVertexIndex < (uint32)TargetVertices.Num(); ++TargetVertexIndex)
{
//Reset the last data without flushing the memmery allocation
QuadTreeTriangleResults.Reset();
FVector2D Extent(DistanceThreshold, DistanceThreshold);
FBox2D CurBox(TargetUV - Extent, TargetUV + Extent);
while (QuadTreeTriangleResults.Num() <= 0)
{
QuadTree.GetElements(CurBox, QuadTreeTriangleResults);
Extent *= 2;
CurBox = FBox2D(TargetUV - Extent, TargetUV + Extent);
}
}
应用
UE4聚合图测试