/// <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> /// 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); }