private static object Get( double x, double y, double width, double height, MXCIFQuadTreeNode node) { if (node is MXCIFQuadTreeNodeLeaf) { var leaf = (MXCIFQuadTreeNodeLeaf) node; return GetFromData(x, y, width, height, leaf.Data); } var branch = (MXCIFQuadTreeNodeBranch) node; var q = node.Bb.GetQuadrantApplies(x, y, width, height); switch (q) { case QuadrantAppliesEnum.NW: return Get(x, y, width, height, branch.Nw); case QuadrantAppliesEnum.NE: return Get(x, y, width, height, branch.Ne); case QuadrantAppliesEnum.SW: return Get(x, y, width, height, branch.Sw); case QuadrantAppliesEnum.SE: return Get(x, y, width, height, branch.Se); case QuadrantAppliesEnum.SOME: return GetFromData(x, y, width, height, branch.Data); } throw new IllegalStateException("Not applicable to any quadrant"); }
private static ICollection <object> Visit( MXCIFQuadTreeNode <object> node, double x, double y, double width, double height, ICollection <object> result) { var data = node.Data; if (data == null) { return(result); } if (data is XYWHRectangleMultiType point) { return(Visit(point, x, y, width, height, result)); } var collection = (ICollection <XYWHRectangleMultiType>)data; foreach (XYWHRectangleMultiType rectangle in collection) { result = Visit(rectangle, x, y, width, height, result); } return(result); }
private static MXCIFQuadTreeNode <object> AddToNode( double x, double y, double width, double height, object value, MXCIFQuadTreeNode <object> node, MXCIFQuadTree <object> tree, bool unique, string indexName) { if (node is MXCIFQuadTreeNodeLeaf <object> ) { var leaf = (MXCIFQuadTreeNodeLeaf <object>)node; if (leaf.Count < tree.LeafCapacity || node.Level >= tree.MaxTreeHeight) { // can be multiple as value can be a collection var numAdded = AddToData(leaf, x, y, width, height, value, unique, indexName); leaf.IncCount(numAdded); if (leaf.Count <= tree.LeafCapacity || node.Level >= tree.MaxTreeHeight) { return(leaf); } } node = Subdivide(leaf, tree, unique, indexName); } var branch = (MXCIFQuadTreeNodeBranch <object>)node; AddToBranch(branch, x, y, width, height, value, tree, unique, indexName); return(node); }
private static ICollection<object> Visit( MXCIFQuadTreeNode node, double x, double y, double width, double height, ICollection<object> result) { var data = node.Data; if (data == null) { return result; } if (data is XYWHRectangleMultiType point) { return Visit(point, x, y, width, height, result); } else if (data is IList<XYWHRectangleMultiType> listData) { var listDataCount = listData.Count; for (var ii = 0; ii < listDataCount; ii++) { result = Visit(listData[ii], x, y, width, height, result); } } else if (data is IEnumerable<XYWHRectangleMultiType> enumData) { foreach (var rectangle in enumData) { result = Visit(rectangle, x, y, width, height, result); } } else { throw new IllegalStateException("type-erasure failure"); } return result; }
public static bool IsEmpty(MXCIFQuadTreeNode node) { if (node is MXCIFQuadTreeNodeLeaf leaf) { return leaf.Data == null; } return false; }
internal MXCIFQuadTree( int leafCapacity, int maxTreeHeight, MXCIFQuadTreeNode root) { LeafCapacity = leafCapacity; MaxTreeHeight = maxTreeHeight; Root = root; }
public static bool IsEmpty(MXCIFQuadTreeNode <object> node) { if (node is MXCIFQuadTreeNodeLeaf <object> leaf) { return(leaf.Data == null); } return(false); }
private static int Count(MXCIFQuadTreeNode node) { if (node is MXCIFQuadTreeNodeLeaf) { var leaf = (MXCIFQuadTreeNodeLeaf) node; return CountData(leaf.Data); } var branch = (MXCIFQuadTreeNodeBranch) node; return Count(branch.Nw) + Count(branch.Ne) + Count(branch.Sw) + Count(branch.Se) + CountData(branch.Data); }
public static void Set( double x, double y, double width, double height, object value, MXCIFQuadTree tree) { MXCIFQuadTreeNode root = tree.Root; MXCIFQuadTreeFilterIndexCheckBB.CheckBB(root.Bb, x, y, width, height); tree.Root = SetOnNode(x, y, width, height, value, root, tree); }
private static int SetOnNodeWithRect( MXCIFQuadTreeNode node, double x, double y, double width, double height, XYWHRectangleWValue value) { if (!value.CoordinateEquals(x, y, width, height)) { throw new IllegalStateException(); } return SetOnNode(node, x, y, width, height, value.Value); }
private static int Count <TL>(MXCIFQuadTreeNode <TL> node) { if (node is MXCIFQuadTreeNodeLeaf <TL> leaf) { return(CountData <TL>(leaf.Data)); } var branch = (MXCIFQuadTreeNodeBranch <TL>)node; return(Count(branch.Nw) + Count(branch.Ne) + Count(branch.Sw) + Count(branch.Se) + CountData <TL>(branch.Data)); }
private static void CollectNode( MXCIFQuadTreeNode <object> node, double x, double y, double width, double height, EventBean eventBean, TT target, QuadTreeCollector <TL, TT> collector) { var rectangles = node.Data; if (rectangles == null) { return; } if (rectangles is XYWHRectangleWValue <TL> rectangleX) { if (BoundingBox.IntersectsBoxIncludingEnd( x, y, x + width, y + height, rectangleX.X, rectangleX.Y, rectangleX.W, rectangleX.H)) { collector.CollectInto(eventBean, rectangleX.Value, target); } return; } var collection = (ICollection <XYWHRectangleWValue <TL> >)rectangles; foreach (XYWHRectangleWValue <TL> rectangle in collection) { if (BoundingBox.IntersectsBoxIncludingEnd( x, y, x + width, y + height, rectangle.X, rectangle.Y, rectangle.W, rectangle.H)) { collector.CollectInto(eventBean, rectangle.Value, target); } } }
public static void Traverse( MXCIFQuadTreeNode node, Consumer<object> consumer) { if (node is MXCIFQuadTreeNodeLeaf) { MXCIFQuadTreeNodeLeaf leaf = (MXCIFQuadTreeNodeLeaf) node; TraverseData(leaf.Data, consumer); return; } MXCIFQuadTreeNodeBranch branch = (MXCIFQuadTreeNodeBranch) node; TraverseData(branch.Data, consumer); Traverse(branch.Nw, consumer); Traverse(branch.Ne, consumer); Traverse(branch.Sw, consumer); Traverse(branch.Se, consumer); }
private static int SetOnNode( MXCIFQuadTreeNode <object> node, double x, double y, double width, double height, TL value) { var currentValue = node.Data; if (currentValue == null) { node.Data = new XYWHRectangleWValue <TL>(x, y, width, height, value); return(1); } if (currentValue is XYWHRectangleWValue <TL> otherXY) { if (otherXY.CoordinateEquals(x, y, width, height)) { otherXY.Value = value; return(0); } var collectionX = new List <XYWHRectangleWValue <TL> >(); collectionX.Add(otherXY); collectionX.Add(new XYWHRectangleWValue <TL>(x, y, width, height, value)); node.Data = collectionX; return(1); } var collection = (ICollection <XYWHRectangleWValue <TL> >)currentValue; foreach (var other in collection) { if (other.CoordinateEquals(x, y, width, height)) { other.Value = value; return(0); } } collection.Add(new XYWHRectangleWValue <TL>(x, y, width, height, value)); return(1); }
private static ICollection <object> QueryNode( MXCIFQuadTreeNode <object> node, double x, double y, double width, double height, ICollection <object> result) { if (node is MXCIFQuadTreeNodeLeaf <object> leaf) { return(Visit(leaf, x, y, width, height, result)); } var branch = (MXCIFQuadTreeNodeBranch <object>)node; result = Visit(branch, x, y, width, height, result); result = QueryNode(branch.Nw, x, y, width, height, result); result = QueryNode(branch.Ne, x, y, width, height, result); result = QueryNode(branch.Sw, x, y, width, height, result); result = QueryNode(branch.Se, x, y, width, height, result); return(result); }
private static void CollectRange( MXCIFQuadTreeNode <object> node, double x, double y, double width, double height, EventBean eventBean, TT target, QuadTreeCollector <TL, TT> collector) { if (node is MXCIFQuadTreeNodeLeaf <object> leaf) { CollectNode(leaf, x, y, width, height, eventBean, target, collector); return; } var branch = (MXCIFQuadTreeNodeBranch <object>)node; CollectNode(branch, x, y, width, height, eventBean, target, collector); CollectRange(branch.Nw, x, y, width, height, eventBean, target, collector); CollectRange(branch.Ne, x, y, width, height, eventBean, target, collector); CollectRange(branch.Sw, x, y, width, height, eventBean, target, collector); CollectRange(branch.Se, x, y, width, height, eventBean, target, collector); }
private static void CollectRange( MXCIFQuadTreeNode node, double x, double y, double width, double height, EventBean eventBean, TT target, QuadTreeCollector<TT> collector, ExprEvaluatorContext ctx) { if (node is MXCIFQuadTreeNodeLeaf leaf) { CollectNode(leaf, x, y, width, height, eventBean, target, collector, ctx); return; } MXCIFQuadTreeNodeBranch branch = (MXCIFQuadTreeNodeBranch) node; CollectNode(branch, x, y, width, height, eventBean, target, collector, ctx); CollectRange(branch.Nw, x, y, width, height, eventBean, target, collector, ctx); CollectRange(branch.Ne, x, y, width, height, eventBean, target, collector, ctx); CollectRange(branch.Sw, x, y, width, height, eventBean, target, collector, ctx); CollectRange(branch.Se, x, y, width, height, eventBean, target, collector, ctx); }
private static MXCIFQuadTreeNode SetOnNode( double x, double y, double width, double height, object value, MXCIFQuadTreeNode node, MXCIFQuadTree tree) { if (node is MXCIFQuadTreeNodeLeaf leaf) { var count = SetOnNode(leaf, x, y, width, height, value); leaf.IncCount(count); if (leaf.Count <= tree.LeafCapacity || node.Level >= tree.MaxTreeHeight) { return leaf; } node = Subdivide(leaf, tree); } var branch = (MXCIFQuadTreeNodeBranch) node; AddToBranch(branch, x, y, width, height, value, tree); return node; }
private static void CollectNode( MXCIFQuadTreeNode node, double x, double y, double width, double height, EventBean eventBean, TT target, QuadTreeCollector<TT> collector, ExprEvaluatorContext ctx) { object rectangles = node.Data; if (rectangles == null) { return; } if (rectangles is XYWHRectangleWValue rectangleWValue) { if (BoundingBox.IntersectsBoxIncludingEnd( x, y, x + width, y + height, rectangleWValue.X, rectangleWValue.Y, rectangleWValue.W, rectangleWValue.H)) { collector.CollectInto(eventBean, rectangleWValue.Value, target, ctx); } } else if (rectangles is List<XYWHRectangleWValue> listWithType) { // Using the enumerable structure has some overhead when called a lot. So, when // we know the value is a list (which it should be), then we attempt to use a // traditional loop to avoid the overhead. Need to measure this against the time // cost for List.ForEach() var listWithTypeCount = listWithType.Count; for (var ii = 0; ii < listWithTypeCount; ii++) { var rectangle = listWithType[ii]; if (BoundingBox.IntersectsBoxIncludingEnd( x, y, x + width, y + height, rectangle.X, rectangle.Y, rectangle.W, rectangle.H)) { collector.CollectInto(eventBean, rectangle.Value, target, ctx); } } } else if (rectangles is IEnumerable<XYWHRectangleWValue> enumerableWithType) { foreach (var rectangle in enumerableWithType) { if (BoundingBox.IntersectsBoxIncludingEnd( x, y, x + width, y + height, rectangle.X, rectangle.Y, rectangle.W, rectangle.H)) { collector.CollectInto(eventBean, rectangle.Value, target, ctx); } } } else { throw new IllegalStateException("unknown type for rectangles"); } }
internal MXCIFQuadTree(int leafCapacity, int maxTreeHeight, MXCIFQuadTreeNode <TL> root) { _leafCapacity = leafCapacity; _maxTreeHeight = maxTreeHeight; _root = root; }
private static MXCIFQuadTreeNode<object> DeleteFromNode( double x, double y, double width, double height, MXCIFQuadTreeNode<object> node, MXCIFQuadTree<object> tree) { if (node is MXCIFQuadTreeNodeLeaf<object> leaf) { var removed = DeleteFromData(x, y, width, height, leaf.Data); if (removed) { leaf.DecCount(); if (leaf.Count == 0) leaf.Data = null; } return leaf; } var branch = (MXCIFQuadTreeNodeBranch<object>) node; var quadrant = node.Bb.GetQuadrantApplies(x, y, width, height); if (quadrant == QuadrantAppliesEnum.NW) { branch.Nw = DeleteFromNode(x, y, width, height, branch.Nw, tree); } else if (quadrant == QuadrantAppliesEnum.NE) { branch.Ne = DeleteFromNode(x, y, width, height, branch.Ne, tree); } else if (quadrant == QuadrantAppliesEnum.SW) { branch.Sw = DeleteFromNode(x, y, width, height, branch.Sw, tree); } else if (quadrant == QuadrantAppliesEnum.SE) { branch.Se = DeleteFromNode(x, y, width, height, branch.Se, tree); } else if (quadrant == QuadrantAppliesEnum.SOME) { var removed = DeleteFromData(x, y, width, height, branch.Data); if (removed) { branch.DecCount(); if (branch.Count == 0) branch.Data = null; } } if (!(branch.Nw is MXCIFQuadTreeNodeLeaf<object> nwLeaf) || !(branch.Ne is MXCIFQuadTreeNodeLeaf<object> neLeaf) || !(branch.Sw is MXCIFQuadTreeNodeLeaf<object> swLeaf) || !(branch.Se is MXCIFQuadTreeNodeLeaf<object> seLeaf)) return branch; var total = nwLeaf.Count + neLeaf.Count + swLeaf.Count + seLeaf.Count + branch.Count; if (total >= tree.LeafCapacity) return branch; var collection = new LinkedList<XYWHRectangleWValue<TL>>(); var count = MergeChildNodes(collection, branch.Data); count += MergeChildNodes(collection, nwLeaf.Data); count += MergeChildNodes(collection, neLeaf.Data); count += MergeChildNodes(collection, swLeaf.Data); count += MergeChildNodes(collection, seLeaf.Data); return new MXCIFQuadTreeNodeLeaf<object>(branch.Bb, branch.Level, collection, count); }
public static void Delete(double x, double y, double width, double height, MXCIFQuadTree<object> tree) { MXCIFQuadTreeNode<object> root = tree.Root; MXCIFQuadTreeFilterIndexCheckBB.CheckBB(root.Bb, x, y, width, height); tree.Root = DeleteFromNode(x, y, width, height, root, tree); }
private static MXCIFQuadTreeNode RemoveFromNode( double x, double y, double width, double height, object value, MXCIFQuadTreeNode node, MXCIFQuadTree tree) { if (node is MXCIFQuadTreeNodeLeaf leaf) { var removed = RemoveFromPoints(x, y, width, height, value, leaf.Data); if (removed) { leaf.DecCount(); if (leaf.Count == 0) { leaf.Data = null; } } return leaf; } var branch = (MXCIFQuadTreeNodeBranch) node; var quadrant = node.Bb.GetQuadrantApplies(x, y, width, height); switch (quadrant) { case QuadrantAppliesEnum.NW: branch.Nw = RemoveFromNode(x, y, width, height, value, branch.Nw, tree); break; case QuadrantAppliesEnum.NE: branch.Ne = RemoveFromNode(x, y, width, height, value, branch.Ne, tree); break; case QuadrantAppliesEnum.SW: branch.Sw = RemoveFromNode(x, y, width, height, value, branch.Sw, tree); break; case QuadrantAppliesEnum.SE: branch.Se = RemoveFromNode(x, y, width, height, value, branch.Se, tree); break; case QuadrantAppliesEnum.SOME: var removed = RemoveFromPoints(x, y, width, height, value, branch.Data); if (removed) { branch.DecCount(); if (branch.Count == 0) { branch.Data = null; } } break; } if (!(branch.Nw is MXCIFQuadTreeNodeLeaf) || !(branch.Ne is MXCIFQuadTreeNodeLeaf) || !(branch.Sw is MXCIFQuadTreeNodeLeaf) || !(branch.Se is MXCIFQuadTreeNodeLeaf)) { return branch; } var nwLeaf = (MXCIFQuadTreeNodeLeaf) branch.Nw; var neLeaf = (MXCIFQuadTreeNodeLeaf) branch.Ne; var swLeaf = (MXCIFQuadTreeNodeLeaf) branch.Sw; var seLeaf = (MXCIFQuadTreeNodeLeaf) branch.Se; var total = branch.Count + nwLeaf.Count + neLeaf.Count + swLeaf.Count + seLeaf.Count; if (total >= tree.LeafCapacity) { return branch; } var collection = new List<XYWHRectangleMultiType>(); var count = MergeChildNodes(collection, branch.Data); count += MergeChildNodes(collection, nwLeaf.Data); count += MergeChildNodes(collection, neLeaf.Data); count += MergeChildNodes(collection, swLeaf.Data); count += MergeChildNodes(collection, seLeaf.Data); return new MXCIFQuadTreeNodeLeaf(branch.Bb, branch.Level, collection, count); }
public static int AddToData( MXCIFQuadTreeNode <object> node, double x, double y, double width, double height, object value, bool unique, string indexName) { var currentValue = node.Data; // value can be multitype itself since we may subdivide-add and don't want to allocate a new object if (value is XYWHRectangleMultiType rectangle) { if (!rectangle.CoordinateEquals(x, y, width, height)) { throw new IllegalStateException(); } if (currentValue == null) { node.Data = rectangle; return(rectangle.Count()); } if (currentValue is XYWHRectangleMultiType otherXYWHR) { if (otherXYWHR.CoordinateEquals(x, y, width, height)) { if (unique) { throw HandleUniqueViolation(indexName, otherXYWHR); } otherXYWHR.AddMultiType(rectangle); return(rectangle.Count()); } var collectionInner = new LinkedList <XYWHRectangleMultiType>(); collectionInner.AddLast(otherXYWHR); collectionInner.AddLast(rectangle); node.Data = collectionInner; return(rectangle.Count()); } var collectionXYWH = (ICollection <XYWHRectangleMultiType>)currentValue; foreach (var other in collectionXYWH) { if (other.CoordinateEquals(x, y, width, height)) { if (unique) { throw HandleUniqueViolation(indexName, other); } other.AddMultiType(rectangle); return(rectangle.Count()); } } collectionXYWH.Add(rectangle); return(rectangle.Count()); } if (currentValue == null) { var point = new XYWHRectangleMultiType(x, y, width, height, value); node.Data = point; return(1); } if (currentValue is XYWHRectangleMultiType otherInnerX) { if (otherInnerX.CoordinateEquals(x, y, width, height)) { if (unique) { throw HandleUniqueViolation(indexName, otherInnerX); } otherInnerX.AddSingleValue(value); return(1); } var collectionXY = new LinkedList <XYWHRectangleMultiType>(); collectionXY.AddLast(otherInnerX); collectionXY.AddLast(new XYWHRectangleMultiType(x, y, width, height, value)); node.Data = collectionXY; return(1); } var collection = (ICollection <XYWHRectangleMultiType>)currentValue; foreach (XYWHRectangleMultiType other in collection) { if (other.CoordinateEquals(x, y, width, height)) { if (unique) { throw HandleUniqueViolation(indexName, other); } other.AddSingleValue(value); return(1); } } collection.Add(new XYWHRectangleMultiType(x, y, width, height, value)); return(1); }
public void Clear() { Root = new MXCIFQuadTreeNodeLeaf(Root.Bb, Root.Level, null, 0); }
public static int AddToData( MXCIFQuadTreeNode node, double x, double y, double width, double height, object value, bool unique, string indexName) { var currentValue = node.Data; // value can be multitype itself since we may subdivide-add and don't want to allocate a new object if (value is XYWHRectangleMultiType) { var rectangle = (XYWHRectangleMultiType) value; if (!rectangle.CoordinateEquals(x, y, width, height)) { throw new IllegalStateException(); } if (currentValue == null) { node.Data = rectangle; return rectangle.Count(); } if (currentValue is XYWHRectangleMultiType) { var other = (XYWHRectangleMultiType) currentValue; if (other.CoordinateEquals(x, y, width, height)) { if (unique) { throw HandleUniqueViolation(indexName, other); } other.AddMultiType(rectangle); return rectangle.Count(); } ICollection<XYWHRectangleMultiType> collectionX = new List<XYWHRectangleMultiType>(); collectionX.Add(other); collectionX.Add(rectangle); node.Data = collectionX; return rectangle.Count(); } var collectionY = (ICollection<XYWHRectangleMultiType>) currentValue; foreach (var other in collectionY) { if (other.CoordinateEquals(x, y, width, height)) { if (unique) { throw HandleUniqueViolation(indexName, other); } other.AddMultiType(rectangle); return rectangle.Count(); } } collectionY.Add(rectangle); return rectangle.Count(); } if (currentValue == null) { node.Data = new XYWHRectangleMultiType(x, y, width, height, value); return 1; } if (currentValue is XYWHRectangleMultiType) { var other = (XYWHRectangleMultiType) currentValue; if (other.CoordinateEquals(x, y, width, height)) { if (unique) { throw HandleUniqueViolation(indexName, other); } other.AddSingleValue(value); return 1; } ICollection<XYWHRectangleMultiType> collectionZ = new List<XYWHRectangleMultiType>(); collectionZ.Add(other); collectionZ.Add(new XYWHRectangleMultiType(x, y, width, height, value)); node.Data = collectionZ; return 1; } var collection = (ICollection<XYWHRectangleMultiType>) currentValue; foreach (var other in collection) { if (other.CoordinateEquals(x, y, width, height)) { if (unique) { throw HandleUniqueViolation(indexName, other); } other.AddSingleValue(value); return 1; } } collection.Add(new XYWHRectangleMultiType(x, y, width, height, value)); return 1; }