程序代码:

http://www.codeproject.com/Articles/30535/A-Simple-QuadTree-Implementation-in-C

四叉树:

 using System;
using System.Drawing;
using System.Collections.Generic;
using System.Diagnostics; namespace QuadTreeLib
{
/// <summary>
/// A Quadtree is a structure designed to partition space so
/// that it's faster to find out what is inside or outside a given
/// area. See http://en.wikipedia.org/wiki/Quadtree
/// This QuadTree contains items that have an area (RectangleF)
/// it will store a reference to the item in the quad
/// that is just big enough to hold it. Each quad has a bucket that
/// contain multiple items.
/// </summary>
public class QuadTree<T> where T : IHasRect
{
/// <summary>
/// The root QuadTreeNode
/// 根节点
/// </summary>
QuadTreeNode<T> m_root; /// <summary>
/// The bounds of this QuadTree
/// 四叉树的包围盒,根节点的范围
/// </summary>
RectangleF m_rectangle; /// <summary>
/// An delegate that performs an action on a QuadTreeNode
/// </summary>
/// <param name="obj"></param>
public delegate void QTAction(QuadTreeNode<T> obj); /// <summary>
///
/// </summary>
/// <param name="rectangle"></param>
public QuadTree(RectangleF rectangle)
{
m_rectangle = rectangle;
m_root = new QuadTreeNode<T>(m_rectangle);//初始化根节点
} /// <summary>
/// Get the count of items in the QuadTree
/// 四叉树节点的数目
/// </summary>
public int Count { get { return m_root.Count; } } /// <summary>
/// Insert the feature into the QuadTree
/// 插入数据项
/// </summary>
/// <param name="item"></param>
public void Insert(T item)
{
m_root.Insert(item);//往四叉树插入数据项,其实是通过根节点插入数据项
} /// <summary>
/// Query the QuadTree, returning the items that are in the given area
/// 查询四叉树,返回给定区域的数据项
/// </summary>
/// <param name="area"></param>
/// <returns></returns>
public List<T> Query(RectangleF area)
{
return m_root.Query(area);
} /// <summary>
/// Do the specified action for each item in the quadtree
/// 执行四叉树中特定的行为
/// </summary>
/// <param name="action"></param>
public void ForEach(QTAction action)
{
m_root.ForEach(action);
} } }

QuadTree

四叉树节点:

 using System;
using System.Collections.Generic;
using System.Drawing;
using System.Diagnostics; namespace QuadTreeLib
{
/// <summary>
/// The QuadTreeNode
/// 四叉树节点
/// </summary>
/// <typeparam name="T"></typeparam>
public class QuadTreeNode<T> where T : IHasRect
{
/// <summary>
/// Construct a quadtree node with the given bounds
/// 根据给定的范围构建四叉树节点
/// </summary>
/// <param name="area"></param>
public QuadTreeNode(RectangleF bounds)
{
m_bounds = bounds;
} /// <summary>
/// The area of this node
/// </summary>
RectangleF m_bounds; /// <summary>
/// The contents of this node.
/// Note that the contents have no limit: this is not the standard way to impement a QuadTree
/// </summary>
List<T> m_contents = new List<T>(); /// <summary>
/// The child nodes of the QuadTree
/// 四叉树的子节点
/// </summary>
List<QuadTreeNode<T>> m_nodes = new List<QuadTreeNode<T>>(); /// <summary>
/// Is the node empty
/// </summary>
public bool IsEmpty { get { return m_bounds.IsEmpty || m_nodes.Count == ; } } /// <summary>
/// Area of the quadtree node
/// 四叉树节点的范围
/// </summary>
public RectangleF Bounds { get { return m_bounds; } } /// <summary>
/// Total number of nodes in the this node and all SubNodes
///
/// </summary>
public int Count
{
get
{
int count = ; foreach (QuadTreeNode<T> node in m_nodes)
count += node.Count; count += this.Contents.Count; return count;
}
} /// <summary>
/// Return the contents of this node and all subnodes in the true below this one.
/// </summary>
public List<T> SubTreeContents
{
get
{
List<T> results = new List<T>(); foreach (QuadTreeNode<T> node in m_nodes)
results.AddRange(node.SubTreeContents); results.AddRange(this.Contents);
return results;
}
} public List<T> Contents { get { return m_contents; } } /// <summary>
/// Query the QuadTree for items that are in the given area
/// 查询给定范围的数据项
/// </summary>
/// <param name="queryArea"></pasram>
/// <returns></returns>
public List<T> Query(RectangleF queryArea)
{
// create a list of the items that are found
List<T> results = new List<T>(); // this quad contains items that are not entirely contained by
// it's four sub-quads. Iterate through the items in this quad
// to see if they intersect.
foreach (T item in this.Contents)
{
if (queryArea.IntersectsWith(item.Rectangle))
results.Add(item);
} foreach (QuadTreeNode<T> node in m_nodes)
{
if (node.IsEmpty)
continue; // Case 1: search area completely contained by sub-quad
// if a node completely contains the query area, go down that branch
// and skip the remaining nodes (break this loop)
if (node.Bounds.Contains(queryArea))
{
results.AddRange(node.Query(queryArea));
break;
} // Case 2: Sub-quad completely contained by search area
// if the query area completely contains a sub-quad,
// just add all the contents of that quad and it's children
// to the result set. You need to continue the loop to test
// the other quads
if (queryArea.Contains(node.Bounds))
{
results.AddRange(node.SubTreeContents);
continue;
} // Case 3: search area intersects with sub-quad
// traverse into this quad, continue the loop to search other
// quads
if (node.Bounds.IntersectsWith(queryArea))
{
results.AddRange(node.Query(queryArea));
}
} return results;
} /// <summary>
/// Insert an item to this node
/// 将数据项递归插入该四叉树节点
/// </summary>
/// <param name="item"></param>
public void Insert(T item)
{
// if the item is not contained in this quad, there's a problem
//数据项不在当前四叉树节点范围内,返回
if (!m_bounds.Contains(item.Rectangle))
{
Trace.TraceWarning("feature is out of the bounds of this quadtree node");
return;
} // if the subnodes are null create them. may not be sucessfull: see below
// we may be at the smallest allowed size in which case the subnodes will not be created
if (m_nodes.Count == )
CreateSubNodes();//分割四叉树,将当前节点分为四个子节点 // for each subnode:
// if the node contains the item, add the item to that node and return
// this recurses into the node that is just large enough to fit this item
foreach (QuadTreeNode<T> node in m_nodes)
{
if (node.Bounds.Contains(item.Rectangle))//四叉树在当前节点范围内,插入
{
node.Insert(item);
return;
}
} // if we make it to here, either
// 1) none of the subnodes completely contained the item. or
// 2) we're at the smallest subnode size allowed
// add the item to this node's contents.
//考虑这一块,如果所有的子节点都不完全包含本数据项,或者达到了子节点的最小限制,将数据项添加到本节点
this.Contents.Add(item);
}
//递归遍历本节点的子节点
public void ForEach(QuadTree<T>.QTAction action)
{
action(this); // draw the child quads
foreach (QuadTreeNode<T> node in this.m_nodes)
node.ForEach(action);
} /// <summary>
/// Internal method to create the subnodes (partitions space)
/// 私有方法,创建子节点
/// </summary>
private void CreateSubNodes()
{
// the smallest subnode has an area
if ((m_bounds.Height * m_bounds.Width) <= )
return; float halfWidth = (m_bounds.Width / 2f);
float halfHeight = (m_bounds.Height / 2f); m_nodes.Add(new QuadTreeNode<T>(new RectangleF(m_bounds.Location, new SizeF(halfWidth, halfHeight))));
m_nodes.Add(new QuadTreeNode<T>(new RectangleF(new PointF(m_bounds.Left, m_bounds.Top + halfHeight), new SizeF(halfWidth, halfHeight))));
m_nodes.Add(new QuadTreeNode<T>(new RectangleF(new PointF(m_bounds.Left + halfWidth, m_bounds.Top), new SizeF(halfWidth, halfHeight))));
m_nodes.Add(new QuadTreeNode<T>(new RectangleF(new PointF(m_bounds.Left + halfWidth, m_bounds.Top + halfHeight), new SizeF(halfWidth, halfHeight))));
} }
}

QuadTreeNode

数据项,作为T传入:

 namespace QuadTreeDemoApp
{
/// <summary>
/// An item with a position, a size and a random colour to test
/// the QuadTree structure.
/// 数据项
/// </summary>
class Item: IHasRect
{
/// <summary>
/// Create an item at the given location with the given size.
/// 数据项,在给定的位置构建特定大小的数据项
/// </summary>
/// <param name="p"></param>
/// <param name="size"></param>
public Item(Point p, int size)
{
m_size = size;
m_rectangle = new RectangleF(p.X, p.Y, m_size, m_size);
m_color = Utility.RandomColor;
} /// <summary>
/// Bounds of this item
/// 数据项的范围
/// </summary>
RectangleF m_rectangle; /// <summary>
///默认大小
/// </summary>
int m_size = ; /// <summary>
/// 颜色
/// </summary>
Color m_color; /// <summary>
/// Colour to draw the item for the QuadTree demo
/// </summary>
public Color Color { get { return m_color; } } #region IHasRect Members /// <summary>
/// The rectangular bounds of this item
/// 数据项的范围矩形
/// </summary>
public RectangleF Rectangle { get { return m_rectangle; } } #endregion
}
}

Item

包围盒接口:

 namespace QuadTreeLib
{
/// <summary>
/// An interface that defines and object with a rectangle
/// 接口定义了对象的包围盒
/// </summary>
public interface IHasRect
{
RectangleF Rectangle { get; }
}
}

IHasRect

渲染四叉树:

 using System;
using System.Collections.Generic;
using System.Drawing; using QuadTreeLib; namespace QuadTreeDemoApp
{
/// <summary>
/// Class draws a QuadTree
/// 绘制四叉树类
/// </summary>
class QuadTreeRenderer
{
/// <summary>
/// Create the renderer, give the QuadTree to render.
/// 渲染四叉树
/// </summary>
/// <param name="quadTree"></param>
public QuadTreeRenderer(QuadTree<Item> quadTree)
{
m_quadTree = quadTree;
} QuadTree<Item> m_quadTree; /// <summary>
/// Hashtable contains a colour for every node in the quad tree so that they are
/// rendered with a consistant colour.
/// </summary>
Dictionary<QuadTreeNode<Item>, Color> m_dictionary = new Dictionary<QuadTreeNode<Item>, Color>(); /// <summary>
/// Get the colour for a QuadTreeNode from the hash table or else create a new colour
/// </summary>
/// <param name="node"></param>
/// <returns></returns>
Color GetColor(QuadTreeNode<Item> node)
{
if (m_dictionary.ContainsKey(node))
return m_dictionary[node]; Color color = Utility.RandomColor;
m_dictionary.Add(node, color);
return color;
} /// <summary>
/// Render the QuadTree into the given Graphics context
/// 在给定的图形设备渲染四叉树
/// </summary>
/// <param name="graphics"></param>
internal void Render(Graphics graphics)
{
//遍历节点触发委托方法
m_quadTree.ForEach(delegate(QuadTreeNode<Item> node)
{ // draw the contents of this quad
if (node.Contents != null)
{
foreach (Item item in node.Contents)
{
using (Brush b = new SolidBrush(item.Color))
graphics.FillEllipse(b, Rectangle.Round(item.Rectangle));
}
} // draw this quad // Draw the border
//绘制包围盒
Color color = GetColor(node);
graphics.DrawRectangle(Pens.Black, Rectangle.Round(node.Bounds)); // draw the inside of the border in a distinct colour
using (Pen p = new Pen(color))
{
Rectangle inside = Rectangle.Round(node.Bounds);
inside.Inflate(-, -);
graphics.DrawRectangle(p, inside);
} }); }
}
}

QuadTreeRenderer

主窗体调用:

  public partial class MainForm : Form
{
QuadTree<Item> m_quadTree; QuadTreeRenderer m_renderer; public MainForm()
{
InitializeComponent();
} private void MainForm_Load(object sender, EventArgs e)
{
Init();
} /// <summary>
/// Resize the window re-initializes the QuadTree to the new size
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MainForm_Resize(object sender, EventArgs e)
{
Init();
} /// <summary>
/// Draw the QuadTree and the selection rectangle
/// Also highlight the selecte items.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MainForm_Paint(object sender, PaintEventArgs e)
{
// draw the QuadTree
m_renderer.Render(e.Graphics); // draw the selection rectangle
if (!m_selectionRect.IsEmpty)
{
// draw the selection rect in semi-transparent yellow
using (Brush b = new SolidBrush(Color.FromArgb(, Color.Yellow)))
e.Graphics.FillRectangle(b, Rectangle.Round(m_selectionRect));
} // draw the selected items with a red ring around them
if (m_selectedItems != null)
{
foreach (Item obj in m_selectedItems)
{
Rectangle selectedRect = Rectangle.Round(obj.Rectangle);
selectedRect.Inflate(, );
using (Pen p = new Pen(Color.Red, ))
e.Graphics.DrawEllipse(p, selectedRect);
}
}
} /// <summary>
/// Initialize the QuadTree to the size of the window.
/// Initialize the QuadTreeRenderer
/// </summary>
private void Init()
{
m_quadTree = new QuadTree<Item>(this.ClientRectangle);//构造客户区范围大小的四叉树
m_renderer = new QuadTreeRenderer(m_quadTree);
} #region mouse interaction code bool m_dragging = false;
RectangleF m_selectionRect;
Point m_startPoint;
List<Item> m_selectedItems; /// <summary>
/// MouseUp:
/// - if you're using the left mouse button insert a new item into
/// the QuadTree at the click point
/// - if you're dragging with the right mouse button, query the
/// QuadTree with the selection rectangle defined by the current
/// point and the point when the mouseDown event happened.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MainForm_MouseUp(object sender, MouseEventArgs e)
{
if (m_dragging && e.Button== MouseButtons.Right)
{
m_selectedItems = m_quadTree.Query(m_selectionRect);
m_dragging = false;
}
else
{
Random rand = new Random(DateTime.Now.Millisecond); m_quadTree.Insert(new Item(e.Location, rand.Next() + ));
} Invalidate(); } /// <summary>
/// If the it's a right click, record the start point and start drag operation
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MainForm_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Right)
{
m_dragging = true;
m_startPoint = e.Location;
}
} /// <summary>
/// MouseMove: if we're dragging the update the area of the selection
/// rectangle using the start point and the current point.
/// Invalidate causes the form to redraw.
/// </summary>
/// <param name="sender"></param>
/// <param name="e"></param>
private void MainForm_MouseMove(object sender, MouseEventArgs e)
{
if (m_dragging)
{
m_selectionRect = RectangleF.FromLTRB(
Math.Min(e.Location.X, m_startPoint.X),
Math.Min(e.Location.Y, m_startPoint.Y),
Math.Max(e.Location.X, m_startPoint.X),
Math.Max(e.Location.Y, m_startPoint.Y)); Invalidate();
}
}
#endregion }

MainForm

运行结果:

一个四叉树Demo学习的更多相关文章

  1. [转]一个四叉树Demo学习

    程序代码: http://www.codeproject.com/Articles/30535/A-Simple-QuadTree-Implementation-in-C 四叉树: using Sys ...

  2. Go学习【02】:理解Gin,搭一个web demo

    Go Gin 框架 说Gin是一个框架,不如说Gin是一个类库或者工具库,其包含了可以组成框架的组件.这样会更好理解一点. 举个 下面的示例代码在这:github 利用Gin组成最基本的框架.说到框架 ...

  3. 《IT蓝豹》吹雪花demo,学习android传感器

    吹雪花demo,学习android传感器 吹雪花demo,学习android传感器,嘴巴对着手机底部吹一下就会出现飘着雪花效果. 算是学习android传感器效果.本例子主要是通过android.me ...

  4. [Unity3D]做个小Demo学习Input.touches

    [Unity3D]做个小Demo学习Input.touches 学不如做,下面用一个简单的Demo展示的Input.touches各项字段,有图有真相. 本项目已发布到Github,地址在(https ...

  5. java线程间通信:一个小Demo完全搞懂

    版权声明:本文出自汪磊的博客,转载请务必注明出处. Java线程系列文章只是自己知识的总结梳理,都是最基础的玩意,已经掌握熟练的可以绕过. 一.从一个小Demo说起 上篇我们聊到了Java多线程的同步 ...

  6. 写一个TODO App学习Flutter本地存储工具Moor

    写一个TODO App学习Flutter本地存储工具Moor Flutter的数据库存储, 官方文档: https://flutter.dev/docs/cookbook/persistence/sq ...

  7. 推荐一个算法编程学习中文社区-51NOD【算法分级,支持多语言,可在线编译】

    最近偶尔发现一个算法编程学习的论坛,刚开始有点好奇,也只是注册了一下.最近有时间好好研究了一下,的确非常赞,所以推荐给大家.功能和介绍看下面介绍吧.首页的标题很给劲,很纯粹的Coding社区....虽 ...

  8. LeadTools Android 入门教学——运行第一个Android Demo

    LeadTools 有很多Windows平台下的Demo,非常全面,但是目前开发手机应用的趋势也越来越明显,LeadTools也给大家提供了10个Android的Demo,这篇文章将会教你如何运行第一 ...

  9. ArcGIS API for JavaScript开发环境搭建及第一个实例demo

    原文:ArcGIS API for JavaScript开发环境搭建及第一个实例demo ESRI公司截止到目前已经发布了最新的ArcGIS Server for JavaScript API v3. ...

随机推荐

  1. 清橙 A1206 小Z的袜子(莫队算法)

    A1206. 小Z的袜子 时间限制:1.0s   内存限制:512.0MB   总提交次数:1357   AC次数:406   平均分:46.75   将本题分享到:        查看未格式化的试题 ...

  2. ExtJS笔记4 容器与布局(Layouts and Containers)

    The layout system is one of the most powerful parts of Ext JS. It handles the sizing and positioning ...

  3. nor flash和nand flash的区别

    NOR和NAND是现在市场上两种主要的非易失闪存技术.Intel于1988年首先开发出NOR flash技术,彻底改变了原先由EPROM和EEPROM一统天下的局面.紧接着,1989年,东芝公司发表了 ...

  4. C#winform项目添加引用编译文件

    打开opencv(Emgu for windows)样例,发现有带引用图标的文件 以前还真没见过这种用法,研究了一下: 1.项目版本信息文件内容及添加: 通过修改项目目录下的csproj(c shar ...

  5. apache的prefork的详解

    apache的prefork的参数详解:ServerLimit 2000 这是最大进程数的阀值StartServers 25  启动时建立的子进程MinSpareServers 25 最小空闲进程Ma ...

  6. Locking

    Computer Science An Overview _J. Glenn Brookshear _11th Edition To solve such problems, a DBMS could ...

  7. (IOS)Swift2.0 Radio 程序分析

    本文主要分享下楼主在学习Swift编程过程中,对GitHub上的一个开源项目Swift Radio的研究心得. 项目地址:https://github.com/swiftcodex/Swift-Rad ...

  8. SVM神经网络的术语理解

    SVM(Support Vector Machine)翻译成中文是支持向量机, 这里的“机(machine,机器)”实际上是一个算法.而支持向量则是指那些在间隔区边缘的训练样本点[1]. 当初看到这个 ...

  9. Python之创建tuple和“可变”的tuple

    Python之创建tuple tuple是另一种有序的列表,中文翻译为" 元组 ".tuple 和 list 非常类似,但是,tuple一旦创建完毕,就不能修改了. 同样是表示班里 ...

  10. 使用JetBrains dotMemory 4.0分析内存

    安装下载地址:http://www.jetbrains.com/profiler/ 1.在本地启动web应用后,打开dotMemory,附加进程 2.附加后会看到集中颜色得粗条,不断往左边走动,这是内 ...