blob: 6ddcb1c89a5441e7eee039591fe51f068447eda4 [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 -08006from color import Color, palette
7import random
8import gi
9import numpy as np
10import scipy.spatial.distance
11gi.require_version('Gtk', '3.0')
John Park91e69732019-03-03 13:12:43 -080012gi.require_version('Gdk', '3.0')
Andrew Runke6842bf92019-01-26 15:38:25 -080013from gi.repository import Gdk, Gtk, GLib
Tabitha Jarvis1007a132018-12-12 21:47:54 -080014import cairo
John Park91e69732019-03-03 13:12:43 -080015from libspline import Spline, DistanceSpline, Trajectory
Tabitha Jarvis1007a132018-12-12 21:47:54 -080016import enum
John Park91e69732019-03-03 13:12:43 -080017import json
18from basic_window import *
19from constants import *
20from drawing_constants import *
21from points import Points
22from graph import Graph
Andrew Runke6842bf92019-01-26 15:38:25 -080023
Tabitha Jarvis1007a132018-12-12 21:47:54 -080024
25class Mode(enum.Enum):
26 kViewing = 0
27 kPlacing = 1
28 kEditing = 2
29 kExporting = 3
30 kImporting = 4
Andrew Runke6842bf92019-01-26 15:38:25 -080031
32
John Park91e69732019-03-03 13:12:43 -080033class GTK_Widget(BaseWindow):
Andrew Runke6842bf92019-01-26 15:38:25 -080034 """Create a GTK+ widget on which we will draw using Cairo"""
Ravago Jones26f7ad02021-02-05 15:45:59 -080035
Tabitha Jarvis1007a132018-12-12 21:47:54 -080036 def __init__(self):
37 super(GTK_Widget, self).__init__()
38
John Park91e69732019-03-03 13:12:43 -080039 self.points = Points()
40
Tabitha Jarvis1007a132018-12-12 21:47:54 -080041 # init field drawing
42 # add default spline for testing purposes
43 # init editing / viewing modes and pointer location
44 self.mode = Mode.kPlacing
45 self.x = 0
46 self.y = 0
Andrew Runke0f945fd2019-01-27 21:10:37 -080047 module_path = os.path.dirname(os.path.realpath(sys.argv[0]))
48 self.path_to_export = os.path.join(module_path,
John Park91e69732019-03-03 13:12:43 -080049 'points_for_pathedit.json')
50
Tabitha Jarvis1007a132018-12-12 21:47:54 -080051 # update list of control points
52 self.point_selected = False
53 # self.adding_spline = False
54 self.index_of_selected = -1
55 self.new_point = []
56
57 # For the editing mode
Andrew Runke6842bf92019-01-26 15:38:25 -080058 self.index_of_edit = -1 # Can't be zero beause array starts at 0
Tabitha Jarvis1007a132018-12-12 21:47:54 -080059 self.held_x = 0
Andrew Runke6842bf92019-01-26 15:38:25 -080060 self.spline_edit = -1
Tabitha Jarvis1007a132018-12-12 21:47:54 -080061
Andrew Runke6842bf92019-01-26 15:38:25 -080062 self.curves = []
63
Ravago Jonesc26b9162021-06-30 20:12:48 -070064 try:
65 self.field_png = cairo.ImageSurface.create_from_png("frc971/control_loops/python/field_images/" + FIELD.field_id + ".png")
66 except cairo.Error:
67 self.field_png = None
68
Andrew Runke6842bf92019-01-26 15:38:25 -080069 self.colors = []
70
71 for c in palette:
72 self.colors.append(palette[c])
73
Tabitha Jarvis1007a132018-12-12 21:47:54 -080074 self.reinit_extents()
75
Andrew Runke6842bf92019-01-26 15:38:25 -080076 self.inStart = None
77 self.inEnd = None
Andrew Runke6842bf92019-01-26 15:38:25 -080078 self.inValue = None
79 self.startSet = False
80
John Park909c0392020-03-05 23:56:30 -080081 self.module_path = os.path.dirname(os.path.realpath(sys.argv[0]))
82
Andrew Runke6842bf92019-01-26 15:38:25 -080083 """set extents on images"""
Ravago Jones26f7ad02021-02-05 15:45:59 -080084
Tabitha Jarvis1007a132018-12-12 21:47:54 -080085 def reinit_extents(self):
John Park91e69732019-03-03 13:12:43 -080086 self.extents_x_min = -1.0 * SCREEN_SIZE
87 self.extents_x_max = SCREEN_SIZE
88 self.extents_y_min = -1.0 * SCREEN_SIZE
89 self.extents_y_max = SCREEN_SIZE
Tabitha Jarvis1007a132018-12-12 21:47:54 -080090
91 # this needs to be rewritten with numpy, i dont think this ought to have
92 # SciPy as a dependecy
93 def get_index_of_nearest_point(self):
94 cur_p = [[self.x, self.y]]
95 distances = scipy.spatial.distance.cdist(cur_p, self.all_controls)
96
97 return np.argmin(distances)
98
99 # return the closest point to the loc of the click event
100 def get_nearest_point(self):
101 return self.all_controls[self.get_index_of_nearest_point()]
102
John Parka30a7782019-02-01 18:47:26 -0800103 def draw_field_elements(self, cr):
Ravago Jones5f787df2021-01-23 16:26:27 -0800104 if FIELD.year == 2019:
John Parkcf545162020-02-23 20:07:25 -0800105 draw_HAB(cr)
106 draw_rockets(cr)
107 draw_cargo_ship(cr)
Ravago Jones5f787df2021-01-23 16:26:27 -0800108 elif FIELD.year == 2020:
John Parkcf545162020-02-23 20:07:25 -0800109 set_color(cr, palette["BLACK"])
110 markers(cr)
111 draw_shield_generator(cr)
112 draw_trench_run(cr)
113 draw_init_lines(cr)
114 draw_control_panel(cr)
Ravago Jones5f787df2021-01-23 16:26:27 -0800115 elif FIELD.year == 2021:
116 draw_at_home_grid(cr)
John Parka30a7782019-02-01 18:47:26 -0800117
John Park91e69732019-03-03 13:12:43 -0800118 def draw_robot_at_point(self, cr, i, p, spline):
119 p1 = [mToPx(spline.Point(i)[0]), mToPx(spline.Point(i)[1])]
120 p2 = [mToPx(spline.Point(i + p)[0]), mToPx(spline.Point(i + p)[1])]
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800121
John Park91e69732019-03-03 13:12:43 -0800122 #Calculate Robot
123 distance = np.sqrt((p2[1] - p1[1])**2 + (p2[0] - p1[0])**2)
124 x_difference_o = p2[0] - p1[0]
125 y_difference_o = p2[1] - p1[1]
Ravago Jones5e09c072021-03-27 13:21:03 -0700126 x_difference = x_difference_o * mToPx(FIELD.robot.length / 2) / distance
127 y_difference = y_difference_o * mToPx(FIELD.robot.length / 2) / distance
John Park91e69732019-03-03 13:12:43 -0800128
129 front_middle = []
130 front_middle.append(p1[0] + x_difference)
131 front_middle.append(p1[1] + y_difference)
132
133 back_middle = []
134 back_middle.append(p1[0] - x_difference)
135 back_middle.append(p1[1] - y_difference)
136
137 slope = [-(1 / x_difference_o) / (1 / y_difference_o)]
138 angle = np.arctan(slope)
139
Ravago Jones5e09c072021-03-27 13:21:03 -0700140 x_difference = np.sin(angle[0]) * mToPx(FIELD.robot.width / 2)
141 y_difference = np.cos(angle[0]) * mToPx(FIELD.robot.width / 2)
John Park91e69732019-03-03 13:12:43 -0800142
143 front_1 = []
144 front_1.append(front_middle[0] - x_difference)
145 front_1.append(front_middle[1] - y_difference)
146
147 front_2 = []
148 front_2.append(front_middle[0] + x_difference)
149 front_2.append(front_middle[1] + y_difference)
150
151 back_1 = []
152 back_1.append(back_middle[0] - x_difference)
153 back_1.append(back_middle[1] - y_difference)
154
155 back_2 = []
156 back_2.append(back_middle[0] + x_difference)
157 back_2.append(back_middle[1] + y_difference)
158
159 x_difference = x_difference_o * mToPx(
Ravago Jones5e09c072021-03-27 13:21:03 -0700160 FIELD.robot.length / 2 + ROBOT_SIDE_TO_BALL_CENTER) / distance
John Park91e69732019-03-03 13:12:43 -0800161 y_difference = y_difference_o * mToPx(
Ravago Jones5e09c072021-03-27 13:21:03 -0700162 FIELD.robot.length / 2 + ROBOT_SIDE_TO_BALL_CENTER) / distance
John Park91e69732019-03-03 13:12:43 -0800163
164 #Calculate Ball
165 ball_center = []
166 ball_center.append(p1[0] + x_difference)
167 ball_center.append(p1[1] + y_difference)
168
169 x_difference = x_difference_o * mToPx(
Ravago Jones5e09c072021-03-27 13:21:03 -0700170 FIELD.robot.length / 2 + ROBOT_SIDE_TO_HATCH_PANEL) / distance
John Park91e69732019-03-03 13:12:43 -0800171 y_difference = y_difference_o * mToPx(
Ravago Jones5e09c072021-03-27 13:21:03 -0700172 FIELD.robot.length / 2 + ROBOT_SIDE_TO_HATCH_PANEL) / distance
John Park91e69732019-03-03 13:12:43 -0800173
174 #Calculate Panel
175 panel_center = []
176 panel_center.append(p1[0] + x_difference)
177 panel_center.append(p1[1] + y_difference)
178
179 x_difference = np.sin(angle[0]) * mToPx(HATCH_PANEL_WIDTH / 2)
180 y_difference = np.cos(angle[0]) * mToPx(HATCH_PANEL_WIDTH / 2)
181
182 panel_1 = []
183 panel_1.append(panel_center[0] + x_difference)
184 panel_1.append(panel_center[1] + y_difference)
185
186 panel_2 = []
187 panel_2.append(panel_center[0] - x_difference)
188 panel_2.append(panel_center[1] - y_difference)
189
190 #Draw Robot
191 cr.move_to(front_1[0], front_1[1])
192 cr.line_to(back_1[0], back_1[1])
193 cr.line_to(back_2[0], back_2[1])
194 cr.line_to(front_2[0], front_2[1])
195 cr.line_to(front_1[0], front_1[1])
196
197 cr.stroke()
198
199 #Draw Ball
200 set_color(cr, palette["ORANGE"], 0.5)
201 cr.move_to(back_middle[0], back_middle[1])
202 cr.line_to(ball_center[0], ball_center[1])
203 cr.arc(ball_center[0], ball_center[1], mToPx(BALL_RADIUS), 0,
204 2 * np.pi)
205 cr.stroke()
206
207 #Draw Panel
208 set_color(cr, palette["YELLOW"], 0.5)
209 cr.move_to(panel_1[0], panel_1[1])
210 cr.line_to(panel_2[0], panel_2[1])
211
212 cr.stroke()
213 cr.set_source_rgba(0, 0, 0, 1)
214
215 def handle_draw(self, cr): # main
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800216 # Fill the background color of the window with grey
John Park91e69732019-03-03 13:12:43 -0800217 set_color(cr, palette["WHITE"])
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800218 cr.paint()
219
220 # Draw a extents rectangle
221 set_color(cr, palette["WHITE"])
222 cr.rectangle(self.extents_x_min, self.extents_y_min,
223 (self.extents_x_max - self.extents_x_min),
224 self.extents_y_max - self.extents_y_min)
225 cr.fill()
226
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800227 cr.move_to(0, 50)
228 cr.show_text('Press "e" to export')
229 cr.show_text('Press "i" to import')
230
James Kuszmaul1c933e02020-03-07 16:17:51 -0800231 cr.save()
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800232 set_color(cr, palette["BLACK"])
Ravago Jones5f787df2021-01-23 16:26:27 -0800233
234 if FIELD.year == 2019: # half field
James Kuszmaul1c933e02020-03-07 16:17:51 -0800235 cr.rectangle(0, -SCREEN_SIZE / 2, SCREEN_SIZE, SCREEN_SIZE)
Ravago Jones5f787df2021-01-23 16:26:27 -0800236 else: # full field
237 cr.translate(mToPx(FIELD.width) / 2.0, 0.0)
238 cr.rectangle(-mToPx(FIELD.width) / 2.0, -mToPx(FIELD.length) / 2.0,
239 mToPx(FIELD.width), mToPx(FIELD.length))
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800240 cr.set_line_join(cairo.LINE_JOIN_ROUND)
241 cr.stroke()
Ravago Jones5f787df2021-01-23 16:26:27 -0800242
Ravago Jonesc26b9162021-06-30 20:12:48 -0700243 if self.field_png:
244 cr.save()
245 cr.translate(-mToPx(FIELD.width) / 2, -mToPx(FIELD.length) / 2)
246 cr.scale(
247 mToPx(FIELD.width) / self.field_png.get_width(),
248 mToPx(FIELD.length) / self.field_png.get_height(),
249 )
250 cr.set_source_surface(self.field_png)
251 cr.paint()
252 cr.restore()
Andrew Runke6842bf92019-01-26 15:38:25 -0800253
John Park91e69732019-03-03 13:12:43 -0800254 # update everything
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800255
John Park91e69732019-03-03 13:12:43 -0800256 if self.mode == Mode.kPlacing or self.mode == Mode.kViewing:
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800257 set_color(cr, palette["BLACK"])
John Park91e69732019-03-03 13:12:43 -0800258 cr.move_to(-SCREEN_SIZE, 170)
259 plotPoints = self.points.getPoints()
260 if plotPoints:
261 for i, point in enumerate(plotPoints):
John Park13d3e282019-01-26 20:16:48 -0800262 draw_px_x(cr, mToPx(point[0]), mToPx(point[1]), 10)
263 cr.move_to(mToPx(point[0]), mToPx(point[1]) - 15)
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800264 display_text(cr, str(i), 0.5, 0.5, 2, 2)
John Park91e69732019-03-03 13:12:43 -0800265 set_color(cr, palette["WHITE"])
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800266
267 elif self.mode == Mode.kEditing:
268 set_color(cr, palette["BLACK"])
John Park91e69732019-03-03 13:12:43 -0800269 cr.move_to(-SCREEN_SIZE, 170)
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800270 display_text(cr, "EDITING", 1, 1, 1, 1)
John Park91e69732019-03-03 13:12:43 -0800271 if self.points.getSplines():
272 self.draw_splines(cr)
273 for i, points in enumerate(self.points.getSplines()):
Andrew Runke6842bf92019-01-26 15:38:25 -0800274
John Park91e69732019-03-03 13:12:43 -0800275 p0 = np.array([mToPx(points[0][0]), mToPx(points[0][1])])
276 p1 = np.array([mToPx(points[1][0]), mToPx(points[1][1])])
277 p2 = np.array([mToPx(points[2][0]), mToPx(points[2][1])])
278 p3 = np.array([mToPx(points[3][0]), mToPx(points[3][1])])
279 p4 = np.array([mToPx(points[4][0]), mToPx(points[4][1])])
280 p5 = np.array([mToPx(points[5][0]), mToPx(points[5][1])])
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800281
John Park91e69732019-03-03 13:12:43 -0800282 draw_control_points(cr, [p0, p1, p2, p3, p4, p5])
283 first_tangent = p0 + 2.0 * (p1 - p0)
284 second_tangent = p5 + 2.0 * (p4 - p5)
285 cr.set_source_rgb(0, 0.5, 0)
286 cr.move_to(p0[0], p0[1])
287 cr.set_line_width(1.0)
288 cr.line_to(first_tangent[0], first_tangent[1])
289 cr.move_to(first_tangent[0], first_tangent[1])
290 cr.line_to(p2[0], p2[1])
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800291
John Park91e69732019-03-03 13:12:43 -0800292 cr.move_to(p5[0], p5[1])
293 cr.line_to(second_tangent[0], second_tangent[1])
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800294
John Park91e69732019-03-03 13:12:43 -0800295 cr.move_to(second_tangent[0], second_tangent[1])
296 cr.line_to(p3[0], p3[1])
297
298 cr.stroke()
299 cr.set_line_width(2.0)
300 self.points.update_lib_spline()
301 set_color(cr, palette["WHITE"])
302
303 cr.paint_with_alpha(0.2)
304
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800305 draw_px_cross(cr, self.x, self.y, 10)
James Kuszmaul1c933e02020-03-07 16:17:51 -0800306 cr.restore()
307 mygraph = Graph(cr, self.points)
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800308
John Park91e69732019-03-03 13:12:43 -0800309 def draw_splines(self, cr):
310 holder_spline = []
311 for i, points in enumerate(self.points.getSplines()):
312 array = np.zeros(shape=(6, 2), dtype=float)
313 for j, point in enumerate(points):
314 array[j, 0] = point[0]
315 array[j, 1] = point[1]
316 spline = Spline(np.ascontiguousarray(np.transpose(array)))
317 for k in np.linspace(0.01, 1, 100):
Ravago Jones26f7ad02021-02-05 15:45:59 -0800318 cr.move_to(
319 mToPx(spline.Point(k - 0.01)[0]),
320 mToPx(spline.Point(k - 0.01)[1]))
321 cr.line_to(
322 mToPx(spline.Point(k)[0]), mToPx(spline.Point(k)[1]))
John Park91e69732019-03-03 13:12:43 -0800323 cr.stroke()
324 holding = [
325 spline.Point(k - 0.01)[0],
326 spline.Point(k - 0.01)[1]
327 ]
328 holder_spline.append(holding)
329 if i == 0:
330 self.draw_robot_at_point(cr, 0.00, 0.01, spline)
331 self.draw_robot_at_point(cr, 1, 0.01, spline)
332 self.curves.append(holder_spline)
333
334 def mouse_move(self, event):
335 old_x = self.x
336 old_y = self.y
Ravago Jones5f787df2021-01-23 16:26:27 -0800337 self.x = event.x - mToPx(FIELD.width / 2.0)
John Park91e69732019-03-03 13:12:43 -0800338 self.y = event.y
James Kuszmaul1c933e02020-03-07 16:17:51 -0800339 dif_x = self.x - old_x
340 dif_y = self.y - old_y
John Park91e69732019-03-03 13:12:43 -0800341 difs = np.array([pxToM(dif_x), pxToM(dif_y)])
342
343 if self.mode == Mode.kEditing:
James Kuszmaulb33b07c2021-02-25 22:39:24 -0800344 self.points.updates_for_mouse_move(
John Park91e69732019-03-03 13:12:43 -0800345 self.index_of_edit, self.spline_edit, self.x, self.y, difs)
346
John Park909c0392020-03-05 23:56:30 -0800347 def export_json(self, file_name):
Ravago Jones09f59722021-03-03 21:11:41 -0800348 self.path_to_export = os.path.join(
349 self.module_path, # position of the python
350 "../../..", # root of the repository
351 get_json_folder(FIELD), # path from the root
352 file_name # selected file
353 )
John Park909c0392020-03-05 23:56:30 -0800354 if file_name[-5:] != ".json":
355 print("Error: Filename doesn't end in .json")
356 else:
357 # Will export to json file
358 self.mode = Mode.kEditing
Ravago Jones3b92afa2021-02-05 14:27:32 -0800359
360 multi_spline = self.points.toMultiSpline()
361 print(multi_spline)
John Park909c0392020-03-05 23:56:30 -0800362 with open(self.path_to_export, mode='w') as points_file:
Ravago Jones3b92afa2021-02-05 14:27:32 -0800363 json.dump(multi_spline, points_file)
John Park909c0392020-03-05 23:56:30 -0800364
365 def import_json(self, file_name):
Ravago Jones09f59722021-03-03 21:11:41 -0800366 self.path_to_export = os.path.join(
367 self.module_path, # position of the python
368 "../../..", # root of the repository
369 get_json_folder(FIELD), # path from the root
370 file_name # selected file
371 )
372
John Park909c0392020-03-05 23:56:30 -0800373 if file_name[-5:] != ".json":
374 print("Error: Filename doesn't end in .json")
375 else:
376 # import from json file
377 self.mode = Mode.kEditing
James Kuszmaul1c933e02020-03-07 16:17:51 -0800378 print("LOADING LOAD FROM " + file_name) # Load takes a few seconds
John Park909c0392020-03-05 23:56:30 -0800379 with open(self.path_to_export) as points_file:
Ravago Jones3b92afa2021-02-05 14:27:32 -0800380 multi_spline = json.load(points_file)
John Park909c0392020-03-05 23:56:30 -0800381
Ravago Jones3b92afa2021-02-05 14:27:32 -0800382 # if people messed with the spline json,
383 # it might not be the right length
384 # so give them a nice error message
Ravago Jones09f59722021-03-03 21:11:41 -0800385 try: # try to salvage as many segments of the spline as possible
Ravago Jones3b92afa2021-02-05 14:27:32 -0800386 self.points.fromMultiSpline(multi_spline)
387 except IndexError:
388 # check if they're both 6+5*(k-1) long
389 expected_length = 6 + 5 * (multi_spline["spline_count"] - 1)
390 x_len = len(multi_spline["spline_x"])
391 y_len = len(multi_spline["spline_x"])
392 if x_len is not expected_length:
Ravago Jones09f59722021-03-03 21:11:41 -0800393 print(
394 "Error: spline x values were not the expected length; expected {} got {}"
395 .format(expected_length, x_len))
Ravago Jones3b92afa2021-02-05 14:27:32 -0800396 elif y_len is not expected_length:
Ravago Jones09f59722021-03-03 21:11:41 -0800397 print(
398 "Error: spline y values were not the expected length; expected {} got {}"
399 .format(expected_length, y_len))
Ravago Jones3b92afa2021-02-05 14:27:32 -0800400
John Park909c0392020-03-05 23:56:30 -0800401 print("SPLINES LOADED")
402
John Park91e69732019-03-03 13:12:43 -0800403 def do_key_press(self, event, file_name):
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800404 keyval = Gdk.keyval_to_lower(event.keyval)
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800405 if keyval == Gdk.KEY_q:
406 print("Found q key and exiting.")
407 quit_main_loop()
John Park909c0392020-03-05 23:56:30 -0800408 if keyval == Gdk.KEY_e:
409 export_json(file_name)
John Park91e69732019-03-03 13:12:43 -0800410
John Park909c0392020-03-05 23:56:30 -0800411 if keyval == Gdk.KEY_i:
412 import_json(file_name)
John Park91e69732019-03-03 13:12:43 -0800413
Andrew Runke6842bf92019-01-26 15:38:25 -0800414 if keyval == Gdk.KEY_p:
415 self.mode = Mode.kPlacing
416 # F0 = A1
417 # B1 = 2F0 - E0
418 # C1= d0 + 4F0 - 4E0
John Park91e69732019-03-03 13:12:43 -0800419 spline_index = len(self.points.getSplines()) - 1
420 self.points.resetPoints()
421 self.points.extrapolate(
422 self.points.getSplines()[len(self.points.getSplines()) - 1][5],
423 self.points.getSplines()[len(self.points.getSplines()) - 1][4],
424 self.points.getSplines()[len(self.points.getSplines()) - 1][3])
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800425
426 def button_press_action(self):
Andrew Runke6842bf92019-01-26 15:38:25 -0800427 if self.mode == Mode.kPlacing:
John Park91e69732019-03-03 13:12:43 -0800428 if self.points.add_point(self.x, self.y):
429 self.mode = Mode.kEditing
Andrew Runke6842bf92019-01-26 15:38:25 -0800430 elif self.mode == Mode.kEditing:
431 # Now after index_of_edit is not -1, the point is selected, so
432 # user can click for new point
433 if self.index_of_edit > -1 and self.held_x != self.x:
John Park91e69732019-03-03 13:12:43 -0800434 self.points.setSplines(self.spline_edit, self.index_of_edit,
435 pxToM(self.x), pxToM(self.y))
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800436
James Kuszmaulb33b07c2021-02-25 22:39:24 -0800437 self.points.splineExtrapolate(self.spline_edit)
Andrew Runke6842bf92019-01-26 15:38:25 -0800438
Andrew Runke6842bf92019-01-26 15:38:25 -0800439 self.index_of_edit = -1
440 self.spline_edit = -1
441 else:
Andrew Runke6842bf92019-01-26 15:38:25 -0800442 # Get clicked point
443 # Find nearest
444 # Move nearest to clicked
John Park13d3e282019-01-26 20:16:48 -0800445 cur_p = [pxToM(self.x), pxToM(self.y)]
Andrew Runke6842bf92019-01-26 15:38:25 -0800446 # Get the distance between each for x and y
447 # Save the index of the point closest
John Park13d3e282019-01-26 20:16:48 -0800448 nearest = 1 # Max distance away a the selected point can be in meters
Andrew Runke6842bf92019-01-26 15:38:25 -0800449 index_of_closest = 0
James Kuszmaul1c933e02020-03-07 16:17:51 -0800450 for index_splines, points in enumerate(
451 self.points.getSplines()):
Andrew Runke6842bf92019-01-26 15:38:25 -0800452 for index_points, val in enumerate(points):
Andrew Runke6842bf92019-01-26 15:38:25 -0800453 distance = np.sqrt((cur_p[0] - val[0])**2 +
454 (cur_p[1] - val[1])**2)
455 if distance < nearest:
456 nearest = distance
457 index_of_closest = index_points
458 print("Nearest: " + str(nearest))
459 print("Index: " + str(index_of_closest))
460 self.index_of_edit = index_of_closest
461 self.spline_edit = index_splines
462 self.held_x = self.x
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800463
464 def do_button_press(self, event):
John Park13d3e282019-01-26 20:16:48 -0800465 # Be consistent with the scaling in the drawing_area
Ravago Jones5f787df2021-01-23 16:26:27 -0800466 self.x = event.x * 2 - mToPx(FIELD.width / 2.0)
Andrew Runkea9c8de52019-01-26 19:54:29 -0800467 self.y = event.y * 2
Tabitha Jarvis1007a132018-12-12 21:47:54 -0800468 self.button_press_action()