diff --git a/clusterview/mode_handlers.py b/clusterview/mode_handlers.py index 816d757..19f807f 100644 --- a/clusterview/mode_handlers.py +++ b/clusterview/mode_handlers.py @@ -10,7 +10,6 @@ from .mode import Mode from .opengl_widget import (set_drawing_event, set_move_bb_top_left, set_move_bb_bottom_right, reset_move_bbs, viewport_height, viewport_width) -from .points import PointSet from .point_manager import PointManager @@ -34,16 +33,10 @@ class __ClickFlag: SELECTED_MOVED = 3 -# Size of point for drawing -__POINT_SIZE = 8 # Canvas pixel border - empirical, not sure where this is stored officially __CANVAS_BORDER = 1 -# PointManager is a class that is filled with static methods -# designed for managing state. -PointManager.point_set = PointSet(__POINT_SIZE, viewport_height(), - viewport_width()) # Module level flag for left click events (used to detect a left # click hold drag) @@ -383,6 +376,38 @@ def reset_centroid_count_and_colors(): point.color = Color.GREY +def generate_random_points(point_count, x_bound, y_bound): + """ + Using the random module of python generate a unique set of xs and ys + to use as points, bounded by the canvas edges. + + @param point_count The count of points to generate. + @param x_bound The width bound. + @param y_bound The height bound. + """ + + # TODO: The window size should be increased slightly to + # accomodate 3000 points (the maximum) given the point size. + # Work out an algorithm and limit the number of points + # selectable based on the maximum amount of points on the screen + # given the point size. + + # First clear the point set + PointManager.point_set.clear() + + point_size = PointManager.point_set.point_size + + # Sample without replacement so points are not duplicated. + xs = random.sample(range(point_size, x_bound), point_count) + + ys = random.sample(range(point_size, y_bound), point_count) + + points = list(zip(xs, ys)) + + for point in points: + PointManager.point_set.add_point(point[0], point[1], Color.GREY) + + # Simple dispatcher to make it easy to dispatch the right mode # function when the OpenGL window is acted on. MODE_HANDLER_MAP = { diff --git a/clusterview/points.py b/clusterview/points.py index 6dd319d..c6594d8 100644 --- a/clusterview/points.py +++ b/clusterview/points.py @@ -250,6 +250,9 @@ class PointSet: return ",".join(s) + def clear(self): + self.__points = [] + @property def points(self): """ diff --git a/main_window.py b/main_window.py index 26b5afe..7d60dd1 100644 --- a/main_window.py +++ b/main_window.py @@ -2,7 +2,7 @@ from functools import partial from PyQt5.QtCore import Qt from PyQt5.QtGui import QCursor -from PyQt5.QtWidgets import QFileDialog, QMainWindow +from PyQt5.QtWidgets import QFileDialog, QInputDialog, QMainWindow from clusterview.exceptions import handle_exceptions from clusterview.colors import Color @@ -10,10 +10,12 @@ from clusterview.mode import Mode from clusterview.mode_handlers import (group, MODE_HANDLER_MAP, ogl_keypress_handler, refresh_point_list, - reset_centroid_count_and_colors) + reset_centroid_count_and_colors, + generate_random_points) from clusterview.opengl_widget import (clear_selection, initialize_gl, mouse_leave, paint_gl, resize_gl, set_drawing_context) +from clusterview.points import PointSet from clusterview.point_manager import PointManager from clusterview.point_list_widget import item_click_handler from clusterview_ui import Ui_MainWindow @@ -34,6 +36,20 @@ class MainWindow(QMainWindow, Ui_MainWindow): super(MainWindow, self).__init__(parent) self.setupUi(self) + # Size of point for drawing + self.__point_size = 8 + + # TODO: THESE ARE HARD CODED TO THE CURRENT QT WIDGET SIZES + # FIX THIS PROPERLY WITH A RESIZE EVENT DETECT. + # PointManager is a class that is filled with static methods + # designed for managing state. + self.__viewport_width = 833 + self.__viewport_height = 656 + + PointManager.point_set = PointSet(self.__point_size, + self.__viewport_width, + self.__viewport_height) + # Spin box should only allow the number of centroids to be no # greater than the number of supported colors minus 2 to exclude # the color for selection (Color.BLUE) and the default color for points @@ -90,6 +106,9 @@ class MainWindow(QMainWindow, Ui_MainWindow): self.action_delete_points.triggered.connect(self.__delete_points) self.action_move_points.triggered.connect(self.__move_points) + (self.action_generate_random_points + .triggered.connect(self.__generate_random_points)) + self.action_save_point_configuration.triggered.connect( self.__save_points_file) @@ -173,6 +192,22 @@ class MainWindow(QMainWindow, Ui_MainWindow): PointManager.centroids = [] reset_centroid_count_and_colors() + def __generate_random_points(self): + value, ok = QInputDialog.getInt(self, "Number of Points", + "Number of Points:", 30, 30, 3000, 1) + + if ok: + self.__mode = Mode.ADD + generate_random_points(value, + (self.__viewport_width - self.__point_size), + (self.__viewport_height - self.__point_size) + ) + self.__mode = Mode.OFF + + self.opengl_widget.update() + + refresh_point_list(self) + @property def mode(self): """ diff --git a/tests/test_point_set.py b/tests/test_point_set.py index 88a192b..965e5e2 100644 --- a/tests/test_point_set.py +++ b/tests/test_point_set.py @@ -9,6 +9,17 @@ def test_empty(): assert point_set.empty() +def test_clear(): + point_set = PointSet(3, 100, 100) + + point_set.add_point(1, 2, Color.GREY) + + assert len(list(point_set.points)) == 1 + + point_set.clear() + + assert len(list(point_set.points)) == 0 + def test_add_to_point_set(): point_set = PointSet(3, 100, 100)