private void LoadSpatialIndex(bool forceRebuild, bool loadFromFile) { //Only load the tree if we haven't already loaded it, or if we want to force a rebuild if (_tree == null || forceRebuild) { // Is this a web application? If so lets store the index in the cache so we don't // need to rebuild it for each request if (HttpContext.Current != null) { //Check if the tree exists in the cache if (HttpContext.Current.Cache[_filename] != null) _tree = (QuadTree)HttpContext.Current.Cache[_filename]; else { _tree = !loadFromFile ? CreateSpatialIndex() : CreateSpatialIndexFromFile(_filename); //Store the tree in the web cache //TODO: Remove this when connection pooling is implemented HttpContext.Current.Cache.Insert(_filename, _tree, null, Cache.NoAbsoluteExpiration, TimeSpan.FromDays(1)); } } else if (!loadFromFile) _tree = CreateSpatialIndex(); else _tree = CreateSpatialIndexFromFile(_filename); } }
/// <summary> /// Forces a rebuild of the spatial index. If the instance of the ShapeFile provider /// uses a file-based index the file is rewritten to disk. /// </summary> public void RebuildSpatialIndex() { if (_fileBasedIndex) { if (File.Exists(_filename + ".sidx")) File.Delete(_filename + ".sidx"); _tree = CreateSpatialIndexFromFile(_filename); } else _tree = CreateSpatialIndex(); if (HttpContext.Current != null) //TODO: Remove this when connection pooling is implemented: HttpContext.Current.Cache.Insert(_filename, _tree, null, Cache.NoAbsoluteExpiration, TimeSpan.FromDays(1)); }
private void Dispose(bool disposing) { if (!_disposed) { if (disposing) { Close(); _envelope = null; _tree = null; } _disposed = true; } }
/// <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[0].Box; for (int i = 0; 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>[2]; // buckets of geometries objBuckets[0] = new List<BoxObjects>(); objBuckets[1] = new List<BoxObjects>(); uint longaxis = _box.LongestAxis; // longest axis double geoavg = 0; // 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 = 0; 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 = 0; i < objList.Count; i++) objBuckets[geoavg > objList[i].Box.GetCentroid()[longaxis] ? 1 : 0].Add(objList[i]); //If objects couldn't be splitted, just store them at the leaf //TODO: Try splitting on another axis if (objBuckets[0].Count == 0 || objBuckets[1].Count == 0) { _child0 = null; _child1 = null; // copy object list _objList = objList; } else { // create new children using the buckets _child0 = new QuadTree(objBuckets[0], depth + 1, heurdata); _child1 = new QuadTree(objBuckets[1], depth + 1, 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> /// 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 = 0; 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); } }
/// <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); } } else { if (node.Box.Intersects(box)) { IntersectTreeRecursive(box, node.Child0, ref list); IntersectTreeRecursive(box, node.Child1, ref list); } } }
/// <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 { _depth = depth, Box = new BoundingBox(br.ReadDouble(), br.ReadDouble(), br.ReadDouble(), br.ReadDouble()) }; var isLeaf = br.ReadBoolean(); if (isLeaf) { int featureCount = br.ReadInt32(); node._objList = new List<BoxObjects>(); for (int i = 0; i < featureCount; i++) { BoxObjects box = new BoxObjects { Box = new BoundingBox( br.ReadDouble(), br.ReadDouble(), br.ReadDouble(), br.ReadDouble()), Id = (uint) br.ReadInt32() }; node._objList.Add(box); } } else { node.Child0 = ReadNode(node._depth + 1, ref br); node.Child1 = ReadNode(node._depth + 1, ref br); } return node; }
/// <summary> /// Disposes the node /// </summary> public void Dispose() { //this._box = null; _child0 = null; _child1 = null; _objList = null; }