/// <summary> /// build a quad tree. /// </summary> /// <param name="vertices">vertex array</param> /// <param name="depthLevel">quad tree depth count</param> /// <returns></returns> public int Build(Vector3[] vertices, int depthLevel) { this.depthLevel = depthLevel; rootNode = BuildNode(vertices, depthLevel); rootNode.Name = "QUADTREE: root node"; return nodeCount; }
protected bool TestUsingQuadTree(CollideElement sourceCollide, QuadNode quadNode, out Vector3 intersect, out Vector3 normal, out float distance) { bool result = false; float tempDistance = 0.0f; Vector3 tempIntersect = Vector3.Zero; Vector3 tempNormal = Vector3.Zero; float closestDistance = float.MaxValue; Vector3 closestIntersection = Vector3.Zero; Vector3 closestNormal = Vector3.Zero; distance = 0.0f; intersect = Vector3.Zero; normal = Vector3.Zero; // checks upper left node. if (quadNode.UpperLeftNode != null) { if (TestUsingQuadTree(sourceCollide, quadNode.UpperLeftNode, out tempIntersect, out tempNormal, out tempDistance)) { result = true; // checks closest if (closestDistance > tempDistance) { closestDistance = tempDistance; closestIntersection = tempIntersect; closestNormal = tempNormal; } } } // checks upper right node. if (quadNode.UpperRightNode != null) { if (TestUsingQuadTree(sourceCollide, quadNode.UpperRightNode, out tempIntersect, out tempNormal, out tempDistance)) { result = true; // checks closest if (closestDistance > tempDistance) { closestDistance = tempDistance; closestIntersection = tempIntersect; closestNormal = tempNormal; } } } // checks lower left node. if (quadNode.LowerLeftNode != null) { if (TestUsingQuadTree(sourceCollide, quadNode.LowerLeftNode, out tempIntersect, out tempNormal, out tempDistance)) { result = true; // checks closest if (closestDistance > tempDistance) { closestDistance = tempDistance; closestIntersection = tempIntersect; closestNormal = tempNormal; } } } // checks lower right node. if (quadNode.LowerRightNode != null) { if (TestUsingQuadTree(sourceCollide, quadNode.LowerRightNode, out tempIntersect, out tempNormal, out tempDistance)) { result = true; // checks closest if (closestDistance > tempDistance) { closestDistance = tempDistance; closestIntersection = tempIntersect; closestNormal = tempNormal; } } } // checks vertices in quad node. if (quadNode.Contains(ref sourceCollide)) { // checks vertices with bounding sphere. if (sourceCollide is CollideSphere) { CollideSphere collide = sourceCollide as CollideSphere; // Hit test sphere with the model BoundingSphere sphere = collide.BoundingSphere; if (quadNode.Vertices != null) { if (TestSphereintersectModel(sphere, quadNode.Vertices, Matrix.Identity, out tempIntersect, out tempNormal, out tempDistance)) { result = true; // checks closest if (closestDistance > tempDistance) { closestDistance = tempDistance; closestIntersection = tempIntersect; closestNormal = tempNormal; } } } } // checks vertices with ray. else if (sourceCollide is CollideRay) { CollideRay collide = sourceCollide as CollideRay; if (quadNode.Vertices != null) { if (TestRayintersectModel(collide.Ray, quadNode.Vertices, Matrix.Identity, out tempIntersect, out tempNormal, out tempDistance)) { result = true; // checks closest if (closestDistance > tempDistance) { closestDistance = tempDistance; closestIntersection = tempIntersect; closestNormal = tempNormal; } } } } } // resolve final result. if (result) { distance = closestDistance; intersect = closestIntersection; normal = closestNormal; } return(result); }
protected bool TestUsingQuadTree(CollideElement sourceCollide, QuadNode quadNode, out Vector3 intersect, out Vector3 normal, out float distance) { bool result = false; float tempDistance = 0.0f; Vector3 tempIntersect = Vector3.Zero; Vector3 tempNormal = Vector3.Zero; float closestDistance = float.MaxValue; Vector3 closestIntersection = Vector3.Zero; Vector3 closestNormal = Vector3.Zero; distance = 0.0f; intersect = Vector3.Zero; normal = Vector3.Zero; // checks upper left node. if (quadNode.UpperLeftNode != null) { if (TestUsingQuadTree(sourceCollide, quadNode.UpperLeftNode, out tempIntersect, out tempNormal, out tempDistance)) { result = true; // checks closest if (closestDistance > tempDistance) { closestDistance = tempDistance; closestIntersection = tempIntersect; closestNormal = tempNormal; } } } // checks upper right node. if (quadNode.UpperRightNode != null) { if (TestUsingQuadTree(sourceCollide, quadNode.UpperRightNode, out tempIntersect, out tempNormal, out tempDistance)) { result = true; // checks closest if (closestDistance > tempDistance) { closestDistance = tempDistance; closestIntersection = tempIntersect; closestNormal = tempNormal; } } } // checks lower left node. if (quadNode.LowerLeftNode != null) { if (TestUsingQuadTree(sourceCollide, quadNode.LowerLeftNode, out tempIntersect, out tempNormal, out tempDistance)) { result = true; // checks closest if (closestDistance > tempDistance) { closestDistance = tempDistance; closestIntersection = tempIntersect; closestNormal = tempNormal; } } } // checks lower right node. if (quadNode.LowerRightNode != null) { if (TestUsingQuadTree(sourceCollide, quadNode.LowerRightNode, out tempIntersect, out tempNormal, out tempDistance)) { result = true; // checks closest if (closestDistance > tempDistance) { closestDistance = tempDistance; closestIntersection = tempIntersect; closestNormal = tempNormal; } } } // checks vertices in quad node. if (quadNode.Contains(ref sourceCollide)) { // checks vertices with bounding sphere. if (sourceCollide is CollideSphere) { CollideSphere collide = sourceCollide as CollideSphere; // Hit test sphere with the model BoundingSphere sphere = collide.BoundingSphere; if (quadNode.Vertices != null) { if (TestSphereintersectModel(sphere, quadNode.Vertices, Matrix.Identity, out tempIntersect, out tempNormal, out tempDistance)) { result = true; // checks closest if (closestDistance > tempDistance) { closestDistance = tempDistance; closestIntersection = tempIntersect; closestNormal = tempNormal; } } } } // checks vertices with ray. else if (sourceCollide is CollideRay) { CollideRay collide = sourceCollide as CollideRay; if (quadNode.Vertices != null) { if (TestRayintersectModel(collide.Ray, quadNode.Vertices, Matrix.Identity, out tempIntersect, out tempNormal, out tempDistance)) { result = true; // checks closest if (closestDistance > tempDistance) { closestDistance = tempDistance; closestIntersection = tempIntersect; closestNormal = tempNormal; } } } } } // resolve final result. if (result) { distance = closestDistance; intersect = closestIntersection; normal = closestNormal; } return result; }
/// <summary> /// build a quad node. /// </summary> /// <param name="vertices">vertex array</param> /// <param name="depthLevel">quad tree depth count</param> /// <returns>new quad node</returns> 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<Vector3> upperLeftVertexList = new List<Vector3>(); List<Vector3> upperRightVertexList = new List<Vector3>(); List<Vector3> lowerLeftVertexList = new List<Vector3>(); List<Vector3> lowerRightVertexList = new List<Vector3>(); List<Vector3> medlineVertexList = new List<Vector3>(); // 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; }
/// <summary> /// build a quad node. /// </summary> /// <param name="vertices">vertex array</param> /// <param name="depthLevel">quad tree depth count</param> /// <returns>new quad node</returns> 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 <Vector3> upperLeftVertexList = new List <Vector3>(); List <Vector3> upperRightVertexList = new List <Vector3>(); List <Vector3> lowerLeftVertexList = new List <Vector3>(); List <Vector3> lowerRightVertexList = new List <Vector3>(); List <Vector3> medlineVertexList = new List <Vector3>(); // 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); }