#region File Description
//-----------------------------------------------------------------------------
// QuadTree.cs
//
// Microsoft XNA Community Game Platform
// Copyright (C) Microsoft Corporation. All rights reserved.
//-----------------------------------------------------------------------------
#endregion
#region Using Statements
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;
using RobotGameData.GameObject;
using RobotGameData.Helper;
#endregion
namespace RobotGameData.Collision
{
///
/// This is a quad tree only colliding. not support render model.
///
public class QuadTree
{
///
/// quad tree area.
///
enum IntersectionType
{
UpperLeft = 0,
UpperRight,
LowerLeft,
LowerRight,
}
#region Fields
protected QuadNode rootNode = null;
protected int nodeCount = 0;
protected int depthLevel = 0;
#endregion
#region Properties
public QuadNode RootNode
{
get { return rootNode; }
}
public int NodeCount
{
get { return nodeCount; }
}
public int DepthLevel
{
get { return depthLevel; }
}
#endregion
///
/// build a quad tree.
///
/// vertex array
/// quad tree depth count
///
public int Build(Vector3[] vertices, int depthLevel)
{
this.depthLevel = depthLevel;
rootNode = BuildNode(vertices, depthLevel);
rootNode.Name = "QUADTREE: root node";
return nodeCount;
}
///
/// build a quad node.
///
/// vertex array
/// quad tree depth count
/// new quad node
protected QuadNode BuildNode(Vector3[] vertices, int depthLevel)
{
QuadNode newNode = null;
Vector3 min = new Vector3(float.MaxValue, float.MaxValue, float.MaxValue);
Vector3 max = new Vector3(float.MinValue, float.MinValue, float.MinValue);
float centerX = 0.0f;
float centerZ = 0.0f;
IntersectionType[] Intersection = new IntersectionType[3];
// checks min and max of vertices
for (int i = 0; i < vertices.Length; i++)
{
if (min.X > vertices[i].X) min.X = vertices[i].X;
if (min.Y > vertices[i].Y) min.Y = vertices[i].Y;
if (min.Z > vertices[i].Z) min.Z = vertices[i].Z;
if (max.X < vertices[i].X) max.X = vertices[i].X;
if (max.Y < vertices[i].Y) max.Y = vertices[i].Y;
if (max.Z < vertices[i].Z) max.Z = vertices[i].Z;
}
centerX = (max.X + min.X) / 2;
centerZ = (max.Z + min.Z) / 2;
// creates node
newNode = new QuadNode(min, max);
newNode.Depth = this.depthLevel - depthLevel;
nodeCount++;
if (depthLevel-- > 0)
{
List upperLeftVertexList = new List();
List upperRightVertexList = new List();
List lowerLeftVertexList = new List();
List lowerRightVertexList = new List();
List medlineVertexList = new List();
// vertex count
for (int count = 0; count < vertices.Length; count += 3)
{
// Triangle
for (int i = 0; i < 3; i++)
{
// inside upper left
if (vertices[count + i].X < centerX &&
vertices[count + i].Z < centerZ)
{
Intersection[i] = IntersectionType.UpperLeft;
}
// inside upper right
else if (vertices[count + i].X > centerX &&
vertices[count + i].Z < centerZ)
{
Intersection[i] = IntersectionType.UpperRight;
}
// inside lower left
else if (vertices[count + i].X < centerX &&
vertices[count + i].Z > centerZ)
{
Intersection[i] = IntersectionType.LowerLeft;
}
// inside lower right
else if (vertices[count + i].X > centerX &&
vertices[count + i].Z > centerZ)
{
Intersection[i] = IntersectionType.LowerRight;
}
}
// intersecting with upper left area
if (Intersection[0] == IntersectionType.UpperLeft &&
Intersection[1] == IntersectionType.UpperLeft &&
Intersection[2] == IntersectionType.UpperLeft)
{
upperLeftVertexList.Add(vertices[count + 0]);
upperLeftVertexList.Add(vertices[count + 1]);
upperLeftVertexList.Add(vertices[count + 2]);
}
// intersecting with upper right area
else if (Intersection[0] == IntersectionType.UpperRight &&
Intersection[1] == IntersectionType.UpperRight &&
Intersection[2] == IntersectionType.UpperRight)
{
upperRightVertexList.Add(vertices[count + 0]);
upperRightVertexList.Add(vertices[count + 1]);
upperRightVertexList.Add(vertices[count + 2]);
}
// intersecting with lower left area
else if (Intersection[0] == IntersectionType.LowerLeft &&
Intersection[1] == IntersectionType.LowerLeft &&
Intersection[2] == IntersectionType.LowerLeft)
{
lowerLeftVertexList.Add(vertices[count + 0]);
lowerLeftVertexList.Add(vertices[count + 1]);
lowerLeftVertexList.Add(vertices[count + 2]);
}
// intersecting with lower right area
else if (Intersection[0] == IntersectionType.LowerRight &&
Intersection[1] == IntersectionType.LowerRight &&
Intersection[2] == IntersectionType.LowerRight)
{
lowerRightVertexList.Add(vertices[count + 0]);
lowerRightVertexList.Add(vertices[count + 1]);
lowerRightVertexList.Add(vertices[count + 2]);
}
// intersecting with medline
else
{
medlineVertexList.Add(vertices[count + 0]);
medlineVertexList.Add(vertices[count + 1]);
medlineVertexList.Add(vertices[count + 2]);
}
}
string prefix = String.Empty;
for (int i = 0; i < this.depthLevel - depthLevel; i++) prefix += "- ";
// upper left
if (upperLeftVertexList.Count > 0)
{
newNode.UpperLeftNode =
BuildNode(upperLeftVertexList.ToArray(), depthLevel);
newNode.UpperLeftNode.Parent = newNode;
newNode.UpperLeftNode.Name = "QUADTREE: " + prefix + "UL ";
if (newNode.UpperLeftNode.IsLeafNode )
newNode.UpperLeftNode.Name += "leaf";
else
newNode.UpperLeftNode.Name += "node";
}
// upper right
if (upperRightVertexList.Count > 0)
{
newNode.UpperRightNode =
BuildNode(upperRightVertexList.ToArray(), depthLevel);
newNode.UpperRightNode.Parent = newNode;
newNode.UpperRightNode.Name = "QUADTREE: " + prefix + "UR ";
if (newNode.UpperRightNode.IsLeafNode )
newNode.UpperRightNode.Name += "leaf";
else
newNode.UpperRightNode.Name += "node";
}
// lower left
if (lowerLeftVertexList.Count > 0)
{
newNode.LowerLeftNode =
BuildNode(lowerLeftVertexList.ToArray(), depthLevel);
newNode.LowerLeftNode.Parent = newNode;
newNode.LowerLeftNode.Name = "QUADTREE: " + prefix + "LL ";
if (newNode.LowerLeftNode.IsLeafNode )
newNode.LowerLeftNode.Name += "leaf";
else
newNode.LowerLeftNode.Name += "node";
}
// lower right
if (lowerRightVertexList.Count > 0)
{
newNode.LowerRightNode =
BuildNode(lowerRightVertexList.ToArray(), depthLevel);
newNode.LowerRightNode.Parent = newNode;
newNode.LowerRightNode.Name = "QUADTREE: " + prefix + "LR ";
if (newNode.LowerRightNode.IsLeafNode )
newNode.LowerRightNode.Name += "leaf";
else
newNode.LowerRightNode.Name += "node";
}
// intersecting with medline
if (medlineVertexList.Count > 0)
{
newNode.CreateVertices(medlineVertexList.ToArray());
}
}
else
{
newNode.CreateVertices(vertices);
}
return newNode;
}
///
/// display build information to debug output window.
///
/// total vertex count
public int Dump()
{
int vertexCount = 0;
vertexCount = this.rootNode.Dump();
System.Diagnostics.Debug.WriteLine(
"QUADTREE: total vertex count = " + vertexCount);
return vertexCount;
}
///
/// Finds a contaning quad node.
///
public QuadNode GetNodeContaining(ref CollideElement bounds)
{
if (rootNode != null)
{
if (rootNode.Contains(ref bounds) )
return rootNode.GetNodeContaining(ref bounds);
}
return null;
}
}
}