asclass AbstractQuadTree extends WidthAndHeightImpl is Matrix { replace Node with O. sclass Composite > Node { Node a, b, c, d; void set(int idx, Node n) { if (idx == 0) a = n; if (idx == 1) b = n; if (idx == 2) c = n; if (idx == 3) d = n; } *(Node n) { a = b = c = d = n; } bool simplifiable() { ret allEq(a, b, c, d); } int compositeNodeCount() { ret 1+ _compositeNodeCount(a) + _compositeNodeCount(b) + _compositeNodeCount(c) + _compositeNodeCount(d); } } Node root = defaultValue(); *() {} *(int *width, int *height) {} int half(int x) { ret roundUpToPowerOfTwo((x+1)/2); } int halfX(Rect r) { ret r.x+half(r.w); } int halfY(Rect r) { ret r.y+half(r.h); } Rect rectA(Rect r) { ret rect(r.x, r.y, half(r.w), half(r.h)); } Rect rectB(Rect r) { ret rectFromPoints(r.x+half(r.w), r.y, r.x2(), halfY(r)); } Rect rectC(Rect r) { ret rectFromPoints(r.x, r.y+half(r.h), r.x+half(r.w), r.y2()); } Rect rectD(Rect r) { ret rectFromPoints(r.x+half(r.w), r.y+half(r.h), r.x2(), r.y2()); } public A get(int x, int y) { Node node = root; Rect r = rect(0, 0, width, height); while (node cast Composite) { int hx = halfX(r), hy = halfY(r); if (y < hy) if (x < hx) { node = node.a; r = rectA(r); } else { node = node.b; r = rectB(r); } else if (x < hx) { node = node.c; r = rectC(r); } else { node = node.d; r = rectD(r); } ifdef QuadTreeBitMatrix_debug printVars(+x, +y, +hx, +hy); endifdef } ret (A) node; } public void set(int x, int y, A value) { set(pointRect(x, y), value); } void set(Rect r, A value) { set(rootCursor(), r, value); } scaffolded void set(Cursor cursor, Rect r, A value) { // no intersection? exit if (!rectsIntersect(r, cursor.r)) ret; // fully contained? replace with primitive if (rectContains(r, cursor.r)) cursor.replace(value); else { // partial intersection - turn into composite cursor.turnIntoComposite(); for (Cursor c : cursor.subCursors()) set(c, r, value); } cursor.simplify(); } class Cursor { settable Composite parent; settable int indexInParent; settable Rect r; settable Node node; L subCursors() { if (node cast Composite) ret ll( subCursor(0, node.a, rectA(r)), subCursor(1, node.b, rectB(r)), subCursor(2, node.c, rectC(r)), subCursor(3, node.d, rectD(r))); ret emptyList(); } Cursor subCursor(int idx, Node n, Rect r) { ret new Cursor().r(r).node(n) .parent((Composite) node).indexInParent(idx); } scaffolded void turnIntoComposite { if (!node instanceof Composite) replace(new Composite(node)); } scaffolded void replace(Node n) { if (node == n) ret; node = n; if (parent == null) root = n; else parent.set(indexInParent, n); } // opposite of turnIntoComposite scaffolded void simplify { if (node cast Composite && node.simplifiable()) replace(node.a); } /*toString { ret stdToString(this); }*/ } Cursor rootCursor() { ret new Cursor().r(bounds()).node(root); } static int _compositeNodeCount(Node n) { if (n cast Composite) ret n.compositeNodeCount(); ret 0; } int compositeNodeCount() { ret _compositeNodeCount(root); } abstract A defaultValue(); }