blob: f11b47cb6605f665f5b045e7e13371fdc17da846 [file] [log] [blame]
Tabitha Jarvis1007a132018-12-12 21:47:54 -08001#!/usr/bin/python3
Tabitha Jarvis1007a132018-12-12 21:47:54 -08002from __future__ import print_function
3import os
Andrew Runke0f945fd2019-01-27 21:10:37 -08004import sys
Andrew Runke6842bf92019-01-26 15:38:25 -08005import copy
Tabitha Jarvis1007a132018-12-12 21:47:54 -08006import basic_window
7from color import Color, palette
8import random
9import gi
10import numpy as np
Andrew Runke6842bf92019-01-26 15:38:25 -080011from libspline import Spline
Tabitha Jarvis1007a132018-12-12 21:47:54 -080012import scipy.spatial.distance
13gi.require_version('Gtk', '3.0')
Andrew Runke6842bf92019-01-26 15:38:25 -080014from gi.repository import Gdk, Gtk, GLib
Tabitha Jarvis1007a132018-12-12 21:47:54 -080015import cairo
Tabitha Jarvis1007a132018-12-12 21:47:54 -080016import enum
Andrew Runke0f945fd2019-01-27 21:10:37 -080017import json # For writing to json files
Tabitha Jarvis1007a132018-12-12 21:47:54 -080018
19from basic_window import OverrideMatrix, identity, quit_main_loop, set_color
20
John Park13d3e282019-01-26 20:16:48 -080021WIDTH_OF_FIELD_IN_METERS = 8.258302
Tabitha Jarvis1007a132018-12-12 21:47:54 -080022PIXELS_ON_SCREEN = 300
23
Andrew Runke6842bf92019-01-26 15:38:25 -080024
John Park13d3e282019-01-26 20:16:48 -080025def pxToM(p):
26 return p * WIDTH_OF_FIELD_IN_METERS / PIXELS_ON_SCREEN
Andrew Runke6842bf92019-01-26 15:38:25 -080027
Tabitha Jarvis1007a132018-12-12 21:47:54 -080028
John Parka30a7782019-02-01 18:47:26 -080029def mToPx(m):
30 return (m*PIXELS_ON_SCREEN/WIDTH_OF_FIELD_IN_METERS)
Tabitha Jarvis1007a132018-12-12 21:47:54 -080031
32def px(cr):
33 return OverrideMatrix(cr, identity)
34
Andrew Runke6842bf92019-01-26 15:38:25 -080035
Tabitha Jarvis1007a132018-12-12 21:47:54 -080036def draw_px_cross(cr, x, y, length_px, color=palette["RED"]):
37 """Draws a cross with fixed dimensions in pixel space."""
38 set_color(cr, color)
39 cr.move_to(x, y - length_px)
40 cr.line_to(x, y + length_px)
41 cr.stroke()
42
43 cr.move_to(x - length_px, y)
44 cr.line_to(x + length_px, y)
45 cr.stroke()
46 set_color(cr, palette["LIGHT_GREY"])
47
Andrew Runke6842bf92019-01-26 15:38:25 -080048
Tabitha Jarvis1007a132018-12-12 21:47:54 -080049def draw_px_x(cr, x, y, length_px1, color=palette["BLACK"]):
50 """Draws a x with fixed dimensions in pixel space."""
51 length_px = length_px1 / np.sqrt(2)
52 set_color(cr, color)
53 cr.move_to(x - length_px, y - length_px)
54 cr.line_to(x + length_px, y + length_px)
55 cr.stroke()
56
57 cr.move_to(x - length_px, y + length_px)
58 cr.line_to(x + length_px, y - length_px)
59 cr.stroke()
60 set_color(cr, palette["LIGHT_GREY"])
61
Andrew Runke6842bf92019-01-26 15:38:25 -080062
Tabitha Jarvis1007a132018-12-12 21:47:54 -080063def draw_points(cr, p, size):
64 for i in range(0, len(p)):
Andrew Runke6842bf92019-01-26 15:38:25 -080065 draw_px_cross(cr, p[i][0], p[i][1], size, Color(
66 0, np.sqrt(0.2 * i), 0))
67
Tabitha Jarvis1007a132018-12-12 21:47:54 -080068
69class Mode(enum.Enum):
70 kViewing = 0
71 kPlacing = 1
72 kEditing = 2
73 kExporting = 3
74 kImporting = 4
Andrew Runke6842bf92019-01-26 15:38:25 -080075 kConstraint = 5
76
77
78class ConstraintType(enum.Enum):
79 kMaxSpeed = 0
80 kMaxAcceleration = 1
81
Tabitha Jarvis1007a132018-12-12 21:47:54 -080082
83def display_text(cr, text, widtha, heighta, widthb, heightb):
84 cr.scale(widtha, -heighta)
85 cr.show_text(text)
86 cr.scale(widthb, -heightb)
87
Andrew Runke6842bf92019-01-26 15:38:25 -080088
89def redraw(needs_redraw, window):
90 print("Redrew")
91 if not needs_redraw:
92 window.queue_draw()
93
94
95class Constraint():
96 def __init__(self, start, end, constraint, value):
97 self.start = start #Array with index and distance from start of spline
98 self.end = end #Array with index and distance from start of spline
99 self.constraint = constraint #INT
100 self.value = value #INT
101 if self.constraint == 0:
102 self.conName = "kMaxSpeed"
103 else:
104 self.conName = "kMaxAcceleration"
105
106 def toString(self):
107
108 return "START: " + str(self.start[0]) + ", " + str(
109 self.start[1]) + " | END: " + str(self.end[0]) + ", " + str(
110 self.end[1]) + " | " + str(self.conName) + ": " + str(
111 self.value)
112
113
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800114class GTK_Widget(basic_window.BaseWindow):
Andrew Runke6842bf92019-01-26 15:38:25 -0800115 """Create a GTK+ widget on which we will draw using Cairo"""
116
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800117 def __init__(self):
118 super(GTK_Widget, self).__init__()
119
120 # init field drawing
121 # add default spline for testing purposes
122 # init editing / viewing modes and pointer location
123 self.mode = Mode.kPlacing
124 self.x = 0
125 self.y = 0
126
Andrew Runke0f945fd2019-01-27 21:10:37 -0800127 module_path = os.path.dirname(os.path.realpath(sys.argv[0]))
128 self.path_to_export = os.path.join(module_path,
129 'points_for_pathedit.json')
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800130 # update list of control points
131 self.point_selected = False
132 # self.adding_spline = False
133 self.index_of_selected = -1
134 self.new_point = []
135
136 # For the editing mode
Andrew Runke6842bf92019-01-26 15:38:25 -0800137 self.index_of_edit = -1 # Can't be zero beause array starts at 0
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800138 self.held_x = 0
Andrew Runke6842bf92019-01-26 15:38:25 -0800139 self.spline_edit = -1
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800140
Andrew Runke6842bf92019-01-26 15:38:25 -0800141 self.curves = []
142
143 self.colors = []
144
145 for c in palette:
146 self.colors.append(palette[c])
147
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800148 self.selected_points = []
Andrew Runke6842bf92019-01-26 15:38:25 -0800149 self.splines = []
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800150 self.reinit_extents()
151
Andrew Runke6842bf92019-01-26 15:38:25 -0800152 self.inStart = None
153 self.inEnd = None
154 self.inConstraint = None
155 self.inValue = None
156 self.startSet = False
157
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800158 #John also wrote this
159 def add_point(self, x, y):
Andrew Runke6842bf92019-01-26 15:38:25 -0800160 if (len(self.selected_points) < 6):
John Park13d3e282019-01-26 20:16:48 -0800161 self.selected_points.append([pxToM(x), pxToM(y)])
Andrew Runke6842bf92019-01-26 15:38:25 -0800162 if (len(self.selected_points) == 6):
163 self.mode = Mode.kEditing
164 self.splines.append(np.array(self.selected_points))
165 self.selected_points = []
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800166
Andrew Runke6842bf92019-01-26 15:38:25 -0800167 """set extents on images"""
168
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800169 def reinit_extents(self):
170 self.extents_x_min = -800
171 self.extents_x_max = 800
172 self.extents_y_min = -800
173 self.extents_y_max = 800
174
175 # this needs to be rewritten with numpy, i dont think this ought to have
176 # SciPy as a dependecy
177 def get_index_of_nearest_point(self):
178 cur_p = [[self.x, self.y]]
179 distances = scipy.spatial.distance.cdist(cur_p, self.all_controls)
180
181 return np.argmin(distances)
182
183 # return the closest point to the loc of the click event
184 def get_nearest_point(self):
185 return self.all_controls[self.get_index_of_nearest_point()]
186
Andrew Runke6842bf92019-01-26 15:38:25 -0800187 def set_index_to_nearest_spline_point(self):
188 nearest = 50
189 index_of_closest = 0
190 self.spline_edit = 0
191 cur_p = [self.x, self.y]
192
193 for index_splines, points in enumerate(self.spline):
John Park13d3e282019-01-26 20:16:48 -0800194 for index_points, point in enumerate(points.curve):
Andrew Runke6842bf92019-01-26 15:38:25 -0800195 # pythagorean
John Park13d3e282019-01-26 20:16:48 -0800196 distance = np.sqrt((cur_p[0] - mToPx(point[0]))**2 +
197 (cur_p[1] - mToPx(point[1])**2))
Andrew Runke6842bf92019-01-26 15:38:25 -0800198 if distance < nearest:
199 nearest = distance
200 print("DISTANCE: ", distance, " | INDEX: ", index_points)
201 index_of_closest = index_points
202 self.index_of_edit = index_of_closest
203 self.spline_edit = index_splines
204 self.held_x = self.x
205 if self.startSet == False:
206 self.inStart = [self.index_of_edit, self.findDistance()]
207 self.startSet = True
208 else:
209 self.inEnd = [self.index_of_edit, self.findDistance()]
Andrew Runke6842bf92019-01-26 15:38:25 -0800210 self.startSet = False
211 self.mode = Mode.kEditing
212 self.spline_edit = -1
213 self.index_of_edit = -1
214
215 print("Nearest: " + str(nearest))
216 print("Spline: " + str(self.spline_edit))
217 print("Index: " + str(index_of_closest))
218
219 def findDistance(self):
220 """ findDistance goes through each point on the spline finding distance to that point from the point before.
221 It does this to find the the length of the spline to the point that is currently selected.
222 """
223 distance = 0
224 points = self.curves[self.spline_edit]
225 for index, point in enumerate(points):
226 if index > 0 and index <= self.index_of_edit:
227 distance += np.sqrt((points[index - 1][0] - point[0])**2 +
228 (points[index - 1][1] - point[1])**2)
John Park13d3e282019-01-26 20:16:48 -0800229 return distance
Andrew Runke6842bf92019-01-26 15:38:25 -0800230
John Parka30a7782019-02-01 18:47:26 -0800231 def draw_HAB(self, cr):
232 print("WENT IN")
233 # BASE Constants
234 X_BASE = -450+mToPx(2.41568)
235 Y_BASE = -150+mToPx(4.129151)
236
237 BACKWALL_X = -450
238
239 # HAB Levels 2 and 3 called in variables backhab
240
241 WIDTH_BACKHAB = mToPx(1.2192)
242
243 Y_TOP_BACKHAB_BOX = Y_BASE + mToPx(0.6096)
244 BACKHAB_LV2_LENGTH = mToPx(1.016)
245
246 BACKHAB_LV3_LENGTH = mToPx(1.2192)
247 Y_LV3_BOX = Y_TOP_BACKHAB_BOX - BACKHAB_LV3_LENGTH
248
249 Y_BOTTOM_BACKHAB_BOX = Y_LV3_BOX -BACKHAB_LV2_LENGTH
250
251 # HAB LEVEL 1
252 X_LV1_BOX = BACKWALL_X + WIDTH_BACKHAB
253
254 WIDTH_LV1_BOX = mToPx(0.90805)
255 LENGTH_LV1_BOX = mToPx(1.6256)
256
257 Y_BOTTOM_LV1_BOX = Y_BASE - LENGTH_LV1_BOX
258
259 # Ramp off Level 1
260 X_RAMP = X_LV1_BOX
261
262 Y_TOP_RAMP = Y_BASE + LENGTH_LV1_BOX
263 WIDTH_TOP_RAMP = mToPx(1.20015)
264 LENGTH_TOP_RAMP = Y_BASE + mToPx(0.28306)
265
266 X_MIDDLE_RAMP = X_RAMP + WIDTH_LV1_BOX
267 Y_MIDDLE_RAMP = Y_BOTTOM_LV1_BOX
268 LENGTH_MIDDLE_RAMP = 2*LENGTH_LV1_BOX
269 WIDTH_MIDDLE_RAMP = WIDTH_TOP_RAMP - WIDTH_LV1_BOX
270
271 Y_BOTTOM_RAMP = Y_BASE - LENGTH_LV1_BOX - LENGTH_TOP_RAMP
272
273 # Side Bars to Hold in balls
274 X_BARS = BACKWALL_X
275 WIDTH_BARS = WIDTH_BACKHAB
276 LENGTH_BARS = mToPx(0.574675)
277
278 Y_TOP_BAR = Y_TOP_BACKHAB_BOX + BACKHAB_LV2_LENGTH
279
280 Y_BOTTOM_BAR = Y_BOTTOM_BACKHAB_BOX - LENGTH_BARS
281
282 set_color(cr, palette["BLACK"])
283 cr.rectangle(BACKWALL_X, Y_TOP_BACKHAB_BOX, WIDTH_BACKHAB,
284 BACKHAB_LV2_LENGTH)
285 cr.rectangle(BACKWALL_X, Y_LV3_BOX, WIDTH_BACKHAB,
286 BACKHAB_LV3_LENGTH)
287 cr.rectangle(BACKWALL_X, Y_BOTTOM_BACKHAB_BOX, WIDTH_BACKHAB,
288 BACKHAB_LV2_LENGTH)
289 cr.rectangle(X_LV1_BOX, Y_BASE, WIDTH_LV1_BOX, LENGTH_LV1_BOX)
290 cr.rectangle(X_LV1_BOX, Y_BOTTOM_LV1_BOX, WIDTH_LV1_BOX,
291 LENGTH_LV1_BOX)
292 cr.rectangle(X_RAMP, Y_TOP_RAMP, WIDTH_TOP_RAMP, LENGTH_TOP_RAMP)
293 cr.rectangle(X_MIDDLE_RAMP, Y_MIDDLE_RAMP, WIDTH_MIDDLE_RAMP,
294 LENGTH_MIDDLE_RAMP)
295 cr.rectangle(X_RAMP, Y_BOTTOM_RAMP, WIDTH_TOP_RAMP, LENGTH_TOP_RAMP)
296 cr.rectangle(X_BARS, Y_TOP_BAR, WIDTH_BARS, LENGTH_BARS)
297 cr.rectangle(X_BARS, Y_BOTTOM_BAR, WIDTH_BARS, LENGTH_BARS)
298 cr.stroke()
299 #draw_px_x(cr, BACKWALL_X, 0, 10) # Midline Point
300 #draw_px_x(cr, X_BASE, Y_BASE, 10) # Bases
301 cr.set_line_join(cairo.LINE_JOIN_ROUND)
302
303 cr.stroke()
304
John Park9208ef92019-02-01 19:47:30 -0800305 def draw_rockets(self, cr):
306 # BASE Constants
307 X_BASE = -450+mToPx(2.41568)
308 Y_BASE = -150+mToPx(4.129151)
309
310 # Top Rocket
311
312 # Leftmost Line
313 cr.move_to(X_BASE + mToPx(2.89973), Y_BASE + mToPx(3.86305))
314 cr.line_to(X_BASE + mToPx(3.15642), Y_BASE + mToPx(3.39548))
315
316 # Top Line
317 cr.move_to(X_BASE + mToPx(3.15642), Y_BASE + mToPx(3.39548))
318 cr.line_to(X_BASE + mToPx(3.63473), Y_BASE + mToPx(3.39238))
319
320 #Rightmost Line
321 cr.move_to(X_BASE + mToPx(3.63473), Y_BASE + mToPx(3.39238))
322 cr.line_to(X_BASE + mToPx(3.89984), Y_BASE + mToPx(3.86305))
323
324 #Back Line
325 cr.move_to(X_BASE + mToPx(2.89973), Y_BASE + mToPx(3.86305))
326 cr.line_to(X_BASE + mToPx(3.89984), Y_BASE + mToPx(3.86305))
327
328 # Bottom Rocket
329
330 # Leftmost Line
331 cr.move_to(X_BASE + mToPx(2.89973), Y_BASE - mToPx(3.86305))
332 cr.line_to(X_BASE + mToPx(3.15642), Y_BASE - mToPx(3.39548))
333
334 # Top Line
335 cr.move_to(X_BASE + mToPx(3.15642), Y_BASE - mToPx(3.39548))
336 cr.line_to(X_BASE + mToPx(3.63473), Y_BASE - mToPx(3.39238))
337
338 #Rightmost Line
339 cr.move_to(X_BASE + mToPx(3.63473), Y_BASE - mToPx(3.39238))
340 cr.line_to(X_BASE + mToPx(3.89984), Y_BASE - mToPx(3.86305))
341
342 #Back Line
343 cr.move_to(X_BASE + mToPx(2.89973), Y_BASE - mToPx(3.86305))
344 cr.line_to(X_BASE + mToPx(3.89984), Y_BASE - mToPx(3.86305))
345
346 cr.stroke()
347
John Parka30a7782019-02-01 18:47:26 -0800348 def draw_field_elements(self, cr):
349 self.draw_HAB(cr)
John Park9208ef92019-02-01 19:47:30 -0800350 self.draw_rockets(cr)
John Parka30a7782019-02-01 18:47:26 -0800351
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800352 def handle_draw(self, cr):
Andrew Runke6842bf92019-01-26 15:38:25 -0800353 # print(self.new_point)
354 # print("SELF.POINT_SELECTED: " + str(self.point_selected))
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800355
356 # begin drawing
357 # Fill the background color of the window with grey
358 set_color(cr, palette["GREY"])
359 cr.paint()
Andrew Runkea9c8de52019-01-26 19:54:29 -0800360 #Scale the field to fit within drawing area
Andrew Runke6696bb82019-02-02 14:33:59 -0800361 cr.scale(0.5, 0.5)
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800362
363 # Draw a extents rectangle
364 set_color(cr, palette["WHITE"])
365 cr.rectangle(self.extents_x_min, self.extents_y_min,
366 (self.extents_x_max - self.extents_x_min),
367 self.extents_y_max - self.extents_y_min)
368 cr.fill()
369
John Parka30a7782019-02-01 18:47:26 -0800370 #Drawing the field
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800371 cr.move_to(0, 50)
372 cr.show_text('Press "e" to export')
373 cr.show_text('Press "i" to import')
374
375 set_color(cr, Color(0.3, 0.3, 0.3))
Andrew Runke6842bf92019-01-26 15:38:25 -0800376 cr.rectangle(-450, -150, 300, 300)
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800377 cr.fill()
378 set_color(cr, palette["BLACK"])
Andrew Runke6842bf92019-01-26 15:38:25 -0800379 cr.rectangle(-450, -150, 300, 300)
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800380 cr.set_line_join(cairo.LINE_JOIN_ROUND)
381 cr.stroke()
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800382
John Parka30a7782019-02-01 18:47:26 -0800383 self.draw_field_elements(cr)
384
Andrew Runke6842bf92019-01-26 15:38:25 -0800385 y = 0
Andrew Runke6842bf92019-01-26 15:38:25 -0800386
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800387 # update all the things
388
389 if self.mode == Mode.kViewing:
390 set_color(cr, palette["BLACK"])
391 cr.move_to(-300, 170)
392 cr.show_text("VIEWING")
393 set_color(cr, palette["GREY"])
Andrew Runke6842bf92019-01-26 15:38:25 -0800394
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800395 if len(self.selected_points) > 0:
396 print("SELECTED_POINTS: " + str(len(self.selected_points)))
397 print("ITEMS:")
Andrew Runke6842bf92019-01-26 15:38:25 -0800398 # for item in self.selected_points:
399 # print(str(item))
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800400 for i, point in enumerate(self.selected_points):
Andrew Runke6842bf92019-01-26 15:38:25 -0800401 # print("I: " + str(i))
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800402 draw_px_x(cr, point[0], point[1], 10)
Andrew Runke6842bf92019-01-26 15:38:25 -0800403 cr.move_to(point[0], point[1] - 15)
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800404 display_text(cr, str(i), 0.5, 0.5, 2, 2)
405
Andrew Runke6842bf92019-01-26 15:38:25 -0800406 elif self.mode == Mode.kPlacing:
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800407 set_color(cr, palette["BLACK"])
408 cr.move_to(-300, 170)
409 display_text(cr, "ADD", 1, 1, 1, 1)
410 set_color(cr, palette["GREY"])
Andrew Runke6842bf92019-01-26 15:38:25 -0800411
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800412 if len(self.selected_points) > 0:
413 print("SELECTED_POINTS: " + str(len(self.selected_points)))
414 print("ITEMS:")
415 for item in self.selected_points:
416 print(str(item))
417 for i, point in enumerate(self.selected_points):
418 print("I: " + str(i))
John Park13d3e282019-01-26 20:16:48 -0800419 draw_px_x(cr, mToPx(point[0]), mToPx(point[1]), 10)
420 cr.move_to(mToPx(point[0]), mToPx(point[1]) - 15)
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800421 display_text(cr, str(i), 0.5, 0.5, 2, 2)
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800422
423 elif self.mode == Mode.kEditing:
424 set_color(cr, palette["BLACK"])
425 cr.move_to(-300, 170)
426 display_text(cr, "EDITING", 1, 1, 1, 1)
Andrew Runke6842bf92019-01-26 15:38:25 -0800427 if len(self.splines) > 0:
Andrew Runke6842bf92019-01-26 15:38:25 -0800428 holder_spline = []
429 for i, points in enumerate(self.splines):
430 array = np.zeros(shape=(6, 2), dtype=float)
431 for j, point in enumerate(points):
John Park13d3e282019-01-26 20:16:48 -0800432 array[j, 0] = mToPx(point[0])
433 array[j, 1] = mToPx(point[1])
Andrew Runke6842bf92019-01-26 15:38:25 -0800434 spline = Spline(np.ascontiguousarray(np.transpose(array)))
435 for k in np.linspace(0.01, 1, 100):
Andrew Runke6842bf92019-01-26 15:38:25 -0800436 cr.move_to(
437 spline.Point(k - 0.01)[0],
438 spline.Point(k - 0.01)[1])
439 cr.line_to(spline.Point(k)[0], spline.Point(k)[1])
440 cr.stroke()
441 holding = [
442 spline.Point(k - 0.01)[0],
443 spline.Point(k - 0.01)[1]
444 ]
Andrew Runke6842bf92019-01-26 15:38:25 -0800445 holder_spline.append(holding)
446 self.curves.append(holder_spline)
447
448 for spline, points in enumerate(self.splines):
449 # for item in points:
450 # print(str(item))
451 for i, point in enumerate(points):
452 # print("I: " + str(i))
453 if spline == self.spline_edit and i == self.index_of_edit:
John Park13d3e282019-01-26 20:16:48 -0800454 draw_px_x(cr, mToPx(point[0]), mToPx(point[1]), 15,
Andrew Runke6842bf92019-01-26 15:38:25 -0800455 self.colors[spline])
456 elif (spline == 0 and not i == 5) or (not i == 0
457 and not i == 5):
John Park13d3e282019-01-26 20:16:48 -0800458 draw_px_x(cr, mToPx(point[0]), mToPx(point[1]), 10,
Andrew Runke6842bf92019-01-26 15:38:25 -0800459 self.colors[spline])
John Park13d3e282019-01-26 20:16:48 -0800460 cr.move_to(mToPx(point[0]), mToPx(point[1]) - 15)
Andrew Runke6842bf92019-01-26 15:38:25 -0800461 display_text(cr, str(i), 0.5, 0.5, 2, 2)
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800462
Andrew Runke6842bf92019-01-26 15:38:25 -0800463 elif self.mode == Mode.kConstraint:
464 print("Drawn")
465 set_color(cr, palette["BLACK"])
466 cr.move_to(-300, 170)
467 display_text(cr, "Adding Constraint", 1, 1, 1, 1)
468 if len(self.splines) > 0:
469 # print("Splines: " + str(len(self.splines)))
470 # print("ITEMS:")
471 for s, points in enumerate(self.splines):
472 # for item in points:
473 # print(str(item))
474 for i, point in enumerate(points):
475 # print("I: " + str(i))
476 draw_px_x(cr, point[0], point[1], 10, self.colors[s])
477 cr.move_to(point[0], point[1] - 15)
478 display_text(cr, str(i), 0.5, 0.5, 2, 2)
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800479
480 cr.paint_with_alpha(.65)
481
482 draw_px_cross(cr, self.x, self.y, 10)
483
484 def do_key_press(self, event):
485 keyval = Gdk.keyval_to_lower(event.keyval)
Andrew Runke6842bf92019-01-26 15:38:25 -0800486 # print("Gdk.KEY_" + Gdk.keyval_name(keyval))
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800487 if keyval == Gdk.KEY_q:
488 print("Found q key and exiting.")
489 quit_main_loop()
490 if keyval == Gdk.KEY_e:
Andrew Runke0f945fd2019-01-27 21:10:37 -0800491 # Will export to json file
492 self.mode = Mode.kEditing
493 print(str(sys.argv))
494 print('out to: ', self.path_to_export)
495 exportList = [l.tolist() for l in self.splines]
496 with open(self.path_to_export, mode='w') as points_file:
497 json.dump(exportList, points_file)
498 print("Wrote: " + str(self.splines))
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800499 if keyval == Gdk.KEY_i:
Andrew Runke0f945fd2019-01-27 21:10:37 -0800500 # import from json file
501 self.mode = Mode.kEditing
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800502 self.selected_points = []
Andrew Runke0f945fd2019-01-27 21:10:37 -0800503 self.splines = []
504 with open(self.path_to_export) as points_file:
505 self.splines = json.load(points_file)
506 print("Added: " + str(self.splines))
Andrew Runke6842bf92019-01-26 15:38:25 -0800507 if keyval == Gdk.KEY_p:
508 self.mode = Mode.kPlacing
509 # F0 = A1
510 # B1 = 2F0 - E0
511 # C1= d0 + 4F0 - 4E0
512 spline_index = len(self.splines) - 1
513 self.selected_points = []
514 f = self.splines[spline_index][5]
515 e = self.splines[spline_index][4]
516 d = self.splines[spline_index][3]
517 self.selected_points.append(f)
518 self.selected_points.append(f * 2 + e * -1)
519 self.selected_points.append(d + f * 4 + e * -4)
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800520
Andrew Runke6842bf92019-01-26 15:38:25 -0800521 if keyval == Gdk.KEY_c:
522 self.mode = Mode.kConstraint
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800523
524 def button_press_action(self):
Andrew Runke6842bf92019-01-26 15:38:25 -0800525 if self.mode == Mode.kPlacing:
526 #Check that the point clicked is on the field
527 if (self.x < -150 and self.x > -450 and self.y < 150
528 and self.y > -150):
529 self.add_point(self.x, self.y)
530 elif self.mode == Mode.kEditing:
531 # Now after index_of_edit is not -1, the point is selected, so
532 # user can click for new point
533 if self.index_of_edit > -1 and self.held_x != self.x:
534 print("INDEX OF EDIT: " + str(self.index_of_edit))
535 self.splines[self.spline_edit][self.index_of_edit] = [
John Park13d3e282019-01-26 20:16:48 -0800536 pxToM(self.x), pxToM(self.y)
Andrew Runke6842bf92019-01-26 15:38:25 -0800537 ]
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800538
Andrew Runke6842bf92019-01-26 15:38:25 -0800539 if not self.spline_edit == len(self.splines) - 1:
540 spline_edit = self.spline_edit + 1
541 f = self.splines[self.spline_edit][5]
542 e = self.splines[self.spline_edit][4]
543 d = self.splines[self.spline_edit][3]
544 self.splines[spline_edit][0] = f
545 self.splines[spline_edit][1] = f * 2 + e * -1
546 self.splines[spline_edit][2] = d + f * 4 + e * -4
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800547
Andrew Runke6842bf92019-01-26 15:38:25 -0800548 if not self.spline_edit == 0:
549 spline_edit = self.spline_edit - 1
550 a = self.splines[self.spline_edit][0]
551 b = self.splines[self.spline_edit][1]
552 c = self.splines[self.spline_edit][2]
553 self.splines[spline_edit][5] = a
554 self.splines[spline_edit][4] = a * 2 + b * -1
555 self.splines[spline_edit][3] = c + a * 4 + b * -4
556
Andrew Runke6842bf92019-01-26 15:38:25 -0800557 self.index_of_edit = -1
558 self.spline_edit = -1
559 else:
560 print("mode == 2")
561 # Get clicked point
562 # Find nearest
563 # Move nearest to clicked
John Park13d3e282019-01-26 20:16:48 -0800564 cur_p = [pxToM(self.x), pxToM(self.y)]
Andrew Runke6842bf92019-01-26 15:38:25 -0800565 print("CUR_P: " + str(self.x) + " " + str(self.y))
566 # Get the distance between each for x and y
567 # Save the index of the point closest
John Park13d3e282019-01-26 20:16:48 -0800568 nearest = 1 # Max distance away a the selected point can be in meters
Andrew Runke6842bf92019-01-26 15:38:25 -0800569 index_of_closest = 0
570 for index_splines, points in enumerate(self.splines):
571 for index_points, val in enumerate(points):
572 # pythagorean
573 distance = np.sqrt((cur_p[0] - val[0])**2 +
574 (cur_p[1] - val[1])**2)
575 if distance < nearest:
576 nearest = distance
577 index_of_closest = index_points
578 print("Nearest: " + str(nearest))
579 print("Index: " + str(index_of_closest))
580 self.index_of_edit = index_of_closest
581 self.spline_edit = index_splines
582 self.held_x = self.x
583 elif self.mode == Mode.kConstraint:
584 print("RAN")
585 self.set_index_to_nearest_spline_point()
586 print("FINISHED")
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800587
588 def do_button_press(self, event):
589 print("button press activated")
John Park13d3e282019-01-26 20:16:48 -0800590 # Be consistent with the scaling in the drawing_area
Andrew Runkea9c8de52019-01-26 19:54:29 -0800591 self.x = event.x * 2
592 self.y = event.y * 2
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800593 self.button_press_action()
594
595
Andrew Runke6842bf92019-01-26 15:38:25 -0800596class GridWindow(Gtk.Window):
597 def method_connect(self, event, cb):
598 def handler(obj, *args):
599 cb(*args)
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800600
Andrew Runke6842bf92019-01-26 15:38:25 -0800601 print("Method_connect ran")
602 self.connect(event, handler)
603
604 def button_press(self, event):
605 print("button press activated")
606 o_x = event.x
607 o_y = event.y
608 x = event.x - self.drawing_area.window_shape[0] / 2
609 y = self.drawing_area.window_shape[1] / 2 - event.y
610 scale = self.drawing_area.get_current_scale()
611 event.x = x / scale + self.drawing_area.center[0]
612 event.y = y / scale + self.drawing_area.center[1]
613 self.drawing_area.do_button_press(event)
614 event.x = o_x
615 event.y = o_y
616
617 def key_press(self, event):
618 print("key press activated")
619 self.drawing_area.do_key_press(event)
620 self.queue_draw()
621
622 def configure(self, event):
623 print("configure activated")
624 self.drawing_area.window_shape = (event.width, event.height)
625
626 def on_submit_click(self, widget):
627 self.drawing_area.inConstraint = int(self.constraint_box.get_text())
628 self.drawing_area.inValue = int(self.value_box.get_text())
629
630 def __init__(self):
631 Gtk.Window.__init__(self)
632
633 self.set_default_size(1366, 738)
634
635 flowBox = Gtk.FlowBox()
636 flowBox.set_valign(Gtk.Align.START)
637 flowBox.set_selection_mode(Gtk.SelectionMode.NONE)
638
639 flowBox.set_valign(Gtk.Align.START)
640
641 self.add(flowBox)
642
643 container = Gtk.Fixed()
644 flowBox.add(container)
645
646 self.eventBox = Gtk.EventBox()
647 container.add(self.eventBox)
648
649 self.eventBox.set_events(Gdk.EventMask.BUTTON_PRESS_MASK
650 | Gdk.EventMask.BUTTON_RELEASE_MASK
651 | Gdk.EventMask.POINTER_MOTION_MASK
652 | Gdk.EventMask.SCROLL_MASK
653 | Gdk.EventMask.KEY_PRESS_MASK)
654
655 self.drawing_area = GTK_Widget()
656 self.eventBox.add(self.drawing_area)
657
658 self.method_connect("key-release-event", self.key_press)
659 self.method_connect("button-release-event", self.button_press)
660 self.method_connect("configure-event", self.configure)
661
662 # Constraint Boxes
663
664 self.start_box = Gtk.Entry()
665 self.start_box.set_size_request(100, 20)
666
667 self.constraint_box = Gtk.Entry()
668 self.constraint_box.set_size_request(100, 20)
669
670 self.constraint_box.set_text("Constraint")
671 self.constraint_box.set_editable(True)
672
673 container.put(self.constraint_box, 700, 0)
674
675 self.value_box = Gtk.Entry()
676 self.value_box.set_size_request(100, 20)
677
678 self.value_box.set_text("Value")
679 self.value_box.set_editable(True)
680
681 container.put(self.value_box, 700, 40)
682
683 self.submit_button = Gtk.Button("Submit")
684 self.submit_button.connect('clicked', self.on_submit_click)
685
686 container.put(self.submit_button, 880, 0)
687
688 self.show_all()
689
690
691window = GridWindow()
John Park13d3e282019-01-26 20:16:48 -0800692basic_window.RunApp()