diff --git a/src/api/geom/multipoint.js b/src/api/geom/multipoint.js new file mode 100644 index 0000000000..7b1fc6c954 --- /dev/null +++ b/src/api/geom/multipoint.js @@ -0,0 +1,143 @@ +goog.provide('ol.geom.multipoint'); + +goog.require('ol.geom.MultiPoint'); +goog.require('ol.geom.point'); +goog.require('ol.projection'); + +///** +// * @typedef {ol.MultiPointLike|Array.|Object} point Point. +// */ +//ol.PointLike; + +/** + * @export + * @param {Array.} opt_arg Point. + * @return {ol.geom.MultiPoint} MultiPoint. + */ +ol.geom.multipoint = function(opt_arg){ + + if (opt_arg instanceof ol.geom.MultiPoint) { + return opt_arg; + } + + var points = []; + if (arguments.length == 1 && goog.isDef(opt_arg)) { + if (goog.isArray(opt_arg)) { + var allValid = goog.array.every(opt_arg, function(spec){ + var p = ol.geom.point(spec); + if (p instanceof ol.geom.Point) { + points.push(p); + return true; + } else { + return false; + } + }); + if (!allValid) { + var msg = 'ol.geom.multipoint: at least one point ' + + 'definition was erroneous.'; + throw new Error(msg); + } + } else { + throw new Error('ol.geom.multipoint'); + } + } + + var mp = new ol.geom.MultiPoint(points); + return mp; +}; +goog.inherits(ol.geom.multipoint, ol.geom.geometry); + +/** + * @export + * @param {Array.=} opt_arg An array of point specifications. + * @return {Array.|ol.geom.MultiPoint|undefined} Result. + */ +ol.geom.MultiPoint.prototype.points = function(opt_arg){ + if (arguments.length == 1 && goog.isDef(opt_arg)) { + var points = [], + allValid = false; + goog.array.every(opt_arg, function(spec){ + var p = ol.geom.point(spec); + if (p instanceof ol.geom.Point) { + points.push(p); + return true; + } else { + return false; + } + }); + if (!allValid) { + points = []; + } + this.setPoints(points); + return this; + } + else { + return this.getPoints(); + } +}; + +/** + * @export + * @param {ol.PointLike} point A point specification. + * @param {number=} opt_index An optional index to add the point(s) at. If not + * provided, the point(s) will be added to the end of the list of points. + * @return {ol.geom.MultiPoint} The MultiPoint instance. + */ +ol.geom.MultiPoint.prototype.add = function(point, opt_index){ + var index = this.points_.length, + allValid = false, + p = ol.geom.point(point); + if (arguments.length == 2 && goog.isDef(opt_index)) { + index = opt_index; + } + this.addPoint(p, index); + return this; +}; + +/** + * @export + * @param {Array.} points Some point specifications. + * @param {number=} opt_index An optional index to add the points at. If not + * provided, the points will be added to the end of the list of points. + * @return {ol.geom.MultiPoint} The MultiPoint instance. + */ +ol.geom.MultiPoint.prototype.addAll = function(points, opt_index){ + var index = this.points_.length, + p; + + if (arguments.length == 2 && goog.isDef(opt_index)) { + index = opt_index; + } + + goog.array.every(points, function(pointSpec){ + p = ol.geom.point(pointSpec); + this.addPoint(p, index); + index++; + return true; + }, this); + + return this; +}; + +/** + * @export + * @param {(ol.geom.Point|Array.)} points A point specification or + * an array of point specifications. + * @return {ol.geom.MultiPoint} The MultiPoint instance. + */ +ol.geom.MultiPoint.prototype.remove = function(points){ + var pointArr = [], + allValid = false; + if (!goog.isArray(points)) { + pointArr.push(points); + } else { + pointArr = points; + } + + goog.array.every(pointArr, function(p){ + this.removePoint(p); + return true; + }, this); + + return this; +}; diff --git a/src/ol.js b/src/ol.js index 9f863ad7d7..1d04286f31 100644 --- a/src/ol.js +++ b/src/ol.js @@ -15,6 +15,7 @@ goog.require("ol.Tile"); goog.require("ol.TileSet"); goog.require("ol.geom.geometry"); goog.require("ol.geom.point"); +goog.require("ol.geom.multipoint"); goog.require('ol.layer.XYZ'); goog.require('ol.layer.OSM'); goog.require('ol.renderer.TileLayerRenderer'); diff --git a/src/ol/geom/MultiPoint.js b/src/ol/geom/MultiPoint.js new file mode 100644 index 0000000000..b5ed08ae43 --- /dev/null +++ b/src/ol/geom/MultiPoint.js @@ -0,0 +1,61 @@ +goog.provide('ol.geom.MultiPoint'); + +goog.require('goog.array'); +goog.require('ol.geom.Geometry'); +goog.require('ol.Projection'); + +/** + * Creates ol.geom.MultiPoint objects. + * + * @extends {ol.geom.Geometry} + * @param {Array.} points An array of points. + * + * @constructor + */ +ol.geom.MultiPoint = function(points) { + /** + * @private + * @type {Array.} + */ + this.points_ = points; + +}; + +goog.inherits(ol.geom.MultiPoint, ol.geom.Geometry); + +/** + * Sets the MultiPoint's points. + * + * @return {Array.} An array of points. + */ +ol.geom.MultiPoint.prototype.getPoints = function() { + return this.points_; +}; + +/** + * Gets the MultiPoint's points. + * + * @param {Array.} points An array of points. + */ +ol.geom.MultiPoint.prototype.setPoints = function(points) { + this.points_ = points; +}; + +/** + * Adds the given point to the list of points at the specified index. + * + * @param {ol.geom.Point} point A point to be added. + * @param {number} index The index where to add. + */ +ol.geom.MultiPoint.prototype.addPoint = function(point, index) { + goog.array.insertAt(this.points_,point,index); +}; + +/** + * Removes the given point from the list of points. + * + * @param {ol.geom.Point} point A point to be removed. + */ +ol.geom.MultiPoint.prototype.removePoint = function(point) { + goog.array.remove(this.points_, point); +}; diff --git a/test/index.html b/test/index.html index e373137787..e4b6022515 100644 --- a/test/index.html +++ b/test/index.html @@ -49,6 +49,7 @@ + @@ -61,6 +62,7 @@ + diff --git a/test/spec/api/geom/multipoint.test.js b/test/spec/api/geom/multipoint.test.js new file mode 100644 index 0000000000..4170389d3c --- /dev/null +++ b/test/spec/api/geom/multipoint.test.js @@ -0,0 +1,224 @@ +describe("ol.geom.multipoint", function() { + var mp; + beforeEach(function() { + mp = ol.geom.multipoint([ + {x:0, y:1}, + {x:2, y:3} + ]); + }); + + afterEach(function() { + mp = null; + }); + describe("can construct instances without some points", function() { + it("works for the object notation of points", function(){ + expect( mp ).toBeA( ol.geom.MultiPoint ); + }); + + it("works for the array notation of points", function(){ + mp = ol.geom.multipoint([ + [0, 1], + [2, 3] + ]); + + expect( mp ).toBeA( ol.geom.MultiPoint ); + }); + + it("works for real points", function(){ + mp = ol.geom.multipoint([ + ol.geom.point([0,1]), + ol.geom.point([2,3]) + ]); + + expect( mp ).toBeA( ol.geom.MultiPoint ); + }); + }); + + describe("can construct instances without any points", function() { + + it("works with an empty array", function(){ + mp = ol.geom.multipoint([]); + + expect( mp ).toBeA( ol.geom.MultiPoint ); + }); + + it("works without arguments", function(){ + mp = ol.geom.multipoint(); + + expect( mp ).toBeA( ol.geom.MultiPoint ); + }); + }); + + describe("the method 'add'", function() { + it("exists", function(){ + expect( mp.add ).toBeA( Function ); + }); + + describe("can be used as setter", function(){ + it("works with a single point specification and an index", function(){ + var p = ol.geom.point([24,7]); + mp.add(p, 0); + + expect(mp.points().length).toBe(3); + + var firstPoint = mp.points()[0]; + + expect( firstPoint.x() + ',' + firstPoint.y() ).toBe( '24,7' ); + }); + + it("works with point instance", function(){ + mp = ol.geom.multipoint(); + mp.add(ol.geom.point([24,7])); + expect(mp.points().length).toBe(1); + var firstPoint = mp.points()[0]; + expect( firstPoint.x() + ',' + firstPoint.y() ).toBe( '24,7' ); + }); + + it("works with array specifications", function(){ + mp = ol.geom.multipoint(); + mp.add([24,7]); + expect(mp.points().length).toBe(1); + var firstPoint = mp.points()[0]; + expect( firstPoint.x() + ',' + firstPoint.y() ).toBe( '24,7' ); + }); + + it("works with object specifications", function(){ + mp = ol.geom.multipoint(); + mp.add({x:24,y:7}); + expect(mp.points().length).toBe(1); + var firstPoint = mp.points()[0]; + expect( firstPoint.x() + ',' + firstPoint.y() ).toBe( '24,7' ); + }); + + it("the index is functional", function(){ + var p = ol.geom.point([24,7]); + mp.add(p, 1); + + expect(mp.points().length).toBe(3); + + var firstPoint = mp.points()[0], // untouched + secondPoint = mp.points()[1], // this should be ours + thirdPoint = mp.points()[2]; // shifted here + + expect( firstPoint.x() + ',' + firstPoint.y() ).toBe( '0,1' ); + expect( secondPoint.x() + ',' + secondPoint.y() ).toBe( '24,7' ); + expect( thirdPoint.x() + ',' + thirdPoint.y() ).toBe( '2,3' ); + }); + + it("the index is optional", function(){ + var p = ol.geom.point([24,7]); + mp.add(p); + + expect(mp.points().length).toBe(3); + + var thirdPoint = mp.points()[2]; + expect( thirdPoint.x() + ',' + thirdPoint.y() ).toBe( '24,7' ); + }); + + it("returns the multipoint instance", function(){ + var p = ol.geom.point([24,7]); + var returned = mp.add(p); + + expect(returned).toBe(mp); + }); + }); + }); + + describe("the method 'addAll'", function(){ + it("exists", function(){ + expect( mp.addAll ).toBeA( Function ); + }); + + describe("can be used as setter", function(){ + + it("works with an array of point specifications and an index", function(){ + var ps = [ + ol.geom.point([24,7]), + ol.geom.point([7,11]) + ]; + mp.addAll(ps, 0); + + expect(mp.points().length).toBe(4); + + var firstPoint = mp.points()[0], + secondPoint = mp.points()[1]; + + expect( firstPoint.x() + ',' + firstPoint.y() ).toBe( '24,7' ); + expect( secondPoint.x() + ',' + secondPoint.y() ).toBe( '7,11' ); + }); + + it("the index is functional", function(){ + var ps = [ + [24,7], + {x:7, y:11} + ]; + mp.addAll(ps, 1); + + expect(mp.points().length).toBe(4); + + var firstPoint = mp.points()[0], // untouched + secondPoint = mp.points()[1], // this should be ours + thirdPoint = mp.points()[2], // this should be ours + fourthPoint = mp.points()[3]; // shifted here + + expect( firstPoint.x() + ',' + firstPoint.y() ).toBe( '0,1' ); + expect( secondPoint.x() + ',' + secondPoint.y() ).toBe( '24,7' ); + expect( thirdPoint.x() + ',' + thirdPoint.y() ).toBe( '7,11' ); + expect( fourthPoint.x() + ',' + fourthPoint.y() ).toBe( '2,3' ); + }); + + it("the index is optional", function(){ + var ps = [ + [24,7], + {x:7, y:11} + ]; + mp.addAll(ps); + + expect(mp.points().length).toBe(4); + + var thirdPoint = mp.points()[2], + fourthPoint = mp.points()[3]; + expect( thirdPoint.x() + ',' + thirdPoint.y() ).toBe( '24,7' ); + expect( fourthPoint.x() + ',' + fourthPoint.y() ).toBe( '7,11' ); + }); + + it("returns the multipoint instance", function(){ + var ps = [ + [24,7], + {x:7, y:11} + ]; + var returned = mp.addAll(ps); + + expect(returned).toBe(mp); + }); + }); + }); + + + describe("the method 'remove'", function() { + it("exists", function(){ + expect( mp.add ).toBeA( Function ); + }); + + it("works with a single point", function(){ + var p = mp.points()[0]; + mp.remove(p); + expect(mp.points().length).toBe(1); + var firstPoint = mp.points()[0]; + expect( firstPoint.x() + ',' + firstPoint.y() ).toBe( '2,3' ); + }); + + it("works with an array of point specifications", function(){ + var ps = [ + mp.points()[1], + mp.points()[0] + ]; + mp.remove(ps); + expect(mp.points().length).toBe(0); + }); + }); +}); + + + + diff --git a/test/spec/ol/geom/MultiPoint.test.js b/test/spec/ol/geom/MultiPoint.test.js new file mode 100644 index 0000000000..f130e8bf96 --- /dev/null +++ b/test/spec/ol/geom/MultiPoint.test.js @@ -0,0 +1,106 @@ +describe("ol.geom.MultiPoint", function() { + var mp; + + beforeEach(function(){ + mp = new ol.geom.MultiPoint([ + new ol.geom.Point(10,20) + ]); + }); + + afterEach(function(){ + mp = null; + }); + + it("constructs instances", function() { + expect( mp ).toBeA( ol.geom.MultiPoint ); + }); + + it("can construct instances without any points", function() { + // empty array + mp = new ol.geom.MultiPoint([]); + expect( mp ).toBeA( ol.geom.MultiPoint ); + + // no argument at all + mp = new ol.geom.MultiPoint(); + expect( mp ).toBeA( ol.geom.MultiPoint ); + }); + + it("inherits from ol.geom.Geometry", function() { + expect( mp ).toBeA( ol.geom.Geometry ); + }); + + it("has a working getter for points", function() { + + var points = mp.getPoints(); + + expect( points ).toBeA( Array ); + expect( points.length ).toBe( 1 ); + expect( points[0] ).toBeA( ol.geom.Point ); + + expect( points[0].getX() + ',' + points[0].getY()).toBe( '10,20' ); + + }); + + it("has a working setter for points", function() { + + mp.setPoints([ + new ol.geom.Point(30,40), + new ol.geom.Point(50,60) + ]); + + var points = mp.getPoints(); + + expect( points.length ).toBe( 2 ); + expect( points[0] ).toBeA( ol.geom.Point ); + expect( points[1] ).toBeA( ol.geom.Point ); + + expect( points[0].getX() + ',' + points[0].getY()).toBe( '30,40' ); + expect( points[1].getX() + ',' + points[1].getY()).toBe( '50,60' ); + + }); + + it("has a method to add points", function() { + + mp.addPoint( + new ol.geom.Point(30,40), + 1 + ); + mp.addPoint( + new ol.geom.Point(50,60), + 2 + ); + mp.addPoint( + new ol.geom.Point(-10,0), + 0 + ); + + var points = mp.getPoints(); + + expect( points.length ).toBe( 4 ); + expect( points[0].getX() + ',' + points[0].getY()).toBe( '-10,0' ); + expect( points[1].getX() + ',' + points[1].getY()).toBe( '10,20' ); + expect( points[2].getX() + ',' + points[2].getY()).toBe( '30,40' ); + expect( points[3].getX() + ',' + points[3].getY()).toBe( '50,60' ); + + }); + + it("has a method to remove points", function() { + mp.setPoints([ + new ol.geom.Point(0,10), + new ol.geom.Point(10,20), + new ol.geom.Point(20,30), + new ol.geom.Point(30,40) + ]); + + var p = mp.getPoints()[2]; // 20,30; + + mp.removePoint( p ); + + var points = mp.getPoints(); + + expect( points.length ).toBe( 3 ); + expect( points[0].getX() + ',' + points[0].getY()).toBe( '0,10' ); + expect( points[1].getX() + ',' + points[1].getY()).toBe( '10,20' ); + expect( points[2].getX() + ',' + points[2].getY()).toBe( '30,40' ); + }); +});