From a9e163b3f76aa05e4f9c45bb29d1fc061eecc9fe Mon Sep 17 00:00:00 2001 From: Taylor Bockman Date: Tue, 12 Nov 2019 17:28:19 -0800 Subject: [PATCH] Draw cluster means, support default 4 clusters. --- clusterview2/ui/mode_handlers.py | 3 ++- clusterview2/ui/opengl_widget.py | 54 +++++++++++++++++++++++++++++++++++++--- main_window.py | 7 ++++-- 3 files changed, 58 insertions(+), 6 deletions(-) diff --git a/clusterview2/ui/mode_handlers.py b/clusterview2/ui/mode_handlers.py index d74dd9e..4671fb2 100644 --- a/clusterview2/ui/mode_handlers.py +++ b/clusterview2/ui/mode_handlers.py @@ -11,7 +11,8 @@ from clusterview2.exceptions import ExceededWindowBoundsError from clusterview2.mode import Mode from clusterview2.ui.opengl_widget import (set_drawing_event, set_move_bb_top_left, set_move_bb_bottom_right, reset_move_bbs, - viewport_height, viewport_width) + viewport_height, viewport_width, + draw_mean_circles) from clusterview2.point_manager import PointManager diff --git a/clusterview2/ui/opengl_widget.py b/clusterview2/ui/opengl_widget.py index 90fb655..1bdcc03 100644 --- a/clusterview2/ui/opengl_widget.py +++ b/clusterview2/ui/opengl_widget.py @@ -13,9 +13,12 @@ It should be split up into a few more separate files eventually... Probably even into it's own module folder. """ -from OpenGL.GL import (glBegin, glClearColor, glColor3f, - glEnd, GL_LINE_LOOP, GL_POINTS, - glPointSize, glVertex3f, glViewport) +import math + +from OpenGL.GL import (glBegin, glClearColor, glColor3f, glColor4f, + glEnable, glEnd, GL_LINE_LOOP, GL_LINE_SMOOTH, + GL_POINTS, glPointSize, glVertex3f, + glViewport) from clusterview2.colors import Color, COLOR_TO_RGBA from clusterview2.exceptions import (handle_exceptions, @@ -188,6 +191,11 @@ def paint_gl(): draw_points(PointManager.point_set) + if (__current_context.mode is Mode.CLUSTERING and + __current_context.clustering_solved): + + draw_mean_circles(PointManager.clusters) + elif __current_context.mode is Mode.MOVE: # We have to repeatedly draw the points while we are showing the # move box. @@ -388,3 +396,43 @@ def draw_points(point_set): __clamp_y(point.y), 0.0) # Z is currently fixed to 0 glEnd() + + +def draw_mean_circles(clusters: list): + """ + Draws a red circle for each mean. + + @param clusters The list of clusters created by k-means. + """ + global __current_context + + if __current_context is None: + raise InvalidStateError('Drawing context must be set before setting ' + + 'drawing mode.') + + if len(clusters) == 0: + raise InvalidStateError('Run clustering before drawing means.') + + radius = 0.02 + segments = 100 + + glViewport(0, 0, __WIDTH, __HEIGHT) + glEnable(GL_LINE_SMOOTH) + + for cluster in clusters: + glBegin(GL_LINE_LOOP) + + blue = COLOR_TO_RGBA[Color.BLUE] + glColor4f(blue[0], blue[1], blue[2], 0.5) + + mean = cluster.mean + + x = __clamp_x(cluster.mean.x) + y = __clamp_y(cluster.mean.y) + + for i in range(0, segments): + glVertex3f(x + (radius * math.cos(i * ((2 * math.pi)/segments))), + y + (radius * math.sin(i * ((2 * math.pi)/segments))), + 0.0) + + glEnd() diff --git a/main_window.py b/main_window.py index d641bf0..b6eb186 100644 --- a/main_window.py +++ b/main_window.py @@ -57,6 +57,8 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.number_of_clusters.setMinimum(0) self.number_of_clusters.setMaximum(Color.count() - 2) + self.clustering_button.setEnabled(False) + # We only need to set the context in our OpenGL state machine # wrapper once here since the window is fixed size. # If we allow resizing of the window, the context must be updated @@ -84,7 +86,6 @@ class MainWindow(QMainWindow, Ui_MainWindow): self)) self.clustering_button.clicked.connect(self._clustering) - self.number_of_clusters.valueChanged.connect(self._clustering_enabled) self.reset_button.clicked.connect(self._reset) @@ -209,7 +210,8 @@ class MainWindow(QMainWindow, Ui_MainWindow): refresh_point_list(self) def _clustering_enabled(self): - self.clustering_button.setEnabled(self.number_of_clusters.value() > 0) + point_count = len(list(PointManager.point_set.points)) + self.clustering_button.setEnabled(point_count > 0) @property def mode(self): @@ -260,4 +262,5 @@ class MainWindow(QMainWindow, Ui_MainWindow): # OpenGL event. The context passed to these functions allows # them to modify on screen widgets such as the QOpenGLWidget and # QListWidget. + self._clustering_enabled() MODE_HANDLER_MAP[self._mode](self, event)