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');
+ });
+ });
+});