From 5d1e854205cb5ce6e32a05ec3914b1b3aeeec8de Mon Sep 17 00:00:00 2001 From: Daniel Huigens Date: Thu, 29 Sep 2016 20:54:38 +0200 Subject: [PATCH] Optimize and simplify forceMinimize() visible area algorithm MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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) --- laskyawm.js | 36 +++++++++++++++++++----------------- 1 file changed, 19 insertions(+), 17 deletions(-) diff --git a/laskyawm.js b/laskyawm.js index f37dc52..8c54bda 100644 --- a/laskyawm.js +++ b/laskyawm.js @@ -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'); @@ -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); }