using GeoAPI.Geometries; using GisSharpBlog.NetTopologySuite.Geometries; using GisSharpBlog.NetTopologySuite.Utilities; namespace GisSharpBlog.NetTopologySuite.Index.Quadtree { /// /// Represents a node of a Quadtree. Nodes contain /// items which have a spatial extent corresponding to the node's position /// in the quadtree. /// public class Node : NodeBase { private readonly ICoordinate centre; private readonly int level; /// /// /// /// /// public Node(IEnvelope env, int level) { Envelope = env; this.level = level; centre = new Coordinate(); centre.X = (env.MinX + env.MaxX)/2; centre.Y = (env.MinY + env.MaxY)/2; } /// /// /// public IEnvelope Envelope { get; private set; } /// /// /// /// /// public static Node CreateNode(IEnvelope env) { Key key = new Key(env); Node node = new Node(key.Envelope, key.Level); return node; } /// /// /// /// /// /// public static Node CreateExpanded(Node node, IEnvelope addEnv) { IEnvelope expandEnv = new Envelope(addEnv); if (node != null) { expandEnv.ExpandToInclude(node.Envelope); } Node largerNode = CreateNode(expandEnv); if (node != null) { largerNode.InsertNode(node); } return largerNode; } /// /// Returns the subquad containing the envelope. /// Creates the subquad if /// it does not already exist. /// /// public Node GetNode(IEnvelope searchEnv) { int subnodeIndex = GetSubnodeIndex(searchEnv, centre); // if subquadIndex is -1 searchEnv is not contained in a subquad if (subnodeIndex != -1) { // create the quad if it does not exist Node node = GetSubnode(subnodeIndex); // recursively search the found/created quad return node.GetNode(searchEnv); } else { return this; } } /// /// Returns the smallest existing /// node containing the envelope. /// /// public NodeBase Find(IEnvelope searchEnv) { int subnodeIndex = GetSubnodeIndex(searchEnv, centre); if (subnodeIndex == -1) { return this; } if (subnode[subnodeIndex] != null) { // query lies in subquad, so search it Node node = subnode[subnodeIndex]; return node.Find(searchEnv); } // no existing subquad, so return this one anyway return this; } /// /// /// /// public void InsertNode(Node node) { Assert.IsTrue(Envelope == null || Envelope.Contains(node.Envelope)); int index = GetSubnodeIndex(node.Envelope, centre); if (node.level == level - 1) { subnode[index] = node; } else { // the quad is not a direct child, so make a new child quad to contain it // and recursively insert the quad Node childNode = CreateSubnode(index); childNode.InsertNode(node); subnode[index] = childNode; } } /// /// /// /// /// protected override bool IsSearchMatch(IEnvelope searchEnv) { return Envelope.Intersects(searchEnv); } /// /// Get the subquad for the index. /// If it doesn't exist, create it. /// /// private Node GetSubnode(int index) { if (subnode[index] == null) { subnode[index] = CreateSubnode(index); } return subnode[index]; } /// /// /// /// /// private Node CreateSubnode(int index) { // create a new subquad in the appropriate quadrant double minx = 0.0; double maxx = 0.0; double miny = 0.0; double maxy = 0.0; switch (index) { case 0: minx = Envelope.MinX; maxx = centre.X; miny = Envelope.MinY; maxy = centre.Y; break; case 1: minx = centre.X; maxx = Envelope.MaxX; miny = Envelope.MinY; maxy = centre.Y; break; case 2: minx = Envelope.MinX; maxx = centre.X; miny = centre.Y; maxy = Envelope.MaxY; break; case 3: minx = centre.X; maxx = Envelope.MaxX; miny = centre.Y; maxy = Envelope.MaxY; break; default: break; } IEnvelope sqEnv = new Envelope(minx, maxx, miny, maxy); Node node = new Node(sqEnv, level - 1); return node; } } }