diff --git a/src/api/geom/multilinestring.js b/src/api/geom/multilinestring.js new file mode 100644 index 0000000000..6349fb3be4 --- /dev/null +++ b/src/api/geom/multilinestring.js @@ -0,0 +1,138 @@ +goog.provide('ol.geom.multilinestring'); + +goog.require('ol.geom.MultiLineString'); +goog.require('ol.geom.point'); +goog.require('ol.geom.collection'); +goog.require('ol.projection'); + +/** + * @export + * @param {Array.} opt_arg Point. + * @return {ol.geom.MultiLineString} MultiLineString. + */ +ol.geom.multilinestring = function(opt_arg){ + + if (opt_arg instanceof ol.geom.MultiLineString) { + return opt_arg; + } + + var ls = []; + if (arguments.length == 1 && goog.isDef(opt_arg)) { + if (goog.isArray(opt_arg)) { + var allValid = goog.array.every(opt_arg, function(spec){ + var l = ol.geom.linestring(spec); + if (l instanceof ol.geom.LineString) { + ls.push(l); + return true; + } else { + return false; + } + }); + if (!allValid) { + var msg = 'ol.geom.linestring: at least one linestring ' + + 'definition was erroneous.'; + throw new Error(msg); + } + } else { + throw new Error('ol.geom.multilinestring'); + } + } + + var mls = new ol.geom.MultiLineString(ls); + return mls; +}; +goog.inherits(ol.geom.multilinestring, ol.geom.collection); + +/** + * @export + * @param {Array.=} opt_arg An array of point specifications. + * @return {Array.|ol.geom.MultiLineString|undefined} Result. + */ +ol.geom.MultiLineString.prototype.linestrings = function(opt_arg){ + if (arguments.length == 1 && goog.isDef(opt_arg)) { + var ls = [], + allValid = false; + allValid = goog.array.every(opt_arg, function(spec){ + var l = ol.geom.linestring(spec); + if (l instanceof ol.geom.LineString) { + ls.push(l); + return true; + } else { + return false; + } + }); + if (!allValid) { + ls = []; + } + this.setComponents(ls); + return this; + } + else { + return this.getComponents(); + } +}; + +/** + * @export + * @param {ol.LineStringLike} line A linestring 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.MultiLineString} The MultiPoint instance. + */ +ol.geom.MultiLineString.prototype.add = function(line, opt_index){ + var index = this.getLineStrings().length, + l = ol.geom.linestring(line); + if (arguments.length == 2 && goog.isDef(opt_index)) { + index = opt_index; + } + this.addLineString(l, index); + return this; +}; + +/** + * @export + * @param {Array.} lines Some linestring specifications. + * @param {number=} opt_index An optional index to add the points at. If not + * provided, the linestrings will be added to the end of the list of + * linestrings. + * @return {ol.geom.MultiLineString} The MultiLineString instance. + */ +ol.geom.MultiLineString.prototype.addAll = function(lines, opt_index){ + var index = this.getLineStrings().length, + l; + + if (arguments.length == 2 && goog.isDef(opt_index)) { + index = opt_index; + } + + goog.array.every(lines, function(pointSpec){ + l = ol.geom.linestring(pointSpec); + this.addLineString(l, index); + index++; + return true; + }, this); + + return this; +}; + +/** + * @export + * @param {(ol.geom.LineString|Array.)} lines A linestring + * specification or an array of linestring specifications. + * @return {ol.geom.MultiLineString} The MultiLineString instance. + */ +ol.geom.MultiLineString.prototype.remove = function(lines){ + var lineArr = []; + if (!goog.isArray(lines)) { + lineArr.push(lines); + } else { + lineArr = lines; + } + + goog.array.every(lineArr, function(l){ + this.removeLineString(l); + return true; + }, this); + + return this; +}; diff --git a/src/ol.js b/src/ol.js index 5427c6e462..f85b363567 100644 --- a/src/ol.js +++ b/src/ol.js @@ -23,6 +23,7 @@ goog.require("ol.geom.geometry"); goog.require("ol.geom.point"); goog.require("ol.geom.multipoint"); goog.require("ol.geom.linestring"); +goog.require("ol.geom.multilinestring"); goog.require("ol.geom.collection"); goog.require('ol.layer.XYZ'); goog.require('ol.layer.OSM'); diff --git a/test/spec/api/geom/multilinestring.test.js b/test/spec/api/geom/multilinestring.test.js new file mode 100644 index 0000000000..10dacc0638 --- /dev/null +++ b/test/spec/api/geom/multilinestring.test.js @@ -0,0 +1,268 @@ +describe("ol.geom.multilinestring", function() { + var mls, + formatPoint = function(p){ + return p.getX() + ',' + p.getY(); + }, + linestringNPointN = function(mls, i, j) { + return formatPoint(mls.linestrings()[i].vertices()[j]); + }; + beforeEach(function() { + mls = ol.geom.multilinestring([ + [ + {x:0, y:0}, + {x:2, y:2} + ], [ + {x:0, y:2}, + {x:2, y:0} + ] + ]); + }); + + afterEach(function() { + mls = null; + }); + describe("can construct instances without some lines", function() { + it("works for the object notation of points", function(){ + expect( mls ).toBeA( ol.geom.MultiLineString ); + }); + + it("works for the array notation of points", function(){ + mls = ol.geom.multilinestring([ + [ + [0, 0], + [2, 2] + ], [ + [0, 2], + [2, 0] + ] + ]); + + expect( mls ).toBeA( ol.geom.MultiLineString ); + }); + + it("works for real lines", function(){ + mls = ol.geom.multilinestring([ + ol.geom.linestring([ + ol.geom.point([0, 0]), + ol.geom.point([2, 2]) + ]), + ol.geom.linestring([ + ol.geom.point([0, 2]), + ol.geom.point([2, 0]) + ]) + ]); + + expect( mls ).toBeA( ol.geom.MultiLineString ); + }); + }); + + describe("can construct instances without any lines", function() { + + it("works with an empty array", function(){ + mls = ol.geom.multilinestring([]); + + expect( mls ).toBeA( ol.geom.MultiLineString ); + }); + + it("works without arguments", function(){ + mls = ol.geom.multilinestring(); + + expect( mls ).toBeA( ol.geom.MultiLineString ); + }); + }); + + describe("the method 'add'", function() { + it("exists", function(){ + expect( mls.add ).toBeA( Function ); + }); + + describe("can be used as setter", function(){ + it("works with a single line specification and an index", function(){ + var ls = ol.geom.linestring([ + [5, 7], + [5, 10] + ]); + mls.add(ls, 0); + + expect(mls.linestrings().length).toBe(3); + + expect( linestringNPointN(mls, 0, 0) ).toBe( '5,7' ); + }); + + it("works with a linestring instance", function(){ + mls = ol.geom.multilinestring(); + mls.add(ol.geom.linestring([ + [-5.2, 7.3], + [-5.6, 7.7] + ])); + expect(mls.linestrings().length).toBe(1); + + expect( linestringNPointN(mls, 0, 0) ).toBe( '-5.2,7.3' ); + }); + + it("the index is functional", function(){ + var l = ol.geom.linestring([ + [-5.2, 7.3], + [-5.6, 7.7] + ]); + mls.add(l, 1); + + expect(mls.linestrings().length).toBe(3); + + expect( linestringNPointN(mls, 0, 0) ).toBe( '0,0' ); + expect( linestringNPointN(mls, 1, 0) ).toBe( '-5.2,7.3' ); + expect( linestringNPointN(mls, 2, 0) ).toBe( '0,2' ); + }); + + it("the index is optional", function(){ + var l = ol.geom.linestring([ + [-5.2, 7.3], + [-5.6, 7.7] + ]); + mls.add(l); + + expect(mls.linestrings().length).toBe(3); + + expect( linestringNPointN(mls, 2, 0) ).toBe( '-5.2,7.3' ); + }); + + it("returns the multipoint instance", function(){ + var l = ol.geom.linestring([ + [-5.2, 7.3], + [-5.6, 7.7] + ]); + var returned = mls.add(l, 1); + + expect(returned).toBe(mls); + }); + }); + }); + + describe("the method 'addAll'", function(){ + it("exists", function(){ + expect( mls.addAll ).toBeA( Function ); + }); + + describe("can be used as setter", function(){ + + it("works with an array of point specifications and an index", function(){ + var lines = [ + ol.geom.linestring([ + [-5.2, 7.3], + [-5.6, 7.7] + ]), + ol.geom.linestring([ + [2, 4], + [5, 7] + ]) + ]; + mls.addAll(lines, 0); + + expect(mls.linestrings().length).toBe(4); + + expect( linestringNPointN(mls, 0, 0) ).toBe( '-5.2,7.3' ); + expect( linestringNPointN(mls, 1, 0) ).toBe( '2,4' ); + }); + + it("the index is functional", function(){ + var lines = [ + ol.geom.linestring([ + [-5.2, 7.3], + [-5.6, 7.7] + ]), + ol.geom.linestring([ + [2, 4], + [5, 7] + ]) + ]; + mls.addAll(lines, 1); + + expect(mls.linestrings().length).toBe(4); + + expect( linestringNPointN(mls, 0, 0) ).toBe( '0,0' ); + expect( linestringNPointN(mls, 1, 0) ).toBe( '-5.2,7.3' ); + expect( linestringNPointN(mls, 2, 0) ).toBe( '2,4' ); + expect( linestringNPointN(mls, 3, 0) ).toBe( '0,2' ); + }); + + it("the index is optional", function(){ + var lines = [ + ol.geom.linestring([ + [-5.2, 7.3], + [-5.6, 7.7] + ]), + ol.geom.linestring([ + [2, 4], + [5, 7] + ]) + ]; + mls.addAll(lines); + + expect(mls.linestrings().length).toBe(4); + + expect( linestringNPointN(mls, 2, 0) ).toBe( '-5.2,7.3' ); + expect( linestringNPointN(mls, 3, 0) ).toBe( '2,4' ); + }); + + it("returns the multipoint instance", function(){ + var lines = [ + ol.geom.linestring([ + [-5.2, 7.3], + [-5.6, 7.7] + ]), + ol.geom.linestring([ + [2, 4], + [5, 7] + ]) + ]; + var returned = mls.addAll(lines, 0); + + expect(returned).toBe(mls); + }); + }); + }); + + describe("the method 'remove'", function() { + it("exists", function(){ + expect( mls.remove ).toBeA( Function ); + }); + + it("works with a single line", function(){ + var l = mls.linestrings()[0]; + mls.remove(l); + expect(mls.linestrings().length).toBe(1); + + expect( linestringNPointN(mls, 0, 0) ).toBe( '0,2' ); + }); + + it("works with an array of linestrings", function(){ + var lines = [ + mls.linestrings()[0], + mls.linestrings()[1] + ]; + mls.remove(lines); + expect(mls.linestrings().length).toBe(0); + }); + }); + + describe("the centroid method is functional", function(){ + it("returns an instance of ol.geom.Point", function(){ + expect(mls.centroid()).toBeA(ol.geom.Point); + }); + + it("has the expected coordinates", function(){ + mls = ol.geom.multilinestring([ + ol.geom.linestring([ + ol.geom.point([2, 1]), + ol.geom.point([2, 3]) + ]), + ol.geom.linestring([ + ol.geom.point([1, 2]), + ol.geom.point([3, 2]) + ]) + ]); + var c = mls.centroid(); + expect( formatPoint(c) ).toBe('2,2'); + }); + }); +});