读取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]二叉树索引的更多相关文章

  1. mysql概要(十四)索引

    1.索引是对数据库数据建立目录加快了查询速度.索引分为哈希索引和二叉树索引 (大数据量转移,如果表中带有大量字段索引,进行数据导入时,建议先去掉索引导入数据再统一加入索引,减少索引计算量) 2.索引原 ...

  2. 数据库索引B+树

    面试时无意间被问到了这个问题:数据库索引的存储结构一般是B+树,为什么不适用红黑树等普通的二叉树? 经过和同学的讨论,得到如下几个情况: 1. 数据库文件是放在硬盘上,每次读取数据库都需要在磁盘上搜索 ...

  3. mysql之索引

    一.索引是什么? 比如我们要在字典中找某一字,如何才能快速找到呢?那就是通过字典的目录. 对数据库来说,索引的作用就是给‘数据’加目录. 二.索引算法 设有N条随机记录,不用索引,平均查找N/2次,那 ...

  4. python/MySQL(索引、执行计划、BDA、分页)

    ---恢复内容开始--- python/MySQL(索引.执行计划.BDA.分页) MySQL索引: 所谓索引的就是具有(约束和加速查找的一种方式)   创建索引的缺点是对数据进行(修改.更新.删除) ...

  5. MySQL数据库索引之B+树

    一.B+树是什么 B+ 树是一种树型数据结构,通常用于数据库和操作系统的文件系统中.B+ 树的特点是能够保持数据稳定有序,其插入与修改操作拥有较稳定的对数时间复杂度.B+ 树元素自底向上插入,这与二叉 ...

  6. mysql概要(十四)(一)索引

    1.索引是对数据库数据建立目录加快了查询速度.索引分为哈希索引和二叉树索引 (大数据量转移,如果表中带有大量字段索引,进行数据导入时,建议先去掉索引导入数据再统一加入索引,减少索引计算量) 2.索引原 ...

  7. oracle索引原理

    B-TREE索引(二叉树索引,默认情况下,我们建的索引都是此种类型) 一个B树索引只有一个根节点,它实际就是位于树的最顶端的分支节点.可以用下图一来描述B树索引的结构.其中,B表示分支节点,而L表示叶 ...

  8. MYSQL初级学习笔记九:MySQL索引的使用!(视频序号:初级_51)

    知识点十一:索引的使用(51) 什么是索引: 索引的定义: 在关系型数据库中,索引是一种与表有关的数据库结构,它可以使对应于表的SQL语句执行的更快.索引的作用相当于图书的目录,可以 根据目录中的页码 ...

  9. 0804关于mysql 索引自动优化机制: 索引选择性(Cardinality:索引基数)

    转自http://blog.csdn.net/zheng0518/article/details/50561761 1.两个同样结构的语句一个没有用到索引的问题: 查1到20号的就不用索引,查1到5号 ...

随机推荐

  1. MarkDown编辑器用法

    代码行1 var s = "JavaScript syntax highlighting"; alert(s); 代码行2:ESC下面的英文3个波浪号~按键 var s = &qu ...

  2. FZU 2092 bfs+记忆化搜索

    晚上团队训练赛的题 和普通bfs不同的是 这是同时操纵人与影子两个单位进行的bfs 由于可能发生人和影子同时接触水晶 所以不可以分开操作 当时使用node记录人和影子的位置 然后进行两重for循环来分 ...

  3. multipart/form-data请求与文件上传

    要上传文件,需要用post方法,并且设置enctype为multipart/form-data. <form action="/upload" method="po ...

  4. PHP使用Xdebug进行远程调试

    PHP使用Xdebug进行远程调试 翻译 by mylxsw posted on 2014/07/14 under 技术文章 > 编程语言 Xdebug提供了客户端与PHP脚本进行交互的接口,这 ...

  5. 【IOS笔记】Delegation

    Delegation Delegation is a simple and powerful pattern in which one object in a program acts on beha ...

  6. LR处理文件上传和下载

    文件上传 在业务场景有上传操作时,使用LR能录制到上传操作,代码如下.在录制的原始代码中,Filename的Value是上传的文件名,name的Value是一串文件名的加密串,file的Value也是 ...

  7. Levenshtein distance

    https://en.wikipedia.org/wiki/Levenshtein_distance 验证码识别 图片中的二维码截取

  8. Vaadin

    Vaadin 这个是用Java 做的  一个人就可以完成 你去网上搜一下  教程 https://vaadin.com/home  官网 http://baike.baidu.com/link?url ...

  9. Chart控件,把Y轴设置成百分比

    这次所有属性设置都用代码(就当整理便于以后查询). 在窗体放置一个Chart控件,未做任何设置:然后编写代码: //设置 chart2.Legends[ ].Enabled = false;//不显示 ...

  10. C/C++预处理和编译

    预处理器的作用 当我们对源代码进行编译时,第一个阶段就是进行预处理.以#开头的都是预处理指令,都会被预处理器处理掉. 也就是说:我们写的代码,不是直接被编译,而是先被预处理器进行修改.那么预处理器如何 ...