'use strict'; function Rectangle(x, y, w, h) { // new Rectangle(bounds) or new Rectangle(x, y, w, h) if (!(this instanceof Rectangle)) { return new Rectangle(x, y, w, h); } var x2, y2, p; if (x.x) { w = x.w; h = x.h; y = x.y; if (x.w !== 0 && !x.w && x.x2) { w = x.x2 - x.x; h = x.y2 - x.y; } else { w = x.w; h = x.h; } x = x.x; // For extra fastitude x2 = x + w; y2 = y + h; p = (h + w) ? false : true; } else { // For extra fastitude x2 = x + w; y2 = y + h; p = (h + w) ? false : true; } this.x1 = this.x = function () { return x; }; this.y1 = this.y = function () { return y; }; this.x2 = function () { return x2; }; this.y2 = function () { return y2; }; this.w = function () { return w; }; this.h = function () { return h; }; this.p = function () { return p; }; this.overlap = function (a) { if (p || a.p()) { return x <= a.x2() && x2 >= a.x() && y <= a.y2() && y2 >= a.y(); } return x < a.x2() && x2 > a.x() && y < a.y2() && y2 > a.y(); }; this.expand = function (a) { var nx, ny; var ax = a.x(); var ay = a.y(); var ax2 = a.x2(); var ay2 = a.y2(); if (x > ax) { nx = ax; } else { nx = x; } if (y > ay) { ny = ay; } else { ny = y; } if (x2 > ax2) { w = x2 - nx; } else { w = ax2 - nx; } if (y2 > ay2) { h = y2 - ny; } else { h = ay2 - ny; } x = nx; y = ny; return this; }; //End of RTree.Rectangle } /* returns true if rectangle 1 overlaps rectangle 2 * [ boolean ] = overlapRectangle(rectangle a, rectangle b) * @static function */ Rectangle.overlapRectangle = function (a, b) { //if(!((a.h||a.w)&&(b.h||b.w))){ not faster resist the urge! if ((a.h === 0 && a.w === 0) || (b.h === 0 && b.w === 0)) { return a.x <= (b.x + b.w) && (a.x + a.w) >= b.x && a.y <= (b.y + b.h) && (a.y + a.h) >= b.y; } else { return a.x < (b.x + b.w) && (a.x + a.w) > b.x && a.y < (b.y + b.h) && (a.y + a.h) > b.y; } }; /* returns true if rectangle a is contained in rectangle b * [ boolean ] = containsRectangle(rectangle a, rectangle b) * @static function */ Rectangle.containsRectangle = function (a, b) { return (a.x + a.w) <= (b.x + b.w) && a.x >= b.x && (a.y + a.h) <= (b.y + b.h) && a.y >= b.y; }; /* expands rectangle A to include rectangle B, rectangle B is untouched * [ rectangle a ] = expandRectangle(rectangle a, rectangle b) * @static function */ Rectangle.expandRectangle = function (a, b) { var nx, ny; var axw = a.x + a.w; var bxw = b.x + b.w; var ayh = a.y + a.h; var byh = b.y + b.h; if (a.x > b.x) { nx = b.x; } else { nx = a.x; } if (a.y > b.y) { ny = b.y; } else { ny = a.y; } if (axw > bxw) { a.w = axw - nx; } else { a.w = bxw - nx; } if (ayh > byh) { a.h = ayh - ny; } else { a.h = byh - ny; } a.x = nx; a.y = ny; return a; }; /* generates a minimally bounding rectangle for all rectangles in * array 'nodes'. If rect is set, it is modified into the MBR. Otherwise, * a new rectangle is generated and returned. * [ rectangle a ] = makeMBR(rectangle array nodes, rectangle rect) * @static function */ Rectangle.makeMBR = function (nodes, rect) { if (!nodes.length) { return { x: 0, y: 0, w: 0, h: 0 }; } rect = rect || {}; rect.x = nodes[0].x; rect.y = nodes[0].y; rect.w = nodes[0].w; rect.h = nodes[0].h; for (var i = 1, len = nodes.length; i < len; i++) { Rectangle.expandRectangle(rect, nodes[i]); } return rect; }; Rectangle.squarifiedRatio = function (l, w, fill) { // Area of new enlarged rectangle var lperi = (l + w) / 2.0; // Average size of a side of the new rectangle var larea = l * w; // Area of new rectangle // return the ratio of the perimeter to the area - the closer to 1 we are, // the more 'square' a rectangle is. conversly, when approaching zero the // more elongated a rectangle is var lgeo = larea / (lperi * lperi); return larea * fill / lgeo; }; module.exports = Rectangle;