public bool Contains(T item) { return(m_Root.Contains(item)); }
public void Add(IndexedPoint3D point) { if (_root == null && !_initialPoints.Any()) { _minX = _maxX = point.X; _minY = _maxY = point.Y; } else { _minX = Math.Min(_minX, point.X); _minY = Math.Min(_minY, point.Y); _maxX = Math.Max(_maxX, point.X); _maxY = Math.Max(_maxY, point.Y); } if (_root == null) { _initialPoints.Add(point); // todo: min number of points or epsilon? if (_minX != _maxX || _minY != _maxY) { _root = new QuadTreeNode(_minX, _minY, Math.Max(_maxX - _minX, _maxY - _minY)); //_root.Count = _count + 1; foreach (var p in _initialPoints) { _root.Add(p); } ++_nodeCount; } } else { // todo: consider whether y goes up or down // zoom out if necessary while (!_root.Contains(point)) { var newX = _root.X; var newY = _root.Y; if (point.X < newX) { newX -= _root.Dimension; } if (point.Y < newY) { newY -= _root.Dimension; } var newRoot = new QuadTreeNode(newX, newY, _root.Dimension * 2); newRoot.Count = _root.Count; ++_nodeCount; if (_root.X == newRoot.X && _root.Y == newRoot.Y) { newRoot.NW = _root; } else if (_root.X == newRoot.X) { newRoot.SW = _root; } else if (_root.Y == newRoot.Y) { newRoot.NE = _root; } else { newRoot.SE = _root; } _root = newRoot; } // now zoom in (until when? initial starting depth?) var node = _root; var depthRemaining = MaxTreeDepth; while (true) { ++node.Count; if (--depthRemaining == 0 || node.IsFinal) { break; } var halfDimension = node.Dimension / 2; var nodeCenterX = node.X + halfDimension; var nodeCenterY = node.Y + halfDimension; if (point.X < nodeCenterX && point.Y < nodeCenterY) { if (node.NW == null) { node.NW = new QuadTreeNode(node.X, node.Y, halfDimension); ++_nodeCount; } node = node.NW; } else if (point.X < nodeCenterX) { if (node.SW == null) { node.SW = new QuadTreeNode(node.X, node.Y + halfDimension, halfDimension); ++_nodeCount; } node = node.SW; } else if (point.Y < nodeCenterY) { if (node.NE == null) { node.NE = new QuadTreeNode(node.X + halfDimension, node.Y, halfDimension); ++_nodeCount; } node = node.NE; } else { if (node.SE == null) { node.SE = new QuadTreeNode(node.X + halfDimension, node.Y + halfDimension, halfDimension); ++_nodeCount; } node = node.SE; } } --node.Count; node.Add(point); } if (_nodeCount > MaxNodes) { // sort non-leaf nodes by depth and count, and find the lowest/smallest to merge //Console.WriteLine($"Reducing nodes at point count {_count}"); var depth = 1; var nodesByDepth = new Dictionary <int, List <QuadTreeNode> >(); nodesByDepth.Add(depth, new List <QuadTreeNode> { _root }); while (nodesByDepth.Count == depth) { var nodes = nodesByDepth[depth]; ++depth; foreach (var node in nodes) { foreach (var child in node.GetNodes()) { if (!child.IsLeaf()) { if (!nodesByDepth.ContainsKey(depth)) { nodesByDepth.Add(depth, new List <QuadTreeNode>()); } nodesByDepth[depth].Add(child); } } } } var targetNodeCount = MaxNodes - ReduceBy; while (--depth > 0 && _nodeCount > targetNodeCount) { var nodes = nodesByDepth[depth].OrderBy(x => x.Count); foreach (var node in nodes) { var leafCount = node.GetNodes().Count(); _nodeCount -= leafCount; // todo: merge indexing info node.Collapse(); } if (_nodeCount <= targetNodeCount) { break; } } } }