diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 404d6cb..f1a50d2 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -7,7 +7,7 @@ Before a PR is accepted it must pass the following requirements in CircleCI: - [ ] All tests must pass - [ ] The code must be lint free as determined by `flake8` -Additionally, any new code included in the PR must be tested fully. +Additionally, any new code included in the PR must be tested fully. ## Developer Requirements @@ -23,7 +23,7 @@ This will install all normal requirements as well as testing requirements. ## Linting -We use `flake8` for linting. +We use `flake8` for linting. Run `python -m flake8` in order to get a lint report. @@ -53,14 +53,14 @@ pyuic5 clusterview.ui clusterview_ui.py ### Import Organization Import organization is a critical part of good software engineering. In large -projects considerable time can be wasted looking for a specific import. +projects considerable time can be wasted looking for a specific import. The imports must be organized as follows: ```python # System imports first -# Third party imports second +# Third party imports second # UNLV/ClusterView modules external to the current module third @@ -93,7 +93,7 @@ add two underscores to the prefix of the method name: def hello_world(): print("Hello, world!") - + # This method can only be seen by the module/class it is defined # in. @@ -104,3 +104,45 @@ def __hello_module(): We only want to expose the absolute bare minimum number of functions to the consumers of our modules. + +## Overview of Function + +In order to understand how things are drawn and maintained there are some classes you need to know. + +### Modes + +Lambas, partially applied functions, and function passing are used throughout the application to not only improve +readability but also improve modularity of the code. You can see modes in `clusterview/mode.py`. These modes are used +to put the application in a global state for adding, editing, moving, and deleting things. + +In order to improve readability `main_window.py`, the main application class module, uses some neat function passing +tricks to determine which modes to use in `clusterview/mode_handlers.py`. The `mode_handlers.py` module is fairly +complicated but defines basically all of the mode handling code used for each mode in the application. + +### Point + +The `Point` class is the base class for all drawn points. It contains important details for calculating location +in space such as it's containing viewport, it's x and y coordinates in the viewport, it's drawn size, it's color, +and a list of optional attributes. + +### PointSet + +A `PointSet` is a convenient holder for all points on a screen. It contains methods that simplify adding to, removing, +moving, and deleting points from the canvas. It maintains a constant viewport state, point size, and other useful +attributes so that you do not need to concern yourself with them during use. + +### PointManager + +The `PointManager` is a global singleton that is shared across the entire application. You can think of the +`PointManager` as the absolute source of truth for the state of points in the application. In addition to maintaining +a global `PointSet`, it also maintains the `save` and `load` configuration features so that they are consistent +each time they are used. + +### Grouping Points + +Each point can be grouped by color, defined in `clusterview/colors.py` in the global `PointSet`. This way you +do not need to explicitly maintain sets of points representing groups, and can instead call the `groups` function +on the `PointSet` to return to you a dictionary from `color.Color` to `Point` representing each group and their +member points. + + diff --git a/README.md b/README.md index ed9fcab..576c13c 100644 --- a/README.md +++ b/README.md @@ -8,13 +8,13 @@ A project for viewing, manipulating, and learning clustering algorithms in Compu First, make sure you have python installed. If not, follow the installation instructions for your distribution. -First: +First: ```sh sudo pip3 install virtualenv ``` -To make sure you have a working `virtualenv`. +To make sure you have a working `virtualenv`. Now, start `virtualenv`: @@ -40,3 +40,4 @@ python3 clusterview.py ``` To start the software. + diff --git a/clusterview/points.py b/clusterview/points.py index f941b60..6dd319d 100644 --- a/clusterview/points.py +++ b/clusterview/points.py @@ -341,3 +341,20 @@ class PointSet: for p in self.__points: if p.hit(x, y): self.__points.remove(p) + + def groups(self): + """ + Returns a map from color to point representing each point's group + membership based on color. + """ + g = {} + + for p in self.__points: + if p.color not in g: + # Create the key for the group color since it does + # not exist. + g[p.color] = [] + + g[p.color].append(p) + + return g diff --git a/tests/test_point_set.py b/tests/test_point_set.py index 95c0efe..88a192b 100644 --- a/tests/test_point_set.py +++ b/tests/test_point_set.py @@ -90,3 +90,25 @@ def test_clear_all_selected_points(): unselected += 1 assert unselected == 2 + + +def test_groups(): + point_set = PointSet(8, 100, 100) + point_set.add_point(4, 4, Color.GREY) + point_set.add_point(5, 5, Color.GREY) + point_set.add_point(10, 4, Color.BLUE) + point_set.add_point(30, 5, Color.BLUE) + + p1 = Point(4, 4, Color.GREY, 8, 100, 100) + p2 = Point(5, 5, Color.GREY, 8, 100, 100) + p3 = Point(10, 4, Color.BLUE, 8, 100, 100) + p4 = Point(30, 5, Color.BLUE, 8, 100, 100) + + expected = { + Color.GREY: [p1, p2], + Color.BLUE: [p3, p4] + } + + groups = point_set.groups() + + assert groups == expected