/// <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, BinaryReader br) { var bbox = new Envelope(new Coordinate(br.ReadDouble(), br.ReadDouble()), new Coordinate(br.ReadDouble(), br.ReadDouble())); var node = new QuadTree(bbox, depth); var isLeaf = br.ReadBoolean(); if (isLeaf) { var featureCount = br.ReadInt32(); node._objList = new List<BoxObjects>(); for (int i = 0; i < featureCount; i++) { var box = new BoxObjects(); box.Box = new Envelope(new Coordinate(br.ReadDouble(), br.ReadDouble()), new Coordinate(br.ReadDouble(), br.ReadDouble())); box.ID = (uint) br.ReadInt32(); node._objList.Add(box); } } else { node.Child0 = ReadNode(depth + 1, br); node.Child1 = ReadNode(depth + 1, br); } return node; }
/// <summary> /// Saves a node to a stream recursively /// </summary> /// <param name="node">Node to save</param> /// <param name="sw">Reference to BinaryWriter</param> private static void SaveNode(QuadTree node, BinaryWriter sw) { //Write node boundingbox var box = node.Box; sw.Write(box.MinX); sw.Write(box.MinY); sw.Write(box.MaxX); sw.Write(box.MaxY); sw.Write(node.IsLeaf); if (node.IsLeaf || node.Child0 == null) { if (node._objList == null) { sw.Write(0); return; } sw.Write(node._objList.Count); //Write number of features at node for (int i = 0; i < node._objList.Count; i++) //Write each featurebox { var bo = node._objList[i]; box = bo.Box; sw.Write(box.MinX); sw.Write(box.MinY); sw.Write(box.MaxX); sw.Write(box.MaxY); sw.Write(bo.ID); } } else if (!node.IsLeaf) //Save next node { SaveNode(node.Child0, sw); SaveNode(node.Child1, 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); } /* 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); } } }
/// <summary> /// Adds a new <see cref="BoxObjects"/> to this node. /// </summary> /// <param name="o">The boxed object</param> /// <param name="h">The child node creation heuristic</param> public void AddNode(BoxObjects o, Heuristic h) { /* -------------------------------------------------------------------- */ /* If there are subnodes, then consider whether this object */ /* will fit in them. */ /* -------------------------------------------------------------------- */ if (_child0 != null && _depth < h.maxdepth) { if (_child0.Box.Contains(o.Box.Centre)) _child0.AddNode(o, h); else if (_child1.Box.Contains(o.Box.Centre)) _child1.AddNode(o, h); return; } /* -------------------------------------------------------------------- */ /* Otherwise, consider creating two subnodes if could fit into */ /* them, and adding to the appropriate subnode. */ /* -------------------------------------------------------------------- */ if( h.maxdepth > _depth && !IsLeaf ) { Envelope half1, half2; SplitBoundingBox(Box, out half1, out half2); if( half1.Contains(o.Box.Centre)) { _child0 = new QuadTree(half1, _depth + 1); _child1 = new QuadTree(half2, _depth + 1); _child0.AddNode(o, h); return; } if(half2.Contains(o.Box.Centre)) { _child0 = new QuadTree(half1, _depth + 1); _child1 = new QuadTree(half2, _depth + 1); _child1.AddNode(o, h); return; } } /* -------------------------------------------------------------------- */ /* If none of that worked, just add it to this nodes list. */ /* -------------------------------------------------------------------- */ //Debug.Assert(_child0 == null); if (_objList == null) _objList = new List<BoxObjects>(); Box.ExpandToInclude(o.Box); _objList.Add(o); }
/// <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 System.IO.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); } }
public void TryAddValue(string key, QuadTree quadTree, TimeSpan fromDays) { HttpCacheUtility.TryAddValue(key, quadTree, fromDays); }
/// <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 = new Envelope(objList[0].Box); for (var i = 1; i < objList.Count; i++) { _box.ExpandToInclude(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)) { var objBuckets = new List <BoxObjects> [2]; // buckets of geometries objBuckets[0] = new List <BoxObjects>(); objBuckets[1] = new List <BoxObjects>(); var longaxis = _box.LongestAxis(); // longest axis var geoavg = 0d; // geometric average - midpoint of ALL the objects // go through all bbox and calculate the average of the midpoints var frac = 1.0d / objList.Count; for (var i = 0; i < objList.Count; i++) { geoavg += objList[i].Box.Centre[longaxis] * frac; } // bucket bbox based on their midpoint's side of the geo average in the longest axis for (var i = 0; i < objList.Count; i++) { objBuckets[geoavg > objList[i].Box.Centre[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 { //We don't need the list anymore; objList.Clear(); // 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> /// 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 System.IO.BinaryReader br) { QuadTree node = new QuadTree(); node._Depth = depth; node.Box = new SharpMap.Geometries.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 = 0; i < FeatureCount; i++) { BoxObjects box = new BoxObjects(); box.box = new SharpMap.Geometries.BoundingBox(br.ReadDouble(), br.ReadDouble(), br.ReadDouble(), br.ReadDouble()); box.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> /// 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(IEnvelope box, QuadTree node, ref Collection<uint> list) { if (node.IsLeaf) //Leaf has been reached { 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); } } }
/// <summary> /// Build the grid based on Quadtree algorithm /// </summary> /// <param name="envelop">Full extent envelop</param> private void BuildGrid(IEnvelope envelop) { if (this._indexBound == null) { this._indexBound = this.CreateSpatialIndex(envelop); } }
public bool TryGetValue(string key, out QuadTree quadTree) { quadTree = null; return false; }
public void TryAddValue(string key, QuadTree quadTree, TimeSpan fromDays) { }
/// <summary> /// Adds a new <see cref="BoxObjects"/> to this node. /// </summary> /// <param name="o">The boxed object</param> /// <param name="h">The child node creation heuristic</param> public void AddNode(BoxObjects o, Heuristic h) { /* -------------------------------------------------------------------- */ /* If there are subnodes, then consider whether this object */ /* will fit in them. */ /* -------------------------------------------------------------------- */ if (_child0 != null && _depth < h.maxdepth) { if (_child0.Box.Contains(o.Box.GetCentroid())) { _child0.AddNode(o, h); } else if (_child1.Box.Contains(o.Box.GetCentroid())) { _child1.AddNode(o, h); } return; } /* -------------------------------------------------------------------- */ /* Otherwise, consider creating two subnodes if could fit into */ /* them, and adding to the appropriate subnode. */ /* -------------------------------------------------------------------- */ if (h.maxdepth > _depth && !IsLeaf) { BoundingBox half1, half2; SplitBoundingBox(Box, out half1, out half2); if (half1.Contains(o.Box.GetCentroid())) { _child0 = new QuadTree(half1, _depth + 1); _child1 = new QuadTree(half2, _depth + 1); _child0.AddNode(o, h); return; } if (half2.Contains(o.Box.GetCentroid())) { _child0 = new QuadTree(half1, _depth + 1); _child1 = new QuadTree(half2, _depth + 1); _child1.AddNode(o, h); return; } } /* -------------------------------------------------------------------- */ /* If none of that worked, just add it to this nodes list. */ /* -------------------------------------------------------------------- */ //Debug.Assert(_child0 == null); if (_objList == null) { _objList = new List <BoxObjects>(); } if (!Box.Contains(o.Box)) { Box = Box.Join(o.Box); } _objList.Add(o); }
/// <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 static void IntersectTreeRecursive(Envelope box, QuadTree node, /*ref*/ ICollection<uint> list) { if (node.IsLeaf) //Leaf has been reached { foreach (var 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)) { if (node.Child0 != null) IntersectTreeRecursive(box, node.Child0, /*ref*/ list); if (node.Child1 != null) IntersectTreeRecursive(box, node.Child1, /*ref*/ list); } } }
private void Dispose(bool disposing) { if (!disposed) { if (disposing) { Close(); _Envelope = null; tree = null; } disposed = true; } }
/// <summary> /// Disposes the node /// </summary> public void Dispose() { //this._box = null; this._child0 = null; this._child1 = null; this._objList = null; }
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 { if (!LoadFromFile) tree = CreateSpatialIndex(_Filename); else tree = 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(_Filename); else tree = CreateSpatialIndexFromFile(_Filename); } }
/// <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(SharpMap.Geometries.BoundingBox box, QuadTree node, ref List<uint> list) { if (node.IsLeaf) //Leaf has been reached { 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); } } }
/// <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(_Filename); if (HttpContext.Current != null) //TODO: Remove this when connection pooling is implemented: HttpContext.Current.Cache.Insert(_Filename, tree, null, Cache.NoAbsoluteExpiration, TimeSpan.FromDays(1)); }
/// <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; } }
public bool TryGetValue(string key, out QuadTree quadTree) { return HttpCacheUtility.TryGetValue(key, out quadTree); }