A computational geometry learning and experimentation tool.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

241 lines
6.5 KiB

"""
This module defines functions that need to be overwritten
in order for OpenGL to work with the main window. This
module is named the same as the actual widget in order
to make namespacing consistent.
To be clear, the actual widget is defined in the UI
generated code - `clusterview_ui.py`. The functions
here are imported as overrides to the OpenGL functions of
that widget.
"""
from enum import Enum
from OpenGL.GL import (glBegin, glClearColor, glColor4f, glEnable,
glEnd, GL_LIGHT0, GL_LIGHTING, GL_POINTS,
glPointSize, glVertex3f, glViewport)
from .exceptions import InvalidModeError, InvalidStateError
from .mode import Mode
class Color(Enum):
BLUE = 0
# A simple map from Color -> RGBA 4-Tuple
# Note: The color values in the tuple are not RGB, but
# rather OpenGL percentage values for RGB.
COLOR_TO_RGBA = {
Color.BLUE: (0, 0.5, 1.0, 0.0)
}
# Size of point for drawing
__POINT_SIZE = 8
# Constants set based on the size of the window.
__BOTTOM_LEFT = (0, 0)
__WIDTH = None
__HEIGHT = None
# Module-global state variables for our drawing
# state machine.
#
# Below functions have to mark these as `global` so
# the interpreter knows that the variables are not
# function local.
__current_mode = None
__current_event = None
__current_context = None
def set_drawing_context(ctx):
"""
Sets the drawing context so that drawing functions can properly
interact with the widget.
"""
global __current_context
print("CALLING SET DRAWING CONTEXT: {}".format(ctx))
__current_context = ctx
print("WIDTH OF OPENGL WINDOW: {}".format(__WIDTH))
print("HEIGHT OF OPENGL WINDOW: {}".format(__HEIGHT))
print("SETTING: {}".format(__current_context))
def set_drawing_mode(mode):
"""
State management function. It is useful to look at the
different drawing modes as modes in a state machine.
Calling this function when a mode changes allows the
OpenGL functions to take the correct drawing action
on the OpenGL Widget.
@param mode The current mode.
"""
global __current_context
global __current_mode
print("SET DRAWING MODE CONTEXT: {}".format(__current_context))
if __current_context is None:
raise InvalidStateError("Drawing context must be set before setting " +
"drawing mode")
if not isinstance(mode, Mode):
raise ValueError("Mode in set_drawing_mode must be of type Mode")
print("CALL FROM SET_DRAWING_MODE(MODE = {})".format(mode))
__current_mode = mode
print("SET LOCALS (CURRENT MODE: {})".format(__current_mode))
def set_drawing_event(event):
"""
State machine event management function.
@param event The event.
"""
global __current_context
global __current_event
if __current_context is None:
raise InvalidStateError("Drawing context must be set before setting " +
"drawing mode")
print("CALL FROM SET_DRAWING_EVENT(event = {})".format(event))
if event is not None:
__current_event = event
print("SET LOCALS (CURRENT EVENT: {})".format(__current_event))
def initialize_gl():
"""
Initializes the OpenGL context on the Window.
"""
# Since we aren't using shaders lighting needs to be
# enabled.
glEnable(GL_LIGHTING);
glEnable(GL_LIGHT0);
# Set white background
glClearColor(255, 255, 255, 0)
def resize_gl(w, h):
"""
OpenGL resize handler used to get the current viewport size.
@param w The new width.
@param h The new height.
"""
global __WIDTH
global __HEIGHT
__WIDTH = __current_context.width()
__HEIGHT = __current_context.height()
def paint_gl():
"""
Stock PaintGL function from OpenGL that switches
on the current mode to determine what action to
perform on the current event.
"""
if (__current_mode in [Mode.ADD, Mode.EDIT, Mode.MOVE, Mode.DELETE] and
__current_event is None):
raise InvalidStateError("Event must exist for ADD, EDIT, MOVE, " +
"and DELETE")
if __current_mode is Mode.ADD:
# TODO: This needs to be modified to instead take the point list
# and redraw the entire list (which will have the new point
# added) each click.
draw_points(__current_event.x(), __current_event.y(), Color.BLUE)
elif __current_mode is Mode.EDIT:
raise NotImplementedError("Drawing for EDIT not implemented.")
elif __current_mode is Mode.MOVE:
raise NotImplementedError("Drawing for MOVE not implemented.")
elif __current_mode is Mode.DELETE:
raise NotImplementedError("Drawing for DELETE not implemented.")
def __clamp_x(x):
"""
X-coordinate clamping function that goes from mouse coordinates to
OpenGL coordinates.
@param x The x-coordinate to clamp.
@returns The clamped x coordinate.
"""
x_w = (x / (__WIDTH / 2.0) - 1.0)
print(x_w)
return x_w
def __clamp_y(y):
"""
Y-coordinate clamping function that goes from mouse coordinates to
OpenGL coordinates.
@param y The y-coordinate to clamp.
@returns The clamped y coordinate.
"""
y_w = -1.0 * (y / (__HEIGHT / 2.0) - 1.0)
print(y_w)
return y_w
def draw_points(x, y, color):
"""
Simple point drawing function.
Given a coordinate (x, y), and a Color enum this
function will draw the given point with the given
color.
@param x The x-coordinate.
@param y The y-coordinate.
@param color The Color Enum.
"""
global __current_context
if __current_context is None:
raise InvalidStateError("Drawing context must be set before setting " +
"drawing mode")
if not isinstance(color, Color):
raise ValueError("Color must exist in the Color enumeration")
ct = COLOR_TO_RGBA[color]
print("DRAW POINT - DRAWING WITH COLOR {}".format(ct))
glViewport(0, 0, __WIDTH, __HEIGHT)
glPointSize(__POINT_SIZE)
glColor4f(ct[0], ct[1], ct[2], ct[3])
glBegin(GL_POINTS)
glVertex3f(__clamp_x(__current_event.x()),
__clamp_y(__current_event.y()),
0.0) # Z is currently fixed to 0
glEnd()
def delete_point(x, y):
"""
Deletes a point.
The list deletion happens in the clusterview.mode module. This
function just overwrites the point color with the background.
@param x The x-coordinate.
@param y The y-coordinate.
"""
raise NotImplementedError("delete_point not implemented.")