From 9dd4dc373093c6ad14186243b1786fa9db5e19d7 Mon Sep 17 00:00:00 2001 From: ahocevar Date: Mon, 20 May 2013 08:50:15 +0200 Subject: [PATCH] Better optimization for advanced compilation mode --- src/ol/structs/rtree.js | 151 ++++++++++++++++++++-------------------- 1 file changed, 74 insertions(+), 77 deletions(-) diff --git a/src/ol/structs/rtree.js b/src/ol/structs/rtree.js index 1ad8a6c0cc..7359870c49 100644 --- a/src/ol/structs/rtree.js +++ b/src/ol/structs/rtree.js @@ -35,9 +35,9 @@ goog.require('goog.object'); /** * @typedef {{x: (number), y: (number), w: (number), h: (number), - * 'leaf': (Object|undefined), - * 'nodes': (Array.|undefined), - * 'target': (Object|undefined), type: (string|undefined)}} + * leaf: (Object|undefined), + * nodes: (Array.|undefined), + * target: (Object|undefined), type: (string|undefined)}} */ ol.structs.RTreeNode; @@ -57,7 +57,7 @@ ol.structs.RTree = function(opt_width) { } // Start with an empty root-tree var tree = /** @type {ol.structs.RTreeNode} */ - ({x: 0, y: 0, w: 0, h: 0, 'nodes': []}); + ({x: 0, y: 0, w: 0, h: 0, nodes: []}); // This is my special addition to the world of r-trees // every other (simple) method I found produced crap trees @@ -92,84 +92,82 @@ ol.structs.RTree = function(opt_width) { } var workingObject = /** @type {ol.structs.RTreeNode} */ ({ - x: rect.x, y: rect.y, w: rect.w, h: rect.h, 'target': obj + x: rect.x, y: rect.y, w: rect.w, h: rect.h, target: obj }); - countStack.push(root['nodes'].length); + countStack.push(root.nodes.length); hitStack.push(root); do { var tree = hitStack.pop(); var i = countStack.pop() - 1; - if (goog.object.containsKey(workingObject, 'target')) { + if (goog.isDef(workingObject.target)) { // We are searching for a target while (i >= 0) { - var lTree = tree['nodes'][i]; + var lTree = tree.nodes[i]; if (ol.structs.RTreeRectangle.overlapRectangle( workingObject, lTree)) { - if ((workingObject['target'] && - goog.object.containsKey(lTree, 'leaf') && - lTree['leaf'] === workingObject['target']) || - (!workingObject['target'] && - (goog.object.containsKey(lTree, 'leaf') || + if ((workingObject.target && goog.isDef(lTree.leaf) && + lTree.leaf === workingObject.target) || + (!workingObject.target && (goog.isDef(lTree.leaf) || ol.structs.RTreeRectangle.containsRectangle( lTree, workingObject)))) { // A Match !! // Yup we found a match... // we can cancel search and start walking up the list - if (goog.object.containsKey(lTree, 'nodes')) { + if (goog.isDef(lTree.nodes)) { // If we are deleting a node not a leaf... returnArray = searchSubtree(lTree, true, [], lTree); - tree['nodes'].splice(i, 1); + tree.nodes.splice(i, 1); } else { - returnArray = tree['nodes'].splice(i, 1); + returnArray = tree.nodes.splice(i, 1); } // Resize MBR down... - ol.structs.RTreeRectangle.makeMBR(tree['nodes'], tree); - delete workingObject['target']; - if (tree['nodes'].length < minWidth) { // Underflow - workingObject['nodes'] = /** @type {Array} */ + ol.structs.RTreeRectangle.makeMBR(tree.nodes, tree); + workingObject.target = undefined; + if (tree.nodes.length < minWidth) { // Underflow + workingObject.nodes = /** @type {Array} */ (searchSubtree(tree, true, [], tree)); } break; - } else if (goog.object.containsKey(lTree, 'nodes')) { + } else if (goog.isDef(lTree.nodes)) { // Not a Leaf currentDepth += 1; countStack.push(i); hitStack.push(tree); tree = lTree; - i = lTree['nodes'].length; + i = lTree.nodes.length; } } i -= 1; } - } else if (goog.object.containsKey(workingObject, 'nodes')) { + } else if (goog.isDef(workingObject.nodes)) { // We are unsplitting - tree['nodes'].splice(i + 1, 1); // Remove unsplit node + tree.nodes.splice(i + 1, 1); // Remove unsplit node // workingObject.nodes contains a list of elements removed from the // tree so far - if (tree['nodes'].length > 0) - ol.structs.RTreeRectangle.makeMBR(tree['nodes'], tree); - for (var t = 0, tt = workingObject['nodes'].length; t < tt; ++t) - insertSubtree(workingObject['nodes'][t], tree); - workingObject['nodes'].length = 0; - if (hitStack.length == 0 && tree['nodes'].length <= 1) { + if (tree.nodes.length > 0) + ol.structs.RTreeRectangle.makeMBR(tree.nodes, tree); + for (var t = 0, tt = workingObject.nodes.length; t < tt; ++t) + insertSubtree(workingObject.nodes[t], tree); + workingObject.nodes.length = 0; + if (hitStack.length == 0 && tree.nodes.length <= 1) { // Underflow..on root! - workingObject['nodes'] = /** @type {Array} */ - (searchSubtree(tree, true, workingObject['nodes'], tree)); - tree['nodes'].length = 0; + workingObject.nodes = /** @type {Array} */ + (searchSubtree(tree, true, workingObject.nodes, tree)); + tree.nodes.length = 0; hitStack.push(tree); countStack.push(1); - } else if (hitStack.length > 0 && tree['nodes'].length < minWidth) { + } else if (hitStack.length > 0 && tree.nodes.length < minWidth) { // Underflow..AGAIN! - workingObject['nodes'] = /** @type {Array} */ - (searchSubtree(tree, true, workingObject['nodes'], tree)); - tree['nodes'].length = 0; + workingObject.nodes = /** @type {Array} */ + (searchSubtree(tree, true, workingObject.nodes, tree)); + tree.nodes.length = 0; } else { - delete workingObject['nodes']; // Just start resizing + workingObject.nodes = undefined; // Just start resizing } } else { // we are just resizing - ol.structs.RTreeRectangle.makeMBR(tree['nodes'], tree); + ol.structs.RTreeRectangle.makeMBR(tree.nodes, tree); } currentDepth -= 1; } while (hitStack.length > 0); @@ -190,25 +188,25 @@ ol.structs.RTree = function(opt_width) { var bestChoiceArea; bestChoiceStack.push(root); - var nodes = root['nodes']; + var nodes = root.nodes; do { if (bestChoiceIndex != -1) { bestChoiceStack.push(nodes[bestChoiceIndex]); - nodes = nodes[bestChoiceIndex]['nodes']; + nodes = nodes[bestChoiceIndex].nodes; bestChoiceIndex = -1; } for (var i = nodes.length - 1; i >= 0; --i) { var lTree = nodes[i]; - if (goog.object.containsKey(lTree, 'leaf')) { + if (goog.isDef(lTree.leaf)) { // Bail out of everything and start inserting bestChoiceIndex = -1; break; } // Area of new enlarged rectangle var oldLRatio = squarifiedRatio(lTree.w, lTree.h, - lTree['nodes'].length + 1); + lTree.nodes.length + 1); // Enlarge rectangle to fit new rectangle var nw = Math.max(lTree.x + lTree.w, rect.x + rect.w) - @@ -217,7 +215,7 @@ ol.structs.RTree = function(opt_width) { Math.min(lTree.y, rect.y); // Area of new enlarged rectangle - var lRatio = squarifiedRatio(nw, nh, lTree['nodes'].length + 2); + var lRatio = squarifiedRatio(nw, nh, lTree.nodes.length + 2); if (bestChoiceIndex < 0 || Math.abs(lRatio - oldLRatio) < bestChoiceArea) { @@ -249,8 +247,8 @@ ol.structs.RTree = function(opt_width) { */ var pickNext = function(nodes, a, b) { // Area of new enlarged rectangle - var areaA = squarifiedRatio(a.w, a.h, a['nodes'].length + 1); - var areaB = squarifiedRatio(b.w, b.h, b['nodes'].length + 1); + var areaA = squarifiedRatio(a.w, a.h, a.nodes.length + 1); + var areaB = squarifiedRatio(b.w, b.h, b.nodes.length + 1); var highAreaDelta; var highAreaNode; var lowestGrowthGroup; @@ -263,7 +261,7 @@ ol.structs.RTree = function(opt_width) { newAreaA.w = Math.max(a.x + a.w, l.x + l.w) - newAreaA.x; newAreaA.h = Math.max(a.y + a.h, l.y + l.h) - newAreaA.y; var changeNewAreaA = Math.abs(squarifiedRatio(newAreaA.w, newAreaA.h, - a['nodes'].length + 2) - areaA); + a.nodes.length + 2) - areaA); var newAreaB = {}; newAreaB.x = Math.min(b.x, l.x); @@ -271,7 +269,7 @@ ol.structs.RTree = function(opt_width) { newAreaB.w = Math.max(b.x + b.w, l.x + l.w) - newAreaB.x; newAreaB.h = Math.max(b.y + b.h, l.y + l.h) - newAreaB.y; var changeNewAreaB = Math.abs(squarifiedRatio( - newAreaB.w, newAreaB.h, b['nodes'].length + 2) - areaB); + newAreaB.w, newAreaB.h, b.nodes.length + 2) - areaB); if (!highAreaNode || !highAreaDelta || Math.abs(changeNewAreaB - changeNewAreaA) < highAreaDelta) { @@ -281,15 +279,15 @@ ol.structs.RTree = function(opt_width) { } } var tempNode = nodes.splice(highAreaNode, 1)[0]; - if (a['nodes'].length + nodes.length + 1 <= minWidth) { - a['nodes'].push(tempNode); + if (a.nodes.length + nodes.length + 1 <= minWidth) { + a.nodes.push(tempNode); ol.structs.RTreeRectangle.expandRectangle(a, tempNode); - } else if (b['nodes'].length + nodes.length + 1 <= minWidth) { - b['nodes'].push(tempNode); + } else if (b.nodes.length + nodes.length + 1 <= minWidth) { + b.nodes.push(tempNode); ol.structs.RTreeRectangle.expandRectangle(b, tempNode); } else { - lowestGrowthGroup['nodes'].push(tempNode); + lowestGrowthGroup.nodes.push(tempNode); ol.structs.RTreeRectangle.expandRectangle(lowestGrowthGroup, tempNode); } }; @@ -342,14 +340,14 @@ ol.structs.RTree = function(opt_width) { } return [ /** @type {ol.structs.RTreeNode} */ - ({x: t1.x, y: t1.y, w: t1.w, h: t1.h, 'nodes': [t1]}), + ({x: t1.x, y: t1.y, w: t1.w, h: t1.h, nodes: [t1]}), /** @type {ol.structs.RTreeNode} */ - ({x: t2.x, y: t2.y, w: t2.w, h: t2.h, 'nodes': [t2]}) + ({x: t2.x, y: t2.y, w: t2.w, h: t2.h, nodes: [t2]}) ]; }; var attachData = function(node, moreTree) { - node['nodes'] = moreTree['nodes']; + node.nodes = moreTree.nodes; node.x = moreTree.x; node.y = moreTree.y; node.w = moreTree.w; node.h = moreTree.h; return node; @@ -372,7 +370,7 @@ ol.structs.RTree = function(opt_width) { return result; } - hitStack.push(root['nodes']); + hitStack.push(root.nodes); do { var nodes = hitStack.pop(); @@ -380,14 +378,14 @@ ol.structs.RTree = function(opt_width) { for (var i = nodes.length - 1; i >= 0; --i) { var lTree = nodes[i]; if (ol.structs.RTreeRectangle.overlapRectangle(rect, lTree)) { - if (goog.object.containsKey(lTree, 'nodes')) { // Not a Leaf - hitStack.push(lTree['nodes']); - } else if (goog.object.containsKey(lTree, 'leaf')) { // A Leaf !! + if (goog.isDef(lTree.nodes)) { // Not a Leaf + hitStack.push(lTree.nodes); + } else if (goog.isDef(lTree.leaf)) { // A Leaf !! if (!returnNode) { // TODO keep track of type on all nodes so we don't have to // walk all the way in to the leaf to know that we don't need it if (!goog.isDef(opt_type) || lTree.type == opt_type) { - var obj = lTree['leaf']; + var obj = lTree.leaf; result[goog.getUid(obj).toString()] = obj; } } else { @@ -409,12 +407,12 @@ ol.structs.RTree = function(opt_width) { var bc; // Best Current node // Initial insertion is special because we resize the Tree and we don't // care about any overflow (seriously, how can the first object overflow?) - if (root['nodes'].length == 0) { + if (root.nodes.length == 0) { root.x = node.x; root.y = node.y; root.w = node.w; root.h = node.h; - root['nodes'].push(node); + root.nodes.push(node); return; } @@ -427,13 +425,12 @@ ol.structs.RTree = function(opt_width) { // Walk back up the tree resizing and inserting as needed do { //handle the case of an empty node (from a split) - if (bc && goog.object.containsKey(bc, 'nodes') && - bc['nodes'].length == 0) { + if (bc && goog.isDef(bc.nodes) && bc.nodes.length == 0) { var pbc = bc; // Past bc bc = treeStack.pop(); - for (var t = 0, tt = bc['nodes'].length; t < tt; ++t) { - if (bc['nodes'][t] === pbc || bc['nodes'][t]['nodes'].length == 0) { - bc['nodes'].splice(t, 1); + for (var t = 0, tt = bc.nodes.length; t < tt; ++t) { + if (bc.nodes[t] === pbc || bc.nodes[t].nodes.length == 0) { + bc.nodes.splice(t, 1); break; } } @@ -443,30 +440,30 @@ ol.structs.RTree = function(opt_width) { // If there is data attached to this workingObject var isArray = goog.isArray(workingObject); - if (goog.object.containsKey(workingObject, 'leaf') || - goog.object.containsKey(workingObject, 'nodes') || isArray) { + if (goog.isDef(workingObject.leaf) || + goog.isDef(workingObject.nodes) || isArray) { // Do Insert if (isArray) { for (var ai = 0, aii = workingObject.length; ai < aii; ++ai) { ol.structs.RTreeRectangle.expandRectangle(bc, workingObject[ai]); } - bc['nodes'] = bc['nodes'].concat(workingObject); + bc.nodes = bc.nodes.concat(workingObject); } else { ol.structs.RTreeRectangle.expandRectangle(bc, workingObject); - bc['nodes'].push(workingObject); // Do Insert + bc.nodes.push(workingObject); // Do Insert } - if (bc['nodes'].length <= maxWidth) { // Start Resizeing Up the Tree + if (bc.nodes.length <= maxWidth) { // Start Resizeing Up the Tree workingObject = /** @type {ol.structs.RTreeNode} */ ({x: bc.x, y: bc.y, w: bc.w, h: bc.h}); } else { // Otherwise Split this Node // linearSplit() returns an array containing two new nodes // formed from the split of the previous node's overflow - var a = linearSplit(bc['nodes']); + var a = linearSplit(bc.nodes); workingObject = a;//[1]; if (treeStack.length < 1) { // If are splitting the root.. - bc['nodes'].push(a[0]); + bc.nodes.push(a[0]); treeStack.push(bc); // Reconsider the root element workingObject = a[1]; } @@ -513,7 +510,7 @@ ol.structs.RTree = function(opt_width) { default: arguments.length = 3; } - if (arguments[1] === false) { // Do area-wide delete + if (arguments[1] === false) { // Do area-wide † var numberDeleted = 0; var result = []; do { @@ -537,7 +534,7 @@ ol.structs.RTree = function(opt_width) { var node = /** @type {ol.structs.RTreeNode} */ ({ x: extent[0], y: extent[2], w: extent[1] - extent[0], h: extent[3] - extent[2], - 'leaf': obj + leaf: obj }); if (goog.isDef(opt_type)) { node.type = opt_type;