diff --git a/CgBase/CgEnums.h b/CgBase/CgEnums.h
index e4a59aa7a99108684e88d506781caab847dedf4d..6ef90ebb772c1e8e15e3e30428ef9dbd9b0b3287 100644
--- a/CgBase/CgEnums.h
+++ b/CgBase/CgEnums.h
@@ -10,7 +10,7 @@
 
 
 
-namespace Cg{
+namespace Cg {
 
     typedef enum EventType {
     CgMouseButtonPress              = 0x00000001,
@@ -33,10 +33,16 @@ namespace Cg{
     // unused, may be changed to whatever     
     CgKdTreeEvent 				    = 0x0004000,
     CgShowNormalsEvent	            = 0x0008000,
-    CgEventGroup1                   = 0x000f000,
+    CgSimplifyEvent                 = 0x0010000,
 
     // feel free to add whatever you like
-    }EventType;
+    } EventType;
+
+	typedef enum ClusteringType {
+		CgIncrementalNumber = 0x00,
+		CgIncrementalDiameter = 0x01,
+		CgHierarchical = 0x02,
+	} ClusteringType;
 
 
 
diff --git a/CgEvents/CgSimplifyEvent.cpp b/CgEvents/CgSimplifyEvent.cpp
index 84e5a142e01c5c75fa19d68954c26f81a5a4c097..461fbdada93d64b355f0e554cb942179e7f338fe 100644
--- a/CgEvents/CgSimplifyEvent.cpp
+++ b/CgEvents/CgSimplifyEvent.cpp
@@ -1,30 +1,53 @@
-#include "CgShowNormalsEvent.h"
+#include "CgSimplifyEvent.h"
 
-CgBaseEvent* CgShowNormalsEvent::clone()
+CgBaseEvent* CgSimplifyEvent::clone()
 {
-    return new CgShowNormalsEvent(m_type);
+    return new CgSimplifyEvent(
+        m_type, 
+        m_do_reset, 
+        m_max_number_of_points, 
+        m_max_diameter_of_cluster, 
+        m_max_variance_of_cluster, 
+        m_clustering_type
+    );
 }
 
-Cg::EventType CgShowNormalsEvent::getType()
+Cg::EventType CgSimplifyEvent::getType()
 {
     return m_type;
 }
 
 
-std::ostream& operator<<(std::ostream& os,const CgShowNormalsEvent& e)
+std::ostream& operator<<(std::ostream& os,const CgSimplifyEvent& e)
 {
-    os << "CgShowNormalsEvent" << " ";
+    os << "CgSimplifyEvent [" 
+    << "reset: " << (e.m_do_reset ? "yes" : "no") << " | "
+    << "max points: " << e.m_max_number_of_points << " | "
+    << "max diameter: " << e.m_max_diameter_of_cluster << " | "
+    << "max variance: " << e.m_max_variance_of_cluster << " | "
+    << "clustering type: " << e.m_clustering_type << "] ";
     return os;
 }
 
-CgShowNormalsEvent::CgShowNormalsEvent(Cg::EventType type)
+CgSimplifyEvent::CgSimplifyEvent()
 {
-    m_type=type;
+    m_type = Cg::CgSimplifyEvent;
 }
 
 
-CgShowNormalsEvent::CgShowNormalsEvent()
-{
-    m_type=Cg::CgShowNormalsEvent;
+CgSimplifyEvent::CgSimplifyEvent(
+    Cg::EventType type,
+    bool do_reset, 
+    unsigned int max_number_of_points, 
+    float max_diameter_of_cluster, 
+    float max_variance_of_cluster, 
+    Cg::ClusteringType clustering_type
+) {
+    m_type = type;
+    m_do_reset = do_reset;
+    m_max_number_of_points = max_number_of_points;
+    m_max_diameter_of_cluster = max_diameter_of_cluster;
+    m_max_variance_of_cluster = max_variance_of_cluster;
+    m_clustering_type = clustering_type;
 }
 
diff --git a/CgEvents/CgSimplifyEvent.h b/CgEvents/CgSimplifyEvent.h
index 908a80889c75d7cad59ae5b7856b68df13c2d9e5..f8d0d4f6e2e921e75151ac941b61e0b92908a16b 100644
--- a/CgEvents/CgSimplifyEvent.h
+++ b/CgEvents/CgSimplifyEvent.h
@@ -1,26 +1,37 @@
-#ifndef CG_SHOWNORMALSEVENT
-#define CG_SHOWNORMALSEVENT
+#ifndef CG_SIMPLIFYEVENT
+#define CG_SIMPLIFYEVENT
 
 #include "../CgBase/CgBaseEvent.h"
 #include "../CgBase/CgEnums.h"
 #include <iostream>
 #include <string>
 
-class CgShowNormalsEvent : public CgBaseEvent
+class CgSimplifyEvent : public CgBaseEvent
 {
 public:
-    CgShowNormalsEvent();
-    CgShowNormalsEvent(Cg::EventType type);
-    ~CgShowNormalsEvent(){};
+    CgSimplifyEvent();
+    CgSimplifyEvent(
+        Cg::EventType type,
+        bool do_reset, 
+        unsigned int max_number_of_points, 
+        float max_diameter_of_cluster, 
+        float max_variance_of_cluster, 
+        Cg::ClusteringType clustering_type
+    );
+    ~CgSimplifyEvent(){};
 
     //inherited
     Cg::EventType  getType();
     CgBaseEvent* clone();
 
-    // CgShowNormalsEvent
-    friend std::ostream& operator <<(std::ostream& os, const CgShowNormalsEvent& e);
-
+    // CgSimplifyEvent
+    friend std::ostream& operator <<(std::ostream& os, const CgSimplifyEvent& e);
 private:
      Cg::EventType m_type;
+     bool m_do_reset;
+     unsigned int m_max_number_of_points;
+     float m_max_diameter_of_cluster;
+     float m_max_variance_of_cluster;
+     Cg::ClusteringType m_clustering_type;
 };
-#endif // CG_SHOWNORMALSEVENT
\ No newline at end of file
+#endif // CG_SIMPLIFYEVENT
\ No newline at end of file
diff --git a/CgMath/CgGMST.h b/CgMath/CgGMST.h
deleted file mode 100644
index 9905ee46641f8cb1c7e6f5e65c411edb0036bf64..0000000000000000000000000000000000000000
--- a/CgMath/CgGMST.h
+++ /dev/null
@@ -1,16 +0,0 @@
-
-#ifndef CGGMST_H
-#define CGGMST_H
-
-// benchmarking utility
-// takes a closure without params that returns void and runs it 
-// amount times, printing the duration in milliseconds to stdout afterwards
-void run_timed(std::string tag, unsigned int amount, std::function<void ()> fn) {
-    auto t1 = std::chrono::high_resolution_clock::now();
-    for(int i = 0; i < amount; i++) fn();
-    auto t2 = std::chrono::high_resolution_clock::now();
-    std::chrono::duration<double, std::milli> ms_double = t2 - t1;
-    std::cout << "average for " << tag << ": "<< ms_double.count() / double(amount) << " ms" << std::endl;
-}
-
-#endif // CGGMST_H
\ No newline at end of file
diff --git a/CgQtViewer/CgQtGui.cpp b/CgQtViewer/CgQtGui.cpp
index 8531aabf18570e75e4029eb75fdb6b3dda51eadd..edea8d18fd523afee01558ac69f5f28d0f8eca37 100644
--- a/CgQtViewer/CgQtGui.cpp
+++ b/CgQtViewer/CgQtGui.cpp
@@ -14,6 +14,7 @@
 #include "../CgEvents/CgPickRayEvent.h"
 #include "../CgEvents/CgKdTreeEvent.h"
 #include "../CgEvents/CgShowNormalsEvent.h"
+#include "../CgEvents/CgSimplifyEvent.h"
 #include "../CgEvents/CgWheelEvent.h"
 
 #include <QSlider>
@@ -52,11 +53,11 @@ CgQtGui::CgQtGui(CgQtMainApplication *mw) : m_mainWindow(mw) {
     createKdTreeOptionPanel(kdTreeOptionsWidget);
 
     QWidget *otheropt = new QWidget;
-    createOptionPanelExample2(otheropt);
+    createSimplifyOptionPanel(otheropt);
 
     QTabWidget* m_tabs = new QTabWidget();
     m_tabs->addTab(kdTreeOptionsWidget,"&k-d tree");
-    m_tabs->addTab(otheropt,"&My Tab2");
+    m_tabs->addTab(otheropt,"&simplify");
     container->addWidget(m_tabs);
 
     m_tabs->setMaximumWidth(400);
@@ -165,7 +166,8 @@ void CgQtGui::createKdTreeOptionPanel(QWidget* parent) {
     max_kd_depth_spinbox->setAlignment(Qt::AlignTop);
     max_kd_depth_spinbox->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
 
-    show_normal_colors_button = new QPushButton("show normal colors");
+    // button for normal vizualization
+    QPushButton* show_normal_colors_button = new QPushButton("show normal colors");
     connect(show_normal_colors_button, SIGNAL(clicked()), this, SLOT(slotShowNormalsButtonPressed()));
     tab1_control->addWidget(show_normal_colors_button);
 
@@ -177,50 +179,115 @@ void CgQtGui::createKdTreeOptionPanel(QWidget* parent) {
     parent->setLayout(tab1_control);
 }
 
-void CgQtGui::createOptionPanelExample2(QWidget* parent) {
+void CgQtGui::createSimplifyOptionPanel(QWidget* parent) {
     QVBoxLayout *tab2_control = new QVBoxLayout();
     QHBoxLayout *subBox = new QHBoxLayout();
 
-    /*Example for using a button group */
-
-    QGroupBox* myGroupBox = new QGroupBox("Radiobutton Group Example ");
-
-    myButtonGroup = new QButtonGroup(subBox);
-    myButtonGroup->setExclusive(true);
-
-    QRadioButton* radiobutton1 = new QRadioButton( "&Option1");
-    QRadioButton* radiobutton2 = new QRadioButton( "&Option2");
-    QRadioButton* radiobutton3 = new QRadioButton( "&Option3");
-    QRadioButton* radiobutton4 = new QRadioButton( "&Option4");
-    QRadioButton* radiobutton5 = new QRadioButton( "&Option5");
-
-    radiobutton2->setChecked(true);
-
-    myButtonGroup->addButton(radiobutton1,0);
-    myButtonGroup->addButton(radiobutton2,1);
-    myButtonGroup->addButton(radiobutton3,2);
-    myButtonGroup->addButton(radiobutton4,3);
-    myButtonGroup->addButton(radiobutton5,4);
-
+    // spinbox for number of points in cluster
+    QLabel *max_points_label = new QLabel("max points (n):");
+    tab2_control->addWidget(max_points_label);
+    max_points_label->setAlignment(Qt::AlignTop);
+    max_points_label->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
+
+    max_number_of_points_spinbox = new QSpinBox();
+    tab2_control->addWidget(max_number_of_points_spinbox);
+    max_number_of_points_spinbox->setMinimum(1);
+    max_number_of_points_spinbox->setMaximum(100);
+    max_number_of_points_spinbox->setValue(15);
+    tab2_control->addWidget(max_number_of_points_spinbox);
+    max_number_of_points_spinbox->setAlignment(Qt::AlignTop);
+    max_number_of_points_spinbox->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
+
+    // spinbox for max diameter of cluster
+    QLabel *max_diameter_label = new QLabel("max diameter (d):");
+    tab2_control->addWidget(max_diameter_label);
+    max_diameter_label->setAlignment(Qt::AlignTop);
+    max_diameter_label->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
+
+    max_diameter_of_cluster_spinbox = new QDoubleSpinBox();
+    tab2_control->addWidget(max_diameter_of_cluster_spinbox);
+    max_diameter_of_cluster_spinbox->setMinimum(0.01);
+    max_diameter_of_cluster_spinbox->setMaximum(10.0);
+    max_diameter_of_cluster_spinbox->setValue(0.05);
+    max_diameter_of_cluster_spinbox->setSingleStep(0.05);
+    tab2_control->addWidget(max_diameter_of_cluster_spinbox);
+    max_diameter_of_cluster_spinbox->setAlignment(Qt::AlignTop);
+    max_diameter_of_cluster_spinbox->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
+
+    // spinbox for max variance of cluster
+    QLabel *max_variance_label = new QLabel("max variance:");
+    tab2_control->addWidget(max_variance_label);
+    max_variance_label->setAlignment(Qt::AlignTop);
+    max_variance_label->setSizePolicy(QSizePolicy::Maximum, QSizePolicy::Fixed);
+
+    max_variance_of_cluster_spinbox = new QDoubleSpinBox();
+    tab2_control->addWidget(max_variance_of_cluster_spinbox);
+    max_variance_of_cluster_spinbox->setMinimum(0.01);
+    max_variance_of_cluster_spinbox->setMaximum(5.0);
+    max_variance_of_cluster_spinbox->setValue(0.05);
+    max_variance_of_cluster_spinbox->setSingleStep(0.05);
+    tab2_control->addWidget(max_variance_of_cluster_spinbox);
+    max_variance_of_cluster_spinbox->setAlignment(Qt::AlignTop);
+    max_variance_of_cluster_spinbox->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Fixed);
+
+    /* select clustering type button group */
+
+    QGroupBox* myGroupBox = new QGroupBox("Clustering Type: ");
+
+    clustering_type_buttongroup = new QButtonGroup(subBox);
+    clustering_type_buttongroup->setExclusive(true);
+
+    QRadioButton* radiobutton1 = new QRadioButton( "Incremental w/ n");
+    QRadioButton* radiobutton2 = new QRadioButton( "Incremental w/ d");
+    QRadioButton* radiobutton3 = new QRadioButton( "Hierarchical");
+
+    radiobutton1->setChecked(true);
+
+    clustering_type_buttongroup->addButton(radiobutton1, int(Cg::CgIncrementalNumber));
+    clustering_type_buttongroup->addButton(radiobutton2, int(Cg::CgIncrementalDiameter));
+    clustering_type_buttongroup->addButton(radiobutton3, int(Cg::CgHierarchical));
 
     QVBoxLayout *vbox = new QVBoxLayout;
     vbox->addWidget(radiobutton1);
     vbox->addWidget(radiobutton2);
     vbox->addWidget(radiobutton3);
-    vbox->addWidget(radiobutton4);
-    vbox->addWidget(radiobutton5);
     vbox->addStretch(1);
     myGroupBox->setLayout(vbox);
     subBox->addWidget(myGroupBox);
     tab2_control->addLayout(subBox);
 
-    connect(myButtonGroup, SIGNAL( buttonClicked(int) ), this, SLOT( slotButtonGroupSelectionChanged() ) );
+    // simplify button
+    QPushButton* calculate_clustering_button = new QPushButton("simplify");
+    connect(calculate_clustering_button, SIGNAL(clicked()), this, SLOT(slotSimplify()));
+    tab2_control->addWidget(calculate_clustering_button);
+
+    // reset button
+    QPushButton* reset_simplification_button = new QPushButton("reset");
+    connect(reset_simplification_button, SIGNAL(clicked()), this, SLOT(slotReset()));
+    tab2_control->addWidget(reset_simplification_button);
+
     parent->setLayout(tab2_control);
+}
 
+void CgQtGui::sendSimplifyEvent(bool reset) {
+    CgBaseEvent* e = new CgSimplifyEvent(
+        Cg::CgSimplifyEvent,
+        reset,
+        max_number_of_points_spinbox->value(),
+        max_diameter_of_cluster_spinbox->value(),
+        max_variance_of_cluster_spinbox->value(),
+        (Cg::ClusteringType) clustering_type_buttongroup->checkedId()
+    );
+    notifyObserver(e);
+    m_glRenderWidget->redraw();
 }
 
-void CgQtGui::slotButtonGroupSelectionChanged() {
+void CgQtGui::slotSimplify() {
+    sendSimplifyEvent(false);
+}
 
+void CgQtGui::slotReset() {
+    sendSimplifyEvent(true);
 }
 
 void CgQtGui::slotKdDepthSpinboxChanged() {
diff --git a/CgQtViewer/CgQtGui.h b/CgQtViewer/CgQtGui.h
index e5a3de507c58d9a67bad0f4a8ad3923881708b46..c3a159dbf76b71c46ed40b70e7b2f7294d873c05 100644
--- a/CgQtViewer/CgQtGui.h
+++ b/CgQtViewer/CgQtGui.h
@@ -52,6 +52,7 @@ class QTabWidget;
 class QTextEdit;
 class QCheckBox;
 class QSpinBox;
+class QDoubleSpinBox;
 class QMenuBar;
 class QAction;
 QT_END_NAMESPACE
@@ -98,16 +99,14 @@ private:
     void createKdTreeOptionPanel(QWidget* panel);
     QSpinBox* max_kd_depth_spinbox;
     QCheckBox* display_kd_tree_checkbox;
-    QPushButton* show_normal_colors_button;
 
     /* additional stuff */
     void createSimplifyOptionPanel(QWidget* panel);
+    void sendSimplifyEvent(bool reset);
     QSpinBox* max_number_of_points_spinbox;
-    QSpinBox* max_diameter_of_cluster_spinbox;
-    QSpinBox* max_variance_of_cluster_spinbox;
+    QDoubleSpinBox* max_diameter_of_cluster_spinbox;
+    QDoubleSpinBox* max_variance_of_cluster_spinbox;
     QButtonGroup* clustering_type_buttongroup;
-    QPushButton* calculate_clustering_button;
-    QPushButton* reset_simplification_button;
 
     bool m_use_spats;
     bool m_show_pickray;
@@ -125,7 +124,8 @@ private slots:
     void slotShowNormalsButtonPressed();
 
     /* additional stuff*/
-    void slotButtonGroupSelectionChanged();
+    void slotSimplify();
+    void slotReset();
     void slotLoadMeshFile();
     void slotLoadPointCloudFile();
     void slotSplatting();
diff --git a/CgSceneGraph/CgSceneControl.cpp b/CgSceneGraph/CgSceneControl.cpp
index 815a1cf6feee1b3248fccde71e22be43967ecb87..73d1d79d2a6dc35b8aee780026deb837cabc1baf 100644
--- a/CgSceneGraph/CgSceneControl.cpp
+++ b/CgSceneGraph/CgSceneControl.cpp
@@ -2,16 +2,6 @@
 
 #include "CgSceneControl.h"
 #include "CgBase/CgEnums.h"
-#include "CgEvents/CgMouseEvent.h"
-#include "CgEvents/CgWheelEvent.h"
-#include "CgEvents/CgKeyEvent.h"
-#include "CgEvents/CgWindowResizeEvent.h"
-#include "CgEvents/CgLoadMeshEvent.h"
-#include "CgEvents/CgLoadPointCloudEvent.h"
-#include "CgEvents/CgTrackballEvent.h"
-#include "CgEvents/CgSplatEvent.h"
-#include "CgEvents/CgPickRayEvent.h"
-#include "CgEvents/CgKdTreeEvent.h"
 #include "CgBase/CgBaseRenderer.h"
 #include "CgPointCloud.h"
 #include "CgPolyLine.h"
@@ -213,6 +203,10 @@ void CgSceneControl::handlePickEvent(float x, float y) {
   }
 }
 
+void CgSceneControl::handleSimplifyEvent(CgSimplifyEvent ev) {
+  std::cout << ev << std::endl;
+}
+
 void CgSceneControl::handleEvent(CgBaseEvent* e) {
     // any kind of MouseEvents can be checked via CgEvent::CgMouseEvent a
     // see CgEvent enums in CgEnums.h
@@ -324,8 +318,15 @@ void CgSceneControl::handleEvent(CgBaseEvent* e) {
 
     // visualize normals by coloring the points according
     // to their object space normals
-    if(e->getType() & Cg::CgShowNormalsEvent) {
-      if(m_pointcloud != nullptr) m_pointcloud->showNormalColors();
+    if(e->getType() & Cg::CgShowNormalsEvent && m_pointcloud != nullptr) {
+      m_pointcloud->showNormalColors();
+      m_renderer->init(m_pointcloud);
+      m_renderer->redraw();
+    }
+
+    if(e->getType() & Cg::CgSimplifyEvent && m_pointcloud != nullptr) {
+      CgSimplifyEvent* ev = (CgSimplifyEvent*) e;
+      handleSimplifyEvent(*ev);
       m_renderer->init(m_pointcloud);
       m_renderer->redraw();
     }
diff --git a/CgSceneGraph/CgSceneControl.h b/CgSceneGraph/CgSceneControl.h
index 4fd2c38cb1e329780f9356b6e6de433c7dda4c86..f8d6bfd82838f24d524fa30627dc6e21e08cbbf3 100644
--- a/CgSceneGraph/CgSceneControl.h
+++ b/CgSceneGraph/CgSceneControl.h
@@ -10,6 +10,18 @@
 #include <iostream>
 #include <numeric>
 
+#include "CgEvents/CgMouseEvent.h"
+#include "CgEvents/CgWheelEvent.h"
+#include "CgEvents/CgKeyEvent.h"
+#include "CgEvents/CgWindowResizeEvent.h"
+#include "CgEvents/CgLoadMeshEvent.h"
+#include "CgEvents/CgLoadPointCloudEvent.h"
+#include "CgEvents/CgTrackballEvent.h"
+#include "CgEvents/CgSplatEvent.h"
+#include "CgEvents/CgPickRayEvent.h"
+#include "CgEvents/CgKdTreeEvent.h"
+#include "CgEvents/CgSimplifyEvent.h"
+
 class CgBaseEvent;
 class CgBaseRenderer;
 class CgPointCloud;
@@ -42,6 +54,7 @@ private:
     void calculateSingularValueDecomposition();
     void createKdTreeViz(int max_depth);
     void handlePickEvent(float x, float y);
+    void handleSimplifyEvent(CgSimplifyEvent ev);
 
     // one single Disc used as Object to render the spats (in own local coordinates)
     CgTriangleMesh* m_disc;