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