读取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. PHP Static Self 的区别

    <?php class Human{ public static function whoami() { echo "来自父类的whoami"; } public stati ...

  2. NBUT 1602 Mod Three(线段树单点更新区间查询)

    [1602] Mod Three 时间限制: 5000 ms 内存限制: 65535 K 问题描述 Please help me to solve this problem, if so, Liang ...

  3. optimize table table_name myisam mysql自动清除删除过留下的空记录

    optimize table table_name 这个可以清除你表里面的空记录,每次清除的时候记得锁表 lock tables table_name  write|read; unlock tabl ...

  4. jQuery 判断多个 input file 都不能为空

    例如有两个图片上传的 input,都必须上传图片: html 选择文件 1 :<input type="file" name="myfile[]" cla ...

  5. 使用AndroidStudio自动生成JavaDoc文档

    选中所需要生成的Module,找到工具栏上的 Tools,选择 Generate JavaDoc 出现如图的窗口 选择输出路径,就自动生成. 如果出现编码错误提示,则在 Other command l ...

  6. MySQL优化常用

    一.mysql的配置都是小写的,使用下划线_或破折号-分割单词,两者是一样的二.在配置文件中可以用1m,1g等单位,但是用set命令,不能使用单位,默认单位是字节三.特殊例子a.query_cache ...

  7. Linguistic corpora 种子语料库-待分析对象-分析与更新语料库

    Computational Linguistics http://matplotlib.org/ https://github.com/matplotlib/matplotlib/blob/maste ...

  8. P1090 合并果子

    #include <bits/stdc++.h> using namespace std; const int maxn = 10005; int main(int argc, char ...

  9. 【转】CSS(10)盒子模型

    CSS中, Box Model叫盒子模型(或框模型),Box Model规定了元素框处理元素内容(element content).内边距(padding).边框(border) 和 外边距(marg ...

  10. Delphi XE5 Android 程序退出功能

    Uses FMX.Platform.Android; ... begin {退出程序} MainActivity.finish; end;