From ea21314de476888110daa82ed9738a7589092f73 Mon Sep 17 00:00:00 2001 From: sbosse Date: Mon, 21 Jul 2025 23:15:22 +0200 Subject: [PATCH] Mon 21 Jul 22:43:21 CEST 2025 --- js/rtree/rectangle.js | 199 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 199 insertions(+) create mode 100644 js/rtree/rectangle.js diff --git a/js/rtree/rectangle.js b/js/rtree/rectangle.js new file mode 100644 index 0000000..e52ab77 --- /dev/null +++ b/js/rtree/rectangle.js @@ -0,0 +1,199 @@ +'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; \ No newline at end of file