diff --git a/src/api/geom/linestring.js b/src/api/geom/linestring.js
new file mode 100644
index 0000000000..61c0ee28a6
--- /dev/null
+++ b/src/api/geom/linestring.js
@@ -0,0 +1,137 @@
+goog.provide('ol.geom.linestring');
+
+goog.require('ol.geom.LineString');
+goog.require('ol.geom.point');
+goog.require('ol.projection');
+
+/**
+ * @export
+ * @param {Array.
} opt_arg Point.
+ * @return {ol.geom.LineString} LineString.
+ */
+ol.geom.linestring = function(opt_arg){
+
+ if (opt_arg instanceof ol.geom.LineString) {
+ return opt_arg;
+ }
+
+ var vertices = [];
+ if (arguments.length == 1 && goog.isDef(opt_arg)) {
+ if (goog.isArray(opt_arg)) {
+ var allValid = goog.array.every(opt_arg, function(spec){
+ var v = ol.geom.point(spec);
+ if (v instanceof ol.geom.Point) {
+ vertices.push(v);
+ return true;
+ } else {
+ return false;
+ }
+ });
+ if (!allValid) {
+ var msg = 'ol.geom.linestring: at least one point '
+ + 'definition was erroneous.';
+ throw new Error(msg);
+ }
+ } else {
+ throw new Error('ol.geom.linestring');
+ }
+ }
+
+ var ls = new ol.geom.LineString(vertices);
+ return ls;
+};
+goog.inherits(ol.geom.linestring, ol.geom.geometry);
+
+/**
+ * @export
+ * @param {Array.=} opt_arg An array of vertex specifications.
+ * @return {Array.|ol.geom.LineString|undefined} Result.
+ */
+ol.geom.LineString.prototype.vertices = function(opt_arg){
+ if (arguments.length == 1 && goog.isDef(opt_arg)) {
+ var vertices = [],
+ allValid = false;
+ goog.array.every(opt_arg, function(spec){
+ var v = ol.geom.point(spec);
+ if (v instanceof ol.geom.Point) {
+ vertices.push(v);
+ return true;
+ } else {
+ return false;
+ }
+ });
+ if (!allValid) {
+ vertices = [];
+ }
+ this.setVertices(vertices);
+ return this;
+ }
+ else {
+ return this.getVertices();
+ }
+};
+
+/**
+ * @export
+ * @param {ol.PointLike} vertex A point specification.
+ * @param {number=} opt_index An optional index to add the vertices at. If not
+ * provided, the vertex will be added to the end of the list of vertices.
+ * @return {ol.geom.LineString} The LineString instance.
+ */
+ol.geom.LineString.prototype.add = function(vertex, opt_index){
+ var index = this.vertices_.length,
+ allValid = false,
+ v = ol.geom.point(vertex);
+ if (arguments.length == 2 && goog.isDef(opt_index)) {
+ index = opt_index;
+ }
+ this.addVertex(v, index);
+ return this;
+};
+
+/**
+ * @export
+ * @param {Array.} vertices Some vertex specifications.
+ * @param {number=} opt_index An optional index to add the vertices at. If not
+ * provided, the points will be added to the end of the list of vertices.
+ * @return {ol.geom.LineString} The LineString instance.
+ */
+ol.geom.LineString.prototype.addAll = function(vertices, opt_index){
+ var index = this.vertices_.length,
+ v;
+
+ if (arguments.length == 2 && goog.isDef(opt_index)) {
+ index = opt_index;
+ }
+
+ goog.array.every(vertices, function(vertexSpec){
+ v = ol.geom.point(vertexSpec);
+ this.addVertex(v, index);
+ index++;
+ return true;
+ }, this);
+
+ return this;
+};
+
+/**
+ * @export
+ * @param {(ol.geom.Point|Array.)} vertices A point specification or
+ * an array of point specifications.
+ * @return {ol.geom.LineString} The MultiPoint instance.
+ */
+ol.geom.LineString.prototype.remove = function(vertices){
+ var vertexArr = [];
+ if (!goog.isArray(vertices)) {
+ vertexArr.push(vertices);
+ } else {
+ vertexArr = vertices;
+ }
+
+ goog.array.every(vertexArr, function(v){
+ this.removeVertex(v);
+ return true;
+ }, this);
+
+ return this;
+};
diff --git a/src/ol/geom/LineString.js b/src/ol/geom/LineString.js
new file mode 100644
index 0000000000..54b07295d5
--- /dev/null
+++ b/src/ol/geom/LineString.js
@@ -0,0 +1,63 @@
+goog.provide('ol.geom.LineString');
+
+goog.require('goog.array');
+goog.require('ol.geom.Geometry');
+goog.require('ol.geom.Point');
+goog.require('ol.Projection');
+
+/**
+ * Creates ol.geom.LineString objects.
+ *
+ * @extends {ol.geom.Geometry}
+ * @param {Array.} vertices An array of points building the
+ * linestrings vertices.
+ *
+ * @constructor
+ */
+ol.geom.LineString = function(vertices) {
+ /**
+ * @private
+ * @type {Array.}
+ */
+ this.vertices_ = vertices;
+
+};
+
+goog.inherits(ol.geom.LineString, ol.geom.Geometry);
+
+/**
+ * Sets the LineString's points.
+ *
+ * @return {Array.} An array of points.
+ */
+ol.geom.LineString.prototype.getVertices = function() {
+ return this.vertices_;
+};
+
+/**
+ * Gets the LineString's points.
+ *
+ * @param {Array.} vertices An array of points.
+ */
+ol.geom.LineString.prototype.setVertices = function(vertices) {
+ this.vertices_ = vertices;
+};
+
+/**
+ * Adds the given vertex to the list of vertices at the specified index.
+ *
+ * @param {ol.geom.Point} vertex A point to be added.
+ * @param {number} index The index where to add.
+ */
+ol.geom.LineString.prototype.addVertex = function(vertex, index) {
+ goog.array.insertAt(this.vertices_,vertex,index);
+};
+
+/**
+ * Removes the given vertex from the list of vertices.
+ *
+ * @param {ol.geom.Point} vertex A point to be removed.
+ */
+ol.geom.LineString.prototype.removeVertex = function(vertex) {
+ goog.array.remove(this.vertices_, vertex);
+};
diff --git a/test/spec/api/geom/linestring.test.js b/test/spec/api/geom/linestring.test.js
new file mode 100644
index 0000000000..356b5b1284
--- /dev/null
+++ b/test/spec/api/geom/linestring.test.js
@@ -0,0 +1,224 @@
+describe("ol.geom.linestring", function() {
+ var ls;
+ beforeEach(function() {
+ ls = ol.geom.linestring([
+ {x:0, y:1},
+ {x:2, y:3}
+ ]);
+ });
+
+ afterEach(function() {
+ ls = null;
+ });
+ describe("can construct instances with some vertices", function() {
+ it("works for the object notation of vertices", function(){
+ expect( ls ).toBeA( ol.geom.LineString );
+ });
+
+ it("works for the array notation of vertices", function(){
+ ls = ol.geom.linestring([
+ [0, 1],
+ [2, 3]
+ ]);
+
+ expect( ls ).toBeA( ol.geom.LineString );
+ });
+
+ it("works for real vertices", function(){
+ ls = ol.geom.linestring([
+ ol.geom.point([0,1]),
+ ol.geom.point([2,3])
+ ]);
+
+ expect( ls ).toBeA( ol.geom.LineString );
+ });
+ });
+
+ describe("can construct instances without any vertices", function() {
+
+ it("works with an empty array", function(){
+ ls = ol.geom.linestring([]);
+
+ expect( ls ).toBeA( ol.geom.LineString );
+ });
+
+ it("works without arguments", function(){
+ ls = ol.geom.linestring();
+
+ expect( ls ).toBeA( ol.geom.LineString );
+ });
+ });
+
+ describe("the method 'add'", function() {
+ it("exists", function(){
+ expect( ls.add ).toBeA( Function );
+ });
+
+ describe("can be used as setter", function(){
+ it("works with a single vertex specification and an index", function(){
+ var p = ol.geom.point([24,7]);
+ ls.add(p, 0);
+
+ expect(ls.vertices().length).toBe(3);
+
+ var firstPoint = ls.vertices()[0];
+
+ expect( firstPoint.x() + ',' + firstPoint.y() ).toBe( '24,7' );
+ });
+
+ it("works with point instance", function(){
+ ls = ol.geom.linestring();
+ ls.add(ol.geom.point([24,7]));
+ expect(ls.vertices().length).toBe(1);
+ var firstPoint = ls.vertices()[0];
+ expect( firstPoint.x() + ',' + firstPoint.y() ).toBe( '24,7' );
+ });
+
+ it("works with array specifications", function(){
+ ls = ol.geom.linestring();
+ ls.add([24,7]);
+ expect(ls.vertices().length).toBe(1);
+ var firstPoint = ls.vertices()[0];
+ expect( firstPoint.x() + ',' + firstPoint.y() ).toBe( '24,7' );
+ });
+
+ it("works with object specifications", function(){
+ ls = ol.geom.linestring();
+ ls.add({x:24,y:7});
+ expect(ls.vertices().length).toBe(1);
+ var firstPoint = ls.vertices()[0];
+ expect( firstPoint.x() + ',' + firstPoint.y() ).toBe( '24,7' );
+ });
+
+ it("the index is functional", function(){
+ var p = ol.geom.point([24,7]);
+ ls.add(p, 1);
+
+ expect(ls.vertices().length).toBe(3);
+
+ var firstPoint = ls.vertices()[0], // untouched
+ secondPoint = ls.vertices()[1], // this should be ours
+ thirdPoint = ls.vertices()[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]);
+ ls.add(p);
+
+ expect(ls.vertices().length).toBe(3);
+
+ var thirdPoint = ls.vertices()[2];
+ expect( thirdPoint.x() + ',' + thirdPoint.y() ).toBe( '24,7' );
+ });
+
+ it("returns the linestring instance", function(){
+ var p = ol.geom.point([24,7]);
+ var returned = ls.add(p);
+
+ expect(returned).toBe(ls);
+ });
+ });
+ });
+
+ describe("the method 'addAll'", function(){
+ it("exists", function(){
+ expect( ls.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])
+ ];
+ ls.addAll(ps, 0);
+
+ expect(ls.vertices().length).toBe(4);
+
+ var firstPoint = ls.vertices()[0],
+ secondPoint = ls.vertices()[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}
+ ];
+ ls.addAll(ps, 1);
+
+ expect(ls.vertices().length).toBe(4);
+
+ var firstPoint = ls.vertices()[0], // untouched
+ secondPoint = ls.vertices()[1], // this should be ours
+ thirdPoint = ls.vertices()[2], // this should be ours
+ fourthPoint = ls.vertices()[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}
+ ];
+ ls.addAll(ps);
+
+ expect(ls.vertices().length).toBe(4);
+
+ var thirdPoint = ls.vertices()[2],
+ fourthPoint = ls.vertices()[3];
+ expect( thirdPoint.x() + ',' + thirdPoint.y() ).toBe( '24,7' );
+ expect( fourthPoint.x() + ',' + fourthPoint.y() ).toBe( '7,11' );
+ });
+
+ it("returns the linestring instance", function(){
+ var ps = [
+ [24,7],
+ {x:7, y:11}
+ ];
+ var returned = ls.addAll(ps);
+
+ expect(returned).toBe(ls);
+ });
+ });
+ });
+
+
+ describe("the method 'remove'", function() {
+ it("exists", function(){
+ expect( ls.add ).toBeA( Function );
+ });
+
+ it("works with a single point", function(){
+ var p = ls.vertices()[0];
+ ls.remove(p);
+ expect(ls.vertices().length).toBe(1);
+ var firstPoint = ls.vertices()[0];
+ expect( firstPoint.x() + ',' + firstPoint.y() ).toBe( '2,3' );
+ });
+
+ it("works with an array of point specifications", function(){
+ var ps = [
+ ls.vertices()[1],
+ ls.vertices()[0]
+ ];
+ ls.remove(ps);
+ expect(ls.vertices().length).toBe(0);
+ });
+ });
+});
+
+
+
+
diff --git a/test/spec/ol/geom/LineString.test.js b/test/spec/ol/geom/LineString.test.js
new file mode 100644
index 0000000000..bf6894706a
--- /dev/null
+++ b/test/spec/ol/geom/LineString.test.js
@@ -0,0 +1,112 @@
+describe("ol.geom.LineString", function() {
+ var ls;
+
+ beforeEach(function(){
+ ls = new ol.geom.LineString([
+ new ol.geom.Point(0,0),
+ new ol.geom.Point(10,10),
+ new ol.geom.Point(10,0),
+ new ol.geom.Point(20,20)
+ ]);
+ });
+
+ afterEach(function(){
+ ls = null;
+ });
+
+ it("constructs instances", function() {
+ expect( ls ).toBeA( ol.geom.LineString );
+ });
+
+ it("can construct instances without any points", function() {
+ // empty array
+ mp = new ol.geom.LineString([]);
+ expect( ls ).toBeA( ol.geom.LineString );
+
+ // no argument at all
+ mp = new ol.geom.LineString();
+ expect( ls ).toBeA( ol.geom.LineString );
+ });
+
+ it("inherits from ol.geom.Geometry", function() {
+ expect( ls ).toBeA( ol.geom.Geometry );
+ });
+
+ it("has a working getter for vertices", function() {
+
+ var vertices = ls.getVertices();
+
+ expect( vertices ).toBeA( Array );
+ expect( vertices.length ).toBe( 4 );
+ expect( vertices[0] ).toBeA( ol.geom.Point );
+
+ expect( vertices[0].getX() + ',' + vertices[0].getY()).toBe( '0,0' );
+
+ });
+
+ it("has a working setter for vertices", function() {
+
+ ls.setVertices([
+ new ol.geom.Point(30,40),
+ new ol.geom.Point(50,60)
+ ]);
+
+ var vertices = ls.getVertices();
+
+ expect( vertices.length ).toBe( 2 );
+ expect( vertices[0] ).toBeA( ol.geom.Point );
+ expect( vertices[1] ).toBeA( ol.geom.Point );
+
+ expect( vertices[0].getX() + ',' + vertices[0].getY()).toBe( '30,40' );
+ expect( vertices[1].getX() + ',' + vertices[1].getY()).toBe( '50,60' );
+
+ });
+
+ it("has a method to add vertices", function() {
+
+ ls.addVertex(
+ new ol.geom.Point(30,40),
+ 1
+ );
+ ls.addVertex(
+ new ol.geom.Point(50,60),
+ 2
+ );
+ ls.addVertex(
+ new ol.geom.Point(-10,0),
+ 0
+ );
+
+ var vertices = ls.getVertices();
+
+ expect( vertices.length ).toBe( 7 );
+ expect( vertices[0].getX() + ',' + vertices[0].getY()).toBe( '-10,0' );
+ expect( vertices[1].getX() + ',' + vertices[1].getY()).toBe( '0,0' );
+ expect( vertices[2].getX() + ',' + vertices[2].getY()).toBe( '30,40' );
+ expect( vertices[3].getX() + ',' + vertices[3].getY()).toBe( '50,60' );
+ expect( vertices[4].getX() + ',' + vertices[4].getY()).toBe( '10,10' );
+ expect( vertices[5].getX() + ',' + vertices[5].getY()).toBe( '10,0' );
+ expect( vertices[6].getX() + ',' + vertices[6].getY()).toBe( '20,20' );
+
+ });
+
+ it("has a method to remove vertices", function() {
+ ls.setVertices([
+ 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 v = ls.getVertices()[2]; // 20,30;
+
+ ls.removeVertex( v );
+
+ var vertices = ls.getVertices();
+
+ expect( vertices.length ).toBe( 3 );
+ expect( vertices[0].getX() + ',' + vertices[0].getY()).toBe( '0,10' );
+ expect( vertices[1].getX() + ',' + vertices[1].getY()).toBe( '10,20' );
+ expect( vertices[2].getX() + ',' + vertices[2].getY()).toBe( '30,40' );
+ });
+});