From d7a753ed0fd98ada8658b57dbfda3aee16767e5e Mon Sep 17 00:00:00 2001 From: alexbol_qbiq Date: Sun, 29 Sep 2024 11:12:31 +0300 Subject: [PATCH] Fix Shape & Multiline intersection #194 --- dist/main.cjs | 184 +++++++++++++++++++---------------------------- dist/main.mjs | 184 +++++++++++++++++++---------------------------- dist/main.umd.js | 184 +++++++++++++++++++---------------------------- package.json | 2 +- 4 files changed, 220 insertions(+), 334 deletions(-) diff --git a/dist/main.cjs b/dist/main.cjs index c3ace59..9ed46e1 100644 --- a/dist/main.cjs +++ b/dist/main.cjs @@ -1070,7 +1070,7 @@ function intersectShape2Shape(shape1, shape2) { function intersectShape2Multiline(shape, multiline) { let ip = []; for (let edge of multiline) { - ip = [...ip, ...intersectShape2Shape(edge, edge.shape)]; + ip = [...ip, ...intersectShape2Shape(shape, edge.shape)]; } return ip; } @@ -3359,7 +3359,7 @@ Flatten.matrix = matrix; /** * Interval is a pair of numbers or a pair of any comparable objects on which may be defined predicates * *equal*, *less* and method *max(p1, p1)* that returns maximum in a pair. - * When interval is an object rather than a pair of numbers, this object should have properties *low*, *high*, *max* + * When interval is an object rather than pair of numbers, this object should have properties *low*, *high*, *max* * and implement methods *less_than(), equal_to(), intersect(), not_intersect(), clone(), output()*. * Two static methods *comparable_max(), comparable_less_than()* define how to compare values in pair.
* This interface is described in typescript definition file *index.d.ts* @@ -3405,7 +3405,7 @@ const Interval = class Interval { */ less_than(other_interval) { return this.low < other_interval.low || - this.low === other_interval.low && this.high < other_interval.high; + this.low == other_interval.low && this.high < other_interval.high; } /** @@ -3414,7 +3414,7 @@ const Interval = class Interval { * @returns {boolean} */ equal_to(other_interval) { - return this.low === other_interval.low && this.high === other_interval.high; + return this.low == other_interval.low && this.high == other_interval.high; } /** @@ -3437,15 +3437,13 @@ const Interval = class Interval { /** * Returns new interval merged with other interval - * @param {Interval} other_interval - Other interval to merge with + * @param {Interval} interval - Other interval to merge with * @returns {Interval} */ merge(other_interval) { return new Interval( - this.low === undefined ? - other_interval.low : (this.low < other_interval.low ? this.low : other_interval.low), - this.high === undefined ? - other_interval.high : (this.high > other_interval.high ? this.high : other_interval.high) + this.low === undefined ? other_interval.low : Math.min(this.low, other_interval.low), + this.high === undefined ? other_interval.high : Math.max(this.high, other_interval.high) ); } @@ -3506,11 +3504,9 @@ class Node { this.item = {key: key, value: value}; // key is supposed to be instance of Interval /* If not, this should by an array of two numbers */ - if (key && key instanceof Array && key.length === 2) { + if (key && key instanceof Array && key.length == 2) { if (!Number.isNaN(key[0]) && !Number.isNaN(key[1])) { - let [low, high] = key; - if (low > high) [low, high] = [high, low]; - this.item.key = new Interval(low, high); + this.item.key = new Interval(Math.min(key[0], key[1]), Math.max(key[0], key[1])); } } @@ -3542,7 +3538,7 @@ class Node { _value_equal(other_node) { return this.item.value && other_node.item.value && this.item.value.equal_to ? this.item.value.equal_to(other_node.item.value) : - this.item.value === other_node.item.value; + this.item.value == other_node.item.value; } equal_to(other_node) { // if tree stores only keys @@ -3662,7 +3658,7 @@ class IntervalTree { * @returns {boolean} */ isEmpty() { - return (this.root == null || this.root === this.nil_node); + return (this.root == null || this.root == this.nil_node); } /** @@ -3694,7 +3690,7 @@ class IntervalTree { */ exist(key, value = key) { let search_node = new Node(key, value); - return !!this.tree_search(this.root, search_node); + return this.tree_search(this.root, search_node) ? true : false; } /** @@ -3733,7 +3729,8 @@ class IntervalTree { */ intersect_any(interval) { let search_node = new Node(interval); - return this.tree_find_any_interval(this.root, search_node); + let found = this.tree_find_any_interval(this.root, search_node); + return found; } /** @@ -3745,34 +3742,15 @@ class IntervalTree { this.tree_walk(this.root, (node) => visitor(node.item.key, node.item.value)); } - /** - * Value Mapper. Walk through every node and map node value to another value - * @param callback(value,key) - function to be called for each tree item - */ + /** Value Mapper. Walk through every node and map node value to another value + * @param callback(value,key) - function to be called for each tree item + */ map(callback) { const tree = new IntervalTree(); this.tree_walk(this.root, (node) => tree.insert(node.item.key, callback(node.item.value, node.item.key))); return tree; } - /** - * @param {Interval} interval - optional if the iterator is intended to start from the beginning - * @param outputMapperFn(value,key) - optional function that maps (value, key) to custom output - * @returns {Iterator} - */ - *iterate(interval, outputMapperFn = (value, key) => value === key ? key.output() : value) { - let node; - if (interval) { - node = this.tree_search_nearest_forward(this.root, new Node(interval)); - } else if (this.root) { - node = this.local_minimum(this.root); - } - while (node) { - yield outputMapperFn(node.item.value, node.item.key); - node = this.tree_successor(node); - } - } - recalc_max(node) { let node_current = node; while (node_current.parent != null) { @@ -3785,11 +3763,11 @@ class IntervalTree { let current_node = this.root; let parent_node = null; - if (this.root == null || this.root === this.nil_node) { + if (this.root == null || this.root == this.nil_node) { this.root = insert_node; } else { - while (current_node !== this.nil_node) { + while (current_node != this.nil_node) { parent_node = current_node; if (insert_node.less_than(current_node)) { current_node = current_node.left; @@ -3819,10 +3797,10 @@ class IntervalTree { let uncle_node; current_node = insert_node; - while (current_node !== this.root && current_node.parent.color === RB_TREE_COLOR_RED) { - if (current_node.parent === current_node.parent.parent.left) { // parent is left child of grandfather + while (current_node != this.root && current_node.parent.color == RB_TREE_COLOR_RED) { + if (current_node.parent == current_node.parent.parent.left) { // parent is left child of grandfather uncle_node = current_node.parent.parent.right; // right brother of parent - if (uncle_node.color === RB_TREE_COLOR_RED) { // Case 1. Uncle is red + if (uncle_node.color == RB_TREE_COLOR_RED) { // Case 1. Uncle is red // re-color father and uncle into black current_node.parent.color = RB_TREE_COLOR_BLACK; uncle_node.color = RB_TREE_COLOR_BLACK; @@ -3830,7 +3808,7 @@ class IntervalTree { current_node = current_node.parent.parent; } else { // Case 2 & 3. Uncle is black - if (current_node === current_node.parent.right) { // Case 2. Current if right child + if (current_node == current_node.parent.right) { // Case 2. Current if right child // This case is transformed into Case 3. current_node = current_node.parent; this.rotate_left(current_node); @@ -3843,7 +3821,7 @@ class IntervalTree { } else { // parent is right child of grandfather uncle_node = current_node.parent.parent.left; // left brother of parent - if (uncle_node.color === RB_TREE_COLOR_RED) { // Case 4. Uncle is red + if (uncle_node.color == RB_TREE_COLOR_RED) { // Case 4. Uncle is red // re-color father and uncle into black current_node.parent.color = RB_TREE_COLOR_BLACK; uncle_node.color = RB_TREE_COLOR_BLACK; @@ -3851,7 +3829,7 @@ class IntervalTree { current_node = current_node.parent.parent; } else { - if (current_node === current_node.parent.left) { // Case 5. Current is left child + if (current_node == current_node.parent.left) { // Case 5. Current is left child // Transform into case 6 current_node = current_node.parent; this.rotate_right(current_node); @@ -3871,7 +3849,7 @@ class IntervalTree { let cut_node; // node to be cut - either delete_node or successor_node ("y" from 14.4) let fix_node; // node to fix rb tree property ("x" from 14.4) - if (delete_node.left === this.nil_node || delete_node.right === this.nil_node) { // delete_node has less then 2 children + if (delete_node.left == this.nil_node || delete_node.right == this.nil_node) { // delete_node has less then 2 children cut_node = delete_node; } else { // delete_node has 2 children @@ -3879,7 +3857,7 @@ class IntervalTree { } // fix_node if single child of cut_node - if (cut_node.left !== this.nil_node) { + if (cut_node.left != this.nil_node) { fix_node = cut_node.left; } else { @@ -3891,11 +3869,11 @@ class IntervalTree { fix_node.parent = cut_node.parent; /*}*/ - if (cut_node === this.root) { + if (cut_node == this.root) { this.root = fix_node; } else { - if (cut_node === cut_node.parent.left) { + if (cut_node == cut_node.parent.left) { cut_node.parent.left = fix_node; } else { @@ -3909,13 +3887,13 @@ class IntervalTree { // COPY DATA !!! // Delete_node becomes cut_node, it means that we cannot hold reference // to node in outer structure and we will have to delete by key, additional search need - if (cut_node !== delete_node) { + if (cut_node != delete_node) { delete_node.copy_data(cut_node); delete_node.update_max(); // update max property of the cut node at the new place this.recalc_max(delete_node); // update max property upward from delete_node to root } - if (/*fix_node != this.nil_node && */cut_node.color === RB_TREE_COLOR_BLACK) { + if (/*fix_node != this.nil_node && */cut_node.color == RB_TREE_COLOR_BLACK) { this.delete_fixup(fix_node); } } @@ -3924,23 +3902,23 @@ class IntervalTree { let current_node = fix_node; let brother_node; - while (current_node !== this.root && current_node.parent != null && current_node.color === RB_TREE_COLOR_BLACK) { - if (current_node === current_node.parent.left) { // fix node is left child + while (current_node != this.root && current_node.parent != null && current_node.color == RB_TREE_COLOR_BLACK) { + if (current_node == current_node.parent.left) { // fix node is left child brother_node = current_node.parent.right; - if (brother_node.color === RB_TREE_COLOR_RED) { // Case 1. Brother is red + if (brother_node.color == RB_TREE_COLOR_RED) { // Case 1. Brother is red brother_node.color = RB_TREE_COLOR_BLACK; // re-color brother current_node.parent.color = RB_TREE_COLOR_RED; // re-color father this.rotate_left(current_node.parent); brother_node = current_node.parent.right; // update brother } // Derive to cases 2..4: brother is black - if (brother_node.left.color === RB_TREE_COLOR_BLACK && - brother_node.right.color === RB_TREE_COLOR_BLACK) { // case 2: both nephews black + if (brother_node.left.color == RB_TREE_COLOR_BLACK && + brother_node.right.color == RB_TREE_COLOR_BLACK) { // case 2: both nephews black brother_node.color = RB_TREE_COLOR_RED; // re-color brother current_node = current_node.parent; // continue iteration } else { - if (brother_node.right.color === RB_TREE_COLOR_BLACK) { // case 3: left nephew red, right nephew black + if (brother_node.right.color == RB_TREE_COLOR_BLACK) { // case 3: left nephew red, right nephew black brother_node.color = RB_TREE_COLOR_RED; // re-color brother brother_node.left.color = RB_TREE_COLOR_BLACK; // re-color nephew this.rotate_right(brother_node); @@ -3957,20 +3935,20 @@ class IntervalTree { } else { // fix node is right child brother_node = current_node.parent.left; - if (brother_node.color === RB_TREE_COLOR_RED) { // Case 1. Brother is red + if (brother_node.color == RB_TREE_COLOR_RED) { // Case 1. Brother is red brother_node.color = RB_TREE_COLOR_BLACK; // re-color brother current_node.parent.color = RB_TREE_COLOR_RED; // re-color father this.rotate_right(current_node.parent); brother_node = current_node.parent.left; // update brother } // Go to cases 2..4 - if (brother_node.left.color === RB_TREE_COLOR_BLACK && - brother_node.right.color === RB_TREE_COLOR_BLACK) { // case 2 + if (brother_node.left.color == RB_TREE_COLOR_BLACK && + brother_node.right.color == RB_TREE_COLOR_BLACK) { // case 2 brother_node.color = RB_TREE_COLOR_RED; // re-color brother current_node = current_node.parent; // continue iteration } else { - if (brother_node.left.color === RB_TREE_COLOR_BLACK) { // case 3: right nephew red, left nephew black + if (brother_node.left.color == RB_TREE_COLOR_BLACK) { // case 3: right nephew red, left nephew black brother_node.color = RB_TREE_COLOR_RED; // re-color brother brother_node.right.color = RB_TREE_COLOR_BLACK; // re-color nephew this.rotate_left(brother_node); @@ -3991,7 +3969,7 @@ class IntervalTree { } tree_search(node, search_node) { - if (node == null || node === this.nil_node) + if (node == null || node == this.nil_node) return undefined; if (search_node.equal_to(node)) { @@ -4005,31 +3983,12 @@ class IntervalTree { } } - tree_search_nearest_forward(node, search_node) { - let best; - let curr = node; - while (curr && curr !== this.nil_node) { - if (curr.less_than(search_node)) { - if (curr.intersect(search_node)) { - best = curr; - curr = curr.left; - } else { - curr = curr.right; - } - } else { - if (!best || curr.less_than(best)) best = curr; - curr = curr.left; - } - } - return best || null; - } - // Original search_interval method; container res support push() insertion // Search all intervals intersecting given one tree_search_interval(node, search_node, res) { - if (node != null && node !== this.nil_node) { + if (node != null && node != this.nil_node) { // if (node->left != this.nil_node && node->left->max >= low) { - if (node.left !== this.nil_node && !node.not_intersect_left_subtree(search_node)) { + if (node.left != this.nil_node && !node.not_intersect_left_subtree(search_node)) { this.tree_search_interval(node.left, search_node, res); } // if (low <= node->high && node->low <= high) { @@ -4037,7 +3996,7 @@ class IntervalTree { res.push(node); } // if (node->right != this.nil_node && node->low <= high) { - if (node.right !== this.nil_node && !node.not_intersect_right_subtree(search_node)) { + if (node.right != this.nil_node && !node.not_intersect_right_subtree(search_node)) { this.tree_search_interval(node.right, search_node, res); } } @@ -4045,14 +4004,17 @@ class IntervalTree { tree_find_any_interval(node, search_node) { let found = false; - if (node != null && node !== this.nil_node) { - if (node.left !== this.nil_node && !node.not_intersect_left_subtree(search_node)) { + if (node != null && node != this.nil_node) { + // if (node->left != this.nil_node && node->left->max >= low) { + if (node.left != this.nil_node && !node.not_intersect_left_subtree(search_node)) { found = this.tree_find_any_interval(node.left, search_node); } + // if (low <= node->high && node->low <= high) { if (!found) { found = node.intersect(search_node); } - if (!found && node.right !== this.nil_node && !node.not_intersect_right_subtree(search_node)) { + // if (node->right != this.nil_node && node->low <= high) { + if (!found && node.right != this.nil_node && !node.not_intersect_right_subtree(search_node)) { found = this.tree_find_any_interval(node.right, search_node); } } @@ -4061,7 +4023,7 @@ class IntervalTree { local_minimum(node) { let node_min = node; - while (node_min.left != null && node_min.left !== this.nil_node) { + while (node_min.left != null && node_min.left != this.nil_node) { node_min = node_min.left; } return node_min; @@ -4070,7 +4032,7 @@ class IntervalTree { // not in use local_maximum(node) { let node_max = node; - while (node_max.right != null && node_max.right !== this.nil_node) { + while (node_max.right != null && node_max.right != this.nil_node) { node_max = node_max.right; } return node_max; @@ -4081,13 +4043,13 @@ class IntervalTree { let current_node; let parent_node; - if (node.right !== this.nil_node) { + if (node.right != this.nil_node) { node_successor = this.local_minimum(node.right); } else { current_node = node; parent_node = node.parent; - while (parent_node != null && parent_node.right === current_node) { + while (parent_node != null && parent_node.right == current_node) { current_node = parent_node; parent_node = parent_node.parent; } @@ -4108,16 +4070,16 @@ class IntervalTree { x.right = y.left; // b goes to x.right - if (y.left !== this.nil_node) { + if (y.left != this.nil_node) { y.left.parent = x; // x becomes parent of b } y.parent = x.parent; // move parent - if (x === this.root) { + if (x == this.root) { this.root = y; // y becomes root } else { // y becomes child of x.parent - if (x === x.parent.left) { + if (x == x.parent.left) { x.parent.left = y; } else { @@ -4127,12 +4089,12 @@ class IntervalTree { y.left = x; // x becomes left child of y x.parent = y; // and y becomes parent of x - if (x != null && x !== this.nil_node) { + if (x != null && x != this.nil_node) { x.update_max(); } y = x.parent; - if (y != null && y !== this.nil_node) { + if (y != null && y != this.nil_node) { y.update_max(); } } @@ -4142,16 +4104,16 @@ class IntervalTree { y.left = x.right; // b goes to y.left - if (x.right !== this.nil_node) { + if (x.right != this.nil_node) { x.right.parent = y; // y becomes parent of b } x.parent = y.parent; // move parent - if (y === this.root) { // x becomes root + if (y == this.root) { // x becomes root this.root = x; } else { // y becomes child of x.parent - if (y === y.parent.left) { + if (y == y.parent.left) { y.parent.left = x; } else { @@ -4161,18 +4123,18 @@ class IntervalTree { x.right = y; // y becomes right child of x y.parent = x; // and x becomes parent of y - if (y !== null && y !== this.nil_node) { + if (y != null && y != this.nil_node) { y.update_max(); } x = y.parent; - if (x != null && x !== this.nil_node) { + if (x != null && x != this.nil_node) { x.update_max(); } } tree_walk(node, action) { - if (node != null && node !== this.nil_node) { + if (node != null && node != this.nil_node) { this.tree_walk(node.left, action); // arr.push(node.toArray()); action(node); @@ -4184,8 +4146,8 @@ class IntervalTree { testRedBlackProperty() { let res = true; this.tree_walk(this.root, function (node) { - if (node.color === RB_TREE_COLOR_RED) { - if (!(node.left.color === RB_TREE_COLOR_BLACK && node.right.color === RB_TREE_COLOR_BLACK)) { + if (node.color == RB_TREE_COLOR_RED) { + if (!(node.left.color == RB_TREE_COLOR_BLACK && node.right.color == RB_TREE_COLOR_BLACK)) { res = false; } } @@ -4198,27 +4160,27 @@ class IntervalTree { let height = 0; let heightLeft = 0; let heightRight = 0; - if (node.color === RB_TREE_COLOR_BLACK) { + if (node.color == RB_TREE_COLOR_BLACK) { height++; } - if (node.left !== this.nil_node) { + if (node.left != this.nil_node) { heightLeft = this.testBlackHeightProperty(node.left); } else { heightLeft = 1; } - if (node.right !== this.nil_node) { + if (node.right != this.nil_node) { heightRight = this.testBlackHeightProperty(node.right); } else { heightRight = 1; } - if (heightLeft !== heightRight) { + if (heightLeft != heightRight) { throw new Error('Red-black height property violated'); } height += heightLeft; return height; - } + }; } /** diff --git a/dist/main.mjs b/dist/main.mjs index a57b25f..0d1bec8 100644 --- a/dist/main.mjs +++ b/dist/main.mjs @@ -1066,7 +1066,7 @@ function intersectShape2Shape(shape1, shape2) { function intersectShape2Multiline(shape, multiline) { let ip = []; for (let edge of multiline) { - ip = [...ip, ...intersectShape2Shape(edge, edge.shape)]; + ip = [...ip, ...intersectShape2Shape(shape, edge.shape)]; } return ip; } @@ -3355,7 +3355,7 @@ Flatten.matrix = matrix; /** * Interval is a pair of numbers or a pair of any comparable objects on which may be defined predicates * *equal*, *less* and method *max(p1, p1)* that returns maximum in a pair. - * When interval is an object rather than a pair of numbers, this object should have properties *low*, *high*, *max* + * When interval is an object rather than pair of numbers, this object should have properties *low*, *high*, *max* * and implement methods *less_than(), equal_to(), intersect(), not_intersect(), clone(), output()*. * Two static methods *comparable_max(), comparable_less_than()* define how to compare values in pair.
* This interface is described in typescript definition file *index.d.ts* @@ -3401,7 +3401,7 @@ const Interval = class Interval { */ less_than(other_interval) { return this.low < other_interval.low || - this.low === other_interval.low && this.high < other_interval.high; + this.low == other_interval.low && this.high < other_interval.high; } /** @@ -3410,7 +3410,7 @@ const Interval = class Interval { * @returns {boolean} */ equal_to(other_interval) { - return this.low === other_interval.low && this.high === other_interval.high; + return this.low == other_interval.low && this.high == other_interval.high; } /** @@ -3433,15 +3433,13 @@ const Interval = class Interval { /** * Returns new interval merged with other interval - * @param {Interval} other_interval - Other interval to merge with + * @param {Interval} interval - Other interval to merge with * @returns {Interval} */ merge(other_interval) { return new Interval( - this.low === undefined ? - other_interval.low : (this.low < other_interval.low ? this.low : other_interval.low), - this.high === undefined ? - other_interval.high : (this.high > other_interval.high ? this.high : other_interval.high) + this.low === undefined ? other_interval.low : Math.min(this.low, other_interval.low), + this.high === undefined ? other_interval.high : Math.max(this.high, other_interval.high) ); } @@ -3502,11 +3500,9 @@ class Node { this.item = {key: key, value: value}; // key is supposed to be instance of Interval /* If not, this should by an array of two numbers */ - if (key && key instanceof Array && key.length === 2) { + if (key && key instanceof Array && key.length == 2) { if (!Number.isNaN(key[0]) && !Number.isNaN(key[1])) { - let [low, high] = key; - if (low > high) [low, high] = [high, low]; - this.item.key = new Interval(low, high); + this.item.key = new Interval(Math.min(key[0], key[1]), Math.max(key[0], key[1])); } } @@ -3538,7 +3534,7 @@ class Node { _value_equal(other_node) { return this.item.value && other_node.item.value && this.item.value.equal_to ? this.item.value.equal_to(other_node.item.value) : - this.item.value === other_node.item.value; + this.item.value == other_node.item.value; } equal_to(other_node) { // if tree stores only keys @@ -3658,7 +3654,7 @@ class IntervalTree { * @returns {boolean} */ isEmpty() { - return (this.root == null || this.root === this.nil_node); + return (this.root == null || this.root == this.nil_node); } /** @@ -3690,7 +3686,7 @@ class IntervalTree { */ exist(key, value = key) { let search_node = new Node(key, value); - return !!this.tree_search(this.root, search_node); + return this.tree_search(this.root, search_node) ? true : false; } /** @@ -3729,7 +3725,8 @@ class IntervalTree { */ intersect_any(interval) { let search_node = new Node(interval); - return this.tree_find_any_interval(this.root, search_node); + let found = this.tree_find_any_interval(this.root, search_node); + return found; } /** @@ -3741,34 +3738,15 @@ class IntervalTree { this.tree_walk(this.root, (node) => visitor(node.item.key, node.item.value)); } - /** - * Value Mapper. Walk through every node and map node value to another value - * @param callback(value,key) - function to be called for each tree item - */ + /** Value Mapper. Walk through every node and map node value to another value + * @param callback(value,key) - function to be called for each tree item + */ map(callback) { const tree = new IntervalTree(); this.tree_walk(this.root, (node) => tree.insert(node.item.key, callback(node.item.value, node.item.key))); return tree; } - /** - * @param {Interval} interval - optional if the iterator is intended to start from the beginning - * @param outputMapperFn(value,key) - optional function that maps (value, key) to custom output - * @returns {Iterator} - */ - *iterate(interval, outputMapperFn = (value, key) => value === key ? key.output() : value) { - let node; - if (interval) { - node = this.tree_search_nearest_forward(this.root, new Node(interval)); - } else if (this.root) { - node = this.local_minimum(this.root); - } - while (node) { - yield outputMapperFn(node.item.value, node.item.key); - node = this.tree_successor(node); - } - } - recalc_max(node) { let node_current = node; while (node_current.parent != null) { @@ -3781,11 +3759,11 @@ class IntervalTree { let current_node = this.root; let parent_node = null; - if (this.root == null || this.root === this.nil_node) { + if (this.root == null || this.root == this.nil_node) { this.root = insert_node; } else { - while (current_node !== this.nil_node) { + while (current_node != this.nil_node) { parent_node = current_node; if (insert_node.less_than(current_node)) { current_node = current_node.left; @@ -3815,10 +3793,10 @@ class IntervalTree { let uncle_node; current_node = insert_node; - while (current_node !== this.root && current_node.parent.color === RB_TREE_COLOR_RED) { - if (current_node.parent === current_node.parent.parent.left) { // parent is left child of grandfather + while (current_node != this.root && current_node.parent.color == RB_TREE_COLOR_RED) { + if (current_node.parent == current_node.parent.parent.left) { // parent is left child of grandfather uncle_node = current_node.parent.parent.right; // right brother of parent - if (uncle_node.color === RB_TREE_COLOR_RED) { // Case 1. Uncle is red + if (uncle_node.color == RB_TREE_COLOR_RED) { // Case 1. Uncle is red // re-color father and uncle into black current_node.parent.color = RB_TREE_COLOR_BLACK; uncle_node.color = RB_TREE_COLOR_BLACK; @@ -3826,7 +3804,7 @@ class IntervalTree { current_node = current_node.parent.parent; } else { // Case 2 & 3. Uncle is black - if (current_node === current_node.parent.right) { // Case 2. Current if right child + if (current_node == current_node.parent.right) { // Case 2. Current if right child // This case is transformed into Case 3. current_node = current_node.parent; this.rotate_left(current_node); @@ -3839,7 +3817,7 @@ class IntervalTree { } else { // parent is right child of grandfather uncle_node = current_node.parent.parent.left; // left brother of parent - if (uncle_node.color === RB_TREE_COLOR_RED) { // Case 4. Uncle is red + if (uncle_node.color == RB_TREE_COLOR_RED) { // Case 4. Uncle is red // re-color father and uncle into black current_node.parent.color = RB_TREE_COLOR_BLACK; uncle_node.color = RB_TREE_COLOR_BLACK; @@ -3847,7 +3825,7 @@ class IntervalTree { current_node = current_node.parent.parent; } else { - if (current_node === current_node.parent.left) { // Case 5. Current is left child + if (current_node == current_node.parent.left) { // Case 5. Current is left child // Transform into case 6 current_node = current_node.parent; this.rotate_right(current_node); @@ -3867,7 +3845,7 @@ class IntervalTree { let cut_node; // node to be cut - either delete_node or successor_node ("y" from 14.4) let fix_node; // node to fix rb tree property ("x" from 14.4) - if (delete_node.left === this.nil_node || delete_node.right === this.nil_node) { // delete_node has less then 2 children + if (delete_node.left == this.nil_node || delete_node.right == this.nil_node) { // delete_node has less then 2 children cut_node = delete_node; } else { // delete_node has 2 children @@ -3875,7 +3853,7 @@ class IntervalTree { } // fix_node if single child of cut_node - if (cut_node.left !== this.nil_node) { + if (cut_node.left != this.nil_node) { fix_node = cut_node.left; } else { @@ -3887,11 +3865,11 @@ class IntervalTree { fix_node.parent = cut_node.parent; /*}*/ - if (cut_node === this.root) { + if (cut_node == this.root) { this.root = fix_node; } else { - if (cut_node === cut_node.parent.left) { + if (cut_node == cut_node.parent.left) { cut_node.parent.left = fix_node; } else { @@ -3905,13 +3883,13 @@ class IntervalTree { // COPY DATA !!! // Delete_node becomes cut_node, it means that we cannot hold reference // to node in outer structure and we will have to delete by key, additional search need - if (cut_node !== delete_node) { + if (cut_node != delete_node) { delete_node.copy_data(cut_node); delete_node.update_max(); // update max property of the cut node at the new place this.recalc_max(delete_node); // update max property upward from delete_node to root } - if (/*fix_node != this.nil_node && */cut_node.color === RB_TREE_COLOR_BLACK) { + if (/*fix_node != this.nil_node && */cut_node.color == RB_TREE_COLOR_BLACK) { this.delete_fixup(fix_node); } } @@ -3920,23 +3898,23 @@ class IntervalTree { let current_node = fix_node; let brother_node; - while (current_node !== this.root && current_node.parent != null && current_node.color === RB_TREE_COLOR_BLACK) { - if (current_node === current_node.parent.left) { // fix node is left child + while (current_node != this.root && current_node.parent != null && current_node.color == RB_TREE_COLOR_BLACK) { + if (current_node == current_node.parent.left) { // fix node is left child brother_node = current_node.parent.right; - if (brother_node.color === RB_TREE_COLOR_RED) { // Case 1. Brother is red + if (brother_node.color == RB_TREE_COLOR_RED) { // Case 1. Brother is red brother_node.color = RB_TREE_COLOR_BLACK; // re-color brother current_node.parent.color = RB_TREE_COLOR_RED; // re-color father this.rotate_left(current_node.parent); brother_node = current_node.parent.right; // update brother } // Derive to cases 2..4: brother is black - if (brother_node.left.color === RB_TREE_COLOR_BLACK && - brother_node.right.color === RB_TREE_COLOR_BLACK) { // case 2: both nephews black + if (brother_node.left.color == RB_TREE_COLOR_BLACK && + brother_node.right.color == RB_TREE_COLOR_BLACK) { // case 2: both nephews black brother_node.color = RB_TREE_COLOR_RED; // re-color brother current_node = current_node.parent; // continue iteration } else { - if (brother_node.right.color === RB_TREE_COLOR_BLACK) { // case 3: left nephew red, right nephew black + if (brother_node.right.color == RB_TREE_COLOR_BLACK) { // case 3: left nephew red, right nephew black brother_node.color = RB_TREE_COLOR_RED; // re-color brother brother_node.left.color = RB_TREE_COLOR_BLACK; // re-color nephew this.rotate_right(brother_node); @@ -3953,20 +3931,20 @@ class IntervalTree { } else { // fix node is right child brother_node = current_node.parent.left; - if (brother_node.color === RB_TREE_COLOR_RED) { // Case 1. Brother is red + if (brother_node.color == RB_TREE_COLOR_RED) { // Case 1. Brother is red brother_node.color = RB_TREE_COLOR_BLACK; // re-color brother current_node.parent.color = RB_TREE_COLOR_RED; // re-color father this.rotate_right(current_node.parent); brother_node = current_node.parent.left; // update brother } // Go to cases 2..4 - if (brother_node.left.color === RB_TREE_COLOR_BLACK && - brother_node.right.color === RB_TREE_COLOR_BLACK) { // case 2 + if (brother_node.left.color == RB_TREE_COLOR_BLACK && + brother_node.right.color == RB_TREE_COLOR_BLACK) { // case 2 brother_node.color = RB_TREE_COLOR_RED; // re-color brother current_node = current_node.parent; // continue iteration } else { - if (brother_node.left.color === RB_TREE_COLOR_BLACK) { // case 3: right nephew red, left nephew black + if (brother_node.left.color == RB_TREE_COLOR_BLACK) { // case 3: right nephew red, left nephew black brother_node.color = RB_TREE_COLOR_RED; // re-color brother brother_node.right.color = RB_TREE_COLOR_BLACK; // re-color nephew this.rotate_left(brother_node); @@ -3987,7 +3965,7 @@ class IntervalTree { } tree_search(node, search_node) { - if (node == null || node === this.nil_node) + if (node == null || node == this.nil_node) return undefined; if (search_node.equal_to(node)) { @@ -4001,31 +3979,12 @@ class IntervalTree { } } - tree_search_nearest_forward(node, search_node) { - let best; - let curr = node; - while (curr && curr !== this.nil_node) { - if (curr.less_than(search_node)) { - if (curr.intersect(search_node)) { - best = curr; - curr = curr.left; - } else { - curr = curr.right; - } - } else { - if (!best || curr.less_than(best)) best = curr; - curr = curr.left; - } - } - return best || null; - } - // Original search_interval method; container res support push() insertion // Search all intervals intersecting given one tree_search_interval(node, search_node, res) { - if (node != null && node !== this.nil_node) { + if (node != null && node != this.nil_node) { // if (node->left != this.nil_node && node->left->max >= low) { - if (node.left !== this.nil_node && !node.not_intersect_left_subtree(search_node)) { + if (node.left != this.nil_node && !node.not_intersect_left_subtree(search_node)) { this.tree_search_interval(node.left, search_node, res); } // if (low <= node->high && node->low <= high) { @@ -4033,7 +3992,7 @@ class IntervalTree { res.push(node); } // if (node->right != this.nil_node && node->low <= high) { - if (node.right !== this.nil_node && !node.not_intersect_right_subtree(search_node)) { + if (node.right != this.nil_node && !node.not_intersect_right_subtree(search_node)) { this.tree_search_interval(node.right, search_node, res); } } @@ -4041,14 +4000,17 @@ class IntervalTree { tree_find_any_interval(node, search_node) { let found = false; - if (node != null && node !== this.nil_node) { - if (node.left !== this.nil_node && !node.not_intersect_left_subtree(search_node)) { + if (node != null && node != this.nil_node) { + // if (node->left != this.nil_node && node->left->max >= low) { + if (node.left != this.nil_node && !node.not_intersect_left_subtree(search_node)) { found = this.tree_find_any_interval(node.left, search_node); } + // if (low <= node->high && node->low <= high) { if (!found) { found = node.intersect(search_node); } - if (!found && node.right !== this.nil_node && !node.not_intersect_right_subtree(search_node)) { + // if (node->right != this.nil_node && node->low <= high) { + if (!found && node.right != this.nil_node && !node.not_intersect_right_subtree(search_node)) { found = this.tree_find_any_interval(node.right, search_node); } } @@ -4057,7 +4019,7 @@ class IntervalTree { local_minimum(node) { let node_min = node; - while (node_min.left != null && node_min.left !== this.nil_node) { + while (node_min.left != null && node_min.left != this.nil_node) { node_min = node_min.left; } return node_min; @@ -4066,7 +4028,7 @@ class IntervalTree { // not in use local_maximum(node) { let node_max = node; - while (node_max.right != null && node_max.right !== this.nil_node) { + while (node_max.right != null && node_max.right != this.nil_node) { node_max = node_max.right; } return node_max; @@ -4077,13 +4039,13 @@ class IntervalTree { let current_node; let parent_node; - if (node.right !== this.nil_node) { + if (node.right != this.nil_node) { node_successor = this.local_minimum(node.right); } else { current_node = node; parent_node = node.parent; - while (parent_node != null && parent_node.right === current_node) { + while (parent_node != null && parent_node.right == current_node) { current_node = parent_node; parent_node = parent_node.parent; } @@ -4104,16 +4066,16 @@ class IntervalTree { x.right = y.left; // b goes to x.right - if (y.left !== this.nil_node) { + if (y.left != this.nil_node) { y.left.parent = x; // x becomes parent of b } y.parent = x.parent; // move parent - if (x === this.root) { + if (x == this.root) { this.root = y; // y becomes root } else { // y becomes child of x.parent - if (x === x.parent.left) { + if (x == x.parent.left) { x.parent.left = y; } else { @@ -4123,12 +4085,12 @@ class IntervalTree { y.left = x; // x becomes left child of y x.parent = y; // and y becomes parent of x - if (x != null && x !== this.nil_node) { + if (x != null && x != this.nil_node) { x.update_max(); } y = x.parent; - if (y != null && y !== this.nil_node) { + if (y != null && y != this.nil_node) { y.update_max(); } } @@ -4138,16 +4100,16 @@ class IntervalTree { y.left = x.right; // b goes to y.left - if (x.right !== this.nil_node) { + if (x.right != this.nil_node) { x.right.parent = y; // y becomes parent of b } x.parent = y.parent; // move parent - if (y === this.root) { // x becomes root + if (y == this.root) { // x becomes root this.root = x; } else { // y becomes child of x.parent - if (y === y.parent.left) { + if (y == y.parent.left) { y.parent.left = x; } else { @@ -4157,18 +4119,18 @@ class IntervalTree { x.right = y; // y becomes right child of x y.parent = x; // and x becomes parent of y - if (y !== null && y !== this.nil_node) { + if (y != null && y != this.nil_node) { y.update_max(); } x = y.parent; - if (x != null && x !== this.nil_node) { + if (x != null && x != this.nil_node) { x.update_max(); } } tree_walk(node, action) { - if (node != null && node !== this.nil_node) { + if (node != null && node != this.nil_node) { this.tree_walk(node.left, action); // arr.push(node.toArray()); action(node); @@ -4180,8 +4142,8 @@ class IntervalTree { testRedBlackProperty() { let res = true; this.tree_walk(this.root, function (node) { - if (node.color === RB_TREE_COLOR_RED) { - if (!(node.left.color === RB_TREE_COLOR_BLACK && node.right.color === RB_TREE_COLOR_BLACK)) { + if (node.color == RB_TREE_COLOR_RED) { + if (!(node.left.color == RB_TREE_COLOR_BLACK && node.right.color == RB_TREE_COLOR_BLACK)) { res = false; } } @@ -4194,27 +4156,27 @@ class IntervalTree { let height = 0; let heightLeft = 0; let heightRight = 0; - if (node.color === RB_TREE_COLOR_BLACK) { + if (node.color == RB_TREE_COLOR_BLACK) { height++; } - if (node.left !== this.nil_node) { + if (node.left != this.nil_node) { heightLeft = this.testBlackHeightProperty(node.left); } else { heightLeft = 1; } - if (node.right !== this.nil_node) { + if (node.right != this.nil_node) { heightRight = this.testBlackHeightProperty(node.right); } else { heightRight = 1; } - if (heightLeft !== heightRight) { + if (heightLeft != heightRight) { throw new Error('Red-black height property violated'); } height += heightLeft; return height; - } + }; } /** diff --git a/dist/main.umd.js b/dist/main.umd.js index e63f4d7..a886341 100644 --- a/dist/main.umd.js +++ b/dist/main.umd.js @@ -1072,7 +1072,7 @@ function intersectShape2Multiline(shape, multiline) { let ip = []; for (let edge of multiline) { - ip = [...ip, ...intersectShape2Shape(edge, edge.shape)]; + ip = [...ip, ...intersectShape2Shape(shape, edge.shape)]; } return ip; } @@ -3361,7 +3361,7 @@ /** * Interval is a pair of numbers or a pair of any comparable objects on which may be defined predicates * *equal*, *less* and method *max(p1, p1)* that returns maximum in a pair. - * When interval is an object rather than a pair of numbers, this object should have properties *low*, *high*, *max* + * When interval is an object rather than pair of numbers, this object should have properties *low*, *high*, *max* * and implement methods *less_than(), equal_to(), intersect(), not_intersect(), clone(), output()*. * Two static methods *comparable_max(), comparable_less_than()* define how to compare values in pair.
* This interface is described in typescript definition file *index.d.ts* @@ -3407,7 +3407,7 @@ */ less_than(other_interval) { return this.low < other_interval.low || - this.low === other_interval.low && this.high < other_interval.high; + this.low == other_interval.low && this.high < other_interval.high; } /** @@ -3416,7 +3416,7 @@ * @returns {boolean} */ equal_to(other_interval) { - return this.low === other_interval.low && this.high === other_interval.high; + return this.low == other_interval.low && this.high == other_interval.high; } /** @@ -3439,15 +3439,13 @@ /** * Returns new interval merged with other interval - * @param {Interval} other_interval - Other interval to merge with + * @param {Interval} interval - Other interval to merge with * @returns {Interval} */ merge(other_interval) { return new Interval( - this.low === undefined ? - other_interval.low : (this.low < other_interval.low ? this.low : other_interval.low), - this.high === undefined ? - other_interval.high : (this.high > other_interval.high ? this.high : other_interval.high) + this.low === undefined ? other_interval.low : Math.min(this.low, other_interval.low), + this.high === undefined ? other_interval.high : Math.max(this.high, other_interval.high) ); } @@ -3508,11 +3506,9 @@ this.item = {key: key, value: value}; // key is supposed to be instance of Interval /* If not, this should by an array of two numbers */ - if (key && key instanceof Array && key.length === 2) { + if (key && key instanceof Array && key.length == 2) { if (!Number.isNaN(key[0]) && !Number.isNaN(key[1])) { - let [low, high] = key; - if (low > high) [low, high] = [high, low]; - this.item.key = new Interval(low, high); + this.item.key = new Interval(Math.min(key[0], key[1]), Math.max(key[0], key[1])); } } @@ -3544,7 +3540,7 @@ _value_equal(other_node) { return this.item.value && other_node.item.value && this.item.value.equal_to ? this.item.value.equal_to(other_node.item.value) : - this.item.value === other_node.item.value; + this.item.value == other_node.item.value; } equal_to(other_node) { // if tree stores only keys @@ -3664,7 +3660,7 @@ * @returns {boolean} */ isEmpty() { - return (this.root == null || this.root === this.nil_node); + return (this.root == null || this.root == this.nil_node); } /** @@ -3696,7 +3692,7 @@ */ exist(key, value = key) { let search_node = new Node(key, value); - return !!this.tree_search(this.root, search_node); + return this.tree_search(this.root, search_node) ? true : false; } /** @@ -3735,7 +3731,8 @@ */ intersect_any(interval) { let search_node = new Node(interval); - return this.tree_find_any_interval(this.root, search_node); + let found = this.tree_find_any_interval(this.root, search_node); + return found; } /** @@ -3747,34 +3744,15 @@ this.tree_walk(this.root, (node) => visitor(node.item.key, node.item.value)); } - /** - * Value Mapper. Walk through every node and map node value to another value - * @param callback(value,key) - function to be called for each tree item - */ + /** Value Mapper. Walk through every node and map node value to another value + * @param callback(value,key) - function to be called for each tree item + */ map(callback) { const tree = new IntervalTree(); this.tree_walk(this.root, (node) => tree.insert(node.item.key, callback(node.item.value, node.item.key))); return tree; } - /** - * @param {Interval} interval - optional if the iterator is intended to start from the beginning - * @param outputMapperFn(value,key) - optional function that maps (value, key) to custom output - * @returns {Iterator} - */ - *iterate(interval, outputMapperFn = (value, key) => value === key ? key.output() : value) { - let node; - if (interval) { - node = this.tree_search_nearest_forward(this.root, new Node(interval)); - } else if (this.root) { - node = this.local_minimum(this.root); - } - while (node) { - yield outputMapperFn(node.item.value, node.item.key); - node = this.tree_successor(node); - } - } - recalc_max(node) { let node_current = node; while (node_current.parent != null) { @@ -3787,11 +3765,11 @@ let current_node = this.root; let parent_node = null; - if (this.root == null || this.root === this.nil_node) { + if (this.root == null || this.root == this.nil_node) { this.root = insert_node; } else { - while (current_node !== this.nil_node) { + while (current_node != this.nil_node) { parent_node = current_node; if (insert_node.less_than(current_node)) { current_node = current_node.left; @@ -3821,10 +3799,10 @@ let uncle_node; current_node = insert_node; - while (current_node !== this.root && current_node.parent.color === RB_TREE_COLOR_RED) { - if (current_node.parent === current_node.parent.parent.left) { // parent is left child of grandfather + while (current_node != this.root && current_node.parent.color == RB_TREE_COLOR_RED) { + if (current_node.parent == current_node.parent.parent.left) { // parent is left child of grandfather uncle_node = current_node.parent.parent.right; // right brother of parent - if (uncle_node.color === RB_TREE_COLOR_RED) { // Case 1. Uncle is red + if (uncle_node.color == RB_TREE_COLOR_RED) { // Case 1. Uncle is red // re-color father and uncle into black current_node.parent.color = RB_TREE_COLOR_BLACK; uncle_node.color = RB_TREE_COLOR_BLACK; @@ -3832,7 +3810,7 @@ current_node = current_node.parent.parent; } else { // Case 2 & 3. Uncle is black - if (current_node === current_node.parent.right) { // Case 2. Current if right child + if (current_node == current_node.parent.right) { // Case 2. Current if right child // This case is transformed into Case 3. current_node = current_node.parent; this.rotate_left(current_node); @@ -3845,7 +3823,7 @@ } else { // parent is right child of grandfather uncle_node = current_node.parent.parent.left; // left brother of parent - if (uncle_node.color === RB_TREE_COLOR_RED) { // Case 4. Uncle is red + if (uncle_node.color == RB_TREE_COLOR_RED) { // Case 4. Uncle is red // re-color father and uncle into black current_node.parent.color = RB_TREE_COLOR_BLACK; uncle_node.color = RB_TREE_COLOR_BLACK; @@ -3853,7 +3831,7 @@ current_node = current_node.parent.parent; } else { - if (current_node === current_node.parent.left) { // Case 5. Current is left child + if (current_node == current_node.parent.left) { // Case 5. Current is left child // Transform into case 6 current_node = current_node.parent; this.rotate_right(current_node); @@ -3873,7 +3851,7 @@ let cut_node; // node to be cut - either delete_node or successor_node ("y" from 14.4) let fix_node; // node to fix rb tree property ("x" from 14.4) - if (delete_node.left === this.nil_node || delete_node.right === this.nil_node) { // delete_node has less then 2 children + if (delete_node.left == this.nil_node || delete_node.right == this.nil_node) { // delete_node has less then 2 children cut_node = delete_node; } else { // delete_node has 2 children @@ -3881,7 +3859,7 @@ } // fix_node if single child of cut_node - if (cut_node.left !== this.nil_node) { + if (cut_node.left != this.nil_node) { fix_node = cut_node.left; } else { @@ -3893,11 +3871,11 @@ fix_node.parent = cut_node.parent; /*}*/ - if (cut_node === this.root) { + if (cut_node == this.root) { this.root = fix_node; } else { - if (cut_node === cut_node.parent.left) { + if (cut_node == cut_node.parent.left) { cut_node.parent.left = fix_node; } else { @@ -3911,13 +3889,13 @@ // COPY DATA !!! // Delete_node becomes cut_node, it means that we cannot hold reference // to node in outer structure and we will have to delete by key, additional search need - if (cut_node !== delete_node) { + if (cut_node != delete_node) { delete_node.copy_data(cut_node); delete_node.update_max(); // update max property of the cut node at the new place this.recalc_max(delete_node); // update max property upward from delete_node to root } - if (/*fix_node != this.nil_node && */cut_node.color === RB_TREE_COLOR_BLACK) { + if (/*fix_node != this.nil_node && */cut_node.color == RB_TREE_COLOR_BLACK) { this.delete_fixup(fix_node); } } @@ -3926,23 +3904,23 @@ let current_node = fix_node; let brother_node; - while (current_node !== this.root && current_node.parent != null && current_node.color === RB_TREE_COLOR_BLACK) { - if (current_node === current_node.parent.left) { // fix node is left child + while (current_node != this.root && current_node.parent != null && current_node.color == RB_TREE_COLOR_BLACK) { + if (current_node == current_node.parent.left) { // fix node is left child brother_node = current_node.parent.right; - if (brother_node.color === RB_TREE_COLOR_RED) { // Case 1. Brother is red + if (brother_node.color == RB_TREE_COLOR_RED) { // Case 1. Brother is red brother_node.color = RB_TREE_COLOR_BLACK; // re-color brother current_node.parent.color = RB_TREE_COLOR_RED; // re-color father this.rotate_left(current_node.parent); brother_node = current_node.parent.right; // update brother } // Derive to cases 2..4: brother is black - if (brother_node.left.color === RB_TREE_COLOR_BLACK && - brother_node.right.color === RB_TREE_COLOR_BLACK) { // case 2: both nephews black + if (brother_node.left.color == RB_TREE_COLOR_BLACK && + brother_node.right.color == RB_TREE_COLOR_BLACK) { // case 2: both nephews black brother_node.color = RB_TREE_COLOR_RED; // re-color brother current_node = current_node.parent; // continue iteration } else { - if (brother_node.right.color === RB_TREE_COLOR_BLACK) { // case 3: left nephew red, right nephew black + if (brother_node.right.color == RB_TREE_COLOR_BLACK) { // case 3: left nephew red, right nephew black brother_node.color = RB_TREE_COLOR_RED; // re-color brother brother_node.left.color = RB_TREE_COLOR_BLACK; // re-color nephew this.rotate_right(brother_node); @@ -3959,20 +3937,20 @@ } else { // fix node is right child brother_node = current_node.parent.left; - if (brother_node.color === RB_TREE_COLOR_RED) { // Case 1. Brother is red + if (brother_node.color == RB_TREE_COLOR_RED) { // Case 1. Brother is red brother_node.color = RB_TREE_COLOR_BLACK; // re-color brother current_node.parent.color = RB_TREE_COLOR_RED; // re-color father this.rotate_right(current_node.parent); brother_node = current_node.parent.left; // update brother } // Go to cases 2..4 - if (brother_node.left.color === RB_TREE_COLOR_BLACK && - brother_node.right.color === RB_TREE_COLOR_BLACK) { // case 2 + if (brother_node.left.color == RB_TREE_COLOR_BLACK && + brother_node.right.color == RB_TREE_COLOR_BLACK) { // case 2 brother_node.color = RB_TREE_COLOR_RED; // re-color brother current_node = current_node.parent; // continue iteration } else { - if (brother_node.left.color === RB_TREE_COLOR_BLACK) { // case 3: right nephew red, left nephew black + if (brother_node.left.color == RB_TREE_COLOR_BLACK) { // case 3: right nephew red, left nephew black brother_node.color = RB_TREE_COLOR_RED; // re-color brother brother_node.right.color = RB_TREE_COLOR_BLACK; // re-color nephew this.rotate_left(brother_node); @@ -3993,7 +3971,7 @@ } tree_search(node, search_node) { - if (node == null || node === this.nil_node) + if (node == null || node == this.nil_node) return undefined; if (search_node.equal_to(node)) { @@ -4007,31 +3985,12 @@ } } - tree_search_nearest_forward(node, search_node) { - let best; - let curr = node; - while (curr && curr !== this.nil_node) { - if (curr.less_than(search_node)) { - if (curr.intersect(search_node)) { - best = curr; - curr = curr.left; - } else { - curr = curr.right; - } - } else { - if (!best || curr.less_than(best)) best = curr; - curr = curr.left; - } - } - return best || null; - } - // Original search_interval method; container res support push() insertion // Search all intervals intersecting given one tree_search_interval(node, search_node, res) { - if (node != null && node !== this.nil_node) { + if (node != null && node != this.nil_node) { // if (node->left != this.nil_node && node->left->max >= low) { - if (node.left !== this.nil_node && !node.not_intersect_left_subtree(search_node)) { + if (node.left != this.nil_node && !node.not_intersect_left_subtree(search_node)) { this.tree_search_interval(node.left, search_node, res); } // if (low <= node->high && node->low <= high) { @@ -4039,7 +3998,7 @@ res.push(node); } // if (node->right != this.nil_node && node->low <= high) { - if (node.right !== this.nil_node && !node.not_intersect_right_subtree(search_node)) { + if (node.right != this.nil_node && !node.not_intersect_right_subtree(search_node)) { this.tree_search_interval(node.right, search_node, res); } } @@ -4047,14 +4006,17 @@ tree_find_any_interval(node, search_node) { let found = false; - if (node != null && node !== this.nil_node) { - if (node.left !== this.nil_node && !node.not_intersect_left_subtree(search_node)) { + if (node != null && node != this.nil_node) { + // if (node->left != this.nil_node && node->left->max >= low) { + if (node.left != this.nil_node && !node.not_intersect_left_subtree(search_node)) { found = this.tree_find_any_interval(node.left, search_node); } + // if (low <= node->high && node->low <= high) { if (!found) { found = node.intersect(search_node); } - if (!found && node.right !== this.nil_node && !node.not_intersect_right_subtree(search_node)) { + // if (node->right != this.nil_node && node->low <= high) { + if (!found && node.right != this.nil_node && !node.not_intersect_right_subtree(search_node)) { found = this.tree_find_any_interval(node.right, search_node); } } @@ -4063,7 +4025,7 @@ local_minimum(node) { let node_min = node; - while (node_min.left != null && node_min.left !== this.nil_node) { + while (node_min.left != null && node_min.left != this.nil_node) { node_min = node_min.left; } return node_min; @@ -4072,7 +4034,7 @@ // not in use local_maximum(node) { let node_max = node; - while (node_max.right != null && node_max.right !== this.nil_node) { + while (node_max.right != null && node_max.right != this.nil_node) { node_max = node_max.right; } return node_max; @@ -4083,13 +4045,13 @@ let current_node; let parent_node; - if (node.right !== this.nil_node) { + if (node.right != this.nil_node) { node_successor = this.local_minimum(node.right); } else { current_node = node; parent_node = node.parent; - while (parent_node != null && parent_node.right === current_node) { + while (parent_node != null && parent_node.right == current_node) { current_node = parent_node; parent_node = parent_node.parent; } @@ -4110,16 +4072,16 @@ x.right = y.left; // b goes to x.right - if (y.left !== this.nil_node) { + if (y.left != this.nil_node) { y.left.parent = x; // x becomes parent of b } y.parent = x.parent; // move parent - if (x === this.root) { + if (x == this.root) { this.root = y; // y becomes root } else { // y becomes child of x.parent - if (x === x.parent.left) { + if (x == x.parent.left) { x.parent.left = y; } else { @@ -4129,12 +4091,12 @@ y.left = x; // x becomes left child of y x.parent = y; // and y becomes parent of x - if (x != null && x !== this.nil_node) { + if (x != null && x != this.nil_node) { x.update_max(); } y = x.parent; - if (y != null && y !== this.nil_node) { + if (y != null && y != this.nil_node) { y.update_max(); } } @@ -4144,16 +4106,16 @@ y.left = x.right; // b goes to y.left - if (x.right !== this.nil_node) { + if (x.right != this.nil_node) { x.right.parent = y; // y becomes parent of b } x.parent = y.parent; // move parent - if (y === this.root) { // x becomes root + if (y == this.root) { // x becomes root this.root = x; } else { // y becomes child of x.parent - if (y === y.parent.left) { + if (y == y.parent.left) { y.parent.left = x; } else { @@ -4163,18 +4125,18 @@ x.right = y; // y becomes right child of x y.parent = x; // and x becomes parent of y - if (y !== null && y !== this.nil_node) { + if (y != null && y != this.nil_node) { y.update_max(); } x = y.parent; - if (x != null && x !== this.nil_node) { + if (x != null && x != this.nil_node) { x.update_max(); } } tree_walk(node, action) { - if (node != null && node !== this.nil_node) { + if (node != null && node != this.nil_node) { this.tree_walk(node.left, action); // arr.push(node.toArray()); action(node); @@ -4186,8 +4148,8 @@ testRedBlackProperty() { let res = true; this.tree_walk(this.root, function (node) { - if (node.color === RB_TREE_COLOR_RED) { - if (!(node.left.color === RB_TREE_COLOR_BLACK && node.right.color === RB_TREE_COLOR_BLACK)) { + if (node.color == RB_TREE_COLOR_RED) { + if (!(node.left.color == RB_TREE_COLOR_BLACK && node.right.color == RB_TREE_COLOR_BLACK)) { res = false; } } @@ -4200,27 +4162,27 @@ let height = 0; let heightLeft = 0; let heightRight = 0; - if (node.color === RB_TREE_COLOR_BLACK) { + if (node.color == RB_TREE_COLOR_BLACK) { height++; } - if (node.left !== this.nil_node) { + if (node.left != this.nil_node) { heightLeft = this.testBlackHeightProperty(node.left); } else { heightLeft = 1; } - if (node.right !== this.nil_node) { + if (node.right != this.nil_node) { heightRight = this.testBlackHeightProperty(node.right); } else { heightRight = 1; } - if (heightLeft !== heightRight) { + if (heightLeft != heightRight) { throw new Error('Red-black height property violated'); } height += heightLeft; return height; - } + }; } /** diff --git a/package.json b/package.json index fa21d55..4226e54 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@flatten-js/core", - "version": "1.6.1", + "version": "1.6.2", "description": "Javascript library for 2d geometry", "main": "dist/main.cjs", "umd:main": "dist/main.umd.js",