blob: ce2118aa976a0f6bc7506f2448ddfb6a162d6eaf [file] [log] [blame]
Tabitha Jarvisdd46c602018-12-12 20:25:27 -08001#!/usr/bin/python3
2
John Park1aaadc72018-11-04 13:13:08 -08003from __future__ import print_function
4import os
5import basic_window
6import random
7import gi
8import numpy as np
9import scipy.spatial.distance
10gi.require_version('Gtk', '3.0')
11from gi.repository import Gdk
12import cairo
13
14import enum
15import csv # For writing to csv files
16
17from basic_window import OverrideMatrix, identity, quit_main_loop
18
19LENGTH_OF_FIELD = 323.65
20PIXELS_ON_SCREEN = 300
21
22def pxToIn(p):
23 return p*LENGTH_OF_FIELD/PIXELS_ON_SCREEN
24
25def inToPx(i):
26 return i*PIXELS_ON_SCREEN/LENGTH_OF_FIELD
27
28def px(cr):
29 return OverrideMatrix(cr, identity)
30
31def draw_px_cross(cr, x, y, length_px, r, g, b):
32 """Draws a cross with fixed dimensions in pixel space."""
33 cr.set_source_rgb(r, g, b)
34 cr.move_to(x, y - length_px)
35 cr.line_to(x, y + length_px)
36 cr.stroke()
37
38 cr.move_to(x - length_px, y)
39 cr.line_to(x + length_px, y)
40 cr.stroke()
41
42def draw_px_x(cr, x, y, length_px1, r, g, b):
43 """Draws a x with fixed dimensions in pixel space."""
44 length_px = length_px1 / np.sqrt(2)
45 cr.set_source_rgb(r, g, b)
46 cr.move_to(x - length_px, y - length_px)
47 cr.line_to(x + length_px, y + length_px)
48 cr.stroke()
49
50 cr.move_to(x - length_px, y + length_px)
51 cr.line_to(x + length_px, y - length_px)
52 cr.stroke()
53
54def draw_points(cr, p, size):
55 for i in range(0, len(p)):
56 draw_px_cross(cr, p[i][0], p[i][1], size, 0, np.sqrt(0.2 * i), 0)
57
58class Mode(enum.Enum):
59 kViewing = 0
60 kPlacing = 1
61 kEditing = 2
62 kExporting = 3
63 kImporting = 4
64
65def display_text(cr, text, widtha, heighta, widthb, heightb):
66 cr.scale(widtha, -heighta)
67 cr.show_text(text)
68 cr.scale(widthb, -heightb)
69
70# Create a GTK+ widget on which we will draw using Cairo
71class GTK_Widget(basic_window.BaseWindow):
72 def __init__(self):
73 super(GTK_Widget, self).__init__()
74
75 # init field drawing
76 # add default spline for testing purposes
77 # init editing / viewing modes and pointer location
78 self.mode = Mode.kPlacing
79 self.x = 0
80 self.y = 0
81
82 self.switch = True
83
84 # update list of control points
85 self.point_selected = False
86 # self.adding_spline = False
87 self.index_of_selected = -1
88 self.new_point = []
89
90 # For the editing mode
91 self.index_of_edit = -1 # Can't be zero beause array starts at 0
92 self.held_x = 0
93
94 # Theo take them from here?
95 self.selected_points = []
96
97 self.reinit_extents()
98
99 #John also wrote this
100 def add_point(self, x, y):
101 if(len(self.selected_points)<4):
102 self.selected_points.append([x,y])
103
104 """set extents on images, this needs to be redone with proper distances"""
105 def reinit_extents(self):
106 self.extents_x_min = -800
107 self.extents_x_max = 800
108 self.extents_y_min = -800
109 self.extents_y_max = 800
110
111 # this needs to be rewritten with numpy, i dont think this ought to have
112 # SciPy as a dependecy
113 def get_index_of_nearest_point(self):
114 cur_p = [[self.x, self.y]]
115 distances = scipy.spatial.distance.cdist(cur_p, self.all_controls)
116
117 return np.argmin(distances)
118
119 # return the closest point to the loc of the click event
120 def get_nearest_point(self):
121 return self.all_controls[self.get_index_of_nearest_point()]
122
123 # Handle the expose-event by updating the Window and drawing
124 def handle_draw(self, cr):
125 print(self.new_point)
126 print("SELF.POINT_SELECTED: " + str(self.point_selected))
127
128 # begin drawing
129 # Fill the background color of the window with grey
130 cr.set_source_rgb(0.5, 0.5, 0.5)
131 cr.paint()
132
133 # Draw a extents rectangle
134 cr.set_source_rgb(1.0, 1.0, 1.0)
135 cr.rectangle(self.extents_x_min, self.extents_y_min,
136 (self.extents_x_max - self.extents_x_min),
137 self.extents_y_max - self.extents_y_min)
138 cr.fill()
139
140 #Drawing the switch and scale in the field
141 cr.move_to(0, 50)
142 cr.show_text('Press "e" to export')
143 cr.show_text('Press "i" to import')
144
145 cr.set_source_rgb(0.3,0.3,0.3)
146 cr.rectangle(-150,-150,300,300)
147 cr.fill()
148 cr.set_source_rgb(0, 0, 0)
149 cr.rectangle(-150,-150,300,300)
150 cr.set_line_join(cairo.LINE_JOIN_ROUND)
151 cr.stroke()
152 cr.set_source_rgb(0, 0, 0)
153 cr.rectangle(inToPx(140-161.825),inToPx(76.575),inToPx(56),inToPx(-153.15))
154 cr.set_line_join(cairo.LINE_JOIN_ROUND)
155 cr.stroke()
156
157 cr.rectangle(inToPx(161.825-24),inToPx(90),inToPx(24),inToPx(-180))
158 cr.set_line_join(cairo.LINE_JOIN_ROUND)
159 cr.stroke()
160
161 cr.set_source_rgb(0.2, 0.2, 0.2)
162 cr.rectangle(inToPx(140-161.825),inToPx(76.575),inToPx(56),inToPx(-153.15))
163 cr.fill()
164
165 cr.rectangle(inToPx(161.825-24),inToPx(90),inToPx(24),inToPx(-180))
166 cr.fill()
167
168 # update all the things
169
170 if self.mode == Mode.kViewing:
171 cr.set_source_rgb(0, 0, 0)
172 cr.move_to(-300, 170)
173 cr.show_text("VIEWING")
174 cr.set_source_rgb(0.5, 0.5, 0.5)
175 # its gonna check for points_added from button_press_action
176 # The behavior of the click is such that it runs twice
177 # This is consistant with graph_edit.py which someone smart wrote
178 # So I'm just going to delete the last element in order to not get
179 # repeating points
180 if len(self.selected_points) > 0:
181 print("SELECTED_POINTS: " + str(len(self.selected_points)))
182 print("ITEMS:")
183 for item in self.selected_points:
184 print(str(item))
185 for i, point in enumerate(self.selected_points):
186 print("I: " + str(i))
187 draw_px_x(cr, point[0], point[1], 10, 0,
188 0, 0)
189 cr.move_to(point[0], point[1]-15)
190 display_text(cr, str(i), 0.5, 0.5, 2, 2)
191
192 if self.mode == Mode.kPlacing:
193 cr.set_source_rgb(0, 0, 0)
194 cr.move_to(-300, 170)
195 display_text(cr, "ADD", 1, 1, 1, 1)
196 cr.set_source_rgb(0.5, 0.5, 0.5)
197 # its gonna check for points_added from button_press_action
198 # The behavior of the click is such that it runs twice
199 # This is consistant with graph_edit.py which someone smart wrote
200 # So I'm just going to delete the last element in order to not get
201 # repeating points
202 if len(self.selected_points) > 0:
203 print("SELECTED_POINTS: " + str(len(self.selected_points)))
204 print("ITEMS:")
205 for item in self.selected_points:
206 print(str(item))
207 for i, point in enumerate(self.selected_points):
208 print("I: " + str(i))
209 draw_px_x(cr, point[0], point[1], 10, 0,
210 0, 0)
211 cr.move_to(point[0], point[1]-15)
212 display_text(cr, str(i), 0.5, 0.5, 2, 2)
213 if(i==3):
214 self.mode = Mode.kEditing
215
216 elif self.mode == Mode.kEditing:
217 cr.set_source_rgb(0, 0, 0)
218 cr.move_to(-300, 170)
219 display_text(cr, "EDITING", 1, 1, 1, 1)
220 cr.set_source_rgb(0.5, 0.5, 0.5)
221 if len(self.selected_points) > 0:
222 print("SELECTED_POINTS: " + str(len(self.selected_points)))
223 print("ITEMS:")
224 for item in self.selected_points:
225 print(str(item))
226 for i, point in enumerate(self.selected_points):
227 print("I: " + str(i))
228 draw_px_x(cr, point[0], point[1], 10, 0,
229 0, 0)
230 cr.move_to(point[0], point[1]-15)
231 display_text(cr, str(i), 0.5, 0.5, 2, 2)
232
233 elif self.mode == Mode.kExporting:
234 cr.set_source_rgb(0, 0, 0)
235 cr.move_to(-300, 170)
236 display_text(cr, "VIEWING", 1, 1, 1, 1)
237 cr.set_source_rgb(0.5, 0.5, 0.5)
238 #its gonna check for points_added from button_press_action
239
240 # The behavior of the click is such that it runs twice
241 # This is consistant with graph_edit.py which someone smart wrote
242 # So I'm just going to delete the last element in order to not get
243 # repeating points
244 if len(self.selected_points) > 0:
245 print("SELECTED_POINTS: " + str(len(self.selected_points)))
246 print("ITEMS:")
247 for item in self.selected_points:
248 print(str(item))
249 for i, point in enumerate(self.selected_points):
250 print("I: " + str(i))
251 draw_px_x(cr, point[0], point[1], 10, 0,
252 0, 0)
253 cr.move_to(point[0], point[1]-15)
254 display_text(cr, str(i), 0.5, 0.5, 2, 2)
255 elif self.mode == Mode.kImporting:
256 cr.set_source_rgb(0, 0, 0)
257 cr.move_to(-300, 170)
258 display_text(cr, "VIEWING", 1, 1, 1, 1)
259 cr.set_source_rgb(0.5, 0.5, 0.5)
260 # its gonna check for points_added from button_press_action
261
262 # The behavior of the click is such that it runs twice
263 # This is consistant with graph_edit.py which someone smart wrote
264 # So I'm just going to delete the last element in order to not get
265 # repeating points
266 if len(self.selected_points) > 0:
267 print("SELECTED_POINTS: " + str(len(self.selected_points)))
268 print("ITEMS:")
269 for item in self.selected_points:
270 print(str(item))
271 for i, point in enumerate(self.selected_points):
272 print("I: " + str(i))
273 draw_px_x(cr, point[0], point[1], 10, 0,
274 0, 0)
275 cr.move_to(point[0], point[1]-15)
276 display_text(cr, str(i), 0.5, 0.5, 2, 2)
277
278 cr.paint_with_alpha(.65)
279
280 draw_px_cross(cr, self.x, self.y, 10, 1, 0, 0)
281
282 def do_key_press(self, event):
283 keyval = Gdk.keyval_to_lower(event.keyval)
284 print("Gdk.KEY_" + Gdk.keyval_name(keyval))
285 if keyval == Gdk.KEY_q:
286 print("Found q key and exiting.")
287 quit_main_loop()
288 if keyval == Gdk.KEY_e:
289 self.mode = Mode.kExporting
290 # Will export to csv file
291 with open('points_for_pathedit.csv', mode='w') as points_file:
292 writer = csv.writer(points_file, delimiter=',', quotechar='"',
293 quoting=csv.QUOTE_MINIMAL)
294 for item in self.selected_points:
295 writer.writerow([str(item[0]), str(item[1])])
296 print("Wrote: " + str(item[0]) + " " + str(item[1]))
297 if keyval == Gdk.KEY_i:
298 self.mode = Mode.kImporting
299 # import from csv file
300 self.selected_points = []
301 with open('points_for_pathedit.csv') as points_file:
302 reader = csv.reader(points_file, delimiter=',')
303 for row in reader:
304 self.add_point(float(row[0]), float(row[1]))
305 print("Added: " + row[0] + " " + row[1])
306
307 self.redraw()
308
309 def button_press_action(self):
310 if self.switch:
311 self.switch = False
312 if self.mode == Mode.kPlacing:
313 #Check that the point clicked is on the field
314 if(self.x<150 and self.x>-150 and self.y <150 and self.y >-150):
315 self.add_point(self.x, self.y)
316 if self.mode == Mode.kEditing:
317 # Now after index_of_edit is not -1, the point is selected, so
318 # user can click for new point
319 print("INDEX OF EDIT: " + str(self.index_of_edit))
320
321 if self.index_of_edit > -1 and self.held_x != self.x:
322 print("INDEX OF EDIT: " + str(self.index_of_edit))
323 self.selected_points[self.index_of_edit] = [self.x, self.y]
324 self.index_of_edit = -1
325 else:
326 print("mode == 2")
327 # Get clicked point
328 # Find nearest
329 # Move nearest to clicked
330 cur_p = [self.x, self.y]
331 print("CUR_P: " + str(self.x) + " " + str(self.y))
332 # What I wanna do is get each point
333 # Get the distance between each for x and y
334 # Save the index of the point closest
335 nearest = 1000
336 index = 0
337 for ind, i in enumerate(self.selected_points):
338 # pythagorean
339 distance = np.sqrt((cur_p[0] - i[0])**2 + (cur_p[1] - i[1])**2)
340 if distance < nearest:
341 nearest = distance
342 index = ind
343 print("Nearest: " + str(nearest))
344 print("Index: " + str(index))
345 self.index_of_edit = index
346 self.held_x = self.x
347 else:
348 self.switch = True
349
350 self.redraw()
351
352
353 def do_button_press(self, event):
354 print("button press activated")
355 self.x = event.x
356 self.y = event.y
357 self.button_press_action()
358
359
360
361silly = GTK_Widget()
362basic_window.RunApp()