[SharpMap]二叉树索引
读取shp文件建立二叉树索引的基本思路分析:
/// <summary>
/// Generates a spatial index for a specified shape file.
/// 根据特定的shp文件构建空间索引
/// </summary>
/// <param name="filename"></param>
private QuadTree CreateSpatialIndex(string filename)
{
List<QuadTree.BoxObjects> objList = new List<QuadTree.BoxObjects>();
//Convert all the geometries to boundingboxes
uint i = ;
foreach (BoundingBox box in GetAllFeatureBoundingBoxes())
{
if (!double.IsNaN(box.Left) && !double.IsNaN(box.Right) && !double.IsNaN(box.Bottom) &&
!double.IsNaN(box.Top))
{
QuadTree.BoxObjects g = new QuadTree.BoxObjects();
g.box = box;
g.ID = i;
objList.Add(g);
i++;
}
} Heuristic heur;
heur.maxdepth = (int) Math.Ceiling(Math.Log(GetFeatureCount(), ));
heur.minerror = ;
heur.tartricnt = ;
heur.mintricnt = ;
return new QuadTree(objList, , heur);
}
// Copyright 2005, 2006 - Morten Nielsen (www.iter.dk)
//
// This file is part of SharpMap.
// SharpMap is free software; you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation; either version 2 of the License, or
// (at your option) any later version.
//
// SharpMap is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Lesser General Public License for more details. // You should have received a copy of the GNU Lesser General Public License
// along with SharpMap; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.IO;
using SharpMap.Geometries; namespace SharpMap.Utilities.SpatialIndexing
{
/// <summary>
/// Heuristics used for tree generation
/// </summary>
public struct Heuristic
{
/// <summary>
/// Maximum tree depth
/// </summary>
public int maxdepth; /// <summary>
/// Minimum Error metric ?the volume of a box + a unit cube.
/// The unit cube in the metric prevents big boxes that happen to be flat having a zero result and muddling things up.
/// </summary>
public int minerror; /// <summary>
/// Minimum object count at node
/// </summary>
public int mintricnt; /// <summary>
/// Target object count at node
/// </summary>
public int tartricnt;
} /// <summary>
/// Constructs a Quad-tree node from a object list and creates its children recursively
/// 二叉树?四叉树?
/// </summary>
public class QuadTree : IDisposable
{
private BoundingBox _box;
private QuadTree _child0;
private QuadTree _child1; /// <summary>
/// Nodes depth in a tree
/// </summary>
protected uint _Depth; /// <summary>
/// Node ID
/// </summary>
public uint? _ID; private List<BoxObjects> _objList; /// <summary>
/// Creates a node and either splits the objects recursively into sub-nodes, or stores them at the node depending on the heuristics.
/// Tree is built top->down
/// </summary>
/// <param name="objList">Geometries to index</param>
/// <param name="depth">Current depth of tree树的深度</param>
/// <param name="heurdata">Heuristics data</param>
public QuadTree(List<BoxObjects> objList, uint depth, Heuristic heurdata)
{
_Depth = depth; _box = objList[].box;
for (int i = ; i < objList.Count; i++)
_box = _box.Join(objList[i].box); // test our build heuristic探试性的- if passes, make children
if (depth < heurdata.maxdepth && objList.Count > heurdata.mintricnt &&
(objList.Count > heurdata.tartricnt || ErrorMetric(_box) > heurdata.minerror))
{
List<BoxObjects>[] objBuckets = new List<BoxObjects>[]; // buckets of geometries大量的几何对象,一桶几何对象
objBuckets[] = new List<BoxObjects>();
objBuckets[] = new List<BoxObjects>(); uint longaxis = _box.LongestAxis; // longest axis
double geoavg = ; // geometric average - midpoint of ALL the objects // go through all bbox and calculate the average of the midpoints
double frac = 1.0f / objList.Count;
for (int i = ; i < objList.Count; i++)
geoavg += objList[i].box.GetCentroid()[longaxis] * frac; // bucket bbox based on their midpoint's side of the geo average in the longest axis
for (int i = ; i < objList.Count; i++)
objBuckets[geoavg > objList[i].box.GetCentroid()[longaxis] ? : ].Add(objList[i]); //If objects couldn't be splitted, just store them at the leaf
//TODO: Try splitting on another axis
if (objBuckets[].Count == || objBuckets[].Count == )
{
_child0 = null;
_child1 = null;
// copy object list
_objList = objList;
}
else
{
// create new children using the buckets
_child0 = new QuadTree(objBuckets[], depth + , heurdata);
_child1 = new QuadTree(objBuckets[], depth + , heurdata);
}
}
else
{
// otherwise the build heuristic failed, this is
// set the first child to null (identifies a leaf)
_child0 = null;
_child1 = null;
// copy object list
_objList = objList;
}
} /// <summary>
/// This instantiator is used internally for loading a tree from a file
/// </summary>
private QuadTree()
{
} #region Read/Write index to/from a file private const double INDEXFILEVERSION = 1.0; /// <summary>
/// Loads a quadtree from a file
/// </summary>
/// <param name="filename"></param>
/// <returns></returns>
public static QuadTree FromFile(string filename)
{
FileStream fs = new FileStream(filename, FileMode.Open, FileAccess.Read);
BinaryReader br = new BinaryReader(fs);
if (br.ReadDouble() != INDEXFILEVERSION) //Check fileindex version
{
fs.Close();
fs.Dispose();
throw new ObsoleteFileFormatException(
"Invalid index file version. Please rebuild the spatial index by either deleting the index");
}
QuadTree node = ReadNode(, ref br);
br.Close();
fs.Close();
return node;
} /// <summary>
/// Reads a node from a stream recursively
/// </summary>
/// <param name="depth">Current depth</param>
/// <param name="br">Binary reader reference</param>
/// <returns></returns>
private static QuadTree ReadNode(uint depth, ref BinaryReader br)
{
QuadTree node = new QuadTree();
node._Depth = depth;
node.Box = new BoundingBox(br.ReadDouble(), br.ReadDouble(), br.ReadDouble(), br.ReadDouble());
bool IsLeaf = br.ReadBoolean();
if (IsLeaf)
{
int FeatureCount = br.ReadInt32();
node._objList = new List<BoxObjects>();
for (int i = ; i < FeatureCount; i++)
{
BoxObjects box = new BoxObjects();
box.box = new BoundingBox(br.ReadDouble(), br.ReadDouble(), br.ReadDouble(), br.ReadDouble());
box.ID = (uint)br.ReadInt32();
node._objList.Add(box);
}
}
else
{
node.Child0 = ReadNode(node._Depth + , ref br);
node.Child1 = ReadNode(node._Depth + , ref br);
}
return node;
} /// <summary>
/// Saves the Quadtree to a file
/// </summary>
/// <param name="filename"></param>
public void SaveIndex(string filename)
{
FileStream fs = new FileStream(filename, FileMode.Create);
BinaryWriter bw = new BinaryWriter(fs);
bw.Write(INDEXFILEVERSION); //Save index version
SaveNode(this, ref bw);
bw.Close();
fs.Close();
} /// <summary>
/// Saves a node to a stream recursively
/// </summary>
/// <param name="node">Node to save</param>
/// <param name="sw">Reference to BinaryWriter</param>
private void SaveNode(QuadTree node, ref BinaryWriter sw)
{
//Write node boundingbox
sw.Write(node.Box.Min.X);
sw.Write(node.Box.Min.Y);
sw.Write(node.Box.Max.X);
sw.Write(node.Box.Max.Y);
sw.Write(node.IsLeaf);
if (node.IsLeaf)
{
sw.Write(node._objList.Count); //Write number of features at node
for (int i = ; i < node._objList.Count; i++) //Write each featurebox
{
sw.Write(node._objList[i].box.Min.X);
sw.Write(node._objList[i].box.Min.Y);
sw.Write(node._objList[i].box.Max.X);
sw.Write(node._objList[i].box.Max.Y);
sw.Write(node._objList[i].ID);
}
}
else if (!node.IsLeaf) //Save next node
{
SaveNode(node.Child0, ref sw);
SaveNode(node.Child1, ref sw);
}
} internal class ObsoleteFileFormatException : Exception
{
/// <summary>
/// Exception thrown when layer rendering has failed
/// </summary>
/// <param name="message"></param>
public ObsoleteFileFormatException(string message)
: base(message)
{
}
} #endregion /// <summary>
/// Determines whether the node is a leaf (if data is stored at the node, we assume the node is a leaf)
/// </summary>
public bool IsLeaf
{
get { return (_objList != null); }
} ///// <summary>
///// Gets/sets the list of objects in the node
///// </summary>
//public List<SharpMap.Geometries.IGeometry> ObjList
//{
// get { return _objList; }
// set { _objList = value; }
//} /// <summary>
/// Gets/sets the Axis Aligned Bounding Box
/// </summary>
public BoundingBox Box
{
get { return _box; }
set { _box = value; }
} /// <summary>
/// Gets/sets the left child node
/// </summary>
public QuadTree Child0
{
get { return _child0; }
set { _child0 = value; }
} /// <summary>
/// Gets/sets the right child node
/// </summary>
public QuadTree Child1
{
get { return _child1; }
set { _child1 = value; }
} /// <summary>
/// Gets the depth of the current node in the tree
/// </summary>
public uint Depth
{
get { return _Depth; }
} #region IDisposable Members /// <summary>
/// Disposes the node
/// </summary>
public void Dispose()
{
//this._box = null;
_child0 = null;
_child1 = null;
_objList = null;
} #endregion /// <summary>
/// Calculate the floating point error metric
/// </summary>
/// <returns></returns>
public double ErrorMetric(BoundingBox box)
{
Point temp = new Point(, ) + (box.Max - box.Min);
return temp.X * temp.Y;
} /// <summary>
/// Searches the tree and looks for intersections with the boundingbox 'bbox'
/// </summary>
/// <param name="box">Boundingbox to intersect with</param>
public Collection<uint> Search(BoundingBox box)
{
Collection<uint> objectlist = new Collection<uint>();
IntersectTreeRecursive(box, this, ref objectlist);
return objectlist;
} /// <summary>
/// Recursive function that traverses the tree and looks for intersections with a boundingbox
/// </summary>
/// <param name="box">Boundingbox to intersect with</param>
/// <param name="node">Node to search from</param>
/// <param name="list">List of found intersections</param>
private void IntersectTreeRecursive(BoundingBox box, QuadTree node, ref Collection<uint> list)
{
if (node.IsLeaf) //Leaf has been reached
{
foreach (BoxObjects boxObject in node._objList)
{
if (box.Intersects(boxObject.box))
list.Add(boxObject.ID); }
/*
for (int i = 0; i < node._objList.Count; i++)
{
list.Add(node._objList[i].ID);
}
*/
}
else
{
if (node.Box.Intersects(box))
{
IntersectTreeRecursive(box, node.Child0, ref list);
IntersectTreeRecursive(box, node.Child1, ref list);
}
}
} #region Nested type: BoxObjects /// <summary>
/// BoundingBox and Feature ID structure used for storing in the quadtree
/// 包围盒和要素ID数据结构,用于在四叉树中存储
/// </summary>
public struct BoxObjects
{
/// <summary>
/// Boundingbox
/// 包围盒
/// </summary>
public BoundingBox box; /// <summary>
/// Feature ID
/// 要素ID
/// </summary>
public uint ID;
} #endregion
}
}
今天看了下DotSpatial中读取Shp的代码,真正实现的四叉树空间索引。
[SharpMap]二叉树索引的更多相关文章
- mysql概要(十四)索引
1.索引是对数据库数据建立目录加快了查询速度.索引分为哈希索引和二叉树索引 (大数据量转移,如果表中带有大量字段索引,进行数据导入时,建议先去掉索引导入数据再统一加入索引,减少索引计算量) 2.索引原 ...
- 数据库索引B+树
面试时无意间被问到了这个问题:数据库索引的存储结构一般是B+树,为什么不适用红黑树等普通的二叉树? 经过和同学的讨论,得到如下几个情况: 1. 数据库文件是放在硬盘上,每次读取数据库都需要在磁盘上搜索 ...
- mysql之索引
一.索引是什么? 比如我们要在字典中找某一字,如何才能快速找到呢?那就是通过字典的目录. 对数据库来说,索引的作用就是给‘数据’加目录. 二.索引算法 设有N条随机记录,不用索引,平均查找N/2次,那 ...
- python/MySQL(索引、执行计划、BDA、分页)
---恢复内容开始--- python/MySQL(索引.执行计划.BDA.分页) MySQL索引: 所谓索引的就是具有(约束和加速查找的一种方式) 创建索引的缺点是对数据进行(修改.更新.删除) ...
- MySQL数据库索引之B+树
一.B+树是什么 B+ 树是一种树型数据结构,通常用于数据库和操作系统的文件系统中.B+ 树的特点是能够保持数据稳定有序,其插入与修改操作拥有较稳定的对数时间复杂度.B+ 树元素自底向上插入,这与二叉 ...
- mysql概要(十四)(一)索引
1.索引是对数据库数据建立目录加快了查询速度.索引分为哈希索引和二叉树索引 (大数据量转移,如果表中带有大量字段索引,进行数据导入时,建议先去掉索引导入数据再统一加入索引,减少索引计算量) 2.索引原 ...
- oracle索引原理
B-TREE索引(二叉树索引,默认情况下,我们建的索引都是此种类型) 一个B树索引只有一个根节点,它实际就是位于树的最顶端的分支节点.可以用下图一来描述B树索引的结构.其中,B表示分支节点,而L表示叶 ...
- MYSQL初级学习笔记九:MySQL索引的使用!(视频序号:初级_51)
知识点十一:索引的使用(51) 什么是索引: 索引的定义: 在关系型数据库中,索引是一种与表有关的数据库结构,它可以使对应于表的SQL语句执行的更快.索引的作用相当于图书的目录,可以 根据目录中的页码 ...
- 0804关于mysql 索引自动优化机制: 索引选择性(Cardinality:索引基数)
转自http://blog.csdn.net/zheng0518/article/details/50561761 1.两个同样结构的语句一个没有用到索引的问题: 查1到20号的就不用索引,查1到5号 ...
随机推荐
- sqlserver ldf过大处理方法
第一步 DUMP TRANSACTION databasename WITH NO_LOG -- 第二步:截断事务日志 BACKUP LOG databasename WITH ...
- apache日志文件太大的问题
apache日志文件太大的问题 处理Apache日志的两种方法 rotatelogs 是 Apache 2.2 中自带的管道日志程序 rotatelogs [ -l ] logfile [ rotat ...
- PHP+jQuery 注册模块的改进之二:激活链接的URL设置与有效期
接<PHP+jQuery 注册模块的改进之一>继续修改: ①在注册成功后返回登录邮件页面( maillogin.php ),在页面中用户可以点击链接跳转到自己注册邮箱的登录页面,可以再次发 ...
- mysql关于字符串字段数据类型
字符串类型 字符串类型指CHAR.VARCHAR.BINARY.VARBINARY.BLOB.TEXT.ENUM和SET.该节描述了这些类型如何工作以及如何在查询中使用这些类型. 类型 大小 用途 C ...
- java web基础1Tomcat服务器基本知识
一.Tomcat安装 (1)先安装JDK,并配置环境变量JAVA_HOME.Tomcat服务器的配置需要JDK的JAVA_HOME环境变量. 并在系统path变量添加%JAVA_HOME%/bin. ...
- DateTime Related Functions
string a = "to_date('" + dtpStart.Value.ToString("yyyy/MM/dd") + "', 'yyyy/ ...
- JMeter使用点滴
作为一款小巧易用的性能测试工具,JMeter不仅免费开源而且功能强大.易于扩展,如果有一定Java开发基础的话还可以在JMeter上做扩展开发新的插件等,几乎能满足各种性能测试需求,本文用于收集使用J ...
- Linux命令echo -e
在Linux命令中 echo -e 这个参数e是什么意思. echo –e “I will use ‘touch’ command to create 3 files.” 这里参数e的作用是什么 ma ...
- Android 加入一个动作按钮
在XML中声明一个动作按钮 所有的动作按钮和其他的可以利用的items都定义在menu资源文件夹中的XML文件中.为了增加一个动作按钮到工具栏,需要在工程 /res/menu/ 目录下面创建一个新的X ...
- Andrew Ng机器学习公开课笔记 -- Mixtures of Gaussians and the EM algorithm
网易公开课,第12,13课 notes,7a, 7b,8 从这章开始,介绍无监督的算法 对于无监督,当然首先想到k means, 最典型也最简单,有需要直接看7a的讲义 Mixtures of G ...