/// <summary> Create copy of the rectangle</summary> public RectangleR2(RectangleR2 r) { this.top = r.top; this.left = r.left; this.bottom = r.bottom; this.right = r.right; }
internal virtual void Find(RectangleR2 r, ArrayList result, int level) { if (--level != 0) { /* this is an internal node in the tree */ for (int i = 0; i < n; i++) { if (r.Intersects(b[i])) { ((RtreeR2Page) branch.Get(i)).Find(r, result, level); } } } else { /* this is a leaf node */ for (int i = 0; i < n; i++) { if (r.Intersects(b[i])) { result.Add(branch.Get(i)); } } } }
internal RectangleR2 Cover() { RectangleR2 r = new RectangleR2(b[0]); for (int i = 1; i < n; i++) { r.Join(b[i]); } return r; }
internal RtreeR2Page AddBranch(Storage storage, RectangleR2 r, IPersistent obj) { if (n < card) { SetBranch(n++, r, obj); return null; } else { return SplitPage(storage, r, obj); } }
internal RtreeR2Page(Storage storage, IPersistent obj, RectangleR2 r) { branch = storage.CreateLink(card); branch.Size = card; b = new RectangleR2[card]; SetBranch(0, new RectangleR2(r), obj); n = 1; for (int i = 1; i < card; i++) { b[i] = new RectangleR2(); } }
internal RtreeR2Page(Storage storage, RtreeR2Page root, RtreeR2Page p) { branch = storage.CreateLink(card); branch.Size = card; b = new RectangleR2[card]; n = 2; SetBranch(0, root.Cover(), root); SetBranch(1, p.Cover(), p); for (int i = 2; i < card; i++) { b[i] = new RectangleR2(); } }
public static void Main(string[] args) { Storage db = StorageFactory.Instance.CreateStorage(); long start = (DateTime.Now.Ticks - 621355968000000000) / 10000; if (args.Length > 0 && "noflush".Equals(args[0])) db.SetProperty("perst.file.noflush", true); db.Open("testr2.dbs"); TestR2 root = (TestR2) db.GetRoot(); if (root == null) { root = new TestR2(); root.index = db.CreateSpatialIndexR2(); db.SetRoot(root); } RectangleR2[] rectangles = new RectangleR2[nObjectsInTree]; long key = 1999; for (int i = 0; i < nIterations; i++) { int j = i % nObjectsInTree; if (i >= nObjectsInTree) { RectangleR2 r = rectangles[j]; IPersistent[] sos = root.index.Get(r); IPersistent po = null; int n = 0; for (int k = 0; k < sos.Length; k++) { SpatialObject so = (SpatialObject) sos[k]; if (r.Equals(so.rect)) { po = so; } else { Assert.That(r.Intersects(so.rect)); } } Assert.That(po != null); for (int k = 0; k < nObjectsInTree; k++) { if (r.Intersects(rectangles[k])) { n += 1; } } Assert.That(n == sos.Length); System.Collections.IEnumerator iterator = root.index.GetEnumerator(r); for (int k = 0; iterator.MoveNext(); k++) { n -= 1; Assert.That(iterator.Current == sos[k]); } Assert.That(n == 0); root.index.Remove(r, po); po.Deallocate(); } key = (3141592621L * key + 2718281829L) % 1000000007L; int top = (int) (key % 1000); int left = (int) (key / 1000 % 1000); key = (3141592621L * key + 2718281829L) % 1000000007L; int bottom = top + (int) (key % 100); int right = left + (int) (key / 100 % 100); SpatialObject so2 = new SpatialObject(); RectangleR2 r2 = new RectangleR2(top, left, bottom, right); so2.rect = r2; rectangles[j] = r2; root.index.Put(r2, so2); if (i % 100 == 0) { Console.Out.Write("Iteration " + i + "\r"); Console.Out.Flush(); db.Commit(); } } root.index.Clear(); Console.Out.WriteLine("\nElapsed time " + ((DateTime.Now.Ticks - 621355968000000000) / 10000 - start)); db.Close(); }
internal RtreeR2Page SplitPage(Storage storage, RectangleR2 r, IPersistent obj) { int i, j, seed0 = 0, seed1 = 0; double[] rectArea = new double[card + 1]; double waste; //UPGRADE_TODO: The equivalent in .NET for field 'java.lang.Double.MIN_VALUE' may return a different value. double worstWaste = Double.MinValue; // // As the seeds for the two groups, find two rectangles which waste // the most area if covered by a single rectangle. // rectArea[0] = r.Area(); for (i = 0; i < card; i++) { rectArea[i + 1] = b[i].Area(); } RectangleR2 bp = r; for (i = 0; i < card; i++) { for (j = i + 1; j <= card; j++) { waste = RectangleR2.JoinArea(bp, b[j - 1]) - rectArea[i] - rectArea[j]; if (waste > worstWaste) { worstWaste = waste; seed0 = i; seed1 = j; } } bp = b[i]; } byte[] taken = new byte[card]; RectangleR2 group0, group1; double groupArea0, groupArea1; int groupCard0, groupCard1; RtreeR2Page pg; taken[seed1 - 1] = 2; group1 = new RectangleR2(b[seed1 - 1]); if (seed0 == 0) { group0 = new RectangleR2(r); pg = new RtreeR2Page(storage, obj, r); } else { group0 = new RectangleR2(b[seed0 - 1]); pg = new RtreeR2Page(storage, branch.GetRaw(seed0 - 1), group0); SetBranch(seed0 - 1, r, obj); } groupCard0 = groupCard1 = 1; groupArea0 = rectArea[seed0]; groupArea1 = rectArea[seed1]; // // Split remaining rectangles between two groups. // The one chosen is the one with the greatest difference in area // expansion depending on which group - the rect most strongly // attracted to one group and repelled from the other. // while (groupCard0 + groupCard1 < card + 1 && groupCard0 < card + 1 - minFill && groupCard1 < card + 1 - minFill) { int betterGroup = -1, chosen = -1; double biggestDiff = -1; for (i = 0; i < card; i++) { if (taken[i] == 0) { double diff = (RectangleR2.JoinArea(group0, b[i]) - groupArea0) - (RectangleR2.JoinArea(group1, b[i]) - groupArea1); if (diff > biggestDiff || -diff > biggestDiff) { chosen = i; if (diff < 0) { betterGroup = 0; biggestDiff = -diff; } else { betterGroup = 1; biggestDiff = diff; } } } } Assert.That(chosen >= 0); if (betterGroup == 0) { group0.Join(b[chosen]); groupArea0 = group0.Area(); taken[chosen] = 1; pg.SetBranch(groupCard0++, b[chosen], branch.GetRaw(chosen)); } else { groupCard1 += 1; group1.Join(b[chosen]); groupArea1 = group1.Area(); taken[chosen] = 2; } } // If one group gets too full, then remaining rectangle are // split between two groups in such way to balance cards of two groups. if (groupCard0 + groupCard1 < card + 1) { for (i = 0; i < card; i++) { if (taken[i] == 0) { if (groupCard0 >= groupCard1) { taken[i] = 2; groupCard1 += 1; } else { taken[i] = 1; pg.SetBranch(groupCard0++, b[i], branch.GetRaw(i)); } } } } pg.n = groupCard0; n = groupCard1; for (i = 0, j = 0; i < groupCard1; j++) { if (taken[j] == 2) { SetBranch(i++, b[j], branch.GetRaw(j)); } } return pg; }
internal void SetBranch(int i, RectangleR2 r, IPersistent obj) { b[i] = r; branch.Set(i, obj); }
internal virtual int Remove(RectangleR2 r, IPersistent obj, int level, ArrayList reinsertList) { if (--level != 0) { for (int i = 0; i < n; i++) { if (r.Intersects(b[i])) { RtreeR2Page pg = (RtreeR2Page) branch.Get(i); int reinsertLevel = pg.Remove(r, obj, level, reinsertList); if (reinsertLevel >= 0) { if (pg.n >= minFill) { SetBranch(i, pg.Cover(), pg); Modify(); } else { // not enough entries in child reinsertList.Add(pg); reinsertLevel = level - 1; RemoveBranch(i); } return reinsertLevel; } } } } else { for (int i = 0; i < n; i++) { if (branch.ContainsElement(i, obj)) { RemoveBranch(i); return 0; } } } return -1; }
internal virtual RtreeR2Page Insert(Storage storage, RectangleR2 r, IPersistent obj, int level) { Modify(); if (--level != 0) { // not leaf page int i, mini = 0; double minIncr = Double.MaxValue; double minArea = Double.MaxValue; for (i = 0; i < n; i++) { double area = b[i].Area(); double incr = RectangleR2.JoinArea(b[i], r) - area; if (incr < minIncr) { minIncr = incr; minArea = area; mini = i; } else if (incr == minIncr && area < minArea) { minArea = area; mini = i; } } RtreeR2Page p = (RtreeR2Page) branch.Get(mini); RtreeR2Page q = p.Insert(storage, r, obj, level); if (q == null) { // child was not split b[mini].Join(r); return null; } else { // child was split SetBranch(mini, p.Cover(), p); return AddBranch(storage, q.Cover(), q); } } else { return AddBranch(storage, new RectangleR2(r), obj); } }
/// <summary> Non destructive join of two rectangles. </summary> /// <param name="a">first joined rectangle /// </param> /// <param name="b">second joined rectangle /// </param> /// <returns> rectangle containing Cover of these two rectangles /// </returns> public static RectangleR2 Join(RectangleR2 a, RectangleR2 b) { RectangleR2 r = new RectangleR2(a); r.Join(b); return r; }
/// <summary> Join two rectangles. This rectangle is updates to contain Cover of this and specified rectangle.</summary> /// <param name="r">rectangle to be joined with this rectangle /// </param> public void Join(RectangleR2 r) { if (left > r.left) { left = r.left; } if (right < r.right) { right = r.right; } if (top > r.top) { top = r.top; } if (bottom < r.bottom) { bottom = r.bottom; } }
/// <summary> Checks if this rectangle intersects with specified rectangle</summary> public bool Intersects(RectangleR2 r) { return left <= r.right && top <= r.bottom && right >= r.left && bottom >= r.top; }
/// <summary> Checks if this rectangle contains the specified rectangle</summary> public bool Contains(RectangleR2 r) { return left <= r.left && top <= r.top && right >= r.right && bottom >= r.bottom; }
/// <summary> Area of covered rectangle for two sepcified rectangles</summary> public static double JoinArea(RectangleR2 a, RectangleR2 b) { double left = (a.left < b.left) ? a.left : b.left; double right = (a.right > b.right) ? a.right : b.right; double top = (a.top < b.top) ? a.top : b.top; double bottom = (a.bottom > b.bottom) ? a.bottom : b.bottom; return (bottom - top) * (right - left); }