diff --git a/Applications/DataExplorer/DataView/GeoTreeView.cpp b/Applications/DataExplorer/DataView/GeoTreeView.cpp
index 7fe5c9967ac7eb6ba56acd0e2564d65f0c94c121..d2f6b4e6daed4ad0f9f2ecdf3207ab0c49e7c474 100644
--- a/Applications/DataExplorer/DataView/GeoTreeView.cpp
+++ b/Applications/DataExplorer/DataView/GeoTreeView.cpp
@@ -125,6 +125,13 @@ void GeoTreeView::contextMenuEvent( QContextMenuEvent* event )
     // The current index is a list of points/polylines/surfaces
     if (list != nullptr)
     {
+        QAction* convertToStationAction(nullptr);
+        if (list->getType() == GeoLib::GEOTYPE::POINT)
+        {
+            convertToStationAction = menu.addAction("Convert to Stations");
+            connect(convertToStationAction, SIGNAL(triggered()),
+                    this, SLOT(convertPointsToStations()));
+        }
         QAction* connectPlyAction(nullptr);
         if (list->getType() == GeoLib::GEOTYPE::POLYLINE)
         {
@@ -183,6 +190,14 @@ void GeoTreeView::contextMenuEvent( QContextMenuEvent* event )
     menu.exec(event->globalPos());
 }
 
+void GeoTreeView::convertPointsToStations()
+{
+    TreeItem const*const item = static_cast<GeoTreeModel*>(model())
+                         ->getItem(this->selectionModel()->currentIndex())
+                         ->parentItem();
+    emit requestPointToStationConversion(item->data(0).toString().toStdString());
+}
+
 void GeoTreeView::connectPolylines()
 {
     TreeItem* item = static_cast<GeoTreeModel*>(model())->getItem(
diff --git a/Applications/DataExplorer/DataView/GeoTreeView.h b/Applications/DataExplorer/DataView/GeoTreeView.h
index 03e601f484a0c03f263b42a1b0618dcfcdaa10d5..5b2d2df63f82e9664db26d1a2d3b9722e43f0dce 100644
--- a/Applications/DataExplorer/DataView/GeoTreeView.h
+++ b/Applications/DataExplorer/DataView/GeoTreeView.h
@@ -58,6 +58,7 @@ private slots:
     void on_Clicked(QModelIndex idx);
     /// Calls a LineEditDialog.
     void connectPolylines();
+    void convertPointsToStations();
     void mapGeometry();
     /// Calls a SetNameDialog.
     void setNameForElement();
@@ -84,5 +85,6 @@ signals:
     void requestCondSetupDialog(const std::string&, const GeoLib::GEOTYPE, const std::size_t, bool on_points);
     void requestLineEditDialog(const std::string&);
     void requestNameChangeDialog(const std::string&, const GeoLib::GEOTYPE, const std::size_t);
+    void requestPointToStationConversion(std::string const&);
     //void saveFEMConditionsRequested(QString, QString);
 };
diff --git a/Applications/DataExplorer/mainwindow.cpp b/Applications/DataExplorer/mainwindow.cpp
index 000116abbd4896a27fa936d60b6fae7d671d6742..ea4f79a776ad4a1a8ce9f5b54d5f721be164c940 100644
--- a/Applications/DataExplorer/mainwindow.cpp
+++ b/Applications/DataExplorer/mainwindow.cpp
@@ -139,6 +139,8 @@ MainWindow::MainWindow(QWidget* parent /* = 0*/)
             this, SLOT(mapGeometry(const std::string&)));
     connect(geoTabWidget->treeView, SIGNAL(saveToFileRequested(QString, QString)),
             this, SLOT(writeGeometryToFile(QString, QString))); // save geometry to file
+    connect(geoTabWidget->treeView, SIGNAL(requestPointToStationConversion(std::string const&)), this,
+            SLOT(convertPointsToStations( std::string const&)));
     connect(geoTabWidget->treeView, SIGNAL(requestLineEditDialog(const std::string &)),
             this, SLOT(showLineEditDialog(const std::string &))); // open line edit dialog
     connect(geoTabWidget->treeView, SIGNAL(requestNameChangeDialog(const std::string&, const GeoLib::GEOTYPE, std::size_t)),
@@ -1097,6 +1099,14 @@ void MainWindow::showMeshAnalysisDialog()
     dlg->exec();
 }
 
+void MainWindow::convertPointsToStations(std::string const& geo_name)
+{
+    std::string stn_name = geo_name + " Stations";
+    int ret = _project.getGEOObjects().geoPointsToStations(geo_name, stn_name);
+    if (ret == 1)
+        OGSError::box("No points found to convert.");
+}
+
 void MainWindow::showLineEditDialog(const std::string &geoName)
 {
     LineEditDialog lineEdit(
diff --git a/Applications/DataExplorer/mainwindow.h b/Applications/DataExplorer/mainwindow.h
index 5765f0c6416df39c907ec79bdace24d7b06e9916..8baee849e3b12f01621b4df88c8f8cdd911e2459 100644
--- a/Applications/DataExplorer/mainwindow.h
+++ b/Applications/DataExplorer/mainwindow.h
@@ -76,6 +76,7 @@ protected slots:
     void loadPetrelFiles();
     void mapGeometry(const std::string &geo_name);
     void convertMeshToGeometry(const MeshLib::Mesh* mesh);
+    void convertPointsToStations(std::string const& geo_name);
     void openRecentFile();
     void about();
     void showAddPipelineFilterItemDialog(QModelIndex parentIndex);
diff --git a/GeoLib/GEOObjects.cpp b/GeoLib/GEOObjects.cpp
index ee1d9baa8ef4d55dbdb5c981e59137017c204c50..1ca37464f2eed20335ee9bef6a0cb132b13e87a6 100644
--- a/GeoLib/GEOObjects.cpp
+++ b/GeoLib/GEOObjects.cpp
@@ -554,9 +554,84 @@ void GEOObjects::renameGeometry(std::string const& old_name,
     }
 }
 
-const GeoLib::GeoObject* GEOObjects::getGeoObject(const std::string &geo_name,
-                                                            GeoLib::GEOTYPE type,
-                                                            const std::string &geo_obj_name) const
+void GEOObjects::markUnusedPoints(std::string const& geo_name,
+                                  std::vector<bool>& transfer_pnts) const
+{
+    GeoLib::PolylineVec const* const ply_obj(getPolylineVecObj(geo_name));
+    if (ply_obj)
+    {
+        std::vector<GeoLib::Polyline*> const& lines(*ply_obj->getVector());
+        for (auto* line : lines)
+        {
+            std::size_t const n_pnts(line->getNumberOfPoints());
+            for (std::size_t i = 0; i < n_pnts; ++i)
+                transfer_pnts[line->getPointID(i)] = false;
+        }
+    }
+
+    GeoLib::SurfaceVec const* const sfc_obj(getSurfaceVecObj(geo_name));
+    if (sfc_obj)
+    {
+        std::vector<GeoLib::Surface*> const& surfaces = *sfc_obj->getVector();
+        for (auto* sfc : surfaces)
+        {
+            std::size_t const n_tri(sfc->getNumberOfTriangles());
+            for (std::size_t i = 0; i < n_tri; ++i)
+            {
+                GeoLib::Triangle const& t = *(*sfc)[i];
+                transfer_pnts[t[0]] = false;
+                transfer_pnts[t[1]] = false;
+                transfer_pnts[t[2]] = false;
+            }
+        }
+    }
+}
+
+int GEOObjects::geoPointsToStations(std::string const& geo_name,
+                                    std::string& stn_name,
+                                    bool const only_unused_pnts)
+{
+    GeoLib::PointVec const* const pnt_obj(getPointVecObj(geo_name));
+    if (pnt_obj == nullptr)
+    {
+        ERR("Point vector %s not found.", geo_name.c_str());
+        return -1;
+    }
+    std::vector<GeoLib::Point*> const& pnts = *pnt_obj->getVector();
+    if (pnts.empty())
+    {
+        ERR("Point vector %s is empty.", geo_name.c_str());
+        return -1;
+    }
+    std::size_t const n_pnts(pnts.size());
+    std::vector<bool> transfer_pnts(n_pnts, true);
+    if (only_unused_pnts)
+        markUnusedPoints(geo_name, transfer_pnts);
+
+    auto stations = std::make_unique<std::vector<GeoLib::Point*>>();
+    for (std::size_t i = 0; i < n_pnts; ++i)
+    {
+        if (!transfer_pnts[i])
+            continue;
+        std::string name = pnt_obj->getItemNameByID(i);
+        if (name.empty())
+            name = "Station " + std::to_string(i);
+        stations->push_back(new GeoLib::Station(pnts[i], name));
+    }
+    if (!stations->empty())
+        addStationVec(std::move(stations), stn_name);
+    else
+    {
+        WARN("No points found to convert.");
+        return 1;
+    }
+    return 0;
+}
+
+const GeoLib::GeoObject* GEOObjects::getGeoObject(
+    const std::string& geo_name,
+    GeoLib::GEOTYPE type,
+    const std::string& geo_obj_name) const
 {
     GeoLib::GeoObject *geo_obj(nullptr);
     switch (type) {
diff --git a/GeoLib/GEOObjects.h b/GeoLib/GEOObjects.h
index 15f0ef42bafb7330707e5e29565c74bce786c659..a3a9779bc83df7aca5878208d99a7e50c05399db 100644
--- a/GeoLib/GEOObjects.h
+++ b/GeoLib/GEOObjects.h
@@ -249,6 +249,15 @@ public:
     void renameGeometry(std::string const& old_name,
                         std::string const& new_name);
 
+    /// Constucts a station-vector based on the points of a given geometry.
+    // @param geo_name name of the geometry
+    // @param stn_name name of the new station vector
+    // @param only_usused_pnts if true only points not in a line or surface are
+    // transferred, otherwise all points
+    int geoPointsToStations(std::string const& geo_name,
+                            std::string& stn_name,
+                            bool const only_unused_pnts = true);
+
     /// Returns the geo object for a geometric item of the given name and type for the associated geometry.
     const GeoLib::GeoObject* getGeoObject(const std::string &geo_name,
                                           GeoLib::GEOTYPE type,
@@ -367,5 +376,8 @@ private:
      */
     void mergeSurfaces(std::vector<std::string> const & geo_names,
             std::string & merged_geo_name, std::vector<std::size_t> const& pnt_offsets);
+
+    void markUnusedPoints(std::string const& geo_name,
+                          std::vector<bool>& transfer_pnts) const;
 };
 } // end namespace
diff --git a/Tests/Data/MeshGeoToolsLib/Hamburg/BrunnenGOK_Outline_ModellHH.gml b/Tests/Data/MeshGeoToolsLib/Hamburg/BrunnenGOK_Outline_ModellHH.gml
new file mode 100644
index 0000000000000000000000000000000000000000..27e3df356c9d6697e364cad1e5c55e01dc74b7ae
--- /dev/null
+++ b/Tests/Data/MeshGeoToolsLib/Hamburg/BrunnenGOK_Outline_ModellHH.gml
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:f32ed9922fea2c51082aa05a4214b1727ae220ae786d6d9d5b0b5005d60831c3
+size 37074
diff --git a/Tests/GeoLib/TestPointToStationConversion.cpp b/Tests/GeoLib/TestPointToStationConversion.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..a258d1d5b9c466da9a820b358a40650a8b621e3c
--- /dev/null
+++ b/Tests/GeoLib/TestPointToStationConversion.cpp
@@ -0,0 +1,55 @@
+/**
+ * @brief Tests for GeoLib::GEOOnjects::geoPointsToStations()
+ *
+ * \copyright
+ * Copyright (c) 2012-2019, 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 "gtest/gtest.h"
+
+#include "BaseLib/BuildInfo.h"
+#include "GeoLib/GEOObjects.h"
+#include "GeoLib/IO/XmlIO/Boost/BoostXmlGmlInterface.h"
+
+TEST(GeoLib, PointToStationConversion)
+{
+    std::string const file_name(
+        BaseLib::BuildInfo::data_path +
+        "/MeshGeoToolsLib/Hamburg/BrunnenGOK_Outline_ModellHH.gml");
+    GeoLib::GEOObjects geo_obj;
+    GeoLib::IO::BoostXmlGmlInterface io(geo_obj);
+    bool const ret = io.readFile(file_name);
+    EXPECT_TRUE(ret);
+    std::vector<std::string> geo_names;
+    geo_obj.getGeometryNames(geo_names);
+    auto const* const pnts = geo_obj.getPointVec(geo_names[0]);
+    assert(pnts != nullptr);
+    std::size_t const exp_all_pnts(310);
+    EXPECT_EQ(exp_all_pnts, pnts->size());
+
+    // converting only unused points
+    std::string stn_orphaned_pnts("Orphaned Points");
+    int const res_orphaned_pnts =
+        geo_obj.geoPointsToStations(geo_names[0], stn_orphaned_pnts, true);
+    EXPECT_EQ(0, res_orphaned_pnts);
+    auto const* const stns = geo_obj.getStationVec(stn_orphaned_pnts);
+    assert(stns != nullptr);
+    std::size_t const n_stns = stns->size();
+    EXPECT_EQ(18, n_stns);
+    for (std::size_t i = 0; i < n_stns; ++i)
+    {
+        EXPECT_EQ((*(*stns)[i])[0], (*(*pnts)[i])[0]);
+        EXPECT_EQ((*(*stns)[i])[1], (*(*pnts)[i])[1]);
+        EXPECT_EQ((*(*stns)[i])[2], (*(*pnts)[i])[2]);
+    }
+
+    // converting all points
+    std::string stn_all_pnts("All Points");
+    int const res_all_pnts =
+        geo_obj.geoPointsToStations(geo_names[0], stn_all_pnts, false);
+    EXPECT_EQ(0, res_all_pnts);
+    EXPECT_EQ(exp_all_pnts, geo_obj.getStationVec(stn_all_pnts)->size());
+}