public bool Set(ref Point2i point, ref T value) { var anySet = setInternal(ref point, ref value); if (anySet) { unsubdivide(); } return(anySet); }
public bool Unset(ref Point2i point) { var anyUnset = unsetInternal(ref point); if (anyUnset) { unsubdivide(); } return(anyUnset); }
private bool unsetInternal(ref Point2i point) { if (!aabb.Contains(point)) { return(false); } if (Type == QuadType.White) { return(false); } if (depth < resolution) { if (Type != QuadType.Grey) { subdivide(); } } else { propagateEvent(EventType.Removing); this.value = null; return(true); } foreach (var quad in quads) { if (quad.unsetInternal(ref point)) { return(true); } } return(false); throw new InvalidOperationException("This is not supposed to happen!"); }
public bool UnsetCircle(Point2i point, int radius) { var rectSize = (int)(radius / Math.Sqrt(2)); var testAABB = new AABB2i( point - new Point2i(rectSize - 1, rectSize - 1), point + new Point2i(rectSize - 1, rectSize - 1)); bool anyOuterUnset = false; for (int i = point.X - radius; i <= point.X + radius; i++) { for (int j = point.Y - radius; j <= point.Y + radius; j++) { var currentPoint = new Point2i(i, j); if (testAABB.Contains(currentPoint)) { continue; } if ((point - currentPoint).Length() <= radius) { anyOuterUnset |= unsetInternal(ref currentPoint); } } } var anyAABBUnset = unsetAABBInternal(ref testAABB); if (anyOuterUnset || anyAABBUnset) { unsubdivide(); } return(anyOuterUnset || anyAABBUnset); }
private bool setInternal(ref Point2i point, ref T value) { if (isPointOutside(point)) { return(false); } if (Type == QuadType.Black && this.value.Value.Equals(value)) { return(false); } if (depth < resolution) { if (Type != QuadType.Grey) { subdivide(); } } else { return(setInternal(ref value)); } foreach (var quad in quads) { if (quad.setInternal(ref point, ref value)) { return(true); } } return(false); throw new InvalidOperationException("Set didn't fail nor succeed. This is not supposed to happen!"); }
public void Combine(ref AABB2i aabb) { LowerBound = new Point2i(Math.Min(LowerBound.X, aabb.LowerBound.X), Math.Min(LowerBound.Y, aabb.LowerBound.Y)); UpperBound = new Point2i(Math.Max(UpperBound.X, aabb.UpperBound.X), Math.Max(UpperBound.Y, aabb.UpperBound.Y)); }
public bool Contains(Point2i point) { return(point.X >= (LowerBound.X) && point.X < (UpperBound.X) && (point.Y >= (LowerBound.Y) && point.Y < (UpperBound.Y))); }
public AABB2i(Point2i min, Point2i max) { LowerBound = min; UpperBound = max; }
public RegionQuadtree <T> ExpandFromCenter() { if (Type != QuadType.Grey) { subdivide(); } Action <RegionQuadtree <T>, Action <RegionQuadtree <T> > > doForEach = null; doForEach = (qt, f) => { f(qt); if (qt.Type == QuadType.Grey) { foreach (var dir in QDO.Quadrants) { doForEach(qt[dir], f); } } }; doForEach(this, (qt) => { if (qt.Type == QuadType.Black) { qt.propagateEvent(EventType.Removing); } }); var newRoot = new RegionQuadtree <T>(resolution + 1); newRoot.AutoExpand = AutoExpand; newRoot.subdivide(); foreach (var child in newRoot.quads) { child.subdivide(); } var offset = new Point2i(newRoot.aabb.Width / 4, newRoot.aabb.Height / 4); var offsets = new Dictionary <QuadDirection, Point2i> { { QuadDirection.NorthWest, new Point2i(quads[0].aabb.Width / 2, quads[0].aabb.Height / 2) }, { QuadDirection.SouthEast, new Point2i(quads[0].aabb.Width / 2, quads[0].aabb.Height / 2) }, { QuadDirection.NorthEast, new Point2i(quads[0].aabb.Width / 2, quads[0].aabb.Height / 2) }, { QuadDirection.SouthWest, new Point2i(quads[0].aabb.Width / 2, quads[0].aabb.Height / 2) }, }; // Set children Action <RegionQuadtree <T>, RegionQuadtree <T> > expandProcessor = null; expandProcessor = (qt, parent) => { // Do this qt.parent = parent; qt.depth = qt.parent.depth + 1; qt.resolution = qt.parent.resolution; // Do children if (qt.Type == QuadType.Grey) { foreach (var dir in QDO.Quadrants) { switch (dir) { case QuadDirection.NorthWest: qt[dir].aabb.LowerBound = qt.aabb.LowerBound; qt[dir].aabb.UpperBound = qt.aabb.LowerBound + new Point2i(qt.aabb.Width / 2, qt.aabb.Height / 2); break; case QuadDirection.NorthEast: qt[dir].aabb.LowerBound = qt.aabb.LowerBound + new Point2i(qt.aabb.Width / 2, 0); qt[dir].aabb.UpperBound = qt.aabb.LowerBound + new Point2i(qt.aabb.Width, qt.aabb.Height / 2); break; case QuadDirection.SouthEast: qt[dir].aabb.LowerBound = qt.aabb.LowerBound + new Point2i(qt.aabb.Width / 2, qt.aabb.Height / 2); qt[dir].aabb.UpperBound = qt.aabb.LowerBound + new Point2i(qt.aabb.Width, qt.aabb.Height); break; case QuadDirection.SouthWest: qt[dir].aabb.LowerBound = qt.aabb.LowerBound + new Point2i(0, qt.aabb.Height / 2); qt[dir].aabb.UpperBound = qt.aabb.LowerBound + new Point2i(qt.aabb.Width / 2, qt.aabb.Height); break; default: throw new ArgumentException("Invalid direction"); } expandProcessor(qt[dir], qt); } } }; foreach (var quadDirection in QDO.Quadrants) { var oldQuad = newRoot[quadDirection][QDO.OpSide(quadDirection)]; newRoot[quadDirection][QDO.OpSide(quadDirection)] = this[quadDirection]; var newQuad = newRoot[quadDirection][QDO.OpSide(quadDirection)]; newQuad.aabb = oldQuad.aabb; expandProcessor(newQuad, oldQuad.parent); } // Call the event if (OnExpand != null) { OnExpand(this, new QuadExpandEventArgs <T>(newRoot, offset)); } // Move events // TODO: Test this works properly newRoot.OnQuadAdded = OnQuadAdded; OnQuadAdded = null; newRoot.OnQuadRemoving = OnQuadRemoving; OnQuadRemoving = null; newRoot.OnQuadChanged = OnQuadChanged; OnQuadChanged = null; doForEach(newRoot, (qt) => { if (qt.Type == QuadType.Black) { qt.propagateEvent(EventType.Added); } }); newRoot.OnExpand = OnExpand; return(newRoot); }
private bool isPointOutside(Point2i point) { return(!aabb.Contains(point)); }
public bool Unset(Point2i point) { return(Unset(ref point)); }
public bool Set(Point2i point, T value) { return(Set(ref point, ref value)); }
public bool SetCircle(Point2i point, int radius, T value) { var rectSize = (int)(radius / Math.Sqrt(2)); var testAABB = new AABB2i(point - new Point2i(rectSize, rectSize), point + new Point2i(rectSize, rectSize)); for (int i = point.X - radius; i <= point.X + radius; i++) { for (int j = point.Y - radius; j <= point.Y + radius; j++) { var currentPoint = new Point2i(i, j); if (testAABB.Contains(currentPoint)) { continue; } if ((point - currentPoint).Length() < radius) { if (isPointOutside(currentPoint)) { if (findRoot() == this && AutoExpand) { RegionQuadtree <T> newRoot = this; if (newRoot.isPointOutside(currentPoint)) { newRoot = newRoot.ExpandFromCenter(); point += new Point2i(newRoot.aabb.Width / 4, newRoot.aabb.Height / 4); } return(newRoot.SetCircle(point, radius, value)); } } } } } bool anyOuterSet = false; for (int i = point.X - radius; i <= point.X + radius; i++) { for (int j = point.Y - radius; j <= point.Y + radius; j++) { var currentPoint = new Point2i(i, j); if (testAABB.Contains(currentPoint)) { continue; } if ((point - currentPoint).Length() < radius) { anyOuterSet |= setInternal(ref currentPoint, ref value); } } } var anyAABBSet = setAABBInternal(ref testAABB, ref value); if (anyOuterSet || anyAABBSet) { unsubdivide(); } return(anyOuterSet || anyAABBSet); }
public QuadExpandEventArgs(RegionQuadtree <T> newRoot, Point2i offset) { this.newRoot = newRoot; this.offset = offset; }