Taylor Bockman
5 years ago
11 changed files with 364 additions and 105 deletions
@ -0,0 +1,63 @@
|
||||
from .mode import Mode |
||||
from .opengl_widget import set_drawing_event |
||||
|
||||
def __handle_add_point(ctx, event): |
||||
""" |
||||
Event handler for the add point mode. |
||||
|
||||
Sets the drawing mode for the OpenGL Widget using |
||||
`set_drawing_mode`, converts a point to our point |
||||
representation, and adds it to the list. |
||||
""" |
||||
print("[ADD] GOT POINT: ({}, {})".format(event.x(), event.y())) |
||||
|
||||
set_drawing_event(event) |
||||
ctx.update() |
||||
# Convert to our point representation and add to list widget |
||||
# Point representation is a class called Point with coordinates, |
||||
# and attributes (currently always None) |
||||
|
||||
def __handle_edit_point(ctx, event): |
||||
# TODO: This function and delete definitely need to make sure they are |
||||
# on a point we have. |
||||
# |
||||
# Since points are unique consider a hashmap of points to make O(1) |
||||
# lookups for addition and deletion. This list can be maintained here |
||||
# in this module. It should be a dictionary - from point to |
||||
# attributes in the case of algorithms that require points to have |
||||
# weights or something. |
||||
# |
||||
# Should move the associated point in the list to the new location if |
||||
# applicable. |
||||
print("[EDIT] GOT POINT: ({}, {})".format(event.x(), event.y())) |
||||
|
||||
# Store old x, y from event |
||||
set_drawing_event(event) |
||||
ctx.update() |
||||
# after this remove the point from the list |
||||
|
||||
def __handle_move_points(ctx, event): |
||||
# TODO: Should move the associated points in the list to the new location. |
||||
print("[MOVE] Pressed - NOTE NEED DRAG EVENT") |
||||
# Store list of old points that are captured |
||||
|
||||
set_drawing_event(event) |
||||
|
||||
# Find and move all points from the old list to their new locations |
||||
|
||||
def __handle_delete_point(ctx, event): |
||||
print("[DELETE] GOT POINT: ({}, {})".format(event.x(), event.y())) |
||||
|
||||
set_drawing_event(event) |
||||
|
||||
# Find the point from event and remove it from the list |
||||
|
||||
# Simple dispatcher to make it easy to dispatch the right mode |
||||
# function when the OpenGL window is clicked. |
||||
MODE_HANDLER_MAP = { |
||||
Mode.OFF: lambda: None, |
||||
Mode.ADD: __handle_add_point, |
||||
Mode.EDIT: __handle_edit_point, |
||||
Mode.MOVE: __handle_move_points, |
||||
Mode.DELETE: __handle_delete_point |
||||
} |
@ -0,0 +1,65 @@
|
||||
class Attribute: |
||||
__name = None |
||||
__value = None |
||||
|
||||
def __init__(self, name, value): |
||||
""" |
||||
Initializes an attribute. |
||||
""" |
||||
self.__name = name |
||||
self.__value = value |
||||
|
||||
|
||||
class PointSet: |
||||
""" |
||||
Useful point set for storing coordinates and attributes. It is |
||||
backed by a set to provide nice convenience functions. |
||||
""" |
||||
__points = set() |
||||
__attributes = {} |
||||
|
||||
def add_point(self, x, y, attrs=[]): |
||||
""" |
||||
Adds a point in screen coordinates and an optional attribute to |
||||
the list. |
||||
|
||||
@param x The x-coordinate. |
||||
@param y The y-coordinate. |
||||
@param attr An optional attribute. |
||||
""" |
||||
|
||||
if attrs != [] and not all(isinstance(x, Attribute) for x in attrs): |
||||
raise ValueError("Attributes in add_point must be an " + |
||||
"attribute array.") |
||||
|
||||
point = (x, y) |
||||
self.__points.add(point) |
||||
self.__attributes[point] = attrs |
||||
|
||||
|
||||
def remove_point(self, x, y): |
||||
""" |
||||
Removes a point and it's attributes from the point set. |
||||
""" |
||||
point = (x, y) |
||||
self.__points.discard(point) |
||||
self.__attributes.pop(point) |
||||
|
||||
|
||||
def attributes(self, x, y): |
||||
""" |
||||
Returns the attribute array for a given point. |
||||
|
||||
@param x The x-coordinate of the point. |
||||
@param y The y-coordinate of the point. |
||||
""" |
||||
return self.__attributes[(x, y)] |
||||
|
||||
@property |
||||
def points(self): |
||||
""" |
||||
Getter for points. Returns a generator for |
||||
looping. |
||||
""" |
||||
for point in self.__points: |
||||
yield point |
@ -1,24 +1,36 @@
|
||||
atomicwrites==1.3.0 |
||||
attrs==19.1.0 |
||||
backcall==0.1.0 |
||||
coverage==4.5.4 |
||||
Cython==0.29.13 |
||||
decorator==4.4.0 |
||||
entrypoints==0.3 |
||||
flake8==3.7.8 |
||||
importlib-metadata==0.19 |
||||
ipython==7.7.0 |
||||
ipython-genutils==0.2.0 |
||||
jedi==0.14.1 |
||||
mccabe==0.6.1 |
||||
more-itertools==7.2.0 |
||||
packaging==19.1 |
||||
parso==0.5.1 |
||||
pexpect==4.7.0 |
||||
pickleshare==0.7.5 |
||||
pluggy==0.12.0 |
||||
prompt-toolkit==2.0.9 |
||||
ptyprocess==0.6.0 |
||||
py==1.8.0 |
||||
pycodestyle==2.5.0 |
||||
pyflakes==2.1.1 |
||||
Pygments==2.4.2 |
||||
PyOpenGL==3.1.0 |
||||
PyOpenGL-accelerate==3.1.3b1 |
||||
pyparsing==2.4.2 |
||||
PyQt5==5.13.0 |
||||
PyQt5-sip==4.19.18 |
||||
pytest==5.0.1 |
||||
pytest-cov==2.7.1 |
||||
six==1.12.0 |
||||
traitlets==4.3.2 |
||||
wcwidth==0.1.7 |
||||
zipp==0.5.2 |
||||
|
@ -0,0 +1,52 @@
|
||||
import pytest |
||||
|
||||
from clusterview.points import Attribute, PointSet |
||||
|
||||
|
||||
def test_add_to_point_set(): |
||||
l = PointSet() |
||||
|
||||
l.add_point(1, 2) |
||||
|
||||
points = list(l.points) |
||||
|
||||
assert len(points) == 1 |
||||
assert points[0] == (1, 2) |
||||
assert len(l.attributes(1, 2)) == 0 |
||||
|
||||
def test_add_to_point_set_with_attributes(): |
||||
attribute = Attribute("thing", 1) |
||||
|
||||
l = PointSet() |
||||
l.add_point(1, 2, attrs=[attribute]) |
||||
|
||||
points = list(l.points) |
||||
attrs = l.attributes(1, 2) |
||||
|
||||
assert len(points) == 1 |
||||
assert points[0] == (1, 2) |
||||
assert len(l.attributes(1, 2)) == 1 |
||||
|
||||
def test_remove_point(): |
||||
attribute = Attribute("thing", 1) |
||||
|
||||
l = PointSet() |
||||
l.add_point(1, 2, attrs=[attribute]) |
||||
|
||||
l.remove_point(1, 2) |
||||
|
||||
points = list(l.points) |
||||
|
||||
assert len(points) == 0 |
||||
|
||||
with pytest.raises(KeyError): |
||||
# We expect a call to attributes on a removed |
||||
# point to raise a KeyError because it no |
||||
# longer exists in the point -> attribute_list |
||||
# dictionary. |
||||
l.attributes(1, 2) |
||||
|
||||
def test_attributes_must_be_array_of_attributes(): |
||||
with pytest.raises(ValueError): |
||||
l = PointSet() |
||||
l.add_point(1, 2, attrs=[1,2,3,4,5]) |
Loading…
Reference in new issue