diff --git a/Applications/Utils/CMakeLists.txt b/Applications/Utils/CMakeLists.txt
index 333890eabce7f2c1a046f73a3e935fb61d9c0323..56386eb5b5ce4ee0bec70545e65e40f6868e471d 100644
--- a/Applications/Utils/CMakeLists.txt
+++ b/Applications/Utils/CMakeLists.txt
@@ -1,4 +1,5 @@
 ADD_SUBDIRECTORY( FileConverter )
+ADD_SUBDIRECTORY( GeoTools )
 ADD_SUBDIRECTORY( MeshEdit )
 ADD_SUBDIRECTORY( SimpleMeshCreation )
 
diff --git a/Applications/Utils/GeoTools/CMakeLists.txt b/Applications/Utils/GeoTools/CMakeLists.txt
new file mode 100644
index 0000000000000000000000000000000000000000..3420b9ddb390d6bdd78b7e709e289fd8f4109503
--- /dev/null
+++ b/Applications/Utils/GeoTools/CMakeLists.txt
@@ -0,0 +1,21 @@
+
+INCLUDE_DIRECTORIES(
+	${CMAKE_SOURCE_DIR}
+	${CMAKE_SOURCE_DIR}/BaseLib
+	${CMAKE_SOURCE_DIR}/GeoLib
+	${CMAKE_SOURCE_DIR}/FileIO
+	${CMAKE_SOURCE_DIR}/MathLib
+)
+
+IF(QT4_FOUND)
+ADD_EXECUTABLE( TriangulatePolyline TriangulatePolyline.cpp )
+TARGET_LINK_LIBRARIES( TriangulatePolyline
+	BaseLib
+	FileIO
+	MathLib
+	${QT_LIBRARIES}
+)
+ENDIF() # QT4_FOUND
+
+SET_TARGET_PROPERTIES(TriangulatePolyline PROPERTIES FOLDER Utilities)
+
diff --git a/Applications/Utils/GeoTools/TriangulatePolyline.cpp b/Applications/Utils/GeoTools/TriangulatePolyline.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..824b4cfec6c439f807150c5da37706b4d524f87d
--- /dev/null
+++ b/Applications/Utils/GeoTools/TriangulatePolyline.cpp
@@ -0,0 +1,132 @@
+/**
+ * \file   TriangulatePolyline.h
+ * \author Karsten Rink
+ * \date   2015-02-02
+ * \brief  Utility for triangulating polylines.
+ *
+ * Copyright (c) 2012-2015, OpenGeoSys Community (http://www.opengeosys.org)
+ *            Distributed under a Modified BSD License.
+ *              See accompanying file LICENSE.txt or
+ *              http://www.opengeosys.org/LICENSE.txt
+ *
+ */
+
+#include <string>
+
+#include "logog/include/logog.hpp"
+#include "tclap/CmdLine.h"
+
+#include "BaseLib/BuildInfo.h"
+#include "BaseLib/LogogSimpleFormatter.h"
+#include "FileIO/XmlIO/Qt/XmlGmlInterface.h"
+#include "GeoLib/AnalyticalGeometry.h"
+#include "GeoLib/GEOObjects.h"
+#include "GeoLib/Polyline.h"
+
+#include <QApplication>
+
+
+std::string output_question()
+{
+	WARN ("Given polyline is not closed. Close polyline now?");
+	WARN ("Enter (Y)es for closing the line or (N)o for abort and press ENTER.");
+	std::string input;
+	std::cin >> input;
+	return input;
+}
+
+int main(int argc, char *argv[])
+{
+	QApplication app(argc, argv, false);
+
+	LOGOG_INITIALIZE();
+	BaseLib::LogogSimpleFormatter *custom_format (new BaseLib::LogogSimpleFormatter);
+	logog::Cout *logogCout(new logog::Cout);
+	logogCout->SetFormatter(*custom_format);
+
+	TCLAP::CmdLine cmd("Triangulates the specified polyline in the given geometry file.", ' ', BaseLib::BuildInfo::git_describe);
+	TCLAP::ValueArg<std::string>  input_arg("i", "input",  "GML input file (*.gml)", true, "", "string");
+	TCLAP::ValueArg<std::string> output_arg("o", "output", "GML output file (*.gml)", true, "", "string");
+	TCLAP::ValueArg<std::string>   name_arg("n", "name",   "Name of polyline in given file", true, "", "string");
+	cmd.add( input_arg );
+	cmd.add( name_arg );
+	cmd.add( output_arg );
+	cmd.parse( argc, argv );
+
+	std::string const& file_name(input_arg.getValue());
+	std::string const& polyline_name(name_arg.getValue());
+
+	GeoLib::GEOObjects geo_objects;
+	FileIO::XmlGmlInterface xml(geo_objects);
+	if (!xml.readFile(file_name))
+	{
+		ERR ("Failed to load geometry file.");
+		return 1;
+	}
+
+	std::vector<std::string> geo_names;
+	geo_objects.getGeometryNames(geo_names);
+	GeoLib::PolylineVec const*const line_vec (geo_objects.getPolylineVecObj(geo_names[0]));
+	GeoLib::Polyline* line = const_cast<GeoLib::Polyline*>(line_vec->getElementByName(polyline_name));
+
+	// check if line exists
+	if (line == nullptr)
+	{
+		ERR ("No polyline found with name \"%s\". Aborting...", polyline_name.c_str());
+		return 1;
+	}
+
+	// check if polyline can be triangulated (i.e. closed + coplanar)
+	if (!line->isCoplanar())
+	{
+		ERR ("Polyline is not coplanar, no unambiguous triangulation possible. Aborting...");
+		return 1;
+	}
+
+	if (!line->isClosed())
+	{
+		std::string input ("");
+		while (input != "y" && input != "Y" && input != "n" && input != "N")
+			input = output_question();
+		
+		if (input == "y" || input == "Y")
+		{
+			line->closePolyline();
+			INFO ("Polyline closed.");
+		}
+		else
+			return 1;
+	}
+
+	// create surface
+	INFO ("Triangulating surface...");
+	std::vector<GeoLib::Surface*> *new_sfc = new std::vector<GeoLib::Surface*>;
+	new_sfc->push_back(GeoLib::Surface::createSurface(*line));
+
+	GeoLib::SurfaceVec* sfc_vec (geo_objects.getSurfaceVecObj(geo_names[0]));
+	if (sfc_vec == nullptr)
+		geo_objects.addSurfaceVec(new_sfc, geo_names[0]);
+	else
+		geo_objects.appendSurfaceVec(*new_sfc, geo_names[0]);
+	std::size_t const sfc_id = geo_objects.getSurfaceVec(geo_names[0])->size() - 1;
+	std::string const surface_name (polyline_name + "_surface");
+	for (std::size_t i=1;;++i)
+	{
+		std::string const new_surface_name = (i>1) ? (surface_name + std::to_string(i)) : surface_name;
+		if (sfc_vec->getElementByName(new_surface_name) == nullptr)
+		{
+			sfc_vec->setNameForElement(sfc_id, new_surface_name);
+			break;
+		}
+	}
+
+	// write new file
+	xml.setNameForExport(geo_names[0]);
+	xml.writeToFile(output_arg.getValue());
+	INFO ("...done.");
+
+	delete logogCout;
+	delete custom_format;
+	LOGOG_SHUTDOWN();
+	return 0;
+}
diff --git a/GeoLib/Polyline.cpp b/GeoLib/Polyline.cpp
index b3a8af26b9ab02e2284df84ba1c2c99891f5e156..56688a179abd82f2fe11c1dab7b14994ff6e4456 100644
--- a/GeoLib/Polyline.cpp
+++ b/GeoLib/Polyline.cpp
@@ -193,6 +193,26 @@ bool Polyline::isClosed() const
 		return false;
 }
 
+bool Polyline::isCoplanar() const
+{
+	std::size_t const n_points (_ply_pnt_ids.size());
+	if (n_points < 4)
+		return true;
+
+	GeoLib::Point const& p0 (*this->getPoint(0));
+	GeoLib::Point const& p1 (*this->getPoint(1));
+	GeoLib::Point const& p2 (*this->getPoint(2));
+	for (std::size_t i=3; i<n_points; ++i)
+	{
+		if (!GeoLib::isCoplanar(p0, p1, p2, *this->getPoint(i)))
+		{
+			DBUG ("Point %d is not coplanar to the first three points of the line.", i);
+			return false;
+		}
+	}
+	return true;
+}
+
 bool Polyline::isPointIDInPolyline(std::size_t pnt_id) const
 {
 	return std::find(_ply_pnt_ids.begin(), _ply_pnt_ids.end(), pnt_id) != _ply_pnt_ids.end();
diff --git a/GeoLib/Polyline.h b/GeoLib/Polyline.h
index 1f5e5bf8d52ec36eaa22d70fa5fece01429b693e..6a90c156bddea9dd8fa9945f15a999f977aa74ec 100644
--- a/GeoLib/Polyline.h
+++ b/GeoLib/Polyline.h
@@ -112,6 +112,9 @@ public:
 	/** returns true if the polyline is closed */
 	bool isClosed() const;
 
+	/** returns true if the polyline is coplanar */
+	bool isCoplanar() const;
+
 	/**
 	 * Method tests if the given id of a point (within the vector of points the polyline is
 	 * based on) is inside the polyline.