/// <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(QuadTreeOld node, ref System.IO.BinaryWriter sw) { //Write node boundingbox sw.Write(node.Box.MinX); sw.Write(node.Box.MinY); sw.Write(node.Box.MaxX); sw.Write(node.Box.MaxY); 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.MinX); sw.Write(node._objList[i].box.MinY); sw.Write(node._objList[i].box.MaxX); sw.Write(node._objList[i].box.MaxY); sw.Write(node._objList[i].ID); } } else if (!node.IsLeaf) //Save next node { SaveNode(node.Child0, ref sw); SaveNode(node.Child1, ref sw); } }
/// <summary> /// Disposes the node /// </summary> public void Dispose() { //this._box = null; this._child0 = null; this._child1 = null; this._objList = null; }
/// <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 QuadTreeOld ReadNode(uint depth, ref System.IO.BinaryReader br) { QuadTreeOld node = new QuadTreeOld(); node._Depth = depth; node.Box = GeometryFactory.CreateEnvelope(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 = GeometryFactory.CreateEnvelope(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> /// Loads a quadtree from a file /// </summary> /// <param name="filename"></param> /// <returns></returns> public static QuadTreeOld FromFile(string filename) { System.IO.FileStream fs = new System.IO.FileStream(filename, System.IO.FileMode.Open, System.IO.FileAccess.Read); System.IO.BinaryReader br = new System.IO.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"); } QuadTreeOld node = ReadNode(0, ref br); br.Close(); fs.Close(); 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, QuadTreeOld node, ref Collection <int> list) { if (node.IsLeaf) //Leaf has been reached { for (int i = 0; i < node._objList.Count; i++) { list.Add((int)node._objList[i].ID); } } else { if (node.Box.Intersects(box)) { IntersectTreeRecursive(box, node.Child0, ref list); IntersectTreeRecursive(box, node.Child1, ref list); } } }
/// <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 QuadTreeOld(List <BoxObjects> objList, uint depth, Heuristic heurdata) { _Depth = depth; _box = new Envelope(objList[0].box); for (int i = 0; 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)) { List <BoxObjects>[] objBuckets = new List <BoxObjects> [2]; // buckets of geometries objBuckets[0] = new List <BoxObjects>(); objBuckets[1] = new List <BoxObjects>(); string longaxis = LongestAxis(_box); // 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++) { if (longaxis == "X") { geoavg += objList[i].box.Centre.X * frac; } else { geoavg += objList[i].box.Centre.Y * 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++) { if (longaxis == "X") { objBuckets[geoavg > objList[i].box.Centre.X ? 1 : 0].Add(objList[i]); } else { objBuckets[geoavg > objList[i].box.Centre.Y ? 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 QuadTreeOld(objBuckets[0], depth + 1, heurdata); _child1 = new QuadTreeOld(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> /// 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 QuadTreeOld(List<BoxObjects> objList, uint depth, Heuristic heurdata) { _Depth = depth; _box = new Envelope(objList[0].box); for (int i = 0; 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)) { List<BoxObjects>[] objBuckets = new List<BoxObjects>[2]; // buckets of geometries objBuckets[0] = new List<BoxObjects>(); objBuckets[1] = new List<BoxObjects>(); string longaxis = LongestAxis(_box); // 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++ ) { if (longaxis=="X") geoavg += objList[i].box.Centre.X * frac; else geoavg += objList[i].box.Centre.Y * 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++ ) { if(longaxis=="X") objBuckets[geoavg > objList[i].box.Centre.X ? 1 : 0].Add(objList[i]); else objBuckets[geoavg > objList[i].box.Centre.Y ? 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 QuadTreeOld(objBuckets[0], depth + 1, heurdata); _child1 = new QuadTreeOld(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> /// 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, QuadTreeOld node, ref Collection<int> list) { if (node.IsLeaf) //Leaf has been reached { for (int i = 0; i < node._objList.Count; i++) { list.Add((int) node._objList[i].ID); } } else { if(node.Box.Intersects(box)) { IntersectTreeRecursive(box, node.Child0, ref list); IntersectTreeRecursive(box, node.Child1, ref list); } } }
/// <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(QuadTreeOld node, ref System.IO.BinaryWriter sw) { //Write node boundingbox sw.Write(node.Box.MinX); sw.Write(node.Box.MinY); sw.Write(node.Box.MaxX); sw.Write(node.Box.MaxY); 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.MinX); sw.Write(node._objList[i].box.MinY); sw.Write(node._objList[i].box.MaxX); sw.Write(node._objList[i].box.MaxY); sw.Write(node._objList[i].ID); } } else if (!node.IsLeaf) //Save next node { SaveNode(node.Child0, ref sw); SaveNode(node.Child1, ref sw); } }
/// <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 QuadTreeOld ReadNode(uint depth, ref System.IO.BinaryReader br) { QuadTreeOld node = new QuadTreeOld(); node._Depth = depth; node.Box = GeometryFactory.CreateEnvelope(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 = GeometryFactory.CreateEnvelope(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; }