private void Collapse(QuadtreeNode <T> node) { if (node.IsLeaf()) { if (node.parent != null && node.IsEmpty()) { Collapse(node.parent); } } else { bool empty = true; for (int i = 0; i < 4 && empty; i++) { if (!node.children[i].IsLeaf() || !node.children[i].IsEmpty()) { empty = false; } } if (empty) { node.children = new QuadtreeNode <T> [4]; if (node.parent != null) { Collapse(node.parent); } } } }
public void TectBuildTree_ZoomLevels_2() { List <DataRow> data = new List <DataRow>(); double val = 0; for (int i = 0; i < 100; i++) { val += i > 0 ? 1.0 / i : 0; data.Add(new DataRow() { Argument = val, Value = 1 }); } QuadtreeNode startNode = QuardtreeBuilder.BuildTree(data, 10); var wholeRange = QuardtreeBuilder.GetWholeRange(startNode); int counter = 0; startNode.VisitNodes(wholeRange, 10, node => { counter++; }); Assert.AreEqual(1, counter); counter = 0; startNode.VisitNodes(wholeRange, 1, node => { counter++; }); Assert.AreEqual(100, counter); counter = 0; startNode.VisitNodes(wholeRange, 2, node => { counter++; }); Assert.AreEqual(3, counter); }
private void Remove(QuadtreeNode <T> node, T value) { if (node == null) { return; } if (!node.Intersects(value.Collider)) { return; } if (!node.IsLeaf()) { foreach (QuadtreeNode <T> child in node.children) { Remove(child, value); } } else { if (node.Remove(value)) { if (node.IsEmpty()) { Collapse(node); } } } }
/// <summary> /// Quick (O(n log n)) and accurate collision detection /// </summary> /// <param name="labels"></param> public static void QuickAccurateCollisionDetectionMethod(List<BaseLabel> labels) { // find minimum / maximum coordinates double minX = double.MaxValue; double maxX = double.MinValue; double minY = double.MaxValue; double maxY = double.MinValue; foreach (BaseLabel l in labels) { ProperBox box = new ProperBox(l.Box); if (box.Left < minX) minX = box.Left; if (box.Right > maxX) maxX = box.Right; if (box.Bottom > maxY) maxY = box.Bottom; if (box.Top < minY) minY = box.Top; } // sort by area (highest priority first, followed by low area to maximize the amount of labels displayed) var sortedLabels = labels.OrderByDescending(label => label.Priority).ThenBy(label => label.Box.Width * label.Box.Height); // make visible if it does not collide with other labels. Uses a quadtree and is therefore fast O(n log n) QuadtreeNode<ProperBox> quadTree = new QuadtreeNode<ProperBox>(minX, maxX, minY, maxY, new LabelBoxContainmentChecker(), 0, 10); foreach (BaseLabel l in sortedLabels) { if (!l.Show) continue; if (quadTree.CollidesWithAny(new ProperBox(l.Box))) { l.Show = false; } else { ProperBox box = new ProperBox(l.Box); quadTree.Insert(box); } } }
public void Subdivide(int depth = 0) { subnodes = new QuadtreeNode <TType> [4]; for (int i = 0; i < subnodes.Length; i++) { Vector2 newPos = position; if ((i & 2) == 2) { newPos.y -= size * 0.25f; } else { newPos.y += size * 0.25f; } if ((i & 1) == 1) { newPos.x += size * 0.25f; } else { newPos.x -= size * 0.25f; } subnodes[i] = new QuadtreeNode <TType>(newPos, size * 0.5f); if (depth > 0) { subnodes[i].Subdivide(depth - 1); } } }
public void accumulate(QuadtreeNode quad, double x0, double y0, double x1, double y1) { double x = 0, y = 0, strength = 0, c; QuadtreeNode q; //对于内部节点,积累来自子象限的力。 if (quad.children != null) { for (int i = 0; i < 4; i++) { if (quad.children[i] != null) { q = quad.children[i]; c = q.value; strength += c; x += c * q.x; y += c * q.y; } } quad.x = x / strength; quad.y = y / strength; } //对叶结点,积累来自重合象限的力 else { q = quad; q.x = q.data.x; q.y = q.data.y; strength += strengthsManyBody[q.data.index]; } quad.value = strength; }
public QuadtreeNode(int size, Vector2F position, QuadtreeNode <T> parent) { this.size = size; this.position = position; this.parent = parent; this.children = new QuadtreeNode <T> [4]; }
/// <summary> /// Inserts a value into the region. /// </summary> /// <param name="x"> /// The X component of the value's position. /// </param> /// <param name="y"> /// The y component of the value's position. /// </param> /// <param name="value"> /// The value to insert. /// </param> /// <returns> /// true if the value was inserted into the region; /// false if the value's position was outside the region. /// </returns> public bool Insert(float x, float y, T value) { var position = new Vector2(x, y); var node = new QuadtreeNode(position, value); return(this.Insert(node)); }
public bool IsInsideCircle(Vector2 position, float radius, QuadtreeNode <TType> node) { Vector2 difference = node.Position - position; difference.x = Math.Max(0, Mathf.Abs(difference.x) - node.Size / 2); difference.y = Math.Max(0, Mathf.Abs(difference.y) - node.Size / 2); return(difference.magnitude < radius); }
public Quadtree(int size) { if (!size.IsPowerOfTwo()) { throw new System.ArgumentException("Size must be power of two!"); } root = new QuadtreeNode <T>(new Rect(0, 0, size, size)); }
private void Split(QuadtreeNode <T> node) { int childSize = node.Size / 2; for (int i = 0; i < 4; i++) { Vector2F childPosition = node.Position + OFFSET[i] * childSize; node.children[i] = new QuadtreeNode <T>(childSize, childPosition, node); } }
public ChildNodes(QuadtreeNode <T> parentNode) { _nodes = new QuadtreeNode <T>[4] { new QuadtreeNode <T>(parentNode._rect.GetFirstQuadrant(), parentNode._maxObjects), new QuadtreeNode <T>(parentNode._rect.GetSecondQuadrant(), parentNode._maxObjects), new QuadtreeNode <T>(parentNode._rect.GetThirdQuadrant(), parentNode._maxObjects), new QuadtreeNode <T>(parentNode._rect.GetFourthQuadrant(), parentNode._maxObjects), }; }
/// <summary> /// Builds a terrain quadtree from the heightmap. /// </summary> /// <param name="heightMap">The heightmap of the terrain.</param> protected QuadtreeNode BuildQuadtree(Texture2D heightMap) { QuadtreeNode root = new QuadtreeNode(new BoundingBox(Vector3.Zero, new Vector3(heightMap.Width * tileSize, 0.0f, heightMap.Height * tileSize))); Color[] heightMapColors = new Color[heightMap.Width * heightMap.Height]; heightMap.GetData(heightMapColors); BuildQuadtree(heightMapColors, root); return(root); }
/// <summary> /// Draws the terrain with with the custom effect. /// </summary> /// <param name="root">The root node of the quadtree.</param> protected void DrawTerrain(QuadtreeNode root) { terrainEffect.Parameters["WorldViewProjection"].SetValue(Matrix.Identity * view * projection); terrainEffect.Parameters["LightDirection"].SetValue(lightDirection); terrainEffect.Parameters["AmbientIntensity"].SetValue(ambientIntensity); foreach (EffectPass pass in terrainEffect.CurrentTechnique.Passes) { pass.Apply(); DrawQuadtree(root); } }
private void Subdivide() { float xo = aabb.extents.x * 0.5f; float yo = aabb.extents.y * 0.5f; northeast = new QuadtreeNode(new AABB(new Vector2(aabb.center.x - xo, aabb.center.y + yo), aabb.extents), capacity); northwest = new QuadtreeNode(new AABB(new Vector2(aabb.center.x + xo, aabb.center.y + yo), aabb.extents), capacity); southeast = new QuadtreeNode(new AABB(new Vector2(aabb.center.x - xo, aabb.center.y - yo), aabb.extents), capacity); southwest = new QuadtreeNode(new AABB(new Vector2(aabb.center.x + xo, aabb.center.y - yo), aabb.extents), capacity); subdivided = true; }
private void DrawNode(QuadtreeNode <int> node, int nodeDepth = 0) { if (!node.IsLeaf()) { foreach (var subNode in node.Nodes) { DrawNode(subNode, nodeDepth + 1); } } Gizmos.color = Color.Lerp(minColor, maxColor, nodeDepth / (float)depth); Gizmos.DrawWireCube(node.Position, new Vector3(1, 1, 0.1f) * node.Size); }
/// <summary> /// 查询初始化 /// </summary> /// <param name="node">初始节点</param> /// <param name="x0"></param> /// <param name="y0"></param> /// <param name="x1"></param> /// <param name="y1"></param> /// <returns></returns> QuadtreeVisit quad(QuadtreeNode node, double x0, double y0, double x1, double y1) { double x00 = x0, y00 = y0, x10 = x1, y10 = y1; QuadtreeVisit visit = new QuadtreeVisit { node = node, x0 = x0, x1 = x1, y0 = y0, y1 = y1 }; return(visit); }
/// <summary> /// Inserts a node into the region. /// </summary> /// <param name="node"> /// The node to insert. /// </param> /// <returns> /// true if the node was inserted into the region; /// false if the position of the node was outside the region. /// </returns> private bool Insert(QuadtreeNode node) { if (!this.boundaries.Contains(node.Position)) { return(false); } if (this.children != null) { Quadtree <T> child; if (node.Position.y < this.children[2].boundaries.yMin) { if (node.Position.x < this.children[1].boundaries.xMin) { child = this.children[0]; } else { child = this.children[1]; } } else { if (node.Position.x < this.children[1].boundaries.xMin) { child = this.children[2]; } else { child = this.children[3]; } } if (child.Insert(node)) { this.Count++; return(true); } } if (this.nodes.Count < this.nodeCapacity) { this.nodes.Add(node); this.Count++; return(true); } this.Subdivide(); return(this.Insert(node)); }
private QuadtreeNode <TType>[] BuildQuadtree(Vector2 position, float size, int depth) { int length = 0; for (int i = 0; i <= depth; ++i) { length += (int)Mathf.Pow(4, i); } var quadtree = new QuadtreeNode <TType> [length]; quadtree[0] = new QuadtreeNode <TType>(position, size, 0); BuildQuadtreeRecursively(quadtree, 0); return(quadtree); }
private void Draw(QuadtreeNode <T> node) { if (node == null) { return; } Gizmos.color = (node.Objects != null) ? Color.red : Color.blue; Vector3 pos = node.Center.ToVector3(); float size = node.Size; Gizmos.DrawWireCube(pos, new Vector3(size, 1, size)); for (int i = 0; i < 4; i++) { Draw(node.children[i]); } }
/// <summary> /// Recursively subdivides the terrain quadtree. /// </summary> /// <param name="depth">The current zero-based depth of the algorithm.</param> /// <param name="heightMapColors">The array of heightmap colors.</param> /// <param name="node">The node of the quadtree that will be subdivided.</param> protected void BuildQuadtree(Color[] heightMapColors, QuadtreeNode node, int depth = 0) { Vector3 min = node.boundingBox.Min; Vector3 max = node.boundingBox.Max; Vector3 middle = (min + max) / 2; BoundingBox topLeft = new BoundingBox(min, middle); BoundingBox topRight = new BoundingBox(new Vector3(middle.X, 0, min.Z), new Vector3(max.X, 0, middle.Z)); BoundingBox bottomLeft = new BoundingBox(new Vector3(min.X, 0, middle.Z), new Vector3(middle.X, 0, max.Z)); BoundingBox bottomRight = new BoundingBox(middle, max); if (depth < 5) { BuildQuadtree(heightMapColors, node.topLeft = new QuadtreeNode(topLeft), depth + 1); BuildQuadtree(heightMapColors, node.topRight = new QuadtreeNode(topRight), depth + 1); BuildQuadtree(heightMapColors, node.bottomLeft = new QuadtreeNode(bottomLeft), depth + 1); BuildQuadtree(heightMapColors, node.bottomRight = new QuadtreeNode(bottomRight), depth + 1); } else { node.topLeft = new QuadtreeLeaf(topLeft, heightMapColors, graphics.GraphicsDevice); node.topRight = new QuadtreeLeaf(topRight, heightMapColors, graphics.GraphicsDevice); node.bottomLeft = new QuadtreeLeaf(bottomLeft, heightMapColors, graphics.GraphicsDevice); node.bottomRight = new QuadtreeLeaf(bottomRight, heightMapColors, graphics.GraphicsDevice); } float[] mins = new float[4] { node.topLeft.boundingBox.Min.Y, node.topRight.boundingBox.Min.Y, node.bottomLeft.boundingBox.Min.Y, node.bottomRight.boundingBox.Min.Y }; Array.Sort(mins); float[] maxes = new float[4] { node.topLeft.boundingBox.Max.Y, node.topRight.boundingBox.Max.Y, node.bottomLeft.boundingBox.Max.Y, node.bottomRight.boundingBox.Max.Y }; Array.Sort(maxes); node.boundingBox.Min.Y = MathHelper.Min(100.0f, mins[0]); node.boundingBox.Max.Y = MathHelper.Max(node.boundingBox.Max.Y, maxes[3]); }
private void FindCollisions(QuadtreeNode <T> node, HashSet <Manifold> collisionSet) { if (node == null) { return; } if (node.IsLeaf()) { node.GetCollisions(collisionSet); } else { foreach (QuadtreeNode <T> child in node.children) { FindCollisions(child, collisionSet); } } }
/// <summary> /// LoadContent will be called once per game and is the place to load /// all of your content. /// </summary> protected override void LoadContent() { spriteBatch = new SpriteBatch(GraphicsDevice); hudfont = Content.Load <SpriteFont>("hudFont"); heightMap = Content.Load <Texture2D>("heightMap"); grass = Content.Load <Texture2D>("grass"); rock = Content.Load <Texture2D>("rock"); sand = Content.Load <Texture2D>("sand"); terrainEffect = Content.Load <Effect>("terrainEffect"); terrainEffect.Parameters["MapWidth"].SetValue(heightMap.Width); terrainEffect.Parameters["MapHeight"].SetValue(heightMap.Height); terrainEffect.Parameters["TileSize"].SetValue(tileSize); terrainEffect.Parameters["MaxHeight"].SetValue(100.0f); terrainEffect.Parameters["WaterHeight"].SetValue(10.0f); terrainEffect.Parameters["HeightMap"].SetValue(heightMap); terrainEffect.Parameters["Texture0"].SetValue(grass); terrainEffect.Parameters["Texture1"].SetValue(rock); terrainEffect.Parameters["Texture2"].SetValue(sand); quadtreeRoot = BuildQuadtree(heightMap); water = Content.Load <Texture2D>("water"); waterNormalMap = Content.Load <Texture2D>("waterNormalMap"); waterEffect = Content.Load <Effect>("waterEffect"); waterEffect.Parameters["ColorMap"].SetValue(water); waterEffect.Parameters["NormalMap"].SetValue(waterNormalMap); VertexPositionTexture[] waterVertices = new VertexPositionTexture[4]; waterVertices[0] = new VertexPositionTexture(new Vector3(-8000, 10, -8000), new Vector2(0, 0)); waterVertices[1] = new VertexPositionTexture(new Vector3(-8000, 10, 8000), new Vector2(0, 16000 / 2)); waterVertices[2] = new VertexPositionTexture(new Vector3(8000, 10, -8000), new Vector2(16000 / 2, 0)); waterVertices[3] = new VertexPositionTexture(new Vector3(8000, 10, 8000), new Vector2(16000 / 2, 16000 / 2)); waterVertexBuffer = new VertexBuffer( GraphicsDevice, typeof(VertexPositionTexture), waterVertices.Length, BufferUsage.WriteOnly); waterVertexBuffer.SetData <VertexPositionTexture>(waterVertices); }
public void TectBuildTree_Simple() { List <DataRow> data = new List <DataRow>(); data.Add(new DataRow() { Argument = 0.5, Value = 0.5, }); data.Add(new DataRow() { Argument = 0, Value = 0, }); data.Add(new DataRow() { Argument = 1, Value = 0, }); data.Add(new DataRow() { Argument = 0, Value = 1, }); data.Add(new DataRow() { Argument = 1, Value = 1, }); QuadtreeNode startNode = QuardtreeBuilder.BuildTree(data); Assert.AreEqual(startNode.X, 0.5); Assert.AreEqual(startNode.Y, 0.5); Assert.AreEqual(startNode.NE.X, 1); Assert.AreEqual(startNode.NE.Y, 1); Assert.AreEqual(startNode.NW.X, 0); Assert.AreEqual(startNode.NW.Y, 1); Assert.AreEqual(startNode.SW.X, 0); Assert.AreEqual(startNode.SW.Y, 0); Assert.AreEqual(startNode.SE.X, 1); Assert.AreEqual(startNode.SE.Y, 0); }
public void Subdivide(Vector2 targetPosition, TType type, int depth = 0) { var subdivIndex = GetIndexOfPosition(targetPosition, position); if (subNodes == null) { subNodes = new QuadtreeNode <TType> [4]; for (int i = 0; i < subNodes.Length; i++) { Vector2 newPos = position; if ((i & 2) == 2) { newPos.y -= size * 0.25f; } else { newPos.y += size * 0.25f; } if ((i & 1) == 1) { newPos.x += size * 0.25f; } else { newPos.x -= size * 0.25f; } subNodes[i] = new QuadtreeNode <TType>(newPos, size * 0.5f); } } if (depth > 0) { Debug.Log("Subdivide the element"); subNodes[subdivIndex].Subdivide(targetPosition, value, depth - 1); } }
public void Visitor_Simple() { List <DataRow> data = new List <DataRow>(); data.Add(new DataRow() { Argument = 0.5, Value = 0.5, }); data.Add(new DataRow() { Argument = 0, Value = 0, }); data.Add(new DataRow() { Argument = 1, Value = 0, }); data.Add(new DataRow() { Argument = 0, Value = 1, }); data.Add(new DataRow() { Argument = 1, Value = 1, }); QuadtreeNode startNode = QuardtreeBuilder.BuildTree(data); List <SimpleNode> result = new List <SimpleNode>(); startNode.VisitNodes(new Tuple <Range, Range>(new Range() { Min = -2.0, Max = 2.0 }, new Range() { Min = -2.0, Max = 2.0 }), 1, node => { result.Add(node); }); Assert.AreEqual(5, result.Count); }
private void BuildQuadtreeRecursively(QuadtreeNode <TType>[] quadtree, int index) { if (quadtree[index].Depth >= this._depth) { return; //We're done if we hit a leaf node } //if we have a tree - the root is equal to 0. //4 x 0 = 0 but if you add one you get the next node. +2 +3 +4 gives the other nodes. //Then if you're at position 1 and you multiply by 4 then you get 4, add 1 gives you 5 which is the first node in the seconde depth. int nextNode = 4 * index; Vector2 deltaX = new Vector2(quadtree[index].Size / 4, 0); Vector2 deltaY = new Vector2(0, quadtree[index].Size / 4); quadtree[nextNode + 1] = new QuadtreeNode <TType>(quadtree[index].Position - deltaX + deltaY, quadtree[index].Size / 2, quadtree[index].Depth + 1); quadtree[nextNode + 2] = new QuadtreeNode <TType>(quadtree[index].Position + deltaX + deltaY, quadtree[index].Size / 2, quadtree[index].Depth + 1); quadtree[nextNode + 3] = new QuadtreeNode <TType>(quadtree[index].Position - deltaX - deltaY, quadtree[index].Size / 2, quadtree[index].Depth + 1); quadtree[nextNode + 4] = new QuadtreeNode <TType>(quadtree[index].Position + deltaX - deltaY, quadtree[index].Size / 2, quadtree[index].Depth + 1); BuildQuadtreeRecursively(quadtree, nextNode + 1); BuildQuadtreeRecursively(quadtree, nextNode + 2); BuildQuadtreeRecursively(quadtree, nextNode + 3); BuildQuadtreeRecursively(quadtree, nextNode + 4); }
private void Insert(QuadtreeNode <T> node, T value) { if (node == null || !node.Intersects(value.Collider)) { return; } if (node.Size <= minSize) { node.AddObject(value); } else { if (node.IsLeaf()) { Split(node); } for (int i = 0; i < 4; i++) { Insert(node.children[i], value); } } }
/// <summary> /// Recursively draws the quadtree terrain nodes that are in the viewing frustum. /// </summary> /// <param name="node">The node or leaf to draw.</param> protected void DrawQuadtree(QuadtreeNode node) { if (!(new BoundingFrustum(Matrix.Identity * view * projection)).Intersects(node.boundingBox)) { return; } if (node.GetType() == typeof(QuadtreeLeaf)) { QuadtreeLeaf leaf = (QuadtreeLeaf)node; GraphicsDevice.SetVertexBuffer(leaf.vertexBuffer); GraphicsDevice.Indices = leaf.indexBuffer; GraphicsDevice.DrawIndexedPrimitives(PrimitiveType.TriangleStrip, 0, 0, leaf.indexBuffer.IndexCount - 4); } else { DrawQuadtree(node.topLeft); DrawQuadtree(node.topRight); DrawQuadtree(node.bottomLeft); DrawQuadtree(node.bottomRight); } }
public Quadtree(float _size, Vector2 _corner, int _maxLevel) { size = _size; corner = _corner; maxLevel = _maxLevel; root = new QuadtreeNode(0, new int[]{0,0}, null, this); }
public QuadtreeNode(int _level, int[] _index, QuadtreeNode _parent, Quadtree _tree) { level = _level; index = _index; parent = _parent; tree = _tree; }
public virtual void CreateChildren() { if (children == null) { children = new QuadtreeNode[2, 2]; for (int xi = 0; xi < 2; xi++) for (int yi = 0; yi < 2; yi++) { int[] newIndex = { index[0] * 2 + xi, index[1] * 2 + yi }; children[xi, yi] = new QuadtreeNode(level + 1, newIndex, this, tree); } } }
public override void Build(AABB aabb, List <Body> bodies) { potentialCollisionCount = 0; rootNode = new QuadtreeNode(aabb, capacity); bodies.ForEach(body => rootNode.Insert(body)); }
// TODO implement private void split() { Children = new QuadtreeNode[4]; Children[0] = new QuadtreeNode(Min, Max); Children[1] = new QuadtreeNode(Min, Max); Children[2] = new QuadtreeNode(Min, Max); Children[3] = new QuadtreeNode(Min, Max); }