From 78d9d8104c8dfaddc47d02b9c3c6487d4fd06d34 Mon Sep 17 00:00:00 2001 From: be5invis Date: Tue, 10 Nov 2015 04:11:13 +0800 Subject: [PATCH 1/4] Basic 2D vector operations. --- src/data_structures/vector2d.js | 22 ++++++++++++++ src/test/data_structures/vector2d.js | 44 ++++++++++++++++++++++++++++ 2 files changed, 66 insertions(+) create mode 100644 src/data_structures/vector2d.js create mode 100644 src/test/data_structures/vector2d.js diff --git a/src/data_structures/vector2d.js b/src/data_structures/vector2d.js new file mode 100644 index 0000000..b8303da --- /dev/null +++ b/src/data_structures/vector2d.js @@ -0,0 +1,22 @@ +function Vector2D(x, y){ + this.x = x; + this.y = y; +} +Vector2D.prototype.add = function(that){ + return new Vector2D(this.x + that.x, this.y + that.y); +} +Vector2D.prototype.minus = function(that){ + return new Vector2D(this.x - that.x, this.y - that.y); +} +Vector2D.prototype.scale = function(amount){ + return new Vector2D(this.x * amount, this.y * amount); +} +Vector2D.prototype.dot = function(that){ + return this.x * that.x + this.y * that.y +} +Vector2D.prototype.cross = function(that){ + return this.x * that.y - this.y * that.x +} + + +module.exports = Vector2D \ No newline at end of file diff --git a/src/test/data_structures/vector2d.js b/src/test/data_structures/vector2d.js new file mode 100644 index 0000000..6da3419 --- /dev/null +++ b/src/test/data_structures/vector2d.js @@ -0,0 +1,44 @@ +'use strict'; + +var root = require('../..'), + Vector2D = root.DataStructures.Vector2D, + assert = require('assert'); + +describe('Vector 2D', function(){ + it('should be able to perform correct addition', function(){ + var p = new Vector2D(1, 2); + var q = new Vector2D(3, 4); + + var r = p.add(q); + assert.equal(r.x, 4); + assert.equal(r.y, 6); + }); + it('should be able to perform correct substraction', function(){ + var p = new Vector2D(1, 2); + var q = new Vector2D(3, 4); + + var r = p.minus(q); + assert.equal(r.x, -2); + assert.equal(r.y, -2); + }); + it('should be able to perform correct scaling', function(){ + var p = new Vector2D(1, 2); + var r = p.scale(9); + assert.equal(r.x, 9); + assert.equal(r.y, 18); + }); + it('should be able to perform correct dot product', function(){ + var p = new Vector2D(1, 2); + var q = new Vector2D(3, 4); + + var r = p.dot(q); + assert.equal(r, 11); + }); + it('should be able to perform correct scalar cross product', function(){ + var p = new Vector2D(1, 2); + var q = new Vector2D(3, 4); + + var r = p.cross(q); + assert.equal(r, -2); + }); +}) \ No newline at end of file From 92336ccff3d960e5ee371e8fe3b58eb01f1c9b79 Mon Sep 17 00:00:00 2001 From: be5invis Date: Tue, 10 Nov 2015 04:11:30 +0800 Subject: [PATCH 2/4] Added Vector2D into data_structures. --- src/data_structures.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/data_structures.js b/src/data_structures.js index 43cbbc1..51965ec 100644 --- a/src/data_structures.js +++ b/src/data_structures.js @@ -14,5 +14,6 @@ module.exports = { Stack: require('./data_structures/stack'), Set: require('./data_structures/set'), DisjointSetForest: require('./data_structures/disjoint_set_forest'), - FenwickTree: require('./data_structures/fenwick_tree') + FenwickTree: require('./data_structures/fenwick_tree'), + Vector2D: require('./data_structures/vector2d') }; From d053d1b90244c438a2d580404cb0ac2b9943a20c Mon Sep 17 00:00:00 2001 From: be5invis Date: Tue, 10 Nov 2015 04:37:19 +0800 Subject: [PATCH 3/4] Added first computatioal geometry algorithm --- in-polygon detection. --- README.md | 8 ++++++++ src/algorithms/geometry/in_polygon.js | 21 +++++++++++++++++++++ src/geometry.js | 6 ++++++ src/index.js | 3 ++- src/test/algorithms/geometry/in_polygon.js | 19 +++++++++++++++++++ 5 files changed, 56 insertions(+), 1 deletion(-) create mode 100644 src/algorithms/geometry/in_polygon.js create mode 100644 src/geometry.js create mode 100644 src/test/algorithms/geometry/in_polygon.js diff --git a/README.md b/README.md index 78913bd..e8f0db5 100644 --- a/README.md +++ b/README.md @@ -137,3 +137,11 @@ require('algorithms').String; * longestCommonSubsequence * longestCommonSubstring * rabinKarp + +#### Computational Geometry +```javascript +require('algorithms/geometry'); +// or +require('algorithms').Geometry; +``` +* inPolygon \ No newline at end of file diff --git a/src/algorithms/geometry/in_polygon.js b/src/algorithms/geometry/in_polygon.js new file mode 100644 index 0000000..4b6f1a9 --- /dev/null +++ b/src/algorithms/geometry/in_polygon.js @@ -0,0 +1,21 @@ +function inPolygon(polygonPoints, testPoint){ + // Detect whether a point is inside a polygon using even-odd winding rule. + var x = testPoint.x, y = testPoint.y; + var inside = false; + for(var i = 0, j = polygonPoints.length - 1; i < polygonPoints.length; j = i++) { + var xi = polygonPoints[i].x, yi = polygonPoints[i].y; + var xj = polygonPoints[j].x, yj = polygonPoints[j].y; + if((xi - x) * (yj - y) === (xj - x) * (yi - y) + && (xi <= x && x <= xj || xj <= x && x <= xi) + && (yi <= y && y <= yj || yj <= y && y <= yi)) { + // The test point is on the boundary. + // Simply return YES. + return true; + } + var intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + if(intersect) inside = !inside; + } + return inside; +} + +module.exports = inPolygon \ No newline at end of file diff --git a/src/geometry.js b/src/geometry.js new file mode 100644 index 0000000..8d3338f --- /dev/null +++ b/src/geometry.js @@ -0,0 +1,6 @@ +'use strict'; + +// Graph algorithms +module.exports = { + inPolygon: require('./algorithms/geometry/in_polygon') +}; diff --git a/src/index.js b/src/index.js index 95c99fb..faacce3 100644 --- a/src/index.js +++ b/src/index.js @@ -6,7 +6,8 @@ var lib = { Math: require('./math'), Search: require('./search'), Sorting: require('./sorting'), - String: require('./string') + String: require('./string'), + Geometry: require('./geometry') }; module.exports = lib; diff --git a/src/test/algorithms/geometry/in_polygon.js b/src/test/algorithms/geometry/in_polygon.js new file mode 100644 index 0000000..4fea0d7 --- /dev/null +++ b/src/test/algorithms/geometry/in_polygon.js @@ -0,0 +1,19 @@ +'use strict'; + +var root = require('../../../'), + inPolygon = root.Geometry.inPolygon, + Vector2D = root.DataStructures.Vector2D, + assert = require('assert'); + +describe('In-polygon detection', function(){ + it('should be able to distinguish whether a point is inside a polygon', function(){ + var polygon = [ new Vector2D(1, 1), new Vector2D(1, 2), new Vector2D(2, 2), new Vector2D(2, 1) ]; + assert(inPolygon(polygon, new Vector2D(1.5, 1.5))); + assert(!inPolygon(polygon, new Vector2D(5, 1))); + }) + it('should be able to treat on-boundary points as inside', function(){ + var polygon = [ new Vector2D(1, 1), new Vector2D(1, 2), new Vector2D(2, 2), new Vector2D(2, 1) ]; + assert(inPolygon(polygon, new Vector2D(1, 1.5))); + assert(inPolygon(polygon, new Vector2D(1.5, 2))); + }) +}) \ No newline at end of file From 7f29000e977c065f7377308f0c913b040de20f2a Mon Sep 17 00:00:00 2001 From: be5invis Date: Tue, 10 Nov 2015 04:48:42 +0800 Subject: [PATCH 4/4] Change styles to pass eslint. --- src/algorithms/geometry/in_polygon.js | 21 +++++++++------ src/data_structures/vector2d.js | 30 ++++++++++++---------- src/test/algorithms/geometry/in_polygon.js | 26 +++++++++++++------ src/test/data_structures/vector2d.js | 14 +++++----- 4 files changed, 54 insertions(+), 37 deletions(-) diff --git a/src/algorithms/geometry/in_polygon.js b/src/algorithms/geometry/in_polygon.js index 4b6f1a9..0c7c0c8 100644 --- a/src/algorithms/geometry/in_polygon.js +++ b/src/algorithms/geometry/in_polygon.js @@ -1,21 +1,26 @@ +'use strict'; + function inPolygon(polygonPoints, testPoint){ // Detect whether a point is inside a polygon using even-odd winding rule. var x = testPoint.x, y = testPoint.y; var inside = false; - for(var i = 0, j = polygonPoints.length - 1; i < polygonPoints.length; j = i++) { + var i = 0; + var j = polygonPoints.length - 1; + for (; i < polygonPoints.length; j = i++) { var xi = polygonPoints[i].x, yi = polygonPoints[i].y; var xj = polygonPoints[j].x, yj = polygonPoints[j].y; - if((xi - x) * (yj - y) === (xj - x) * (yi - y) + if ((xi - x) * (yj - y) === (xj - x) * (yi - y) && (xi <= x && x <= xj || xj <= x && x <= xi) && (yi <= y && y <= yj || yj <= y && y <= yi)) { // The test point is on the boundary. // Simply return YES. return true; - } - var intersect = ((yi > y) != (yj > y)) && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); - if(intersect) inside = !inside; - } + }; + var intersect = ((yi > y) !== (yj > y)) + && (x < (xj - xi) * (y - yi) / (yj - yi) + xi); + if (intersect) inside = !inside; + }; return inside; -} +}; -module.exports = inPolygon \ No newline at end of file +module.exports = inPolygon; \ No newline at end of file diff --git a/src/data_structures/vector2d.js b/src/data_structures/vector2d.js index b8303da..8842af4 100644 --- a/src/data_structures/vector2d.js +++ b/src/data_structures/vector2d.js @@ -1,22 +1,24 @@ +'use strict'; + function Vector2D(x, y){ this.x = x; this.y = y; -} -Vector2D.prototype.add = function(that){ +}; +Vector2D.prototype.add = function (that){ return new Vector2D(this.x + that.x, this.y + that.y); -} -Vector2D.prototype.minus = function(that){ +}; +Vector2D.prototype.minus = function (that){ return new Vector2D(this.x - that.x, this.y - that.y); -} -Vector2D.prototype.scale = function(amount){ +}; +Vector2D.prototype.scale = function (amount){ return new Vector2D(this.x * amount, this.y * amount); -} -Vector2D.prototype.dot = function(that){ - return this.x * that.x + this.y * that.y -} -Vector2D.prototype.cross = function(that){ - return this.x * that.y - this.y * that.x -} +}; +Vector2D.prototype.dot = function (that){ + return this.x * that.x + this.y * that.y; +}; +Vector2D.prototype.cross = function (that){ + return this.x * that.y - this.y * that.x; +}; -module.exports = Vector2D \ No newline at end of file +module.exports = Vector2D; \ No newline at end of file diff --git a/src/test/algorithms/geometry/in_polygon.js b/src/test/algorithms/geometry/in_polygon.js index 4fea0d7..558c55e 100644 --- a/src/test/algorithms/geometry/in_polygon.js +++ b/src/test/algorithms/geometry/in_polygon.js @@ -5,15 +5,25 @@ var root = require('../../../'), Vector2D = root.DataStructures.Vector2D, assert = require('assert'); -describe('In-polygon detection', function(){ - it('should be able to distinguish whether a point is inside a polygon', function(){ - var polygon = [ new Vector2D(1, 1), new Vector2D(1, 2), new Vector2D(2, 2), new Vector2D(2, 1) ]; +describe('In-polygon detection', function (){ + it('should be able to detect if a point is inside a polygon', function (){ + var polygon = [ + new Vector2D(1, 1), + new Vector2D(1, 2), + new Vector2D(2, 2), + new Vector2D(2, 1) + ]; assert(inPolygon(polygon, new Vector2D(1.5, 1.5))); assert(!inPolygon(polygon, new Vector2D(5, 1))); - }) - it('should be able to treat on-boundary points as inside', function(){ - var polygon = [ new Vector2D(1, 1), new Vector2D(1, 2), new Vector2D(2, 2), new Vector2D(2, 1) ]; + }); + it('should treat on-boundary points as inside', function (){ + var polygon = [ + new Vector2D(1, 1), + new Vector2D(1, 2), + new Vector2D(2, 2), + new Vector2D(2, 1) + ]; assert(inPolygon(polygon, new Vector2D(1, 1.5))); assert(inPolygon(polygon, new Vector2D(1.5, 2))); - }) -}) \ No newline at end of file + }); +}); \ No newline at end of file diff --git a/src/test/data_structures/vector2d.js b/src/test/data_structures/vector2d.js index 6da3419..c6e2458 100644 --- a/src/test/data_structures/vector2d.js +++ b/src/test/data_structures/vector2d.js @@ -4,8 +4,8 @@ var root = require('../..'), Vector2D = root.DataStructures.Vector2D, assert = require('assert'); -describe('Vector 2D', function(){ - it('should be able to perform correct addition', function(){ +describe('Vector 2D', function (){ + it('should be able to perform correct addition', function (){ var p = new Vector2D(1, 2); var q = new Vector2D(3, 4); @@ -13,7 +13,7 @@ describe('Vector 2D', function(){ assert.equal(r.x, 4); assert.equal(r.y, 6); }); - it('should be able to perform correct substraction', function(){ + it('should be able to perform correct substraction', function (){ var p = new Vector2D(1, 2); var q = new Vector2D(3, 4); @@ -21,24 +21,24 @@ describe('Vector 2D', function(){ assert.equal(r.x, -2); assert.equal(r.y, -2); }); - it('should be able to perform correct scaling', function(){ + it('should be able to perform correct scaling', function (){ var p = new Vector2D(1, 2); var r = p.scale(9); assert.equal(r.x, 9); assert.equal(r.y, 18); }); - it('should be able to perform correct dot product', function(){ + it('should be able to perform correct dot product', function (){ var p = new Vector2D(1, 2); var q = new Vector2D(3, 4); var r = p.dot(q); assert.equal(r, 11); }); - it('should be able to perform correct scalar cross product', function(){ + it('should be able to perform correct scalar cross product', function (){ var p = new Vector2D(1, 2); var q = new Vector2D(3, 4); var r = p.cross(q); assert.equal(r, -2); }); -}) \ No newline at end of file +}); \ No newline at end of file