Skip to content

Commit

Permalink
Optimize and simplify forceMinimize() visible area algorithm
Browse files Browse the repository at this point in the history
A diagram for understanding the algorithm (D on top, A on the bottom):

    ┌────────────────────────────────┐
    │                                │
    │    D                           │
    │           ┌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌├──────┐
    │           ┆                    │      │
    │      ┌╌╌╌╌┆--------------┐     │  C   │
    │      ┆    ┆              :     │      │
    │      ┆    ┆   ┌ - - - - -:-----│╌╌╌╌╌╌├────┐
    │      ┆    ┆   .          :     │      │    │
    │      ┆    ┆   .          :     │      │    │
    │      ┆    ┆   .    *     :     │      │    │
    │      ┆    ┆   .          :     │      │    │
    │      ┆    ┆   .          :     │      │    │
    │      ┆    └╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌╌├──────┘    │
    │      ┆        :          ┆     │           │
    │      ┆        :          ┆     │           │
    │      ┆        :          ┆     │           │
    └──────┬───────────────────┬─────┘           │
           │        ┆          │                 │
           │    B   ┆          │         A       │
           └────────┬──────────┘                 │
                    │                            │
                    └────────────────────────────┘

We want the visible area of A. Let's subtract B and C from A:
(I(A, B): the area of the intersection of A and B)

    Area(A) - I(A, B) - I(A, C)

However, B and C overlap, so there's an area which we've subtracted from
A twice (marked with a * in the diagram above.) So we add that back
again once:

    … + I(A, B, C)

Now let's subtract D, and add back the parts of D that overlap with
what we've already subtracted:

    … - I(A, D) + I(A, B, D) + I(A, C, D) - I(A, B, C, D)

So the complete sum is (for four rectangles):

      VisibleArea(A) =
      Area(A)
    - I(A, B)
    - I(A, C)
    - I(A, D)
    + I(A, B, C)
    + I(A, B, D)
    + I(A, C, D)
    - I(A, B, C, D)

More generally: we take every subset of the rectangles on top of A, and
add or subtract (depending on subset.length % 2) the intersection of
those rectangles and A.

This implementation exploits the fact that I(A, B, C) = I(I(A, B), C),
and passes the result of I(A, B) to the computation of I(A, B, C).
To see that this is useful, we reorder the sum above:

      VisibleArea(A) =
      Area(A)
    - I(A, B)
    + I(A, B, C)
    - I(A, B, C, D)
    + I(A, B, D)
    - I(A, C)
    + I(A, C, D)
    - I(A, D)
  • Loading branch information
twiss committed Sep 29, 2016
1 parent 986adab commit 5d1e854
Showing 1 changed file with 19 additions and 17 deletions.
36 changes: 19 additions & 17 deletions laskyawm.js
Original file line number Diff line number Diff line change
Expand Up @@ -577,24 +577,9 @@ function forceMinimize() {
};
}).reverse();

for(var i = 0, len = windows.length; i < len; i++) {
for(var i = windows.length; --i >= 0;) {
var win = windows[i];
for(var amount = 0, sign = 1, area = 0; amount <= i; amount++, sign *= -1) {
for(var b = 0; b < Math.pow(2, i); b++) {
if(b.toString(2).replace(/0/g, '').length === amount) {
var x1 = win.x1, y1 = win.y1, x2 = win.x2, y2 = win.y2;
for(var j = 0; j < len; j++) {
if(Math.pow(2, j) & b) {
if(windows[j].x1 > x1) x1 = windows[j].x1;
if(windows[j].y1 > y1) y1 = windows[j].y1;
if(windows[j].x2 < x2) x2 = windows[j].x2;
if(windows[j].y2 < y2) y2 = windows[j].y2;
}
}
area += sign * O(x1, y1, x2, y2);
}
}
}
var area = add(1, i, win.x1, win.y1, win.x2, win.y2, windows);
if(area === 0) {
win.div.classList.add('force-minimized');
win.div.classList.add('minimized');
Expand All @@ -607,6 +592,23 @@ function forceMinimize() {
positionMinimized();
}

function add(sign, i, _x1, _y1, _x2, _y2, windows) {
var area = sign * O(_x1, _y1, _x2, _y2);

for(var j = i; --j >= 0;) {
var x1 = _x1, y1 = _y1, x2 = _x2, y2 = _y2;

if(windows[j].x1 > x1) x1 = windows[j].x1;
if(windows[j].y1 > y1) y1 = windows[j].y1;
if(windows[j].x2 < x2) x2 = windows[j].x2;
if(windows[j].y2 < y2) y2 = windows[j].y2;

area += add(-sign, j, x1, y1, x2, y2, windows);
}

return area;
}

function O(x1, y1, x2, y2) {
return Math.max(0, x2 - x1) * Math.max(0, y2 - y1);
}
Expand Down

0 comments on commit 5d1e854

Please sign in to comment.